1230592Sken/*-
2281564Sslm * Copyright (c) 2011-2015 LSI Corp.
3281564Sslm * Copyright (c) 2013-2015 Avago Technologies
4230592Sken * All rights reserved.
5230592Sken *
6230592Sken * Redistribution and use in source and binary forms, with or without
7230592Sken * modification, are permitted provided that the following conditions
8230592Sken * are met:
9230592Sken * 1. Redistributions of source code must retain the above copyright
10230592Sken *    notice, this list of conditions and the following disclaimer.
11230592Sken * 2. Redistributions in binary form must reproduce the above copyright
12230592Sken *    notice, this list of conditions and the following disclaimer in the
13230592Sken *    documentation and/or other materials provided with the distribution.
14230592Sken *
15230592Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16230592Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17230592Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18230592Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19230592Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20230592Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21230592Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22230592Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23230592Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24230592Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25230592Sken * SUCH DAMAGE.
26230592Sken *
27281564Sslm * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
28230592Sken */
29230592Sken
30230592Sken#include <sys/cdefs.h>
31230592Sken__FBSDID("$FreeBSD: stable/10/sys/dev/mps/mps_config.c 322661 2017-08-18 15:38:08Z ken $");
32230592Sken
33230592Sken/* TODO Move headers to mpsvar */
34230592Sken#include <sys/types.h>
35230592Sken#include <sys/param.h>
36230592Sken#include <sys/lock.h>
37230592Sken#include <sys/mutex.h>
38230592Sken#include <sys/systm.h>
39230592Sken#include <sys/kernel.h>
40230592Sken#include <sys/malloc.h>
41230592Sken#include <sys/kthread.h>
42230592Sken#include <sys/taskqueue.h>
43230592Sken#include <sys/bus.h>
44230592Sken#include <sys/endian.h>
45230592Sken#include <sys/sysctl.h>
46230592Sken#include <sys/eventhandler.h>
47230592Sken#include <sys/uio.h>
48230592Sken#include <machine/bus.h>
49230592Sken#include <machine/resource.h>
50230592Sken#include <dev/mps/mpi/mpi2_type.h>
51230592Sken#include <dev/mps/mpi/mpi2.h>
52230592Sken#include <dev/mps/mpi/mpi2_ioc.h>
53230592Sken#include <dev/mps/mpi/mpi2_sas.h>
54230592Sken#include <dev/mps/mpi/mpi2_cnfg.h>
55230592Sken#include <dev/mps/mpi/mpi2_init.h>
56230592Sken#include <dev/mps/mpi/mpi2_tool.h>
57230592Sken#include <dev/mps/mps_ioctl.h>
58230592Sken#include <dev/mps/mpsvar.h>
59230592Sken
60230592Sken/**
61230592Sken * mps_config_get_ioc_pg8 - obtain ioc page 8
62230592Sken * @sc: per adapter object
63230592Sken * @mpi_reply: reply mf payload returned from firmware
64230592Sken * @config_page: contents of the config page
65230592Sken * Context: sleep.
66230592Sken *
67230592Sken * Returns 0 for success, non-zero for failure.
68230592Sken */
69230592Skenint
70230592Skenmps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
71230592Sken    Mpi2IOCPage8_t *config_page)
72230592Sken{
73230592Sken	MPI2_CONFIG_REQUEST *request;
74322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
75230592Sken	struct mps_command *cm;
76230592Sken	MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
77230592Sken	int error = 0;
78230592Sken	u16 ioc_status;
79230592Sken
80230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
81230592Sken
82230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
83230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
84230592Sken		    __LINE__);
85230592Sken		error = EBUSY;
86230592Sken		goto out;
87230592Sken	}
88230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
89230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
90230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
91230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
92230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
93230592Sken	request->Header.PageNumber = 8;
94230592Sken	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
95230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
96230592Sken	cm->cm_data = NULL;
97322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
98322661Sken	if (cm != NULL)
99322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
100230592Sken	if (error || (reply == NULL)) {
101230592Sken		/* FIXME */
102253550Sken		/*
103253550Sken		 * If the request returns an error then we need to do a diag
104253550Sken		 * reset
105253550Sken		 */
106253550Sken		printf("%s: request for header completed with error %d",
107230592Sken		    __func__, error);
108230592Sken		error = ENXIO;
109230592Sken		goto out;
110230592Sken	}
111230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
112230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
113230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
114230592Sken		/* FIXME */
115253550Sken		/*
116253550Sken		 * If the request returns an error then we need to do a diag
117253550Sken		 * reset
118253550Sken		 */
119230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
120230592Sken		    __func__, ioc_status);
121230592Sken		error = ENXIO;
122230592Sken		goto out;
123230592Sken	}
124230592Sken	/* We have to do free and alloc for the reply-free and reply-post
125230592Sken	 * counters to match - Need to review the reply FIFO handling.
126230592Sken	 */
127230592Sken	mps_free_command(sc, cm);
128230592Sken
129230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
130230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
131230592Sken		    __LINE__);
132230592Sken		error = EBUSY;
133230592Sken		goto out;
134230592Sken	}
135230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
136230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
137230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
138230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
139230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
140230592Sken	request->Header.PageNumber = 8;
141230592Sken	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
142230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
143230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
144230592Sken	cm->cm_sge = &request->PageBufferSGE;
145230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
146230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
147230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
148230592Sken	page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
149230592Sken	if (!page) {
150230592Sken		printf("%s: page alloc failed\n", __func__);
151230592Sken		error = ENOMEM;
152230592Sken		goto out;
153230592Sken	}
154230592Sken	cm->cm_data = page;
155253550Sken
156322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
157322661Sken	if (cm != NULL)
158322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
159230592Sken	if (error || (reply == NULL)) {
160230592Sken		/* FIXME */
161253550Sken		/*
162253550Sken		 * If the request returns an error then we need to do a diag
163253550Sken		 * reset
164253550Sken		 */
165253550Sken		printf("%s: request for page completed with error %d",
166230592Sken		    __func__, error);
167230592Sken		error = ENXIO;
168230592Sken		goto out;
169230592Sken	}
170230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
171230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
172230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
173230592Sken		/* FIXME */
174253550Sken		/*
175253550Sken		 * If the request returns an error then we need to do a diag
176253550Sken		 * reset
177253550Sken		 */
178230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
179230592Sken		    __func__, ioc_status);
180230592Sken		error = ENXIO;
181230592Sken		goto out;
182230592Sken	}
183230592Sken	bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
184230592Sken
185230592Skenout:
186230592Sken	free(page, M_MPT2);
187230592Sken	if (cm)
188230592Sken		mps_free_command(sc, cm);
189230592Sken	return (error);
190230592Sken}
191230592Sken
192230592Sken/**
193230592Sken * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
194230592Sken *   accordingly.  Currently, this page does not need to return to caller.
195230592Sken * @sc: per adapter object
196230592Sken * @mpi_reply: reply mf payload returned from firmware
197230592Sken * Context: sleep.
198230592Sken *
199230592Sken * Returns 0 for success, non-zero for failure.
200230592Sken */
201230592Skenint
202230592Skenmps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
203230592Sken{
204230592Sken	MPI2_CONFIG_REQUEST *request;
205322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
206230592Sken	struct mps_command *cm;
207230592Sken	pMpi2ManufacturingPagePS_t page = NULL;
208230592Sken	uint32_t *pPS_info;
209230592Sken	uint8_t OEM_Value = 0;
210230592Sken	int error = 0;
211230592Sken	u16 ioc_status;
212230592Sken
213230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
214230592Sken
215230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
216230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
217230592Sken		    __LINE__);
218230592Sken		error = EBUSY;
219230592Sken		goto out;
220230592Sken	}
221230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
222230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
223230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
224230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
225230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
226230592Sken	request->Header.PageNumber = 10;
227230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
228230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
229230592Sken	cm->cm_data = NULL;
230253550Sken
231253550Sken	/*
232253550Sken	 * This page must be polled because the IOC isn't ready yet when this
233253550Sken	 * page is needed.
234253550Sken	 */
235322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
236322661Sken	if (cm != NULL)
237322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
238230592Sken	if (error || (reply == NULL)) {
239230592Sken		/* FIXME */
240230592Sken		/* If the poll returns error then we need to do diag reset */
241230592Sken		printf("%s: poll for header completed with error %d",
242230592Sken		    __func__, error);
243230592Sken		error = ENXIO;
244230592Sken		goto out;
245230592Sken	}
246230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
247230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
248230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
249230592Sken		/* FIXME */
250230592Sken		/* If the poll returns error then we need to do diag reset */
251230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
252230592Sken		    __func__, ioc_status);
253230592Sken		error = ENXIO;
254230592Sken		goto out;
255230592Sken	}
256230592Sken	/* We have to do free and alloc for the reply-free and reply-post
257230592Sken	 * counters to match - Need to review the reply FIFO handling.
258230592Sken	 */
259230592Sken	mps_free_command(sc, cm);
260230592Sken
261230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
262230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
263230592Sken		    __LINE__);
264230592Sken		error = EBUSY;
265230592Sken		goto out;
266230592Sken	}
267230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
268230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
269230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
270230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
271230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
272230592Sken	request->Header.PageNumber = 10;
273230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
274230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
275230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
276230592Sken	cm->cm_sge = &request->PageBufferSGE;
277230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
278230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
279230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
280230592Sken	page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
281230592Sken	if (!page) {
282230592Sken		printf("%s: page alloc failed\n", __func__);
283230592Sken		error = ENOMEM;
284230592Sken		goto out;
285230592Sken	}
286230592Sken	cm->cm_data = page;
287253550Sken
288253550Sken	/*
289253550Sken	 * This page must be polled because the IOC isn't ready yet when this
290253550Sken	 * page is needed.
291253550Sken	 */
292322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
293322661Sken	if (cm != NULL)
294322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
295230592Sken	if (error || (reply == NULL)) {
296230592Sken		/* FIXME */
297230592Sken		/* If the poll returns error then we need to do diag reset */
298230592Sken		printf("%s: poll for page completed with error %d",
299230592Sken		    __func__, error);
300230592Sken		error = ENXIO;
301230592Sken		goto out;
302230592Sken	}
303230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
304230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
305230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
306230592Sken		/* FIXME */
307230592Sken		/* If the poll returns error then we need to do diag reset */
308230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
309230592Sken		    __func__, ioc_status);
310230592Sken		error = ENXIO;
311230592Sken		goto out;
312230592Sken	}
313230592Sken
314230592Sken	/*
315230592Sken	 * If OEM ID is unknown, fail the request.
316230592Sken	 */
317230592Sken	sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
318230592Sken	OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
319230592Sken	if (OEM_Value != MPS_WD_LSI_OEM) {
320230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
321230592Sken		    "(0x%x)\n", OEM_Value);
322230592Sken		error = ENXIO;
323230592Sken		goto out;
324230592Sken	}
325230592Sken
326230592Sken	/*
327230592Sken	 * Set the phys disks hide/expose value.
328230592Sken	 */
329230592Sken	pPS_info = &page->ProductSpecificInfo;
330230592Sken	sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
331230592Sken	sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
332230592Sken	if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
333230592Sken	    (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
334230592Sken	    (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
335230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
336230592Sken		    "hide/expose: 0x%x\n", sc->WD_hide_expose);
337230592Sken		error = ENXIO;
338230592Sken		goto out;
339230592Sken	}
340230592Sken
341230592Skenout:
342230592Sken	free(page, M_MPT2);
343230592Sken	if (cm)
344230592Sken		mps_free_command(sc, cm);
345230592Sken	return (error);
346230592Sken}
347230592Sken
348230592Sken/**
349230592Sken * mps_base_static_config_pages - static start of day config pages.
350230592Sken * @sc: per adapter object
351230592Sken *
352230592Sken * Return nothing.
353230592Sken */
354230592Skenvoid
355230592Skenmps_base_static_config_pages(struct mps_softc *sc)
356230592Sken{
357230592Sken	Mpi2ConfigReply_t	mpi_reply;
358230592Sken	int			retry;
359230592Sken
360230592Sken	retry = 0;
361230592Sken	while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
362230592Sken		retry++;
363230592Sken		if (retry > 5) {
364230592Sken			/* We need to Handle this situation */
365230592Sken			/*FIXME*/
366230592Sken			break;
367230592Sken		}
368230592Sken	}
369230592Sken}
370230592Sken
371230592Sken/**
372230592Sken * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
373230592Sken *    be called after discovery is complete to guarentee that IR info is there.
374230592Sken * @sc: per adapter object
375230592Sken *
376230592Sken * Return nothing.
377230592Sken */
378230592Skenvoid
379230592Skenmps_wd_config_pages(struct mps_softc *sc)
380230592Sken{
381230592Sken	Mpi2ConfigReply_t	mpi_reply;
382230592Sken	pMpi2RaidVolPage0_t	raid_vol_pg0 = NULL;
383230592Sken	Mpi2RaidPhysDiskPage0_t	phys_disk_pg0;
384230592Sken	pMpi2RaidVol0PhysDisk_t	pRVPD;
385230592Sken	uint32_t		stripe_size, phys_disk_page_address;
386230592Sken	uint16_t		block_size;
387230592Sken	uint8_t			index, stripe_exp = 0, block_exp = 0;
388230592Sken
389230592Sken	/*
390230592Sken	 * Get the WD settings from manufacturing page 10 if using a WD HBA.
391230592Sken	 * This will be used to determine if phys disks should always be
392230592Sken	 * hidden, hidden only if part of a WD volume, or never hidden.  Also,
393230592Sken	 * get the WD RAID Volume info and fail if volume does not exist or if
394230592Sken	 * volume does not meet the requirements for a WD volume.  No retry
395230592Sken	 * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
396230592Sken	 * Valid flag if Volume info fails.
397230592Sken	 */
398230592Sken	sc->WD_valid_config = FALSE;
399230592Sken	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
400230592Sken		if (mps_config_get_man_pg10(sc, &mpi_reply)) {
401230592Sken			mps_dprint(sc, MPS_FAULT,
402230592Sken			    "mps_config_get_man_pg10 failed! Using 0 (Hide "
403230592Sken			    "Always) for WarpDrive hide/expose value.\n");
404230592Sken			sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
405230592Sken		}
406230592Sken
407230592Sken		/*
408230592Sken		 * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
409230592Sken		 */
410230592Sken		raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) +
411230592Sken		    (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
412230592Sken		    M_MPT2, M_ZERO | M_NOWAIT);
413230592Sken		if (!raid_vol_pg0) {
414230592Sken			printf("%s: page alloc failed\n", __func__);
415230592Sken			goto out;
416230592Sken		}
417230592Sken
418230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
419230592Sken		    0x0000FFFF)) {
420230592Sken			mps_dprint(sc, MPS_INFO,
421230592Sken			    "mps_config_get_raid_volume_pg0 failed! Assuming "
422230592Sken			    "WarpDrive IT mode.\n");
423230592Sken			goto out;
424230592Sken		}
425230592Sken
426230592Sken		/*
427230592Sken		 * Check for valid WD configuration:
428230592Sken		 *   volume type is RAID0
429230592Sken		 *   number of phys disks in the volume is no more than 8
430230592Sken		 */
431230592Sken		if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
432230592Sken		    (raid_vol_pg0->NumPhysDisks > 8)) {
433230592Sken			mps_dprint(sc, MPS_FAULT,
434230592Sken			    "Invalid WarpDrive configuration. Direct Drive I/O "
435230592Sken			    "will not be used.\n");
436230592Sken			goto out;
437230592Sken		}
438230592Sken
439230592Sken		/*
440230592Sken		 * Save the WD RAID data to be used during WD I/O.
441230592Sken		 */
442230592Sken		sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
443230592Sken		    32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
444230592Sken		sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
445230592Sken		sc->DD_dev_handle = raid_vol_pg0->DevHandle;
446230592Sken		sc->DD_stripe_size = raid_vol_pg0->StripeSize;
447230592Sken		sc->DD_block_size = raid_vol_pg0->BlockSize;
448230592Sken
449230592Sken		/*
450230592Sken		 * Find power of 2 of stripe size and set this as the exponent.
451230592Sken		 * Fail if stripe size is 0.
452230592Sken		 */
453230592Sken		stripe_size = raid_vol_pg0->StripeSize;
454230592Sken		for (index = 0; index < 32; index++) {
455230592Sken			if (stripe_size & 1)
456230592Sken				break;
457230592Sken			stripe_exp++;
458230592Sken			stripe_size >>= 1;
459230592Sken		}
460230592Sken		if (index == 32) {
461230592Sken			mps_dprint(sc, MPS_FAULT,
462230592Sken			    "RAID Volume's stripe size is 0. Direct Drive I/O "
463230592Sken			    "will not be used.\n");
464230592Sken			goto out;
465230592Sken		}
466230592Sken		sc->DD_stripe_exponent = stripe_exp;
467230592Sken
468230592Sken		/*
469230592Sken		 * Find power of 2 of block size and set this as the exponent.
470230592Sken		 * Fail if block size is 0.
471230592Sken		 */
472230592Sken		block_size = raid_vol_pg0->BlockSize;
473230592Sken		for (index = 0; index < 16; index++) {
474230592Sken			if (block_size & 1)
475230592Sken				break;
476230592Sken			block_exp++;
477230592Sken			block_size >>= 1;
478230592Sken		}
479230592Sken		if (index == 16) {
480230592Sken			mps_dprint(sc, MPS_FAULT,
481230592Sken			    "RAID Volume's block size is 0. Direct Drive I/O "
482230592Sken			    "will not be used.\n");
483230592Sken			goto out;
484230592Sken		}
485230592Sken		sc->DD_block_exponent = block_exp;
486230592Sken
487230592Sken		/*
488230592Sken		 * Loop through all of the volume's Phys Disks to map the phys
489230592Sken		 * disk number into the columm map.  This is used during Direct
490230592Sken		 * Drive I/O to send the request to the correct SSD.
491230592Sken		 */
492230592Sken		pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
493230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
494230592Sken			sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
495230592Sken			    pRVPD->PhysDiskNum;
496230592Sken			pRVPD++;
497230592Sken		}
498230592Sken
499230592Sken		/*
500230592Sken		 * Get second RAID Volume Page0 using previous handle.  This
501230592Sken		 * page should not exist.  If it does, must not proceed with WD
502230592Sken		 * handling.
503230592Sken		 */
504230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
505230592Sken		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
506302225Sslm			if ((le16toh(mpi_reply.IOCStatus) &
507302225Sslm			    MPI2_IOCSTATUS_MASK) !=
508230592Sken			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
509230592Sken				mps_dprint(sc, MPS_FAULT,
510230592Sken				    "Multiple RAID Volume Page0! Direct Drive "
511230592Sken				    "I/O will not be used.\n");
512230592Sken				goto out;
513230592Sken			}
514230592Sken		} else {
515230592Sken			mps_dprint(sc, MPS_FAULT,
516230592Sken			    "Multiple volumes! Direct Drive I/O will not be "
517230592Sken			    "used.\n");
518230592Sken			goto out;
519230592Sken		}
520230592Sken
521230592Sken		/*
522230592Sken		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
523230592Sken		 */
524230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
525230592Sken			phys_disk_page_address =
526230592Sken			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
527230592Sken			    sc->DD_column_map[index].phys_disk_num;
528230592Sken			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
529230592Sken			    &phys_disk_pg0, phys_disk_page_address)) {
530230592Sken				mps_dprint(sc, MPS_FAULT,
531230592Sken				    "mps_config_get_raid_pd_pg0 failed! Direct "
532230592Sken				    "Drive I/O will not be used.\n");
533230592Sken				goto out;
534230592Sken			}
535230592Sken			if (phys_disk_pg0.DevHandle == 0xFFFF) {
536230592Sken				mps_dprint(sc, MPS_FAULT,
537230592Sken				    "Invalid Phys Disk DevHandle! Direct Drive "
538230592Sken				    "I/O will not be used.\n");
539230592Sken				goto out;
540230592Sken			}
541230592Sken			sc->DD_column_map[index].dev_handle =
542230592Sken			    phys_disk_pg0.DevHandle;
543230592Sken		}
544230592Sken		sc->WD_valid_config = TRUE;
545230592Skenout:
546230592Sken		if (raid_vol_pg0)
547230592Sken			free(raid_vol_pg0, M_MPT2);
548230592Sken	}
549230592Sken}
550230592Sken
551230592Sken/**
552230592Sken * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
553230592Sken * @sc: per adapter object
554230592Sken * @mpi_reply: reply mf payload returned from firmware
555230592Sken * @config_page: contents of the config page
556230592Sken * @sz: size of buffer passed in config_page
557230592Sken * Context: sleep.
558230592Sken *
559230592Sken * Returns 0 for success, non-zero for failure.
560230592Sken */
561230592Skenint
562230592Skenmps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
563230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 sz)
564230592Sken{
565230592Sken	MPI2_CONFIG_REQUEST *request;
566322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
567230592Sken	struct mps_command *cm;
568230592Sken	Mpi2DriverMappingPage0_t *page = NULL;
569230592Sken	int error = 0;
570230592Sken	u16 ioc_status;
571230592Sken
572230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
573230592Sken
574230592Sken	memset(config_page, 0, sz);
575230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
576230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
577230592Sken		    __LINE__);
578230592Sken		error = EBUSY;
579230592Sken		goto out;
580230592Sken	}
581230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
582230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
583230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
584230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
585230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
586230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
587230592Sken	request->Header.PageNumber = 0;
588230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
589230592Sken	request->PageAddress = sc->max_dpm_entries <<
590230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
591230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
592230592Sken	cm->cm_data = NULL;
593322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
594322661Sken	if (cm != NULL)
595322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
596230592Sken	if (error || (reply == NULL)) {
597230592Sken		/* FIXME */
598253550Sken		/*
599253550Sken		 * If the request returns an error then we need to do a diag
600253550Sken		 * reset
601253550Sken		 */
602253550Sken		printf("%s: request for header completed with error %d",
603230592Sken		    __func__, error);
604230592Sken		error = ENXIO;
605230592Sken		goto out;
606230592Sken	}
607230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
608230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
609230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
610230592Sken		/* FIXME */
611253550Sken		/*
612253550Sken		 * If the request returns an error then we need to do a diag
613253550Sken		 * reset
614253550Sken		 */
615230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
616230592Sken		    __func__, ioc_status);
617230592Sken		error = ENXIO;
618230592Sken		goto out;
619230592Sken	}
620230592Sken	/* We have to do free and alloc for the reply-free and reply-post
621230592Sken	 * counters to match - Need to review the reply FIFO handling.
622230592Sken	 */
623230592Sken	mps_free_command(sc, cm);
624230592Sken
625230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
626230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
627230592Sken		    __LINE__);
628230592Sken		error = EBUSY;
629230592Sken		goto out;
630230592Sken	}
631230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
632230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
633230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
634230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
635230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
636230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
637230592Sken	request->Header.PageNumber = 0;
638230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
639230592Sken	request->PageAddress = sc->max_dpm_entries <<
640230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
641230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
642230592Sken	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
643230592Sken	cm->cm_sge = &request->PageBufferSGE;
644230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
645230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
646230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
647230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
648230592Sken	if (!page) {
649230592Sken		printf("%s: page alloc failed\n", __func__);
650230592Sken		error = ENOMEM;
651230592Sken		goto out;
652230592Sken	}
653230592Sken	cm->cm_data = page;
654322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
655322661Sken	if (cm != NULL)
656322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
657230592Sken	if (error || (reply == NULL)) {
658230592Sken		/* FIXME */
659253550Sken		/*
660253550Sken		 * If the request returns an error then we need to do a diag
661253550Sken		 * reset
662253550Sken		 */
663253550Sken		printf("%s: request for page completed with error %d",
664230592Sken		    __func__, error);
665230592Sken		error = ENXIO;
666230592Sken		goto out;
667230592Sken	}
668230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
669230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
670230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
671230592Sken		/* FIXME */
672253550Sken		/*
673253550Sken		 * If the request returns an error then we need to do a diag
674253550Sken		 * reset
675253550Sken		 */
676230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
677230592Sken		    __func__, ioc_status);
678230592Sken		error = ENXIO;
679230592Sken		goto out;
680230592Sken	}
681230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sz));
682230592Skenout:
683230592Sken	free(page, M_MPT2);
684230592Sken	if (cm)
685230592Sken		mps_free_command(sc, cm);
686230592Sken	return (error);
687230592Sken}
688230592Sken
689230592Sken/**
690230592Sken * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
691230592Sken * @sc: per adapter object
692230592Sken * @mpi_reply: reply mf payload returned from firmware
693230592Sken * @config_page: contents of the config page
694230592Sken * @entry_idx: entry index in DPM Page0 to be modified
695230592Sken * Context: sleep.
696230592Sken *
697230592Sken * Returns 0 for success, non-zero for failure.
698230592Sken */
699230592Sken
700230592Skenint mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
701230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
702230592Sken{
703230592Sken	MPI2_CONFIG_REQUEST *request;
704322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
705230592Sken	struct mps_command *cm;
706230592Sken	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
707230592Sken	int error = 0;
708230592Sken	u16 ioc_status;
709230592Sken
710230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
711230592Sken
712230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
713230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
714230592Sken		    __LINE__);
715230592Sken		error = EBUSY;
716230592Sken		goto out;
717230592Sken	}
718230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
719230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
720230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
721230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
722230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
723230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
724230592Sken	request->Header.PageNumber = 0;
725230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
726237683Sken	/* We can remove below two lines ????*/
727230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
728230592Sken	request->PageAddress |= htole16(entry_idx);
729230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
730230592Sken	cm->cm_data = NULL;
731322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
732322661Sken	if (cm != NULL)
733322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
734230592Sken	if (error || (reply == NULL)) {
735230592Sken		/* FIXME */
736253550Sken		/*
737253550Sken		 * If the request returns an error then we need to do a diag
738253550Sken		 * reset
739253550Sken		 */
740253550Sken		printf("%s: request for header completed with error %d",
741230592Sken		    __func__, error);
742230592Sken		error = ENXIO;
743230592Sken		goto out;
744230592Sken	}
745230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
746230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
747230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
748230592Sken		/* FIXME */
749253550Sken		/*
750253550Sken		 * If the request returns an error then we need to do a diag
751253550Sken		 * reset
752253550Sken		 */
753230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
754230592Sken		    __func__, ioc_status);
755230592Sken		error = ENXIO;
756230592Sken		goto out;
757230592Sken	}
758230592Sken	/* We have to do free and alloc for the reply-free and reply-post
759230592Sken	 * counters to match - Need to review the reply FIFO handling.
760230592Sken	 */
761230592Sken	mps_free_command(sc, cm);
762230592Sken
763230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
764230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
765230592Sken		    __LINE__);
766230592Sken		error = EBUSY;
767230592Sken		goto out;
768230592Sken	}
769230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
770230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
771230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
772230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
773230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
774230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
775230592Sken	request->Header.PageNumber = 0;
776230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
777230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
778230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
779230592Sken	request->PageAddress |= htole16(entry_idx);
780230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
781230592Sken	cm->cm_sge = &request->PageBufferSGE;
782230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
783230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
784230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
785230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
786230592Sken	if (!page) {
787230592Sken		printf("%s: page alloc failed\n", __func__);
788230592Sken		error = ENOMEM;
789230592Sken		goto out;
790230592Sken	}
791230592Sken	bcopy(config_page, page, MIN(cm->cm_length,
792230592Sken	    (sizeof(Mpi2DriverMappingPage0_t))));
793230592Sken	cm->cm_data = page;
794322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
795322661Sken	if (cm != NULL)
796322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
797230592Sken	if (error || (reply == NULL)) {
798230592Sken		/* FIXME */
799253550Sken		/*
800253550Sken		 * If the request returns an error then we need to do a diag
801253550Sken		 * reset
802253550Sken		 */
803253550Sken		printf("%s: request to write page completed with error %d",
804230592Sken		    __func__, error);
805230592Sken		error = ENXIO;
806230592Sken		goto out;
807230592Sken	}
808230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
809230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
810230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
811230592Sken		/* FIXME */
812253550Sken		/*
813253550Sken		 * If the request returns an error then we need to do a diag
814253550Sken		 * reset
815253550Sken		 */
816230592Sken		printf("%s: page written with error; iocstatus = 0x%x\n",
817230592Sken		    __func__, ioc_status);
818230592Sken		error = ENXIO;
819230592Sken		goto out;
820230592Sken	}
821230592Skenout:
822230592Sken	free(page, M_MPT2);
823230592Sken	if (cm)
824230592Sken		mps_free_command(sc, cm);
825230592Sken	return (error);
826230592Sken}
827230592Sken
828230592Sken/**
829230592Sken * mps_config_get_sas_device_pg0 - obtain sas device page 0
830230592Sken * @sc: per adapter object
831230592Sken * @mpi_reply: reply mf payload returned from firmware
832230592Sken * @config_page: contents of the config page
833230592Sken * @form: GET_NEXT_HANDLE or HANDLE
834230592Sken * @handle: device handle
835230592Sken * Context: sleep.
836230592Sken *
837230592Sken * Returns 0 for success, non-zero for failure.
838230592Sken */
839230592Skenint
840230592Skenmps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
841230592Sken    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
842230592Sken{
843230592Sken	MPI2_CONFIG_REQUEST *request;
844322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
845230592Sken	struct mps_command *cm;
846230592Sken	Mpi2SasDevicePage0_t *page = NULL;
847230592Sken	int error = 0;
848230592Sken	u16 ioc_status;
849230592Sken
850230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
851230592Sken
852230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
853230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
854230592Sken		    __LINE__);
855230592Sken		error = EBUSY;
856230592Sken		goto out;
857230592Sken	}
858230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
859230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
860230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
861230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
862230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
863230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
864230592Sken	request->Header.PageNumber = 0;
865230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
866230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
867230592Sken	cm->cm_data = NULL;
868322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
869322661Sken	if (cm != NULL)
870322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
871230592Sken	if (error || (reply == NULL)) {
872230592Sken		/* FIXME */
873253550Sken		/*
874253550Sken		 * If the request returns an error then we need to do a diag
875253550Sken		 * reset
876253550Sken		 */
877253550Sken		printf("%s: request for header completed with error %d",
878230592Sken		    __func__, error);
879230592Sken		error = ENXIO;
880230592Sken		goto out;
881230592Sken	}
882230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
883230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
884230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
885230592Sken		/* FIXME */
886253550Sken		/*
887253550Sken		 * If the request returns an error then we need to do a diag
888253550Sken		 * reset
889253550Sken		 */
890230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
891230592Sken		    __func__, ioc_status);
892230592Sken		error = ENXIO;
893230592Sken		goto out;
894230592Sken	}
895230592Sken	/* We have to do free and alloc for the reply-free and reply-post
896230592Sken	 * counters to match - Need to review the reply FIFO handling.
897230592Sken	 */
898230592Sken	mps_free_command(sc, cm);
899230592Sken
900230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
901230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
902230592Sken		    __LINE__);
903230592Sken		error = EBUSY;
904230592Sken		goto out;
905230592Sken	}
906230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
907230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
908230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
909230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
910230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
911230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
912230592Sken	request->Header.PageNumber = 0;
913230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
914230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
915230592Sken	request->PageAddress = htole32(form | handle);
916230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
917230592Sken	cm->cm_sge = &request->PageBufferSGE;
918230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
919230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
920230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
921230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
922230592Sken	if (!page) {
923230592Sken		printf("%s: page alloc failed\n", __func__);
924230592Sken		error = ENOMEM;
925230592Sken		goto out;
926230592Sken	}
927230592Sken	cm->cm_data = page;
928230592Sken
929322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
930322661Sken	if (cm != NULL)
931322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
932230592Sken	if (error || (reply == NULL)) {
933230592Sken		/* FIXME */
934253550Sken		/*
935253550Sken		 * If the request returns an error then we need to do a diag
936253550Sken		 * reset
937253550Sken		 */
938253550Sken		printf("%s: request for page completed with error %d",
939230592Sken		    __func__, error);
940230592Sken		error = ENXIO;
941230592Sken		goto out;
942230592Sken	}
943230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
944230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
945230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
946230592Sken		/* FIXME */
947253550Sken		/*
948253550Sken		 * If the request returns an error then we need to do a diag
949253550Sken		 * reset
950253550Sken		 */
951230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
952230592Sken		    __func__, ioc_status);
953230592Sken		error = ENXIO;
954230592Sken		goto out;
955230592Sken	}
956230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
957230592Sken	    sizeof(Mpi2SasDevicePage0_t)));
958230592Skenout:
959230592Sken	free(page, M_MPT2);
960230592Sken	if (cm)
961230592Sken		mps_free_command(sc, cm);
962230592Sken	return (error);
963230592Sken}
964230592Sken
965230592Sken/**
966230592Sken * mps_config_get_bios_pg3 - obtain BIOS page 3
967230592Sken * @sc: per adapter object
968230592Sken * @mpi_reply: reply mf payload returned from firmware
969230592Sken * @config_page: contents of the config page
970230592Sken * Context: sleep.
971230592Sken *
972230592Sken * Returns 0 for success, non-zero for failure.
973230592Sken */
974230592Skenint
975230592Skenmps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
976230592Sken    Mpi2BiosPage3_t *config_page)
977230592Sken{
978230592Sken	MPI2_CONFIG_REQUEST *request;
979322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
980230592Sken	struct mps_command *cm;
981230592Sken	Mpi2BiosPage3_t *page = NULL;
982230592Sken	int error = 0;
983230592Sken	u16 ioc_status;
984230592Sken
985230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
986230592Sken
987230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
988230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
989230592Sken		    __LINE__);
990230592Sken		error = EBUSY;
991230592Sken		goto out;
992230592Sken	}
993230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
994230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
995230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
996230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
997230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
998230592Sken	request->Header.PageNumber = 3;
999230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
1000230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1001230592Sken	cm->cm_data = NULL;
1002322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
1003322661Sken	if (cm != NULL)
1004322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1005230592Sken	if (error || (reply == NULL)) {
1006230592Sken		/* FIXME */
1007253550Sken		/*
1008253550Sken		 * If the request returns an error then we need to do a diag
1009253550Sken		 * reset
1010253550Sken		 */
1011253550Sken		printf("%s: request for header completed with error %d",
1012230592Sken		    __func__, error);
1013230592Sken		error = ENXIO;
1014230592Sken		goto out;
1015230592Sken	}
1016230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1017230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1018230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1019230592Sken		/* FIXME */
1020253550Sken		/*
1021253550Sken		 * If the request returns an error then we need to do a diag
1022253550Sken		 * reset
1023253550Sken		 */
1024230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1025230592Sken		    __func__, ioc_status);
1026230592Sken		error = ENXIO;
1027230592Sken		goto out;
1028230592Sken	}
1029230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1030230592Sken	 * counters to match - Need to review the reply FIFO handling.
1031230592Sken	 */
1032230592Sken	mps_free_command(sc, cm);
1033230592Sken
1034230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1035230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1036230592Sken		    __LINE__);
1037230592Sken		error = EBUSY;
1038230592Sken		goto out;
1039230592Sken	}
1040230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1041230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1042230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1043230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1044230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
1045230592Sken	request->Header.PageNumber = 3;
1046230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
1047230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1048230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1049230592Sken	cm->cm_sge = &request->PageBufferSGE;
1050230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1051230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1052230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1053230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1054230592Sken	if (!page) {
1055230592Sken		printf("%s: page alloc failed\n", __func__);
1056230592Sken		error = ENOMEM;
1057230592Sken		goto out;
1058230592Sken	}
1059230592Sken	cm->cm_data = page;
1060230592Sken
1061322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
1062322661Sken	if (cm != NULL)
1063322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1064230592Sken	if (error || (reply == NULL)) {
1065230592Sken		/* FIXME */
1066253550Sken		/*
1067253550Sken		 * If the request returns an error then we need to do a diag
1068253550Sken		 * reset
1069253550Sken		 */
1070253550Sken		printf("%s: request for page completed with error %d",
1071230592Sken		    __func__, error);
1072230592Sken		error = ENXIO;
1073230592Sken		goto out;
1074230592Sken	}
1075230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1076230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1077230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1078230592Sken		/* FIXME */
1079253550Sken		/*
1080253550Sken		 * If the request returns an error then we need to do a diag
1081253550Sken		 * reset
1082253550Sken		 */
1083230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1084230592Sken		    __func__, ioc_status);
1085230592Sken		error = ENXIO;
1086230592Sken		goto out;
1087230592Sken	}
1088230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
1089230592Skenout:
1090230592Sken	free(page, M_MPT2);
1091230592Sken	if (cm)
1092230592Sken		mps_free_command(sc, cm);
1093230592Sken	return (error);
1094230592Sken}
1095230592Sken
1096230592Sken/**
1097230592Sken * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
1098230592Sken * @sc: per adapter object
1099230592Sken * @mpi_reply: reply mf payload returned from firmware
1100230592Sken * @config_page: contents of the config page
1101230592Sken * @page_address: form and handle value used to get page
1102230592Sken * Context: sleep.
1103230592Sken *
1104230592Sken * Returns 0 for success, non-zero for failure.
1105230592Sken */
1106230592Skenint
1107230592Skenmps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
1108230592Sken    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
1109230592Sken{
1110230592Sken	MPI2_CONFIG_REQUEST *request;
1111322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
1112230592Sken	struct mps_command *cm;
1113230592Sken	Mpi2RaidVolPage0_t *page = NULL;
1114230592Sken	int error = 0;
1115230592Sken	u16 ioc_status;
1116230592Sken
1117230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1118230592Sken
1119230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1120230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1121230592Sken		    __LINE__);
1122230592Sken		error = EBUSY;
1123230592Sken		goto out;
1124230592Sken	}
1125230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1126230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1127230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1128230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1129230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1130230592Sken	request->Header.PageNumber = 0;
1131230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1132230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1133230592Sken	cm->cm_data = NULL;
1134253550Sken
1135253550Sken	/*
1136253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1137253550Sken	 * page is needed.
1138253550Sken	 */
1139322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
1140322661Sken	if (cm != NULL)
1141322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1142230592Sken	if (error || (reply == NULL)) {
1143230592Sken		/* FIXME */
1144230592Sken		/* If the poll returns error then we need to do diag reset */
1145230592Sken		printf("%s: poll for header completed with error %d",
1146230592Sken		    __func__, error);
1147230592Sken		error = ENXIO;
1148230592Sken		goto out;
1149230592Sken	}
1150230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1151230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1152230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1153230592Sken		/* FIXME */
1154230592Sken		/* If the poll returns error then we need to do diag reset */
1155230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1156230592Sken		    __func__, ioc_status);
1157230592Sken		error = ENXIO;
1158230592Sken		goto out;
1159230592Sken	}
1160230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1161230592Sken	 * counters to match - Need to review the reply FIFO handling.
1162230592Sken	 */
1163230592Sken	mps_free_command(sc, cm);
1164230592Sken
1165230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1166230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1167230592Sken		    __LINE__);
1168230592Sken		error = EBUSY;
1169230592Sken		goto out;
1170230592Sken	}
1171230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1172230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1173230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1174230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1175230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1176230592Sken	request->Header.PageNumber = 0;
1177230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1178230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1179230592Sken	request->PageAddress = page_address;
1180230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1181230592Sken	cm->cm_sge = &request->PageBufferSGE;
1182230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1183230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1184230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1185230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1186230592Sken	if (!page) {
1187230592Sken		printf("%s: page alloc failed\n", __func__);
1188230592Sken		error = ENOMEM;
1189230592Sken		goto out;
1190230592Sken	}
1191230592Sken	cm->cm_data = page;
1192230592Sken
1193253550Sken	/*
1194253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1195253550Sken	 * page is needed.
1196253550Sken	 */
1197322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
1198322661Sken	if (cm != NULL)
1199322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1200230592Sken	if (error || (reply == NULL)) {
1201230592Sken		/* FIXME */
1202230592Sken		/* If the poll returns error then we need to do diag reset */
1203230592Sken		printf("%s: poll for page completed with error %d",
1204230592Sken		    __func__, error);
1205230592Sken		error = ENXIO;
1206230592Sken		goto out;
1207230592Sken	}
1208230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1209230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1210230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1211230592Sken		/* FIXME */
1212230592Sken		/* If the poll returns error then we need to do diag reset */
1213230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1214230592Sken		    __func__, ioc_status);
1215230592Sken		error = ENXIO;
1216230592Sken		goto out;
1217230592Sken	}
1218230592Sken	bcopy(page, config_page, cm->cm_length);
1219230592Skenout:
1220230592Sken	free(page, M_MPT2);
1221230592Sken	if (cm)
1222230592Sken		mps_free_command(sc, cm);
1223230592Sken	return (error);
1224230592Sken}
1225230592Sken
1226230592Sken/**
1227230592Sken * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
1228230592Sken * @sc: per adapter object
1229230592Sken * @mpi_reply: reply mf payload returned from firmware
1230230592Sken * @config_page: contents of the config page
1231230592Sken * @form: GET_NEXT_HANDLE or HANDLE
1232230592Sken * @handle: volume handle
1233230592Sken * Context: sleep.
1234230592Sken *
1235230592Sken * Returns 0 for success, non-zero for failure.
1236230592Sken */
1237230592Skenint
1238230592Skenmps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
1239230592Sken    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
1240230592Sken{
1241230592Sken	MPI2_CONFIG_REQUEST *request;
1242322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
1243230592Sken	struct mps_command *cm;
1244230592Sken	Mpi2RaidVolPage1_t *page = NULL;
1245230592Sken	int error = 0;
1246230592Sken	u16 ioc_status;
1247230592Sken
1248230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1249230592Sken
1250230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1251230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1252230592Sken		    __LINE__);
1253230592Sken		error = EBUSY;
1254230592Sken		goto out;
1255230592Sken	}
1256230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1257230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1258230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1259230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1260230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1261230592Sken	request->Header.PageNumber = 1;
1262230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1263230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1264230592Sken	cm->cm_data = NULL;
1265322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
1266322661Sken	if (cm != NULL)
1267322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1268230592Sken	if (error || (reply == NULL)) {
1269230592Sken		/* FIXME */
1270253550Sken		/*
1271253550Sken		 * If the request returns an error then we need to do a diag
1272253550Sken		 * reset
1273253550Sken		 */
1274253550Sken		printf("%s: request for header completed with error %d",
1275230592Sken		    __func__, error);
1276230592Sken		error = ENXIO;
1277230592Sken		goto out;
1278230592Sken	}
1279230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1280230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1281230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1282230592Sken		/* FIXME */
1283253550Sken		/*
1284253550Sken		 * If the request returns an error then we need to do a diag
1285253550Sken		 * reset
1286253550Sken		 */
1287230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1288230592Sken		    __func__, ioc_status);
1289230592Sken		error = ENXIO;
1290230592Sken		goto out;
1291230592Sken	}
1292230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1293230592Sken	 * counters to match - Need to review the reply FIFO handling.
1294230592Sken	 */
1295230592Sken	mps_free_command(sc, cm);
1296230592Sken
1297230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1298230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1299230592Sken		    __LINE__);
1300230592Sken		error = EBUSY;
1301230592Sken		goto out;
1302230592Sken	}
1303230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1304230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1305230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1306230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1307230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1308230592Sken	request->Header.PageNumber = 1;
1309230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1310230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1311230592Sken	request->PageAddress = htole32(form | handle);
1312230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1313230592Sken	cm->cm_sge = &request->PageBufferSGE;
1314230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1315230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1316230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1317230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1318230592Sken	if (!page) {
1319230592Sken		printf("%s: page alloc failed\n", __func__);
1320230592Sken		error = ENOMEM;
1321230592Sken		goto out;
1322230592Sken	}
1323230592Sken	cm->cm_data = page;
1324230592Sken
1325322661Sken	error = mps_wait_command(sc, &cm, 60, CAN_SLEEP);
1326322661Sken	if (cm != NULL)
1327322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1328230592Sken	if (error || (reply == NULL)) {
1329230592Sken		/* FIXME */
1330253550Sken		/*
1331253550Sken		 * If the request returns an error then we need to do a diag
1332253550Sken		 * reset
1333253550Sken		 */
1334253550Sken		printf("%s: request for page completed with error %d",
1335230592Sken		    __func__, error);
1336230592Sken		error = ENXIO;
1337230592Sken		goto out;
1338230592Sken	}
1339230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1340230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1341230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1342230592Sken		/* FIXME */
1343253550Sken		/*
1344253550Sken		 * If the request returns an error then we need to do a diag
1345253550Sken		 * reset
1346253550Sken		 */
1347230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1348230592Sken		    __func__, ioc_status);
1349230592Sken		error = ENXIO;
1350230592Sken		goto out;
1351230592Sken	}
1352230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1353230592Sken	    sizeof(Mpi2RaidVolPage1_t)));
1354230592Skenout:
1355230592Sken	free(page, M_MPT2);
1356230592Sken	if (cm)
1357230592Sken		mps_free_command(sc, cm);
1358230592Sken	return (error);
1359230592Sken}
1360230592Sken
1361230592Sken/**
1362230592Sken * mps_config_get_volume_wwid - returns wwid given the volume handle
1363230592Sken * @sc: per adapter object
1364230592Sken * @volume_handle: volume handle
1365230592Sken * @wwid: volume wwid
1366230592Sken * Context: sleep.
1367230592Sken *
1368230592Sken * Returns 0 for success, non-zero for failure.
1369230592Sken */
1370230592Skenint
1371230592Skenmps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
1372230592Sken{
1373230592Sken	Mpi2ConfigReply_t mpi_reply;
1374230592Sken	Mpi2RaidVolPage1_t raid_vol_pg1;
1375230592Sken
1376230592Sken	*wwid = 0;
1377230592Sken	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
1378230592Sken	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
1379230592Sken		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
1380230592Sken		    raid_vol_pg1.WWID.Low);
1381230592Sken		return 0;
1382230592Sken	} else
1383230592Sken		return -1;
1384230592Sken}
1385230592Sken
1386230592Sken/**
1387230592Sken * mps_config_get_pd_pg0 - obtain raid phys disk page 0
1388230592Sken * @sc: per adapter object
1389230592Sken * @mpi_reply: reply mf payload returned from firmware
1390230592Sken * @config_page: contents of the config page
1391230592Sken * @page_address: form and handle value used to get page
1392230592Sken * Context: sleep.
1393230592Sken *
1394230592Sken * Returns 0 for success, non-zero for failure.
1395230592Sken */
1396230592Skenint
1397230592Skenmps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
1398230592Sken    Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
1399230592Sken{
1400230592Sken	MPI2_CONFIG_REQUEST *request;
1401322661Sken	MPI2_CONFIG_REPLY *reply = NULL;
1402230592Sken	struct mps_command *cm;
1403230592Sken	Mpi2RaidPhysDiskPage0_t *page = NULL;
1404230592Sken	int error = 0;
1405230592Sken	u16 ioc_status;
1406230592Sken
1407230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1408230592Sken
1409230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1410230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1411230592Sken		    __LINE__);
1412230592Sken		error = EBUSY;
1413230592Sken		goto out;
1414230592Sken	}
1415230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1416230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1417230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1418230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1419230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1420230592Sken	request->Header.PageNumber = 0;
1421230592Sken	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1422230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1423230592Sken	cm->cm_data = NULL;
1424253550Sken
1425253550Sken	/*
1426253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1427253550Sken	 * page is needed.
1428253550Sken	 */
1429322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
1430322661Sken	if (cm != NULL)
1431322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1432230592Sken	if (error || (reply == NULL)) {
1433230592Sken		/* FIXME */
1434230592Sken		/* If the poll returns error then we need to do diag reset */
1435230592Sken		printf("%s: poll for header completed with error %d",
1436230592Sken		    __func__, error);
1437230592Sken		error = ENXIO;
1438230592Sken		goto out;
1439230592Sken	}
1440230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1441230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1442230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1443230592Sken		/* FIXME */
1444230592Sken		/* If the poll returns error then we need to do diag reset */
1445230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1446230592Sken		    __func__, ioc_status);
1447230592Sken		error = ENXIO;
1448230592Sken		goto out;
1449230592Sken	}
1450230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1451230592Sken	 * counters to match - Need to review the reply FIFO handling.
1452230592Sken	 */
1453230592Sken	mps_free_command(sc, cm);
1454230592Sken
1455230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1456230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1457230592Sken		    __LINE__);
1458230592Sken		error = EBUSY;
1459230592Sken		goto out;
1460230592Sken	}
1461230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1462230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1463230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1464230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1465230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1466230592Sken	request->Header.PageNumber = 0;
1467230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1468230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1469230592Sken	request->PageAddress = page_address;
1470230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1471230592Sken	cm->cm_sge = &request->PageBufferSGE;
1472230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1473230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1474230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1475230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1476230592Sken	if (!page) {
1477230592Sken		printf("%s: page alloc failed\n", __func__);
1478230592Sken		error = ENOMEM;
1479230592Sken		goto out;
1480230592Sken	}
1481230592Sken	cm->cm_data = page;
1482230592Sken
1483253550Sken	/*
1484253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1485253550Sken	 * page is needed.
1486253550Sken	 */
1487322661Sken	error = mps_wait_command(sc, &cm, 60, 0);
1488322661Sken	if (cm != NULL)
1489322661Sken		reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1490230592Sken	if (error || (reply == NULL)) {
1491230592Sken		/* FIXME */
1492230592Sken		/* If the poll returns error then we need to do diag reset */
1493230592Sken		printf("%s: poll for page completed with error %d",
1494230592Sken		    __func__, error);
1495230592Sken		error = ENXIO;
1496230592Sken		goto out;
1497230592Sken	}
1498230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1499230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1500230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1501230592Sken		/* FIXME */
1502230592Sken		/* If the poll returns error then we need to do diag reset */
1503230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1504230592Sken		    __func__, ioc_status);
1505230592Sken		error = ENXIO;
1506230592Sken		goto out;
1507230592Sken	}
1508230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1509230592Sken	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1510230592Skenout:
1511230592Sken	free(page, M_MPT2);
1512230592Sken	if (cm)
1513230592Sken		mps_free_command(sc, cm);
1514230592Sken	return (error);
1515230592Sken}
1516