1230592Sken/*-
2279253Sslm * Copyright (c) 2011-2015 LSI Corp.
3279253Sslm * 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 *
27279253Sslm * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
28230592Sken */
29230592Sken
30230592Sken#include <sys/cdefs.h>
31230592Sken__FBSDID("$FreeBSD: releng/11.0/sys/dev/mps/mps_config.c 302031 2016-06-20 18:14:51Z 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	 */
233286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
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	 */
289286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
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
369298955Spfg *    be called after discovery is complete to guarantee 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)) {
502302031Sslm			if ((le16toh(mpi_reply.IOCStatus) &
503302031Sslm			    MPI2_IOCSTATUS_MASK) !=
504230592Sken			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
505230592Sken				mps_dprint(sc, MPS_FAULT,
506230592Sken				    "Multiple RAID Volume Page0! Direct Drive "
507230592Sken				    "I/O will not be used.\n");
508230592Sken				goto out;
509230592Sken			}
510230592Sken		} else {
511230592Sken			mps_dprint(sc, MPS_FAULT,
512230592Sken			    "Multiple volumes! Direct Drive I/O will not be "
513230592Sken			    "used.\n");
514230592Sken			goto out;
515230592Sken		}
516230592Sken
517230592Sken		/*
518230592Sken		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
519230592Sken		 */
520230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
521230592Sken			phys_disk_page_address =
522230592Sken			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
523230592Sken			    sc->DD_column_map[index].phys_disk_num;
524230592Sken			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
525230592Sken			    &phys_disk_pg0, phys_disk_page_address)) {
526230592Sken				mps_dprint(sc, MPS_FAULT,
527230592Sken				    "mps_config_get_raid_pd_pg0 failed! Direct "
528230592Sken				    "Drive I/O will not be used.\n");
529230592Sken				goto out;
530230592Sken			}
531230592Sken			if (phys_disk_pg0.DevHandle == 0xFFFF) {
532230592Sken				mps_dprint(sc, MPS_FAULT,
533230592Sken				    "Invalid Phys Disk DevHandle! Direct Drive "
534230592Sken				    "I/O will not be used.\n");
535230592Sken				goto out;
536230592Sken			}
537230592Sken			sc->DD_column_map[index].dev_handle =
538230592Sken			    phys_disk_pg0.DevHandle;
539230592Sken		}
540230592Sken		sc->WD_valid_config = TRUE;
541230592Skenout:
542230592Sken		if (raid_vol_pg0)
543230592Sken			free(raid_vol_pg0, M_MPT2);
544230592Sken	}
545230592Sken}
546230592Sken
547230592Sken/**
548230592Sken * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
549230592Sken * @sc: per adapter object
550230592Sken * @mpi_reply: reply mf payload returned from firmware
551230592Sken * @config_page: contents of the config page
552230592Sken * @sz: size of buffer passed in config_page
553230592Sken * Context: sleep.
554230592Sken *
555230592Sken * Returns 0 for success, non-zero for failure.
556230592Sken */
557230592Skenint
558230592Skenmps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
559230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 sz)
560230592Sken{
561230592Sken	MPI2_CONFIG_REQUEST *request;
562230592Sken	MPI2_CONFIG_REPLY *reply;
563230592Sken	struct mps_command *cm;
564230592Sken	Mpi2DriverMappingPage0_t *page = NULL;
565230592Sken	int error = 0;
566230592Sken	u16 ioc_status;
567230592Sken
568230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
569230592Sken
570230592Sken	memset(config_page, 0, sz);
571230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
572230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
573230592Sken		    __LINE__);
574230592Sken		error = EBUSY;
575230592Sken		goto out;
576230592Sken	}
577230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
578230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
579230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
580230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
581230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
582230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
583230592Sken	request->Header.PageNumber = 0;
584230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
585230592Sken	request->PageAddress = sc->max_dpm_entries <<
586230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
587230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
588230592Sken	cm->cm_data = NULL;
589253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
590230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
591230592Sken	if (error || (reply == NULL)) {
592230592Sken		/* FIXME */
593253550Sken		/*
594253550Sken		 * If the request returns an error then we need to do a diag
595253550Sken		 * reset
596253550Sken		 */
597253550Sken		printf("%s: request for header completed with error %d",
598230592Sken		    __func__, error);
599230592Sken		error = ENXIO;
600230592Sken		goto out;
601230592Sken	}
602230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
603230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
604230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
605230592Sken		/* FIXME */
606253550Sken		/*
607253550Sken		 * If the request returns an error then we need to do a diag
608253550Sken		 * reset
609253550Sken		 */
610230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
611230592Sken		    __func__, ioc_status);
612230592Sken		error = ENXIO;
613230592Sken		goto out;
614230592Sken	}
615230592Sken	/* We have to do free and alloc for the reply-free and reply-post
616230592Sken	 * counters to match - Need to review the reply FIFO handling.
617230592Sken	 */
618230592Sken	mps_free_command(sc, cm);
619230592Sken
620230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
621230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
622230592Sken		    __LINE__);
623230592Sken		error = EBUSY;
624230592Sken		goto out;
625230592Sken	}
626230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
627230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
628230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
629230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
630230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
631230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
632230592Sken	request->Header.PageNumber = 0;
633230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
634230592Sken	request->PageAddress = sc->max_dpm_entries <<
635230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
636230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
637230592Sken	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
638230592Sken	cm->cm_sge = &request->PageBufferSGE;
639230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
640230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
641230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
642230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
643230592Sken	if (!page) {
644230592Sken		printf("%s: page alloc failed\n", __func__);
645230592Sken		error = ENOMEM;
646230592Sken		goto out;
647230592Sken	}
648230592Sken	cm->cm_data = page;
649253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
650230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
651230592Sken	if (error || (reply == NULL)) {
652230592Sken		/* FIXME */
653253550Sken		/*
654253550Sken		 * If the request returns an error then we need to do a diag
655253550Sken		 * reset
656253550Sken		 */
657253550Sken		printf("%s: request for page completed with error %d",
658230592Sken		    __func__, error);
659230592Sken		error = ENXIO;
660230592Sken		goto out;
661230592Sken	}
662230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
663230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
664230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
665230592Sken		/* FIXME */
666253550Sken		/*
667253550Sken		 * If the request returns an error then we need to do a diag
668253550Sken		 * reset
669253550Sken		 */
670230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
671230592Sken		    __func__, ioc_status);
672230592Sken		error = ENXIO;
673230592Sken		goto out;
674230592Sken	}
675230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sz));
676230592Skenout:
677230592Sken	free(page, M_MPT2);
678230592Sken	if (cm)
679230592Sken		mps_free_command(sc, cm);
680230592Sken	return (error);
681230592Sken}
682230592Sken
683230592Sken/**
684230592Sken * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
685230592Sken * @sc: per adapter object
686230592Sken * @mpi_reply: reply mf payload returned from firmware
687230592Sken * @config_page: contents of the config page
688230592Sken * @entry_idx: entry index in DPM Page0 to be modified
689230592Sken * Context: sleep.
690230592Sken *
691230592Sken * Returns 0 for success, non-zero for failure.
692230592Sken */
693230592Sken
694230592Skenint mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
695230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
696230592Sken{
697230592Sken	MPI2_CONFIG_REQUEST *request;
698230592Sken	MPI2_CONFIG_REPLY *reply;
699230592Sken	struct mps_command *cm;
700230592Sken	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
701230592Sken	int error = 0;
702230592Sken	u16 ioc_status;
703230592Sken
704230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
705230592Sken
706230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
707230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
708230592Sken		    __LINE__);
709230592Sken		error = EBUSY;
710230592Sken		goto out;
711230592Sken	}
712230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
713230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
714230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
715230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
716230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
717230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
718230592Sken	request->Header.PageNumber = 0;
719230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
720237683Sken	/* We can remove below two lines ????*/
721230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
722230592Sken	request->PageAddress |= htole16(entry_idx);
723230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
724230592Sken	cm->cm_data = NULL;
725253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
726230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
727230592Sken	if (error || (reply == NULL)) {
728230592Sken		/* FIXME */
729253550Sken		/*
730253550Sken		 * If the request returns an error then we need to do a diag
731253550Sken		 * reset
732253550Sken		 */
733253550Sken		printf("%s: request for header completed with error %d",
734230592Sken		    __func__, error);
735230592Sken		error = ENXIO;
736230592Sken		goto out;
737230592Sken	}
738230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
739230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
740230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
741230592Sken		/* FIXME */
742253550Sken		/*
743253550Sken		 * If the request returns an error then we need to do a diag
744253550Sken		 * reset
745253550Sken		 */
746230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
747230592Sken		    __func__, ioc_status);
748230592Sken		error = ENXIO;
749230592Sken		goto out;
750230592Sken	}
751230592Sken	/* We have to do free and alloc for the reply-free and reply-post
752230592Sken	 * counters to match - Need to review the reply FIFO handling.
753230592Sken	 */
754230592Sken	mps_free_command(sc, cm);
755230592Sken
756230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
757230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
758230592Sken		    __LINE__);
759230592Sken		error = EBUSY;
760230592Sken		goto out;
761230592Sken	}
762230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
763230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
764230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
765230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
766230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
767230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
768230592Sken	request->Header.PageNumber = 0;
769230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
770230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
771230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
772230592Sken	request->PageAddress |= htole16(entry_idx);
773230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
774230592Sken	cm->cm_sge = &request->PageBufferSGE;
775230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
776230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
777230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
778230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
779230592Sken	if (!page) {
780230592Sken		printf("%s: page alloc failed\n", __func__);
781230592Sken		error = ENOMEM;
782230592Sken		goto out;
783230592Sken	}
784230592Sken	bcopy(config_page, page, MIN(cm->cm_length,
785230592Sken	    (sizeof(Mpi2DriverMappingPage0_t))));
786230592Sken	cm->cm_data = page;
787253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
788230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
789230592Sken	if (error || (reply == NULL)) {
790230592Sken		/* FIXME */
791253550Sken		/*
792253550Sken		 * If the request returns an error then we need to do a diag
793253550Sken		 * reset
794253550Sken		 */
795253550Sken		printf("%s: request to write page completed with error %d",
796230592Sken		    __func__, error);
797230592Sken		error = ENXIO;
798230592Sken		goto out;
799230592Sken	}
800230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
801230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
802230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
803230592Sken		/* FIXME */
804253550Sken		/*
805253550Sken		 * If the request returns an error then we need to do a diag
806253550Sken		 * reset
807253550Sken		 */
808230592Sken		printf("%s: page written with error; iocstatus = 0x%x\n",
809230592Sken		    __func__, ioc_status);
810230592Sken		error = ENXIO;
811230592Sken		goto out;
812230592Sken	}
813230592Skenout:
814230592Sken	free(page, M_MPT2);
815230592Sken	if (cm)
816230592Sken		mps_free_command(sc, cm);
817230592Sken	return (error);
818230592Sken}
819230592Sken
820230592Sken/**
821230592Sken * mps_config_get_sas_device_pg0 - obtain sas device page 0
822230592Sken * @sc: per adapter object
823230592Sken * @mpi_reply: reply mf payload returned from firmware
824230592Sken * @config_page: contents of the config page
825230592Sken * @form: GET_NEXT_HANDLE or HANDLE
826230592Sken * @handle: device handle
827230592Sken * Context: sleep.
828230592Sken *
829230592Sken * Returns 0 for success, non-zero for failure.
830230592Sken */
831230592Skenint
832230592Skenmps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
833230592Sken    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
834230592Sken{
835230592Sken	MPI2_CONFIG_REQUEST *request;
836230592Sken	MPI2_CONFIG_REPLY *reply;
837230592Sken	struct mps_command *cm;
838230592Sken	Mpi2SasDevicePage0_t *page = NULL;
839230592Sken	int error = 0;
840230592Sken	u16 ioc_status;
841230592Sken
842230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
843230592Sken
844230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
845230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
846230592Sken		    __LINE__);
847230592Sken		error = EBUSY;
848230592Sken		goto out;
849230592Sken	}
850230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
851230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
852230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
853230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
854230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
855230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
856230592Sken	request->Header.PageNumber = 0;
857230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
858230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
859230592Sken	cm->cm_data = NULL;
860253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
861230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
862230592Sken	if (error || (reply == NULL)) {
863230592Sken		/* FIXME */
864253550Sken		/*
865253550Sken		 * If the request returns an error then we need to do a diag
866253550Sken		 * reset
867253550Sken		 */
868253550Sken		printf("%s: request for header completed with error %d",
869230592Sken		    __func__, error);
870230592Sken		error = ENXIO;
871230592Sken		goto out;
872230592Sken	}
873230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
874230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
875230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
876230592Sken		/* FIXME */
877253550Sken		/*
878253550Sken		 * If the request returns an error then we need to do a diag
879253550Sken		 * reset
880253550Sken		 */
881230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
882230592Sken		    __func__, ioc_status);
883230592Sken		error = ENXIO;
884230592Sken		goto out;
885230592Sken	}
886230592Sken	/* We have to do free and alloc for the reply-free and reply-post
887230592Sken	 * counters to match - Need to review the reply FIFO handling.
888230592Sken	 */
889230592Sken	mps_free_command(sc, cm);
890230592Sken
891230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
892230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
893230592Sken		    __LINE__);
894230592Sken		error = EBUSY;
895230592Sken		goto out;
896230592Sken	}
897230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
898230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
899230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
900230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
901230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
902230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
903230592Sken	request->Header.PageNumber = 0;
904230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
905230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
906230592Sken	request->PageAddress = htole32(form | handle);
907230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
908230592Sken	cm->cm_sge = &request->PageBufferSGE;
909230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
910230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
911230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
912230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
913230592Sken	if (!page) {
914230592Sken		printf("%s: page alloc failed\n", __func__);
915230592Sken		error = ENOMEM;
916230592Sken		goto out;
917230592Sken	}
918230592Sken	cm->cm_data = page;
919230592Sken
920253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
921230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
922230592Sken	if (error || (reply == NULL)) {
923230592Sken		/* FIXME */
924253550Sken		/*
925253550Sken		 * If the request returns an error then we need to do a diag
926253550Sken		 * reset
927253550Sken		 */
928253550Sken		printf("%s: request for page completed with error %d",
929230592Sken		    __func__, error);
930230592Sken		error = ENXIO;
931230592Sken		goto out;
932230592Sken	}
933230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
934230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
935230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
936230592Sken		/* FIXME */
937253550Sken		/*
938253550Sken		 * If the request returns an error then we need to do a diag
939253550Sken		 * reset
940253550Sken		 */
941230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
942230592Sken		    __func__, ioc_status);
943230592Sken		error = ENXIO;
944230592Sken		goto out;
945230592Sken	}
946230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
947230592Sken	    sizeof(Mpi2SasDevicePage0_t)));
948230592Skenout:
949230592Sken	free(page, M_MPT2);
950230592Sken	if (cm)
951230592Sken		mps_free_command(sc, cm);
952230592Sken	return (error);
953230592Sken}
954230592Sken
955230592Sken/**
956230592Sken * mps_config_get_bios_pg3 - obtain BIOS page 3
957230592Sken * @sc: per adapter object
958230592Sken * @mpi_reply: reply mf payload returned from firmware
959230592Sken * @config_page: contents of the config page
960230592Sken * Context: sleep.
961230592Sken *
962230592Sken * Returns 0 for success, non-zero for failure.
963230592Sken */
964230592Skenint
965230592Skenmps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
966230592Sken    Mpi2BiosPage3_t *config_page)
967230592Sken{
968230592Sken	MPI2_CONFIG_REQUEST *request;
969230592Sken	MPI2_CONFIG_REPLY *reply;
970230592Sken	struct mps_command *cm;
971230592Sken	Mpi2BiosPage3_t *page = NULL;
972230592Sken	int error = 0;
973230592Sken	u16 ioc_status;
974230592Sken
975230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
976230592Sken
977230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
978230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
979230592Sken		    __LINE__);
980230592Sken		error = EBUSY;
981230592Sken		goto out;
982230592Sken	}
983230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
984230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
985230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
986230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
987230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
988230592Sken	request->Header.PageNumber = 3;
989230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
990230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
991230592Sken	cm->cm_data = NULL;
992253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
993230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
994230592Sken	if (error || (reply == NULL)) {
995230592Sken		/* FIXME */
996253550Sken		/*
997253550Sken		 * If the request returns an error then we need to do a diag
998253550Sken		 * reset
999253550Sken		 */
1000253550Sken		printf("%s: request for header completed with error %d",
1001230592Sken		    __func__, error);
1002230592Sken		error = ENXIO;
1003230592Sken		goto out;
1004230592Sken	}
1005230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1006230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1007230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1008230592Sken		/* FIXME */
1009253550Sken		/*
1010253550Sken		 * If the request returns an error then we need to do a diag
1011253550Sken		 * reset
1012253550Sken		 */
1013230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1014230592Sken		    __func__, ioc_status);
1015230592Sken		error = ENXIO;
1016230592Sken		goto out;
1017230592Sken	}
1018230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1019230592Sken	 * counters to match - Need to review the reply FIFO handling.
1020230592Sken	 */
1021230592Sken	mps_free_command(sc, cm);
1022230592Sken
1023230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1024230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1025230592Sken		    __LINE__);
1026230592Sken		error = EBUSY;
1027230592Sken		goto out;
1028230592Sken	}
1029230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1030230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1031230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1032230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1033230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
1034230592Sken	request->Header.PageNumber = 3;
1035230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
1036230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1037230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1038230592Sken	cm->cm_sge = &request->PageBufferSGE;
1039230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1040230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1041230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1042230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1043230592Sken	if (!page) {
1044230592Sken		printf("%s: page alloc failed\n", __func__);
1045230592Sken		error = ENOMEM;
1046230592Sken		goto out;
1047230592Sken	}
1048230592Sken	cm->cm_data = page;
1049230592Sken
1050253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1051230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1052230592Sken	if (error || (reply == NULL)) {
1053230592Sken		/* FIXME */
1054253550Sken		/*
1055253550Sken		 * If the request returns an error then we need to do a diag
1056253550Sken		 * reset
1057253550Sken		 */
1058253550Sken		printf("%s: request for page completed with error %d",
1059230592Sken		    __func__, error);
1060230592Sken		error = ENXIO;
1061230592Sken		goto out;
1062230592Sken	}
1063230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1064230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1065230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1066230592Sken		/* FIXME */
1067253550Sken		/*
1068253550Sken		 * If the request returns an error then we need to do a diag
1069253550Sken		 * reset
1070253550Sken		 */
1071230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1072230592Sken		    __func__, ioc_status);
1073230592Sken		error = ENXIO;
1074230592Sken		goto out;
1075230592Sken	}
1076230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
1077230592Skenout:
1078230592Sken	free(page, M_MPT2);
1079230592Sken	if (cm)
1080230592Sken		mps_free_command(sc, cm);
1081230592Sken	return (error);
1082230592Sken}
1083230592Sken
1084230592Sken/**
1085230592Sken * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
1086230592Sken * @sc: per adapter object
1087230592Sken * @mpi_reply: reply mf payload returned from firmware
1088230592Sken * @config_page: contents of the config page
1089230592Sken * @page_address: form and handle value used to get page
1090230592Sken * Context: sleep.
1091230592Sken *
1092230592Sken * Returns 0 for success, non-zero for failure.
1093230592Sken */
1094230592Skenint
1095230592Skenmps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
1096230592Sken    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
1097230592Sken{
1098230592Sken	MPI2_CONFIG_REQUEST *request;
1099230592Sken	MPI2_CONFIG_REPLY *reply;
1100230592Sken	struct mps_command *cm;
1101230592Sken	Mpi2RaidVolPage0_t *page = NULL;
1102230592Sken	int error = 0;
1103230592Sken	u16 ioc_status;
1104230592Sken
1105230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1106230592Sken
1107230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1108230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1109230592Sken		    __LINE__);
1110230592Sken		error = EBUSY;
1111230592Sken		goto out;
1112230592Sken	}
1113230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1114230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1115230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1116230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1117230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1118230592Sken	request->Header.PageNumber = 0;
1119230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1120230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1121230592Sken	cm->cm_data = NULL;
1122253550Sken
1123253550Sken	/*
1124253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1125253550Sken	 * page is needed.
1126253550Sken	 */
1127286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
1128230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1129230592Sken	if (error || (reply == NULL)) {
1130230592Sken		/* FIXME */
1131230592Sken		/* If the poll returns error then we need to do diag reset */
1132230592Sken		printf("%s: poll for header completed with error %d",
1133230592Sken		    __func__, error);
1134230592Sken		error = ENXIO;
1135230592Sken		goto out;
1136230592Sken	}
1137230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1138230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1139230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1140230592Sken		/* FIXME */
1141230592Sken		/* If the poll returns error then we need to do diag reset */
1142230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1143230592Sken		    __func__, ioc_status);
1144230592Sken		error = ENXIO;
1145230592Sken		goto out;
1146230592Sken	}
1147230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1148230592Sken	 * counters to match - Need to review the reply FIFO handling.
1149230592Sken	 */
1150230592Sken	mps_free_command(sc, cm);
1151230592Sken
1152230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1153230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1154230592Sken		    __LINE__);
1155230592Sken		error = EBUSY;
1156230592Sken		goto out;
1157230592Sken	}
1158230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1159230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1160230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1161230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1162230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1163230592Sken	request->Header.PageNumber = 0;
1164230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1165230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1166230592Sken	request->PageAddress = page_address;
1167230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1168230592Sken	cm->cm_sge = &request->PageBufferSGE;
1169230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1170230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1171230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1172230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1173230592Sken	if (!page) {
1174230592Sken		printf("%s: page alloc failed\n", __func__);
1175230592Sken		error = ENOMEM;
1176230592Sken		goto out;
1177230592Sken	}
1178230592Sken	cm->cm_data = page;
1179230592Sken
1180253550Sken	/*
1181253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1182253550Sken	 * page is needed.
1183253550Sken	 */
1184286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
1185230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1186230592Sken	if (error || (reply == NULL)) {
1187230592Sken		/* FIXME */
1188230592Sken		/* If the poll returns error then we need to do diag reset */
1189230592Sken		printf("%s: poll for page completed with error %d",
1190230592Sken		    __func__, error);
1191230592Sken		error = ENXIO;
1192230592Sken		goto out;
1193230592Sken	}
1194230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1195230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1196230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1197230592Sken		/* FIXME */
1198230592Sken		/* If the poll returns error then we need to do diag reset */
1199230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1200230592Sken		    __func__, ioc_status);
1201230592Sken		error = ENXIO;
1202230592Sken		goto out;
1203230592Sken	}
1204230592Sken	bcopy(page, config_page, cm->cm_length);
1205230592Skenout:
1206230592Sken	free(page, M_MPT2);
1207230592Sken	if (cm)
1208230592Sken		mps_free_command(sc, cm);
1209230592Sken	return (error);
1210230592Sken}
1211230592Sken
1212230592Sken/**
1213230592Sken * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
1214230592Sken * @sc: per adapter object
1215230592Sken * @mpi_reply: reply mf payload returned from firmware
1216230592Sken * @config_page: contents of the config page
1217230592Sken * @form: GET_NEXT_HANDLE or HANDLE
1218230592Sken * @handle: volume handle
1219230592Sken * Context: sleep.
1220230592Sken *
1221230592Sken * Returns 0 for success, non-zero for failure.
1222230592Sken */
1223230592Skenint
1224230592Skenmps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
1225230592Sken    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
1226230592Sken{
1227230592Sken	MPI2_CONFIG_REQUEST *request;
1228230592Sken	MPI2_CONFIG_REPLY *reply;
1229230592Sken	struct mps_command *cm;
1230230592Sken	Mpi2RaidVolPage1_t *page = NULL;
1231230592Sken	int error = 0;
1232230592Sken	u16 ioc_status;
1233230592Sken
1234230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1235230592Sken
1236230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1237230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1238230592Sken		    __LINE__);
1239230592Sken		error = EBUSY;
1240230592Sken		goto out;
1241230592Sken	}
1242230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1243230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1244230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1245230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1246230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1247230592Sken	request->Header.PageNumber = 1;
1248230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1249230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1250230592Sken	cm->cm_data = NULL;
1251253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1252230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1253230592Sken	if (error || (reply == NULL)) {
1254230592Sken		/* FIXME */
1255253550Sken		/*
1256253550Sken		 * If the request returns an error then we need to do a diag
1257253550Sken		 * reset
1258253550Sken		 */
1259253550Sken		printf("%s: request for header completed with error %d",
1260230592Sken		    __func__, error);
1261230592Sken		error = ENXIO;
1262230592Sken		goto out;
1263230592Sken	}
1264230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1265230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1266230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1267230592Sken		/* FIXME */
1268253550Sken		/*
1269253550Sken		 * If the request returns an error then we need to do a diag
1270253550Sken		 * reset
1271253550Sken		 */
1272230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1273230592Sken		    __func__, ioc_status);
1274230592Sken		error = ENXIO;
1275230592Sken		goto out;
1276230592Sken	}
1277230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1278230592Sken	 * counters to match - Need to review the reply FIFO handling.
1279230592Sken	 */
1280230592Sken	mps_free_command(sc, cm);
1281230592Sken
1282230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1283230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1284230592Sken		    __LINE__);
1285230592Sken		error = EBUSY;
1286230592Sken		goto out;
1287230592Sken	}
1288230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1289230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1290230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1291230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1292230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1293230592Sken	request->Header.PageNumber = 1;
1294230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1295230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1296230592Sken	request->PageAddress = htole32(form | handle);
1297230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1298230592Sken	cm->cm_sge = &request->PageBufferSGE;
1299230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1300230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1301230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1302230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1303230592Sken	if (!page) {
1304230592Sken		printf("%s: page alloc failed\n", __func__);
1305230592Sken		error = ENOMEM;
1306230592Sken		goto out;
1307230592Sken	}
1308230592Sken	cm->cm_data = page;
1309230592Sken
1310253550Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1311230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1312230592Sken	if (error || (reply == NULL)) {
1313230592Sken		/* FIXME */
1314253550Sken		/*
1315253550Sken		 * If the request returns an error then we need to do a diag
1316253550Sken		 * reset
1317253550Sken		 */
1318253550Sken		printf("%s: request for page completed with error %d",
1319230592Sken		    __func__, error);
1320230592Sken		error = ENXIO;
1321230592Sken		goto out;
1322230592Sken	}
1323230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1324230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1325230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1326230592Sken		/* FIXME */
1327253550Sken		/*
1328253550Sken		 * If the request returns an error then we need to do a diag
1329253550Sken		 * reset
1330253550Sken		 */
1331230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1332230592Sken		    __func__, ioc_status);
1333230592Sken		error = ENXIO;
1334230592Sken		goto out;
1335230592Sken	}
1336230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1337230592Sken	    sizeof(Mpi2RaidVolPage1_t)));
1338230592Skenout:
1339230592Sken	free(page, M_MPT2);
1340230592Sken	if (cm)
1341230592Sken		mps_free_command(sc, cm);
1342230592Sken	return (error);
1343230592Sken}
1344230592Sken
1345230592Sken/**
1346230592Sken * mps_config_get_volume_wwid - returns wwid given the volume handle
1347230592Sken * @sc: per adapter object
1348230592Sken * @volume_handle: volume handle
1349230592Sken * @wwid: volume wwid
1350230592Sken * Context: sleep.
1351230592Sken *
1352230592Sken * Returns 0 for success, non-zero for failure.
1353230592Sken */
1354230592Skenint
1355230592Skenmps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
1356230592Sken{
1357230592Sken	Mpi2ConfigReply_t mpi_reply;
1358230592Sken	Mpi2RaidVolPage1_t raid_vol_pg1;
1359230592Sken
1360230592Sken	*wwid = 0;
1361230592Sken	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
1362230592Sken	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
1363230592Sken		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
1364230592Sken		    raid_vol_pg1.WWID.Low);
1365230592Sken		return 0;
1366230592Sken	} else
1367230592Sken		return -1;
1368230592Sken}
1369230592Sken
1370230592Sken/**
1371230592Sken * mps_config_get_pd_pg0 - obtain raid phys disk page 0
1372230592Sken * @sc: per adapter object
1373230592Sken * @mpi_reply: reply mf payload returned from firmware
1374230592Sken * @config_page: contents of the config page
1375230592Sken * @page_address: form and handle value used to get page
1376230592Sken * Context: sleep.
1377230592Sken *
1378230592Sken * Returns 0 for success, non-zero for failure.
1379230592Sken */
1380230592Skenint
1381230592Skenmps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
1382230592Sken    Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
1383230592Sken{
1384230592Sken	MPI2_CONFIG_REQUEST *request;
1385230592Sken	MPI2_CONFIG_REPLY *reply;
1386230592Sken	struct mps_command *cm;
1387230592Sken	Mpi2RaidPhysDiskPage0_t *page = NULL;
1388230592Sken	int error = 0;
1389230592Sken	u16 ioc_status;
1390230592Sken
1391230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1392230592Sken
1393230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1394230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1395230592Sken		    __LINE__);
1396230592Sken		error = EBUSY;
1397230592Sken		goto out;
1398230592Sken	}
1399230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1400230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1401230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1402230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1403230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1404230592Sken	request->Header.PageNumber = 0;
1405230592Sken	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1406230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1407230592Sken	cm->cm_data = NULL;
1408253550Sken
1409253550Sken	/*
1410253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1411253550Sken	 * page is needed.
1412253550Sken	 */
1413286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
1414230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1415230592Sken	if (error || (reply == NULL)) {
1416230592Sken		/* FIXME */
1417230592Sken		/* If the poll returns error then we need to do diag reset */
1418230592Sken		printf("%s: poll for header completed with error %d",
1419230592Sken		    __func__, error);
1420230592Sken		error = ENXIO;
1421230592Sken		goto out;
1422230592Sken	}
1423230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1424230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1425230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1426230592Sken		/* FIXME */
1427230592Sken		/* If the poll returns error then we need to do diag reset */
1428230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1429230592Sken		    __func__, ioc_status);
1430230592Sken		error = ENXIO;
1431230592Sken		goto out;
1432230592Sken	}
1433230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1434230592Sken	 * counters to match - Need to review the reply FIFO handling.
1435230592Sken	 */
1436230592Sken	mps_free_command(sc, cm);
1437230592Sken
1438230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1439230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1440230592Sken		    __LINE__);
1441230592Sken		error = EBUSY;
1442230592Sken		goto out;
1443230592Sken	}
1444230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1445230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1446230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1447230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1448230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1449230592Sken	request->Header.PageNumber = 0;
1450230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1451230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1452230592Sken	request->PageAddress = page_address;
1453230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1454230592Sken	cm->cm_sge = &request->PageBufferSGE;
1455230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1456230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1457230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1458230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1459230592Sken	if (!page) {
1460230592Sken		printf("%s: page alloc failed\n", __func__);
1461230592Sken		error = ENOMEM;
1462230592Sken		goto out;
1463230592Sken	}
1464230592Sken	cm->cm_data = page;
1465230592Sken
1466253550Sken	/*
1467253550Sken	 * This page must be polled because the IOC isn't ready yet when this
1468253550Sken	 * page is needed.
1469253550Sken	 */
1470286568Sscottl	error = mps_wait_command(sc, cm, 60, 0);
1471230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1472230592Sken	if (error || (reply == NULL)) {
1473230592Sken		/* FIXME */
1474230592Sken		/* If the poll returns error then we need to do diag reset */
1475230592Sken		printf("%s: poll for page completed with error %d",
1476230592Sken		    __func__, error);
1477230592Sken		error = ENXIO;
1478230592Sken		goto out;
1479230592Sken	}
1480230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1481230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1482230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1483230592Sken		/* FIXME */
1484230592Sken		/* If the poll returns error then we need to do diag reset */
1485230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1486230592Sken		    __func__, ioc_status);
1487230592Sken		error = ENXIO;
1488230592Sken		goto out;
1489230592Sken	}
1490230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1491230592Sken	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1492230592Skenout:
1493230592Sken	free(page, M_MPT2);
1494230592Sken	if (cm)
1495230592Sken		mps_free_command(sc, cm);
1496230592Sken	return (error);
1497230592Sken}
1498