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