|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2011 Michael Brown <[email protected]>. ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <stdint.h> ! 22: #include <string.h> ! 23: #include <errno.h> ! 24: #include <ipxe/uaccess.h> ! 25: #include <ipxe/list.h> ! 26: #include <ipxe/ethernet.h> ! 27: #include <ipxe/bofm.h> ! 28: ! 29: /** @file ! 30: * ! 31: * IBM BladeCenter Open Fabric Manager (BOFM) ! 32: * ! 33: */ ! 34: ! 35: /** List of BOFM devices */ ! 36: static LIST_HEAD ( bofmdevs ); ! 37: ! 38: /** ! 39: * Register BOFM device ! 40: * ! 41: * @v bofm BOFM device ! 42: * @ret rc Return status code ! 43: */ ! 44: int bofm_register ( struct bofm_device *bofm ) { ! 45: ! 46: list_add ( &bofm->list, &bofmdevs ); ! 47: DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n", ! 48: PCI_ARGS ( bofm->pci ), bofm->pci->id->name ); ! 49: return 0; ! 50: } ! 51: ! 52: /** ! 53: * Unregister BOFM device ! 54: * ! 55: * @v bofm BOFM device ! 56: */ ! 57: void bofm_unregister ( struct bofm_device *bofm ) { ! 58: ! 59: list_del ( &bofm->list ); ! 60: DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) ); ! 61: } ! 62: ! 63: /** ! 64: * Find BOFM device matching PCI bus:dev.fn address ! 65: * ! 66: * @v busdevfn PCI bus:dev.fn address ! 67: * @ret bofm BOFM device, or NULL ! 68: */ ! 69: static struct bofm_device * bofm_find_busdevfn ( unsigned int busdevfn ) { ! 70: struct bofm_device *bofm; ! 71: ! 72: list_for_each_entry ( bofm, &bofmdevs, list ) { ! 73: if ( bofm->pci->busdevfn == busdevfn ) ! 74: return bofm; ! 75: } ! 76: return NULL; ! 77: } ! 78: ! 79: /** ! 80: * Find BOFM driver for PCI device ! 81: * ! 82: * @v pci PCI device ! 83: * @ret rc Return status code ! 84: */ ! 85: int bofm_find_driver ( struct pci_device *pci ) { ! 86: struct pci_driver *driver; ! 87: struct pci_device_id *id; ! 88: unsigned int i; ! 89: ! 90: for_each_table_entry ( driver, BOFM_DRIVERS ) { ! 91: for ( i = 0 ; i < driver->id_count ; i++ ) { ! 92: id = &driver->ids[i]; ! 93: if ( ( id->vendor == pci->vendor ) && ! 94: ( id->device == pci->device ) ) { ! 95: pci_set_driver ( pci, driver, id ); ! 96: return 0; ! 97: } ! 98: } ! 99: } ! 100: return -ENOENT; ! 101: } ! 102: ! 103: /** ! 104: * Probe PCI device for BOFM driver ! 105: * ! 106: * @v pci PCI device ! 107: * @ret rc Return status code ! 108: */ ! 109: static int bofm_probe ( struct pci_device *pci ) { ! 110: int rc; ! 111: ! 112: /* Probe device */ ! 113: if ( ( rc = pci_probe ( pci ) ) != 0 ) { ! 114: DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n", ! 115: PCI_ARGS ( pci ), strerror ( rc ) ); ! 116: return rc; ! 117: } ! 118: ! 119: return 0; ! 120: } ! 121: ! 122: /** ! 123: * Remove PCI device ! 124: * ! 125: * @v pci PCI device ! 126: */ ! 127: static void bofm_remove ( struct pci_device *pci ) { ! 128: ! 129: /* Note that the IBM BIOS may re-read the expansion ROM after ! 130: * the BOFM initialisation call. The BOFM driver must ensure ! 131: * that the card is left in a state in which expansion ROM ! 132: * reads will succeed. (For example, if a card contains an ! 133: * embedded CPU that may issue reads to the same underlying ! 134: * flash device, and these reads are not locked against reads ! 135: * via the expansion ROM BAR, then the CPU must be stopped.) ! 136: * ! 137: * If this is not done, then occasional corrupted reads from ! 138: * the expansion ROM will be seen, and the BIOS may complain ! 139: * about a ROM checksum error. ! 140: */ ! 141: pci_remove ( pci ); ! 142: DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) ); ! 143: } ! 144: ! 145: /** ! 146: * Locate BOFM table section ! 147: * ! 148: * @v bofmtab BOFM table ! 149: * @v len Length of BOFM table ! 150: * @v magic Section magic ! 151: * @v bofmsec BOFM section header to fill in ! 152: * @ret offset Offset to section, or 0 if not found ! 153: */ ! 154: static size_t bofm_locate_section ( userptr_t bofmtab, size_t len, ! 155: uint32_t magic, ! 156: struct bofm_section_header *bofmsec ) { ! 157: size_t offset = sizeof ( struct bofm_global_header ); ! 158: ! 159: while ( offset < len ) { ! 160: copy_from_user ( bofmsec, bofmtab, offset, ! 161: sizeof ( *bofmsec ) ); ! 162: if ( bofmsec->magic == magic ) ! 163: return offset; ! 164: if ( bofmsec->magic == BOFM_DONE_MAGIC ) ! 165: break; ! 166: offset += ( sizeof ( *bofmsec ) + bofmsec->length ); ! 167: } ! 168: return 0; ! 169: } ! 170: ! 171: /** ! 172: * Process BOFM Ethernet parameter entry ! 173: * ! 174: * @v bofm BOFM device ! 175: * @v en EN parameter entry ! 176: * @ret rc Return status code ! 177: */ ! 178: static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) { ! 179: uint8_t mac[6]; ! 180: int rc; ! 181: ! 182: /* Retrieve current MAC address */ ! 183: if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) { ! 184: DBG ( "BOFM: " PCI_FMT " port %d could not harvest: %s\n", ! 185: PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) ); ! 186: return rc; ! 187: } ! 188: ! 189: /* Harvest MAC address if necessary */ ! 190: if ( en->options & BOFM_EN_RQ_HVST_MASK ) { ! 191: DBG ( "BOFM: " PCI_FMT " port %d harvested MAC %s\n", ! 192: PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) ); ! 193: memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) ); ! 194: en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST ); ! 195: } ! 196: ! 197: /* Mark as changed if necessary */ ! 198: if ( ( en->options & BOFM_EN_EN_A ) && ! 199: ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) { ! 200: DBG ( "BOFM: " PCI_FMT " port %d MAC %s", ! 201: PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) ); ! 202: DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) ); ! 203: en->options |= BOFM_EN_CHG_CHANGED; ! 204: } ! 205: ! 206: /* Apply MAC address if necessary */ ! 207: if ( ( en->options & BOFM_EN_EN_A ) && ! 208: ( en->options & BOFM_EN_USAGE_ENTRY ) && ! 209: ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) { ! 210: DBG ( "BOFM: " PCI_FMT " port %d applied MAC %s\n", ! 211: PCI_ARGS ( bofm->pci ), en->mport, ! 212: eth_ntoa ( en->mac_a ) ); ! 213: memcpy ( mac, en->mac_a, sizeof ( mac ) ); ! 214: } ! 215: ! 216: /* Store MAC address */ ! 217: if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) { ! 218: DBG ( "BOFM: " PCI_FMT " port %d could not update: %s\n", ! 219: PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) ); ! 220: return rc; ! 221: } ! 222: ! 223: return 0; ! 224: } ! 225: ! 226: /** ! 227: * Process BOFM table ! 228: * ! 229: * @v bofmtab BOFM table ! 230: * @v pci PCI device ! 231: * @ret bofmrc BOFM return status ! 232: */ ! 233: int bofm ( userptr_t bofmtab, struct pci_device *pci ) { ! 234: struct bofm_global_header bofmhdr; ! 235: struct bofm_section_header bofmsec; ! 236: struct bofm_en en; ! 237: struct bofm_device *bofm; ! 238: size_t en_region_offset; ! 239: size_t en_offset; ! 240: int skip; ! 241: int rc; ! 242: int bofmrc; ! 243: ! 244: /* Read BOFM structure */ ! 245: copy_from_user ( &bofmhdr, bofmtab, 0, sizeof ( bofmhdr ) ); ! 246: if ( bofmhdr.magic != BOFM_IOAA_MAGIC ) { ! 247: DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n", ! 248: BOFM_MAGIC_ARGS ( bofmhdr.magic ) ); ! 249: bofmrc = BOFM_ERR_INVALID_ACTION; ! 250: goto err_bad_signature; ! 251: } ! 252: DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n", ! 253: BOFM_MAGIC_ARGS ( bofmhdr.action ), bofmhdr.profile ); ! 254: ! 255: /* Determine whether or not we should skip normal POST ! 256: * initialisation. ! 257: */ ! 258: switch ( bofmhdr.action ) { ! 259: case BOFM_ACTION_UPDT: ! 260: case BOFM_ACTION_DFLT: ! 261: case BOFM_ACTION_HVST: ! 262: skip = BOFM_SKIP_INIT; ! 263: break; ! 264: case BOFM_ACTION_PARM: ! 265: case BOFM_ACTION_NONE: ! 266: skip = 0; ! 267: break; ! 268: default: ! 269: DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n", ! 270: BOFM_MAGIC_ARGS ( bofmhdr.action ) ); ! 271: bofmrc = BOFM_ERR_INVALID_ACTION; ! 272: goto err_bad_action; ! 273: } ! 274: ! 275: /* Find BOFM driver */ ! 276: if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) { ! 277: DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) ); ! 278: bofmrc = BOFM_ERR_DEVICE_ERROR; ! 279: goto err_find_driver; ! 280: } ! 281: ! 282: /* Probe driver for PCI device */ ! 283: if ( ( rc = bofm_probe ( pci ) ) != 0 ) { ! 284: bofmrc = BOFM_ERR_DEVICE_ERROR; ! 285: goto err_probe; ! 286: } ! 287: ! 288: /* Locate EN section, if present */ ! 289: en_region_offset = bofm_locate_section ( bofmtab, bofmhdr.length, ! 290: BOFM_EN_MAGIC, &bofmsec ); ! 291: if ( ! en_region_offset ) { ! 292: DBG ( "BOFM: No EN section found\n" ); ! 293: bofmrc = ( BOFM_SUCCESS | skip ); ! 294: goto err_no_en_section; ! 295: } ! 296: ! 297: /* Iterate through EN entries */ ! 298: for ( en_offset = ( en_region_offset + sizeof ( bofmsec ) ) ; ! 299: en_offset < ( en_region_offset + sizeof ( bofmsec ) + ! 300: bofmsec.length ) ; en_offset += sizeof ( en ) ) { ! 301: copy_from_user ( &en, bofmtab, en_offset, sizeof ( en ) ); ! 302: DBG2 ( "BOFM: EN entry found:\n" ); ! 303: DBG2_HDA ( en_offset, &en, sizeof ( en ) ); ! 304: if ( ( en.options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) { ! 305: DBG ( "BOFM: slot %d port %d has no PCI mapping\n", ! 306: en.slot, en.port ); ! 307: continue; ! 308: } ! 309: bofm = bofm_find_busdevfn ( en.busdevfn ); ! 310: if ( ! bofm ) { ! 311: DBG ( "BOFM: " PCI_FMT " ignored\n", ! 312: PCI_BUS ( en.busdevfn ), PCI_SLOT ( en.busdevfn ), ! 313: PCI_FUNC ( en.busdevfn ) ); ! 314: continue; ! 315: } ! 316: if ( ( rc = bofm_en ( bofm, &en ) ) == 0 ) { ! 317: en.options |= BOFM_EN_CSM_SUCCESS; ! 318: } else { ! 319: en.options |= BOFM_EN_CSM_FAILED; ! 320: } ! 321: DBG2 ( "BOFM: EN entry after processing:\n" ); ! 322: DBG2_HDA ( en_offset, &en, sizeof ( en ) ); ! 323: copy_to_user ( bofmtab, en_offset, &en, sizeof ( en ) ); ! 324: } ! 325: ! 326: bofmrc = ( BOFM_SUCCESS | skip ); ! 327: ! 328: err_no_en_section: ! 329: bofm_remove ( pci ); ! 330: err_probe: ! 331: err_find_driver: ! 332: err_bad_action: ! 333: err_bad_signature: ! 334: return bofmrc; ! 335: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.