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