iPXE
bofm.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2011 Michael Brown <mbrown@fensystems.co.uk>.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26#include <stdint.h>
27#include <string.h>
28#include <errno.h>
29#include <ipxe/list.h>
30#include <ipxe/ethernet.h>
31#include <ipxe/bofm.h>
32
33/** @file
34 *
35 * IBM BladeCenter Open Fabric Manager (BOFM)
36 *
37 */
38
39/** List of BOFM devices */
40static LIST_HEAD ( bofmdevs );
41
42/**
43 * Register BOFM device
44 *
45 * @v bofm BOFM device
46 * @ret rc Return status code
47 */
49
50 list_add ( &bofm->list, &bofmdevs );
51 DBG ( "BOFM: " PCI_FMT " registered using driver \"%s\"\n",
52 PCI_ARGS ( bofm->pci ), bofm->pci->id->name );
53 return 0;
54}
55
56/**
57 * Unregister BOFM device
58 *
59 * @v bofm BOFM device
60 */
62
63 list_del ( &bofm->list );
64 DBG ( "BOFM: " PCI_FMT " unregistered\n", PCI_ARGS ( bofm->pci ) );
65}
66
67/**
68 * Find BOFM device matching PCI bus:dev.fn address
69 *
70 * @v busdevfn PCI bus:dev.fn address
71 * @ret bofm BOFM device, or NULL
72 */
73static struct bofm_device * bofm_find_busdevfn ( unsigned int busdevfn ) {
74 struct bofm_device *bofm;
75
76 list_for_each_entry ( bofm, &bofmdevs, list ) {
77 if ( bofm->pci->busdevfn == busdevfn )
78 return bofm;
79 }
80 return NULL;
81}
82
83/**
84 * Find BOFM driver for PCI device
85 *
86 * @v pci PCI device
87 * @ret rc Return status code
88 */
90 struct pci_driver *driver;
91 struct pci_device_id *id;
92 unsigned int i;
93
95 for ( i = 0 ; i < driver->id_count ; i++ ) {
96 id = &driver->ids[i];
97 if ( ( id->vendor == pci->vendor ) &&
98 ( id->device == pci->device ) ) {
99 pci_set_driver ( pci, driver, id );
100 return 0;
101 }
102 }
103 }
104 return -ENOENT;
105}
106
107/**
108 * Probe PCI device for BOFM driver
109 *
110 * @v pci PCI device
111 * @ret rc Return status code
112 */
113static int bofm_probe ( struct pci_device *pci ) {
114 int rc;
115
116 /* Probe device */
117 if ( ( rc = pci_probe ( pci ) ) != 0 ) {
118 DBG ( "BOFM: " PCI_FMT " could not load driver: %s\n",
119 PCI_ARGS ( pci ), strerror ( rc ) );
120 return rc;
121 }
122
123 return 0;
124}
125
126/**
127 * Remove PCI device
128 *
129 * @v pci PCI device
130 */
131static void bofm_remove ( struct pci_device *pci ) {
132
133 /* Note that the IBM BIOS may re-read the expansion ROM after
134 * the BOFM initialisation call. The BOFM driver must ensure
135 * that the card is left in a state in which expansion ROM
136 * reads will succeed. (For example, if a card contains an
137 * embedded CPU that may issue reads to the same underlying
138 * flash device, and these reads are not locked against reads
139 * via the expansion ROM BAR, then the CPU must be stopped.)
140 *
141 * If this is not done, then occasional corrupted reads from
142 * the expansion ROM will be seen, and the BIOS may complain
143 * about a ROM checksum error.
144 */
145 pci_remove ( pci );
146 DBG ( "BOFM: " PCI_FMT " removed\n", PCI_ARGS ( pci ) );
147}
148
149/**
150 * Locate BOFM table section
151 *
152 * @v bofmhdr BOFM table header
153 * @v magic Section magic
154 * @ret bofmsec BOFM section header, or NULL if not found
155 */
156static struct bofm_section_header *
158 struct bofm_section_header *bofmsec;
159 size_t offset;
160
161 /* Scan for section */
162 for ( offset = sizeof ( *bofmhdr ) ; offset < bofmhdr->length ;
163 offset += ( sizeof ( *bofmsec ) + bofmsec->length ) ) {
164 bofmsec = ( ( ( void * ) bofmhdr ) + offset );
165 if ( bofmsec->magic == magic )
166 return bofmsec;
167 if ( bofmsec->magic == BOFM_DONE_MAGIC )
168 break;
169 }
170 return NULL;
171}
172
173/**
174 * Process BOFM Ethernet parameter entry
175 *
176 * @v bofm BOFM device
177 * @v en EN parameter entry
178 * @ret rc Return status code
179 */
180static int bofm_en ( struct bofm_device *bofm, struct bofm_en *en ) {
181 uint8_t mac[6];
182 int rc;
183
184 /* Retrieve current MAC address */
185 if ( ( rc = bofm->op->harvest ( bofm, en->mport, mac ) ) != 0 ) {
186 DBG ( "BOFM: " PCI_FMT " mport %d could not harvest: %s\n",
187 PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
188 return rc;
189 }
190
191 /* Harvest MAC address if necessary */
192 if ( en->options & BOFM_EN_RQ_HVST_MASK ) {
193 DBG ( "BOFM: " PCI_FMT " mport %d harvested MAC %s\n",
194 PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
195 memcpy ( en->mac_a, mac, sizeof ( en->mac_a ) );
196 en->options |= ( BOFM_EN_EN_A | BOFM_EN_HVST );
197 }
198
199 /* Mark as changed if necessary */
200 if ( ( en->options & BOFM_EN_EN_A ) &&
201 ( memcmp ( en->mac_a, mac, sizeof ( en->mac_a ) ) != 0 ) ) {
202 DBG ( "BOFM: " PCI_FMT " mport %d MAC %s",
203 PCI_ARGS ( bofm->pci ), en->mport, eth_ntoa ( mac ) );
204 DBG ( " changed to %s\n", eth_ntoa ( en->mac_a ) );
205 en->options |= BOFM_EN_CHG_CHANGED;
206 }
207
208 /* Apply MAC address if necessary */
209 if ( ( en->options & BOFM_EN_EN_A ) &&
210 ( en->options & BOFM_EN_USAGE_ENTRY ) &&
211 ( ! ( en->options & BOFM_EN_USAGE_HARVEST ) ) ) {
212 DBG ( "BOFM: " PCI_FMT " mport %d applied MAC %s\n",
213 PCI_ARGS ( bofm->pci ), en->mport,
214 eth_ntoa ( en->mac_a ) );
215 memcpy ( mac, en->mac_a, sizeof ( mac ) );
216 }
217
218 /* Store MAC address */
219 if ( ( rc = bofm->op->update ( bofm, en->mport, mac ) ) != 0 ) {
220 DBG ( "BOFM: " PCI_FMT " mport %d could not update: %s\n",
221 PCI_ARGS ( bofm->pci ), en->mport, strerror ( rc ) );
222 return rc;
223 }
224
225 return 0;
226}
227
228/**
229 * Process BOFM table
230 *
231 * @v bofmtab BOFM table
232 * @v pci PCI device
233 * @ret bofmrc BOFM return status
234 */
235int bofm ( void *bofmtab, struct pci_device *pci ) {
236 struct bofm_global_header *bofmhdr;
237 struct bofm_section_header *bofmsec;
238 struct bofm_en *en;
239 struct bofm_device *bofm;
240 size_t offset;
241 int skip;
242 int rc;
243 int bofmrc;
244
245 /* Read BOFM structure */
246 bofmhdr = bofmtab;
247 if ( bofmhdr->magic != BOFM_IOAA_MAGIC ) {
248 DBG ( "BOFM: invalid table signature " BOFM_MAGIC_FMT "\n",
249 BOFM_MAGIC_ARGS ( bofmhdr->magic ) );
251 goto err_bad_signature;
252 }
253 DBG ( "BOFM: " BOFM_MAGIC_FMT " (profile \"%s\")\n",
254 BOFM_MAGIC_ARGS ( bofmhdr->action ), bofmhdr->profile );
255
256 /* Determine whether or not we should skip normal POST
257 * initialisation.
258 */
259 switch ( bofmhdr->action ) {
260 case BOFM_ACTION_UPDT:
261 case BOFM_ACTION_DFLT:
262 case BOFM_ACTION_HVST:
263 skip = BOFM_SKIP_INIT;
264 break;
265 case BOFM_ACTION_PARM:
266 case BOFM_ACTION_NONE:
267 skip = 0;
268 break;
269 default:
270 DBG ( "BOFM: invalid action " BOFM_MAGIC_FMT "\n",
271 BOFM_MAGIC_ARGS ( bofmhdr->action ) );
273 goto err_bad_action;
274 }
275
276 /* Find BOFM driver */
277 if ( ( rc = bofm_find_driver ( pci ) ) != 0 ) {
278 DBG ( "BOFM: " PCI_FMT " has no driver\n", PCI_ARGS ( pci ) );
279 bofmrc = BOFM_ERR_DEVICE_ERROR;
280 goto err_find_driver;
281 }
282
283 /* Probe driver for PCI device */
284 if ( ( rc = bofm_probe ( pci ) ) != 0 ) {
285 bofmrc = BOFM_ERR_DEVICE_ERROR;
286 goto err_probe;
287 }
288
289 /* Locate EN section, if present */
290 bofmsec = bofm_locate_section ( bofmhdr, BOFM_EN_MAGIC );
291 if ( ! bofmsec ) {
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 ( offset = sizeof ( *bofmsec ) ; offset < bofmsec->length ;
299 offset += sizeof ( *en ) ) {
300 en = ( ( ( void * ) bofmsec ) + offset );
301 DBG2 ( "BOFM: EN entry found:\n" );
302 DBG2_HDA ( offset, en, sizeof ( *en ) );
303 if ( ( en->options & BOFM_EN_MAP_MASK ) != BOFM_EN_MAP_PFA ) {
304 DBG ( "BOFM: slot %d port %d has no PCI mapping\n",
305 en->slot, ( en->port + 1 ) );
306 continue;
307 }
308 DBG ( "BOFM: slot %d port %d%s is " PCI_FMT " mport %d\n",
309 en->slot, ( en->port + 1 ),
310 ( ( en->slot || en->port ) ? "" : "(?)" ), 0,
311 PCI_BUS ( en->busdevfn ), PCI_SLOT ( en->busdevfn ),
312 PCI_FUNC ( en->busdevfn ), en->mport );
313 bofm = bofm_find_busdevfn ( en->busdevfn );
314 if ( ! bofm ) {
315 DBG ( "BOFM: " PCI_FMT " mport %d ignored\n", 0,
316 PCI_BUS ( en->busdevfn ),
317 PCI_SLOT ( en->busdevfn ),
318 PCI_FUNC ( en->busdevfn ), en->mport );
319 continue;
320 }
321 if ( ( rc = bofm_en ( bofm, en ) ) == 0 ) {
322 en->options |= BOFM_EN_CSM_SUCCESS;
323 } else {
324 en->options |= BOFM_EN_CSM_FAILED;
325 }
326 DBG2 ( "BOFM: EN entry after processing:\n" );
327 DBG2_HDA ( offset, en, sizeof ( *en ) );
328 }
329
330 bofmrc = ( BOFM_SUCCESS | skip );
331
332 err_no_en_section:
333 bofm_remove ( pci );
334 err_probe:
335 err_find_driver:
336 err_bad_action:
337 err_bad_signature:
338 return bofmrc;
339}
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
static void bofm_remove(struct pci_device *pci)
Remove PCI device.
Definition bofm.c:131
static int bofm_probe(struct pci_device *pci)
Probe PCI device for BOFM driver.
Definition bofm.c:113
static struct bofm_device * bofm_find_busdevfn(unsigned int busdevfn)
Find BOFM device matching PCI bus:dev.fn address.
Definition bofm.c:73
static int bofm_en(struct bofm_device *bofm, struct bofm_en *en)
Process BOFM Ethernet parameter entry.
Definition bofm.c:180
static struct bofm_section_header * bofm_locate_section(struct bofm_global_header *bofmhdr, uint32_t magic)
Locate BOFM table section.
Definition bofm.c:157
int bofm_find_driver(struct pci_device *pci)
Find BOFM driver for PCI device.
Definition bofm.c:89
int bofm(void *bofmtab, struct pci_device *pci)
Process BOFM table.
Definition bofm.c:235
int bofm_register(struct bofm_device *bofm)
Register BOFM device.
Definition bofm.c:48
void bofm_unregister(struct bofm_device *bofm)
Unregister BOFM device.
Definition bofm.c:61
IBM BladeCenter Open Fabric Manager (BOFM)
#define BOFM_MAGIC_FMT
BOFM magic value debug message format.
Definition bofm.h:278
#define BOFM_IOAA_MAGIC
BOFM table header signature.
Definition bofm.h:103
#define BOFM_DRIVERS
BOFM driver table.
Definition bofm.h:318
#define BOFM_MAGIC_ARGS(magic)
BOFM magic value debug message arguments.
Definition bofm.h:281
#define BOFM_SKIP_INIT
Skip option ROM initialisation.
Definition bofm.h:70
struct bofm_en en
Definition bofm_test.c:45
uint16_t magic
Magic signature.
Definition bzimage.h:1
uint16_t offset
Offset to command line.
Definition bzimage.h:3
uint8_t id
Request identifier.
Definition ena.h:1
uint8_t mac[ETH_ALEN]
MAC address.
Definition ena.h:13
uint16_t busdevfn
PCI bus:dev.fn address.
Definition ena.h:17
Error codes.
const char * eth_ntoa(const void *ll_addr)
Transcribe Ethernet address.
Definition ethernet.c:176
Ethernet protocol.
#define BOFM_ACTION_PARM
Update MAC/WWN and initialise device.
Definition bofm.h:123
#define BOFM_ACTION_DFLT
Restore MAC/WWN to factory default.
Definition bofm.h:117
#define BOFM_ACTION_NONE
Just initialise the device.
Definition bofm.h:126
#define BOFM_ACTION_UPDT
Update MAC/WWN.
Definition bofm.h:114
#define BOFM_ACTION_HVST
Harvest MAC/WWN.
Definition bofm.h:120
#define BOFM_EN_CSM_FAILED
Entry has been used but failed.
Definition bofm.h:240
#define BOFM_EN_USAGE_ENTRY
Use entry values for assignment.
Definition bofm.h:255
#define BOFM_EN_CSM_SUCCESS
Entry has been used successfully.
Definition bofm.h:237
#define BOFM_EN_MAP_PFA
Port mapping is by PCI bus:dev.fn.
Definition bofm.h:213
#define BOFM_EN_CHG_CHANGED
Consumed entry is different than previous active entry.
Definition bofm.h:249
#define BOFM_EN_EN_A
MAC address A is present.
Definition bofm.h:225
#define BOFM_EN_MAP_MASK
Port mapping mask.
Definition bofm.h:210
#define BOFM_EN_USAGE_HARVEST
Ignore values - it's harvest time.
Definition bofm.h:252
#define BOFM_EN_RQ_HVST_MASK
Harvest request mask.
Definition bofm.h:264
#define BOFM_EN_HVST
Harvest complete.
Definition bofm.h:261
#define BOFM_ERR_INVALID_ACTION
Invalid action string.
Definition bofm.h:50
#define BOFM_ERR_DEVICE_ERROR
Device error prohibited MAC/WWN update.
Definition bofm.h:56
#define BOFM_SUCCESS
Successful.
Definition bofm.h:47
#define BOFM_DONE_MAGIC
End marker.
Definition bofm.h:154
#define BOFM_EN_MAGIC
EN start marker.
Definition bofm.h:151
#define DBG2(...)
Definition compiler.h:515
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define DBG2_HDA(...)
Definition compiler.h:516
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOENT
No such file or directory.
Definition errno.h:515
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
Linked lists.
#define list_for_each_entry(pos, head, member)
Iterate over entries in a list.
Definition list.h:432
#define list_del(list)
Delete an entry from a list.
Definition list.h:120
#define LIST_HEAD(list)
Declare a static list head.
Definition list.h:38
#define list_add(new, head)
Add a new entry to the head of a list.
Definition list.h:70
int pci_probe(struct pci_device *pci)
Probe a PCI device.
Definition pci.c:418
void pci_remove(struct pci_device *pci)
Remove a PCI device.
Definition pci.c:440
#define PCI_FMT
PCI device debug message format.
Definition pci.h:312
#define PCI_FUNC(busdevfn)
Definition pci.h:286
#define PCI_BUS(busdevfn)
Definition pci.h:284
#define PCI_ARGS(pci)
PCI device debug message arguments.
Definition pci.h:315
#define PCI_SLOT(busdevfn)
Definition pci.h:285
static void pci_set_driver(struct pci_device *pci, struct pci_driver *driver, struct pci_device_id *id)
Set PCI driver.
Definition pci.h:352
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
A BOFM device.
Definition bofm.h:286
struct list_head list
List of BOFM devices.
Definition bofm.h:292
struct pci_device * pci
Underlying PCI device.
Definition bofm.h:288
BOFM Ethernet parameter entry.
Definition bofm.h:163
BOFM table header.
Definition bofm.h:77
uint32_t action
Subsignature (action string)
Definition bofm.h:81
char profile[32]
Data structure profile.
Definition bofm.h:91
uint32_t magic
Signature.
Definition bofm.h:79
uint16_t length
Data structure length.
Definition bofm.h:87
BOFM section header.
Definition bofm.h:135
uint32_t magic
Signature.
Definition bofm.h:137
uint16_t length
Length.
Definition bofm.h:139
A PCI device ID list entry.
Definition pci.h:175
A PCI device.
Definition pci.h:211
uint16_t vendor
Vendor ID.
Definition pci.h:228
uint16_t device
Device ID.
Definition pci.h:230
A PCI driver.
Definition pci.h:252
struct pci_device_id * ids
PCI ID table.
Definition pci.h:254
unsigned int id_count
Number of entries in PCI ID table.
Definition pci.h:256
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386