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