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