mps_config.c revision 279253
118334Speter/*-
290075Sobrien * Copyright (c) 2011-2015 LSI Corp.
390075Sobrien * Copyright (c) 2013-2015 Avago Technologies
418334Speter * All rights reserved.
590075Sobrien *
618334Speter * Redistribution and use in source and binary forms, with or without
790075Sobrien * modification, are permitted provided that the following conditions
890075Sobrien * are met:
990075Sobrien * 1. Redistributions of source code must retain the above copyright
1090075Sobrien *    notice, this list of conditions and the following disclaimer.
1118334Speter * 2. Redistributions in binary form must reproduce the above copyright
1290075Sobrien *    notice, this list of conditions and the following disclaimer in the
1390075Sobrien *    documentation and/or other materials provided with the distribution.
1490075Sobrien *
1590075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1618334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1718334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1890075Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1990075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2090075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2118334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2250397Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2350397Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2418334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2518334Speter * SUCH DAMAGE.
2618334Speter *
2790075Sobrien * Avago Technologies (LSI) MPT-Fusion Host Adapter FreeBSD
2818334Speter */
2950397Sobrien
3018334Speter#include <sys/cdefs.h>
3118334Speter__FBSDID("$FreeBSD: head/sys/dev/mps/mps_config.c 279253 2015-02-24 22:07:42Z slm $");
3218334Speter
3390075Sobrien/* TODO Move headers to mpsvar */
3490075Sobrien#include <sys/types.h>
3518334Speter#include <sys/param.h>
3650397Sobrien#include <sys/lock.h>
3752284Sobrien#include <sys/mutex.h>
3890075Sobrien#include <sys/systm.h>
3990075Sobrien#include <sys/kernel.h>
4090075Sobrien#include <sys/malloc.h>
4118334Speter#include <sys/kthread.h>
4250397Sobrien#include <sys/taskqueue.h>
4350397Sobrien#include <sys/bus.h>
4450397Sobrien#include <sys/endian.h>
4550397Sobrien#include <sys/sysctl.h>
4650397Sobrien#include <sys/eventhandler.h>
4750397Sobrien#include <sys/uio.h>
4818334Speter#include <machine/bus.h>
4918334Speter#include <machine/resource.h>
5052284Sobrien#include <dev/mps/mpi/mpi2_type.h>
5118334Speter#include <dev/mps/mpi/mpi2.h>
5252284Sobrien#include <dev/mps/mpi/mpi2_ioc.h>
5390075Sobrien#include <dev/mps/mpi/mpi2_sas.h>
5490075Sobrien#include <dev/mps/mpi/mpi2_cnfg.h>
5518334Speter#include <dev/mps/mpi/mpi2_init.h>
5618334Speter#include <dev/mps/mpi/mpi2_tool.h>
5790075Sobrien#include <dev/mps/mps_ioctl.h>
5890075Sobrien#include <dev/mps/mpsvar.h>
5950397Sobrien
6090075Sobrien/**
6190075Sobrien * mps_config_get_ioc_pg8 - obtain ioc page 8
6218334Speter * @sc: per adapter object
6390075Sobrien * @mpi_reply: reply mf payload returned from firmware
6490075Sobrien * @config_page: contents of the config page
6590075Sobrien * Context: sleep.
6690075Sobrien *
6718334Speter * Returns 0 for success, non-zero for failure.
6818334Speter */
6918334Speterint
7018334Spetermps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
7118334Speter    Mpi2IOCPage8_t *config_page)
7218334Speter{
7390075Sobrien	MPI2_CONFIG_REQUEST *request;
7490075Sobrien	MPI2_CONFIG_REPLY *reply;
7518334Speter	struct mps_command *cm;
7618334Speter	MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
7718334Speter	int error = 0;
7818334Speter	u16 ioc_status;
7990075Sobrien
8090075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
8190075Sobrien
8218334Speter	if ((cm = mps_alloc_command(sc)) == NULL) {
8390075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
8490075Sobrien		    __LINE__);
8550397Sobrien		error = EBUSY;
8690075Sobrien		goto out;
8790075Sobrien	}
8896263Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
8996263Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
9090075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
9190075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
9290075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
9390075Sobrien	request->Header.PageNumber = 8;
9490075Sobrien	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
9590075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
9690075Sobrien	cm->cm_data = NULL;
9790075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
9890075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
9990075Sobrien	if (error || (reply == NULL)) {
10090075Sobrien		/* FIXME */
10190075Sobrien		/*
10218334Speter		 * If the request returns an error then we need to do a diag
10390075Sobrien		 * reset
10490075Sobrien		 */
10590075Sobrien		printf("%s: request for header completed with error %d",
10618334Speter		    __func__, error);
10790075Sobrien		error = ENXIO;
10890075Sobrien		goto out;
10918334Speter	}
11090075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
11190075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
11290075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
11390075Sobrien		/* FIXME */
11490075Sobrien		/*
11590075Sobrien		 * If the request returns an error then we need to do a diag
11650397Sobrien		 * reset
11790075Sobrien		 */
11890075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
11990075Sobrien		    __func__, ioc_status);
12050397Sobrien		error = ENXIO;
12190075Sobrien		goto out;
12218334Speter	}
12318334Speter	/* We have to do free and alloc for the reply-free and reply-post
12418334Speter	 * counters to match - Need to review the reply FIFO handling.
12590075Sobrien	 */
12618334Speter	mps_free_command(sc, cm);
12718334Speter
12890075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
12918334Speter		printf("%s: command alloc failed @ line %d\n", __func__,
13090075Sobrien		    __LINE__);
13190075Sobrien		error = EBUSY;
13290075Sobrien		goto out;
13390075Sobrien	}
13418334Speter	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
13590075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
13690075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
13790075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
13890075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
13918334Speter	request->Header.PageNumber = 8;
14090075Sobrien	request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
14190075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
14218334Speter	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
14352284Sobrien	cm->cm_sge = &request->PageBufferSGE;
14490075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
14590075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
14690075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
14790075Sobrien	page = malloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
14890075Sobrien	if (!page) {
14990075Sobrien		printf("%s: page alloc failed\n", __func__);
15090075Sobrien		error = ENOMEM;
15118334Speter		goto out;
15218334Speter	}
15390075Sobrien	cm->cm_data = page;
15490075Sobrien
15590075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
15690075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
15790075Sobrien	if (error || (reply == NULL)) {
15890075Sobrien		/* FIXME */
15990075Sobrien		/*
16018334Speter		 * If the request returns an error then we need to do a diag
16190075Sobrien		 * reset
16290075Sobrien		 */
16390075Sobrien		printf("%s: request for page completed with error %d",
16490075Sobrien		    __func__, error);
16518334Speter		error = ENXIO;
16618334Speter		goto out;
16790075Sobrien	}
16890075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
16990075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
17018334Speter	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
17190075Sobrien		/* FIXME */
17290075Sobrien		/*
17318334Speter		 * If the request returns an error then we need to do a diag
17490075Sobrien		 * reset
17590075Sobrien		 */
17690075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
17790075Sobrien		    __func__, ioc_status);
17890075Sobrien		error = ENXIO;
17990075Sobrien		goto out;
18090075Sobrien	}
18190075Sobrien	bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
18290075Sobrien
18390075Sobrienout:
18490075Sobrien	free(page, M_MPT2);
18518334Speter	if (cm)
18690075Sobrien		mps_free_command(sc, cm);
18790075Sobrien	return (error);
18890075Sobrien}
18990075Sobrien
19050397Sobrien/**
19190075Sobrien * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
19290075Sobrien *   accordingly.  Currently, this page does not need to return to caller.
19390075Sobrien * @sc: per adapter object
19450397Sobrien * @mpi_reply: reply mf payload returned from firmware
19590075Sobrien * Context: sleep.
19690075Sobrien *
19790075Sobrien * Returns 0 for success, non-zero for failure.
19890075Sobrien */
19990075Sobrienint
20050397Sobrienmps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
20150397Sobrien{
20250397Sobrien	MPI2_CONFIG_REQUEST *request;
20318334Speter	MPI2_CONFIG_REPLY *reply;
20490075Sobrien	struct mps_command *cm;
20590075Sobrien	pMpi2ManufacturingPagePS_t page = NULL;
20690075Sobrien	uint32_t *pPS_info;
20718334Speter	uint8_t OEM_Value = 0;
20890075Sobrien	int error = 0;
20990075Sobrien	u16 ioc_status;
21090075Sobrien
21118334Speter	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
21218334Speter
21318334Speter	if ((cm = mps_alloc_command(sc)) == NULL) {
21490075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
21518334Speter		    __LINE__);
21690075Sobrien		error = EBUSY;
21790075Sobrien		goto out;
21890075Sobrien	}
21918334Speter	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
22090075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
22190075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
22290075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
22390075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
22490075Sobrien	request->Header.PageNumber = 10;
22590075Sobrien	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
22618334Speter	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
22790075Sobrien	cm->cm_data = NULL;
22818334Speter
22918334Speter	/*
23090075Sobrien	 * This page must be polled because the IOC isn't ready yet when this
23190075Sobrien	 * page is needed.
23290075Sobrien	 */
23390075Sobrien	error = mps_request_polled(sc, cm);
23490075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
23590075Sobrien	if (error || (reply == NULL)) {
23690075Sobrien		/* FIXME */
23790075Sobrien		/* If the poll returns error then we need to do diag reset */
23850397Sobrien		printf("%s: poll for header completed with error %d",
23990075Sobrien		    __func__, error);
24090075Sobrien		error = ENXIO;
24150397Sobrien		goto out;
24290075Sobrien	}
24396263Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
24490075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
24550397Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
24690075Sobrien		/* FIXME */
24750397Sobrien		/* If the poll returns error then we need to do diag reset */
24850397Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
24990075Sobrien		    __func__, ioc_status);
25090075Sobrien		error = ENXIO;
25190075Sobrien		goto out;
25290075Sobrien	}
25390075Sobrien	/* We have to do free and alloc for the reply-free and reply-post
25490075Sobrien	 * counters to match - Need to review the reply FIFO handling.
25590075Sobrien	 */
25618334Speter	mps_free_command(sc, cm);
25790075Sobrien
25818334Speter	if ((cm = mps_alloc_command(sc)) == NULL) {
25952284Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
26052284Sobrien		    __LINE__);
26190075Sobrien		error = EBUSY;
26290075Sobrien		goto out;
26390075Sobrien	}
26452284Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
26590075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
26652284Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
26790075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
26818334Speter	request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
26990075Sobrien	request->Header.PageNumber = 10;
27090075Sobrien	request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
27190075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
27290075Sobrien	cm->cm_length =  le16toh(mpi_reply->Header.PageLength) * 4;
27390075Sobrien	cm->cm_sge = &request->PageBufferSGE;
27418334Speter	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
27596263Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
27696263Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
27796263Sobrien	page = malloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
27890075Sobrien	if (!page) {
27990075Sobrien		printf("%s: page alloc failed\n", __func__);
28096263Sobrien		error = ENOMEM;
28190075Sobrien		goto out;
28290075Sobrien	}
28390075Sobrien	cm->cm_data = page;
28490075Sobrien
28518334Speter	/*
28690075Sobrien	 * This page must be polled because the IOC isn't ready yet when this
28790075Sobrien	 * page is needed.
28818334Speter	 */
28990075Sobrien	error = mps_request_polled(sc, cm);
29018334Speter	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
29190075Sobrien	if (error || (reply == NULL)) {
29290075Sobrien		/* FIXME */
29390075Sobrien		/* If the poll returns error then we need to do diag reset */
29490075Sobrien		printf("%s: poll for page completed with error %d",
29590075Sobrien		    __func__, error);
29618334Speter		error = ENXIO;
29790075Sobrien		goto out;
29890075Sobrien	}
29990075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
30018334Speter	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
30190075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
30290075Sobrien		/* FIXME */
30390075Sobrien		/* If the poll returns error then we need to do diag reset */
30418334Speter		printf("%s: page read with error; iocstatus = 0x%x\n",
30590075Sobrien		    __func__, ioc_status);
30690075Sobrien		error = ENXIO;
30790075Sobrien		goto out;
30890075Sobrien	}
30990075Sobrien
31018334Speter	/*
31190075Sobrien	 * If OEM ID is unknown, fail the request.
31290075Sobrien	 */
31390075Sobrien	sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
31490075Sobrien	OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
31590075Sobrien	if (OEM_Value != MPS_WD_LSI_OEM) {
31618334Speter		mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
31790075Sobrien		    "(0x%x)\n", OEM_Value);
31890075Sobrien		error = ENXIO;
31990075Sobrien		goto out;
32090075Sobrien	}
32190075Sobrien
32218334Speter	/*
32390075Sobrien	 * Set the phys disks hide/expose value.
32490075Sobrien	 */
32590075Sobrien	pPS_info = &page->ProductSpecificInfo;
32618334Speter	sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
32790075Sobrien	sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
32890075Sobrien	if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
32990075Sobrien	    (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
33090075Sobrien	    (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
33190075Sobrien		mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
33290075Sobrien		    "hide/expose: 0x%x\n", sc->WD_hide_expose);
33390075Sobrien		error = ENXIO;
33490075Sobrien		goto out;
33590075Sobrien	}
33690075Sobrien
33790075Sobrienout:
33890075Sobrien	free(page, M_MPT2);
33918334Speter	if (cm)
34090075Sobrien		mps_free_command(sc, cm);
34190075Sobrien	return (error);
34290075Sobrien}
34390075Sobrien
34490075Sobrien/**
34518334Speter * mps_base_static_config_pages - static start of day config pages.
34690075Sobrien * @sc: per adapter object
34790075Sobrien *
34890075Sobrien * Return nothing.
34990075Sobrien */
35090075Sobrienvoid
35118334Spetermps_base_static_config_pages(struct mps_softc *sc)
35290075Sobrien{
35318334Speter	Mpi2ConfigReply_t	mpi_reply;
35490075Sobrien	int			retry;
35590075Sobrien
35690075Sobrien	retry = 0;
35790075Sobrien	while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
35890075Sobrien		retry++;
35990075Sobrien		if (retry > 5) {
36090075Sobrien			/* We need to Handle this situation */
36190075Sobrien			/*FIXME*/
36290075Sobrien			break;
36390075Sobrien		}
36418334Speter	}
36590075Sobrien}
36690075Sobrien
36790075Sobrien/**
36890075Sobrien * mps_wd_config_pages - get info required to support WarpDrive.  This needs to
36990075Sobrien *    be called after discovery is complete to guarentee that IR info is there.
37090075Sobrien * @sc: per adapter object
37190075Sobrien *
37290075Sobrien * Return nothing.
37390075Sobrien */
37490075Sobrienvoid
37518334Spetermps_wd_config_pages(struct mps_softc *sc)
37690075Sobrien{
37790075Sobrien	Mpi2ConfigReply_t	mpi_reply;
37890075Sobrien	pMpi2RaidVolPage0_t	raid_vol_pg0 = NULL;
37918334Speter	Mpi2RaidPhysDiskPage0_t	phys_disk_pg0;
38090075Sobrien	pMpi2RaidVol0PhysDisk_t	pRVPD;
38190075Sobrien	uint32_t		stripe_size, phys_disk_page_address;
38290075Sobrien	uint16_t		block_size;
38390075Sobrien	uint8_t			index, stripe_exp = 0, block_exp = 0;
38418334Speter
38590075Sobrien	/*
38690075Sobrien	 * Get the WD settings from manufacturing page 10 if using a WD HBA.
38790075Sobrien	 * This will be used to determine if phys disks should always be
38890075Sobrien	 * hidden, hidden only if part of a WD volume, or never hidden.  Also,
38990075Sobrien	 * get the WD RAID Volume info and fail if volume does not exist or if
39090075Sobrien	 * volume does not meet the requirements for a WD volume.  No retry
39190075Sobrien	 * here.  Just default to HIDE ALWAYS if man Page10 fails, or clear WD
39290075Sobrien	 * Valid flag if Volume info fails.
39390075Sobrien	 */
39490075Sobrien	sc->WD_valid_config = FALSE;
39518334Speter	if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
39690075Sobrien		if (mps_config_get_man_pg10(sc, &mpi_reply)) {
39790075Sobrien			mps_dprint(sc, MPS_FAULT,
39890075Sobrien			    "mps_config_get_man_pg10 failed! Using 0 (Hide "
39918334Speter			    "Always) for WarpDrive hide/expose value.\n");
40090075Sobrien			sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
40190075Sobrien		}
40290075Sobrien
40390075Sobrien		/*
40490075Sobrien		 * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
40590075Sobrien		 */
40690075Sobrien		raid_vol_pg0 = malloc(sizeof(Mpi2RaidVolPage0_t) +
40790075Sobrien		    (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
40890075Sobrien		    M_MPT2, M_ZERO | M_NOWAIT);
40990075Sobrien		if (!raid_vol_pg0) {
41090075Sobrien			printf("%s: page alloc failed\n", __func__);
41190075Sobrien			goto out;
41290075Sobrien		}
41318334Speter
41490075Sobrien		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
41590075Sobrien		    0x0000FFFF)) {
41690075Sobrien			mps_dprint(sc, MPS_INFO,
41790075Sobrien			    "mps_config_get_raid_volume_pg0 failed! Assuming "
41890075Sobrien			    "WarpDrive IT mode.\n");
41990075Sobrien			goto out;
42090075Sobrien		}
42190075Sobrien
42290075Sobrien		/*
42390075Sobrien		 * Check for valid WD configuration:
42490075Sobrien		 *   volume type is RAID0
42590075Sobrien		 *   number of phys disks in the volume is no more than 8
42690075Sobrien		 */
42790075Sobrien		if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
42890075Sobrien		    (raid_vol_pg0->NumPhysDisks > 8)) {
42990075Sobrien			mps_dprint(sc, MPS_FAULT,
43090075Sobrien			    "Invalid WarpDrive configuration. Direct Drive I/O "
43190075Sobrien			    "will not be used.\n");
43290075Sobrien			goto out;
43390075Sobrien		}
43490075Sobrien
43590075Sobrien		/*
43690075Sobrien		 * Save the WD RAID data to be used during WD I/O.
43790075Sobrien		 */
43890075Sobrien		sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
43990075Sobrien		    32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
44090075Sobrien		sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
44190075Sobrien		sc->DD_dev_handle = raid_vol_pg0->DevHandle;
44290075Sobrien		sc->DD_stripe_size = raid_vol_pg0->StripeSize;
44390075Sobrien		sc->DD_block_size = raid_vol_pg0->BlockSize;
44490075Sobrien
44518334Speter		/*
44690075Sobrien		 * Find power of 2 of stripe size and set this as the exponent.
44790075Sobrien		 * Fail if stripe size is 0.
44890075Sobrien		 */
44990075Sobrien		stripe_size = raid_vol_pg0->StripeSize;
45090075Sobrien		for (index = 0; index < 32; index++) {
45190075Sobrien			if (stripe_size & 1)
45290075Sobrien				break;
45390075Sobrien			stripe_exp++;
45490075Sobrien			stripe_size >>= 1;
45590075Sobrien		}
45690075Sobrien		if (index == 32) {
45790075Sobrien			mps_dprint(sc, MPS_FAULT,
45818334Speter			    "RAID Volume's stripe size is 0. Direct Drive I/O "
45990075Sobrien			    "will not be used.\n");
46090075Sobrien			goto out;
46190075Sobrien		}
46290075Sobrien		sc->DD_stripe_exponent = stripe_exp;
46318334Speter
46490075Sobrien		/*
46590075Sobrien		 * Find power of 2 of block size and set this as the exponent.
46690075Sobrien		 * Fail if block size is 0.
46790075Sobrien		 */
46818334Speter		block_size = raid_vol_pg0->BlockSize;
46990075Sobrien		for (index = 0; index < 16; index++) {
47090075Sobrien			if (block_size & 1)
47190075Sobrien				break;
47290075Sobrien			block_exp++;
47390075Sobrien			block_size >>= 1;
47490075Sobrien		}
47590075Sobrien		if (index == 16) {
47690075Sobrien			mps_dprint(sc, MPS_FAULT,
47718334Speter			    "RAID Volume's block size is 0. Direct Drive I/O "
47890075Sobrien			    "will not be used.\n");
47990075Sobrien			goto out;
48090075Sobrien		}
48190075Sobrien		sc->DD_block_exponent = block_exp;
48218334Speter
48390075Sobrien		/*
48490075Sobrien		 * Loop through all of the volume's Phys Disks to map the phys
48590075Sobrien		 * disk number into the columm map.  This is used during Direct
48690075Sobrien		 * Drive I/O to send the request to the correct SSD.
48790075Sobrien		 */
48890075Sobrien		pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
48990075Sobrien		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
49090075Sobrien			sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
49190075Sobrien			    pRVPD->PhysDiskNum;
49290075Sobrien			pRVPD++;
49390075Sobrien		}
49418334Speter
49590075Sobrien		/*
49690075Sobrien		 * Get second RAID Volume Page0 using previous handle.  This
49790075Sobrien		 * page should not exist.  If it does, must not proceed with WD
49890075Sobrien		 * handling.
49990075Sobrien		 */
50090075Sobrien		if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
50190075Sobrien		    raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
50290075Sobrien			if (mpi_reply.IOCStatus !=
50390075Sobrien			    MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
50490075Sobrien				mps_dprint(sc, MPS_FAULT,
50590075Sobrien				    "Multiple RAID Volume Page0! Direct Drive "
50618334Speter				    "I/O will not be used.\n");
50790075Sobrien				goto out;
50890075Sobrien			}
50990075Sobrien		} else {
51090075Sobrien			mps_dprint(sc, MPS_FAULT,
51190075Sobrien			    "Multiple volumes! Direct Drive I/O will not be "
51290075Sobrien			    "used.\n");
51390075Sobrien			goto out;
51490075Sobrien		}
51590075Sobrien
51690075Sobrien		/*
51718334Speter		 * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
51890075Sobrien		 */
51990075Sobrien		for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
52090075Sobrien			phys_disk_page_address =
52190075Sobrien			    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
52290075Sobrien			    sc->DD_column_map[index].phys_disk_num;
52390075Sobrien			if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
52490075Sobrien			    &phys_disk_pg0, phys_disk_page_address)) {
52590075Sobrien				mps_dprint(sc, MPS_FAULT,
52690075Sobrien				    "mps_config_get_raid_pd_pg0 failed! Direct "
52790075Sobrien				    "Drive I/O will not be used.\n");
52818334Speter				goto out;
52990075Sobrien			}
53090075Sobrien			if (phys_disk_pg0.DevHandle == 0xFFFF) {
53190075Sobrien				mps_dprint(sc, MPS_FAULT,
53290075Sobrien				    "Invalid Phys Disk DevHandle! Direct Drive "
53390075Sobrien				    "I/O will not be used.\n");
53490075Sobrien				goto out;
53590075Sobrien			}
53690075Sobrien			sc->DD_column_map[index].dev_handle =
53790075Sobrien			    phys_disk_pg0.DevHandle;
53890075Sobrien		}
53990075Sobrien		sc->WD_valid_config = TRUE;
54090075Sobrienout:
54118334Speter		if (raid_vol_pg0)
54290075Sobrien			free(raid_vol_pg0, M_MPT2);
54390075Sobrien	}
54490075Sobrien}
54590075Sobrien
54690075Sobrien/**
54790075Sobrien * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
54890075Sobrien * @sc: per adapter object
54990075Sobrien * @mpi_reply: reply mf payload returned from firmware
55018334Speter * @config_page: contents of the config page
55190075Sobrien * @sz: size of buffer passed in config_page
55290075Sobrien * Context: sleep.
55390075Sobrien *
55490075Sobrien * Returns 0 for success, non-zero for failure.
55590075Sobrien */
55690075Sobrienint
55790075Sobrienmps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
55890075Sobrien    Mpi2DriverMappingPage0_t *config_page, u16 sz)
55918334Speter{
56090075Sobrien	MPI2_CONFIG_REQUEST *request;
56190075Sobrien	MPI2_CONFIG_REPLY *reply;
56290075Sobrien	struct mps_command *cm;
56390075Sobrien	Mpi2DriverMappingPage0_t *page = NULL;
56490075Sobrien	int error = 0;
56590075Sobrien	u16 ioc_status;
56690075Sobrien
56718334Speter	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
56890075Sobrien
56990075Sobrien	memset(config_page, 0, sz);
57090075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
57190075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
57290075Sobrien		    __LINE__);
57390075Sobrien		error = EBUSY;
57418334Speter		goto out;
57590075Sobrien	}
57690075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
57790075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
57890075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
57990075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
58090075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
58190075Sobrien	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
58290075Sobrien	request->Header.PageNumber = 0;
58390075Sobrien	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
58490075Sobrien	request->PageAddress = sc->max_dpm_entries <<
58590075Sobrien	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
58690075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
58790075Sobrien	cm->cm_data = NULL;
58890075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
58990075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
59090075Sobrien	if (error || (reply == NULL)) {
59190075Sobrien		/* FIXME */
59290075Sobrien		/*
59390075Sobrien		 * If the request returns an error then we need to do a diag
59490075Sobrien		 * reset
59590075Sobrien		 */
59618334Speter		printf("%s: request for header completed with error %d",
59790075Sobrien		    __func__, error);
59890075Sobrien		error = ENXIO;
59990075Sobrien		goto out;
60090075Sobrien	}
60118334Speter	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
60290075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
60390075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
60490075Sobrien		/* FIXME */
60590075Sobrien		/*
60618334Speter		 * If the request returns an error then we need to do a diag
60790075Sobrien		 * reset
60890075Sobrien		 */
60990075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
61018334Speter		    __func__, ioc_status);
61190075Sobrien		error = ENXIO;
61290075Sobrien		goto out;
61390075Sobrien	}
61418334Speter	/* We have to do free and alloc for the reply-free and reply-post
61590075Sobrien	 * counters to match - Need to review the reply FIFO handling.
61690075Sobrien	 */
61790075Sobrien	mps_free_command(sc, cm);
61890075Sobrien
61990075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
62018334Speter		printf("%s: command alloc failed @ line %d\n", __func__,
62190075Sobrien		    __LINE__);
62290075Sobrien		error = EBUSY;
62390075Sobrien		goto out;
62490075Sobrien	}
62590075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
62690075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
62790075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
62890075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
62990075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
63090075Sobrien	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
63190075Sobrien	request->Header.PageNumber = 0;
63290075Sobrien	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
63390075Sobrien	request->PageAddress = sc->max_dpm_entries <<
63490075Sobrien	    MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
63590075Sobrien	request->ExtPageLength = mpi_reply->ExtPageLength;
63690075Sobrien	cm->cm_length =  le16toh(request->ExtPageLength) * 4;
63790075Sobrien	cm->cm_sge = &request->PageBufferSGE;
63890075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
63990075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
64090075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
64190075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
64290075Sobrien	if (!page) {
64390075Sobrien		printf("%s: page alloc failed\n", __func__);
64490075Sobrien		error = ENOMEM;
64590075Sobrien		goto out;
64690075Sobrien	}
64790075Sobrien	cm->cm_data = page;
64850397Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
64918334Speter	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
65018334Speter	if (error || (reply == NULL)) {
65190075Sobrien		/* FIXME */
65218334Speter		/*
65390075Sobrien		 * If the request returns an error then we need to do a diag
65490075Sobrien		 * reset
65590075Sobrien		 */
65618334Speter		printf("%s: request for page completed with error %d",
65790075Sobrien		    __func__, error);
65850397Sobrien		error = ENXIO;
65990075Sobrien		goto out;
66018334Speter	}
66190075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
66290075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
66318334Speter	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
66490075Sobrien		/* FIXME */
66590075Sobrien		/*
66690075Sobrien		 * If the request returns an error then we need to do a diag
66790075Sobrien		 * reset
66890075Sobrien		 */
66990075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
67090075Sobrien		    __func__, ioc_status);
67190075Sobrien		error = ENXIO;
67290075Sobrien		goto out;
67390075Sobrien	}
67418334Speter	bcopy(page, config_page, MIN(cm->cm_length, sz));
67590075Sobrienout:
67690075Sobrien	free(page, M_MPT2);
67718334Speter	if (cm)
67890075Sobrien		mps_free_command(sc, cm);
67990075Sobrien	return (error);
68018334Speter}
68190075Sobrien
68218334Speter/**
68390075Sobrien * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
68418334Speter * @sc: per adapter object
68518334Speter * @mpi_reply: reply mf payload returned from firmware
68618334Speter * @config_page: contents of the config page
68718334Speter * @entry_idx: entry index in DPM Page0 to be modified
68890075Sobrien * Context: sleep.
68990075Sobrien *
69090075Sobrien * Returns 0 for success, non-zero for failure.
69190075Sobrien */
69218334Speter
69318334Speterint mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
69452284Sobrien    Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
69518334Speter{
69618334Speter	MPI2_CONFIG_REQUEST *request;
69718334Speter	MPI2_CONFIG_REPLY *reply;
69818334Speter	struct mps_command *cm;
69918334Speter	MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
70018334Speter	int error = 0;
70118334Speter	u16 ioc_status;
70218334Speter
70318334Speter	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
70418334Speter
70552284Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
70652284Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
70752284Sobrien		    __LINE__);
70890075Sobrien		error = EBUSY;
70990075Sobrien		goto out;
71090075Sobrien	}
71152284Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
71290075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
71352284Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
71452284Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
71590075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
71652284Sobrien	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
71752284Sobrien	request->Header.PageNumber = 0;
71852284Sobrien	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
71952284Sobrien	/* We can remove below two lines ????*/
72052284Sobrien	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
72152284Sobrien	request->PageAddress |= htole16(entry_idx);
72252284Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
72390075Sobrien	cm->cm_data = NULL;
72452284Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
72590075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
72690075Sobrien	if (error || (reply == NULL)) {
72790075Sobrien		/* FIXME */
72852284Sobrien		/*
72952284Sobrien		 * If the request returns an error then we need to do a diag
73052284Sobrien		 * reset
73152284Sobrien		 */
73252284Sobrien		printf("%s: request for header completed with error %d",
73390075Sobrien		    __func__, error);
73452284Sobrien		error = ENXIO;
73590075Sobrien		goto out;
73690075Sobrien	}
73752284Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
73852284Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
73990075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
74052284Sobrien		/* FIXME */
74190075Sobrien		/*
74252284Sobrien		 * If the request returns an error then we need to do a diag
74352284Sobrien		 * reset
74490075Sobrien		 */
74552284Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
74690075Sobrien		    __func__, ioc_status);
74752284Sobrien		error = ENXIO;
74890075Sobrien		goto out;
74990075Sobrien	}
75052284Sobrien	/* We have to do free and alloc for the reply-free and reply-post
75190075Sobrien	 * counters to match - Need to review the reply FIFO handling.
75290075Sobrien	 */
75390075Sobrien	mps_free_command(sc, cm);
75490075Sobrien
75590075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
75690075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
75790075Sobrien		    __LINE__);
75890075Sobrien		error = EBUSY;
75990075Sobrien		goto out;
76090075Sobrien	}
76190075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
76290075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
76390075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
76452284Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
76552284Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
76618334Speter	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
76790075Sobrien	request->Header.PageNumber = 0;
76890075Sobrien	request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
76918334Speter	request->ExtPageLength = mpi_reply->ExtPageLength;
77090075Sobrien	request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
77118334Speter	request->PageAddress |= htole16(entry_idx);
77290075Sobrien	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
77390075Sobrien	cm->cm_sge = &request->PageBufferSGE;
77490075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
77590075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
77690075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
77790075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
77818334Speter	if (!page) {
77990075Sobrien		printf("%s: page alloc failed\n", __func__);
78090075Sobrien		error = ENOMEM;
78190075Sobrien		goto out;
78290075Sobrien	}
78318334Speter	bcopy(config_page, page, MIN(cm->cm_length,
78490075Sobrien	    (sizeof(Mpi2DriverMappingPage0_t))));
78590075Sobrien	cm->cm_data = page;
78618334Speter	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
78790075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
78890075Sobrien	if (error || (reply == NULL)) {
78918334Speter		/* FIXME */
79090075Sobrien		/*
79190075Sobrien		 * If the request returns an error then we need to do a diag
79290075Sobrien		 * reset
79390075Sobrien		 */
79418334Speter		printf("%s: request to write page completed with error %d",
79590075Sobrien		    __func__, error);
79690075Sobrien		error = ENXIO;
79790075Sobrien		goto out;
79890075Sobrien	}
79990075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
80090075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
80118334Speter	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
80290075Sobrien		/* FIXME */
80390075Sobrien		/*
80490075Sobrien		 * If the request returns an error then we need to do a diag
80518334Speter		 * reset
80690075Sobrien		 */
80790075Sobrien		printf("%s: page written with error; iocstatus = 0x%x\n",
80890075Sobrien		    __func__, ioc_status);
80990075Sobrien		error = ENXIO;
81018334Speter		goto out;
81190075Sobrien	}
81290075Sobrienout:
81396263Sobrien	free(page, M_MPT2);
81496263Sobrien	if (cm)
81590075Sobrien		mps_free_command(sc, cm);
81618334Speter	return (error);
81790075Sobrien}
81890075Sobrien
81990075Sobrien/**
82090075Sobrien * mps_config_get_sas_device_pg0 - obtain sas device page 0
82190075Sobrien * @sc: per adapter object
82218334Speter * @mpi_reply: reply mf payload returned from firmware
82390075Sobrien * @config_page: contents of the config page
82490075Sobrien * @form: GET_NEXT_HANDLE or HANDLE
82518334Speter * @handle: device handle
82690075Sobrien * Context: sleep.
82790075Sobrien *
82818334Speter * Returns 0 for success, non-zero for failure.
82990075Sobrien */
83018334Speterint
83190075Sobrienmps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
83290075Sobrien    *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
83390075Sobrien{
83490075Sobrien	MPI2_CONFIG_REQUEST *request;
83590075Sobrien	MPI2_CONFIG_REPLY *reply;
83690075Sobrien	struct mps_command *cm;
83790075Sobrien	Mpi2SasDevicePage0_t *page = NULL;
83890075Sobrien	int error = 0;
83990075Sobrien	u16 ioc_status;
84090075Sobrien
84190075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
84290075Sobrien
84390075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
84490075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
84590075Sobrien		    __LINE__);
84690075Sobrien		error = EBUSY;
84790075Sobrien		goto out;
84890075Sobrien	}
84990075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
85090075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
85190075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
85290075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
85390075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
85490075Sobrien	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
85590075Sobrien	request->Header.PageNumber = 0;
85690075Sobrien	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
85790075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
85890075Sobrien	cm->cm_data = NULL;
85990075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
86090075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
86190075Sobrien	if (error || (reply == NULL)) {
86290075Sobrien		/* FIXME */
86390075Sobrien		/*
86490075Sobrien		 * If the request returns an error then we need to do a diag
86590075Sobrien		 * reset
86690075Sobrien		 */
86718334Speter		printf("%s: request for header completed with error %d",
86890075Sobrien		    __func__, error);
86990075Sobrien		error = ENXIO;
87018334Speter		goto out;
87190075Sobrien	}
87290075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
87318334Speter	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
87490075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
87590075Sobrien		/* FIXME */
87690075Sobrien		/*
87790075Sobrien		 * If the request returns an error then we need to do a diag
87890075Sobrien		 * reset
87990075Sobrien		 */
88090075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
88190075Sobrien		    __func__, ioc_status);
88290075Sobrien		error = ENXIO;
88390075Sobrien		goto out;
88490075Sobrien	}
88518334Speter	/* We have to do free and alloc for the reply-free and reply-post
88690075Sobrien	 * counters to match - Need to review the reply FIFO handling.
88790075Sobrien	 */
88890075Sobrien	mps_free_command(sc, cm);
88918334Speter
89090075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
89118334Speter		printf("%s: command alloc failed @ line %d\n", __func__,
89290075Sobrien		    __LINE__);
89390075Sobrien		error = EBUSY;
89490075Sobrien		goto out;
89590075Sobrien	}
89690075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
89790075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
89818334Speter	request->Function = MPI2_FUNCTION_CONFIG;
89990075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
90090075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
90190075Sobrien	request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
90290075Sobrien	request->Header.PageNumber = 0;
90390075Sobrien	request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
90490075Sobrien	request->ExtPageLength = mpi_reply->ExtPageLength;
90590075Sobrien	request->PageAddress = htole32(form | handle);
90690075Sobrien	cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
90790075Sobrien	cm->cm_sge = &request->PageBufferSGE;
90890075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
90990075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
91090075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
91190075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
91218334Speter	if (!page) {
91390075Sobrien		printf("%s: page alloc failed\n", __func__);
91490075Sobrien		error = ENOMEM;
91518334Speter		goto out;
91690075Sobrien	}
91718334Speter	cm->cm_data = page;
91890075Sobrien
91990075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
92090075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
92190075Sobrien	if (error || (reply == NULL)) {
92290075Sobrien		/* FIXME */
92390075Sobrien		/*
92490075Sobrien		 * If the request returns an error then we need to do a diag
92590075Sobrien		 * reset
92690075Sobrien		 */
92790075Sobrien		printf("%s: request for page completed with error %d",
92890075Sobrien		    __func__, error);
92990075Sobrien		error = ENXIO;
93090075Sobrien		goto out;
93190075Sobrien	}
93290075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
93390075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
93418334Speter	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
93590075Sobrien		/* FIXME */
93690075Sobrien		/*
93790075Sobrien		 * If the request returns an error then we need to do a diag
93890075Sobrien		 * reset
93990075Sobrien		 */
94090075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
94190075Sobrien		    __func__, ioc_status);
94290075Sobrien		error = ENXIO;
94318334Speter		goto out;
94490075Sobrien	}
94590075Sobrien	bcopy(page, config_page, MIN(cm->cm_length,
94690075Sobrien	    sizeof(Mpi2SasDevicePage0_t)));
94790075Sobrienout:
94818334Speter	free(page, M_MPT2);
94990075Sobrien	if (cm)
95090075Sobrien		mps_free_command(sc, cm);
95118334Speter	return (error);
95290075Sobrien}
95390075Sobrien
95490075Sobrien/**
95590075Sobrien * mps_config_get_bios_pg3 - obtain BIOS page 3
95690075Sobrien * @sc: per adapter object
95790075Sobrien * @mpi_reply: reply mf payload returned from firmware
95890075Sobrien * @config_page: contents of the config page
95990075Sobrien * Context: sleep.
96090075Sobrien *
96190075Sobrien * Returns 0 for success, non-zero for failure.
96218334Speter */
96390075Sobrienint
96490075Sobrienmps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
96518334Speter    Mpi2BiosPage3_t *config_page)
96690075Sobrien{
96790075Sobrien	MPI2_CONFIG_REQUEST *request;
96890075Sobrien	MPI2_CONFIG_REPLY *reply;
96918334Speter	struct mps_command *cm;
97090075Sobrien	Mpi2BiosPage3_t *page = NULL;
97190075Sobrien	int error = 0;
97250397Sobrien	u16 ioc_status;
97390075Sobrien
97490075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
97590075Sobrien
97690075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
97790075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
97890075Sobrien		    __LINE__);
97990075Sobrien		error = EBUSY;
98018334Speter		goto out;
98190075Sobrien	}
98290075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
98318334Speter	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
98490075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
98590075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
98618334Speter	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
98790075Sobrien	request->Header.PageNumber = 3;
98890075Sobrien	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
98990075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
99090075Sobrien	cm->cm_data = NULL;
99190075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
99290075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
99390075Sobrien	if (error || (reply == NULL)) {
99490075Sobrien		/* FIXME */
99590075Sobrien		/*
99690075Sobrien		 * If the request returns an error then we need to do a diag
99790075Sobrien		 * reset
99890075Sobrien		 */
99990075Sobrien		printf("%s: request for header completed with error %d",
100090075Sobrien		    __func__, error);
100190075Sobrien		error = ENXIO;
100290075Sobrien		goto out;
100318334Speter	}
100490075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
100590075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
100690075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
100790075Sobrien		/* FIXME */
100890075Sobrien		/*
100918334Speter		 * If the request returns an error then we need to do a diag
101090075Sobrien		 * reset
101190075Sobrien		 */
101290075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
101390075Sobrien		    __func__, ioc_status);
101418334Speter		error = ENXIO;
101590075Sobrien		goto out;
101690075Sobrien	}
101790075Sobrien	/* We have to do free and alloc for the reply-free and reply-post
101890075Sobrien	 * counters to match - Need to review the reply FIFO handling.
101990075Sobrien	 */
102090075Sobrien	mps_free_command(sc, cm);
102118334Speter
102290075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
102390075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
102418334Speter		    __LINE__);
102590075Sobrien		error = EBUSY;
102690075Sobrien		goto out;
102790075Sobrien	}
102890075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
102990075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
103090075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
103118334Speter	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
103290075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
103390075Sobrien	request->Header.PageNumber = 3;
103418334Speter	request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
103590075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
103690075Sobrien	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
103790075Sobrien	cm->cm_sge = &request->PageBufferSGE;
103890075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
103990075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
104090075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
104190075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
104290075Sobrien	if (!page) {
104318334Speter		printf("%s: page alloc failed\n", __func__);
104490075Sobrien		error = ENOMEM;
104590075Sobrien		goto out;
104618334Speter	}
104718334Speter	cm->cm_data = page;
104890075Sobrien
104990075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
105090075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
105190075Sobrien	if (error || (reply == NULL)) {
105290075Sobrien		/* FIXME */
105318334Speter		/*
105490075Sobrien		 * If the request returns an error then we need to do a diag
105590075Sobrien		 * reset
105690075Sobrien		 */
105790075Sobrien		printf("%s: request for page completed with error %d",
105890075Sobrien		    __func__, error);
105990075Sobrien		error = ENXIO;
106090075Sobrien		goto out;
106190075Sobrien	}
106290075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
106318334Speter	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
106490075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
106590075Sobrien		/* FIXME */
106690075Sobrien		/*
106752284Sobrien		 * If the request returns an error then we need to do a diag
106818334Speter		 * reset
106990075Sobrien		 */
107090075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
107190075Sobrien		    __func__, ioc_status);
107290075Sobrien		error = ENXIO;
107390075Sobrien		goto out;
107490075Sobrien	}
107518334Speter	bcopy(page, config_page, MIN(cm->cm_length, sizeof(Mpi2BiosPage3_t)));
107618334Speterout:
107790075Sobrien	free(page, M_MPT2);
107890075Sobrien	if (cm)
107990075Sobrien		mps_free_command(sc, cm);
108090075Sobrien	return (error);
108190075Sobrien}
108290075Sobrien
108390075Sobrien/**
108490075Sobrien * mps_config_get_raid_volume_pg0 - obtain raid volume page 0
108590075Sobrien * @sc: per adapter object
108690075Sobrien * @mpi_reply: reply mf payload returned from firmware
108790075Sobrien * @config_page: contents of the config page
108890075Sobrien * @page_address: form and handle value used to get page
108990075Sobrien * Context: sleep.
109090075Sobrien *
109190075Sobrien * Returns 0 for success, non-zero for failure.
109290075Sobrien */
109390075Sobrienint
109418334Spetermps_config_get_raid_volume_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
109590075Sobrien    *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 page_address)
109690075Sobrien{
109790075Sobrien	MPI2_CONFIG_REQUEST *request;
109890075Sobrien	MPI2_CONFIG_REPLY *reply;
109990075Sobrien	struct mps_command *cm;
110090075Sobrien	Mpi2RaidVolPage0_t *page = NULL;
110190075Sobrien	int error = 0;
110290075Sobrien	u16 ioc_status;
110390075Sobrien
110490075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
110590075Sobrien
110690075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
110718334Speter		printf("%s: command alloc failed @ line %d\n", __func__,
110890075Sobrien		    __LINE__);
110990075Sobrien		error = EBUSY;
111090075Sobrien		goto out;
111190075Sobrien	}
111218334Speter	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
111390075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
111490075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
111590075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
111690075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
111790075Sobrien	request->Header.PageNumber = 0;
111890075Sobrien	request->Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
111990075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
112090075Sobrien	cm->cm_data = NULL;
112190075Sobrien
112290075Sobrien	/*
112390075Sobrien	 * This page must be polled because the IOC isn't ready yet when this
112490075Sobrien	 * page is needed.
112590075Sobrien	 */
112690075Sobrien	error = mps_request_polled(sc, cm);
112790075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
112890075Sobrien	if (error || (reply == NULL)) {
112918334Speter		/* FIXME */
113090075Sobrien		/* If the poll returns error then we need to do diag reset */
113190075Sobrien		printf("%s: poll for header completed with error %d",
113290075Sobrien		    __func__, error);
113390075Sobrien		error = ENXIO;
113490075Sobrien		goto out;
113590075Sobrien	}
113690075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
113718334Speter	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
113890075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
113990075Sobrien		/* FIXME */
114090075Sobrien		/* If the poll returns error then we need to do diag reset */
114190075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
114218334Speter		    __func__, ioc_status);
114390075Sobrien		error = ENXIO;
114490075Sobrien		goto out;
114590075Sobrien	}
114690075Sobrien	/* We have to do free and alloc for the reply-free and reply-post
114790075Sobrien	 * counters to match - Need to review the reply FIFO handling.
114890075Sobrien	 */
114918334Speter	mps_free_command(sc, cm);
115090075Sobrien
115190075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
115252284Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
115390075Sobrien		    __LINE__);
115418334Speter		error = EBUSY;
115590075Sobrien		goto out;
115690075Sobrien	}
115790075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
115890075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
115990075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
116090075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
116190075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
116218334Speter	request->Header.PageNumber = 0;
116390075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
116490075Sobrien	request->Header.PageVersion = mpi_reply->Header.PageVersion;
116518334Speter	request->PageAddress = page_address;
116690075Sobrien	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
116790075Sobrien	cm->cm_sge = &request->PageBufferSGE;
116890075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
116990075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
117090075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
117190075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
117290075Sobrien	if (!page) {
117390075Sobrien		printf("%s: page alloc failed\n", __func__);
117490075Sobrien		error = ENOMEM;
117590075Sobrien		goto out;
117690075Sobrien	}
117790075Sobrien	cm->cm_data = page;
117890075Sobrien
117990075Sobrien	/*
118090075Sobrien	 * This page must be polled because the IOC isn't ready yet when this
118190075Sobrien	 * page is needed.
118290075Sobrien	 */
118390075Sobrien	error = mps_request_polled(sc, cm);
118490075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
118590075Sobrien	if (error || (reply == NULL)) {
118690075Sobrien		/* FIXME */
118790075Sobrien		/* If the poll returns error then we need to do diag reset */
118890075Sobrien		printf("%s: poll for page completed with error %d",
118990075Sobrien		    __func__, error);
119090075Sobrien		error = ENXIO;
119190075Sobrien		goto out;
119290075Sobrien	}
119390075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
119490075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
119590075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
119690075Sobrien		/* FIXME */
119790075Sobrien		/* If the poll returns error then we need to do diag reset */
119890075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
119990075Sobrien		    __func__, ioc_status);
120090075Sobrien		error = ENXIO;
120190075Sobrien		goto out;
120290075Sobrien	}
120390075Sobrien	bcopy(page, config_page, cm->cm_length);
120490075Sobrienout:
120590075Sobrien	free(page, M_MPT2);
120690075Sobrien	if (cm)
120790075Sobrien		mps_free_command(sc, cm);
120890075Sobrien	return (error);
120990075Sobrien}
121090075Sobrien
121190075Sobrien/**
121290075Sobrien * mps_config_get_raid_volume_pg1 - obtain raid volume page 1
121390075Sobrien * @sc: per adapter object
121490075Sobrien * @mpi_reply: reply mf payload returned from firmware
121590075Sobrien * @config_page: contents of the config page
121690075Sobrien * @form: GET_NEXT_HANDLE or HANDLE
121790075Sobrien * @handle: volume handle
121890075Sobrien * Context: sleep.
121990075Sobrien *
122090075Sobrien * Returns 0 for success, non-zero for failure.
122190075Sobrien */
122290075Sobrienint
122390075Sobrienmps_config_get_raid_volume_pg1(struct mps_softc *sc, Mpi2ConfigReply_t
122490075Sobrien    *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u16 handle)
122590075Sobrien{
122690075Sobrien	MPI2_CONFIG_REQUEST *request;
122718334Speter	MPI2_CONFIG_REPLY *reply;
122890075Sobrien	struct mps_command *cm;
122918334Speter	Mpi2RaidVolPage1_t *page = NULL;
123090075Sobrien	int error = 0;
123190075Sobrien	u16 ioc_status;
123290075Sobrien
123390075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
123490075Sobrien
123590075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
123690075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
123790075Sobrien		    __LINE__);
123890075Sobrien		error = EBUSY;
123990075Sobrien		goto out;
124090075Sobrien	}
124190075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
124290075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
124318334Speter	request->Function = MPI2_FUNCTION_CONFIG;
124490075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
124590075Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
124690075Sobrien	request->Header.PageNumber = 1;
124790075Sobrien	request->Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
124890075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
124990075Sobrien	cm->cm_data = NULL;
125090075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
125190075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
125290075Sobrien	if (error || (reply == NULL)) {
125390075Sobrien		/* FIXME */
125490075Sobrien		/*
125590075Sobrien		 * If the request returns an error then we need to do a diag
125690075Sobrien		 * reset
125790075Sobrien		 */
125852284Sobrien		printf("%s: request for header completed with error %d",
125990075Sobrien		    __func__, error);
126090075Sobrien		error = ENXIO;
126152284Sobrien		goto out;
126290075Sobrien	}
126390075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
126490075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
126590075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
126690075Sobrien		/* FIXME */
126790075Sobrien		/*
126890075Sobrien		 * If the request returns an error then we need to do a diag
126990075Sobrien		 * reset
127090075Sobrien		 */
127190075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
127290075Sobrien		    __func__, ioc_status);
127390075Sobrien		error = ENXIO;
127490075Sobrien		goto out;
127590075Sobrien	}
127690075Sobrien	/* We have to do free and alloc for the reply-free and reply-post
127790075Sobrien	 * counters to match - Need to review the reply FIFO handling.
127890075Sobrien	 */
127990075Sobrien	mps_free_command(sc, cm);
128090075Sobrien
128190075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
128252284Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
128390075Sobrien		    __LINE__);
128490075Sobrien		error = EBUSY;
128518334Speter		goto out;
128690075Sobrien	}
128790075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
128890075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
128990075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
129090075Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
129150397Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
129290075Sobrien	request->Header.PageNumber = 1;
129390075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
129450397Sobrien	request->Header.PageVersion = mpi_reply->Header.PageVersion;
129590075Sobrien	request->PageAddress = htole32(form | handle);
129618334Speter	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
129790075Sobrien	cm->cm_sge = &request->PageBufferSGE;
129890075Sobrien	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
129990075Sobrien	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
130018334Speter	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
130190075Sobrien	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
130290075Sobrien	if (!page) {
130396263Sobrien		printf("%s: page alloc failed\n", __func__);
130490075Sobrien		error = ENOMEM;
130590075Sobrien		goto out;
130690075Sobrien	}
130790075Sobrien	cm->cm_data = page;
130890075Sobrien
130990075Sobrien	error = mps_wait_command(sc, cm, 60, CAN_SLEEP);
131096263Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
131190075Sobrien	if (error || (reply == NULL)) {
131290075Sobrien		/* FIXME */
131390075Sobrien		/*
131452284Sobrien		 * If the request returns an error then we need to do a diag
131552284Sobrien		 * reset
131690075Sobrien		 */
131790075Sobrien		printf("%s: request for page completed with error %d",
131818334Speter		    __func__, error);
131918334Speter		error = ENXIO;
132090075Sobrien		goto out;
132190075Sobrien	}
132290075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
132390075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
132490075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
132518334Speter		/* FIXME */
132696263Sobrien		/*
132790075Sobrien		 * If the request returns an error then we need to do a diag
132890075Sobrien		 * reset
132990075Sobrien		 */
133090075Sobrien		printf("%s: page read with error; iocstatus = 0x%x\n",
133190075Sobrien		    __func__, ioc_status);
133290075Sobrien		error = ENXIO;
133390075Sobrien		goto out;
133490075Sobrien	}
133590075Sobrien	bcopy(page, config_page, MIN(cm->cm_length,
133690075Sobrien	    sizeof(Mpi2RaidVolPage1_t)));
133790075Sobrienout:
133890075Sobrien	free(page, M_MPT2);
133990075Sobrien	if (cm)
134052284Sobrien		mps_free_command(sc, cm);
134118334Speter	return (error);
134290075Sobrien}
134390075Sobrien
134490075Sobrien/**
134518334Speter * mps_config_get_volume_wwid - returns wwid given the volume handle
134690075Sobrien * @sc: per adapter object
134790075Sobrien * @volume_handle: volume handle
134890075Sobrien * @wwid: volume wwid
134990075Sobrien * Context: sleep.
135096263Sobrien *
135190075Sobrien * Returns 0 for success, non-zero for failure.
135290075Sobrien */
135390075Sobrienint
135490075Sobrienmps_config_get_volume_wwid(struct mps_softc *sc, u16 volume_handle, u64 *wwid)
135590075Sobrien{
135690075Sobrien	Mpi2ConfigReply_t mpi_reply;
135790075Sobrien	Mpi2RaidVolPage1_t raid_vol_pg1;
135890075Sobrien
135990075Sobrien	*wwid = 0;
136090075Sobrien	if (!(mps_config_get_raid_volume_pg1(sc, &mpi_reply, &raid_vol_pg1,
136118334Speter	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, volume_handle))) {
136290075Sobrien		*wwid = le64toh((u64)raid_vol_pg1.WWID.High << 32 |
136318334Speter		    raid_vol_pg1.WWID.Low);
136490075Sobrien		return 0;
136590075Sobrien	} else
136690075Sobrien		return -1;
136790075Sobrien}
136890075Sobrien
136990075Sobrien/**
137090075Sobrien * mps_config_get_pd_pg0 - obtain raid phys disk page 0
137190075Sobrien * @sc: per adapter object
137290075Sobrien * @mpi_reply: reply mf payload returned from firmware
137318334Speter * @config_page: contents of the config page
137490075Sobrien * @page_address: form and handle value used to get page
137590075Sobrien * Context: sleep.
137690075Sobrien *
137790075Sobrien * Returns 0 for success, non-zero for failure.
137890075Sobrien */
137990075Sobrienint
138090075Sobrienmps_config_get_raid_pd_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
138118334Speter    Mpi2RaidPhysDiskPage0_t *config_page, u32 page_address)
138290075Sobrien{
138390075Sobrien	MPI2_CONFIG_REQUEST *request;
138418334Speter	MPI2_CONFIG_REPLY *reply;
138590075Sobrien	struct mps_command *cm;
138690075Sobrien	Mpi2RaidPhysDiskPage0_t *page = NULL;
138790075Sobrien	int error = 0;
138890075Sobrien	u16 ioc_status;
138918334Speter
139090075Sobrien	mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
139190075Sobrien
139290075Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
139390075Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
139418334Speter		    __LINE__);
139590075Sobrien		error = EBUSY;
139618334Speter		goto out;
139790075Sobrien	}
139890075Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
139990075Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
140090075Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
140118334Speter	request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
140218334Speter	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
140318334Speter	request->Header.PageNumber = 0;
140490075Sobrien	request->Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
140590075Sobrien	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
140690075Sobrien	cm->cm_data = NULL;
140790075Sobrien
140818334Speter	/*
140990075Sobrien	 * This page must be polled because the IOC isn't ready yet when this
141096263Sobrien	 * page is needed.
141190075Sobrien	 */
141290075Sobrien	error = mps_request_polled(sc, cm);
141390075Sobrien	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
141490075Sobrien	if (error || (reply == NULL)) {
141590075Sobrien		/* FIXME */
141690075Sobrien		/* If the poll returns error then we need to do diag reset */
141790075Sobrien		printf("%s: poll for header completed with error %d",
141896263Sobrien		    __func__, error);
141990075Sobrien		error = ENXIO;
142090075Sobrien		goto out;
142190075Sobrien	}
142290075Sobrien	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
142390075Sobrien	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
142490075Sobrien	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
142590075Sobrien		/* FIXME */
142690075Sobrien		/* If the poll returns error then we need to do diag reset */
142790075Sobrien		printf("%s: header read with error; iocstatus = 0x%x\n",
142890075Sobrien		    __func__, ioc_status);
142990075Sobrien		error = ENXIO;
143096263Sobrien		goto out;
143190075Sobrien	}
143296263Sobrien	/* We have to do free and alloc for the reply-free and reply-post
143390075Sobrien	 * counters to match - Need to review the reply FIFO handling.
143496263Sobrien	 */
143596263Sobrien	mps_free_command(sc, cm);
143696263Sobrien
143796263Sobrien	if ((cm = mps_alloc_command(sc)) == NULL) {
143896263Sobrien		printf("%s: command alloc failed @ line %d\n", __func__,
143996263Sobrien		    __LINE__);
144096263Sobrien		error = EBUSY;
144196263Sobrien		goto out;
144296263Sobrien	}
144396263Sobrien	request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
144496263Sobrien	bzero(request, sizeof(MPI2_CONFIG_REQUEST));
144596263Sobrien	request->Function = MPI2_FUNCTION_CONFIG;
144696263Sobrien	request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
144796263Sobrien	request->Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
144896263Sobrien	request->Header.PageNumber = 0;
144990075Sobrien	request->Header.PageLength = mpi_reply->Header.PageLength;
145018334Speter	request->Header.PageVersion = mpi_reply->Header.PageVersion;
1451	request->PageAddress = page_address;
1452	cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
1453	cm->cm_sge = &request->PageBufferSGE;
1454	cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
1455	cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
1456	cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
1457	page = malloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
1458	if (!page) {
1459		printf("%s: page alloc failed\n", __func__);
1460		error = ENOMEM;
1461		goto out;
1462	}
1463	cm->cm_data = page;
1464
1465	/*
1466	 * This page must be polled because the IOC isn't ready yet when this
1467	 * page is needed.
1468	 */
1469	error = mps_request_polled(sc, cm);
1470	reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
1471	if (error || (reply == NULL)) {
1472		/* FIXME */
1473		/* If the poll returns error then we need to do diag reset */
1474		printf("%s: poll for page completed with error %d",
1475		    __func__, error);
1476		error = ENXIO;
1477		goto out;
1478	}
1479	ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
1480	bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
1481	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1482		/* FIXME */
1483		/* If the poll returns error then we need to do diag reset */
1484		printf("%s: page read with error; iocstatus = 0x%x\n",
1485		    __func__, ioc_status);
1486		error = ENXIO;
1487		goto out;
1488	}
1489	bcopy(page, config_page, MIN(cm->cm_length,
1490	    sizeof(Mpi2RaidPhysDiskPage0_t)));
1491out:
1492	free(page, M_MPT2);
1493	if (cm)
1494		mps_free_command(sc, cm);
1495	return (error);
1496}
1497