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: releng/10.2/sys/dev/mps/mps_config.c 281564 2015-04-15 21:47:15Z slm $");
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;
74230592Sken	MPI2_CONFIG_REPLY *reply;
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;
97253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
98230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
99230592Sken	if (error || (reply == NULL)) {
100230592Sken		/* FIXME */
101253550Sken		/*
102253550Sken		 * If the request returns an error then we need to do a diag
103253550Sken		 * reset
104253550Sken		 */
105253550Sken		printf("%s: request for header completed with error %d",
106230592Sken		    __func__, error);
107230592Sken		error = ENXIO;
108230592Sken		goto out;
109230592Sken	}
110230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
111230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
112230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
113230592Sken		/* FIXME */
114253550Sken		/*
115253550Sken		 * If the request returns an error then we need to do a diag
116253550Sken		 * reset
117253550Sken		 */
118230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
119230592Sken		    __func__, ioc_status);
120230592Sken		error = ENXIO;
121230592Sken		goto out;
122230592Sken	}
123230592Sken	/* We have to do free and alloc for the reply-free and reply-post
124230592Sken	 * counters to match - Need to review the reply FIFO handling.
125230592Sken	 */
126230592Sken	mps_free_command(sc, cm);
127230592Sken
128230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
129230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
130230592Sken		    __LINE__);
131230592Sken		error = EBUSY;
132230592Sken		goto out;
133230592Sken	}
134230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
135230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
136230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
137230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
138230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
139230592Sken	request->Header.PageNumber = 8;
140230592Sken	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
141230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
142230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
143230592Sken	cm->cm_sge = &request->PageBufferSGE;
144230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
145230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
146230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
147230592Sken	page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
148230592Sken	if (!page) {
149230592Sken		printf("%s: page alloc failed\n", __func__);
150230592Sken		error = ENOMEM;
151230592Sken		goto out;
152230592Sken	}
153230592Sken	cm->cm_data = page;
154253550Sken
155253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
156230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
157230592Sken	if (error || (reply == NULL)) {
158230592Sken		/* FIXME */
159253550Sken		/*
160253550Sken		 * If the request returns an error then we need to do a diag
161253550Sken		 * reset
162253550Sken		 */
163253550Sken		printf("%s: request for page completed with error %d",
164230592Sken		    __func__, error);
165230592Sken		error = ENXIO;
166230592Sken		goto out;
167230592Sken	}
168230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
169230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
170230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
171230592Sken		/* FIXME */
172253550Sken		/*
173253550Sken		 * If the request returns an error then we need to do a diag
174253550Sken		 * reset
175253550Sken		 */
176230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
177230592Sken		    __func__, ioc_status);
178230592Sken		error = ENXIO;
179230592Sken		goto out;
180230592Sken	}
181230592Sken	bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
182230592Sken
183230592Skenout:
184230592Sken	free(page, M_MPT2);
185230592Sken	if (cm)
186230592Sken		mps_free_command(sc, cm);
187230592Sken	return (error);
188230592Sken}
189230592Sken
190230592Sken/**
191230592Sken * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
192230592Sken *   accordingly.  Currently, this page does not need to return to caller.
193230592Sken * @sc: per adapter object
194230592Sken * @mpi_reply: reply mf payload returned from firmware
195230592Sken * Context: sleep.
196230592Sken *
197230592Sken * Returns 0 for success, non-zero for failure.
198230592Sken */
199230592Skenint
200230592Skenmps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
201230592Sken{
202230592Sken	MPI2_CONFIG_REQUEST *request;
203230592Sken	MPI2_CONFIG_REPLY *reply;
204230592Sken	struct mps_command *cm;
205230592Sken	pMpi2ManufacturingPagePS_t page = NULL;
206230592Sken	uint32_t *pPS_info;
207230592Sken	uint8_t OEM_Value = 0;
208230592Sken	int error = 0;
209230592Sken	u16 ioc_status;
210230592Sken
211230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
212230592Sken
213230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
214230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
215230592Sken		    __LINE__);
216230592Sken		error = EBUSY;
217230592Sken		goto out;
218230592Sken	}
219230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
220230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
221230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
222230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
223230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
224230592Sken	request->Header.PageNumber = 10;
225230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
226230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
227230592Sken	cm->cm_data = NULL;
228253550Sken
229253550Sken	/*
230253550Sken	 * This page must be polled because the IOC isn't ready yet when this
231253550Sken	 * page is needed.
232253550Sken	 */
233230592Sken	error = mps_request_polled(sc, cm);
234230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
235230592Sken	if (error || (reply == NULL)) {
236230592Sken		/* FIXME */
237230592Sken		/* If the poll returns error then we need to do diag reset */
238230592Sken		printf("%s: poll for header completed with error %d",
239230592Sken		    __func__, error);
240230592Sken		error = ENXIO;
241230592Sken		goto out;
242230592Sken	}
243230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
244230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
245230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
246230592Sken		/* FIXME */
247230592Sken		/* If the poll returns error then we need to do diag reset */
248230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
249230592Sken		    __func__, ioc_status);
250230592Sken		error = ENXIO;
251230592Sken		goto out;
252230592Sken	}
253230592Sken	/* We have to do free and alloc for the reply-free and reply-post
254230592Sken	 * counters to match - Need to review the reply FIFO handling.
255230592Sken	 */
256230592Sken	mps_free_command(sc, cm);
257230592Sken
258230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
259230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
260230592Sken		    __LINE__);
261230592Sken		error = EBUSY;
262230592Sken		goto out;
263230592Sken	}
264230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
265230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
266230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
267230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
268230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
269230592Sken	request->Header.PageNumber = 10;
270230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
271230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
272230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
273230592Sken	cm->cm_sge = &request->PageBufferSGE;
274230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
275230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
276230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
277230592Sken	page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
278230592Sken	if (!page) {
279230592Sken		printf("%s: page alloc failed\n", __func__);
280230592Sken		error = ENOMEM;
281230592Sken		goto out;
282230592Sken	}
283230592Sken	cm->cm_data = page;
284253550Sken
285253550Sken	/*
286253550Sken	 * This page must be polled because the IOC isn't ready yet when this
287253550Sken	 * page is needed.
288253550Sken	 */
289230592Sken	error = mps_request_polled(sc, cm);
290230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
291230592Sken	if (error || (reply == NULL)) {
292230592Sken		/* FIXME */
293230592Sken		/* If the poll returns error then we need to do diag reset */
294230592Sken		printf("%s: poll for page completed with error %d",
295230592Sken		    __func__, error);
296230592Sken		error = ENXIO;
297230592Sken		goto out;
298230592Sken	}
299230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
300230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
301230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
302230592Sken		/* FIXME */
303230592Sken		/* If the poll returns error then we need to do diag reset */
304230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
305230592Sken		    __func__, ioc_status);
306230592Sken		error = ENXIO;
307230592Sken		goto out;
308230592Sken	}
309230592Sken
310230592Sken	/*
311230592Sken	 * If OEM ID is unknown, fail the request.
312230592Sken	 */
313230592Sken	sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
314230592Sken	OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
315230592Sken	if (OEM_Value != MPS_WD_LSI_OEM) {
316230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
317230592Sken		    "(0x%x)\n", OEM_Value);
318230592Sken		error = ENXIO;
319230592Sken		goto out;
320230592Sken	}
321230592Sken
322230592Sken	/*
323230592Sken	 * Set the phys disks hide/expose value.
324230592Sken	 */
325230592Sken	pPS_info = &page->ProductSpecificInfo;
326230592Sken	sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
327230592Sken	sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
328230592Sken	if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
329230592Sken	    (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
330230592Sken	    (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
331230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
332230592Sken		    "hide/expose: 0x%x\n", sc->WD_hide_expose);
333230592Sken		error = ENXIO;
334230592Sken		goto out;
335230592Sken	}
336230592Sken
337230592Skenout:
338230592Sken	free(page, M_MPT2);
339230592Sken	if (cm)
340230592Sken		mps_free_command(sc, cm);
341230592Sken	return (error);
342230592Sken}
343230592Sken
344230592Sken/**
345230592Sken * mps_base_static_config_pages - static start of day config pages.
346230592Sken * @sc: per adapter object
347230592Sken *
348230592Sken * Return nothing.
349230592Sken */
350230592Skenvoid
351230592Skenmps_base_static_config_pages(struct mps_softc *sc)
352230592Sken{
353230592Sken	Mpi2ConfigReply_t	mpi_reply;
354230592Sken	int			retry;
355230592Sken
356230592Sken	retry = 0;
357230592Sken	while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
358230592Sken		retry++;
359230592Sken		if (retry > 5) {
360230592Sken			/* We need to Handle this situation */
361230592Sken			/*FIXME*/
362230592Sken			break;
363230592Sken		}
364230592Sken	}
365230592Sken}
366230592Sken
367230592Sken/**
368230592Sken * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
369230592Sken *    be called after discovery is complete to guarentee that IR info is there.
370230592Sken * @sc: per adapter object
371230592Sken *
372230592Sken * Return nothing.
373230592Sken */
374230592Skenvoid
375230592Skenmps_wd_config_pages(struct mps_softc *sc)
376230592Sken{
377230592Sken	Mpi2ConfigReply_t	mpi_reply;
378230592Sken	pMpi2RaidVolPage0_t	raid_vol_pg0 = NULL;
379230592Sken	Mpi2RaidPhysDiskPage0_t	phys_disk_pg0;
380230592Sken	pMpi2RaidVol0PhysDisk_t	pRVPD;
381230592Sken	uint32_t		stripe_size, phys_disk_page_address;
382230592Sken	uint16_t		block_size;
383230592Sken	uint8_t			index, stripe_exp = 0, block_exp = 0;
384230592Sken
385230592Sken	/*
386230592Sken	 * Get the WD settings from manufacturing page 10 if using a WD HBA.
387230592Sken	 * This will be used to determine if phys disks should always be
388230592Sken	 * hidden, hidden only if part of a WD volume, or never hidden.  Also,
389230592Sken	 * get the WD RAID Volume info and fail if volume does not exist or if
390230592Sken	 * volume does not meet the requirements for a WD volume.  No retry
391230592Sken	 * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
392230592Sken	 * Valid flag if Volume info fails.
393230592Sken	 */
394230592Sken	sc->WD_valid_config = FALSE;
395230592Sken	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
396230592Sken		if (mps_config_get_man_pg10(sc, &mpi_reply)) {
397230592Sken			mps_dprint(sc, MPS_FAULT,
398230592Sken			    "mps_config_get_man_pg10 failed! Using 0 (Hide "
399230592Sken			    "Always) for WarpDrive hide/expose value.\n");
400230592Sken			sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
401230592Sken		}
402230592Sken
403230592Sken		/*
404230592Sken		 * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
405230592Sken		 */
406230592Sken		raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) +
407230592Sken		    (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
408230592Sken		    M_MPT2, M_ZERO | M_NOWAIT);
409230592Sken		if (!raid_vol_pg0) {
410230592Sken			printf("%s: page alloc failed\n", __func__);
411230592Sken			goto out;
412230592Sken		}
413230592Sken
414230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
415230592Sken		    0x0000FFFF)) {
416230592Sken			mps_dprint(sc, MPS_INFO,
417230592Sken			    "mps_config_get_raid_volume_pg0 failed! Assuming "
418230592Sken			    "WarpDrive IT mode.\n");
419230592Sken			goto out;
420230592Sken		}
421230592Sken
422230592Sken		/*
423230592Sken		 * Check for valid WD configuration:
424230592Sken		 *   volume type is RAID0
425230592Sken		 *   number of phys disks in the volume is no more than 8
426230592Sken		 */
427230592Sken		if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
428230592Sken		    (raid_vol_pg0->NumPhysDisks > 8)) {
429230592Sken			mps_dprint(sc, MPS_FAULT,
430230592Sken			    "Invalid WarpDrive configuration. Direct Drive I/O "
431230592Sken			    "will not be used.\n");
432230592Sken			goto out;
433230592Sken		}
434230592Sken
435230592Sken		/*
436230592Sken		 * Save the WD RAID data to be used during WD I/O.
437230592Sken		 */
438230592Sken		sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
439230592Sken		    32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
440230592Sken		sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
441230592Sken		sc->DD_dev_handle = raid_vol_pg0->DevHandle;
442230592Sken		sc->DD_stripe_size = raid_vol_pg0->StripeSize;
443230592Sken		sc->DD_block_size = raid_vol_pg0->BlockSize;
444230592Sken
445230592Sken		/*
446230592Sken		 * Find power of 2 of stripe size and set this as the exponent.
447230592Sken		 * Fail if stripe size is 0.
448230592Sken		 */
449230592Sken		stripe_size = raid_vol_pg0->StripeSize;
450230592Sken		for (index = 0; index < 32; index++) {
451230592Sken			if (stripe_size & 1)
452230592Sken				break;
453230592Sken			stripe_exp++;
454230592Sken			stripe_size >>= 1;
455230592Sken		}
456230592Sken		if (index == 32) {
457230592Sken			mps_dprint(sc, MPS_FAULT,
458230592Sken			    "RAID Volume's stripe size is 0. Direct Drive I/O "
459230592Sken			    "will not be used.\n");
460230592Sken			goto out;
461230592Sken		}
462230592Sken		sc->DD_stripe_exponent = stripe_exp;
463230592Sken
464230592Sken		/*
465230592Sken		 * Find power of 2 of block size and set this as the exponent.
466230592Sken		 * Fail if block size is 0.
467230592Sken		 */
468230592Sken		block_size = raid_vol_pg0->BlockSize;
469230592Sken		for (index = 0; index < 16; index++) {
470230592Sken			if (block_size & 1)
471230592Sken				break;
472230592Sken			block_exp++;
473230592Sken			block_size >>= 1;
474230592Sken		}
475230592Sken		if (index == 16) {
476230592Sken			mps_dprint(sc, MPS_FAULT,
477230592Sken			    "RAID Volume's block size is 0. Direct Drive I/O "
478230592Sken			    "will not be used.\n");
479230592Sken			goto out;
480230592Sken		}
481230592Sken		sc->DD_block_exponent = block_exp;
482230592Sken
483230592Sken		/*
484230592Sken		 * Loop through all of the volume's Phys Disks to map the phys
485230592Sken		 * disk number into the columm map.  This is used during Direct
486230592Sken		 * Drive I/O to send the request to the correct SSD.
487230592Sken		 */
488230592Sken		pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
489230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
490230592Sken			sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
491230592Sken			    pRVPD->PhysDiskNum;
492230592Sken			pRVPD++;
493230592Sken		}
494230592Sken
495230592Sken		/*
496230592Sken		 * Get second RAID Volume Page0 using previous handle.  This
497230592Sken		 * page should not exist.  If it does, must not proceed with WD
498230592Sken		 * handling.
499230592Sken		 */
500230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
501230592Sken		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
502230592Sken			if (mpi_reply.IOCStatus !=
503230592Sken			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
504230592Sken				mps_dprint(sc, MPS_FAULT,
505230592Sken				    "Multiple RAID Volume Page0! Direct Drive "
506230592Sken				    "I/O will not be used.\n");
507230592Sken				goto out;
508230592Sken			}
509230592Sken		} else {
510230592Sken			mps_dprint(sc, MPS_FAULT,
511230592Sken			    "Multiple volumes! Direct Drive I/O will not be "
512230592Sken			    "used.\n");
513230592Sken			goto out;
514230592Sken		}
515230592Sken
516230592Sken		/*
517230592Sken		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
518230592Sken		 */
519230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
520230592Sken			phys_disk_page_address =
521230592Sken			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
522230592Sken			    sc->DD_column_map[index].phys_disk_num;
523230592Sken			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
524230592Sken			    &phys_disk_pg0, phys_disk_page_address)) {
525230592Sken				mps_dprint(sc, MPS_FAULT,
526230592Sken				    "mps_config_get_raid_pd_pg0 failed! Direct "
527230592Sken				    "Drive I/O will not be used.\n");
528230592Sken				goto out;
529230592Sken			}
530230592Sken			if (phys_disk_pg0.DevHandle == 0xFFFF) {
531230592Sken				mps_dprint(sc, MPS_FAULT,
532230592Sken				    "Invalid Phys Disk DevHandle! Direct Drive "
533230592Sken				    "I/O will not be used.\n");
534230592Sken				goto out;
535230592Sken			}
536230592Sken			sc->DD_column_map[index].dev_handle =
537230592Sken			    phys_disk_pg0.DevHandle;
538230592Sken		}
539230592Sken		sc->WD_valid_config = TRUE;
540230592Skenout:
541230592Sken		if (raid_vol_pg0)
542230592Sken			free(raid_vol_pg0, M_MPT2);
543230592Sken	}
544230592Sken}
545230592Sken
546230592Sken/**
547230592Sken * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
548230592Sken * @sc: per adapter object
549230592Sken * @mpi_reply: reply mf payload returned from firmware
550230592Sken * @config_page: contents of the config page
551230592Sken * @sz: size of buffer passed in config_page
552230592Sken * Context: sleep.
553230592Sken *
554230592Sken * Returns 0 for success, non-zero for failure.
555230592Sken */
556230592Skenint
557230592Skenmps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
558230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 sz)
559230592Sken{
560230592Sken	MPI2_CONFIG_REQUEST *request;
561230592Sken	MPI2_CONFIG_REPLY *reply;
562230592Sken	struct mps_command *cm;
563230592Sken	Mpi2DriverMappingPage0_t *page = NULL;
564230592Sken	int error = 0;
565230592Sken	u16 ioc_status;
566230592Sken
567230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
568230592Sken
569230592Sken	memset(config_page, 0, sz);
570230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
571230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
572230592Sken		    __LINE__);
573230592Sken		error = EBUSY;
574230592Sken		goto out;
575230592Sken	}
576230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
577230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
578230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
579230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
580230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
581230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
582230592Sken	request->Header.PageNumber = 0;
583230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
584230592Sken	request->PageAddress = sc->max_dpm_entries <<
585230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
586230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
587230592Sken	cm->cm_data = NULL;
588253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
589230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
590230592Sken	if (error || (reply == NULL)) {
591230592Sken		/* FIXME */
592253550Sken		/*
593253550Sken		 * If the request returns an error then we need to do a diag
594253550Sken		 * reset
595253550Sken		 */
596253550Sken		printf("%s: request for header completed with error %d",
597230592Sken		    __func__, error);
598230592Sken		error = ENXIO;
599230592Sken		goto out;
600230592Sken	}
601230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
602230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
603230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
604230592Sken		/* FIXME */
605253550Sken		/*
606253550Sken		 * If the request returns an error then we need to do a diag
607253550Sken		 * reset
608253550Sken		 */
609230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
610230592Sken		    __func__, ioc_status);
611230592Sken		error = ENXIO;
612230592Sken		goto out;
613230592Sken	}
614230592Sken	/* We have to do free and alloc for the reply-free and reply-post
615230592Sken	 * counters to match - Need to review the reply FIFO handling.
616230592Sken	 */
617230592Sken	mps_free_command(sc, cm);
618230592Sken
619230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
620230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
621230592Sken		    __LINE__);
622230592Sken		error = EBUSY;
623230592Sken		goto out;
624230592Sken	}
625230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
626230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
627230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
628230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
629230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
630230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
631230592Sken	request->Header.PageNumber = 0;
632230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
633230592Sken	request->PageAddress = sc->max_dpm_entries <<
634230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
635230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
636230592Sken	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
637230592Sken	cm->cm_sge = &request->PageBufferSGE;
638230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
639230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
640230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
641230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
642230592Sken	if (!page) {
643230592Sken		printf("%s: page alloc failed\n", __func__);
644230592Sken		error = ENOMEM;
645230592Sken		goto out;
646230592Sken	}
647230592Sken	cm->cm_data = page;
648253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
649230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
650230592Sken	if (error || (reply == NULL)) {
651230592Sken		/* FIXME */
652253550Sken		/*
653253550Sken		 * If the request returns an error then we need to do a diag
654253550Sken		 * reset
655253550Sken		 */
656253550Sken		printf("%s: request for page completed with error %d",
657230592Sken		    __func__, error);
658230592Sken		error = ENXIO;
659230592Sken		goto out;
660230592Sken	}
661230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
662230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
663230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
664230592Sken		/* FIXME */
665253550Sken		/*
666253550Sken		 * If the request returns an error then we need to do a diag
667253550Sken		 * reset
668253550Sken		 */
669230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
670230592Sken		    __func__, ioc_status);
671230592Sken		error = ENXIO;
672230592Sken		goto out;
673230592Sken	}
674230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sz));
675230592Skenout:
676230592Sken	free(page, M_MPT2);
677230592Sken	if (cm)
678230592Sken		mps_free_command(sc, cm);
679230592Sken	return (error);
680230592Sken}
681230592Sken
682230592Sken/**
683230592Sken * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
684230592Sken * @sc: per adapter object
685230592Sken * @mpi_reply: reply mf payload returned from firmware
686230592Sken * @config_page: contents of the config page
687230592Sken * @entry_idx: entry index in DPM Page0 to be modified
688230592Sken * Context: sleep.
689230592Sken *
690230592Sken * Returns 0 for success, non-zero for failure.
691230592Sken */
692230592Sken
693230592Skenint mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
694230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
695230592Sken{
696230592Sken	MPI2_CONFIG_REQUEST *request;
697230592Sken	MPI2_CONFIG_REPLY *reply;
698230592Sken	struct mps_command *cm;
699230592Sken	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
700230592Sken	int error = 0;
701230592Sken	u16 ioc_status;
702230592Sken
703230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
704230592Sken
705230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
706230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
707230592Sken		    __LINE__);
708230592Sken		error = EBUSY;
709230592Sken		goto out;
710230592Sken	}
711230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
712230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
713230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
714230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
715230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
716230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
717230592Sken	request->Header.PageNumber = 0;
718230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
719237683Sken	/* We can remove below two lines ????*/
720230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
721230592Sken	request->PageAddress |= htole16(entry_idx);
722230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
723230592Sken	cm->cm_data = NULL;
724253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
725230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
726230592Sken	if (error || (reply == NULL)) {
727230592Sken		/* FIXME */
728253550Sken		/*
729253550Sken		 * If the request returns an error then we need to do a diag
730253550Sken		 * reset
731253550Sken		 */
732253550Sken		printf("%s: request for header completed with error %d",
733230592Sken		    __func__, error);
734230592Sken		error = ENXIO;
735230592Sken		goto out;
736230592Sken	}
737230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
738230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
739230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
740230592Sken		/* FIXME */
741253550Sken		/*
742253550Sken		 * If the request returns an error then we need to do a diag
743253550Sken		 * reset
744253550Sken		 */
745230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
746230592Sken		    __func__, ioc_status);
747230592Sken		error = ENXIO;
748230592Sken		goto out;
749230592Sken	}
750230592Sken	/* We have to do free and alloc for the reply-free and reply-post
751230592Sken	 * counters to match - Need to review the reply FIFO handling.
752230592Sken	 */
753230592Sken	mps_free_command(sc, cm);
754230592Sken
755230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
756230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
757230592Sken		    __LINE__);
758230592Sken		error = EBUSY;
759230592Sken		goto out;
760230592Sken	}
761230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
762230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
763230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
764230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
765230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
766230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
767230592Sken	request->Header.PageNumber = 0;
768230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
769230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
770230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
771230592Sken	request->PageAddress |= htole16(entry_idx);
772230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
773230592Sken	cm->cm_sge = &request->PageBufferSGE;
774230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
775230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
776230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
777230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
778230592Sken	if (!page) {
779230592Sken		printf("%s: page alloc failed\n", __func__);
780230592Sken		error = ENOMEM;
781230592Sken		goto out;
782230592Sken	}
783230592Sken	bcopy(config_page, page, MIN(cm->cm_length,
784230592Sken	    (sizeof(Mpi2DriverMappingPage0_t))));
785230592Sken	cm->cm_data = page;
786253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
787230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
788230592Sken	if (error || (reply == NULL)) {
789230592Sken		/* FIXME */
790253550Sken		/*
791253550Sken		 * If the request returns an error then we need to do a diag
792253550Sken		 * reset
793253550Sken		 */
794253550Sken		printf("%s: request to write page completed with error %d",
795230592Sken		    __func__, error);
796230592Sken		error = ENXIO;
797230592Sken		goto out;
798230592Sken	}
799230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
800230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
801230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
802230592Sken		/* FIXME */
803253550Sken		/*
804253550Sken		 * If the request returns an error then we need to do a diag
805253550Sken		 * reset
806253550Sken		 */
807230592Sken		printf("%s: page written with error; iocstatus = 0x%x\n",
808230592Sken		    __func__, ioc_status);
809230592Sken		error = ENXIO;
810230592Sken		goto out;
811230592Sken	}
812230592Skenout:
813230592Sken	free(page, M_MPT2);
814230592Sken	if (cm)
815230592Sken		mps_free_command(sc, cm);
816230592Sken	return (error);
817230592Sken}
818230592Sken
819230592Sken/**
820230592Sken * mps_config_get_sas_device_pg0 - obtain sas device page 0
821230592Sken * @sc: per adapter object
822230592Sken * @mpi_reply: reply mf payload returned from firmware
823230592Sken * @config_page: contents of the config page
824230592Sken * @form: GET_NEXT_HANDLE or HANDLE
825230592Sken * @handle: device handle
826230592Sken * Context: sleep.
827230592Sken *
828230592Sken * Returns 0 for success, non-zero for failure.
829230592Sken */
830230592Skenint
831230592Skenmps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
832230592Sken    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
833230592Sken{
834230592Sken	MPI2_CONFIG_REQUEST *request;
835230592Sken	MPI2_CONFIG_REPLY *reply;
836230592Sken	struct mps_command *cm;
837230592Sken	Mpi2SasDevicePage0_t *page = NULL;
838230592Sken	int error = 0;
839230592Sken	u16 ioc_status;
840230592Sken
841230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
842230592Sken
843230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
844230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
845230592Sken		    __LINE__);
846230592Sken		error = EBUSY;
847230592Sken		goto out;
848230592Sken	}
849230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
850230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
851230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
852230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
853230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
854230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
855230592Sken	request->Header.PageNumber = 0;
856230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
857230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
858230592Sken	cm->cm_data = NULL;
859253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
860230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
861230592Sken	if (error || (reply == NULL)) {
862230592Sken		/* FIXME */
863253550Sken		/*
864253550Sken		 * If the request returns an error then we need to do a diag
865253550Sken		 * reset
866253550Sken		 */
867253550Sken		printf("%s: request for header completed with error %d",
868230592Sken		    __func__, error);
869230592Sken		error = ENXIO;
870230592Sken		goto out;
871230592Sken	}
872230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
873230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
874230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
875230592Sken		/* FIXME */
876253550Sken		/*
877253550Sken		 * If the request returns an error then we need to do a diag
878253550Sken		 * reset
879253550Sken		 */
880230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
881230592Sken		    __func__, ioc_status);
882230592Sken		error = ENXIO;
883230592Sken		goto out;
884230592Sken	}
885230592Sken	/* We have to do free and alloc for the reply-free and reply-post
886230592Sken	 * counters to match - Need to review the reply FIFO handling.
887230592Sken	 */
888230592Sken	mps_free_command(sc, cm);
889230592Sken
890230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
891230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
892230592Sken		    __LINE__);
893230592Sken		error = EBUSY;
894230592Sken		goto out;
895230592Sken	}
896230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
897230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
898230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
899230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
900230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
901230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
902230592Sken	request->Header.PageNumber = 0;
903230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
904230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
905230592Sken	request->PageAddress = htole32(form | handle);
906230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
907230592Sken	cm->cm_sge = &request->PageBufferSGE;
908230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
909230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
910230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
911230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
912230592Sken	if (!page) {
913230592Sken		printf("%s: page alloc failed\n", __func__);
914230592Sken		error = ENOMEM;
915230592Sken		goto out;
916230592Sken	}
917230592Sken	cm->cm_data = page;
918230592Sken
919253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
920230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
921230592Sken	if (error || (reply == NULL)) {
922230592Sken		/* FIXME */
923253550Sken		/*
924253550Sken		 * If the request returns an error then we need to do a diag
925253550Sken		 * reset
926253550Sken		 */
927253550Sken		printf("%s: request for page completed with error %d",
928230592Sken		    __func__, error);
929230592Sken		error = ENXIO;
930230592Sken		goto out;
931230592Sken	}
932230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
933230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
934230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
935230592Sken		/* FIXME */
936253550Sken		/*
937253550Sken		 * If the request returns an error then we need to do a diag
938253550Sken		 * reset
939253550Sken		 */
940230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
941230592Sken		    __func__, ioc_status);
942230592Sken		error = ENXIO;
943230592Sken		goto out;
944230592Sken	}
945230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
946230592Sken	    sizeof(Mpi2SasDevicePage0_t)));
947230592Skenout:
948230592Sken	free(page, M_MPT2);
949230592Sken	if (cm)
950230592Sken		mps_free_command(sc, cm);
951230592Sken	return (error);
952230592Sken}
953230592Sken
954230592Sken/**
955230592Sken * mps_config_get_bios_pg3 - obtain BIOS page 3
956230592Sken * @sc: per adapter object
957230592Sken * @mpi_reply: reply mf payload returned from firmware
958230592Sken * @config_page: contents of the config page
959230592Sken * Context: sleep.
960230592Sken *
961230592Sken * Returns 0 for success, non-zero for failure.
962230592Sken */
963230592Skenint
964230592Skenmps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
965230592Sken    Mpi2BiosPage3_t *config_page)
966230592Sken{
967230592Sken	MPI2_CONFIG_REQUEST *request;
968230592Sken	MPI2_CONFIG_REPLY *reply;
969230592Sken	struct mps_command *cm;
970230592Sken	Mpi2BiosPage3_t *page = NULL;
971230592Sken	int error = 0;
972230592Sken	u16 ioc_status;
973230592Sken
974230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
975230592Sken
976230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
977230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
978230592Sken		    __LINE__);
979230592Sken		error = EBUSY;
980230592Sken		goto out;
981230592Sken	}
982230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
983230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
984230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
985230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
986230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
987230592Sken	request->Header.PageNumber = 3;
988230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
989230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
990230592Sken	cm->cm_data = NULL;
991253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
992230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
993230592Sken	if (error || (reply == NULL)) {
994230592Sken		/* FIXME */
995253550Sken		/*
996253550Sken		 * If the request returns an error then we need to do a diag
997253550Sken		 * reset
998253550Sken		 */
999253550Sken		printf("%s: request for header completed with error %d",
1000230592Sken		    __func__, error);
1001230592Sken		error = ENXIO;
1002230592Sken		goto out;
1003230592Sken	}
1004230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1005230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1006230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1007230592Sken		/* FIXME */
1008253550Sken		/*
1009253550Sken		 * If the request returns an error then we need to do a diag
1010253550Sken		 * reset
1011253550Sken		 */
1012230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1013230592Sken		    __func__, ioc_status);
1014230592Sken		error = ENXIO;
1015230592Sken		goto out;
1016230592Sken	}
1017230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1018230592Sken	 * counters to match - Need to review the reply FIFO handling.
1019230592Sken	 */
1020230592Sken	mps_free_command(sc, cm);
1021230592Sken
1022230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1023230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1024230592Sken		    __LINE__);
1025230592Sken		error = EBUSY;
1026230592Sken		goto out;
1027230592Sken	}
1028230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1029230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1030230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1031230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1032230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
1033230592Sken	request->Header.PageNumber = 3;
1034230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
1035230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1036230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1037230592Sken	cm->cm_sge = &request->PageBufferSGE;
1038230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1039230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1040230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1041230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1042230592Sken	if (!page) {
1043230592Sken		printf("%s: page alloc failed\n", __func__);
1044230592Sken		error = ENOMEM;
1045230592Sken		goto out;
1046230592Sken	}
1047230592Sken	cm->cm_data = page;
1048230592Sken
1049253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1050230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1051230592Sken	if (error || (reply == NULL)) {
1052230592Sken		/* FIXME */
1053253550Sken		/*
1054253550Sken		 * If the request returns an error then we need to do a diag
1055253550Sken		 * reset
1056253550Sken		 */
1057253550Sken		printf("%s: request for page completed with error %d",
1058230592Sken		    __func__, error);
1059230592Sken		error = ENXIO;
1060230592Sken		goto out;
1061230592Sken	}
1062230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1063230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1064230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1065230592Sken		/* FIXME */
1066253550Sken		/*
1067253550Sken		 * If the request returns an error then we need to do a diag
1068253550Sken		 * reset
1069253550Sken		 */
1070230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1071230592Sken		    __func__, ioc_status);
1072230592Sken		error = ENXIO;
1073230592Sken		goto out;
1074230592Sken	}
1075230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
1076230592Skenout:
1077230592Sken	free(page, M_MPT2);
1078230592Sken	if (cm)
1079230592Sken		mps_free_command(sc, cm);
1080230592Sken	return (error);
1081230592Sken}
1082230592Sken
1083230592Sken/**
1084230592Sken * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
1085230592Sken * @sc: per adapter object
1086230592Sken * @mpi_reply: reply mf payload returned from firmware
1087230592Sken * @config_page: contents of the config page
1088230592Sken * @page_address: form and handle value used to get page
1089230592Sken * Context: sleep.
1090230592Sken *
1091230592Sken * Returns 0 for success, non-zero for failure.
1092230592Sken */
1093230592Skenint
1094230592Skenmps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
1095230592Sken    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
1096230592Sken{
1097230592Sken	MPI2_CONFIG_REQUEST *request;
1098230592Sken	MPI2_CONFIG_REPLY *reply;
1099230592Sken	struct mps_command *cm;
1100230592Sken	Mpi2RaidVolPage0_t *page = NULL;
1101230592Sken	int error = 0;
1102230592Sken	u16 ioc_status;
1103230592Sken
1104230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1105230592Sken
1106230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1107230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1108230592Sken		    __LINE__);
1109230592Sken		error = EBUSY;
1110230592Sken		goto out;
1111230592Sken	}
1112230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1113230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1114230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1115230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1116230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1117230592Sken	request->Header.PageNumber = 0;
1118230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1119230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1120230592Sken	cm->cm_data = NULL;
1121253550Sken
1122253550Sken	/*
1123253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1124253550Sken	 * page is needed.
1125253550Sken	 */
1126230592Sken	error = mps_request_polled(sc, cm);
1127230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1128230592Sken	if (error || (reply == NULL)) {
1129230592Sken		/* FIXME */
1130230592Sken		/* If the poll returns error then we need to do diag reset */
1131230592Sken		printf("%s: poll for header completed with error %d",
1132230592Sken		    __func__, error);
1133230592Sken		error = ENXIO;
1134230592Sken		goto out;
1135230592Sken	}
1136230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1137230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1138230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1139230592Sken		/* FIXME */
1140230592Sken		/* If the poll returns error then we need to do diag reset */
1141230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1142230592Sken		    __func__, ioc_status);
1143230592Sken		error = ENXIO;
1144230592Sken		goto out;
1145230592Sken	}
1146230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1147230592Sken	 * counters to match - Need to review the reply FIFO handling.
1148230592Sken	 */
1149230592Sken	mps_free_command(sc, cm);
1150230592Sken
1151230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1152230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1153230592Sken		    __LINE__);
1154230592Sken		error = EBUSY;
1155230592Sken		goto out;
1156230592Sken	}
1157230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1158230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1159230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1160230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1161230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1162230592Sken	request->Header.PageNumber = 0;
1163230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1164230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1165230592Sken	request->PageAddress = page_address;
1166230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1167230592Sken	cm->cm_sge = &request->PageBufferSGE;
1168230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1169230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1170230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1171230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1172230592Sken	if (!page) {
1173230592Sken		printf("%s: page alloc failed\n", __func__);
1174230592Sken		error = ENOMEM;
1175230592Sken		goto out;
1176230592Sken	}
1177230592Sken	cm->cm_data = page;
1178230592Sken
1179253550Sken	/*
1180253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1181253550Sken	 * page is needed.
1182253550Sken	 */
1183230592Sken	error = mps_request_polled(sc, cm);
1184230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1185230592Sken	if (error || (reply == NULL)) {
1186230592Sken		/* FIXME */
1187230592Sken		/* If the poll returns error then we need to do diag reset */
1188230592Sken		printf("%s: poll for page completed with error %d",
1189230592Sken		    __func__, error);
1190230592Sken		error = ENXIO;
1191230592Sken		goto out;
1192230592Sken	}
1193230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1194230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1195230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1196230592Sken		/* FIXME */
1197230592Sken		/* If the poll returns error then we need to do diag reset */
1198230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1199230592Sken		    __func__, ioc_status);
1200230592Sken		error = ENXIO;
1201230592Sken		goto out;
1202230592Sken	}
1203230592Sken	bcopy(page, config_page, cm->cm_length);
1204230592Skenout:
1205230592Sken	free(page, M_MPT2);
1206230592Sken	if (cm)
1207230592Sken		mps_free_command(sc, cm);
1208230592Sken	return (error);
1209230592Sken}
1210230592Sken
1211230592Sken/**
1212230592Sken * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
1213230592Sken * @sc: per adapter object
1214230592Sken * @mpi_reply: reply mf payload returned from firmware
1215230592Sken * @config_page: contents of the config page
1216230592Sken * @form: GET_NEXT_HANDLE or HANDLE
1217230592Sken * @handle: volume handle
1218230592Sken * Context: sleep.
1219230592Sken *
1220230592Sken * Returns 0 for success, non-zero for failure.
1221230592Sken */
1222230592Skenint
1223230592Skenmps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
1224230592Sken    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
1225230592Sken{
1226230592Sken	MPI2_CONFIG_REQUEST *request;
1227230592Sken	MPI2_CONFIG_REPLY *reply;
1228230592Sken	struct mps_command *cm;
1229230592Sken	Mpi2RaidVolPage1_t *page = NULL;
1230230592Sken	int error = 0;
1231230592Sken	u16 ioc_status;
1232230592Sken
1233230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1234230592Sken
1235230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1236230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1237230592Sken		    __LINE__);
1238230592Sken		error = EBUSY;
1239230592Sken		goto out;
1240230592Sken	}
1241230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1242230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1243230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1244230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1245230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1246230592Sken	request->Header.PageNumber = 1;
1247230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1248230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1249230592Sken	cm->cm_data = NULL;
1250253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1251230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1252230592Sken	if (error || (reply == NULL)) {
1253230592Sken		/* FIXME */
1254253550Sken		/*
1255253550Sken		 * If the request returns an error then we need to do a diag
1256253550Sken		 * reset
1257253550Sken		 */
1258253550Sken		printf("%s: request for header completed with error %d",
1259230592Sken		    __func__, error);
1260230592Sken		error = ENXIO;
1261230592Sken		goto out;
1262230592Sken	}
1263230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1264230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1265230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1266230592Sken		/* FIXME */
1267253550Sken		/*
1268253550Sken		 * If the request returns an error then we need to do a diag
1269253550Sken		 * reset
1270253550Sken		 */
1271230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1272230592Sken		    __func__, ioc_status);
1273230592Sken		error = ENXIO;
1274230592Sken		goto out;
1275230592Sken	}
1276230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1277230592Sken	 * counters to match - Need to review the reply FIFO handling.
1278230592Sken	 */
1279230592Sken	mps_free_command(sc, cm);
1280230592Sken
1281230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1282230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1283230592Sken		    __LINE__);
1284230592Sken		error = EBUSY;
1285230592Sken		goto out;
1286230592Sken	}
1287230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1288230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1289230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1290230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1291230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1292230592Sken	request->Header.PageNumber = 1;
1293230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1294230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1295230592Sken	request->PageAddress = htole32(form | handle);
1296230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1297230592Sken	cm->cm_sge = &request->PageBufferSGE;
1298230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1299230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1300230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1301230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1302230592Sken	if (!page) {
1303230592Sken		printf("%s: page alloc failed\n", __func__);
1304230592Sken		error = ENOMEM;
1305230592Sken		goto out;
1306230592Sken	}
1307230592Sken	cm->cm_data = page;
1308230592Sken
1309253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1310230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1311230592Sken	if (error || (reply == NULL)) {
1312230592Sken		/* FIXME */
1313253550Sken		/*
1314253550Sken		 * If the request returns an error then we need to do a diag
1315253550Sken		 * reset
1316253550Sken		 */
1317253550Sken		printf("%s: request for page completed with error %d",
1318230592Sken		    __func__, error);
1319230592Sken		error = ENXIO;
1320230592Sken		goto out;
1321230592Sken	}
1322230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1323230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1324230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1325230592Sken		/* FIXME */
1326253550Sken		/*
1327253550Sken		 * If the request returns an error then we need to do a diag
1328253550Sken		 * reset
1329253550Sken		 */
1330230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1331230592Sken		    __func__, ioc_status);
1332230592Sken		error = ENXIO;
1333230592Sken		goto out;
1334230592Sken	}
1335230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1336230592Sken	    sizeof(Mpi2RaidVolPage1_t)));
1337230592Skenout:
1338230592Sken	free(page, M_MPT2);
1339230592Sken	if (cm)
1340230592Sken		mps_free_command(sc, cm);
1341230592Sken	return (error);
1342230592Sken}
1343230592Sken
1344230592Sken/**
1345230592Sken * mps_config_get_volume_wwid - returns wwid given the volume handle
1346230592Sken * @sc: per adapter object
1347230592Sken * @volume_handle: volume handle
1348230592Sken * @wwid: volume wwid
1349230592Sken * Context: sleep.
1350230592Sken *
1351230592Sken * Returns 0 for success, non-zero for failure.
1352230592Sken */
1353230592Skenint
1354230592Skenmps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
1355230592Sken{
1356230592Sken	Mpi2ConfigReply_t mpi_reply;
1357230592Sken	Mpi2RaidVolPage1_t raid_vol_pg1;
1358230592Sken
1359230592Sken	*wwid = 0;
1360230592Sken	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
1361230592Sken	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
1362230592Sken		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
1363230592Sken		    raid_vol_pg1.WWID.Low);
1364230592Sken		return 0;
1365230592Sken	} else
1366230592Sken		return -1;
1367230592Sken}
1368230592Sken
1369230592Sken/**
1370230592Sken * mps_config_get_pd_pg0 - obtain raid phys disk page 0
1371230592Sken * @sc: per adapter object
1372230592Sken * @mpi_reply: reply mf payload returned from firmware
1373230592Sken * @config_page: contents of the config page
1374230592Sken * @page_address: form and handle value used to get page
1375230592Sken * Context: sleep.
1376230592Sken *
1377230592Sken * Returns 0 for success, non-zero for failure.
1378230592Sken */
1379230592Skenint
1380230592Skenmps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
1381230592Sken    Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
1382230592Sken{
1383230592Sken	MPI2_CONFIG_REQUEST *request;
1384230592Sken	MPI2_CONFIG_REPLY *reply;
1385230592Sken	struct mps_command *cm;
1386230592Sken	Mpi2RaidPhysDiskPage0_t *page = NULL;
1387230592Sken	int error = 0;
1388230592Sken	u16 ioc_status;
1389230592Sken
1390230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1391230592Sken
1392230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1393230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1394230592Sken		    __LINE__);
1395230592Sken		error = EBUSY;
1396230592Sken		goto out;
1397230592Sken	}
1398230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1399230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1400230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1401230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1402230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1403230592Sken	request->Header.PageNumber = 0;
1404230592Sken	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1405230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1406230592Sken	cm->cm_data = NULL;
1407253550Sken
1408253550Sken	/*
1409253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1410253550Sken	 * page is needed.
1411253550Sken	 */
1412230592Sken	error = mps_request_polled(sc, cm);
1413230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1414230592Sken	if (error || (reply == NULL)) {
1415230592Sken		/* FIXME */
1416230592Sken		/* If the poll returns error then we need to do diag reset */
1417230592Sken		printf("%s: poll for header completed with error %d",
1418230592Sken		    __func__, error);
1419230592Sken		error = ENXIO;
1420230592Sken		goto out;
1421230592Sken	}
1422230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1423230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1424230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1425230592Sken		/* FIXME */
1426230592Sken		/* If the poll returns error then we need to do diag reset */
1427230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1428230592Sken		    __func__, ioc_status);
1429230592Sken		error = ENXIO;
1430230592Sken		goto out;
1431230592Sken	}
1432230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1433230592Sken	 * counters to match - Need to review the reply FIFO handling.
1434230592Sken	 */
1435230592Sken	mps_free_command(sc, cm);
1436230592Sken
1437230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1438230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1439230592Sken		    __LINE__);
1440230592Sken		error = EBUSY;
1441230592Sken		goto out;
1442230592Sken	}
1443230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1444230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1445230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1446230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1447230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1448230592Sken	request->Header.PageNumber = 0;
1449230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1450230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1451230592Sken	request->PageAddress = page_address;
1452230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1453230592Sken	cm->cm_sge = &request->PageBufferSGE;
1454230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1455230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1456230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1457230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1458230592Sken	if (!page) {
1459230592Sken		printf("%s: page alloc failed\n", __func__);
1460230592Sken		error = ENOMEM;
1461230592Sken		goto out;
1462230592Sken	}
1463230592Sken	cm->cm_data = page;
1464230592Sken
1465253550Sken	/*
1466253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1467253550Sken	 * page is needed.
1468253550Sken	 */
1469230592Sken	error = mps_request_polled(sc, cm);
1470230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1471230592Sken	if (error || (reply == NULL)) {
1472230592Sken		/* FIXME */
1473230592Sken		/* If the poll returns error then we need to do diag reset */
1474230592Sken		printf("%s: poll for page completed with error %d",
1475230592Sken		    __func__, error);
1476230592Sken		error = ENXIO;
1477230592Sken		goto out;
1478230592Sken	}
1479230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1480230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1481230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1482230592Sken		/* FIXME */
1483230592Sken		/* If the poll returns error then we need to do diag reset */
1484230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1485230592Sken		    __func__, ioc_status);
1486230592Sken		error = ENXIO;
1487230592Sken		goto out;
1488230592Sken	}
1489230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1490230592Sken	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1491230592Skenout:
1492230592Sken	free(page, M_MPT2);
1493230592Sken	if (cm)
1494230592Sken		mps_free_command(sc, cm);
1495230592Sken	return (error);
1496230592Sken}
1497