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