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