1230592Sken/*-
2237876Sken * Copyright (c) 2011, 2012 LSI Corp.
3230592Sken * All rights reserved.
4230592Sken *
5230592Sken * Redistribution and use in source and binary forms, with or without
6230592Sken * modification, are permitted provided that the following conditions
7230592Sken * are met:
8230592Sken * 1. Redistributions of source code must retain the above copyright
9230592Sken *    notice, this list of conditions and the following disclaimer.
10230592Sken * 2. Redistributions in binary form must reproduce the above copyright
11230592Sken *    notice, this list of conditions and the following disclaimer in the
12230592Sken *    documentation and/or other materials provided with the distribution.
13230592Sken *
14230592Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15230592Sken * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16230592Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17230592Sken * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18230592Sken * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19230592Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20230592Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21230592Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22230592Sken * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23230592Sken * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24230592Sken * SUCH DAMAGE.
25230592Sken *
26230592Sken * LSI MPT-Fusion Host Adapter FreeBSD
27230592Sken */
28230592Sken
29230592Sken#include <sys/cdefs.h>
30230592Sken__FBSDID("$FreeBSD$");
31230592Sken
32230592Sken/* TODO Move headers to mpsvar */
33230592Sken#include <sys/types.h>
34230592Sken#include <sys/param.h>
35230592Sken#include <sys/lock.h>
36230592Sken#include <sys/mutex.h>
37230592Sken#include <sys/systm.h>
38230592Sken#include <sys/kernel.h>
39230592Sken#include <sys/malloc.h>
40230592Sken#include <sys/kthread.h>
41230592Sken#include <sys/taskqueue.h>
42230592Sken#include <sys/bus.h>
43230592Sken#include <sys/endian.h>
44230592Sken#include <sys/sysctl.h>
45230592Sken#include <sys/eventhandler.h>
46230592Sken#include <sys/uio.h>
47230592Sken#include <machine/bus.h>
48230592Sken#include <machine/resource.h>
49230592Sken#include <dev/mps/mpi/mpi2_type.h>
50230592Sken#include <dev/mps/mpi/mpi2.h>
51230592Sken#include <dev/mps/mpi/mpi2_ioc.h>
52230592Sken#include <dev/mps/mpi/mpi2_sas.h>
53230592Sken#include <dev/mps/mpi/mpi2_cnfg.h>
54230592Sken#include <dev/mps/mpi/mpi2_init.h>
55230592Sken#include <dev/mps/mpi/mpi2_tool.h>
56230592Sken#include <dev/mps/mps_ioctl.h>
57230592Sken#include <dev/mps/mpsvar.h>
58230592Sken
59230592Sken/**
60230592Sken * mps_config_get_ioc_pg8 - obtain ioc page 8
61230592Sken * @sc: per adapter object
62230592Sken * @mpi_reply: reply mf payload returned from firmware
63230592Sken * @config_page: contents of the config page
64230592Sken * Context: sleep.
65230592Sken *
66230592Sken * Returns 0 for success, non-zero for failure.
67230592Sken */
68230592Skenint
69230592Skenmps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
70230592Sken    Mpi2IOCPage8_t *config_page)
71230592Sken{
72230592Sken	MPI2_CONFIG_REQUEST *request;
73230592Sken	MPI2_CONFIG_REPLY *reply;
74230592Sken	struct mps_command *cm;
75230592Sken	MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
76230592Sken	int error = 0;
77230592Sken	u16 ioc_status;
78230592Sken
79230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
80230592Sken
81230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
82230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
83230592Sken		    __LINE__);
84230592Sken		error = EBUSY;
85230592Sken		goto out;
86230592Sken	}
87230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
88230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
89230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
90230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
91230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
92230592Sken	request->Header.PageNumber = 8;
93230592Sken	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
94230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
95230592Sken	cm->cm_data = NULL;
96254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
97230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
98230592Sken	if (error || (reply == NULL)) {
99230592Sken		/* FIXME */
100254938Sken		/*
101254938Sken		 * If the request returns an error then we need to do a diag
102254938Sken		 * reset
103254938Sken		 */
104254938Sken		printf("%s: request for header completed with error %d",
105230592Sken		    __func__, error);
106230592Sken		error = ENXIO;
107230592Sken		goto out;
108230592Sken	}
109230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
110230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
111230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
112230592Sken		/* FIXME */
113254938Sken		/*
114254938Sken		 * If the request returns an error then we need to do a diag
115254938Sken		 * reset
116254938Sken		 */
117230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
118230592Sken		    __func__, ioc_status);
119230592Sken		error = ENXIO;
120230592Sken		goto out;
121230592Sken	}
122230592Sken	/* We have to do free and alloc for the reply-free and reply-post
123230592Sken	 * counters to match - Need to review the reply FIFO handling.
124230592Sken	 */
125230592Sken	mps_free_command(sc, cm);
126230592Sken
127230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
128230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
129230592Sken		    __LINE__);
130230592Sken		error = EBUSY;
131230592Sken		goto out;
132230592Sken	}
133230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
134230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
135230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
136230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
137230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
138230592Sken	request->Header.PageNumber = 8;
139230592Sken	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
140230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
141230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
142230592Sken	cm->cm_sge = &request->PageBufferSGE;
143230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
144230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
145230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
146230592Sken	page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
147230592Sken	if (!page) {
148230592Sken		printf("%s: page alloc failed\n", __func__);
149230592Sken		error = ENOMEM;
150230592Sken		goto out;
151230592Sken	}
152230592Sken	cm->cm_data = page;
153254938Sken
154254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
155230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
156230592Sken	if (error || (reply == NULL)) {
157230592Sken		/* FIXME */
158254938Sken		/*
159254938Sken		 * If the request returns an error then we need to do a diag
160254938Sken		 * reset
161254938Sken		 */
162254938Sken		printf("%s: request for page completed with error %d",
163230592Sken		    __func__, error);
164230592Sken		error = ENXIO;
165230592Sken		goto out;
166230592Sken	}
167230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
168230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
169230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
170230592Sken		/* FIXME */
171254938Sken		/*
172254938Sken		 * If the request returns an error then we need to do a diag
173254938Sken		 * reset
174254938Sken		 */
175230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
176230592Sken		    __func__, ioc_status);
177230592Sken		error = ENXIO;
178230592Sken		goto out;
179230592Sken	}
180230592Sken	bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
181230592Sken
182230592Skenout:
183230592Sken	free(page, M_MPT2);
184230592Sken	if (cm)
185230592Sken		mps_free_command(sc, cm);
186230592Sken	return (error);
187230592Sken}
188230592Sken
189230592Sken/**
190230592Sken * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
191230592Sken *   accordingly.  Currently, this page does not need to return to caller.
192230592Sken * @sc: per adapter object
193230592Sken * @mpi_reply: reply mf payload returned from firmware
194230592Sken * Context: sleep.
195230592Sken *
196230592Sken * Returns 0 for success, non-zero for failure.
197230592Sken */
198230592Skenint
199230592Skenmps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
200230592Sken{
201230592Sken	MPI2_CONFIG_REQUEST *request;
202230592Sken	MPI2_CONFIG_REPLY *reply;
203230592Sken	struct mps_command *cm;
204230592Sken	pMpi2ManufacturingPagePS_t page = NULL;
205230592Sken	uint32_t *pPS_info;
206230592Sken	uint8_t OEM_Value = 0;
207230592Sken	int error = 0;
208230592Sken	u16 ioc_status;
209230592Sken
210230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
211230592Sken
212230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
213230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
214230592Sken		    __LINE__);
215230592Sken		error = EBUSY;
216230592Sken		goto out;
217230592Sken	}
218230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
219230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
220230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
221230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
222230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
223230592Sken	request->Header.PageNumber = 10;
224230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
225230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
226230592Sken	cm->cm_data = NULL;
227254938Sken
228254938Sken	/*
229254938Sken	 * This page must be polled because the IOC isn't ready yet when this
230254938Sken	 * page is needed.
231254938Sken	 */
232230592Sken	error = mps_request_polled(sc, cm);
233230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
234230592Sken	if (error || (reply == NULL)) {
235230592Sken		/* FIXME */
236230592Sken		/* If the poll returns error then we need to do diag reset */
237230592Sken		printf("%s: poll for header completed with error %d",
238230592Sken		    __func__, error);
239230592Sken		error = ENXIO;
240230592Sken		goto out;
241230592Sken	}
242230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
243230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
244230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
245230592Sken		/* FIXME */
246230592Sken		/* If the poll returns error then we need to do diag reset */
247230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
248230592Sken		    __func__, ioc_status);
249230592Sken		error = ENXIO;
250230592Sken		goto out;
251230592Sken	}
252230592Sken	/* We have to do free and alloc for the reply-free and reply-post
253230592Sken	 * counters to match - Need to review the reply FIFO handling.
254230592Sken	 */
255230592Sken	mps_free_command(sc, cm);
256230592Sken
257230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
258230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
259230592Sken		    __LINE__);
260230592Sken		error = EBUSY;
261230592Sken		goto out;
262230592Sken	}
263230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
264230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
265230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
266230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
267230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
268230592Sken	request->Header.PageNumber = 10;
269230592Sken	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
270230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
271230592Sken	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
272230592Sken	cm->cm_sge = &request->PageBufferSGE;
273230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
274230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
275230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
276230592Sken	page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
277230592Sken	if (!page) {
278230592Sken		printf("%s: page alloc failed\n", __func__);
279230592Sken		error = ENOMEM;
280230592Sken		goto out;
281230592Sken	}
282230592Sken	cm->cm_data = page;
283254938Sken
284254938Sken	/*
285254938Sken	 * This page must be polled because the IOC isn't ready yet when this
286254938Sken	 * page is needed.
287254938Sken	 */
288230592Sken	error = mps_request_polled(sc, cm);
289230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
290230592Sken	if (error || (reply == NULL)) {
291230592Sken		/* FIXME */
292230592Sken		/* If the poll returns error then we need to do diag reset */
293230592Sken		printf("%s: poll for page completed with error %d",
294230592Sken		    __func__, error);
295230592Sken		error = ENXIO;
296230592Sken		goto out;
297230592Sken	}
298230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
299230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
300230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
301230592Sken		/* FIXME */
302230592Sken		/* If the poll returns error then we need to do diag reset */
303230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
304230592Sken		    __func__, ioc_status);
305230592Sken		error = ENXIO;
306230592Sken		goto out;
307230592Sken	}
308230592Sken
309230592Sken	/*
310230592Sken	 * If OEM ID is unknown, fail the request.
311230592Sken	 */
312230592Sken	sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
313230592Sken	OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
314230592Sken	if (OEM_Value != MPS_WD_LSI_OEM) {
315230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
316230592Sken		    "(0x%x)\n", OEM_Value);
317230592Sken		error = ENXIO;
318230592Sken		goto out;
319230592Sken	}
320230592Sken
321230592Sken	/*
322230592Sken	 * Set the phys disks hide/expose value.
323230592Sken	 */
324230592Sken	pPS_info = &page->ProductSpecificInfo;
325230592Sken	sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
326230592Sken	sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
327230592Sken	if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
328230592Sken	    (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
329230592Sken	    (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
330230592Sken		mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
331230592Sken		    "hide/expose: 0x%x\n", sc->WD_hide_expose);
332230592Sken		error = ENXIO;
333230592Sken		goto out;
334230592Sken	}
335230592Sken
336230592Skenout:
337230592Sken	free(page, M_MPT2);
338230592Sken	if (cm)
339230592Sken		mps_free_command(sc, cm);
340230592Sken	return (error);
341230592Sken}
342230592Sken
343230592Sken/**
344230592Sken * mps_base_static_config_pages - static start of day config pages.
345230592Sken * @sc: per adapter object
346230592Sken *
347230592Sken * Return nothing.
348230592Sken */
349230592Skenvoid
350230592Skenmps_base_static_config_pages(struct mps_softc *sc)
351230592Sken{
352230592Sken	Mpi2ConfigReply_t	mpi_reply;
353230592Sken	int			retry;
354230592Sken
355230592Sken	retry = 0;
356230592Sken	while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
357230592Sken		retry++;
358230592Sken		if (retry > 5) {
359230592Sken			/* We need to Handle this situation */
360230592Sken			/*FIXME*/
361230592Sken			break;
362230592Sken		}
363230592Sken	}
364230592Sken}
365230592Sken
366230592Sken/**
367230592Sken * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
368230592Sken *    be called after discovery is complete to guarentee that IR info is there.
369230592Sken * @sc: per adapter object
370230592Sken *
371230592Sken * Return nothing.
372230592Sken */
373230592Skenvoid
374230592Skenmps_wd_config_pages(struct mps_softc *sc)
375230592Sken{
376230592Sken	Mpi2ConfigReply_t	mpi_reply;
377230592Sken	pMpi2RaidVolPage0_t	raid_vol_pg0 = NULL;
378230592Sken	Mpi2RaidPhysDiskPage0_t	phys_disk_pg0;
379230592Sken	pMpi2RaidVol0PhysDisk_t	pRVPD;
380230592Sken	uint32_t		stripe_size, phys_disk_page_address;
381230592Sken	uint16_t		block_size;
382230592Sken	uint8_t			index, stripe_exp = 0, block_exp = 0;
383230592Sken
384230592Sken	/*
385230592Sken	 * Get the WD settings from manufacturing page 10 if using a WD HBA.
386230592Sken	 * This will be used to determine if phys disks should always be
387230592Sken	 * hidden, hidden only if part of a WD volume, or never hidden.  Also,
388230592Sken	 * get the WD RAID Volume info and fail if volume does not exist or if
389230592Sken	 * volume does not meet the requirements for a WD volume.  No retry
390230592Sken	 * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
391230592Sken	 * Valid flag if Volume info fails.
392230592Sken	 */
393230592Sken	sc->WD_valid_config = FALSE;
394230592Sken	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
395230592Sken		if (mps_config_get_man_pg10(sc, &mpi_reply)) {
396230592Sken			mps_dprint(sc, MPS_FAULT,
397230592Sken			    "mps_config_get_man_pg10 failed! Using 0 (Hide "
398230592Sken			    "Always) for WarpDrive hide/expose value.\n");
399230592Sken			sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
400230592Sken		}
401230592Sken
402230592Sken		/*
403230592Sken		 * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
404230592Sken		 */
405230592Sken		raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) +
406230592Sken		    (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
407230592Sken		    M_MPT2, M_ZERO | M_NOWAIT);
408230592Sken		if (!raid_vol_pg0) {
409230592Sken			printf("%s: page alloc failed\n", __func__);
410230592Sken			goto out;
411230592Sken		}
412230592Sken
413230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
414230592Sken		    0x0000FFFF)) {
415230592Sken			mps_dprint(sc, MPS_INFO,
416230592Sken			    "mps_config_get_raid_volume_pg0 failed! Assuming "
417230592Sken			    "WarpDrive IT mode.\n");
418230592Sken			goto out;
419230592Sken		}
420230592Sken
421230592Sken		/*
422230592Sken		 * Check for valid WD configuration:
423230592Sken		 *   volume type is RAID0
424230592Sken		 *   number of phys disks in the volume is no more than 8
425230592Sken		 */
426230592Sken		if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
427230592Sken		    (raid_vol_pg0->NumPhysDisks > 8)) {
428230592Sken			mps_dprint(sc, MPS_FAULT,
429230592Sken			    "Invalid WarpDrive configuration. Direct Drive I/O "
430230592Sken			    "will not be used.\n");
431230592Sken			goto out;
432230592Sken		}
433230592Sken
434230592Sken		/*
435230592Sken		 * Save the WD RAID data to be used during WD I/O.
436230592Sken		 */
437230592Sken		sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
438230592Sken		    32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
439230592Sken		sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
440230592Sken		sc->DD_dev_handle = raid_vol_pg0->DevHandle;
441230592Sken		sc->DD_stripe_size = raid_vol_pg0->StripeSize;
442230592Sken		sc->DD_block_size = raid_vol_pg0->BlockSize;
443230592Sken
444230592Sken		/*
445230592Sken		 * Find power of 2 of stripe size and set this as the exponent.
446230592Sken		 * Fail if stripe size is 0.
447230592Sken		 */
448230592Sken		stripe_size = raid_vol_pg0->StripeSize;
449230592Sken		for (index = 0; index < 32; index++) {
450230592Sken			if (stripe_size & 1)
451230592Sken				break;
452230592Sken			stripe_exp++;
453230592Sken			stripe_size >>= 1;
454230592Sken		}
455230592Sken		if (index == 32) {
456230592Sken			mps_dprint(sc, MPS_FAULT,
457230592Sken			    "RAID Volume's stripe size is 0. Direct Drive I/O "
458230592Sken			    "will not be used.\n");
459230592Sken			goto out;
460230592Sken		}
461230592Sken		sc->DD_stripe_exponent = stripe_exp;
462230592Sken
463230592Sken		/*
464230592Sken		 * Find power of 2 of block size and set this as the exponent.
465230592Sken		 * Fail if block size is 0.
466230592Sken		 */
467230592Sken		block_size = raid_vol_pg0->BlockSize;
468230592Sken		for (index = 0; index < 16; index++) {
469230592Sken			if (block_size & 1)
470230592Sken				break;
471230592Sken			block_exp++;
472230592Sken			block_size >>= 1;
473230592Sken		}
474230592Sken		if (index == 16) {
475230592Sken			mps_dprint(sc, MPS_FAULT,
476230592Sken			    "RAID Volume's block size is 0. Direct Drive I/O "
477230592Sken			    "will not be used.\n");
478230592Sken			goto out;
479230592Sken		}
480230592Sken		sc->DD_block_exponent = block_exp;
481230592Sken
482230592Sken		/*
483230592Sken		 * Loop through all of the volume's Phys Disks to map the phys
484230592Sken		 * disk number into the columm map.  This is used during Direct
485230592Sken		 * Drive I/O to send the request to the correct SSD.
486230592Sken		 */
487230592Sken		pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
488230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
489230592Sken			sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
490230592Sken			    pRVPD->PhysDiskNum;
491230592Sken			pRVPD++;
492230592Sken		}
493230592Sken
494230592Sken		/*
495230592Sken		 * Get second RAID Volume Page0 using previous handle.  This
496230592Sken		 * page should not exist.  If it does, must not proceed with WD
497230592Sken		 * handling.
498230592Sken		 */
499230592Sken		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
500230592Sken		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
501230592Sken			if (mpi_reply.IOCStatus !=
502230592Sken			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
503230592Sken				mps_dprint(sc, MPS_FAULT,
504230592Sken				    "Multiple RAID Volume Page0! Direct Drive "
505230592Sken				    "I/O will not be used.\n");
506230592Sken				goto out;
507230592Sken			}
508230592Sken		} else {
509230592Sken			mps_dprint(sc, MPS_FAULT,
510230592Sken			    "Multiple volumes! Direct Drive I/O will not be "
511230592Sken			    "used.\n");
512230592Sken			goto out;
513230592Sken		}
514230592Sken
515230592Sken		/*
516230592Sken		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
517230592Sken		 */
518230592Sken		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
519230592Sken			phys_disk_page_address =
520230592Sken			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
521230592Sken			    sc->DD_column_map[index].phys_disk_num;
522230592Sken			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
523230592Sken			    &phys_disk_pg0, phys_disk_page_address)) {
524230592Sken				mps_dprint(sc, MPS_FAULT,
525230592Sken				    "mps_config_get_raid_pd_pg0 failed! Direct "
526230592Sken				    "Drive I/O will not be used.\n");
527230592Sken				goto out;
528230592Sken			}
529230592Sken			if (phys_disk_pg0.DevHandle == 0xFFFF) {
530230592Sken				mps_dprint(sc, MPS_FAULT,
531230592Sken				    "Invalid Phys Disk DevHandle! Direct Drive "
532230592Sken				    "I/O will not be used.\n");
533230592Sken				goto out;
534230592Sken			}
535230592Sken			sc->DD_column_map[index].dev_handle =
536230592Sken			    phys_disk_pg0.DevHandle;
537230592Sken		}
538230592Sken		sc->WD_valid_config = TRUE;
539230592Skenout:
540230592Sken		if (raid_vol_pg0)
541230592Sken			free(raid_vol_pg0, M_MPT2);
542230592Sken	}
543230592Sken}
544230592Sken
545230592Sken/**
546230592Sken * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
547230592Sken * @sc: per adapter object
548230592Sken * @mpi_reply: reply mf payload returned from firmware
549230592Sken * @config_page: contents of the config page
550230592Sken * @sz: size of buffer passed in config_page
551230592Sken * Context: sleep.
552230592Sken *
553230592Sken * Returns 0 for success, non-zero for failure.
554230592Sken */
555230592Skenint
556230592Skenmps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
557230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 sz)
558230592Sken{
559230592Sken	MPI2_CONFIG_REQUEST *request;
560230592Sken	MPI2_CONFIG_REPLY *reply;
561230592Sken	struct mps_command *cm;
562230592Sken	Mpi2DriverMappingPage0_t *page = NULL;
563230592Sken	int error = 0;
564230592Sken	u16 ioc_status;
565230592Sken
566230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
567230592Sken
568230592Sken	memset(config_page, 0, sz);
569230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
570230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
571230592Sken		    __LINE__);
572230592Sken		error = EBUSY;
573230592Sken		goto out;
574230592Sken	}
575230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
576230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
577230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
578230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
579230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
580230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
581230592Sken	request->Header.PageNumber = 0;
582230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
583230592Sken	request->PageAddress = sc->max_dpm_entries <<
584230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
585230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
586230592Sken	cm->cm_data = NULL;
587254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
588230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
589230592Sken	if (error || (reply == NULL)) {
590230592Sken		/* FIXME */
591254938Sken		/*
592254938Sken		 * If the request returns an error then we need to do a diag
593254938Sken		 * reset
594254938Sken		 */
595254938Sken		printf("%s: request for header completed with error %d",
596230592Sken		    __func__, error);
597230592Sken		error = ENXIO;
598230592Sken		goto out;
599230592Sken	}
600230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
601230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
602230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
603230592Sken		/* FIXME */
604254938Sken		/*
605254938Sken		 * If the request returns an error then we need to do a diag
606254938Sken		 * reset
607254938Sken		 */
608230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
609230592Sken		    __func__, ioc_status);
610230592Sken		error = ENXIO;
611230592Sken		goto out;
612230592Sken	}
613230592Sken	/* We have to do free and alloc for the reply-free and reply-post
614230592Sken	 * counters to match - Need to review the reply FIFO handling.
615230592Sken	 */
616230592Sken	mps_free_command(sc, cm);
617230592Sken
618230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
619230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
620230592Sken		    __LINE__);
621230592Sken		error = EBUSY;
622230592Sken		goto out;
623230592Sken	}
624230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
625230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
626230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
627230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
628230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
629230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
630230592Sken	request->Header.PageNumber = 0;
631230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
632230592Sken	request->PageAddress = sc->max_dpm_entries <<
633230592Sken	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
634230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
635230592Sken	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
636230592Sken	cm->cm_sge = &request->PageBufferSGE;
637230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
638230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
639230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
640230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
641230592Sken	if (!page) {
642230592Sken		printf("%s: page alloc failed\n", __func__);
643230592Sken		error = ENOMEM;
644230592Sken		goto out;
645230592Sken	}
646230592Sken	cm->cm_data = page;
647254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
648230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
649230592Sken	if (error || (reply == NULL)) {
650230592Sken		/* FIXME */
651254938Sken		/*
652254938Sken		 * If the request returns an error then we need to do a diag
653254938Sken		 * reset
654254938Sken		 */
655254938Sken		printf("%s: request for page completed with error %d",
656230592Sken		    __func__, error);
657230592Sken		error = ENXIO;
658230592Sken		goto out;
659230592Sken	}
660230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
661230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
662230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
663230592Sken		/* FIXME */
664254938Sken		/*
665254938Sken		 * If the request returns an error then we need to do a diag
666254938Sken		 * reset
667254938Sken		 */
668230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
669230592Sken		    __func__, ioc_status);
670230592Sken		error = ENXIO;
671230592Sken		goto out;
672230592Sken	}
673230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sz));
674230592Skenout:
675230592Sken	free(page, M_MPT2);
676230592Sken	if (cm)
677230592Sken		mps_free_command(sc, cm);
678230592Sken	return (error);
679230592Sken}
680230592Sken
681230592Sken/**
682230592Sken * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
683230592Sken * @sc: per adapter object
684230592Sken * @mpi_reply: reply mf payload returned from firmware
685230592Sken * @config_page: contents of the config page
686230592Sken * @entry_idx: entry index in DPM Page0 to be modified
687230592Sken * Context: sleep.
688230592Sken *
689230592Sken * Returns 0 for success, non-zero for failure.
690230592Sken */
691230592Sken
692230592Skenint mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
693230592Sken    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
694230592Sken{
695230592Sken	MPI2_CONFIG_REQUEST *request;
696230592Sken	MPI2_CONFIG_REPLY *reply;
697230592Sken	struct mps_command *cm;
698230592Sken	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
699230592Sken	int error = 0;
700230592Sken	u16 ioc_status;
701230592Sken
702230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
703230592Sken
704230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
705230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
706230592Sken		    __LINE__);
707230592Sken		error = EBUSY;
708230592Sken		goto out;
709230592Sken	}
710230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
711230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
712230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
713230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
714230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
715230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
716230592Sken	request->Header.PageNumber = 0;
717230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
718237876Sken	/* We can remove below two lines ????*/
719230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
720230592Sken	request->PageAddress |= htole16(entry_idx);
721230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
722230592Sken	cm->cm_data = NULL;
723254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
724230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
725230592Sken	if (error || (reply == NULL)) {
726230592Sken		/* FIXME */
727254938Sken		/*
728254938Sken		 * If the request returns an error then we need to do a diag
729254938Sken		 * reset
730254938Sken		 */
731254938Sken		printf("%s: request for header completed with error %d",
732230592Sken		    __func__, error);
733230592Sken		error = ENXIO;
734230592Sken		goto out;
735230592Sken	}
736230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
737230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
738230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
739230592Sken		/* FIXME */
740254938Sken		/*
741254938Sken		 * If the request returns an error then we need to do a diag
742254938Sken		 * reset
743254938Sken		 */
744230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
745230592Sken		    __func__, ioc_status);
746230592Sken		error = ENXIO;
747230592Sken		goto out;
748230592Sken	}
749230592Sken	/* We have to do free and alloc for the reply-free and reply-post
750230592Sken	 * counters to match - Need to review the reply FIFO handling.
751230592Sken	 */
752230592Sken	mps_free_command(sc, cm);
753230592Sken
754230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
755230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
756230592Sken		    __LINE__);
757230592Sken		error = EBUSY;
758230592Sken		goto out;
759230592Sken	}
760230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
761230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
762230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
763230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
764230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
765230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
766230592Sken	request->Header.PageNumber = 0;
767230592Sken	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
768230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
769230592Sken	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
770230592Sken	request->PageAddress |= htole16(entry_idx);
771230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
772230592Sken	cm->cm_sge = &request->PageBufferSGE;
773230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
774230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
775230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
776230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
777230592Sken	if (!page) {
778230592Sken		printf("%s: page alloc failed\n", __func__);
779230592Sken		error = ENOMEM;
780230592Sken		goto out;
781230592Sken	}
782230592Sken	bcopy(config_page, page, MIN(cm->cm_length,
783230592Sken	    (sizeof(Mpi2DriverMappingPage0_t))));
784230592Sken	cm->cm_data = page;
785254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
786230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
787230592Sken	if (error || (reply == NULL)) {
788230592Sken		/* FIXME */
789254938Sken		/*
790254938Sken		 * If the request returns an error then we need to do a diag
791254938Sken		 * reset
792254938Sken		 */
793254938Sken		printf("%s: request to write page completed with error %d",
794230592Sken		    __func__, error);
795230592Sken		error = ENXIO;
796230592Sken		goto out;
797230592Sken	}
798230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
799230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
800230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
801230592Sken		/* FIXME */
802254938Sken		/*
803254938Sken		 * If the request returns an error then we need to do a diag
804254938Sken		 * reset
805254938Sken		 */
806230592Sken		printf("%s: page written with error; iocstatus = 0x%x\n",
807230592Sken		    __func__, ioc_status);
808230592Sken		error = ENXIO;
809230592Sken		goto out;
810230592Sken	}
811230592Skenout:
812230592Sken	free(page, M_MPT2);
813230592Sken	if (cm)
814230592Sken		mps_free_command(sc, cm);
815230592Sken	return (error);
816230592Sken}
817230592Sken
818230592Sken/**
819230592Sken * mps_config_get_sas_device_pg0 - obtain sas device page 0
820230592Sken * @sc: per adapter object
821230592Sken * @mpi_reply: reply mf payload returned from firmware
822230592Sken * @config_page: contents of the config page
823230592Sken * @form: GET_NEXT_HANDLE or HANDLE
824230592Sken * @handle: device handle
825230592Sken * Context: sleep.
826230592Sken *
827230592Sken * Returns 0 for success, non-zero for failure.
828230592Sken */
829230592Skenint
830230592Skenmps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
831230592Sken    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
832230592Sken{
833230592Sken	MPI2_CONFIG_REQUEST *request;
834230592Sken	MPI2_CONFIG_REPLY *reply;
835230592Sken	struct mps_command *cm;
836230592Sken	Mpi2SasDevicePage0_t *page = NULL;
837230592Sken	int error = 0;
838230592Sken	u16 ioc_status;
839230592Sken
840230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
841230592Sken
842230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
843230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
844230592Sken		    __LINE__);
845230592Sken		error = EBUSY;
846230592Sken		goto out;
847230592Sken	}
848230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
849230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
850230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
851230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
852230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
853230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
854230592Sken	request->Header.PageNumber = 0;
855230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
856230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
857230592Sken	cm->cm_data = NULL;
858254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
859230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
860230592Sken	if (error || (reply == NULL)) {
861230592Sken		/* FIXME */
862254938Sken		/*
863254938Sken		 * If the request returns an error then we need to do a diag
864254938Sken		 * reset
865254938Sken		 */
866254938Sken		printf("%s: request for header completed with error %d",
867230592Sken		    __func__, error);
868230592Sken		error = ENXIO;
869230592Sken		goto out;
870230592Sken	}
871230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
872230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
873230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
874230592Sken		/* FIXME */
875254938Sken		/*
876254938Sken		 * If the request returns an error then we need to do a diag
877254938Sken		 * reset
878254938Sken		 */
879230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
880230592Sken		    __func__, ioc_status);
881230592Sken		error = ENXIO;
882230592Sken		goto out;
883230592Sken	}
884230592Sken	/* We have to do free and alloc for the reply-free and reply-post
885230592Sken	 * counters to match - Need to review the reply FIFO handling.
886230592Sken	 */
887230592Sken	mps_free_command(sc, cm);
888230592Sken
889230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
890230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
891230592Sken		    __LINE__);
892230592Sken		error = EBUSY;
893230592Sken		goto out;
894230592Sken	}
895230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
896230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
897230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
898230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
899230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
900230592Sken	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
901230592Sken	request->Header.PageNumber = 0;
902230592Sken	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
903230592Sken	request->ExtPageLength = mpi_reply->ExtPageLength;
904230592Sken	request->PageAddress = htole32(form | handle);
905230592Sken	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
906230592Sken	cm->cm_sge = &request->PageBufferSGE;
907230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
908230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
909230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
910230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
911230592Sken	if (!page) {
912230592Sken		printf("%s: page alloc failed\n", __func__);
913230592Sken		error = ENOMEM;
914230592Sken		goto out;
915230592Sken	}
916230592Sken	cm->cm_data = page;
917230592Sken
918254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
919230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
920230592Sken	if (error || (reply == NULL)) {
921230592Sken		/* FIXME */
922254938Sken		/*
923254938Sken		 * If the request returns an error then we need to do a diag
924254938Sken		 * reset
925254938Sken		 */
926254938Sken		printf("%s: request for page completed with error %d",
927230592Sken		    __func__, error);
928230592Sken		error = ENXIO;
929230592Sken		goto out;
930230592Sken	}
931230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
932230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
933230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
934230592Sken		/* FIXME */
935254938Sken		/*
936254938Sken		 * If the request returns an error then we need to do a diag
937254938Sken		 * reset
938254938Sken		 */
939230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
940230592Sken		    __func__, ioc_status);
941230592Sken		error = ENXIO;
942230592Sken		goto out;
943230592Sken	}
944230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
945230592Sken	    sizeof(Mpi2SasDevicePage0_t)));
946230592Skenout:
947230592Sken	free(page, M_MPT2);
948230592Sken	if (cm)
949230592Sken		mps_free_command(sc, cm);
950230592Sken	return (error);
951230592Sken}
952230592Sken
953230592Sken/**
954230592Sken * mps_config_get_bios_pg3 - obtain BIOS page 3
955230592Sken * @sc: per adapter object
956230592Sken * @mpi_reply: reply mf payload returned from firmware
957230592Sken * @config_page: contents of the config page
958230592Sken * Context: sleep.
959230592Sken *
960230592Sken * Returns 0 for success, non-zero for failure.
961230592Sken */
962230592Skenint
963230592Skenmps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
964230592Sken    Mpi2BiosPage3_t *config_page)
965230592Sken{
966230592Sken	MPI2_CONFIG_REQUEST *request;
967230592Sken	MPI2_CONFIG_REPLY *reply;
968230592Sken	struct mps_command *cm;
969230592Sken	Mpi2BiosPage3_t *page = NULL;
970230592Sken	int error = 0;
971230592Sken	u16 ioc_status;
972230592Sken
973230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
974230592Sken
975230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
976230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
977230592Sken		    __LINE__);
978230592Sken		error = EBUSY;
979230592Sken		goto out;
980230592Sken	}
981230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
982230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
983230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
984230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
985230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
986230592Sken	request->Header.PageNumber = 3;
987230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
988230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
989230592Sken	cm->cm_data = NULL;
990254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
991230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
992230592Sken	if (error || (reply == NULL)) {
993230592Sken		/* FIXME */
994254938Sken		/*
995254938Sken		 * If the request returns an error then we need to do a diag
996254938Sken		 * reset
997254938Sken		 */
998254938Sken		printf("%s: request for header completed with error %d",
999230592Sken		    __func__, error);
1000230592Sken		error = ENXIO;
1001230592Sken		goto out;
1002230592Sken	}
1003230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1004230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1005230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1006230592Sken		/* FIXME */
1007254938Sken		/*
1008254938Sken		 * If the request returns an error then we need to do a diag
1009254938Sken		 * reset
1010254938Sken		 */
1011230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1012230592Sken		    __func__, ioc_status);
1013230592Sken		error = ENXIO;
1014230592Sken		goto out;
1015230592Sken	}
1016230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1017230592Sken	 * counters to match - Need to review the reply FIFO handling.
1018230592Sken	 */
1019230592Sken	mps_free_command(sc, cm);
1020230592Sken
1021230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1022230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1023230592Sken		    __LINE__);
1024230592Sken		error = EBUSY;
1025230592Sken		goto out;
1026230592Sken	}
1027230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1028230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1029230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1030230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1031230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
1032230592Sken	request->Header.PageNumber = 3;
1033230592Sken	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
1034230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1035230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1036230592Sken	cm->cm_sge = &request->PageBufferSGE;
1037230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1038230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1039230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1040230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1041230592Sken	if (!page) {
1042230592Sken		printf("%s: page alloc failed\n", __func__);
1043230592Sken		error = ENOMEM;
1044230592Sken		goto out;
1045230592Sken	}
1046230592Sken	cm->cm_data = page;
1047230592Sken
1048254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1049230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1050230592Sken	if (error || (reply == NULL)) {
1051230592Sken		/* FIXME */
1052254938Sken		/*
1053254938Sken		 * If the request returns an error then we need to do a diag
1054254938Sken		 * reset
1055254938Sken		 */
1056254938Sken		printf("%s: request for page completed with error %d",
1057230592Sken		    __func__, error);
1058230592Sken		error = ENXIO;
1059230592Sken		goto out;
1060230592Sken	}
1061230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1062230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1063230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1064230592Sken		/* FIXME */
1065254938Sken		/*
1066254938Sken		 * If the request returns an error then we need to do a diag
1067254938Sken		 * reset
1068254938Sken		 */
1069230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1070230592Sken		    __func__, ioc_status);
1071230592Sken		error = ENXIO;
1072230592Sken		goto out;
1073230592Sken	}
1074230592Sken	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
1075230592Skenout:
1076230592Sken	free(page, M_MPT2);
1077230592Sken	if (cm)
1078230592Sken		mps_free_command(sc, cm);
1079230592Sken	return (error);
1080230592Sken}
1081230592Sken
1082230592Sken/**
1083230592Sken * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
1084230592Sken * @sc: per adapter object
1085230592Sken * @mpi_reply: reply mf payload returned from firmware
1086230592Sken * @config_page: contents of the config page
1087230592Sken * @page_address: form and handle value used to get page
1088230592Sken * Context: sleep.
1089230592Sken *
1090230592Sken * Returns 0 for success, non-zero for failure.
1091230592Sken */
1092230592Skenint
1093230592Skenmps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
1094230592Sken    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
1095230592Sken{
1096230592Sken	MPI2_CONFIG_REQUEST *request;
1097230592Sken	MPI2_CONFIG_REPLY *reply;
1098230592Sken	struct mps_command *cm;
1099230592Sken	Mpi2RaidVolPage0_t *page = NULL;
1100230592Sken	int error = 0;
1101230592Sken	u16 ioc_status;
1102230592Sken
1103230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1104230592Sken
1105230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1106230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1107230592Sken		    __LINE__);
1108230592Sken		error = EBUSY;
1109230592Sken		goto out;
1110230592Sken	}
1111230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1112230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1113230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1114230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1115230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1116230592Sken	request->Header.PageNumber = 0;
1117230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
1118230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1119230592Sken	cm->cm_data = NULL;
1120254938Sken
1121254938Sken	/*
1122254938Sken	 * This page must be polled because the IOC isn't ready yet when this
1123254938Sken	 * page is needed.
1124254938Sken	 */
1125230592Sken	error = mps_request_polled(sc, cm);
1126230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1127230592Sken	if (error || (reply == NULL)) {
1128230592Sken		/* FIXME */
1129230592Sken		/* If the poll returns error then we need to do diag reset */
1130230592Sken		printf("%s: poll for header completed with error %d",
1131230592Sken		    __func__, error);
1132230592Sken		error = ENXIO;
1133230592Sken		goto out;
1134230592Sken	}
1135230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1136230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1137230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1138230592Sken		/* FIXME */
1139230592Sken		/* If the poll returns error then we need to do diag reset */
1140230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1141230592Sken		    __func__, ioc_status);
1142230592Sken		error = ENXIO;
1143230592Sken		goto out;
1144230592Sken	}
1145230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1146230592Sken	 * counters to match - Need to review the reply FIFO handling.
1147230592Sken	 */
1148230592Sken	mps_free_command(sc, cm);
1149230592Sken
1150230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1151230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1152230592Sken		    __LINE__);
1153230592Sken		error = EBUSY;
1154230592Sken		goto out;
1155230592Sken	}
1156230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1157230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1158230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1159230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1160230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1161230592Sken	request->Header.PageNumber = 0;
1162230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1163230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1164230592Sken	request->PageAddress = page_address;
1165230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1166230592Sken	cm->cm_sge = &request->PageBufferSGE;
1167230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1168230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1169230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1170230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1171230592Sken	if (!page) {
1172230592Sken		printf("%s: page alloc failed\n", __func__);
1173230592Sken		error = ENOMEM;
1174230592Sken		goto out;
1175230592Sken	}
1176230592Sken	cm->cm_data = page;
1177230592Sken
1178254938Sken	/*
1179254938Sken	 * This page must be polled because the IOC isn't ready yet when this
1180254938Sken	 * page is needed.
1181254938Sken	 */
1182230592Sken	error = mps_request_polled(sc, cm);
1183230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1184230592Sken	if (error || (reply == NULL)) {
1185230592Sken		/* FIXME */
1186230592Sken		/* If the poll returns error then we need to do diag reset */
1187230592Sken		printf("%s: poll for page completed with error %d",
1188230592Sken		    __func__, error);
1189230592Sken		error = ENXIO;
1190230592Sken		goto out;
1191230592Sken	}
1192230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1193230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1194230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1195230592Sken		/* FIXME */
1196230592Sken		/* If the poll returns error then we need to do diag reset */
1197230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1198230592Sken		    __func__, ioc_status);
1199230592Sken		error = ENXIO;
1200230592Sken		goto out;
1201230592Sken	}
1202230592Sken	bcopy(page, config_page, cm->cm_length);
1203230592Skenout:
1204230592Sken	free(page, M_MPT2);
1205230592Sken	if (cm)
1206230592Sken		mps_free_command(sc, cm);
1207230592Sken	return (error);
1208230592Sken}
1209230592Sken
1210230592Sken/**
1211230592Sken * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
1212230592Sken * @sc: per adapter object
1213230592Sken * @mpi_reply: reply mf payload returned from firmware
1214230592Sken * @config_page: contents of the config page
1215230592Sken * @form: GET_NEXT_HANDLE or HANDLE
1216230592Sken * @handle: volume handle
1217230592Sken * Context: sleep.
1218230592Sken *
1219230592Sken * Returns 0 for success, non-zero for failure.
1220230592Sken */
1221230592Skenint
1222230592Skenmps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
1223230592Sken    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
1224230592Sken{
1225230592Sken	MPI2_CONFIG_REQUEST *request;
1226230592Sken	MPI2_CONFIG_REPLY *reply;
1227230592Sken	struct mps_command *cm;
1228230592Sken	Mpi2RaidVolPage1_t *page = NULL;
1229230592Sken	int error = 0;
1230230592Sken	u16 ioc_status;
1231230592Sken
1232230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1233230592Sken
1234230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1235230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1236230592Sken		    __LINE__);
1237230592Sken		error = EBUSY;
1238230592Sken		goto out;
1239230592Sken	}
1240230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1241230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1242230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1243230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1244230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1245230592Sken	request->Header.PageNumber = 1;
1246230592Sken	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
1247230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1248230592Sken	cm->cm_data = NULL;
1249254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1250230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1251230592Sken	if (error || (reply == NULL)) {
1252230592Sken		/* FIXME */
1253254938Sken		/*
1254254938Sken		 * If the request returns an error then we need to do a diag
1255254938Sken		 * reset
1256254938Sken		 */
1257254938Sken		printf("%s: request for header completed with error %d",
1258230592Sken		    __func__, error);
1259230592Sken		error = ENXIO;
1260230592Sken		goto out;
1261230592Sken	}
1262230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1263230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1264230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1265230592Sken		/* FIXME */
1266254938Sken		/*
1267254938Sken		 * If the request returns an error then we need to do a diag
1268254938Sken		 * reset
1269254938Sken		 */
1270230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1271230592Sken		    __func__, ioc_status);
1272230592Sken		error = ENXIO;
1273230592Sken		goto out;
1274230592Sken	}
1275230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1276230592Sken	 * counters to match - Need to review the reply FIFO handling.
1277230592Sken	 */
1278230592Sken	mps_free_command(sc, cm);
1279230592Sken
1280230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1281230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1282230592Sken		    __LINE__);
1283230592Sken		error = EBUSY;
1284230592Sken		goto out;
1285230592Sken	}
1286230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1287230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1288230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1289230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1290230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
1291230592Sken	request->Header.PageNumber = 1;
1292230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1293230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1294230592Sken	request->PageAddress = htole32(form | handle);
1295230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1296230592Sken	cm->cm_sge = &request->PageBufferSGE;
1297230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1298230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1299230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1300230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1301230592Sken	if (!page) {
1302230592Sken		printf("%s: page alloc failed\n", __func__);
1303230592Sken		error = ENOMEM;
1304230592Sken		goto out;
1305230592Sken	}
1306230592Sken	cm->cm_data = page;
1307230592Sken
1308254938Sken	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
1309230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1310230592Sken	if (error || (reply == NULL)) {
1311230592Sken		/* FIXME */
1312254938Sken		/*
1313254938Sken		 * If the request returns an error then we need to do a diag
1314254938Sken		 * reset
1315254938Sken		 */
1316254938Sken		printf("%s: request for page completed with error %d",
1317230592Sken		    __func__, error);
1318230592Sken		error = ENXIO;
1319230592Sken		goto out;
1320230592Sken	}
1321230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1322230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1323230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1324230592Sken		/* FIXME */
1325254938Sken		/*
1326254938Sken		 * If the request returns an error then we need to do a diag
1327254938Sken		 * reset
1328254938Sken		 */
1329230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1330230592Sken		    __func__, ioc_status);
1331230592Sken		error = ENXIO;
1332230592Sken		goto out;
1333230592Sken	}
1334230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1335230592Sken	    sizeof(Mpi2RaidVolPage1_t)));
1336230592Skenout:
1337230592Sken	free(page, M_MPT2);
1338230592Sken	if (cm)
1339230592Sken		mps_free_command(sc, cm);
1340230592Sken	return (error);
1341230592Sken}
1342230592Sken
1343230592Sken/**
1344230592Sken * mps_config_get_volume_wwid - returns wwid given the volume handle
1345230592Sken * @sc: per adapter object
1346230592Sken * @volume_handle: volume handle
1347230592Sken * @wwid: volume wwid
1348230592Sken * Context: sleep.
1349230592Sken *
1350230592Sken * Returns 0 for success, non-zero for failure.
1351230592Sken */
1352230592Skenint
1353230592Skenmps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
1354230592Sken{
1355230592Sken	Mpi2ConfigReply_t mpi_reply;
1356230592Sken	Mpi2RaidVolPage1_t raid_vol_pg1;
1357230592Sken
1358230592Sken	*wwid = 0;
1359230592Sken	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
1360230592Sken	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
1361230592Sken		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
1362230592Sken		    raid_vol_pg1.WWID.Low);
1363230592Sken		return 0;
1364230592Sken	} else
1365230592Sken		return -1;
1366230592Sken}
1367230592Sken
1368230592Sken/**
1369230592Sken * mps_config_get_pd_pg0 - obtain raid phys disk page 0
1370230592Sken * @sc: per adapter object
1371230592Sken * @mpi_reply: reply mf payload returned from firmware
1372230592Sken * @config_page: contents of the config page
1373230592Sken * @page_address: form and handle value used to get page
1374230592Sken * Context: sleep.
1375230592Sken *
1376230592Sken * Returns 0 for success, non-zero for failure.
1377230592Sken */
1378230592Skenint
1379230592Skenmps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
1380230592Sken    Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
1381230592Sken{
1382230592Sken	MPI2_CONFIG_REQUEST *request;
1383230592Sken	MPI2_CONFIG_REPLY *reply;
1384230592Sken	struct mps_command *cm;
1385230592Sken	Mpi2RaidPhysDiskPage0_t *page = NULL;
1386230592Sken	int error = 0;
1387230592Sken	u16 ioc_status;
1388230592Sken
1389230592Sken	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
1390230592Sken
1391230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1392230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1393230592Sken		    __LINE__);
1394230592Sken		error = EBUSY;
1395230592Sken		goto out;
1396230592Sken	}
1397230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1398230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1399230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1400230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
1401230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1402230592Sken	request->Header.PageNumber = 0;
1403230592Sken	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
1404230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1405230592Sken	cm->cm_data = NULL;
1406254938Sken
1407254938Sken	/*
1408254938Sken	 * This page must be polled because the IOC isn't ready yet when this
1409254938Sken	 * page is needed.
1410254938Sken	 */
1411230592Sken	error = mps_request_polled(sc, cm);
1412230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1413230592Sken	if (error || (reply == NULL)) {
1414230592Sken		/* FIXME */
1415230592Sken		/* If the poll returns error then we need to do diag reset */
1416230592Sken		printf("%s: poll for header completed with error %d",
1417230592Sken		    __func__, error);
1418230592Sken		error = ENXIO;
1419230592Sken		goto out;
1420230592Sken	}
1421230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1422230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1423230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1424230592Sken		/* FIXME */
1425230592Sken		/* If the poll returns error then we need to do diag reset */
1426230592Sken		printf("%s: header read with error; iocstatus = 0x%x\n",
1427230592Sken		    __func__, ioc_status);
1428230592Sken		error = ENXIO;
1429230592Sken		goto out;
1430230592Sken	}
1431230592Sken	/* We have to do free and alloc for the reply-free and reply-post
1432230592Sken	 * counters to match - Need to review the reply FIFO handling.
1433230592Sken	 */
1434230592Sken	mps_free_command(sc, cm);
1435230592Sken
1436230592Sken	if ((cm = mps_alloc_command(sc)) == NULL) {
1437230592Sken		printf("%s: command alloc failed @ line %d\n", __func__,
1438230592Sken		    __LINE__);
1439230592Sken		error = EBUSY;
1440230592Sken		goto out;
1441230592Sken	}
1442230592Sken	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
1443230592Sken	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
1444230592Sken	request->Function = MPI2_FUNCTION_CONFIG;
1445230592Sken	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
1446230592Sken	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
1447230592Sken	request->Header.PageNumber = 0;
1448230592Sken	request->Header.PageLength = mpi_reply->Header.PageLength;
1449230592Sken	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1450230592Sken	request->PageAddress = page_address;
1451230592Sken	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1452230592Sken	cm->cm_sge = &request->PageBufferSGE;
1453230592Sken	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1454230592Sken	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1455230592Sken	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1456230592Sken	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1457230592Sken	if (!page) {
1458230592Sken		printf("%s: page alloc failed\n", __func__);
1459230592Sken		error = ENOMEM;
1460230592Sken		goto out;
1461230592Sken	}
1462230592Sken	cm->cm_data = page;
1463230592Sken
1464254938Sken	/*
1465254938Sken	 * This page must be polled because the IOC isn't ready yet when this
1466254938Sken	 * page is needed.
1467254938Sken	 */
1468230592Sken	error = mps_request_polled(sc, cm);
1469230592Sken	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1470230592Sken	if (error || (reply == NULL)) {
1471230592Sken		/* FIXME */
1472230592Sken		/* If the poll returns error then we need to do diag reset */
1473230592Sken		printf("%s: poll for page completed with error %d",
1474230592Sken		    __func__, error);
1475230592Sken		error = ENXIO;
1476230592Sken		goto out;
1477230592Sken	}
1478230592Sken	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1479230592Sken	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1480230592Sken	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1481230592Sken		/* FIXME */
1482230592Sken		/* If the poll returns error then we need to do diag reset */
1483230592Sken		printf("%s: page read with error; iocstatus = 0x%x\n",
1484230592Sken		    __func__, ioc_status);
1485230592Sken		error = ENXIO;
1486230592Sken		goto out;
1487230592Sken	}
1488230592Sken	bcopy(page, config_page, MIN(cm->cm_length,
1489230592Sken	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1490230592Skenout:
1491230592Sken	free(page, M_MPT2);
1492230592Sken	if (cm)
1493230592Sken		mps_free_command(sc, cm);
1494230592Sken	return (error);
1495230592Sken}
1496