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