xref: /freebsd/sys/dev/mps/mps_config.c (revision 3ef51c5fb9163f2aafb1c14729e06a8bf0c4d113)
1 /*-
2  * Copyright (c) 2011 LSI Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * LSI MPT-Fusion Host Adapter FreeBSD
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 /* TODO Move headers to mpsvar */
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/lock.h>
36 #include <sys/mutex.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/malloc.h>
40 #include <sys/kthread.h>
41 #include <sys/taskqueue.h>
42 #include <sys/bus.h>
43 #include <sys/endian.h>
44 #include <sys/sysctl.h>
45 #include <sys/eventhandler.h>
46 #include <sys/uio.h>
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <dev/mps/mpi/mpi2_type.h>
50 #include <dev/mps/mpi/mpi2.h>
51 #include <dev/mps/mpi/mpi2_ioc.h>
52 #include <dev/mps/mpi/mpi2_sas.h>
53 #include <dev/mps/mpi/mpi2_cnfg.h>
54 #include <dev/mps/mpi/mpi2_init.h>
55 #include <dev/mps/mpi/mpi2_tool.h>
56 #include <dev/mps/mps_ioctl.h>
57 #include <dev/mps/mpsvar.h>
58 
59 /**
60  * mps_config_get_ioc_pg8 - obtain ioc page 8
61  * @sc: per adapter object
62  * @mpi_reply: reply mf payload returned from firmware
63  * @config_page: contents of the config page
64  * Context: sleep.
65  *
66  * Returns 0 for success, non-zero for failure.
67  */
68 int
69 mps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
70     Mpi2IOCPage8_t *config_page)
71 {
72 	MPI2_CONFIG_REQUEST *request;
73 	MPI2_CONFIG_REPLY *reply;
74 	struct mps_command *cm;
75 	MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
76 	int error = 0;
77 	u16 ioc_status;
78 
79 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
80 
81 	if ((cm = mps_alloc_command(sc)) == NULL) {
82 		printf("%s: command alloc failed @ line %d\n", __func__,
83 		    __LINE__);
84 		error = EBUSY;
85 		goto out;
86 	}
87 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
88 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
89 	request->Function = MPI2_FUNCTION_CONFIG;
90 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
91 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
92 	request->Header.PageNumber = 8;
93 	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
94 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
95 	cm->cm_data = NULL;
96 	error = mps_request_polled(sc, cm);
97 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
98 	if (error || (reply == NULL)) {
99 		/* FIXME */
100 		/* If the poll returns error then we need to do diag reset */
101 		printf("%s: poll for header completed with error %d",
102 		    __func__, error);
103 		error = ENXIO;
104 		goto out;
105 	}
106 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
107 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
108 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
109 		/* FIXME */
110 		/* If the poll returns error then we need to do diag reset */
111 		printf("%s: header read with error; iocstatus = 0x%x\n",
112 		    __func__, ioc_status);
113 		error = ENXIO;
114 		goto out;
115 	}
116 	/* We have to do free and alloc for the reply-free and reply-post
117 	 * counters to match - Need to review the reply FIFO handling.
118 	 */
119 	mps_free_command(sc, cm);
120 
121 	if ((cm = mps_alloc_command(sc)) == NULL) {
122 		printf("%s: command alloc failed @ line %d\n", __func__,
123 		    __LINE__);
124 		error = EBUSY;
125 		goto out;
126 	}
127 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
128 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
129 	request->Function = MPI2_FUNCTION_CONFIG;
130 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
131 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
132 	request->Header.PageNumber = 8;
133 	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
134 	request->Header.PageLength = mpi_reply->Header.PageLength;
135 	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
136 	cm->cm_sge = &request->PageBufferSGE;
137 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
138 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
139 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
140 	page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
141 	if (!page) {
142 		printf("%s: page alloc failed\n", __func__);
143 		error = ENOMEM;
144 		goto out;
145 	}
146 	cm->cm_data = page;
147 	error = mps_request_polled(sc, cm);
148 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
149 	if (error || (reply == NULL)) {
150 		/* FIXME */
151 		/* If the poll returns error then we need to do diag reset */
152 		printf("%s: poll for page completed with error %d",
153 		    __func__, error);
154 		error = ENXIO;
155 		goto out;
156 	}
157 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
158 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
159 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
160 		/* FIXME */
161 		/* If the poll returns error then we need to do diag reset */
162 		printf("%s: page read with error; iocstatus = 0x%x\n",
163 		    __func__, ioc_status);
164 		error = ENXIO;
165 		goto out;
166 	}
167 	bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
168 
169 out:
170 	free(page, M_MPT2);
171 	if (cm)
172 		mps_free_command(sc, cm);
173 	return (error);
174 }
175 
176 /**
177  * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
178  *   accordingly.  Currently, this page does not need to return to caller.
179  * @sc: per adapter object
180  * @mpi_reply: reply mf payload returned from firmware
181  * Context: sleep.
182  *
183  * Returns 0 for success, non-zero for failure.
184  */
185 int
186 mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
187 {
188 	MPI2_CONFIG_REQUEST *request;
189 	MPI2_CONFIG_REPLY *reply;
190 	struct mps_command *cm;
191 	pMpi2ManufacturingPagePS_t page = NULL;
192 	uint32_t *pPS_info;
193 	uint8_t OEM_Value = 0;
194 	int error = 0;
195 	u16 ioc_status;
196 
197 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
198 
199 	if ((cm = mps_alloc_command(sc)) == NULL) {
200 		printf("%s: command alloc failed @ line %d\n", __func__,
201 		    __LINE__);
202 		error = EBUSY;
203 		goto out;
204 	}
205 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
206 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
207 	request->Function = MPI2_FUNCTION_CONFIG;
208 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
209 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
210 	request->Header.PageNumber = 10;
211 	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
212 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
213 	cm->cm_data = NULL;
214 	error = mps_request_polled(sc, cm);
215 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
216 	if (error || (reply == NULL)) {
217 		/* FIXME */
218 		/* If the poll returns error then we need to do diag reset */
219 		printf("%s: poll for header completed with error %d",
220 		    __func__, error);
221 		error = ENXIO;
222 		goto out;
223 	}
224 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
225 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
226 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
227 		/* FIXME */
228 		/* If the poll returns error then we need to do diag reset */
229 		printf("%s: header read with error; iocstatus = 0x%x\n",
230 		    __func__, ioc_status);
231 		error = ENXIO;
232 		goto out;
233 	}
234 	/* We have to do free and alloc for the reply-free and reply-post
235 	 * counters to match - Need to review the reply FIFO handling.
236 	 */
237 	mps_free_command(sc, cm);
238 
239 	if ((cm = mps_alloc_command(sc)) == NULL) {
240 		printf("%s: command alloc failed @ line %d\n", __func__,
241 		    __LINE__);
242 		error = EBUSY;
243 		goto out;
244 	}
245 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
246 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
247 	request->Function = MPI2_FUNCTION_CONFIG;
248 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
249 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
250 	request->Header.PageNumber = 10;
251 	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
252 	request->Header.PageLength = mpi_reply->Header.PageLength;
253 	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
254 	cm->cm_sge = &request->PageBufferSGE;
255 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
256 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
257 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
258 	page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
259 	if (!page) {
260 		printf("%s: page alloc failed\n", __func__);
261 		error = ENOMEM;
262 		goto out;
263 	}
264 	cm->cm_data = page;
265 	error = mps_request_polled(sc, cm);
266 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
267 	if (error || (reply == NULL)) {
268 		/* FIXME */
269 		/* If the poll returns error then we need to do diag reset */
270 		printf("%s: poll for page completed with error %d",
271 		    __func__, error);
272 		error = ENXIO;
273 		goto out;
274 	}
275 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
276 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
277 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
278 		/* FIXME */
279 		/* If the poll returns error then we need to do diag reset */
280 		printf("%s: page read with error; iocstatus = 0x%x\n",
281 		    __func__, ioc_status);
282 		error = ENXIO;
283 		goto out;
284 	}
285 
286 	/*
287 	 * If OEM ID is unknown, fail the request.
288 	 */
289 	sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
290 	OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
291 	if (OEM_Value != MPS_WD_LSI_OEM) {
292 		mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
293 		    "(0x%x)\n", OEM_Value);
294 		error = ENXIO;
295 		goto out;
296 	}
297 
298 	/*
299 	 * Set the phys disks hide/expose value.
300 	 */
301 	pPS_info = &page->ProductSpecificInfo;
302 	sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
303 	sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
304 	if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
305 	    (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
306 	    (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
307 		mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
308 		    "hide/expose: 0x%x\n", sc->WD_hide_expose);
309 		error = ENXIO;
310 		goto out;
311 	}
312 
313 out:
314 	free(page, M_MPT2);
315 	if (cm)
316 		mps_free_command(sc, cm);
317 	return (error);
318 }
319 
320 /**
321  * mps_base_static_config_pages - static start of day config pages.
322  * @sc: per adapter object
323  *
324  * Return nothing.
325  */
326 void
327 mps_base_static_config_pages(struct mps_softc *sc)
328 {
329 	Mpi2ConfigReply_t	mpi_reply;
330 	int			retry;
331 
332 	retry = 0;
333 	while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
334 		retry++;
335 		if (retry > 5) {
336 			/* We need to Handle this situation */
337 			/*FIXME*/
338 			break;
339 		}
340 	}
341 }
342 
343 /**
344  * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
345  *    be called after discovery is complete to guarentee that IR info is there.
346  * @sc: per adapter object
347  *
348  * Return nothing.
349  */
350 void
351 mps_wd_config_pages(struct mps_softc *sc)
352 {
353 	Mpi2ConfigReply_t	mpi_reply;
354 	pMpi2RaidVolPage0_t	raid_vol_pg0 = NULL;
355 	Mpi2RaidPhysDiskPage0_t	phys_disk_pg0;
356 	pMpi2RaidVol0PhysDisk_t	pRVPD;
357 	uint32_t		stripe_size, phys_disk_page_address;
358 	uint16_t		block_size;
359 	uint8_t			index, stripe_exp = 0, block_exp = 0;
360 
361 	/*
362 	 * Get the WD settings from manufacturing page 10 if using a WD HBA.
363 	 * This will be used to determine if phys disks should always be
364 	 * hidden, hidden only if part of a WD volume, or never hidden.  Also,
365 	 * get the WD RAID Volume info and fail if volume does not exist or if
366 	 * volume does not meet the requirements for a WD volume.  No retry
367 	 * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
368 	 * Valid flag if Volume info fails.
369 	 */
370 	sc->WD_valid_config = FALSE;
371 	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
372 		if (mps_config_get_man_pg10(sc, &mpi_reply)) {
373 			mps_dprint(sc, MPS_FAULT,
374 			    "mps_config_get_man_pg10 failed! Using 0 (Hide "
375 			    "Always) for WarpDrive hide/expose value.\n");
376 			sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
377 		}
378 
379 		/*
380 		 * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
381 		 */
382 		raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) +
383 		    (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
384 		    M_MPT2, M_ZERO | M_NOWAIT);
385 		if (!raid_vol_pg0) {
386 			printf("%s: page alloc failed\n", __func__);
387 			goto out;
388 		}
389 
390 		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
391 		    0x0000FFFF)) {
392 			mps_dprint(sc, MPS_INFO,
393 			    "mps_config_get_raid_volume_pg0 failed! Assuming "
394 			    "WarpDrive IT mode.\n");
395 			goto out;
396 		}
397 
398 		/*
399 		 * Check for valid WD configuration:
400 		 *   volume type is RAID0
401 		 *   number of phys disks in the volume is no more than 8
402 		 */
403 		if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
404 		    (raid_vol_pg0->NumPhysDisks > 8)) {
405 			mps_dprint(sc, MPS_FAULT,
406 			    "Invalid WarpDrive configuration. Direct Drive I/O "
407 			    "will not be used.\n");
408 			goto out;
409 		}
410 
411 		/*
412 		 * Save the WD RAID data to be used during WD I/O.
413 		 */
414 		sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
415 		    32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
416 		sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
417 		sc->DD_dev_handle = raid_vol_pg0->DevHandle;
418 		sc->DD_stripe_size = raid_vol_pg0->StripeSize;
419 		sc->DD_block_size = raid_vol_pg0->BlockSize;
420 
421 		/*
422 		 * Find power of 2 of stripe size and set this as the exponent.
423 		 * Fail if stripe size is 0.
424 		 */
425 		stripe_size = raid_vol_pg0->StripeSize;
426 		for (index = 0; index < 32; index++) {
427 			if (stripe_size & 1)
428 				break;
429 			stripe_exp++;
430 			stripe_size >>= 1;
431 		}
432 		if (index == 32) {
433 			mps_dprint(sc, MPS_FAULT,
434 			    "RAID Volume's stripe size is 0. Direct Drive I/O "
435 			    "will not be used.\n");
436 			goto out;
437 		}
438 		sc->DD_stripe_exponent = stripe_exp;
439 
440 		/*
441 		 * Find power of 2 of block size and set this as the exponent.
442 		 * Fail if block size is 0.
443 		 */
444 		block_size = raid_vol_pg0->BlockSize;
445 		for (index = 0; index < 16; index++) {
446 			if (block_size & 1)
447 				break;
448 			block_exp++;
449 			block_size >>= 1;
450 		}
451 		if (index == 16) {
452 			mps_dprint(sc, MPS_FAULT,
453 			    "RAID Volume's block size is 0. Direct Drive I/O "
454 			    "will not be used.\n");
455 			goto out;
456 		}
457 		sc->DD_block_exponent = block_exp;
458 
459 		/*
460 		 * Loop through all of the volume's Phys Disks to map the phys
461 		 * disk number into the columm map.  This is used during Direct
462 		 * Drive I/O to send the request to the correct SSD.
463 		 */
464 		pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
465 		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
466 			sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
467 			    pRVPD->PhysDiskNum;
468 			pRVPD++;
469 		}
470 
471 		/*
472 		 * Get second RAID Volume Page0 using previous handle.  This
473 		 * page should not exist.  If it does, must not proceed with WD
474 		 * handling.
475 		 */
476 		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
477 		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
478 			if (mpi_reply.IOCStatus !=
479 			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
480 				mps_dprint(sc, MPS_FAULT,
481 				    "Multiple RAID Volume Page0! Direct Drive "
482 				    "I/O will not be used.\n");
483 				goto out;
484 			}
485 		} else {
486 			mps_dprint(sc, MPS_FAULT,
487 			    "Multiple volumes! Direct Drive I/O will not be "
488 			    "used.\n");
489 			goto out;
490 		}
491 
492 		/*
493 		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
494 		 */
495 		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
496 			phys_disk_page_address =
497 			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
498 			    sc->DD_column_map[index].phys_disk_num;
499 			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
500 			    &phys_disk_pg0, phys_disk_page_address)) {
501 				mps_dprint(sc, MPS_FAULT,
502 				    "mps_config_get_raid_pd_pg0 failed! Direct "
503 				    "Drive I/O will not be used.\n");
504 				goto out;
505 			}
506 			if (phys_disk_pg0.DevHandle == 0xFFFF) {
507 				mps_dprint(sc, MPS_FAULT,
508 				    "Invalid Phys Disk DevHandle! Direct Drive "
509 				    "I/O will not be used.\n");
510 				goto out;
511 			}
512 			sc->DD_column_map[index].dev_handle =
513 			    phys_disk_pg0.DevHandle;
514 		}
515 		sc->WD_valid_config = TRUE;
516 out:
517 		if (raid_vol_pg0)
518 			free(raid_vol_pg0, M_MPT2);
519 	}
520 }
521 
522 /**
523  * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
524  * @sc: per adapter object
525  * @mpi_reply: reply mf payload returned from firmware
526  * @config_page: contents of the config page
527  * @sz: size of buffer passed in config_page
528  * Context: sleep.
529  *
530  * Returns 0 for success, non-zero for failure.
531  */
532 int
533 mps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
534     Mpi2DriverMappingPage0_t *config_page, u16 sz)
535 {
536 	MPI2_CONFIG_REQUEST *request;
537 	MPI2_CONFIG_REPLY *reply;
538 	struct mps_command *cm;
539 	Mpi2DriverMappingPage0_t *page = NULL;
540 	int error = 0;
541 	u16 ioc_status;
542 
543 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
544 
545 	memset(config_page, 0, sz);
546 	if ((cm = mps_alloc_command(sc)) == NULL) {
547 		printf("%s: command alloc failed @ line %d\n", __func__,
548 		    __LINE__);
549 		error = EBUSY;
550 		goto out;
551 	}
552 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
553 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
554 	request->Function = MPI2_FUNCTION_CONFIG;
555 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
556 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
557 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
558 	request->Header.PageNumber = 0;
559 	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
560 	request->PageAddress = sc->max_dpm_entries <<
561 	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
562 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
563 	cm->cm_data = NULL;
564 	error = mps_request_polled(sc, cm);
565 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
566 	if (error || (reply == NULL)) {
567 		/* FIXME */
568 		/* If the poll returns error then we need to do diag reset */
569 		printf("%s: poll for header completed with error %d",
570 		    __func__, error);
571 		error = ENXIO;
572 		goto out;
573 	}
574 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
575 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
576 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
577 		/* FIXME */
578 		/* If the poll returns error then we need to do diag reset */
579 		printf("%s: header read with error; iocstatus = 0x%x\n",
580 		    __func__, ioc_status);
581 		error = ENXIO;
582 		goto out;
583 	}
584 	/* We have to do free and alloc for the reply-free and reply-post
585 	 * counters to match - Need to review the reply FIFO handling.
586 	 */
587 	mps_free_command(sc, cm);
588 
589 	if ((cm = mps_alloc_command(sc)) == NULL) {
590 		printf("%s: command alloc failed @ line %d\n", __func__,
591 		    __LINE__);
592 		error = EBUSY;
593 		goto out;
594 	}
595 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
596 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
597 	request->Function = MPI2_FUNCTION_CONFIG;
598 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
599 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
600 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
601 	request->Header.PageNumber = 0;
602 	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
603 	request->PageAddress = sc->max_dpm_entries <<
604 	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
605 	request->ExtPageLength = mpi_reply->ExtPageLength;
606 	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
607 	cm->cm_sge = &request->PageBufferSGE;
608 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
609 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
610 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
611 	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
612 	if (!page) {
613 		printf("%s: page alloc failed\n", __func__);
614 		error = ENOMEM;
615 		goto out;
616 	}
617 	cm->cm_data = page;
618 	error = mps_request_polled(sc, cm);
619 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
620 	if (error || (reply == NULL)) {
621 		/* FIXME */
622 		/* If the poll returns error then we need to do diag reset */
623 		printf("%s: poll for page completed with error %d",
624 		    __func__, error);
625 		error = ENXIO;
626 		goto out;
627 	}
628 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
629 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
630 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
631 		/* FIXME */
632 		/* If the poll returns error then we need to do diag reset */
633 		printf("%s: page read with error; iocstatus = 0x%x\n",
634 		    __func__, ioc_status);
635 		error = ENXIO;
636 		goto out;
637 	}
638 	bcopy(page, config_page, MIN(cm->cm_length, sz));
639 out:
640 	free(page, M_MPT2);
641 	if (cm)
642 		mps_free_command(sc, cm);
643 	return (error);
644 }
645 
646 /**
647  * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
648  * @sc: per adapter object
649  * @mpi_reply: reply mf payload returned from firmware
650  * @config_page: contents of the config page
651  * @entry_idx: entry index in DPM Page0 to be modified
652  * Context: sleep.
653  *
654  * Returns 0 for success, non-zero for failure.
655  */
656 
657 int mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
658     Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
659 {
660 	MPI2_CONFIG_REQUEST *request;
661 	MPI2_CONFIG_REPLY *reply;
662 	struct mps_command *cm;
663 	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
664 	int error = 0;
665 	u16 ioc_status;
666 
667 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
668 
669 	if ((cm = mps_alloc_command(sc)) == NULL) {
670 		printf("%s: command alloc failed @ line %d\n", __func__,
671 		    __LINE__);
672 		error = EBUSY;
673 		goto out;
674 	}
675 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
676 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
677 	request->Function = MPI2_FUNCTION_CONFIG;
678 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
679 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
680 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
681 	request->Header.PageNumber = 0;
682 	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
683 	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
684 	request->PageAddress |= htole16(entry_idx);
685 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
686 	cm->cm_data = NULL;
687 	error = mps_request_polled(sc, cm);
688 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
689 	if (error || (reply == NULL)) {
690 		/* FIXME */
691 		/* If the poll returns error then we need to do diag reset */
692 		printf("%s: poll for header completed with error %d",
693 		    __func__, error);
694 		error = ENXIO;
695 		goto out;
696 	}
697 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
698 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
699 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
700 		/* FIXME */
701 		/* If the poll returns error then we need to do diag reset */
702 		printf("%s: header read with error; iocstatus = 0x%x\n",
703 		    __func__, ioc_status);
704 		error = ENXIO;
705 		goto out;
706 	}
707 	/* We have to do free and alloc for the reply-free and reply-post
708 	 * counters to match - Need to review the reply FIFO handling.
709 	 */
710 	mps_free_command(sc, cm);
711 
712 	if ((cm = mps_alloc_command(sc)) == NULL) {
713 		printf("%s: command alloc failed @ line %d\n", __func__,
714 		    __LINE__);
715 		error = EBUSY;
716 		goto out;
717 	}
718 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
719 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
720 	request->Function = MPI2_FUNCTION_CONFIG;
721 	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
722 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
723 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
724 	request->Header.PageNumber = 0;
725 	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
726 	request->ExtPageLength = mpi_reply->ExtPageLength;
727 	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
728 	request->PageAddress |= htole16(entry_idx);
729 	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
730 	cm->cm_sge = &request->PageBufferSGE;
731 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
732 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
733 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
734 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
735 	if (!page) {
736 		printf("%s: page alloc failed\n", __func__);
737 		error = ENOMEM;
738 		goto out;
739 	}
740 	bcopy(config_page, page, MIN(cm->cm_length,
741 	    (sizeof(Mpi2DriverMappingPage0_t))));
742 	cm->cm_data = page;
743 	error = mps_request_polled(sc, cm);
744 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
745 	if (error || (reply == NULL)) {
746 		/* FIXME */
747 		/* If the poll returns error then we need to do diag reset */
748 		printf("%s: poll for page completed with error %d",
749 		    __func__, error);
750 		error = ENXIO;
751 		goto out;
752 	}
753 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
754 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
755 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
756 		/* FIXME */
757 		/* If the poll returns error then we need to do diag reset */
758 		printf("%s: page written with error; iocstatus = 0x%x\n",
759 		    __func__, ioc_status);
760 		error = ENXIO;
761 		goto out;
762 	}
763 out:
764 	free(page, M_MPT2);
765 	if (cm)
766 		mps_free_command(sc, cm);
767 	return (error);
768 }
769 
770 /**
771  * mps_config_get_sas_device_pg0 - obtain sas device page 0
772  * @sc: per adapter object
773  * @mpi_reply: reply mf payload returned from firmware
774  * @config_page: contents of the config page
775  * @form: GET_NEXT_HANDLE or HANDLE
776  * @handle: device handle
777  * Context: sleep.
778  *
779  * Returns 0 for success, non-zero for failure.
780  */
781 int
782 mps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
783     *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
784 {
785 	MPI2_CONFIG_REQUEST *request;
786 	MPI2_CONFIG_REPLY *reply;
787 	struct mps_command *cm;
788 	Mpi2SasDevicePage0_t *page = NULL;
789 	int error = 0;
790 	u16 ioc_status;
791 
792 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
793 
794 	if ((cm = mps_alloc_command(sc)) == NULL) {
795 		printf("%s: command alloc failed @ line %d\n", __func__,
796 		    __LINE__);
797 		error = EBUSY;
798 		goto out;
799 	}
800 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
801 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
802 	request->Function = MPI2_FUNCTION_CONFIG;
803 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
804 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
805 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
806 	request->Header.PageNumber = 0;
807 	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
808 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
809 	cm->cm_data = NULL;
810 	error = mps_request_polled(sc, cm);
811 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
812 	if (error || (reply == NULL)) {
813 		/* FIXME */
814 		/* If the poll returns error then we need to do diag reset */
815 		printf("%s: poll for header completed with error %d",
816 		    __func__, error);
817 		error = ENXIO;
818 		goto out;
819 	}
820 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
821 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
822 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
823 		/* FIXME */
824 		/* If the poll returns error then we need to do diag reset */
825 		printf("%s: header read with error; iocstatus = 0x%x\n",
826 		    __func__, ioc_status);
827 		error = ENXIO;
828 		goto out;
829 	}
830 	/* We have to do free and alloc for the reply-free and reply-post
831 	 * counters to match - Need to review the reply FIFO handling.
832 	 */
833 	mps_free_command(sc, cm);
834 
835 	if ((cm = mps_alloc_command(sc)) == NULL) {
836 		printf("%s: command alloc failed @ line %d\n", __func__,
837 		    __LINE__);
838 		error = EBUSY;
839 		goto out;
840 	}
841 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
842 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
843 	request->Function = MPI2_FUNCTION_CONFIG;
844 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
845 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
846 	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
847 	request->Header.PageNumber = 0;
848 	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
849 	request->ExtPageLength = mpi_reply->ExtPageLength;
850 	request->PageAddress = htole32(form | handle);
851 	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
852 	cm->cm_sge = &request->PageBufferSGE;
853 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
854 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
855 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
856 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
857 	if (!page) {
858 		printf("%s: page alloc failed\n", __func__);
859 		error = ENOMEM;
860 		goto out;
861 	}
862 	cm->cm_data = page;
863 
864 	error = mps_request_polled(sc, cm);
865 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
866 	if (error || (reply == NULL)) {
867 		/* FIXME */
868 		/* If the poll returns error then we need to do diag reset */
869 		printf("%s: poll for page completed with error %d",
870 		    __func__, error);
871 		error = ENXIO;
872 		goto out;
873 	}
874 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
875 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
876 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
877 		/* FIXME */
878 		/* If the poll returns error then we need to do diag reset */
879 		printf("%s: page read with error; iocstatus = 0x%x\n",
880 		    __func__, ioc_status);
881 		error = ENXIO;
882 		goto out;
883 	}
884 	bcopy(page, config_page, MIN(cm->cm_length,
885 	    sizeof(Mpi2SasDevicePage0_t)));
886 out:
887 	free(page, M_MPT2);
888 	if (cm)
889 		mps_free_command(sc, cm);
890 	return (error);
891 }
892 
893 /**
894  * mps_config_get_bios_pg3 - obtain BIOS page 3
895  * @sc: per adapter object
896  * @mpi_reply: reply mf payload returned from firmware
897  * @config_page: contents of the config page
898  * Context: sleep.
899  *
900  * Returns 0 for success, non-zero for failure.
901  */
902 int
903 mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
904     Mpi2BiosPage3_t *config_page)
905 {
906 	MPI2_CONFIG_REQUEST *request;
907 	MPI2_CONFIG_REPLY *reply;
908 	struct mps_command *cm;
909 	Mpi2BiosPage3_t *page = NULL;
910 	int error = 0;
911 	u16 ioc_status;
912 
913 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
914 
915 	if ((cm = mps_alloc_command(sc)) == NULL) {
916 		printf("%s: command alloc failed @ line %d\n", __func__,
917 		    __LINE__);
918 		error = EBUSY;
919 		goto out;
920 	}
921 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
922 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
923 	request->Function = MPI2_FUNCTION_CONFIG;
924 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
925 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
926 	request->Header.PageNumber = 3;
927 	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
928 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
929 	cm->cm_data = NULL;
930 	error = mps_request_polled(sc, cm);
931 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
932 	if (error || (reply == NULL)) {
933 		/* FIXME */
934 		/* If the poll returns error then we need to do diag reset */
935 		printf("%s: poll for header completed with error %d",
936 		    __func__, error);
937 		error = ENXIO;
938 		goto out;
939 	}
940 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
941 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
942 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
943 		/* FIXME */
944 		/* If the poll returns error then we need to do diag reset */
945 		printf("%s: header read with error; iocstatus = 0x%x\n",
946 		    __func__, ioc_status);
947 		error = ENXIO;
948 		goto out;
949 	}
950 	/* We have to do free and alloc for the reply-free and reply-post
951 	 * counters to match - Need to review the reply FIFO handling.
952 	 */
953 	mps_free_command(sc, cm);
954 
955 	if ((cm = mps_alloc_command(sc)) == NULL) {
956 		printf("%s: command alloc failed @ line %d\n", __func__,
957 		    __LINE__);
958 		error = EBUSY;
959 		goto out;
960 	}
961 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
962 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
963 	request->Function = MPI2_FUNCTION_CONFIG;
964 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
965 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
966 	request->Header.PageNumber = 3;
967 	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
968 	request->Header.PageLength = mpi_reply->Header.PageLength;
969 	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
970 	cm->cm_sge = &request->PageBufferSGE;
971 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
972 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
973 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
974 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
975 	if (!page) {
976 		printf("%s: page alloc failed\n", __func__);
977 		error = ENOMEM;
978 		goto out;
979 	}
980 	cm->cm_data = page;
981 
982 	error = mps_request_polled(sc, cm);
983 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
984 	if (error || (reply == NULL)) {
985 		/* FIXME */
986 		/* If the poll returns error then we need to do diag reset */
987 		printf("%s: poll for page completed with error %d",
988 		    __func__, error);
989 		error = ENXIO;
990 		goto out;
991 	}
992 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
993 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
994 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
995 		/* FIXME */
996 		/* If the poll returns error then we need to do diag reset */
997 		printf("%s: page read with error; iocstatus = 0x%x\n",
998 		    __func__, ioc_status);
999 		error = ENXIO;
1000 		goto out;
1001 	}
1002 	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
1003 out:
1004 	free(page, M_MPT2);
1005 	if (cm)
1006 		mps_free_command(sc, cm);
1007 	return (error);
1008 }
1009 
1010 /**
1011  * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
1012  * @sc: per adapter object
1013  * @mpi_reply: reply mf payload returned from firmware
1014  * @config_page: contents of the config page
1015  * @page_address: form and handle value used to get page
1016  * Context: sleep.
1017  *
1018  * Returns 0 for success, non-zero for failure.
1019  */
1020 int
1021 mps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
1022     *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
1023 {
1024 	MPI2_CONFIG_REQUEST *request;
1025 	MPI2_CONFIG_REPLY *reply;
1026 	struct mps_command *cm;
1027 	Mpi2RaidVolPage0_t *page = NULL;
1028 	int error = 0;
1029 	u16 ioc_status;
1030 
1031 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1032 
1033 	if ((cm = mps_alloc_command(sc)) == NULL) {
1034 		printf("%s: command alloc failed @ line %d\n", __func__,
1035 		    __LINE__);
1036 		error = EBUSY;
1037 		goto out;
1038 	}
1039 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1040 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1041 	request->Function = MPI2_FUNCTION_CONFIG;
1042 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1043 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1044 	request->Header.PageNumber = 0;
1045 	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1046 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1047 	cm->cm_data = NULL;
1048 	error = mps_request_polled(sc, cm);
1049 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1050 	if (error || (reply == NULL)) {
1051 		/* FIXME */
1052 		/* If the poll returns error then we need to do diag reset */
1053 		printf("%s: poll for header completed with error %d",
1054 		    __func__, error);
1055 		error = ENXIO;
1056 		goto out;
1057 	}
1058 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1059 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1060 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1061 		/* FIXME */
1062 		/* If the poll returns error then we need to do diag reset */
1063 		printf("%s: header read with error; iocstatus = 0x%x\n",
1064 		    __func__, ioc_status);
1065 		error = ENXIO;
1066 		goto out;
1067 	}
1068 	/* We have to do free and alloc for the reply-free and reply-post
1069 	 * counters to match - Need to review the reply FIFO handling.
1070 	 */
1071 	mps_free_command(sc, cm);
1072 
1073 	if ((cm = mps_alloc_command(sc)) == NULL) {
1074 		printf("%s: command alloc failed @ line %d\n", __func__,
1075 		    __LINE__);
1076 		error = EBUSY;
1077 		goto out;
1078 	}
1079 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1080 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1081 	request->Function = MPI2_FUNCTION_CONFIG;
1082 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1083 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1084 	request->Header.PageNumber = 0;
1085 	request->Header.PageLength = mpi_reply->Header.PageLength;
1086 	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1087 	request->PageAddress = page_address;
1088 	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1089 	cm->cm_sge = &request->PageBufferSGE;
1090 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1091 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1092 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1093 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1094 	if (!page) {
1095 		printf("%s: page alloc failed\n", __func__);
1096 		error = ENOMEM;
1097 		goto out;
1098 	}
1099 	cm->cm_data = page;
1100 
1101 	error = mps_request_polled(sc, cm);
1102 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1103 	if (error || (reply == NULL)) {
1104 		/* FIXME */
1105 		/* If the poll returns error then we need to do diag reset */
1106 		printf("%s: poll for page completed with error %d",
1107 		    __func__, error);
1108 		error = ENXIO;
1109 		goto out;
1110 	}
1111 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1112 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1113 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1114 		/* FIXME */
1115 		/* If the poll returns error then we need to do diag reset */
1116 		printf("%s: page read with error; iocstatus = 0x%x\n",
1117 		    __func__, ioc_status);
1118 		error = ENXIO;
1119 		goto out;
1120 	}
1121 	bcopy(page, config_page, cm->cm_length);
1122 out:
1123 	free(page, M_MPT2);
1124 	if (cm)
1125 		mps_free_command(sc, cm);
1126 	return (error);
1127 }
1128 
1129 /**
1130  * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
1131  * @sc: per adapter object
1132  * @mpi_reply: reply mf payload returned from firmware
1133  * @config_page: contents of the config page
1134  * @form: GET_NEXT_HANDLE or HANDLE
1135  * @handle: volume handle
1136  * Context: sleep.
1137  *
1138  * Returns 0 for success, non-zero for failure.
1139  */
1140 int
1141 mps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
1142     *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
1143 {
1144 	MPI2_CONFIG_REQUEST *request;
1145 	MPI2_CONFIG_REPLY *reply;
1146 	struct mps_command *cm;
1147 	Mpi2RaidVolPage1_t *page = NULL;
1148 	int error = 0;
1149 	u16 ioc_status;
1150 
1151 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1152 
1153 	if ((cm = mps_alloc_command(sc)) == NULL) {
1154 		printf("%s: command alloc failed @ line %d\n", __func__,
1155 		    __LINE__);
1156 		error = EBUSY;
1157 		goto out;
1158 	}
1159 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1160 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1161 	request->Function = MPI2_FUNCTION_CONFIG;
1162 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1163 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1164 	request->Header.PageNumber = 1;
1165 	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1166 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1167 	cm->cm_data = NULL;
1168 	error = mps_request_polled(sc, cm);
1169 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1170 	if (error || (reply == NULL)) {
1171 		/* FIXME */
1172 		/* If the poll returns error then we need to do diag reset */
1173 		printf("%s: poll for header completed with error %d",
1174 		    __func__, error);
1175 		error = ENXIO;
1176 		goto out;
1177 	}
1178 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1179 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1180 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1181 		/* FIXME */
1182 		/* If the poll returns error then we need to do diag reset */
1183 		printf("%s: header read with error; iocstatus = 0x%x\n",
1184 		    __func__, ioc_status);
1185 		error = ENXIO;
1186 		goto out;
1187 	}
1188 	/* We have to do free and alloc for the reply-free and reply-post
1189 	 * counters to match - Need to review the reply FIFO handling.
1190 	 */
1191 	mps_free_command(sc, cm);
1192 
1193 	if ((cm = mps_alloc_command(sc)) == NULL) {
1194 		printf("%s: command alloc failed @ line %d\n", __func__,
1195 		    __LINE__);
1196 		error = EBUSY;
1197 		goto out;
1198 	}
1199 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1200 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1201 	request->Function = MPI2_FUNCTION_CONFIG;
1202 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1203 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1204 	request->Header.PageNumber = 1;
1205 	request->Header.PageLength = mpi_reply->Header.PageLength;
1206 	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1207 	request->PageAddress = htole32(form | handle);
1208 	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1209 	cm->cm_sge = &request->PageBufferSGE;
1210 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1211 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1212 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1213 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1214 	if (!page) {
1215 		printf("%s: page alloc failed\n", __func__);
1216 		error = ENOMEM;
1217 		goto out;
1218 	}
1219 	cm->cm_data = page;
1220 
1221 	error = mps_request_polled(sc, cm);
1222 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1223 	if (error || (reply == NULL)) {
1224 		/* FIXME */
1225 		/* If the poll returns error then we need to do diag reset */
1226 		printf("%s: poll for page completed with error %d",
1227 		    __func__, error);
1228 		error = ENXIO;
1229 		goto out;
1230 	}
1231 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1232 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1233 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1234 		/* FIXME */
1235 		/* If the poll returns error then we need to do diag reset */
1236 		printf("%s: page read with error; iocstatus = 0x%x\n",
1237 		    __func__, ioc_status);
1238 		error = ENXIO;
1239 		goto out;
1240 	}
1241 	bcopy(page, config_page, MIN(cm->cm_length,
1242 	    sizeof(Mpi2RaidVolPage1_t)));
1243 out:
1244 	free(page, M_MPT2);
1245 	if (cm)
1246 		mps_free_command(sc, cm);
1247 	return (error);
1248 }
1249 
1250 /**
1251  * mps_config_get_volume_wwid - returns wwid given the volume handle
1252  * @sc: per adapter object
1253  * @volume_handle: volume handle
1254  * @wwid: volume wwid
1255  * Context: sleep.
1256  *
1257  * Returns 0 for success, non-zero for failure.
1258  */
1259 int
1260 mps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
1261 {
1262 	Mpi2ConfigReply_t mpi_reply;
1263 	Mpi2RaidVolPage1_t raid_vol_pg1;
1264 
1265 	*wwid = 0;
1266 	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
1267 	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
1268 		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
1269 		    raid_vol_pg1.WWID.Low);
1270 		return 0;
1271 	} else
1272 		return -1;
1273 }
1274 
1275 /**
1276  * mps_config_get_pd_pg0 - obtain raid phys disk page 0
1277  * @sc: per adapter object
1278  * @mpi_reply: reply mf payload returned from firmware
1279  * @config_page: contents of the config page
1280  * @page_address: form and handle value used to get page
1281  * Context: sleep.
1282  *
1283  * Returns 0 for success, non-zero for failure.
1284  */
1285 int
1286 mps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
1287     Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
1288 {
1289 	MPI2_CONFIG_REQUEST *request;
1290 	MPI2_CONFIG_REPLY *reply;
1291 	struct mps_command *cm;
1292 	Mpi2RaidPhysDiskPage0_t *page = NULL;
1293 	int error = 0;
1294 	u16 ioc_status;
1295 
1296 	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1297 
1298 	if ((cm = mps_alloc_command(sc)) == NULL) {
1299 		printf("%s: command alloc failed @ line %d\n", __func__,
1300 		    __LINE__);
1301 		error = EBUSY;
1302 		goto out;
1303 	}
1304 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1305 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1306 	request->Function = MPI2_FUNCTION_CONFIG;
1307 	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1308 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1309 	request->Header.PageNumber = 0;
1310 	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1311 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1312 	cm->cm_data = NULL;
1313 	error = mps_request_polled(sc, cm);
1314 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1315 	if (error || (reply == NULL)) {
1316 		/* FIXME */
1317 		/* If the poll returns error then we need to do diag reset */
1318 		printf("%s: poll for header completed with error %d",
1319 		    __func__, error);
1320 		error = ENXIO;
1321 		goto out;
1322 	}
1323 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1324 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1325 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1326 		/* FIXME */
1327 		/* If the poll returns error then we need to do diag reset */
1328 		printf("%s: header read with error; iocstatus = 0x%x\n",
1329 		    __func__, ioc_status);
1330 		error = ENXIO;
1331 		goto out;
1332 	}
1333 	/* We have to do free and alloc for the reply-free and reply-post
1334 	 * counters to match - Need to review the reply FIFO handling.
1335 	 */
1336 	mps_free_command(sc, cm);
1337 
1338 	if ((cm = mps_alloc_command(sc)) == NULL) {
1339 		printf("%s: command alloc failed @ line %d\n", __func__,
1340 		    __LINE__);
1341 		error = EBUSY;
1342 		goto out;
1343 	}
1344 	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1345 	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1346 	request->Function = MPI2_FUNCTION_CONFIG;
1347 	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1348 	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1349 	request->Header.PageNumber = 0;
1350 	request->Header.PageLength = mpi_reply->Header.PageLength;
1351 	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1352 	request->PageAddress = page_address;
1353 	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1354 	cm->cm_sge = &request->PageBufferSGE;
1355 	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1356 	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1357 	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1358 	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1359 	if (!page) {
1360 		printf("%s: page alloc failed\n", __func__);
1361 		error = ENOMEM;
1362 		goto out;
1363 	}
1364 	cm->cm_data = page;
1365 
1366 	error = mps_request_polled(sc, cm);
1367 	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1368 	if (error || (reply == NULL)) {
1369 		/* FIXME */
1370 		/* If the poll returns error then we need to do diag reset */
1371 		printf("%s: poll for page completed with error %d",
1372 		    __func__, error);
1373 		error = ENXIO;
1374 		goto out;
1375 	}
1376 	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1377 	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1378 	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1379 		/* FIXME */
1380 		/* If the poll returns error then we need to do diag reset */
1381 		printf("%s: page read with error; iocstatus = 0x%x\n",
1382 		    __func__, ioc_status);
1383 		error = ENXIO;
1384 		goto out;
1385 	}
1386 	bcopy(page, config_page, MIN(cm->cm_length,
1387 	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1388 out:
1389 	free(page, M_MPT2);
1390 	if (cm)
1391 		mps_free_command(sc, cm);
1392 	return (error);
1393 }
1394