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