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