.\" Author: Ken Merry <ken@FreeBSD.org>
.\"
.\" $Id: //depot/SpectraBSD/head/share/man/man4/mps.4#4 $
-.\" $FreeBSD: src/share/man/man4/mps.4,v 1.3 2010/10/07 21:56:10 ken Exp $
+.\" $FreeBSD: src/share/man/man4/mps.4,v 1.5 2011/11/11 12:06:09 brueffer Exp $
.\"
.Dd September 13, 2010
.Dt MPS 4
.Tn SAS
controllers.
.Sh HARDWARE
-The following controllers are supported by the
+The
.Nm
-driver
+driver supports the following controllers:
.Pp
.Bl -bullet -compact
.It
.Xr sa 4 ,
.Xr scsi 4 ,
.Xr targ 4
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was originally written by
+.An Scott Long Aq scottl@FreeBSD.org .
+This man page was written by
+.An Ken Merry Aq ken@FreeBSD.org .
.Sh BUGS
This driver is still in development, it has only been tested on the amd64
architecture and has some known shortcomings:
.It
The error recovery code isn't complete.
.El
-.Sh HISTORY
-The
-.Nm
-driver first appeared in
-.Fx 9.0 .
-.Sh AUTHORS
-.An -nosplit
-The
-.Nm
-driver was originally written by
-.An Scott Long Aq scottl@FreeBSD.org .
-This man page was written by
-.An Ken Merry Aq ken@FreeBSD.org .
bus/mmc/mmcbr_if.m standard
bus/mmc/mmcbus_if.m standard
dev/disk/mmcsd/mmcsd.c optional mmcsd
-dev/disk/mps/mps.c optional mps
-dev/disk/mps/mps_pci.c optional mps pci
-dev/disk/mps/mps_sas.c optional mps
-dev/disk/mps/mps_table.c optional mps
-dev/disk/mps/mps_user.c optional mps
+dev/raid/mps/mps.c optional mps
+dev/raid/mps/mps_config.c optional mps
+dev/raid/mps/mps_mapping.c optional mps
+dev/raid/mps/mps_pci.c optional mps pci
+dev/raid/mps/mps_sas.c optional mps
+dev/raid/mps/mps_sas_lsi.c optional mps
+dev/raid/mps/mps_table.c optional mps
+dev/raid/mps/mps_user.c optional mps
dev/disk/mpt/mpt.c optional mpt
dev/disk/mpt/mpt_cam.c optional mpt
dev/disk/mpt/mpt_debug.c optional mpt
.include "${.CURDIR}/../../platform/${MACHINE_PLATFORM}/Makefile.inc"
-SUBDIR= ahci aic aic7xxx ccd dm iscsi isp ispfw md mmcsd mps mpt ncv nsp
+SUBDIR= ahci aic aic7xxx ccd dm iscsi isp ispfw md mmcsd mpt ncv nsp
SUBDIR+= sbp sdhci sili stg sym trm vn vpo
.for dir in ${SUBDIR}
+++ /dev/null
-# $FreeBSD: src/sys/modules/mps/Makefile,v 1.3 2010/10/17 20:01:56 scottl Exp $
-
-KMOD= mps
-SRCS= mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c
-SRCS+= opt_mps.h opt_cam.h opt_compat.h
-SRCS+= device_if.h bus_if.h pci_if.h
-
-#CFLAGS += -DMPS_DEBUG
-
-.include <bsd.kmod.mk>
+++ /dev/null
-/*-
- * Copyright (c) 2008 Yahoo!, Inc.
- * All rights reserved.
- * Written by: John Baldwin <jhb@FreeBSD.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * LSI MPT-Fusion Host Adapter FreeBSD userland interface
- *
- * $FreeBSD: src/sys/dev/mps/mps_ioctl.h,v 1.2 2010/10/11 21:26:24 mdf Exp $
- */
-
-#ifndef _MPS_IOCTL_H_
-#define _MPS_IOCTL_H_
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpi/mpi2_sas.h>
-
-/*
- * For the read header requests, the header should include the page
- * type or extended page type, page number, and page version. The
- * buffer and length are unused. The completed header is returned in
- * the 'header' member.
- *
- * For the read page and write page requests, 'buf' should point to a
- * buffer of 'len' bytes which holds the entire page (including the
- * header).
- *
- * All requests specify the page address in 'page_address'.
- */
-struct mps_cfg_page_req {
- MPI2_CONFIG_PAGE_HEADER header;
- uint32_t page_address;
- void *buf;
- int len;
- uint16_t ioc_status;
-};
-
-struct mps_ext_cfg_page_req {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
- uint32_t page_address;
- void *buf;
- int len;
- uint16_t ioc_status;
-};
-
-struct mps_raid_action {
- uint8_t action;
- uint8_t volume_bus;
- uint8_t volume_id;
- uint8_t phys_disk_num;
- uint32_t action_data_word;
- void *buf;
- int len;
- uint32_t volume_status;
- uint32_t action_data[4];
- uint16_t action_status;
- uint16_t ioc_status;
- uint8_t write;
-};
-
-struct mps_usr_command {
- void *req;
- uint32_t req_len;
- void *rpl;
- uint32_t rpl_len;
- void *buf;
- int len;
- uint32_t flags;
-};
-
-#define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01
-#define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02
-#define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req)
-#define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req)
-#define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req)
-#define MPSIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mps_ext_cfg_page_req)
-#define MPSIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mps_cfg_page_req)
-#define MPSIO_RAID_ACTION _IOWR('M', 205, struct mps_raid_action)
-#define MPSIO_MPS_COMMAND _IOWR('M', 210, struct mps_usr_command)
-
-#endif /* !_MPS_IOCTL_H_ */
+++ /dev/null
-/*-
- * Copyright (c) 2009 Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/mps/mps_sas.c,v 1.7 2010/12/11 00:36:35 ken Exp $
- */
-
-/* Communications core for LSI MPT2 */
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/bio.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
-#include <sys/sysctl.h>
-#include <sys/endian.h>
-
-#include <sys/rman.h>
-#include <sys/lock.h>
-#include <sys/globaldata.h>
-
-#include <bus/cam/cam.h>
-#include <bus/cam/cam_ccb.h>
-#include <bus/cam/cam_debug.h>
-#include <bus/cam/cam_sim.h>
-#include <bus/cam/cam_xpt_sim.h>
-#include <bus/cam/cam_xpt_periph.h>
-#include <bus/cam/cam_periph.h>
-#include <bus/cam/scsi/scsi_all.h>
-#include <bus/cam/scsi/scsi_message.h>
-#if __FreeBSD_version >= 900026
-#include <bus/cam/scsi/smp_all.h>
-#endif
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_sas.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpi/mpi2_init.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
-
-struct mpssas_target {
- uint16_t handle;
- uint8_t linkrate;
- uint64_t devname;
- uint64_t sasaddr;
- uint32_t devinfo;
- uint16_t encl_handle;
- uint16_t encl_slot;
- uint16_t parent_handle;
- int flags;
-#define MPSSAS_TARGET_INABORT (1 << 0)
-#define MPSSAS_TARGET_INRESET (1 << 1)
-#define MPSSAS_TARGET_INCHIPRESET (1 << 2)
-#define MPSSAS_TARGET_INRECOVERY 0x7
- uint16_t tid;
-};
-
-struct mpssas_softc {
- struct mps_softc *sc;
- u_int flags;
-#define MPSSAS_IN_DISCOVERY (1 << 0)
-#define MPSSAS_IN_STARTUP (1 << 1)
-#define MPSSAS_DISCOVERY_TIMEOUT_PENDING (1 << 2)
-#define MPSSAS_QUEUE_FROZEN (1 << 3)
- struct mpssas_target *targets;
- struct cam_devq *devq;
- struct cam_sim *sim;
- struct cam_path *path;
- struct intr_config_hook sas_ich;
- struct callout discovery_callout;
- u_int discovery_timeouts;
- struct mps_event_handle *mpssas_eh;
-};
-
-struct mpssas_devprobe {
- struct mps_config_params params;
- u_int state;
-#define MPSSAS_PROBE_DEV1 0x01
-#define MPSSAS_PROBE_DEV2 0x02
-#define MPSSAS_PROBE_PHY 0x03
-#define MPSSAS_PROBE_EXP 0x04
-#define MPSSAS_PROBE_PHY2 0x05
-#define MPSSAS_PROBE_EXP2 0x06
- struct mpssas_target target;
-};
-
-#define MPSSAS_DISCOVERY_TIMEOUT 20
-#define MPSSAS_MAX_DISCOVERY_TIMEOUTS 10 /* 200 seconds */
-
-MALLOC_DEFINE(M_MPSSAS, "MPSSAS", "MPS SAS memory");
-
-static __inline int mpssas_set_lun(uint8_t *lun, u_int ccblun);
-static struct mpssas_target * mpssas_alloc_target(struct mpssas_softc *,
- struct mpssas_target *);
-static struct mpssas_target * mpssas_find_target(struct mpssas_softc *, int,
- uint16_t);
-static void mpssas_announce_device(struct mpssas_softc *,
- struct mpssas_target *);
-static void mpssas_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
-static void mpssas_startup(void *data);
-static void mpssas_discovery_end(struct mpssas_softc *sassc);
-static void mpssas_discovery_timeout(void *data);
-static void mpssas_prepare_remove(struct mpssas_softc *,
- MPI2_EVENT_SAS_TOPO_PHY_ENTRY *);
-static void mpssas_remove_device(struct mps_softc *, struct mps_command *);
-static void mpssas_remove_complete(struct mps_softc *, struct mps_command *);
-static void mpssas_action(struct cam_sim *sim, union ccb *ccb);
-static void mpssas_poll(struct cam_sim *sim);
-static void mpssas_probe_device(struct mps_softc *sc, uint16_t handle);
-static void mpssas_probe_device_complete(struct mps_softc *sc,
- struct mps_config_params *params);
-static void mpssas_scsiio_timeout(void *data);
-static void mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_recovery(struct mps_softc *, struct mps_command *);
-static int mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_issue_tm_request(struct mps_softc *sc,
- struct mps_command *cm);
-static void mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm,
- int error);
-static int mpssas_complete_tm_request(struct mps_softc *sc,
- struct mps_command *cm, int free_cm);
-static void mpssas_action_scsiio(struct mpssas_softc *, union ccb *);
-static void mpssas_scsiio_complete(struct mps_softc *, struct mps_command *);
-#if __FreeBSD_version >= 900026
-static void mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm);
-static void mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb,
- uint64_t sasaddr);
-static void mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb);
-#endif /* __FreeBSD_version >= 900026 */
-static void mpssas_resetdev(struct mpssas_softc *, struct mps_command *);
-static void mpssas_action_resetdev(struct mpssas_softc *, union ccb *);
-static void mpssas_resetdev_complete(struct mps_softc *, struct mps_command *);
-static void mpssas_freeze_device(struct mpssas_softc *, struct mpssas_target *);
-static void mpssas_unfreeze_device(struct mpssas_softc *, struct mpssas_target *) __unused;
-
-/*
- * Abstracted so that the driver can be backwards and forwards compatible
- * with future versions of CAM that will provide this functionality.
- */
-#define MPS_SET_LUN(lun, ccblun) \
- mpssas_set_lun(lun, ccblun)
-
-static __inline int
-mpssas_set_lun(uint8_t *lun, u_int ccblun)
-{
- uint64_t *newlun;
-
- newlun = (uint64_t *)lun;
- *newlun = 0;
- if (ccblun <= 0xff) {
- /* Peripheral device address method, LUN is 0 to 255 */
- lun[1] = ccblun;
- } else if (ccblun <= 0x3fff) {
- /* Flat space address method, LUN is <= 16383 */
- scsi_ulto2b(ccblun, lun);
- lun[0] |= 0x40;
- } else if (ccblun <= 0xffffff) {
- /* Extended flat space address method, LUN is <= 16777215 */
- scsi_ulto3b(ccblun, &lun[1]);
- /* Extended Flat space address method */
- lun[0] = 0xc0;
- /* Length = 1, i.e. LUN is 3 bytes long */
- lun[0] |= 0x10;
- /* Extended Address Method */
- lun[0] |= 0x02;
- } else {
- return (EINVAL);
- }
-
- return (0);
-}
-
-static struct mpssas_target *
-mpssas_alloc_target(struct mpssas_softc *sassc, struct mpssas_target *probe)
-{
- struct mpssas_target *target;
- int start;
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
- /*
- * If it's not a sata or sas target, CAM won't be able to see it. Put
- * it into a high-numbered slot so that it's accessible but not
- * interrupting the target numbering sequence of real drives.
- */
- if ((probe->devinfo & (MPI2_SAS_DEVICE_INFO_SSP_TARGET |
- MPI2_SAS_DEVICE_INFO_STP_TARGET | MPI2_SAS_DEVICE_INFO_SATA_DEVICE))
- == 0) {
- start = 200;
- } else {
- /*
- * Use the enclosure number and slot number as a hint for target
- * numbering. If that doesn't produce a sane result, search the
- * entire space.
- */
-#if 0
- start = probe->encl_handle * 16 + probe->encl_slot;
-#else
- start = probe->encl_slot;
-#endif
- if (start >= sassc->sc->facts->MaxTargets)
- start = 0;
- }
-
- target = mpssas_find_target(sassc, start, 0);
-
- /*
- * Nothing found on the first pass, try a second pass that searches the
- * entire space.
- */
- if (target == NULL)
- target = mpssas_find_target(sassc, 0, 0);
-
- return (target);
-}
-
-static struct mpssas_target *
-mpssas_find_target(struct mpssas_softc *sassc, int start, uint16_t handle)
-{
- struct mpssas_target *target;
- int i;
-
- for (i = start; i < sassc->sc->facts->MaxTargets; i++) {
- target = &sassc->targets[i];
- if (target->handle == handle)
- return (target);
- }
-
- return (NULL);
-}
-
-/*
- * Start the probe sequence for a given device handle. This will not
- * block.
- */
-static void
-mpssas_probe_device(struct mps_softc *sc, uint16_t handle)
-{
- struct mpssas_devprobe *probe;
- struct mps_config_params *params;
- MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
- int error;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- probe = kmalloc(sizeof(*probe), M_MPSSAS, M_NOWAIT | M_ZERO);
- if (probe == NULL) {
- mps_dprint(sc, MPS_FAULT, "Out of memory starting probe\n");
- return;
- }
- params = &probe->params;
- hdr = ¶ms->hdr.Ext;
-
- params->action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- params->page_address = MPI2_SAS_DEVICE_PGAD_FORM_HANDLE | handle;
- hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
- hdr->ExtPageLength = 0;
- hdr->PageNumber = 0;
- hdr->PageVersion = 0;
- params->buffer = NULL;
- params->length = 0;
- params->callback = mpssas_probe_device_complete;
- params->cbdata = probe;
- probe->target.handle = handle;
- probe->state = MPSSAS_PROBE_DEV1;
-
- if ((error = mps_read_config_page(sc, params)) != 0) {
- kfree(probe, M_MPSSAS);
- mps_dprint(sc, MPS_FAULT, "Failure starting device probe\n");
- return;
- }
-}
-
-static void
-mpssas_probe_device_complete(struct mps_softc *sc,
- struct mps_config_params *params)
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
- struct mpssas_devprobe *probe;
- int error;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- hdr = ¶ms->hdr.Ext;
- probe = params->cbdata;
-
- switch (probe->state) {
- case MPSSAS_PROBE_DEV1:
- case MPSSAS_PROBE_PHY:
- case MPSSAS_PROBE_EXP:
- if (params->status != MPI2_IOCSTATUS_SUCCESS) {
- mps_dprint(sc, MPS_FAULT,
- "Probe Failure 0x%x state %d\n", params->status,
- probe->state);
- kfree(probe, M_MPSSAS);
- return;
- }
- params->action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- params->length = hdr->ExtPageLength * 4;
- params->buffer = kmalloc(params->length, M_MPSSAS,
- M_ZERO|M_NOWAIT);
- if (params->buffer == NULL) {
- mps_dprint(sc, MPS_FAULT, "Out of memory at state "
- "0x%x, size 0x%x\n", probe->state, params->length);
- kfree(probe, M_MPSSAS);
- return;
- }
- if (probe->state == MPSSAS_PROBE_DEV1)
- probe->state = MPSSAS_PROBE_DEV2;
- else if (probe->state == MPSSAS_PROBE_PHY)
- probe->state = MPSSAS_PROBE_PHY2;
- else if (probe->state == MPSSAS_PROBE_EXP)
- probe->state = MPSSAS_PROBE_EXP2;
- error = mps_read_config_page(sc, params);
- break;
- case MPSSAS_PROBE_DEV2:
- {
- MPI2_CONFIG_PAGE_SAS_DEV_0 *buf;
-
- if (params->status != MPI2_IOCSTATUS_SUCCESS) {
- mps_dprint(sc, MPS_FAULT,
- "Probe Failure 0x%x state %d\n", params->status,
- probe->state);
- kfree(params->buffer, M_MPSSAS);
- kfree(probe, M_MPSSAS);
- return;
- }
- buf = params->buffer;
- mps_print_sasdev0(sc, buf);
-
- probe->target.devname = mps_to_u64(&buf->DeviceName);
- probe->target.devinfo = buf->DeviceInfo;
- probe->target.encl_handle = buf->EnclosureHandle;
- probe->target.encl_slot = buf->Slot;
- probe->target.sasaddr = mps_to_u64(&buf->SASAddress);
- probe->target.parent_handle = buf->ParentDevHandle;
-
- if (buf->DeviceInfo & MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH) {
- params->page_address =
- MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | buf->PhyNum;
- hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
- hdr->PageNumber = 0;
- probe->state = MPSSAS_PROBE_PHY;
- } else {
- params->page_address =
- MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
- buf->ParentDevHandle | (buf->PhyNum << 16);
- hdr->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
- hdr->PageNumber = 1;
- probe->state = MPSSAS_PROBE_EXP;
- }
- params->action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- hdr->ExtPageLength = 0;
- hdr->PageVersion = 0;
- params->buffer = NULL;
- params->length = 0;
- kfree(buf, M_MPSSAS);
- error = mps_read_config_page(sc, params);
- break;
- }
- case MPSSAS_PROBE_PHY2:
- case MPSSAS_PROBE_EXP2:
- {
- MPI2_CONFIG_PAGE_SAS_PHY_0 *phy;
- MPI2_CONFIG_PAGE_EXPANDER_1 *exp;
- struct mpssas_softc *sassc;
- struct mpssas_target *targ;
- char devstring[80];
- uint16_t handle;
-
- if (params->status != MPI2_IOCSTATUS_SUCCESS) {
- mps_dprint(sc, MPS_FAULT,
- "Probe Failure 0x%x state %d\n", params->status,
- probe->state);
- kfree(params->buffer, M_MPSSAS);
- kfree(probe, M_MPSSAS);
- return;
- }
-
- if (probe->state == MPSSAS_PROBE_PHY2) {
- phy = params->buffer;
- mps_print_sasphy0(sc, phy);
- probe->target.linkrate = phy->NegotiatedLinkRate & 0xf;
- } else {
- exp = params->buffer;
- mps_print_expander1(sc, exp);
- probe->target.linkrate = exp->NegotiatedLinkRate & 0xf;
- }
- kfree(params->buffer, M_MPSSAS);
-
- sassc = sc->sassc;
- handle = probe->target.handle;
- if ((targ = mpssas_find_target(sassc, 0, handle)) != NULL) {
- mps_printf(sc, "Ignoring dup device handle 0x%04x\n",
- handle);
- kfree(probe, M_MPSSAS);
- return;
- }
- if ((targ = mpssas_alloc_target(sassc, &probe->target)) == NULL) {
- mps_printf(sc, "Target table overflow, handle 0x%04x\n",
- handle);
- kfree(probe, M_MPSSAS);
- return;
- }
-
- *targ = probe->target; /* Copy the attributes */
- targ->tid = targ - sassc->targets;
- mps_describe_devinfo(targ->devinfo, devstring, 80);
- if (bootverbose)
- mps_printf(sc, "Found device <%s> <%s> <0x%04x> "
- "<%d/%d>\n", devstring,
- mps_describe_table(mps_linkrate_names,
- targ->linkrate), targ->handle, targ->encl_handle,
- targ->encl_slot);
-
- kfree(probe, M_MPSSAS);
- mpssas_announce_device(sassc, targ);
- break;
- }
- default:
- kprintf("what?\n");
- }
-}
-
-/*
- * The MPT2 firmware performs debounce on the link to avoid transient link errors
- * and false removals. When it does decide that link has been lost and a device
- * need to go away, it expects that the host will perform a target reset and then
- * an op remove. The reset has the side-effect of aborting any outstanding
- * requests for the device, which is required for the op-remove to succeed. It's
- * not clear if the host should check for the device coming back alive after the
- * reset.
- */
-static void
-mpssas_prepare_remove(struct mpssas_softc *sassc, MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy)
-{
- MPI2_SCSI_TASK_MANAGE_REQUEST *req;
- struct mps_softc *sc;
- struct mps_command *cm;
- struct mpssas_target *targ = NULL;
- uint16_t handle;
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
- handle = phy->AttachedDevHandle;
- targ = mpssas_find_target(sassc, 0, handle);
- if (targ == NULL)
- /* We don't know about this device? */
- return;
-
- sc = sassc->sc;
- cm = mps_alloc_command(sc);
- if (cm == NULL) {
- mps_printf(sc, "command alloc failure in mpssas_prepare_remove\n");
- return;
- }
-
- req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
- req->DevHandle = targ->handle;
- req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-
- /* SAS Hard Link Reset / SATA Link Reset */
- req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
-
- cm->cm_data = NULL;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- cm->cm_complete = mpssas_remove_device;
- cm->cm_targ = targ;
- mpssas_issue_tm_request(sc, cm);
-}
-
-static void
-mpssas_remove_device(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SCSI_TASK_MANAGE_REPLY *reply;
- MPI2_SAS_IOUNIT_CONTROL_REQUEST *req;
- struct mpssas_target *targ;
- uint16_t handle;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- reply = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
- handle = cm->cm_targ->handle;
-
- mpssas_complete_tm_request(sc, cm, /*free_cm*/ 0);
-
- if (reply->IOCStatus != MPI2_IOCSTATUS_SUCCESS) {
- mps_printf(sc, "Failure 0x%x reseting device 0x%04x\n",
- reply->IOCStatus, handle);
- mps_free_command(sc, cm);
- return;
- }
-
- mps_printf(sc, "Reset aborted %d commands\n",
- (u_int)reply->TerminationCount);
- mps_free_reply(sc, cm->cm_reply_data);
-
- /* Reuse the existing command */
- req = (MPI2_SAS_IOUNIT_CONTROL_REQUEST *)cm->cm_req;
- req->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
- req->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
- req->DevHandle = handle;
- cm->cm_data = NULL;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- cm->cm_flags &= ~MPS_CM_FLAGS_COMPLETE;
- cm->cm_complete = mpssas_remove_complete;
-
- mps_map_command(sc, cm);
-
- mps_dprint(sc, MPS_INFO, "clearing target handle 0x%04x\n", handle);
- targ = mpssas_find_target(sc->sassc, 0, handle);
- if (targ != NULL) {
- targ->handle = 0x0;
- mpssas_announce_device(sc->sassc, targ);
- }
-}
-
-static void
-mpssas_remove_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SAS_IOUNIT_CONTROL_REPLY *reply;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- reply = (MPI2_SAS_IOUNIT_CONTROL_REPLY *)cm->cm_reply;
-
- mps_printf(sc, "mpssas_remove_complete on target 0x%04x,"
- " IOCStatus= 0x%x\n", cm->cm_targ->tid, reply->IOCStatus);
-
- mps_free_command(sc, cm);
-}
-
-static void
-mpssas_evt_handler(struct mps_softc *sc, uintptr_t data,
- MPI2_EVENT_NOTIFICATION_REPLY *event)
-{
- struct mpssas_softc *sassc;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- sassc = sc->sassc;
- mps_print_evt_sas(sc, event);
-
- switch (event->Event) {
- case MPI2_EVENT_SAS_DISCOVERY:
- {
- MPI2_EVENT_DATA_SAS_DISCOVERY *data;
-
- data = (MPI2_EVENT_DATA_SAS_DISCOVERY *)&event->EventData;
-
- if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_STARTED)
- mps_dprint(sc, MPS_TRACE,"SAS discovery start event\n");
- if (data->ReasonCode & MPI2_EVENT_SAS_DISC_RC_COMPLETED) {
- mps_dprint(sc, MPS_TRACE, "SAS discovery end event\n");
- sassc->flags &= ~MPSSAS_IN_DISCOVERY;
- mpssas_discovery_end(sassc);
- }
- break;
- }
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- {
- MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *data;
- MPI2_EVENT_SAS_TOPO_PHY_ENTRY *phy;
- int i;
-
- data = (MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST *)
- &event->EventData;
-
- if (data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) {
- if (bootverbose)
- kprintf("Expander found at enclosure %d\n",
- data->EnclosureHandle);
- mpssas_probe_device(sc, data->ExpanderDevHandle);
- }
-
- for (i = 0; i < data->NumEntries; i++) {
- phy = &data->PHY[i];
- switch (phy->PhyStatus & MPI2_EVENT_SAS_TOPO_RC_MASK) {
- case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- mpssas_probe_device(sc, phy->AttachedDevHandle);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- mpssas_prepare_remove(sassc, phy);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
- case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
- case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
- default:
- break;
- }
- }
-
- break;
- }
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- break;
- default:
- break;
- }
-
- mps_free_reply(sc, data);
-}
-
-static int
-mpssas_register_events(struct mps_softc *sc)
-{
- uint8_t events[16];
-
- bzero(events, 16);
- setbit(events, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
- setbit(events, MPI2_EVENT_SAS_DISCOVERY);
- setbit(events, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
- setbit(events, MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE);
- setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW);
- setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
- setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
-
- mps_register_events(sc, events, mpssas_evt_handler, NULL,
- &sc->sassc->mpssas_eh);
-
- return (0);
-}
-
-int
-mps_attach_sas(struct mps_softc *sc)
-{
- struct mpssas_softc *sassc;
- int error = 0;
- int num_sim_reqs;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- sassc = kmalloc(sizeof(struct mpssas_softc), M_MPT2, M_WAITOK|M_ZERO);
- sassc->targets = kmalloc(sizeof(struct mpssas_target) *
- sc->facts->MaxTargets, M_MPT2, M_WAITOK|M_ZERO);
- sc->sassc = sassc;
- sassc->sc = sc;
-
- /*
- * Tell CAM that we can handle 5 fewer requests than we have
- * allocated. If we allow the full number of requests, all I/O
- * will halt when we run out of resources. Things work fine with
- * just 1 less request slot given to CAM than we have allocated.
- * We also need a couple of extra commands so that we can send down
- * abort, reset, etc. requests when commands time out. Otherwise
- * we could wind up in a situation with sc->num_reqs requests down
- * on the card and no way to send an abort.
- *
- * XXX KDM need to figure out why I/O locks up if all commands are
- * used.
- */
- num_sim_reqs = sc->num_reqs - 5;
-
- if ((sassc->devq = cam_simq_alloc(num_sim_reqs)) == NULL) {
- mps_dprint(sc, MPS_FAULT, "Cannot allocate SIMQ\n");
- error = ENOMEM;
- goto out;
- }
-
- sassc->sim = cam_sim_alloc(mpssas_action, mpssas_poll, "mps", sassc,
- device_get_unit(sc->mps_dev), &sc->mps_lock, num_sim_reqs,
- num_sim_reqs, sassc->devq);
- if (sassc->sim == NULL) {
- mps_dprint(sc, MPS_FAULT, "Cannot allocate SIM\n");
- error = EINVAL;
- goto out;
- }
-
- /*
- * XXX There should be a bus for every port on the adapter, but since
- * we're just going to fake the topology for now, we'll pretend that
- * everything is just a target on a single bus.
- */
- mps_lock(sc);
- if ((error = xpt_bus_register(sassc->sim, 0)) != 0) {
- mps_dprint(sc, MPS_FAULT, "Error %d registering SCSI bus\n",
- error);
- mps_unlock(sc);
- goto out;
- }
-
- /*
- * Assume that discovery events will start right away. Freezing
- * the simq will prevent the CAM boottime scanner from running
- * before discovery is complete.
- */
- sassc->flags = MPSSAS_IN_STARTUP | MPSSAS_IN_DISCOVERY;
- xpt_freeze_simq(sassc->sim, 1);
-
- mps_unlock(sc);
-
- callout_init(&sassc->discovery_callout);
- sassc->discovery_timeouts = 0;
-
- mpssas_register_events(sc);
-out:
- if (error)
- mps_detach_sas(sc);
- return (error);
-}
-
-int
-mps_detach_sas(struct mps_softc *sc)
-{
- struct mpssas_softc *sassc;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- if (sc->sassc == NULL)
- return (0);
-
- sassc = sc->sassc;
-
- /* Make sure CAM doesn't wedge if we had to bail out early. */
- mps_lock(sc);
- if (sassc->flags & MPSSAS_IN_STARTUP)
- xpt_release_simq(sassc->sim, 1);
- mps_unlock(sc);
-
- if (sassc->mpssas_eh != NULL)
- mps_deregister_events(sc, sassc->mpssas_eh);
-
- mps_lock(sc);
-
- if (sassc->sim != NULL) {
- xpt_bus_deregister(cam_sim_path(sassc->sim));
- cam_sim_free(sassc->sim);
- }
- mps_unlock(sc);
-
- if (sassc->devq != NULL)
- cam_simq_release(sassc->devq);
-
- kfree(sassc->targets, M_MPT2);
- kfree(sassc, M_MPT2);
- sc->sassc = NULL;
-
- return (0);
-}
-
-static void
-mpssas_discovery_end(struct mpssas_softc *sassc)
-{
- struct mps_softc *sc = sassc->sc;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- if (sassc->flags & MPSSAS_DISCOVERY_TIMEOUT_PENDING)
- callout_stop(&sassc->discovery_callout);
-
- if ((sassc->flags & MPSSAS_IN_STARTUP) != 0) {
- mps_dprint(sc, MPS_INFO,
- "mpssas_discovery_end: removing confighook\n");
- sassc->flags &= ~MPSSAS_IN_STARTUP;
- xpt_release_simq(sassc->sim, 1);
- }
-#if 0
- mpssas_announce_device(sassc, NULL);
-#endif
-
-}
-
-static void
-mpssas_announce_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
- union ccb *ccb;
- int bus, tid, lun;
-
- /*
- * Force a rescan, a hackish way to announce devices.
- * XXX Doing a scan on an individual device is hackish in that it
- * won't scan the LUNs.
- * XXX Does it matter if any of this fails?
- */
- bus = cam_sim_path(sassc->sim);
- if (targ != NULL) {
- tid = targ->tid;
- lun = 0;
- } else {
- tid = CAM_TARGET_WILDCARD;
- lun = CAM_LUN_WILDCARD;
- }
- ccb = xpt_alloc_ccb();
- if (ccb == NULL)
- return;
- if (xpt_create_path(&ccb->ccb_h.path, xpt_periph, bus, tid,
- CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
- xpt_free_ccb(ccb);
- return;
- }
- mps_dprint(sassc->sc, MPS_INFO, "Triggering rescan of %d:%d:-1\n",
- bus, tid);
- xpt_setup_ccb(&ccb->ccb_h, ccb->ccb_h.path, 5/*priority (low)*/);
- ccb->ccb_h.func_code = XPT_SCAN_BUS;
- ccb->ccb_h.cbfcnp = mpssas_bus_scan_cb;
- ccb->crcn.flags = CAM_FLAG_NONE;
- xpt_action(ccb);
-}
-
-static void
-mpssas_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
-{
- xpt_free_path(ccb->ccb_h.path);
- kfree(ccb, M_TEMP);
-}
-
-static void
-mpssas_startup(void *data)
-{
- struct mpssas_softc *sassc = data;
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
- mps_lock(sassc->sc);
- if ((sassc->flags & MPSSAS_IN_DISCOVERY) == 0) {
- mpssas_discovery_end(sassc);
- } else {
- if (sassc->discovery_timeouts < MPSSAS_MAX_DISCOVERY_TIMEOUTS) {
- sassc->flags |= MPSSAS_DISCOVERY_TIMEOUT_PENDING;
- callout_reset(&sassc->discovery_callout,
- MPSSAS_DISCOVERY_TIMEOUT * hz,
- mpssas_discovery_timeout, sassc);
- sassc->discovery_timeouts++;
- } else {
- mps_dprint(sassc->sc, MPS_FAULT,
- "Discovery timed out, continuing.\n");
- sassc->flags &= ~MPSSAS_IN_DISCOVERY;
- mpssas_discovery_end(sassc);
- }
- }
- mps_unlock(sassc->sc);
-
- return;
-}
-
-static void
-mpssas_discovery_timeout(void *data)
-{
- struct mpssas_softc *sassc = data;
- struct mps_softc *sc;
-
- sc = sassc->sc;
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- mps_lock(sc);
- mps_printf(sc,
- "Timeout waiting for discovery, interrupts may not be working!\n");
- sassc->flags &= ~MPSSAS_DISCOVERY_TIMEOUT_PENDING;
-
- /* Poll the hardware for events in case interrupts aren't working */
- mps_intr_locked(sc);
- mps_unlock(sc);
-
- /* Check the status of discovery and re-arm the timeout if needed */
- mpssas_startup(sassc);
-}
-
-static void
-mpssas_action(struct cam_sim *sim, union ccb *ccb)
-{
- struct mpssas_softc *sassc;
-
- sassc = cam_sim_softc(sim);
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s func 0x%x\n", __func__,
- ccb->ccb_h.func_code);
-
- switch (ccb->ccb_h.func_code) {
- case XPT_PATH_INQ:
- {
- struct ccb_pathinq *cpi = &ccb->cpi;
-
- cpi->version_num = 1;
- cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
- cpi->target_sprt = 0;
- cpi->hba_misc = PIM_NOBUSRESET;
- cpi->hba_eng_cnt = 0;
- cpi->max_target = sassc->sc->facts->MaxTargets - 1;
- cpi->max_lun = 0;
- cpi->initiator_id = 255;
- strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
- strncpy(cpi->hba_vid, "LSILogic", HBA_IDLEN);
- strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
- cpi->unit_number = cam_sim_unit(sim);
- cpi->bus_id = cam_sim_bus(sim);
- cpi->base_transfer_speed = 150000;
- cpi->transport = XPORT_SAS;
- cpi->transport_version = 0;
- cpi->protocol = PROTO_SCSI;
- cpi->protocol_version = SCSI_REV_SPC;
- cpi->ccb_h.status = CAM_REQ_CMP;
- break;
- }
- case XPT_GET_TRAN_SETTINGS:
- {
- struct ccb_trans_settings *cts;
- struct ccb_trans_settings_sas *sas;
- struct ccb_trans_settings_scsi *scsi;
- struct mpssas_target *targ;
-
- cts = &ccb->cts;
- sas = &cts->xport_specific.sas;
- scsi = &cts->proto_specific.scsi;
-
- targ = &sassc->targets[cts->ccb_h.target_id];
- if (targ->handle == 0x0) {
- cts->ccb_h.status = CAM_TID_INVALID;
- break;
- }
-
- cts->protocol_version = SCSI_REV_SPC2;
- cts->transport = XPORT_SAS;
- cts->transport_version = 0;
-
- sas->valid = CTS_SAS_VALID_SPEED;
- switch (targ->linkrate) {
- case 0x08:
- sas->bitrate = 150000;
- break;
- case 0x09:
- sas->bitrate = 300000;
- break;
- case 0x0a:
- sas->bitrate = 600000;
- break;
- default:
- sas->valid = 0;
- }
-
- cts->protocol = PROTO_SCSI;
- scsi->valid = CTS_SCSI_VALID_TQ;
- scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
-
- cts->ccb_h.status = CAM_REQ_CMP;
- break;
- }
- case XPT_CALC_GEOMETRY:
- cam_calc_geometry(&ccb->ccg, /*extended*/1);
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- case XPT_RESET_DEV:
- mpssas_action_resetdev(sassc, ccb);
- return;
- case XPT_RESET_BUS:
- case XPT_ABORT:
- case XPT_TERM_IO:
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- case XPT_SCSI_IO:
- mpssas_action_scsiio(sassc, ccb);
- return;
-#if __FreeBSD_version >= 900026
- case XPT_SMP_IO:
- mpssas_action_smpio(sassc, ccb);
- return;
-#endif /* __FreeBSD_version >= 900026 */
- default:
- ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
- break;
- }
- xpt_done(ccb);
-
-}
-
-#if 0
-static void
-mpssas_resettimeout_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SCSI_TASK_MANAGE_REPLY *resp;
- uint16_t code;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
- code = resp->ResponseCode;
-
- mps_free_command(sc, cm);
- mpssas_unfreeze_device(sassc, targ);
-
- if (code != MPI2_SCSITASKMGMT_RSP_TM_COMPLETE) {
- mps_reset_controller(sc);
- }
-
- return;
-}
-#endif
-
-static void
-mpssas_scsiio_timeout(void *data)
-{
- union ccb *ccb;
- struct mps_softc *sc;
- struct mps_command *cm;
- struct mpssas_target *targ;
-#if 0
- char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
-#endif
-
- cm = (struct mps_command *)data;
- sc = cm->cm_sc;
-
- /*
- * Run the interrupt handler to make sure it's not pending. This
- * isn't perfect because the command could have already completed
- * and been re-used, though this is unlikely.
- */
- mps_lock(sc);
- mps_intr_locked(sc);
- if (cm->cm_state == MPS_CM_STATE_FREE) {
- mps_unlock(sc);
- return;
- }
-
- ccb = cm->cm_complete_data;
- targ = cm->cm_targ;
- if (targ == NULL)
- /* Driver bug */
- targ = &sc->sassc->targets[ccb->ccb_h.target_id];
-
- xpt_print(ccb->ccb_h.path, "SCSI command timeout on device handle "
- "0x%04x SMID %d\n", targ->handle, cm->cm_desc.Default.SMID);
- /*
- * XXX KDM this is useful for debugging purposes, but the existing
- * scsi_op_desc() implementation can't handle a NULL value for
- * inq_data. So this will remain commented out until I bring in
- * those changes as well.
- */
-#if 0
- xpt_print(ccb->ccb_h.path, "Timed out command: %s. CDB %s\n",
- scsi_op_desc((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
- ccb->csio.cdb_io.cdb_ptr[0] :
- ccb->csio.cdb_io.cdb_bytes[0], NULL),
- scsi_cdb_string((ccb->ccb_h.flags & CAM_CDB_POINTER) ?
- ccb->csio.cdb_io.cdb_ptr :
- ccb->csio.cdb_io.cdb_bytes, cdb_str,
- sizeof(cdb_str)));
-#endif
-
- /* Inform CAM about the timeout and that recovery is starting. */
-#if 0
- if ((targ->flags & MPSSAS_TARGET_INRECOVERY) == 0) {
- mpssas_freeze_device(sc->sassc, targ);
- ccb->ccb_h.status = CAM_CMD_TIMEOUT;
- xpt_done(ccb);
- }
-#endif
- mpssas_freeze_device(sc->sassc, targ);
- ccb->ccb_h.status = CAM_CMD_TIMEOUT;
-
- /*
- * recycle the command into recovery so that there's no risk of
- * command allocation failure.
- */
- cm->cm_state = MPS_CM_STATE_TIMEDOUT;
- mpssas_recovery(sc, cm);
- mps_unlock(sc);
-}
-
-static void
-mpssas_abort_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-
- req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
-
- mps_printf(sc, "%s: abort request on handle %#04x SMID %d "
- "complete\n", __func__, req->DevHandle, req->TaskMID);
-
- mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1);
-}
-
-static void
-mpssas_recovery(struct mps_softc *sc, struct mps_command *abort_cm)
-{
- struct mps_command *cm;
- MPI2_SCSI_TASK_MANAGE_REQUEST *req, *orig_req;
-
- cm = mps_alloc_command(sc);
- if (cm == NULL) {
- mps_printf(sc, "%s: command allocation failure\n", __func__);
- return;
- }
-
- cm->cm_targ = abort_cm->cm_targ;
- cm->cm_complete = mpssas_abort_complete;
-
- req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
- orig_req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)abort_cm->cm_req;
- req->DevHandle = abort_cm->cm_targ->handle;
- req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK;
- memcpy(req->LUN, orig_req->LUN, sizeof(req->LUN));
- req->TaskMID = abort_cm->cm_desc.Default.SMID;
-
- cm->cm_data = NULL;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
- mpssas_issue_tm_request(sc, cm);
-
-}
-
-/*
- * Can return 0 or EINPROGRESS on success. Any other value means failure.
- */
-static int
-mpssas_map_tm_request(struct mps_softc *sc, struct mps_command *cm)
-{
- int error;
-
- error = 0;
-
- cm->cm_flags |= MPS_CM_FLAGS_ACTIVE;
- error = mps_map_command(sc, cm);
- if ((error == 0)
- || (error == EINPROGRESS))
- sc->tm_cmds_active++;
-
- return (error);
-}
-
-static void
-mpssas_issue_tm_request(struct mps_softc *sc, struct mps_command *cm)
-{
- int freeze_queue, send_command, error;
-
- freeze_queue = 0;
- send_command = 0;
- error = 0;
-
- KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
-
- /*
- * If there are no other pending task management commands, go
- * ahead and send this one. There is a small amount of anecdotal
- * evidence that sending lots of task management commands at once
- * may cause the controller to lock up. Or, if the user has
- * configured the driver (via the allow_multiple_tm_cmds variable) to
- * not serialize task management commands, go ahead and send the
- * command if even other task management commands are pending.
- */
- if (TAILQ_FIRST(&sc->tm_list) == NULL) {
- send_command = 1;
- freeze_queue = 1;
- } else if (sc->allow_multiple_tm_cmds != 0)
- send_command = 1;
-
- TAILQ_INSERT_TAIL(&sc->tm_list, cm, cm_link);
- if (send_command != 0) {
- /*
- * Freeze the SIM queue while we issue the task management
- * command. According to the Fusion-MPT 2.0 spec, task
- * management requests are serialized, and so the host
- * should not send any I/O requests while task management
- * requests are pending.
- */
- if (freeze_queue != 0)
- xpt_freeze_simq(sc->sassc->sim, 1);
-
- error = mpssas_map_tm_request(sc, cm);
-
- /*
- * At present, there is no error path back from
- * mpssas_map_tm_request() (which calls mps_map_command())
- * when cm->cm_data == NULL. But since there is a return
- * value, we check it just in case the implementation
- * changes later.
- */
- if ((error != 0)
- && (error != EINPROGRESS))
- mpssas_tm_complete(sc, cm,
- MPI2_SCSITASKMGMT_RSP_TM_FAILED);
- }
-}
-
-static void
-mpssas_tm_complete(struct mps_softc *sc, struct mps_command *cm, int error)
-{
- MPI2_SCSI_TASK_MANAGE_REPLY *resp;
-
- resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
-
- resp->ResponseCode = error;
-
- /*
- * Call the callback for this command, it will be
- * removed from the list and freed via the callback.
- */
- cm->cm_complete(sc, cm);
-}
-
-/*
- * Complete a task management request. The basic completion operation will
- * always succeed. Returns status for sending any further task management
- * commands that were queued.
- */
-static int
-mpssas_complete_tm_request(struct mps_softc *sc, struct mps_command *cm,
- int free_cm)
-{
- int error;
-
- error = 0;
-
- KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
-
- TAILQ_REMOVE(&sc->tm_list, cm, cm_link);
- cm->cm_flags &= ~MPS_CM_FLAGS_ACTIVE;
- sc->tm_cmds_active--;
-
- if (free_cm != 0)
- mps_free_command(sc, cm);
-
- if (TAILQ_FIRST(&sc->tm_list) == NULL) {
- /*
- * Release the SIM queue, we froze it when we sent the first
- * task management request.
- */
- xpt_release_simq(sc->sassc->sim, 1);
- } else if ((sc->tm_cmds_active == 0)
- || (sc->allow_multiple_tm_cmds != 0)) {
- int error;
- struct mps_command *cm2;
-
-restart_traversal:
-
- /*
- * We don't bother using TAILQ_FOREACH_SAFE here, but
- * rather use the standard version and just restart the
- * list traversal if we run into the error case.
- * TAILQ_FOREACH_SAFE allows safe removal of the current
- * list element, but if you have a queue of task management
- * commands, all of which have mapping errors, you'll end
- * up with recursive calls to this routine and so you could
- * wind up removing more than just the current list element.
- */
- TAILQ_FOREACH(cm2, &sc->tm_list, cm_link) {
- MPI2_SCSI_TASK_MANAGE_REQUEST *req;
-
- /* This command is active, no need to send it again */
- if (cm2->cm_flags & MPS_CM_FLAGS_ACTIVE)
- continue;
-
- req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm2->cm_req;
-
- mps_printf(sc, "%s: sending deferred task management "
- "request for handle %#04x SMID %d\n", __func__,
- req->DevHandle, req->TaskMID);
-
- error = mpssas_map_tm_request(sc, cm2);
-
- /*
- * Check for errors. If we had an error, complete
- * this command with an error, and keep going through
- * the list until we are able to send at least one
- * command or all of them are completed with errors.
- *
- * We don't want to wind up in a situation where
- * we're stalled out with no way for queued task
- * management commands to complete.
- *
- * Note that there is not currently an error path
- * back from mpssas_map_tm_request() (which calls
- * mps_map_command()) when cm->cm_data == NULL.
- * But we still want to check for errors here in
- * case the implementation changes, or in case
- * there is some reason for a data payload here.
- */
- if ((error != 0)
- && (error != EINPROGRESS)) {
- mpssas_tm_complete(sc, cm,
- MPI2_SCSITASKMGMT_RSP_TM_FAILED);
-
- /*
- * If we don't currently have any commands
- * active, go back to the beginning and see
- * if there are any more that can be started.
- * Otherwise, we're done here.
- */
- if (sc->tm_cmds_active == 0)
- goto restart_traversal;
- else
- break;
- }
-
- /*
- * If the user only wants one task management command
- * active at a time, we're done, since we've
- * already successfully sent a command at this point.
- */
- if (sc->allow_multiple_tm_cmds == 0)
- break;
- }
- }
-
- return (error);
-}
-
-static void
-mpssas_action_scsiio(struct mpssas_softc *sassc, union ccb *ccb)
-{
- MPI2_SCSI_IO_REQUEST *req;
- struct ccb_scsiio *csio;
- struct mps_softc *sc;
- struct mpssas_target *targ;
- struct mps_command *cm;
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
- sc = sassc->sc;
-
- csio = &ccb->csio;
- targ = &sassc->targets[csio->ccb_h.target_id];
- if (targ->handle == 0x0) {
- csio->ccb_h.status = CAM_SEL_TIMEOUT;
- xpt_done(ccb);
- return;
- }
-
- cm = mps_alloc_command(sc);
- if (cm == NULL) {
- if ((sassc->flags & MPSSAS_QUEUE_FROZEN) == 0) {
- xpt_freeze_simq(sassc->sim, 1);
- sassc->flags |= MPSSAS_QUEUE_FROZEN;
- }
- ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
- ccb->ccb_h.status |= CAM_REQUEUE_REQ;
- xpt_done(ccb);
- return;
- }
-
- req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req;
- req->DevHandle = targ->handle;
- req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- req->MsgFlags = 0;
- req->SenseBufferLowAddress = cm->cm_sense_busaddr;
- req->SenseBufferLength = MPS_SENSE_LEN;
- req->SGLFlags = 0;
- req->ChainOffset = 0;
- req->SGLOffset0 = 24; /* 32bit word offset to the SGL */
- req->SGLOffset1= 0;
- req->SGLOffset2= 0;
- req->SGLOffset3= 0;
- req->SkipCount = 0;
- req->DataLength = csio->dxfer_len;
- req->BidirectionalDataLength = 0;
- req->IoFlags = csio->cdb_len;
- req->EEDPFlags = 0;
-
- /* Note: BiDirectional transfers are not supported */
- switch (csio->ccb_h.flags & CAM_DIR_MASK) {
- case CAM_DIR_IN:
- req->Control = MPI2_SCSIIO_CONTROL_READ;
- cm->cm_flags |= MPS_CM_FLAGS_DATAIN;
- break;
- case CAM_DIR_OUT:
- req->Control = MPI2_SCSIIO_CONTROL_WRITE;
- cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
- break;
- case CAM_DIR_NONE:
- default:
- req->Control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
- break;
- }
-
- /*
- * It looks like the hardware doesn't require an explicit tag
- * number for each transaction. SAM Task Management not supported
- * at the moment.
- */
- switch (csio->tag_action) {
- case MSG_HEAD_OF_Q_TAG:
- req->Control |= MPI2_SCSIIO_CONTROL_HEADOFQ;
- break;
- case MSG_ORDERED_Q_TAG:
- req->Control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
- break;
- case MSG_ACA_TASK:
- req->Control |= MPI2_SCSIIO_CONTROL_ACAQ;
- break;
- case CAM_TAG_ACTION_NONE:
- case MSG_SIMPLE_Q_TAG:
- default:
- req->Control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- break;
- }
-
- if (MPS_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) {
- mps_free_command(sc, cm);
- ccb->ccb_h.status = CAM_LUN_INVALID;
- xpt_done(ccb);
- return;
- }
-
- if (csio->ccb_h.flags & CAM_CDB_POINTER)
- bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len);
- else
- bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len);
- req->IoFlags = csio->cdb_len;
-
- /*
- * XXX need to handle S/G lists and physical addresses here.
- */
- cm->cm_data = csio->data_ptr;
- cm->cm_length = csio->dxfer_len;
- cm->cm_sge = &req->SGL;
- cm->cm_sglsize = (32 - 24) * 4;
- cm->cm_desc.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- cm->cm_desc.SCSIIO.DevHandle = targ->handle;
- cm->cm_complete = mpssas_scsiio_complete;
- cm->cm_complete_data = ccb;
- cm->cm_targ = targ;
-
- callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000,
- mpssas_scsiio_timeout, cm);
-
- mps_map_command(sc, cm);
- return;
-}
-
-static void
-mpssas_scsiio_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SCSI_IO_REPLY *rep;
- union ccb *ccb;
- struct mpssas_softc *sassc;
- u_int sense_len;
- int dir = 0;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- callout_stop(&cm->cm_callout);
-
- sassc = sc->sassc;
- ccb = cm->cm_complete_data;
- rep = (MPI2_SCSI_IO_REPLY *)cm->cm_reply;
-
- if (cm->cm_data != NULL) {
- if (cm->cm_flags & MPS_CM_FLAGS_DATAIN)
- dir = BUS_DMASYNC_POSTREAD;
- else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT)
- dir = BUS_DMASYNC_POSTWRITE;;
- bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap, dir);
- bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
- }
-
- if (sassc->flags & MPSSAS_QUEUE_FROZEN) {
- ccb->ccb_h.flags |= CAM_RELEASE_SIMQ;
- sassc->flags &= ~MPSSAS_QUEUE_FROZEN;
- }
-
- /* Take the fast path to completion */
- if (cm->cm_reply == NULL) {
- ccb->ccb_h.status = CAM_REQ_CMP;
- ccb->csio.scsi_status = SCSI_STATUS_OK;
- mps_free_command(sc, cm);
- xpt_done(ccb);
- return;
- }
-
- mps_dprint(sc, MPS_INFO, "(%d:%d:%d) IOCStatus= 0x%x, "
- "ScsiStatus= 0x%x, SCSIState= 0x%x TransferCount= 0x%x\n",
- xpt_path_path_id(ccb->ccb_h.path),
- xpt_path_target_id(ccb->ccb_h.path),
- xpt_path_lun_id(ccb->ccb_h.path), rep->IOCStatus,
- rep->SCSIStatus, rep->SCSIState, (u_int)rep->TransferCount);
-
- switch (rep->IOCStatus & MPI2_IOCSTATUS_MASK) {
- case MPI2_IOCSTATUS_BUSY:
- case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
- /*
- * The controller is overloaded, try waiting a bit for it
- * to free up.
- */
- ccb->ccb_h.status = CAM_BUSY;
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- ccb->csio.resid = cm->cm_length - rep->TransferCount;
- /* FALLTHROUGH */
- case MPI2_IOCSTATUS_SUCCESS:
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- ccb->ccb_h.status = CAM_REQ_CMP;
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- /* resid is ignored for this condition */
- ccb->csio.resid = 0;
- ccb->ccb_h.status = CAM_DATA_RUN_ERR;
- break;
- case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- ccb->ccb_h.status = CAM_DEV_NOT_THERE;
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- /*
- * This is one of the responses that comes back when an I/O
- * has been aborted. If it is because of a timeout that we
- * initiated, just set the status to CAM_CMD_TIMEOUT.
- * Otherwise set it to CAM_REQ_ABORTED. The effect on the
- * command is the same (it gets retried, subject to the
- * retry counter), the only difference is what gets printed
- * on the console.
- */
- if (cm->cm_state == MPS_CM_STATE_TIMEDOUT)
- ccb->ccb_h.status = CAM_CMD_TIMEOUT;
- else
- ccb->ccb_h.status = CAM_REQ_ABORTED;
- break;
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- ccb->ccb_h.status = CAM_REQ_ABORTED;
- break;
- case MPI2_IOCSTATUS_INVALID_SGL:
- mps_print_scsiio_cmd(sc, cm);
- ccb->ccb_h.status = CAM_UNREC_HBA_ERROR;
- break;
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- case MPI2_IOCSTATUS_INTERNAL_ERROR:
- case MPI2_IOCSTATUS_INVALID_VPID:
- case MPI2_IOCSTATUS_INVALID_FIELD:
- case MPI2_IOCSTATUS_INVALID_STATE:
- case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- default:
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- }
-
-
- if ((rep->SCSIState & MPI2_SCSI_STATE_NO_SCSI_STATUS) == 0) {
- ccb->csio.scsi_status = rep->SCSIStatus;
-
- switch (rep->SCSIStatus) {
- case MPI2_SCSI_STATUS_TASK_SET_FULL:
- case MPI2_SCSI_STATUS_CHECK_CONDITION:
- ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
- break;
- case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
- case MPI2_SCSI_STATUS_TASK_ABORTED:
- ccb->ccb_h.status = CAM_REQ_ABORTED;
- break;
- case MPI2_SCSI_STATUS_GOOD:
- default:
- break;
- }
- }
-
- if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- sense_len = MIN(rep->SenseCount,
- sizeof(struct scsi_sense_data));
- if (sense_len < rep->SenseCount)
- ccb->csio.sense_resid = rep->SenseCount - sense_len;
- bcopy(cm->cm_sense, &ccb->csio.sense_data, sense_len);
- ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
- }
-
- if (rep->SCSIState & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
- ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
-
- if (rep->SCSIState & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-
- mps_free_command(sc, cm);
- xpt_done(ccb);
-}
-
-#if __FreeBSD_version >= 900026
-static void
-mpssas_smpio_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SMP_PASSTHROUGH_REPLY *rpl;
- MPI2_SMP_PASSTHROUGH_REQUEST *req;
- uint64_t sasaddr;
- union ccb *ccb;
-
- ccb = cm->cm_complete_data;
- rpl = (MPI2_SMP_PASSTHROUGH_REPLY *)cm->cm_reply;
- if (rpl == NULL) {
- mps_dprint(sc, MPS_INFO, "%s: NULL cm_reply!\n", __func__);
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- goto bailout;
- }
-
- req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
- sasaddr = le32toh(req->SASAddress.Low);
- sasaddr |= ((uint64_t)(le32toh(req->SASAddress.High))) << 32;
-
- if ((rpl->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS ||
- rpl->SASStatus != MPI2_SASSTATUS_SUCCESS) {
- mps_dprint(sc, MPS_INFO, "%s: IOCStatus %04x SASStatus %02x\n",
- __func__, rpl->IOCStatus, rpl->SASStatus);
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- goto bailout;
- }
-
- mps_dprint(sc, MPS_INFO, "%s: SMP request to SAS address "
- "%#jx completed successfully\n", __func__,
- (uintmax_t)sasaddr);
-
- if (ccb->smpio.smp_response[2] == SMP_FR_ACCEPTED)
- ccb->ccb_h.status = CAM_REQ_CMP;
- else
- ccb->ccb_h.status = CAM_SMP_STATUS_ERROR;
-
-bailout:
- /*
- * We sync in both directions because we had DMAs in the S/G list
- * in both directions.
- */
- bus_dmamap_sync(sc->buffer_dmat, cm->cm_dmamap,
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
- mps_free_command(sc, cm);
- xpt_done(ccb);
-}
-
-static void
-mpssas_send_smpcmd(struct mpssas_softc *sassc, union ccb *ccb, uint64_t sasaddr)
-{
- struct mps_command *cm;
- uint8_t *request, *response;
- MPI2_SMP_PASSTHROUGH_REQUEST *req;
- struct mps_softc *sc;
- struct sglist *sg;
- int error;
-
- sc = sassc->sc;
- sg = NULL;
- error = 0;
-
- /*
- * XXX We don't yet support physical addresses here.
- */
- if (ccb->ccb_h.flags & (CAM_DATA_PHYS|CAM_SG_LIST_PHYS)) {
- mps_printf(sc, "%s: physical addresses not supported\n",
- __func__);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- return;
- }
-
- /*
- * If the user wants to send an S/G list, check to make sure they
- * have single buffers.
- */
- if (ccb->ccb_h.flags & CAM_SCATTER_VALID) {
- /*
- * The chip does not support more than one buffer for the
- * request or response.
- */
- if ((ccb->smpio.smp_request_sglist_cnt > 1)
- || (ccb->smpio.smp_response_sglist_cnt > 1)) {
- mps_printf(sc, "%s: multiple request or response "
- "buffer segments not supported for SMP\n",
- __func__);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- xpt_done(ccb);
- return;
- }
-
- /*
- * The CAM_SCATTER_VALID flag was originally implemented
- * for the XPT_SCSI_IO CCB, which only has one data pointer.
- * We have two. So, just take that flag to mean that we
- * might have S/G lists, and look at the S/G segment count
- * to figure out whether that is the case for each individual
- * buffer.
- */
- if (ccb->smpio.smp_request_sglist_cnt != 0) {
- bus_dma_segment_t *req_sg;
-
- req_sg = (bus_dma_segment_t *)ccb->smpio.smp_request;
- request = (uint8_t *)req_sg[0].ds_addr;
- } else
- request = ccb->smpio.smp_request;
-
- if (ccb->smpio.smp_response_sglist_cnt != 0) {
- bus_dma_segment_t *rsp_sg;
-
- rsp_sg = (bus_dma_segment_t *)ccb->smpio.smp_response;
- response = (uint8_t *)rsp_sg[0].ds_addr;
- } else
- response = ccb->smpio.smp_response;
- } else {
- request = ccb->smpio.smp_request;
- response = ccb->smpio.smp_response;
- }
-
- cm = mps_alloc_command(sc);
- if (cm == NULL) {
- mps_printf(sc, "%s: cannot allocate command\n", __func__);
- ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- xpt_done(ccb);
- return;
- }
-
- req = (MPI2_SMP_PASSTHROUGH_REQUEST *)cm->cm_req;
- bzero(req, sizeof(*req));
- req->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
-
- /* Allow the chip to use any route to this SAS address. */
- req->PhysicalPort = 0xff;
-
- req->RequestDataLength = ccb->smpio.smp_request_len;
- req->SGLFlags =
- MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE | MPI2_SGLFLAGS_SGL_TYPE_MPI;
-
- mps_dprint(sc, MPS_INFO, "%s: sending SMP request to SAS "
- "address %#jx\n", __func__, (uintmax_t)sasaddr);
-
- mpi_init_sge(cm, req, &req->SGL);
-
- /*
- * Set up a uio to pass into mps_map_command(). This allows us to
- * do one map command, and one busdma call in there.
- */
- cm->cm_uio.uio_iov = cm->cm_iovec;
- cm->cm_uio.uio_iovcnt = 2;
- cm->cm_uio.uio_segflg = UIO_SYSSPACE;
-
- /*
- * The read/write flag isn't used by busdma, but set it just in
- * case. This isn't exactly accurate, either, since we're going in
- * both directions.
- */
- cm->cm_uio.uio_rw = UIO_WRITE;
-
- cm->cm_iovec[0].iov_base = request;
- cm->cm_iovec[0].iov_len = req->RequestDataLength;
- cm->cm_iovec[1].iov_base = response;
- cm->cm_iovec[1].iov_len = ccb->smpio.smp_response_len;
-
- cm->cm_uio.uio_resid = cm->cm_iovec[0].iov_len +
- cm->cm_iovec[1].iov_len;
-
- /*
- * Trigger a warning message in mps_data_cb() for the user if we
- * wind up exceeding two S/G segments. The chip expects one
- * segment for the request and another for the response.
- */
- cm->cm_max_segs = 2;
-
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- cm->cm_complete = mpssas_smpio_complete;
- cm->cm_complete_data = ccb;
-
- /*
- * Tell the mapping code that we're using a uio, and that this is
- * an SMP passthrough request. There is a little special-case
- * logic there (in mps_data_cb()) to handle the bidirectional
- * transfer.
- */
- cm->cm_flags |= MPS_CM_FLAGS_USE_UIO | MPS_CM_FLAGS_SMP_PASS |
- MPS_CM_FLAGS_DATAIN | MPS_CM_FLAGS_DATAOUT;
-
- /* The chip data format is little endian. */
- req->SASAddress.High = htole32(sasaddr >> 32);
- req->SASAddress.Low = htole32(sasaddr);
-
- /*
- * XXX Note that we don't have a timeout/abort mechanism here.
- * From the manual, it looks like task management requests only
- * work for SCSI IO and SATA passthrough requests. We may need to
- * have a mechanism to retry requests in the event of a chip reset
- * at least. Hopefully the chip will insure that any errors short
- * of that are relayed back to the driver.
- */
- error = mps_map_command(sc, cm);
- if ((error != 0) && (error != EINPROGRESS)) {
- mps_printf(sc, "%s: error %d returned from mps_map_command()\n",
- __func__, error);
- goto bailout_error;
- }
-
- return;
-
-bailout_error:
- mps_free_command(sc, cm);
- ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- xpt_done(ccb);
- return;
-
-}
-
-static void
-mpssas_action_smpio(struct mpssas_softc *sassc, union ccb *ccb)
-{
- struct mps_softc *sc;
- struct mpssas_target *targ;
- uint64_t sasaddr = 0;
-
- sc = sassc->sc;
-
- /*
- * Make sure the target exists.
- */
- targ = &sassc->targets[ccb->ccb_h.target_id];
- if (targ->handle == 0x0) {
- mps_printf(sc, "%s: target %d does not exist!\n", __func__,
- ccb->ccb_h.target_id);
- ccb->ccb_h.status = CAM_SEL_TIMEOUT;
- xpt_done(ccb);
- return;
- }
-
- /*
- * If this device has an embedded SMP target, we'll talk to it
- * directly.
- * figure out what the expander's address is.
- */
- if ((targ->devinfo & MPI2_SAS_DEVICE_INFO_SMP_TARGET) != 0)
- sasaddr = targ->sasaddr;
-
- /*
- * If we don't have a SAS address for the expander yet, try
- * grabbing it from the page 0x83 information cached in the
- * transport layer for this target. LSI expanders report the
- * expander SAS address as the port-associated SAS address in
- * Inquiry VPD page 0x83. Maxim expanders don't report it in page
- * 0x83.
- *
- * XXX KDM disable this for now, but leave it commented out so that
- * it is obvious that this is another possible way to get the SAS
- * address.
- *
- * The parent handle method below is a little more reliable, and
- * the other benefit is that it works for devices other than SES
- * devices. So you can send a SMP request to a da(4) device and it
- * will get routed to the expander that device is attached to.
- * (Assuming the da(4) device doesn't contain an SMP target...)
- */
-#if 0
- if (sasaddr == 0)
- sasaddr = xpt_path_sas_addr(ccb->ccb_h.path);
-#endif
-
- /*
- * If we still don't have a SAS address for the expander, look for
- * the parent device of this device, which is probably the expander.
- */
- if (sasaddr == 0) {
- struct mpssas_target *parent_target;
-
- if (targ->parent_handle == 0x0) {
- mps_printf(sc, "%s: handle %d does not have a valid "
- "parent handle!\n", __func__, targ->handle);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- goto bailout;
- }
- parent_target = mpssas_find_target(sassc, 0,
- targ->parent_handle);
-
- if (parent_target == NULL) {
- mps_printf(sc, "%s: handle %d does not have a valid "
- "parent target!\n", __func__, targ->handle);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- goto bailout;
- }
-
- if ((parent_target->devinfo &
- MPI2_SAS_DEVICE_INFO_SMP_TARGET) == 0) {
- mps_printf(sc, "%s: handle %d parent %d does not "
- "have an SMP target!\n", __func__,
- targ->handle, parent_target->handle);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- goto bailout;
-
- }
-
- sasaddr = parent_target->sasaddr;
- }
-
- if (sasaddr == 0) {
- mps_printf(sc, "%s: unable to find SAS address for handle %d\n",
- __func__, targ->handle);
- ccb->ccb_h.status = CAM_REQ_INVALID;
- goto bailout;
- }
- mpssas_send_smpcmd(sassc, ccb, sasaddr);
-
- return;
-
-bailout:
- xpt_done(ccb);
-
-}
-
-#endif /* __FreeBSD_version >= 900026 */
-
-static void
-mpssas_action_resetdev(struct mpssas_softc *sassc, union ccb *ccb)
-{
- struct mps_softc *sc;
- struct mps_command *cm;
- struct mpssas_target *targ;
-
- sc = sassc->sc;
- targ = &sassc->targets[ccb->ccb_h.target_id];
-
- if (targ->flags & MPSSAS_TARGET_INRECOVERY) {
- ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- xpt_done(ccb);
- return;
- }
-
- cm = mps_alloc_command(sc);
- if (cm == NULL) {
- mps_printf(sc, "%s: cannot alloc command\n", __func__);
- ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
- xpt_done(ccb);
- return;
- }
-
- cm->cm_targ = targ;
- cm->cm_complete = mpssas_resetdev_complete;
- cm->cm_complete_data = ccb;
-
- mpssas_resetdev(sassc, cm);
-}
-
-static void
-mpssas_resetdev(struct mpssas_softc *sassc, struct mps_command *cm)
-{
- MPI2_SCSI_TASK_MANAGE_REQUEST *req;
- struct mps_softc *sc;
-
- mps_dprint(sassc->sc, MPS_TRACE, "%s\n", __func__);
-
- sc = sassc->sc;
-
- req = (MPI2_SCSI_TASK_MANAGE_REQUEST *)cm->cm_req;
- req->DevHandle = cm->cm_targ->handle;
- req->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- req->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
-
- /* SAS Hard Link Reset / SATA Link Reset */
- req->MsgFlags = MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET;
-
- cm->cm_data = NULL;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
- mpssas_issue_tm_request(sc, cm);
-}
-
-static void
-mpssas_resetdev_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_SCSI_TASK_MANAGE_REPLY *resp;
- union ccb *ccb;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- resp = (MPI2_SCSI_TASK_MANAGE_REPLY *)cm->cm_reply;
- ccb = cm->cm_complete_data;
-
- kprintf("resetdev complete IOCStatus= 0x%x ResponseCode= 0x%x\n",
- resp->IOCStatus, resp->ResponseCode);
-
- if (resp->ResponseCode == MPI2_SCSITASKMGMT_RSP_TM_COMPLETE)
- ccb->ccb_h.status = CAM_REQ_CMP;
- else
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
-
- mpssas_complete_tm_request(sc, cm, /*free_cm*/ 1);
-
- xpt_done(ccb);
-}
-
-static void
-mpssas_poll(struct cam_sim *sim)
-{
- struct mpssas_softc *sassc;
-
- sassc = cam_sim_softc(sim);
- mps_intr_locked(sassc->sc);
-}
-
-static void
-mpssas_freeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
-}
-
-static void
-mpssas_unfreeze_device(struct mpssas_softc *sassc, struct mpssas_target *targ)
-{
-}
+++ /dev/null
-/*-
- * Copyright (c) 2008 Yahoo!, Inc.
- * All rights reserved.
- * Written by: John Baldwin <jhb@FreeBSD.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * LSI MPS-Fusion Host Adapter FreeBSD userland interface
- *
- * $FreeBSD: src/sys/dev/mps/mps_user.c,v 1.9 2010/11/30 22:39:46 ken Exp $
- */
-
-#include "opt_compat.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/conf.h>
-#include <sys/bio.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
-#include <sys/sysctl.h>
-#include <sys/ioccom.h>
-#include <sys/endian.h>
-#include <sys/proc.h>
-#include <sys/sysent.h>
-
-#include <sys/rman.h>
-#include <sys/device.h>
-
-#include <bus/cam/scsi/scsi_all.h>
-
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
-#include <dev/disk/mps/mps_ioctl.h>
-
-static d_open_t mps_open;
-static d_close_t mps_close;
-static d_ioctl_t mps_ioctl_devsw;
-
-static struct dev_ops mps_ops = {
- { "mps", 0, 0 },
- .d_open = mps_open,
- .d_close = mps_close,
- .d_ioctl = mps_ioctl_devsw,
-};
-
-typedef int (mps_user_f)(struct mps_command *, struct mps_usr_command *);
-static mps_user_f mpi_pre_ioc_facts;
-static mps_user_f mpi_pre_port_facts;
-static mps_user_f mpi_pre_fw_download;
-static mps_user_f mpi_pre_fw_upload;
-static mps_user_f mpi_pre_sata_passthrough;
-static mps_user_f mpi_pre_smp_passthrough;
-static mps_user_f mpi_pre_config;
-static mps_user_f mpi_pre_sas_io_unit_control;
-
-static int mps_user_read_cfg_header(struct mps_softc *,
- struct mps_cfg_page_req *);
-static int mps_user_read_cfg_page(struct mps_softc *,
- struct mps_cfg_page_req *, void *);
-static int mps_user_read_extcfg_header(struct mps_softc *,
- struct mps_ext_cfg_page_req *);
-static int mps_user_read_extcfg_page(struct mps_softc *,
- struct mps_ext_cfg_page_req *, void *);
-static int mps_user_write_cfg_page(struct mps_softc *,
- struct mps_cfg_page_req *, void *);
-static int mps_user_setup_request(struct mps_command *,
- struct mps_usr_command *);
-static int mps_user_command(struct mps_softc *, struct mps_usr_command *);
-
-static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls");
-
-int
-mps_attach_user(struct mps_softc *sc)
-{
- int unit;
-
- unit = device_get_unit(sc->mps_dev);
- sc->mps_cdev = make_dev(&mps_ops, unit, UID_ROOT, GID_OPERATOR, 0640,
- "mps%d", unit);
- if (sc->mps_cdev == NULL) {
- return (ENOMEM);
- }
- sc->mps_cdev->si_drv1 = sc;
- return (0);
-}
-
-void
-mps_detach_user(struct mps_softc *sc)
-{
-
- /* XXX: do a purge of pending requests? */
- destroy_dev(sc->mps_cdev);
- dev_ops_remove_minor(&mps_ops, device_get_unit(sc->mps_dev));
-
-}
-
-static int
-mps_open(struct dev_open_args *ap)
-{
-
- return (0);
-}
-
-static int
-mps_close(struct dev_close_args *ap)
-{
-
- return (0);
-}
-
-static int
-mps_user_read_cfg_header(struct mps_softc *sc,
- struct mps_cfg_page_req *page_req)
-{
- MPI2_CONFIG_PAGE_HEADER *hdr;
- struct mps_config_params params;
- int error;
-
- hdr = ¶ms.hdr.Struct;
- params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- params.page_address = le32toh(page_req->page_address);
- hdr->PageVersion = 0;
- hdr->PageLength = 0;
- hdr->PageNumber = page_req->header.PageNumber;
- hdr->PageType = page_req->header.PageType;
- params.buffer = NULL;
- params.length = 0;
- params.callback = NULL;
-
- if ((error = mps_read_config_page(sc, ¶ms)) != 0) {
- /*
- * Leave the request. Without resetting the chip, it's
- * still owned by it and we'll just get into trouble
- * freeing it now. Mark it as abandoned so that if it
- * shows up later it can be freed.
- */
- mps_printf(sc, "read_cfg_header timed out\n");
- return (ETIMEDOUT);
- }
-
- page_req->ioc_status = htole16(params.status);
- if ((page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
- MPI2_IOCSTATUS_SUCCESS) {
- bcopy(hdr, &page_req->header, sizeof(page_req->header));
- }
-
- return (0);
-}
-
-static int
-mps_user_read_cfg_page(struct mps_softc *sc, struct mps_cfg_page_req *page_req,
- void *buf)
-{
- MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
- struct mps_config_params params;
- int error;
-
- reqhdr = buf;
- hdr = ¶ms.hdr.Struct;
- hdr->PageVersion = reqhdr->PageVersion;
- hdr->PageLength = reqhdr->PageLength;
- hdr->PageNumber = reqhdr->PageNumber;
- hdr->PageType = reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK;
- params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- params.page_address = le32toh(page_req->page_address);
- params.buffer = buf;
- params.length = le32toh(page_req->len);
- params.callback = NULL;
-
- if ((error = mps_read_config_page(sc, ¶ms)) != 0) {
- mps_printf(sc, "mps_user_read_cfg_page timed out\n");
- return (ETIMEDOUT);
- }
-
- page_req->ioc_status = htole16(params.status);
- return (0);
-}
-
-static int
-mps_user_read_extcfg_header(struct mps_softc *sc,
- struct mps_ext_cfg_page_req *ext_page_req)
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER *hdr;
- struct mps_config_params params;
- int error;
-
- hdr = ¶ms.hdr.Ext;
- params.action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- hdr->PageVersion = ext_page_req->header.PageVersion;
- hdr->ExtPageLength = 0;
- hdr->PageNumber = ext_page_req->header.PageNumber;
- hdr->ExtPageType = ext_page_req->header.ExtPageType;
- params.page_address = le32toh(ext_page_req->page_address);
- if ((error = mps_read_config_page(sc, ¶ms)) != 0) {
- /*
- * Leave the request. Without resetting the chip, it's
- * still owned by it and we'll just get into trouble
- * freeing it now. Mark it as abandoned so that if it
- * shows up later it can be freed.
- */
- mps_printf(sc, "mps_user_read_extcfg_header timed out\n");
- return (ETIMEDOUT);
- }
-
- ext_page_req->ioc_status = htole16(params.status);
- if ((ext_page_req->ioc_status & MPI2_IOCSTATUS_MASK) ==
- MPI2_IOCSTATUS_SUCCESS) {
- ext_page_req->header.PageVersion = hdr->PageVersion;
- ext_page_req->header.PageNumber = hdr->PageNumber;
- ext_page_req->header.PageType = hdr->PageType;
- ext_page_req->header.ExtPageLength = hdr->ExtPageLength;
- ext_page_req->header.ExtPageType = hdr->ExtPageType;
- }
-
- return (0);
-}
-
-static int
-mps_user_read_extcfg_page(struct mps_softc *sc,
- struct mps_ext_cfg_page_req *ext_page_req, void *buf)
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER *reqhdr, *hdr;
- struct mps_config_params params;
- int error;
-
- reqhdr = buf;
- hdr = ¶ms.hdr.Ext;
- params.action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- params.page_address = le32toh(ext_page_req->page_address);
- hdr->PageVersion = reqhdr->PageVersion;
- hdr->PageNumber = reqhdr->PageNumber;
- hdr->ExtPageType = reqhdr->ExtPageType;
- hdr->ExtPageLength = reqhdr->ExtPageLength;
- params.buffer = buf;
- params.length = le32toh(ext_page_req->len);
- params.callback = NULL;
-
- if ((error = mps_read_config_page(sc, ¶ms)) != 0) {
- mps_printf(sc, "mps_user_read_extcfg_page timed out\n");
- return (ETIMEDOUT);
- }
-
- ext_page_req->ioc_status = htole16(params.status);
- return (0);
-}
-
-static int
-mps_user_write_cfg_page(struct mps_softc *sc,
- struct mps_cfg_page_req *page_req, void *buf)
-{
- MPI2_CONFIG_PAGE_HEADER *reqhdr, *hdr;
- struct mps_config_params params;
- u_int hdr_attr;
- int error;
-
- reqhdr = buf;
- hdr = ¶ms.hdr.Struct;
- hdr_attr = reqhdr->PageType & MPI2_CONFIG_PAGEATTR_MASK;
- if (hdr_attr != MPI2_CONFIG_PAGEATTR_CHANGEABLE &&
- hdr_attr != MPI2_CONFIG_PAGEATTR_PERSISTENT) {
- mps_printf(sc, "page type 0x%x not changeable\n",
- reqhdr->PageType & MPI2_CONFIG_PAGETYPE_MASK);
- return (EINVAL);
- }
-
- /*
- * There isn't any point in restoring stripped out attributes
- * if you then mask them going down to issue the request.
- */
-
- hdr->PageVersion = reqhdr->PageVersion;
- hdr->PageLength = reqhdr->PageLength;
- hdr->PageNumber = reqhdr->PageNumber;
- hdr->PageType = reqhdr->PageType;
- params.action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- params.page_address = le32toh(page_req->page_address);
- params.buffer = buf;
- params.length = le32toh(page_req->len);
- params.callback = NULL;
-
- if ((error = mps_write_config_page(sc, ¶ms)) != 0) {
- mps_printf(sc, "mps_write_cfg_page timed out\n");
- return (ETIMEDOUT);
- }
-
- page_req->ioc_status = htole16(params.status);
- return (0);
-}
-
-void
-mpi_init_sge(struct mps_command *cm, void *req, void *sge)
-{
- int off, space;
-
- space = (int)cm->cm_sc->facts->IOCRequestFrameSize * 4;
- off = (uintptr_t)sge - (uintptr_t)req;
-
- KASSERT(off < space, ("bad pointers %p %p, off %d, space %d",
- req, sge, off, space));
-
- cm->cm_sge = sge;
- cm->cm_sglsize = space - off;
-}
-
-/*
- * Prepare the mps_command for an IOC_FACTS request.
- */
-static int
-mpi_pre_ioc_facts(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_IOC_FACTS_REQUEST *req = (void *)cm->cm_req;
- MPI2_IOC_FACTS_REPLY *rpl;
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- cm->cm_sge = NULL;
- cm->cm_sglsize = 0;
- return (0);
-}
-
-/*
- * Prepare the mps_command for a PORT_FACTS request.
- */
-static int
-mpi_pre_port_facts(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_PORT_FACTS_REQUEST *req = (void *)cm->cm_req;
- MPI2_PORT_FACTS_REPLY *rpl;
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- cm->cm_sge = NULL;
- cm->cm_sglsize = 0;
- return (0);
-}
-
-/*
- * Prepare the mps_command for a FW_DOWNLOAD request.
- */
-static int
-mpi_pre_fw_download(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_FW_DOWNLOAD_REQUEST *req = (void *)cm->cm_req;
- MPI2_FW_DOWNLOAD_REPLY *rpl;
- MPI2_FW_DOWNLOAD_TCSGE tc;
- int error;
-
- /*
- * This code assumes there is room in the request's SGL for
- * the TransactionContext plus at least a SGL chain element.
- */
- CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- if (cmd->len == 0)
- return (EINVAL);
-
- error = copyin(cmd->buf, cm->cm_data, cmd->len);
- if (error != 0)
- return (error);
-
- mpi_init_sge(cm, req, &req->SGL);
- bzero(&tc, sizeof tc);
-
- /*
- * For now, the F/W image must be provided in a single request.
- */
- if ((req->MsgFlags & MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT) == 0)
- return (EINVAL);
- if (req->TotalImageSize != cmd->len)
- return (EINVAL);
-
- /*
- * The value of the first two elements is specified in the
- * Fusion-MPT Message Passing Interface document.
- */
- tc.ContextSize = 0;
- tc.DetailsLength = 12;
- tc.ImageOffset = 0;
- tc.ImageSize = cmd->len;
-
- cm->cm_flags |= MPS_CM_FLAGS_DATAOUT;
-
- return (mps_push_sge(cm, &tc, sizeof tc, 0));
-}
-
-/*
- * Prepare the mps_command for a FW_UPLOAD request.
- */
-static int
-mpi_pre_fw_upload(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_FW_UPLOAD_REQUEST *req = (void *)cm->cm_req;
- MPI2_FW_UPLOAD_REPLY *rpl;
- MPI2_FW_UPLOAD_TCSGE tc;
-
- /*
- * This code assumes there is room in the request's SGL for
- * the TransactionContext plus at least a SGL chain element.
- */
- CTASSERT(sizeof req->SGL >= sizeof tc + MPS_SGC_SIZE);
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- mpi_init_sge(cm, req, &req->SGL);
- if (cmd->len == 0) {
- /* Perhaps just asking what the size of the fw is? */
- return (0);
- }
-
- bzero(&tc, sizeof tc);
-
- /*
- * The value of the first two elements is specified in the
- * Fusion-MPT Message Passing Interface document.
- */
- tc.ContextSize = 0;
- tc.DetailsLength = 12;
- /*
- * XXX Is there any reason to fetch a partial image? I.e. to
- * set ImageOffset to something other than 0?
- */
- tc.ImageOffset = 0;
- tc.ImageSize = cmd->len;
-
- return (mps_push_sge(cm, &tc, sizeof tc, 0));
-}
-
-/*
- * Prepare the mps_command for a SATA_PASSTHROUGH request.
- */
-static int
-mpi_pre_sata_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_SATA_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
- MPI2_SATA_PASSTHROUGH_REPLY *rpl;
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- mpi_init_sge(cm, req, &req->SGL);
- return (0);
-}
-
-/*
- * Prepare the mps_command for a SMP_PASSTHROUGH request.
- */
-static int
-mpi_pre_smp_passthrough(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_SMP_PASSTHROUGH_REQUEST *req = (void *)cm->cm_req;
- MPI2_SMP_PASSTHROUGH_REPLY *rpl;
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- mpi_init_sge(cm, req, &req->SGL);
- return (0);
-}
-
-/*
- * Prepare the mps_command for a CONFIG request.
- */
-static int
-mpi_pre_config(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_CONFIG_REQUEST *req = (void *)cm->cm_req;
- MPI2_CONFIG_REPLY *rpl;
-
- if (cmd->req_len != sizeof *req)
- return (EINVAL);
- if (cmd->rpl_len != sizeof *rpl)
- return (EINVAL);
-
- mpi_init_sge(cm, req, &req->PageBufferSGE);
- return (0);
-}
-
-/*
- * Prepare the mps_command for a SAS_IO_UNIT_CONTROL request.
- */
-static int
-mpi_pre_sas_io_unit_control(struct mps_command *cm,
- struct mps_usr_command *cmd)
-{
-
- cm->cm_sge = NULL;
- cm->cm_sglsize = 0;
- return (0);
-}
-
-/*
- * A set of functions to prepare an mps_command for the various
- * supported requests.
- */
-struct mps_user_func {
- U8 Function;
- mps_user_f *f_pre;
-} mps_user_func_list[] = {
- { MPI2_FUNCTION_IOC_FACTS, mpi_pre_ioc_facts },
- { MPI2_FUNCTION_PORT_FACTS, mpi_pre_port_facts },
- { MPI2_FUNCTION_FW_DOWNLOAD, mpi_pre_fw_download },
- { MPI2_FUNCTION_FW_UPLOAD, mpi_pre_fw_upload },
- { MPI2_FUNCTION_SATA_PASSTHROUGH, mpi_pre_sata_passthrough },
- { MPI2_FUNCTION_SMP_PASSTHROUGH, mpi_pre_smp_passthrough},
- { MPI2_FUNCTION_CONFIG, mpi_pre_config},
- { MPI2_FUNCTION_SAS_IO_UNIT_CONTROL, mpi_pre_sas_io_unit_control },
- { 0xFF, NULL } /* list end */
-};
-
-static int
-mps_user_setup_request(struct mps_command *cm, struct mps_usr_command *cmd)
-{
- MPI2_REQUEST_HEADER *hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
- struct mps_user_func *f;
-
- for (f = mps_user_func_list; f->f_pre != NULL; f++) {
- if (hdr->Function == f->Function)
- return (f->f_pre(cm, cmd));
- }
- return (EINVAL);
-}
-
-static int
-mps_user_command(struct mps_softc *sc, struct mps_usr_command *cmd)
-{
- MPI2_REQUEST_HEADER *hdr;
- MPI2_DEFAULT_REPLY *rpl;
- void *buf = NULL;
- struct mps_command *cm = NULL;
- int err = 0;
- int sz;
-
- mps_lock(sc);
- cm = mps_alloc_command(sc);
-
- if (cm == NULL) {
- mps_printf(sc, "mps_user_command: no mps requests\n");
- err = ENOMEM;
- goto Ret;
- }
- mps_unlock(sc);
-
- hdr = (MPI2_REQUEST_HEADER *)cm->cm_req;
-
- mps_dprint(sc, MPS_INFO, "mps_user_command: req %p %d rpl %p %d\n",
- cmd->req, cmd->req_len, cmd->rpl, cmd->rpl_len );
-
- if (cmd->req_len > (int)sc->facts->IOCRequestFrameSize * 4) {
- err = EINVAL;
- goto RetFreeUnlocked;
- }
- err = copyin(cmd->req, hdr, cmd->req_len);
- if (err != 0)
- goto RetFreeUnlocked;
-
- mps_dprint(sc, MPS_INFO, "mps_user_command: Function %02X "
- "MsgFlags %02X\n", hdr->Function, hdr->MsgFlags );
-
- err = mps_user_setup_request(cm, cmd);
- if (err != 0) {
- mps_printf(sc, "mps_user_command: unsupported function 0x%X\n",
- hdr->Function );
- goto RetFreeUnlocked;
- }
-
- if (cmd->len > 0) {
- buf = kmalloc(cmd->len, M_MPSUSER, M_WAITOK|M_ZERO);
- cm->cm_data = buf;
- cm->cm_length = cmd->len;
- } else {
- cm->cm_data = NULL;
- cm->cm_length = 0;
- }
-
- cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_WAKEUP;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
-
- mps_lock(sc);
- err = mps_map_command(sc, cm);
-
- if (err != 0 && err != EINPROGRESS) {
- mps_printf(sc, "%s: invalid request: error %d\n",
- __func__, err);
- goto Ret;
- }
- lksleep(cm, &sc->mps_lock, 0, "mpsuser", 0);
-
- rpl = (MPI2_DEFAULT_REPLY *)cm->cm_reply;
- sz = rpl->MsgLength * 4;
-
- if (sz > cmd->rpl_len) {
- mps_printf(sc,
- "mps_user_command: reply buffer too small %d required %d\n",
- cmd->rpl_len, sz );
- err = EINVAL;
- sz = cmd->rpl_len;
- }
-
- mps_unlock(sc);
- copyout(rpl, cmd->rpl, sz);
- if (buf != NULL)
- copyout(buf, cmd->buf, cmd->len);
- mps_dprint(sc, MPS_INFO, "mps_user_command: reply size %d\n", sz );
-
-RetFreeUnlocked:
- mps_lock(sc);
- if (cm != NULL)
- mps_free_command(sc, cm);
-Ret:
- mps_unlock(sc);
- if (buf != NULL)
- kfree(buf, M_MPSUSER);
- return (err);
-}
-
-static int
-mps_ioctl(struct cdev *dev, u_long cmd, void *arg, int flag)
-{
- struct mps_softc *sc;
- struct mps_cfg_page_req *page_req;
- struct mps_ext_cfg_page_req *ext_page_req;
- void *mps_page;
- int error;
-
- mps_page = NULL;
- sc = dev->si_drv1;
- page_req = (void *)arg;
- ext_page_req = (void *)arg;
-
- switch (cmd) {
- case MPSIO_READ_CFG_HEADER:
- mps_lock(sc);
- error = mps_user_read_cfg_header(sc, page_req);
- mps_unlock(sc);
- break;
- case MPSIO_READ_CFG_PAGE:
- mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK | M_ZERO);
- error = copyin(page_req->buf, mps_page,
- sizeof(MPI2_CONFIG_PAGE_HEADER));
- if (error)
- break;
- mps_lock(sc);
- error = mps_user_read_cfg_page(sc, page_req, mps_page);
- mps_unlock(sc);
- if (error)
- break;
- error = copyout(mps_page, page_req->buf, page_req->len);
- break;
- case MPSIO_READ_EXT_CFG_HEADER:
- mps_lock(sc);
- error = mps_user_read_extcfg_header(sc, ext_page_req);
- mps_unlock(sc);
- break;
- case MPSIO_READ_EXT_CFG_PAGE:
- mps_page = kmalloc(ext_page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
- error = copyin(ext_page_req->buf, mps_page,
- sizeof(MPI2_CONFIG_EXTENDED_PAGE_HEADER));
- if (error)
- break;
- mps_lock(sc);
- error = mps_user_read_extcfg_page(sc, ext_page_req, mps_page);
- mps_unlock(sc);
- if (error)
- break;
- error = copyout(mps_page, ext_page_req->buf, ext_page_req->len);
- break;
- case MPSIO_WRITE_CFG_PAGE:
- mps_page = kmalloc(page_req->len, M_MPSUSER, M_WAITOK|M_ZERO);
- error = copyin(page_req->buf, mps_page, page_req->len);
- if (error)
- break;
- mps_lock(sc);
- error = mps_user_write_cfg_page(sc, page_req, mps_page);
- mps_unlock(sc);
- break;
- case MPSIO_MPS_COMMAND:
- error = mps_user_command(sc, (struct mps_usr_command *)arg);
- break;
- default:
- error = ENOIOCTL;
- break;
- }
-
- if (mps_page != NULL)
- kfree(mps_page, M_MPSUSER);
-
- return (error);
-}
-
-#ifdef COMPAT_FREEBSD32
-
-/* Macros from compat/freebsd32/freebsd32.h */
-#define PTRIN(v) (void *)(uintptr_t)(v)
-#define PTROUT(v) (uint32_t)(uintptr_t)(v)
-
-#define CP(src,dst,fld) do { (dst).fld = (src).fld; } while (0)
-#define PTRIN_CP(src,dst,fld) \
- do { (dst).fld = PTRIN((src).fld); } while (0)
-#define PTROUT_CP(src,dst,fld) \
- do { (dst).fld = PTROUT((src).fld); } while (0)
-
-struct mps_cfg_page_req32 {
- MPI2_CONFIG_PAGE_HEADER header;
- uint32_t page_address;
- uint32_t buf;
- int len;
- uint16_t ioc_status;
-};
-
-struct mps_ext_cfg_page_req32 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
- uint32_t page_address;
- uint32_t buf;
- int len;
- uint16_t ioc_status;
-};
-
-struct mps_raid_action32 {
- uint8_t action;
- uint8_t volume_bus;
- uint8_t volume_id;
- uint8_t phys_disk_num;
- uint32_t action_data_word;
- uint32_t buf;
- int len;
- uint32_t volume_status;
- uint32_t action_data[4];
- uint16_t action_status;
- uint16_t ioc_status;
- uint8_t write;
-};
-
-struct mps_usr_command32 {
- uint32_t req;
- uint32_t req_len;
- uint32_t rpl;
- uint32_t rpl_len;
- uint32_t buf;
- int len;
- uint32_t flags;
-};
-
-#define MPSIO_READ_CFG_HEADER32 _IOWR('M', 200, struct mps_cfg_page_req32)
-#define MPSIO_READ_CFG_PAGE32 _IOWR('M', 201, struct mps_cfg_page_req32)
-#define MPSIO_READ_EXT_CFG_HEADER32 _IOWR('M', 202, struct mps_ext_cfg_page_req32)
-#define MPSIO_READ_EXT_CFG_PAGE32 _IOWR('M', 203, struct mps_ext_cfg_page_req32)
-#define MPSIO_WRITE_CFG_PAGE32 _IOWR('M', 204, struct mps_cfg_page_req32)
-#define MPSIO_RAID_ACTION32 _IOWR('M', 205, struct mps_raid_action32)
-#define MPSIO_MPS_COMMAND32 _IOWR('M', 210, struct mps_usr_command32)
-
-static int
-mps_ioctl32(struct cdev *dev, u_long cmd32, void *_arg, int flag,
- struct thread *td)
-{
- struct mps_cfg_page_req32 *page32 = _arg;
- struct mps_ext_cfg_page_req32 *ext32 = _arg;
- struct mps_raid_action32 *raid32 = _arg;
- struct mps_usr_command32 *user32 = _arg;
- union {
- struct mps_cfg_page_req page;
- struct mps_ext_cfg_page_req ext;
- struct mps_raid_action raid;
- struct mps_usr_command user;
- } arg;
- u_long cmd;
- int error;
-
- switch (cmd32) {
- case MPSIO_READ_CFG_HEADER32:
- case MPSIO_READ_CFG_PAGE32:
- case MPSIO_WRITE_CFG_PAGE32:
- if (cmd32 == MPSIO_READ_CFG_HEADER32)
- cmd = MPSIO_READ_CFG_HEADER;
- else if (cmd32 == MPSIO_READ_CFG_PAGE32)
- cmd = MPSIO_READ_CFG_PAGE;
- else
- cmd = MPSIO_WRITE_CFG_PAGE;
- CP(*page32, arg.page, header);
- CP(*page32, arg.page, page_address);
- PTRIN_CP(*page32, arg.page, buf);
- CP(*page32, arg.page, len);
- CP(*page32, arg.page, ioc_status);
- break;
-
- case MPSIO_READ_EXT_CFG_HEADER32:
- case MPSIO_READ_EXT_CFG_PAGE32:
- if (cmd32 == MPSIO_READ_EXT_CFG_HEADER32)
- cmd = MPSIO_READ_EXT_CFG_HEADER;
- else
- cmd = MPSIO_READ_EXT_CFG_PAGE;
- CP(*ext32, arg.ext, header);
- CP(*ext32, arg.ext, page_address);
- PTRIN_CP(*ext32, arg.ext, buf);
- CP(*ext32, arg.ext, len);
- CP(*ext32, arg.ext, ioc_status);
- break;
-
- case MPSIO_RAID_ACTION32:
- cmd = MPSIO_RAID_ACTION;
- CP(*raid32, arg.raid, action);
- CP(*raid32, arg.raid, volume_bus);
- CP(*raid32, arg.raid, volume_id);
- CP(*raid32, arg.raid, phys_disk_num);
- CP(*raid32, arg.raid, action_data_word);
- PTRIN_CP(*raid32, arg.raid, buf);
- CP(*raid32, arg.raid, len);
- CP(*raid32, arg.raid, volume_status);
- bcopy(raid32->action_data, arg.raid.action_data,
- sizeof arg.raid.action_data);
- CP(*raid32, arg.raid, ioc_status);
- CP(*raid32, arg.raid, write);
- break;
-
- case MPSIO_MPS_COMMAND32:
- cmd = MPSIO_MPS_COMMAND;
- PTRIN_CP(*user32, arg.user, req);
- CP(*user32, arg.user, req_len);
- PTRIN_CP(*user32, arg.user, rpl);
- CP(*user32, arg.user, rpl_len);
- PTRIN_CP(*user32, arg.user, buf);
- CP(*user32, arg.user, len);
- CP(*user32, arg.user, flags);
- break;
- default:
- return (ENOIOCTL);
- }
-
- error = mps_ioctl(dev, cmd, &arg, flag, td);
- if (error == 0 && (cmd32 & IOC_OUT) != 0) {
- switch (cmd32) {
- case MPSIO_READ_CFG_HEADER32:
- case MPSIO_READ_CFG_PAGE32:
- case MPSIO_WRITE_CFG_PAGE32:
- CP(arg.page, *page32, header);
- CP(arg.page, *page32, page_address);
- PTROUT_CP(arg.page, *page32, buf);
- CP(arg.page, *page32, len);
- CP(arg.page, *page32, ioc_status);
- break;
-
- case MPSIO_READ_EXT_CFG_HEADER32:
- case MPSIO_READ_EXT_CFG_PAGE32:
- CP(arg.ext, *ext32, header);
- CP(arg.ext, *ext32, page_address);
- PTROUT_CP(arg.ext, *ext32, buf);
- CP(arg.ext, *ext32, len);
- CP(arg.ext, *ext32, ioc_status);
- break;
-
- case MPSIO_RAID_ACTION32:
- CP(arg.raid, *raid32, action);
- CP(arg.raid, *raid32, volume_bus);
- CP(arg.raid, *raid32, volume_id);
- CP(arg.raid, *raid32, phys_disk_num);
- CP(arg.raid, *raid32, action_data_word);
- PTROUT_CP(arg.raid, *raid32, buf);
- CP(arg.raid, *raid32, len);
- CP(arg.raid, *raid32, volume_status);
- bcopy(arg.raid.action_data, raid32->action_data,
- sizeof arg.raid.action_data);
- CP(arg.raid, *raid32, ioc_status);
- CP(arg.raid, *raid32, write);
- break;
-
- case MPSIO_MPS_COMMAND32:
- PTROUT_CP(arg.user, *user32, req);
- CP(arg.user, *user32, req_len);
- PTROUT_CP(arg.user, *user32, rpl);
- CP(arg.user, *user32, rpl_len);
- PTROUT_CP(arg.user, *user32, buf);
- CP(arg.user, *user32, len);
- CP(arg.user, *user32, flags);
- break;
- }
- }
-
- return (error);
-}
-#endif /* COMPAT_FREEBSD32 */
-
-static int
-mps_ioctl_devsw(struct dev_ioctl_args *ap)
-{
- cdev_t dev = ap->a_head.a_dev;
- u_long com = ap->a_cmd;
- caddr_t arg = ap->a_data;
- int flag = ap->a_fflag;
-
-#ifdef COMPAT_FREEBSD32
- if (SV_CURPROC_FLAG(SV_ILP32))
- return (mps_ioctl32(dev, com, arg, flag, td));
-#endif
- return (mps_ioctl(dev, com, arg, flag));
-}
+++ /dev/null
-/*-
- * Copyright (c) 2009 Yahoo! Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/dev/mps/mpsvar.h,v 1.5 2010/12/10 21:45:10 ken Exp $
- */
-
-#ifndef _MPSVAR_H
-#define _MPSVAR_H
-
-#define MPS_DB_MAX_WAIT 2500
-
-#define MPS_REQ_FRAMES 1024
-#define MPS_EVT_REPLY_FRAMES 32
-#define MPS_REPLY_FRAMES MPS_REQ_FRAMES
-#define MPS_CHAIN_FRAMES 1024
-#define MPS_SENSE_LEN SSD_FULL_SIZE
-#define MPS_MSI_COUNT 1
-#define MPS_SGE64_SIZE 12
-#define MPS_SGE32_SIZE 8
-#define MPS_SGC_SIZE 8
-
-#define MPS_PERIODIC_DELAY 1 /* 1 second heartbeat/watchdog check */
-
-struct mps_softc;
-struct mps_command;
-struct mpssas_softc;
-struct mpssas_target;
-
-MALLOC_DECLARE(M_MPT2);
-
-typedef void mps_evt_callback_t(struct mps_softc *, uintptr_t,
- MPI2_EVENT_NOTIFICATION_REPLY *reply);
-typedef void mps_command_callback_t(struct mps_softc *, struct mps_command *cm);
-
-struct mps_chain {
- TAILQ_ENTRY(mps_chain) chain_link;
- MPI2_SGE_IO_UNION *chain;
- uint32_t chain_busaddr;
-};
-
-/*
- * This needs to be at least 2 to support SMP passthrough.
- */
-#define MPS_IOVEC_COUNT 2
-
-struct mps_command {
- TAILQ_ENTRY(mps_command) cm_link;
- struct mps_softc *cm_sc;
- void *cm_data;
- u_int cm_length;
- struct uio cm_uio;
- struct iovec cm_iovec[MPS_IOVEC_COUNT];
- u_int cm_max_segs;
- u_int cm_sglsize;
- MPI2_SGE_IO_UNION *cm_sge;
- uint8_t *cm_req;
- uint8_t *cm_reply;
- uint32_t cm_reply_data;
- mps_command_callback_t *cm_complete;
- void *cm_complete_data;
- struct mpssas_target *cm_targ;
- MPI2_REQUEST_DESCRIPTOR_UNION cm_desc;
- u_int cm_flags;
-#define MPS_CM_FLAGS_POLLED (1 << 0)
-#define MPS_CM_FLAGS_COMPLETE (1 << 1)
-#define MPS_CM_FLAGS_SGE_SIMPLE (1 << 2)
-#define MPS_CM_FLAGS_DATAOUT (1 << 3)
-#define MPS_CM_FLAGS_DATAIN (1 << 4)
-#define MPS_CM_FLAGS_WAKEUP (1 << 5)
-#define MPS_CM_FLAGS_ACTIVE (1 << 6)
-#define MPS_CM_FLAGS_USE_UIO (1 << 7)
-#define MPS_CM_FLAGS_SMP_PASS (1 << 8)
- u_int cm_state;
-#define MPS_CM_STATE_FREE 0
-#define MPS_CM_STATE_BUSY 1
-#define MPS_CM_STATE_TIMEDOUT 2
- bus_dmamap_t cm_dmamap;
- struct scsi_sense_data *cm_sense;
- TAILQ_HEAD(, mps_chain) cm_chain_list;
- uint32_t cm_req_busaddr;
- uint32_t cm_sense_busaddr;
- struct callout cm_callout;
-};
-
-struct mps_event_handle {
- TAILQ_ENTRY(mps_event_handle) eh_list;
- mps_evt_callback_t *callback;
- void *data;
- uint8_t mask[16];
-};
-
-struct mps_softc {
- device_t mps_dev;
- struct cdev *mps_cdev;
- u_int mps_flags;
-#define MPS_FLAGS_INTX (1 << 0)
-#define MPS_FLAGS_MSI (1 << 1)
-#define MPS_FLAGS_BUSY (1 << 2)
-#define MPS_FLAGS_SHUTDOWN (1 << 3)
- u_int mps_debug;
- u_int allow_multiple_tm_cmds;
- int tm_cmds_active;
- struct sysctl_ctx_list sysctl_ctx;
- struct sysctl_oid *sysctl_tree;
- struct mps_command *commands;
- struct mps_chain *chains;
- struct callout periodic;
-
- struct mpssas_softc *sassc;
-
- TAILQ_HEAD(, mps_command) req_list;
- TAILQ_HEAD(, mps_chain) chain_list;
- TAILQ_HEAD(, mps_command) tm_list;
- int replypostindex;
- int replyfreeindex;
-
- struct resource *mps_regs_resource;
- bus_space_handle_t mps_bhandle;
- bus_space_tag_t mps_btag;
- int mps_regs_rid;
-
- bus_dma_tag_t mps_parent_dmat;
- bus_dma_tag_t buffer_dmat;
-
- MPI2_IOC_FACTS_REPLY *facts;
- MPI2_PORT_FACTS_REPLY *pfacts;
- int num_reqs;
- int num_replies;
- int fqdepth; /* Free queue */
- int pqdepth; /* Post queue */
-
- uint8_t event_mask[16];
- TAILQ_HEAD(, mps_event_handle) event_list;
- struct mps_event_handle *mps_log_eh;
-
- struct lock mps_lock;
- struct intr_config_hook mps_ich;
- struct resource *mps_irq[MPS_MSI_COUNT];
- void *mps_intrhand[MPS_MSI_COUNT];
- int mps_irq_rid[MPS_MSI_COUNT];
-
- uint8_t *req_frames;
- bus_addr_t req_busaddr;
- bus_dma_tag_t req_dmat;
- bus_dmamap_t req_map;
-
- uint8_t *reply_frames;
- bus_addr_t reply_busaddr;
- bus_dma_tag_t reply_dmat;
- bus_dmamap_t reply_map;
-
- struct scsi_sense_data *sense_frames;
- bus_addr_t sense_busaddr;
- bus_dma_tag_t sense_dmat;
- bus_dmamap_t sense_map;
-
- uint8_t *chain_frames;
- bus_addr_t chain_busaddr;
- bus_dma_tag_t chain_dmat;
- bus_dmamap_t chain_map;
-
- MPI2_REPLY_DESCRIPTORS_UNION *post_queue;
- bus_addr_t post_busaddr;
- uint32_t *free_queue;
- bus_addr_t free_busaddr;
- bus_dma_tag_t queues_dmat;
- bus_dmamap_t queues_map;
-};
-
-struct mps_config_params {
- MPI2_CONFIG_EXT_PAGE_HEADER_UNION hdr;
- u_int action;
- u_int page_address; /* Attributes, not a phys address */
- u_int status;
- void *buffer;
- u_int length;
- int timeout;
- void (*callback)(struct mps_softc *, struct mps_config_params *);
- void *cbdata;
-};
-
-static __inline uint32_t
-mps_regread(struct mps_softc *sc, uint32_t offset)
-{
- return (bus_space_read_4(sc->mps_btag, sc->mps_bhandle, offset));
-}
-
-static __inline void
-mps_regwrite(struct mps_softc *sc, uint32_t offset, uint32_t val)
-{
- bus_space_write_4(sc->mps_btag, sc->mps_bhandle, offset, val);
-}
-
-static __inline void
-mps_free_reply(struct mps_softc *sc, uint32_t busaddr)
-{
-
- if (++sc->replyfreeindex >= sc->fqdepth)
- sc->replyfreeindex = 0;
- sc->free_queue[sc->replyfreeindex] = busaddr;
- mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
-}
-
-static __inline struct mps_chain *
-mps_alloc_chain(struct mps_softc *sc)
-{
- struct mps_chain *chain;
-
- if ((chain = TAILQ_FIRST(&sc->chain_list)) != NULL)
- TAILQ_REMOVE(&sc->chain_list, chain, chain_link);
- return (chain);
-}
-
-static __inline void
-mps_free_chain(struct mps_softc *sc, struct mps_chain *chain)
-{
-#if 0
- bzero(chain->chain, 128);
-#endif
- TAILQ_INSERT_TAIL(&sc->chain_list, chain, chain_link);
-}
-
-static __inline void
-mps_free_command(struct mps_softc *sc, struct mps_command *cm)
-{
- struct mps_chain *chain, *chain_temp;
-
- if (cm->cm_reply != NULL) {
- mps_free_reply(sc, cm->cm_reply_data);
- cm->cm_reply = NULL;
- }
- cm->cm_flags = 0;
- cm->cm_complete = NULL;
- cm->cm_complete_data = NULL;
- cm->cm_targ = 0;
- cm->cm_max_segs = 0;
- cm->cm_state = MPS_CM_STATE_FREE;
- TAILQ_FOREACH_MUTABLE(chain, &cm->cm_chain_list, chain_link, chain_temp) {
- TAILQ_REMOVE(&cm->cm_chain_list, chain, chain_link);
- mps_free_chain(sc, chain);
- }
- TAILQ_INSERT_TAIL(&sc->req_list, cm, cm_link);
-}
-
-static __inline struct mps_command *
-mps_alloc_command(struct mps_softc *sc)
-{
- struct mps_command *cm;
-
- cm = TAILQ_FIRST(&sc->req_list);
- if (cm == NULL)
- return (NULL);
-
- TAILQ_REMOVE(&sc->req_list, cm, cm_link);
- KASSERT(cm->cm_state == MPS_CM_STATE_FREE, ("mps: Allocating busy command\n"));
- cm->cm_state = MPS_CM_STATE_BUSY;
- return (cm);
-}
-
-static __inline void
-mps_lock(struct mps_softc *sc)
-{
- lockmgr(&sc->mps_lock, LK_EXCLUSIVE);
-}
-
-static __inline void
-mps_unlock(struct mps_softc *sc)
-{
- lockmgr(&sc->mps_lock, LK_RELEASE);
-}
-
-#define MPS_INFO (1 << 0)
-#define MPS_TRACE (1 << 1)
-#define MPS_FAULT (1 << 2)
-#define MPS_EVENT (1 << 3)
-#define MPS_LOG (1 << 4)
-
-#define mps_printf(sc, args...) \
- device_printf((sc)->mps_dev, ##args)
-
-#define mps_dprint(sc, level, msg, args...) \
-do { \
- if (sc->mps_debug & level) \
- device_printf(sc->mps_dev, msg, ##args); \
-} while (0)
-
-#define mps_dprint_field(sc, level, msg, args...) \
-do { \
- if (sc->mps_debug & level) \
- kprintf("\t" msg, ##args); \
-} while (0)
-
-#define MPS_PRINTFIELD_START(sc, tag...) \
- mps_dprint((sc), MPS_INFO, ##tag); \
- mps_dprint_field((sc), MPS_INFO, ":\n")
-#define MPS_PRINTFIELD_END(sc, tag) \
- mps_dprint((sc), MPS_INFO, tag "\n")
-#define MPS_PRINTFIELD(sc, facts, attr, fmt) \
- mps_dprint_field((sc), MPS_INFO, #attr ": " #fmt "\n", (facts)->attr)
-
-#define MPS_EVENTFIELD_START(sc, tag...) \
- mps_dprint((sc), MPS_EVENT, ##tag); \
- mps_dprint_field((sc), MPS_EVENT, ":\n")
-#define MPS_EVENTFIELD(sc, facts, attr, fmt) \
- mps_dprint_field((sc), MPS_EVENT, #attr ": " #fmt "\n", (facts)->attr)
-
-static __inline void
-mps_from_u64(uint64_t data, U64 *mps)
-{
- (mps)->High = (uint32_t)((data) >> 32);
- (mps)->Low = (uint32_t)((data) & 0xffffffff);
-}
-
-static __inline uint64_t
-mps_to_u64(U64 *data)
-{
-
- return (((uint64_t)data->High << 32) | data->Low);
-}
-
-static __inline void
-mps_mask_intr(struct mps_softc *sc)
-{
- uint32_t mask;
-
- mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
- mask |= MPI2_HIM_REPLY_INT_MASK;
- mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
-}
-
-static __inline void
-mps_unmask_intr(struct mps_softc *sc)
-{
- uint32_t mask;
-
- mask = mps_regread(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET);
- mask &= ~MPI2_HIM_REPLY_INT_MASK;
- mps_regwrite(sc, MPI2_HOST_INTERRUPT_MASK_OFFSET, mask);
-}
-
-int mps_pci_setup_interrupts(struct mps_softc *);
-int mps_attach(struct mps_softc *sc);
-int mps_free(struct mps_softc *sc);
-void mps_intr(void *);
-void mps_intr_msi(void *);
-void mps_intr_locked(void *);
-int mps_register_events(struct mps_softc *, uint8_t *, mps_evt_callback_t *,
- void *, struct mps_event_handle **);
-int mps_update_events(struct mps_softc *, struct mps_event_handle *, uint8_t *);
-int mps_deregister_events(struct mps_softc *, struct mps_event_handle *);
-int mps_request_polled(struct mps_softc *sc, struct mps_command *cm);
-void mps_enqueue_request(struct mps_softc *, struct mps_command *);
-int mps_push_sge(struct mps_command *, void *, size_t, int);
-int mps_add_dmaseg(struct mps_command *, vm_paddr_t, size_t, u_int, int);
-int mps_attach_sas(struct mps_softc *sc);
-int mps_detach_sas(struct mps_softc *sc);
-int mps_map_command(struct mps_softc *sc, struct mps_command *cm);
-int mps_read_config_page(struct mps_softc *, struct mps_config_params *);
-int mps_write_config_page(struct mps_softc *, struct mps_config_params *);
-void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int );
-void mpi_init_sge(struct mps_command *cm, void *req, void *sge);
-int mps_attach_user(struct mps_softc *);
-void mps_detach_user(struct mps_softc *);
-
-SYSCTL_DECL(_hw_mps);
-
-#endif
SUBDIR= aac amr arcmsr asr ciss hptiop hptmv \
- iir ips mfi mlx mly pst twa twe tws vinum
+ iir ips mfi mlx mly mps pst twa twe tws vinum
.include <bsd.subdir.mk>
--- /dev/null
+# $FreeBSD: src/sys/modules/mps/Makefile,v 1.4 2012/01/26 18:17:21 ken Exp $
+
+.PATH: ${.CURDIR}/../../dev/mps
+
+KMOD= mps
+SRCS= mps_pci.c mps.c mps_sas.c mps_table.c mps_user.c
+SRCS+= mps_config.c mps_mapping.c mps_sas_lsi.c
+SRCS+= opt_cam.h opt_compat.h
+SRCS+= device_if.h bus_if.h pci_if.h
+
+#CFLAGS += -DMPS_DEBUG
+DEBUG_FLAGS += -g
+
+.include <bsd.kmod.mk>
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2009 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2.h
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.14
+ * mpi2.h Version: 02.00.18
*
* Version History
* ---------------
* Added MSI-x index mask and shift for Reply Post Host
* Index register.
* Added function code for Host Based Discovery Action.
+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ * Added defines for product-specific range of message
+ * function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
* --------------------------------------------------------------------------
*/
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0E)
+#define MPI2_HEADER_VERSION_UNIT (0x12)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
/*****************************************************************************
*
* Message Functions
-* 0x80 -> 0x8F reserved for private message use per product
-*
*
*****************************************************************************/
#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator */
#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) /* Host Based Discovery Action */
+#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) /* Power Management Control */
+#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) /* beginning of product-specific range */
+#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) /* end of product-specific range */
#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00)
#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04)
+#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
+#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
+
/* Address Size */
#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
/* Data Location Address Space */
#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03)
-#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
-#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
+#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) /* IEEE Simple Element only */
#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
-#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
-
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) /* IEEE Simple Element only */
+#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR (0x03) /* IEEE Chain Element only */
/****************************************************************************
* IEEE SGE operation Macros
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_cnfg.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_cnfg.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2009 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_cnfg.h
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.13
+ * mpi2_cnfg.h Version: 02.00.17
*
* Version History
* ---------------
* Added Ethernet configuration pages.
* 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
* Added SAS PHY Page 4 structure and defines.
+ * 02-10-10 02.00.14 Modified the comments for the configuration page
+ * structures that contain an array of data. The host
+ * should use the "count" field in the page data (e.g. the
+ * NumPhys field) to determine the number of valid elements
+ * in the array.
+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added PowerManagementCapabilities to IO Unit Page 7.
+ * Added PortWidthModGroup field to
+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
+ * defines.
+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ * the Pinout field.
+ * Added BoardTemperature and BoardTemperatureUnits fields
+ * to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
* --------------------------------------------------------------------------
*/
#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17)
#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
+#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
/*****************************************************************************
#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Config Reply Message */
#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
+#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
+
#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2208_7 (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2208_8 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
+#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
+#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
+
+
/* Manufacturing Page 0 */
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1)
U32 Pinout; /* 0x00 */
U8 Connector[16]; /* 0x04 */
U8 Location; /* 0x14 */
- U8 Reserved1; /* 0x15 */
+ U8 ReceptacleID; /* 0x15 */
U16 Slot; /* 0x16 */
U32 Reserved2; /* 0x18 */
} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
/* defines for the Pinout field */
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100)
-#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x00000002)
-#define MPI2_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001)
+#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00)
+#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8)
+
+#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF)
+#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00)
+#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01)
+#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02)
+#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03)
+#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04)
+#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06)
+#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07)
+#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08)
+#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
+#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
+#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
/* defines for the Location field */
#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1)
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
-#define MPI2_MANUFACTURING7_PAGEVERSION (0x00)
+#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
/* defines for the Flags field */
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
/* IO Unit Page 1 Flags defines */
#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
+#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040)
#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004)
-#define MPI2_IOUNITPAGE1_MULTI_PATHING (0x00000002)
-#define MPI2_IOUNITPAGE1_SINGLE_PATHING (0x00000000)
/* IO Unit Page 3 */
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for GPIOCount at runtime.
*/
#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1)
/*
* Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumDmaEngines at runtime.
+ * one and check the value returned for NumDmaEngines at runtime.
*/
#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
U8 PCIeWidth; /* 0x06 */
U8 PCIeSpeed; /* 0x07 */
U32 ProcessorState; /* 0x08 */
- U32 Reserved2; /* 0x0C */
+ U32 PowerManagementCapabilities; /* 0x0C */
U16 IOCTemperature; /* 0x10 */
U8 IOCTemperatureUnits; /* 0x12 */
U8 IOCSpeed; /* 0x13 */
- U32 Reserved3; /* 0x14 */
+ U16 BoardTemperature; /* 0x14 */
+ U8 BoardTemperatureUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
-#define MPI2_IOUNITPAGE7_PAGEVERSION (0x00)
+#define MPI2_IOUNITPAGE7_PAGEVERSION (0x02)
/* defines for IO Unit Page 7 PCIeWidth field */
#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
+/* defines for IO Unit Page 7 PowerManagementCapabilities field */
+#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400)
+#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200)
+#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008)
+#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004)
+
/* defines for IO Unit Page 7 IOCTemperatureUnits field */
#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
+/* defines for IO Unit Page 7 BoardTemperatureUnits field */
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01)
+#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02)
+
/****************************************************************************
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
+ * one and check the value returned for NumPhysDisks at runtime.
*/
#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1)
#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000)
#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000)
#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000)
+#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080)
#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03)
#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04)
#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05)
+#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06)
#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
/* PhysDiskAttributes defines */
+#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
+
+#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength or NumPhysDiskPaths at runtime.
+ * one and check the value returned for NumPhysDiskPaths at runtime.
*/
#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1)
#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
+#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
#define MPI2_SAS_IOUNIT0_PHY_MAX (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
#define MPI2_SAS_IOUNIT1_PHY_MAX (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * four and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
#define MPI2_SAS_IOUNIT4_PHY_MAX (4)
typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS
{
U8 ControlFlags; /* 0x00 */
- U8 Reserved1; /* 0x01 */
+ U8 PortWidthModGroup; /* 0x01 */
U16 InactivityTimerExponent; /* 0x02 */
U8 SATAPartialTimeout; /* 0x04 */
U8 Reserved2; /* 0x05 */
#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
+/* defines for PortWidthModeGroup field */
+#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF)
+
/* defines for InactivityTimerExponent field */
#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumPhys at runtime.
*/
#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x00)
+#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01)
+
+
+/* SAS IO Unit Page 6 */
+
+typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+{
+ U8 CurrentStatus; /* 0x00 */
+ U8 CurrentModulation; /* 0x01 */
+ U8 CurrentUtilization; /* 0x02 */
+ U8 Reserved1; /* 0x03 */
+ U32 Reserved2; /* 0x04 */
+} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
+ Mpi2SasIOUnit6PortWidthModGroupStatus_t,
+ MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
+
+/* defines for CurrentStatus field */
+#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00)
+#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01)
+#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02)
+#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03)
+#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04)
+#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06)
+#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07)
+
+/* defines for CurrentModulation field */
+#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00)
+#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01)
+#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02)
+#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
+#define MPI2_SAS_IOUNIT6_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 Reserved2; /* 0x0C */
+ U8 NumGroups; /* 0x10 */
+ U8 Reserved3; /* 0x11 */
+ U16 Reserved4; /* 0x12 */
+ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
+ PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
+ Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
+
+#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 7 */
+
+typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+{
+ U8 Flags; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 Threshold75Pct; /* 0x04 */
+ U8 Threshold50Pct; /* 0x05 */
+ U8 Threshold25Pct; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
+ Mpi2SasIOUnit7PortWidthModGroupSettings_t,
+ MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
+
+/* defines for Flags field */
+#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01)
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check the value returned for NumGroups at runtime.
+ */
+#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
+#define MPI2_SAS_IOUNIT7_GROUP_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U8 SamplingInterval; /* 0x08 */
+ U8 WindowLength; /* 0x09 */
+ U16 Reserved1; /* 0x0A */
+ U32 Reserved2; /* 0x0C */
+ U32 Reserved3; /* 0x10 */
+ U8 NumGroups; /* 0x14 */
+ U8 Reserved4; /* 0x15 */
+ U16 Reserved5; /* 0x16 */
+ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
+ PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
+ Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
+
+#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00)
+
+
+/* SAS IO Unit Page 8 */
+
+typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U32 PowerManagementCapabilities; /* 0x0C */
+ U32 Reserved2; /* 0x10 */
+} MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
+ Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
+
+#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00)
+
+/* defines for PowerManagementCapabilities field */
+#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x000001000)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x000000800)
+#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x000000400)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x000000200)
+#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x000000100)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x000000010)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x000000008)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x000000004)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x000000002)
+#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x000000001)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ * one and check the value returned for NumPhyEvents at runtime.
*/
#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumLogEntries at runtime.
*/
#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
#define MPI2_LOG_0_NUM_LOG_ENTRIES (1)
/*
* Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.ExtPageLength or NumPhys at runtime.
+ * one and check the value returned for NumElements at runtime.
*/
#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1)
#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
+/****************************************************************************
+* Extended Manufacturing Config Pages
+****************************************************************************/
+
+/*
+ * Generic structure to use for product-specific extended manufacturing pages
+ * (currently Extended Manufacturing Page 40 through Extended Manufacturing
+ * Page 60).
+ */
+
+typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS
+{
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 ProductSpecificInfo; /* 0x08 */
+} MPI2_CONFIG_PAGE_EXT_MAN_PS,
+ MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
+ Mpi2ExtManufacturingPagePS_t, MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
+
+/* PageVersion should be provided by product-specific code */
+
#endif
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_hbd.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_hbd.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2009 LSI Corporation.
+ * Copyright (c) 2009-2011 LSI Corporation.
*
*
* Name: mpi2_hbd.h
* Title: MPI Host Based Discovery messages and structures
* Creation Date: October 21, 2009
*
- * mpi2_hbd.h Version: 02.00.00
+ * mpi2_hbd.h Version: 02.00.01
*
* Version History
* ---------------
* Date Version Description
* -------- -------- ------------------------------------------------------
* 10-28-09 02.00.00 Initial version.
+ * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from
+ * HBD Action request, replaced by AdditionalInfo field.
* --------------------------------------------------------------------------
*/
U8 Port; /* 0x25 */
U8 MaxConnections; /* 0x26 */
U8 MaxRate; /* 0x27 */
- U8 PortGroups; /* 0x28 */
- U8 DmaGroup; /* 0x29 */
- U8 ControlGroup; /* 0x2A */
- U8 Reserved6; /* 0x2B */
+ U32 AdditionalInfo; /* 0x28 */
U16 InitialAWT; /* 0x2C */
U16 Reserved7; /* 0x2E */
U32 Reserved8; /* 0x30 */
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_history.txt,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_history.txt,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
==============================
Fusion-MPT MPI 2.0 Header File Change History
==============================
- Copyright (c) 2000-2009 LSI Corporation.
+ Copyright (c) 2000-2011 LSI Corporation.
---------------------------------------
- Header Set Release Version: 02.00.14
- Header Set Release Date: 10-28-09
+ Header Set Release Version: 02.00.18
+ Header Set Release Date: 11-10-10
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi2.h 02.00.14 02.00.13
- mpi2_cnfg.h 02.00.13 02.00.12
- mpi2_init.h 02.00.08 02.00.07
- mpi2_ioc.h 02.00.13 02.00.12
- mpi2_raid.h 02.00.04 02.00.04
- mpi2_sas.h 02.00.03 02.00.02
- mpi2_targ.h 02.00.03 02.00.03
- mpi2_tool.h 02.00.04 02.00.04
+ mpi2.h 02.00.18 02.00.17
+ mpi2_cnfg.h 02.00.17 02.00.16
+ mpi2_init.h 02.00.11 02.00.10
+ mpi2_ioc.h 02.00.16 02.00.15
+ mpi2_raid.h 02.00.05 02.00.05
+ mpi2_sas.h 02.00.05 02.00.05
+ mpi2_targ.h 02.00.04 02.00.04
+ mpi2_tool.h 02.00.06 02.00.06
mpi2_type.h 02.00.00 02.00.00
mpi2_ra.h 02.00.00 02.00.00
- mpi2_hbd.h 02.00.00
- mpi2_history.txt 02.00.14 02.00.13
+ mpi2_hbd.h 02.00.01 02.00.01
+ mpi2_history.txt 02.00.18 02.00.17
* Date Version Description
* Added MSI-x index mask and shift for Reply Post Host
* Index register.
* Added function code for Host Based Discovery Action.
+ * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
+ * Added defines for product-specific range of message
+ * function codes, 0xF0 to 0xFF.
+ * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added alternative defines for the SGE Direction bit.
+ * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
* --------------------------------------------------------------------------
mpi2_cnfg.h
* Added Ethernet configuration pages.
* 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
* Added SAS PHY Page 4 structure and defines.
+ * 02-10-10 02.00.14 Modified the comments for the configuration page
+ * structures that contain an array of data. The host
+ * should use the "count" field in the page data (e.g. the
+ * NumPhys field) to determine the number of valid elements
+ * in the array.
+ * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
+ * Added PowerManagementCapabilities to IO Unit Page 7.
+ * Added PortWidthModGroup field to
+ * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
+ * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
+ * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
+ * define.
+ * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
+ * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
+ * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
+ * defines.
+ * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
+ * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
+ * the Pinout field.
+ * Added BoardTemperature and BoardTemperatureUnits fields
+ * to MPI2_CONFIG_PAGE_IO_UNIT_7.
+ * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
+ * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
* --------------------------------------------------------------------------
mpi2_init.h
* both SCSI IO Error Reply and SCSI Task Management Reply.
* Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
* Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
* --------------------------------------------------------------------------
mpi2_ioc.h
* (MPI2_FW_HEADER_PID_).
* Modified values for SAS ProductID Family
* (MPI2_FW_HEADER_PID_FAMILY_).
+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
+ * Added PowerManagementControl Request structures and
+ * defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
* --------------------------------------------------------------------------
mpi2_raid.h
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
mpi2_sas.h
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
* --------------------------------------------------------------------------
mpi2_targ.h
* MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
* Target Status Send Request only takes a single SGE for
* response data.
+ * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure.
* --------------------------------------------------------------------------
mpi2_tool.h
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
+ * Post Request.
* --------------------------------------------------------------------------
mpi2_type.h
mpi2_hbd.h
* 10-28-09 02.00.00 Initial version.
+ * 08-11-10 02.00.01 Removed PortGroups, DmaGroup, and ControlGroup from
+ * HBD Action request, replaced by AdditionalInfo field.
* --------------------------------------------------------------------------
mpi2_history.txt Parts list history
-Filename 02.00.14 02.00.13 02.00.12
----------- -------- -------- --------
-mpi2.h 02.00.14 02.00.13 02.00.12
-mpi2_cnfg.h 02.00.13 02.00.12 02.00.11
-mpi2_init.h 02.00.08 02.00.07 02.00.07
-mpi2_ioc.h 02.00.13 02.00.12 02.00.11
-mpi2_raid.h 02.00.04 02.00.04 02.00.03
-mpi2_sas.h 02.00.03 02.00.02 02.00.02
-mpi2_targ.h 02.00.03 02.00.03 02.00.03
-mpi2_tool.h 02.00.04 02.00.04 02.00.03
-mpi2_type.h 02.00.00 02.00.00 02.00.00
-mpi2_ra.h 02.00.00 02.00.00 02.00.00
-mpi2_hbd.h 02.00.00
+Filename 02.00.18
+---------- --------
+mpi2.h 02.00.18
+mpi2_cnfg.h 02.00.17
+mpi2_init.h 02.00.11
+mpi2_ioc.h 02.00.16
+mpi2_raid.h 02.00.05
+mpi2_sas.h 02.00.05
+mpi2_targ.h 02.00.04
+mpi2_tool.h 02.00.06
+mpi2_type.h 02.00.00
+mpi2_ra.h 02.00.00
+mpi2_hbd.h 02.00.01
+
+Filename 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.17 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12
+mpi2_cnfg.h 02.00.16 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11
+mpi2_init.h 02.00.10 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07
+mpi2_ioc.h 02.00.15 02.00.15 02.00.14 02.00.13 02.00.12 02.00.11
+mpi2_raid.h 02.00.05 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03
+mpi2_sas.h 02.00.05 02.00.04 02.00.03 02.00.03 02.00.02 02.00.02
+mpi2_targ.h 02.00.04 02.00.04 02.00.04 02.00.03 02.00.03 02.00.03
+mpi2_tool.h 02.00.06 02.00.05 02.00.04 02.00.04 02.00.04 02.00.03
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ra.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_hbd.h 02.00.01 02.00.00 02.00.00 02.00.00
Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
---------- -------- -------- -------- -------- -------- --------
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_init.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_init.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2009 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_init.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.08
+ * mpi2_init.h Version: 02.00.11
*
* Version History
* ---------------
* both SCSI IO Error Reply and SCSI Task Management Reply.
* Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
* Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
+ * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
+ * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
+ * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
* --------------------------------------------------------------------------
*/
} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
-/* TBD: I don't think this is needed for MPI2/Gen2 */
-#if 0
-typedef struct
-{
- U8 CDB[16]; /* 0x00 */
- U32 DataLength; /* 0x10 */
- U32 PrimaryReferenceTag; /* 0x14 */
- U16 PrimaryApplicationTag; /* 0x18 */
- U16 PrimaryApplicationTagMask; /* 0x1A */
- U32 TransferLength; /* 0x1C */
-} MPI2_SCSI_IO32_CDB_EEDP16, MPI2_POINTER PTR_MPI2_SCSI_IO32_CDB_EEDP16,
- Mpi2ScsiIo32CdbEedp16_t, MPI2_POINTER pMpi2ScsiIo32CdbEedp16_t;
-#endif
-
typedef union
{
U8 CDB32[32];
U8 LUN[8]; /* 0x34 */
U32 Control; /* 0x3C */
MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+
+#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
+ MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
+#endif
+
MPI2_SGE_IO_UNION SGL; /* 0x60 */
+
} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4)
#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0)
+/* number of SGLOffset fields */
+#define MPI2_SCSIIO_NUM_SGLOFFSETS (4)
+
/* SCSI IO IoFlags bits */
/* Large CDB Address Space */
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_ioc.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_ioc.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2009 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_ioc.h
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.13
+ * mpi2_ioc.h Version: 02.00.16
*
* Version History
* ---------------
* (MPI2_FW_HEADER_PID_).
* Modified values for SAS ProductID Family
* (MPI2_FW_HEADER_PID_FAMILY_).
+ * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
+ * Added PowerManagementControl Request structures and
+ * defines.
+ * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
+ * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
+ * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
* --------------------------------------------------------------------------
*/
#define MPI2_EVENT_STATE_CHANGE (0x0002)
#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005)
#define MPI2_EVENT_EVENT_CHANGE (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL (0x000E)
+#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */
#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F)
#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014)
#define MPI2_EVENT_SAS_DISCOVERY (0x0016)
#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
+#define MPI2_EVENT_SAS_QUIESCE (0x0025)
/* Log Entry Added Event data */
MPI2_POINTER pMpi2EventDataHardResetReceived_t;
/* Task Set Full Event data */
+/* this event is obsolete */
typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
{
#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
+#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
/* use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the ThresholdFlags field */
+/* SAS Quiesce Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE
+{
+ U8 ReasonCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 Reserved3; /* 0x04 */
+} MPI2_EVENT_DATA_SAS_QUIESCE,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
+ Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
+
+/* SAS Quiesce Event data ReasonCode values */
+#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01)
+#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02)
+
+
/* Host Based Discovery Phy Event data */
typedef struct _MPI2_EVENT_HBD_PHY_SAS
#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
+#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A)
#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
+#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
/* FWDownload TransactionContext Element */
typedef struct _MPI2_FW_DOWNLOAD_TCSGE
#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14)
+/****************************************************************************
+* PowerManagementControl message
+****************************************************************************/
+
+/* PowerManagementControl Request message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST
+{
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 Parameter1; /* 0x0C */
+ U8 Parameter2; /* 0x0D */
+ U8 Parameter3; /* 0x0E */
+ U8 Parameter4; /* 0x0F */
+ U32 Reserved5; /* 0x10 */
+ U32 Reserved6; /* 0x14 */
+} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
+ Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
+
+/* defines for the Feature field */
+#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01)
+#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02)
+#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03)
+#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80)
+#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF)
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
+/* Parameter1 contains a PHY number */
+/* Parameter2 indicates power condition action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01)
+#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02)
+#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION Feature */
+/* Parameter1 contains SAS port width modulation group number */
+/* Parameter2 indicates IOC action using these defines */
+#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01)
+#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02)
+#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03)
+/* Parameter3 indicates desired modulation level using these defines */
+#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00)
+#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01)
+#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02)
+#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03)
+/* Parameter4 is reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
+/* Parameter1 indicates desired PCIe link speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01)
+#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02)
+/* Parameter2 indicates desired PCIe link width using these defines */
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04)
+#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08)
+/* Parameter3 and Parameter4 are reserved */
+
+/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
+/* Parameter1 indicates desired IOC hardware clock speed using these defines */
+#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01)
+#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02)
+#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04)
+#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08)
+/* Parameter2, Parameter3, and Parameter4 are reserved */
+
+
+/* PowerManagementControl Reply message */
+typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY
+{
+ U8 Feature; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
+ Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
+
+
#endif
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_ra.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_ra.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2009 LSI Corporation.
+ * Copyright (c) 2011 LSI Corporation.
*
*
* Name: mpi2_ra.h
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_raid.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_raid.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_raid.h
* Title: MPI Integrated RAID messages and structures
* Creation Date: April 26, 2007
*
- * mpi2_raid.h Version: 02.00.04
+ * mpi2_raid.h Version: 02.00.05
*
* Version History
* ---------------
* can be sized by the build environment.
* 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
* VolumeCreationFlags and marked the old one as obsolete.
+ * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
* --------------------------------------------------------------------------
*/
#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
+#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
/* RAID Action Reply ActionData union */
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_sas.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_sas.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_sas.h
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: February 9, 2007
*
- * mpi2.h Version: 02.00.03
+ * mpi2_sas.h Version: 02.00.05
*
* Version History
* ---------------
* Request.
* 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
* to MPI2_SGE_IO_UNION since it supports chained SGLs.
+ * 05-12-10 02.00.04 Modified some comments.
+ * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
* --------------------------------------------------------------------------
*/
/* values for PassthroughFlags field */
#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SMP Passthrough Reply Message */
U32 Reserved4; /* 0x14 */
U32 DataLength; /* 0x18 */
U8 CommandFIS[20]; /* 0x1C */
- MPI2_SGE_IO_UNION SGL; /* 0x20 */
+ MPI2_SGE_IO_UNION SGL; /* 0x30 */
} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* SATA Passthrough Reply Message */
#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
+#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14)
+#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15)
#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
/* values for the PrimFlags field */
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_targ.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_targ.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_targ.h
* Title: MPI Target mode messages and structures
* Creation Date: September 8, 2006
*
- * mpi2_targ.h Version: 02.00.03
+ * mpi2_targ.h Version: 02.00.04
*
* Version History
* ---------------
* MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
* Target Status Send Request only takes a single SGE for
* response data.
+ * 02-10-10 02.00.04 Added comment to MPI2_TARGET_SSP_RSP_IU structure.
* --------------------------------------------------------------------------
*/
typedef struct _MPI2_TARGET_SSP_RSP_IU
{
U32 Reserved0[6]; /* reserved for SSP header */ /* 0x00 */
+
/* start of RESPONSE information unit */
U32 Reserved1; /* 0x18 */
U32 Reserved2; /* 0x1C */
U32 Reserved4; /* 0x24 */
U32 SenseDataLength; /* 0x28 */
U32 ResponseDataLength; /* 0x2C */
+
+ /* start of Response or Sense Data (size may vary dynamically) */
U8 ResponseSenseData[4]; /* 0x30 */
} MPI2_TARGET_SSP_RSP_IU, MPI2_POINTER PTR_MPI2_TARGET_SSP_RSP_IU,
Mpi2TargetSspRspIu_t, MPI2_POINTER pMpi2TargetSspRspIu_t;
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_tool.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_tool.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2009 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.04
+ * mpi2_tool.h Version: 02.00.06
*
* Version History
* ---------------
* and reply messages.
* Added MPI2_DIAG_BUF_TYPE_EXTENDED.
* Incremented MPI2_DIAG_BUF_TYPE_COUNT.
+ * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
+ * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
+ * Post Request.
* --------------------------------------------------------------------------
*/
/* defines for the Tools */
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
+#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02)
#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
/****************************************************************************
+* Toolbox Diagnostic Data Upload request
+****************************************************************************/
+
+typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST
+{
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 Flags; /* 0x10 */
+ U32 DataLength; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
+} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
+ Mpi2ToolboxDiagDataUploadRequest_t,
+ MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
+
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
+
+
+typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER
+{
+ U32 DiagDataLength; /* 00h */
+ U8 FormatCode; /* 04h */
+ U8 Reserved1; /* 05h */
+ U16 Reserved2; /* 06h */
+} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
+ Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
+
+
+/****************************************************************************
* Toolbox ISTWI Read Write Tool
****************************************************************************/
#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox ISTWI Read Write Tool reply message */
Mpi2ToolboxDiagnosticCliRequest_t,
MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
-/* values for SGLFlags field are in the SGL section of mpi2.h */
+/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
/* Toolbox Diagnostic CLI Tool reply message */
/* count of the number of buffer types */
#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
+/* values for the Flags field */
+#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002)
+#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001)
+
/****************************************************************************
* Diagnostic Buffer Post reply
-/* $FreeBSD: src/sys/dev/mps/mpi/mpi2_type.h,v 1.1 2010/09/10 15:03:56 ken Exp $ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mpi/mpi2_type.h,v 1.2 2012/01/26 18:17:21 ken Exp $
+ */
+
/*
- * Copyright (c) 2000-2007 LSI Corporation.
+ * Copyright (c) 2000-2011 LSI Corporation.
*
*
* Name: mpi2_type.h
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/dev/mps/mps.c,v 1.9 2010/12/10 21:45:10 ken Exp $
+ */
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mps.c,v 1.14 2012/01/26 18:17:21 ken Exp $
*/
/* Communications core for LSI MPT2 */
+/* TODO Move headers to mpsvar */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
-#include <sys/mutex.h>
+#include <sys/globaldata.h>
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/malloc.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/kthread.h>
#include <sys/endian.h>
+#include <sys/eventhandler.h>
#include <sys/rman.h>
-#include <bus/cam/scsi/scsi_all.h>
+#include <bus/pci/pcivar.h>
-#include <dev/disk/mps/mpi/mpi2_type.h>
-#include <dev/disk/mps/mpi/mpi2.h>
-#include <dev/disk/mps/mpi/mpi2_ioc.h>
-#include <dev/disk/mps/mpi/mpi2_cnfg.h>
-#include <dev/disk/mps/mpsvar.h>
-#include <dev/disk/mps/mps_table.h>
+#include <bus/cam/scsi/scsi_all.h>
+#include <dev/raid/mps/mpi/mpi2_type.h>
+#include <dev/raid/mps/mpi/mpi2.h>
+#include <dev/raid/mps/mpi/mpi2_ioc.h>
+#include <dev/raid/mps/mpi/mpi2_sas.h>
+#include <dev/raid/mps/mpi/mpi2_cnfg.h>
+#include <dev/raid/mps/mpi/mpi2_init.h>
+#include <dev/raid/mps/mpi/mpi2_tool.h>
+#include <dev/raid/mps/mps_ioctl.h>
+#include <dev/raid/mps/mpsvar.h>
+#include <dev/raid/mps/mps_table.h>
+
+static int mps_diag_reset(struct mps_softc *sc);
+static int mps_init_queues(struct mps_softc *sc);
+static int mps_message_unit_reset(struct mps_softc *sc);
+static int mps_transition_operational(struct mps_softc *sc);
static void mps_startup(void *arg);
-static void mps_startup_complete(struct mps_softc *sc, struct mps_command *cm);
static int mps_send_iocinit(struct mps_softc *sc);
static int mps_attach_log(struct mps_softc *sc);
-static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data, MPI2_EVENT_NOTIFICATION_REPLY *reply);
+static __inline void mps_complete_command(struct mps_command *cm);
+static void mps_dispatch_event(struct mps_softc *sc, uintptr_t data,
+ MPI2_EVENT_NOTIFICATION_REPLY *reply);
static void mps_config_complete(struct mps_softc *sc, struct mps_command *cm);
static void mps_periodic(void *);
+static int mps_reregister_events(struct mps_softc *sc);
+static void mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm);
SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters");
static char mpt2_reset_magic[] = { 0x00, 0x0f, 0x04, 0x0b, 0x02, 0x07, 0x0d };
static int
-mps_hard_reset(struct mps_softc *sc)
+mps_diag_reset(struct mps_softc *sc)
{
uint32_t reg;
int i, error, tries = 0;
}
static int
-mps_soft_reset(struct mps_softc *sc)
+mps_message_unit_reset(struct mps_softc *sc)
{
mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
* resetting it.
*/
if (reg & MPI2_DOORBELL_USED) {
- mps_hard_reset(sc);
+ mps_diag_reset(sc);
DELAY(50000);
continue;
}
} else if (state == MPI2_IOC_STATE_FAULT) {
mps_dprint(sc, MPS_INFO, "IOC in fault state 0x%x\n",
state & MPI2_DOORBELL_FAULT_CODE_MASK);
- mps_hard_reset(sc);
+ mps_diag_reset(sc);
} else if (state == MPI2_IOC_STATE_OPERATIONAL) {
/* Need to take ownership */
- mps_soft_reset(sc);
+ mps_message_unit_reset(sc);
} else if (state == MPI2_IOC_STATE_RESET) {
/* Wait a bit, IOC might be in transition */
mps_dprint(sc, MPS_FAULT,
state = reg & MPI2_IOC_STATE_MASK;
if (state != MPI2_IOC_STATE_READY) {
- if ((error = mps_transition_ready(sc)) != 0)
+ if ((error = mps_transition_ready(sc)) != 0) {
+ mps_dprint(sc, MPS_FAULT,
+ "%s failed to transition ready\n", __func__);
return (error);
+ }
}
error = mps_send_iocinit(sc);
return (error);
}
+/*
+ * XXX Some of this should probably move to mps.c
+ *
+ * The terms diag reset and hard reset are used interchangeably in the MPI
+ * docs to mean resetting the controller chip. In this code diag reset
+ * cleans everything up, and the hard reset function just sends the reset
+ * sequence to the chip. This should probably be refactored so that every
+ * subsystem gets a reset notification of some sort, and can clean up
+ * appropriately.
+ */
+int
+mps_reinit(struct mps_softc *sc)
+{
+ int error;
+ uint32_t db;
+
+ mps_printf(sc, "%s sc %p\n", __func__, sc);
+
+ KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+ if (sc->mps_flags & MPS_FLAGS_DIAGRESET) {
+ mps_printf(sc, "%s reset already in progress\n", __func__);
+ return 0;
+ }
+
+ /* make sure the completion callbacks can recognize they're getting
+ * a NULL cm_reply due to a reset.
+ */
+ sc->mps_flags |= MPS_FLAGS_DIAGRESET;
+
+ mps_printf(sc, "%s mask interrupts\n", __func__);
+ mps_mask_intr(sc);
+
+ error = mps_diag_reset(sc);
+ if (error != 0) {
+ panic("%s hard reset failed with error %d\n",
+ __func__, error);
+ }
+
+ /* Restore the PCI state, including the MSI-X registers */
+ mps_pci_restore(sc);
+
+ /* Give the I/O subsystem special priority to get itself prepared */
+ mpssas_handle_reinit(sc);
+
+ /* reinitialize queues after the reset */
+ bzero(sc->free_queue, sc->fqdepth * 4);
+ mps_init_queues(sc);
+
+ /* get the chip out of the reset state */
+ error = mps_transition_operational(sc);
+ if (error != 0)
+ panic("%s transition operational failed with error %d\n",
+ __func__, error);
+
+ /* Reinitialize the reply queue. This is delicate because this
+ * function is typically invoked by task mgmt completion callbacks,
+ * which are called by the interrupt thread. We need to make sure
+ * the interrupt handler loop will exit when we return to it, and
+ * that it will recognize the indexes we've changed.
+ */
+ sc->replypostindex = 0;
+ mps_regwrite(sc, MPI2_REPLY_FREE_HOST_INDEX_OFFSET, sc->replyfreeindex);
+ mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex);
+
+ db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
+ mps_printf(sc, "%s doorbell 0x%08x\n", __func__, db);
+
+ mps_printf(sc, "%s unmask interrupts post %u free %u\n", __func__,
+ sc->replypostindex, sc->replyfreeindex);
+
+ mps_unmask_intr(sc);
+
+ mps_printf(sc, "%s restarting post %u free %u\n", __func__,
+ sc->replypostindex, sc->replyfreeindex);
+
+ /* restart will reload the event masks clobbered by the reset, and
+ * then enable the port.
+ */
+ mps_reregister_events(sc);
+
+ /* the end of discovery will release the simq, so we're done. */
+ mps_printf(sc, "%s finished sc %p post %u free %u\n",
+ __func__, sc,
+ sc->replypostindex, sc->replyfreeindex);
+
+ sc->mps_flags &= ~MPS_FLAGS_DIAGRESET;
+
+ return 0;
+}
+
/* Wait for the chip to ACK a word that we've put into its FIFO */
static int
mps_wait_db_ack(struct mps_softc *sc)
return (0);
}
-void
+static void
mps_enqueue_request(struct mps_softc *sc, struct mps_command *cm)
{
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+ mps_dprint(sc, MPS_TRACE, "%s SMID %u cm %p ccb %p\n", __func__,
+ cm->cm_desc.Default.SMID, cm, cm->cm_ccb);
+
+ if (sc->mps_flags & MPS_FLAGS_ATTACH_DONE)
+ KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+ if (++sc->io_cmds_active > sc->io_cmds_highwater)
+ sc->io_cmds_highwater++;
mps_regwrite(sc, MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET,
cm->cm_desc.Words.Low);
cm->cm_desc.Words.High);
}
-int
-mps_request_polled(struct mps_softc *sc, struct mps_command *cm)
-{
- int error, timeout = 0;
-
- error = 0;
-
- cm->cm_flags |= MPS_CM_FLAGS_POLLED;
- cm->cm_complete = NULL;
- mps_map_command(sc, cm);
-
- while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
- mps_intr(sc);
- DELAY(50 * 1000);
- if (timeout++ > 1000) {
- mps_dprint(sc, MPS_FAULT, "polling failed\n");
- error = ETIMEDOUT;
- break;
- }
- }
-
- return (error);
-}
-
/*
* Just the FACTS, ma'am.
*/
cm->cm_data = NULL;
error = mps_request_polled(sc, cm);
reply = (MPI2_PORT_FACTS_REPLY *)cm->cm_reply;
- if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+ if (reply == NULL) {
+ mps_printf(sc, "%s NULL reply\n", __func__);
+ goto done;
+ }
+ if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) {
+ mps_printf(sc,
+ "%s error %d iocstatus 0x%x iocloginfo 0x%x type 0x%x\n",
+ __func__, error, reply->IOCStatus, (u_int)reply->IOCLogInfo,
+ reply->PortType);
error = ENXIO;
+ }
bcopy(reply, facts, sizeof(MPI2_PORT_FACTS_REPLY));
+done:
mps_free_command(sc, cm);
return (error);
return (error);
}
-static int
-mps_send_portenable(struct mps_softc *sc)
-{
- MPI2_PORT_ENABLE_REQUEST *request;
- struct mps_command *cm;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- if ((cm = mps_alloc_command(sc)) == NULL)
- return (EBUSY);
- request = (MPI2_PORT_ENABLE_REQUEST *)cm->cm_req;
- request->Function = MPI2_FUNCTION_PORT_ENABLE;
- request->MsgFlags = 0;
- request->VP_ID = 0;
- cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- cm->cm_complete = mps_startup_complete;
-
- mps_enqueue_request(sc, cm);
- return (0);
-}
-
-static int
-mps_send_mur(struct mps_softc *sc)
-{
-
- /* Placeholder */
- return (0);
-}
-
void
mps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
bus_dmamap_load(sc->req_dmat, sc->req_map, sc->req_frames, rsize,
mps_memaddr_cb, &sc->req_busaddr, 0);
- rsize = sc->facts->IOCRequestFrameSize * MPS_CHAIN_FRAMES * 4;
+ rsize = sc->facts->IOCRequestFrameSize * sc->max_chains * 4;
if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */
16, 0, /* algnmnt, boundary */
BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
bus_dmamap_load(sc->sense_dmat, sc->sense_map, sc->sense_frames, rsize,
mps_memaddr_cb, &sc->sense_busaddr, 0);
- sc->chains = kmalloc(sizeof(struct mps_chain) * MPS_CHAIN_FRAMES,
- M_MPT2, M_WAITOK | M_ZERO);
- for (i = 0; i < MPS_CHAIN_FRAMES; i++) {
+ sc->chains = kmalloc(sizeof(struct mps_chain) * sc->max_chains, M_MPT2,
+ M_WAITOK | M_ZERO);
+ for (i = 0; i < sc->max_chains; i++) {
chain = &sc->chains[i];
chain->chain = (MPI2_SGE_IO_UNION *)(sc->chain_frames +
i * sc->facts->IOCRequestFrameSize * 4);
chain->chain_busaddr = sc->chain_busaddr +
i * sc->facts->IOCRequestFrameSize * 4;
mps_free_chain(sc, chain);
+ sc->chain_free_lowwater++;
}
/* XXX Need to pick a more precise value */
BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
BUS_DMA_ALLOCNOW, /* flags */
&sc->buffer_dmat)) {
- device_printf(sc->mps_dev, "Cannot allocate sense DMA tag\n");
+ device_printf(sc->mps_dev, "Cannot allocate buffer DMA tag\n");
return (ENOMEM);
}
/* XXX Is a failure here a critical problem? */
if (bus_dmamap_create(sc->buffer_dmat, 0, &cm->cm_dmamap) == 0)
- mps_free_command(sc, cm);
+ if (i <= sc->facts->HighPriorityCredit)
+ mps_free_high_priority_command(sc, cm);
+ else
+ mps_free_command(sc, cm);
else {
+ panic("failed to allocate command %d\n", i);
sc->num_reqs = i;
break;
}
return (0);
}
-int
-mps_attach(struct mps_softc *sc)
+/* Get the driver parameter tunables. Lowest priority are the driver defaults.
+ * Next are the global settings, if they exist. Highest are the per-unit
+ * settings, if they exist.
+ */
+static void
+mps_get_tunables(struct mps_softc *sc)
{
- int i, error;
- char tmpstr[80], tmpstr2[80];
+ char tmpstr[80];
+
+ /* XXX default to some debugging for now */
+ sc->mps_debug = MPS_FAULT;
+#if 0 /* XXX swildner */
+ sc->disable_msix = 0;
+#endif
+ sc->enable_msi = 1;
+ sc->max_chains = MPS_CHAIN_FRAMES;
/*
- * Grab any tunable-set debug level so that tracing works as early
- * as possible.
+ * Grab the global variables.
*/
- ksnprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.debug_level",
+ TUNABLE_INT_FETCH("hw.mps.debug_level", &sc->mps_debug);
+#if 0 /* XXX swildner */
+ TUNABLE_INT_FETCH("hw.mps.disable_msix", &sc->disable_msix);
+#endif
+ TUNABLE_INT_FETCH("hw.mps.msi.enable", &sc->enable_msi);
+ TUNABLE_INT_FETCH("hw.mps.max_chains", &sc->max_chains);
+
+ /* Grab the unit-instance variables */
+ ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.debug_level",
device_get_unit(sc->mps_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->mps_debug);
- ksnprintf(tmpstr, sizeof(tmpstr), "hw.mps.%d.allow_multiple_tm_cmds",
+
+#if 0 /* XXX swildner */
+ ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.disable_msix",
device_get_unit(sc->mps_dev));
- TUNABLE_INT_FETCH(tmpstr, &sc->allow_multiple_tm_cmds);
+ TUNABLE_INT_FETCH(tmpstr, &sc->disable_msix);
+#endif
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+ ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.enable_msi",
+ device_get_unit(sc->mps_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->enable_msi);
- lockinit(&sc->mps_lock, "MPT2SAS lock", 0, LK_CANRECURSE);
- callout_init(&sc->periodic);
- TAILQ_INIT(&sc->event_list);
+ ksnprintf(tmpstr, sizeof(tmpstr), "dev.mps.%d.max_chains",
+ device_get_unit(sc->mps_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->max_chains);
+}
+
+static void
+mps_setup_sysctl(struct mps_softc *sc)
+{
+ struct sysctl_ctx_list *sysctl_ctx = NULL;
+ struct sysctl_oid *sysctl_tree = NULL;
+ char tmpstr[80], tmpstr2[80];
/*
* Setup the sysctl variable so the user can change the debug level
sysctl_ctx_init(&sc->sysctl_ctx);
sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
- SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2, CTLFLAG_RD,
- 0, tmpstr);
+ SYSCTL_STATIC_CHILDREN(_hw_mps), OID_AUTO, tmpstr2,
+ CTLFLAG_RD, 0, tmpstr);
if (sc->sysctl_tree == NULL)
- return (ENOMEM);
+ return;
+ sysctl_ctx = &sc->sysctl_ctx;
+ sysctl_tree = sc->sysctl_tree;
- SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "debug_level", CTLFLAG_RW, &sc->mps_debug, 0,
"mps debug level");
- SYSCTL_ADD_INT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
- OID_AUTO, "allow_multiple_tm_cmds", CTLFLAG_RW,
- &sc->allow_multiple_tm_cmds, 0,
- "allow multiple simultaneous task management cmds");
+#if 0 /* XXX swildner */
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "disable_msix", CTLFLAG_RD, &sc->disable_msix, 0,
+ "Disable the use of MSI-X interrupts");
+#endif
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "enable_msi", CTLFLAG_RD, &sc->enable_msi, 0,
+ "Enable the use of MSI interrupts");
+
+ SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "firmware_version", CTLFLAG_RW, &sc->fw_version,
+ strlen(sc->fw_version), "firmware version");
+
+ SYSCTL_ADD_STRING(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "driver_version", CTLFLAG_RW, MPS_DRIVER_VERSION,
+ strlen(MPS_DRIVER_VERSION), "driver version");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "io_cmds_active", CTLFLAG_RD,
+ &sc->io_cmds_active, 0, "number of currently active commands");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "io_cmds_highwater", CTLFLAG_RD,
+ &sc->io_cmds_highwater, 0, "maximum active commands seen");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_free", CTLFLAG_RD,
+ &sc->chain_free, 0, "number of free chain elements");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_free_lowwater", CTLFLAG_RD,
+ &sc->chain_free_lowwater, 0,"lowest number of free chain elements");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "max_chains", CTLFLAG_RD,
+ &sc->max_chains, 0,"maximum chain frames that will be allocated");
+
+#if __FreeBSD_version >= 900030
+ SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "chain_alloc_fail", CTLFLAG_RD,
+ &sc->chain_alloc_fail, "chain allocation failures");
+#endif //FreeBSD_version >= 900030
+}
+
+int
+mps_attach(struct mps_softc *sc)
+{
+ int i, error;
+
+ mps_get_tunables(sc);
- if ((error = mps_transition_ready(sc)) != 0)
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ lockinit(&sc->mps_lock, "MPT2SAS lock", 0, LK_CANRECURSE);
+ callout_init(&sc->periodic);
+ TAILQ_INIT(&sc->event_list);
+
+ if ((error = mps_transition_ready(sc)) != 0) {
+ mps_printf(sc, "%s failed to transition ready\n", __func__);
return (error);
+ }
sc->facts = kmalloc(sizeof(MPI2_IOC_FACTS_REPLY), M_MPT2,
M_ZERO|M_NOWAIT);
mps_print_iocfacts(sc, sc->facts);
- mps_printf(sc, "Firmware: %02d.%02d.%02d.%02d\n",
+ ksnprintf(sc->fw_version, sizeof(sc->fw_version),
+ "%02d.%02d.%02d.%02d",
sc->facts->FWVersion.Struct.Major,
sc->facts->FWVersion.Struct.Minor,
sc->facts->FWVersion.Struct.Unit,
sc->facts->FWVersion.Struct.Dev);
- mps_printf(sc, "IOCCapabilities: %b\n",
- (u_int)(sc->facts->IOCCapabilities),
+
+ mps_printf(sc, "Firmware: %s, Driver: %s\n", sc->fw_version,
+ MPS_DRIVER_VERSION);
+ mps_printf(sc, "IOCCapabilities: %b\n", (int)sc->facts->IOCCapabilities,
"\20" "\3ScsiTaskFull" "\4DiagTrace" "\5SnapBuf" "\6ExtBuf"
"\7EEDP" "\10BiDirTarg" "\11Multicast" "\14TransRetry" "\15IR"
"\16EventReplay" "\17RaidAccel" "\20MSIXIndex" "\21HostDisc");
*/
if ((sc->facts->IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY) == 0) {
- mps_hard_reset(sc);
+ mps_diag_reset(sc);
if ((error = mps_transition_ready(sc)) != 0)
return (error);
}
/*
+ * Set flag if IR Firmware is loaded.
+ */
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+ sc->ir_firmware = 1;
+
+ /*
+ * Check if controller supports FW diag buffers and set flag to enable
+ * each type.
+ */
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_TRACE].enabled =
+ TRUE;
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_SNAPSHOT].enabled =
+ TRUE;
+ if (sc->facts->IOCCapabilities &
+ MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
+ sc->fw_diag_buffer_list[MPI2_DIAG_BUF_TYPE_EXTENDED].enabled =
+ TRUE;
+
+ /*
+ * Set flag if EEDP is supported and if TLR is supported.
+ */
+ if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP)
+ sc->eedp_enabled = TRUE;
+ if (sc->facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)
+ sc->control_TLR = TRUE;
+
+ /*
* Size the queues. Since the reply queues always need one free entry,
* we'll just deduct one reply message here.
*/
sc->num_replies = MIN(MPS_REPLY_FRAMES + MPS_EVT_REPLY_FRAMES,
sc->facts->MaxReplyDescriptorPostQueueDepth) - 1;
TAILQ_INIT(&sc->req_list);
+ TAILQ_INIT(&sc->high_priority_req_list);
TAILQ_INIT(&sc->chain_list);
TAILQ_INIT(&sc->tm_list);
if (((error = mps_alloc_queues(sc)) != 0) ||
((error = mps_alloc_replies(sc)) != 0) ||
((error = mps_alloc_requests(sc)) != 0)) {
+ mps_printf(sc, "%s failed to alloc\n", __func__);
mps_free(sc);
return (error);
}
if (((error = mps_init_queues(sc)) != 0) ||
((error = mps_transition_operational(sc)) != 0)) {
+ mps_printf(sc, "%s failed to transition operational\n", __func__);
mps_free(sc);
return (error);
}
sc->facts->NumberOfPorts, M_MPT2, M_ZERO|M_WAITOK);
for (i = 0; i < sc->facts->NumberOfPorts; i++) {
if ((error = mps_get_portfacts(sc, &sc->pfacts[i], i)) != 0) {
+ mps_printf(sc, "%s failed to get portfacts for port %d\n",
+ __func__, i);
mps_free(sc);
return (error);
}
}
if ((error = mps_pci_setup_interrupts(sc)) != 0) {
+ mps_printf(sc, "%s failed to setup interrupts\n", __func__);
mps_free(sc);
return (error);
}
+ /*
+ * The static page function currently read is ioc page8. Others can be
+ * added in future.
+ */
+ mps_base_static_config_pages(sc);
+
/* Start the periodic watchdog check on the IOC Doorbell */
mps_periodic(sc);
error = EINVAL;
}
+ /*
+ * Allow IR to shutdown gracefully when shutdown occurs.
+ */
+ sc->shutdown_eh = EVENTHANDLER_REGISTER(shutdown_final,
+ mpssas_ir_shutdown, sc, SHUTDOWN_PRI_DEFAULT);
+
+ if (sc->shutdown_eh == NULL)
+ mps_dprint(sc, MPS_FAULT, "shutdown event registration "
+ "failed\n");
+
+ mps_setup_sysctl(sc);
+
+ sc->mps_flags |= MPS_FLAGS_ATTACH_DONE;
+
return (error);
}
+/* Run through any late-start handlers. */
static void
mps_startup(void *arg)
{
mps_lock(sc);
mps_unmask_intr(sc);
- mps_send_portenable(sc);
+ /* initialize device mapping tables */
+ mps_mapping_initialize(sc);
+ mpssas_startup(sc);
mps_unlock(sc);
}
uint32_t db;
sc = (struct mps_softc *)arg;
- if (sc->mps_flags & MPS_FLAGS_SHUTDOWN)
+ mps_lock(sc);
+ if (sc->mps_flags & MPS_FLAGS_SHUTDOWN) {
+ mps_unlock(sc);
return;
+ }
db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
device_printf(sc->mps_dev, "IOC Fault 0x%08x, Resetting\n", db);
- /* XXX Need to broaden this to re-initialize the chip */
- mps_hard_reset(sc);
- db = mps_regread(sc, MPI2_DOORBELL_OFFSET);
- if ((db & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- device_printf(sc->mps_dev, "Second IOC Fault 0x%08x, "
- "Giving up!\n", db);
- return;
- }
+
+ mps_reinit(sc);
}
callout_reset(&sc->periodic, MPS_PERIODIC_DELAY * hz, mps_periodic, sc);
-}
-
-static void
-mps_startup_complete(struct mps_softc *sc, struct mps_command *cm)
-{
- MPI2_PORT_ENABLE_REPLY *reply;
-
- mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
-
- reply = (MPI2_PORT_ENABLE_REPLY *)cm->cm_reply;
- if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
- mps_dprint(sc, MPS_FAULT, "Portenable failed\n");
-
- mps_free_command(sc, cm);
- config_intrhook_disestablish(&sc->mps_ich);
-
+ mps_unlock(sc);
}
static void
#if 0 /* XXX swildner */
/* Lock must not be held for this */
callout_drain(&sc->periodic);
+#else
+ callout_stop(&sc->periodic);
#endif
if (((error = mps_detach_log(sc)) != 0) ||
/* Put the IOC back in the READY state. */
mps_lock(sc);
- if ((error = mps_send_mur(sc)) != 0) {
+ if ((error = mps_transition_ready(sc)) != 0) {
mps_unlock(sc);
return (error);
}
if (sc->sysctl_tree != NULL)
sysctl_ctx_free(&sc->sysctl_ctx);
+ mps_mapping_free_memory(sc);
+
+ /* Deregister the shutdown function */
+ if (sc->shutdown_eh != NULL)
+ EVENTHANDLER_DEREGISTER(shutdown_final, sc->shutdown_eh);
+
lockuninit(&sc->mps_lock);
return (0);
}
+static __inline void
+mps_complete_command(struct mps_command *cm)
+{
+ if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
+ cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
+
+ if (cm->cm_complete != NULL) {
+ mps_dprint(cm->cm_sc, MPS_TRACE,
+ "%s cm %p calling cm_complete %p data %p reply %p\n",
+ __func__, cm, cm->cm_complete, cm->cm_complete_data,
+ cm->cm_reply);
+ cm->cm_complete(cm->cm_sc, cm);
+ }
+
+ if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP) {
+ mps_dprint(cm->cm_sc, MPS_TRACE, "%s: waking up %p\n",
+ __func__, cm);
+ wakeup(cm);
+ }
+
+ if (cm->cm_sc->io_cmds_active != 0) {
+ cm->cm_sc->io_cmds_active--;
+ } else {
+ mps_dprint(cm->cm_sc, MPS_INFO, "Warning: io_cmds_active is "
+ "out of sync - resynching to 0\n");
+ }
+}
+
void
mps_intr(void *data)
{
struct mps_softc *sc;
sc = (struct mps_softc *)data;
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
mps_lock(sc);
mps_intr_locked(data);
mps_unlock(sc);
struct mps_command *cm = NULL;
uint8_t flags;
u_int pq;
+ MPI2_DIAG_RELEASE_REPLY *rel_rep;
+ mps_fw_diagnostic_buffer_t *pBuffer;
sc = (struct mps_softc *)data;
pq = sc->replypostindex;
+ mps_dprint(sc, MPS_TRACE,
+ "%s sc %p starting with replypostindex %u\n",
+ __func__, sc, sc->replypostindex);
for ( ;; ) {
cm = NULL;
- desc = &sc->post_queue[pq];
+ desc = &sc->post_queue[sc->replypostindex];
flags = desc->Default.ReplyFlags &
MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
if ((flags == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
|| (desc->Words.High == 0xffffffff))
break;
+ /* increment the replypostindex now, so that event handlers
+ * and cm completion handlers which decide to do a diag
+ * reset can zero it without it getting incremented again
+ * afterwards, and we break out of this loop on the next
+ * iteration since the reply post queue has been cleared to
+ * 0xFF and all descriptors look unused (which they are).
+ */
+ if (++sc->replypostindex >= sc->pqdepth)
+ sc->replypostindex = 0;
+
switch (flags) {
case MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS:
cm = &sc->commands[desc->SCSIIOSuccess.SMID];
panic("Reply address out of range");
}
if (desc->AddressReply.SMID == 0) {
- mps_dispatch_event(sc, baddr,
- (MPI2_EVENT_NOTIFICATION_REPLY *) reply);
+ if (((MPI2_DEFAULT_REPLY *)reply)->Function ==
+ MPI2_FUNCTION_DIAG_BUFFER_POST) {
+ /*
+ * If SMID is 0 for Diag Buffer Post,
+ * this implies that the reply is due to
+ * a release function with a status that
+ * the buffer has been released. Set
+ * the buffer flags accordingly.
+ */
+ rel_rep =
+ (MPI2_DIAG_RELEASE_REPLY *)reply;
+ if (rel_rep->IOCStatus ==
+ MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED)
+ {
+ pBuffer =
+ &sc->fw_diag_buffer_list[
+ rel_rep->BufferType];
+ pBuffer->valid_data = TRUE;
+ pBuffer->owned_by_firmware =
+ FALSE;
+ pBuffer->immediate = FALSE;
+ }
+ } else
+ mps_dispatch_event(sc, baddr,
+ (MPI2_EVENT_NOTIFICATION_REPLY *)
+ reply);
} else {
cm = &sc->commands[desc->AddressReply.SMID];
cm->cm_reply = reply;
break;
}
- if (cm != NULL) {
- if (cm->cm_flags & MPS_CM_FLAGS_POLLED)
- cm->cm_flags |= MPS_CM_FLAGS_COMPLETE;
-
- if (cm->cm_complete != NULL)
- cm->cm_complete(sc, cm);
-
- if (cm->cm_flags & MPS_CM_FLAGS_WAKEUP)
- wakeup(cm);
- }
+ if (cm != NULL)
+ mps_complete_command(cm);
desc->Words.Low = 0xffffffff;
desc->Words.High = 0xffffffff;
- if (++pq >= sc->pqdepth)
- pq = 0;
}
if (pq != sc->replypostindex) {
- mps_dprint(sc, MPS_INFO, "writing postindex %d\n", pq);
- mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, pq);
- sc->replypostindex = pq;
+ mps_dprint(sc, MPS_TRACE,
+ "%s sc %p writing postindex %d\n",
+ __func__, sc, sc->replypostindex);
+ mps_regwrite(sc, MPI2_REPLY_POST_HOST_INDEX_OFFSET, sc->replypostindex);
}
return;
if (handled == 0)
device_printf(sc->mps_dev, "Unhandled event 0x%x\n", event);
+
+ /*
+ * This is the only place that the event/reply should be freed.
+ * Anything wanting to hold onto the event data should have
+ * already copied it into their own storage.
+ */
+ mps_free_reply(sc, data);
+}
+
+static void
+mps_reregister_events_complete(struct mps_softc *sc, struct mps_command *cm)
+{
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if (cm->cm_reply)
+ mps_print_event(sc,
+ (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply);
+
+ mps_free_command(sc, cm);
+
+ /* next, send a port enable */
+ mpssas_startup(sc);
}
/*
error = mps_request_polled(sc, cm);
reply = (MPI2_EVENT_NOTIFICATION_REPLY *)cm->cm_reply;
- if ((reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
+ if ((reply == NULL) ||
+ (reply->IOCStatus & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS)
error = ENXIO;
mps_print_event(sc, reply);
+ mps_dprint(sc, MPS_TRACE, "%s finished error %d\n", __func__, error);
mps_free_command(sc, cm);
return (error);
}
+static int
+mps_reregister_events(struct mps_softc *sc)
+{
+ MPI2_EVENT_NOTIFICATION_REQUEST *evtreq;
+ struct mps_command *cm;
+ struct mps_event_handle *eh;
+ int error, i;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ /* first, reregister events */
+
+ memset(sc->event_mask, 0xff, 16);
+
+ TAILQ_FOREACH(eh, &sc->event_list, eh_list) {
+ for (i = 0; i < 16; i++)
+ sc->event_mask[i] &= ~eh->mask[i];
+ }
+
+ if ((cm = mps_alloc_command(sc)) == NULL)
+ return (EBUSY);
+ evtreq = (MPI2_EVENT_NOTIFICATION_REQUEST *)cm->cm_req;
+ evtreq->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
+ evtreq->MsgFlags = 0;
+ evtreq->SASBroadcastPrimitiveMasks = 0;
+#ifdef MPS_DEBUG_ALL_EVENTS
+ {
+ u_char fullmask[16];
+ memset(fullmask, 0x00, 16);
+ bcopy(fullmask, (uint8_t *)&evtreq->EventMasks, 16);
+ }
+#else
+ bcopy(sc->event_mask, (uint8_t *)&evtreq->EventMasks, 16);
+#endif
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ cm->cm_complete = mps_reregister_events_complete;
+
+ error = mps_map_command(sc, cm);
+
+ mps_dprint(sc, MPS_TRACE, "%s finished with error %d\n", __func__, error);
+ return (error);
+}
+
int
mps_deregister_events(struct mps_softc *sc, struct mps_event_handle *handle)
{
MPI2_SGE_TRANSACTION_UNION *tc = sgep;
MPI2_SGE_SIMPLE64 *sge = sgep;
int error, type;
+ uint32_t saved_buf_len, saved_address_low, saved_address_high;
type = (tc->Flags & MPI2_SGE_FLAGS_ELEMENT_MASK);
if (((sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT) &
MPI2_SGE_FLAGS_ADDRESS_SIZE) == 0)
panic("SGE simple %p flags %02x not marked 64-bit?",
- sge,
- (u_int)(sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT));
+ sge, (u_int)(sge->FlagsLength >> MPI2_SGE_FLAGS_SHIFT));
break;
default:
if (segsleft == 1 && type == MPI2_SGE_FLAGS_SIMPLE_ELEMENT) {
/*
- * Last element of the last segment of the entire
- * buffer.
+ * If this is a bi-directional request, need to account for that
+ * here. Save the pre-filled sge values. These will be used
+ * either for the 2nd SGL or for a single direction SGL. If
+ * cm_out_len is non-zero, this is a bi-directional request, so
+ * fill in the OUT SGL first, then the IN SGL, otherwise just
+ * fill in the IN SGL. Note that at this time, when filling in
+ * 2 SGL's for a bi-directional request, they both use the same
+ * DMA buffer (same cm command).
*/
- sge->FlagsLength |= ((MPI2_SGE_FLAGS_LAST_ELEMENT |
+ saved_buf_len = sge->FlagsLength & 0x00FFFFFF;
+ saved_address_low = sge->Address.Low;
+ saved_address_high = sge->Address.High;
+ if (cm->cm_out_len) {
+ sge->FlagsLength = cm->cm_out_len |
+ ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER |
+ MPI2_SGE_FLAGS_HOST_TO_IOC |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ cm->cm_sglsize -= len;
+ bcopy(sgep, cm->cm_sge, len);
+ cm->cm_sge = (MPI2_SGE_IO_UNION *)((uintptr_t)cm->cm_sge
+ + len);
+ }
+ sge->FlagsLength = saved_buf_len |
+ ((uint32_t)(MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT);
+ MPI2_SGE_FLAGS_LAST_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_LIST |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ if (cm->cm_flags & MPS_CM_FLAGS_DATAIN) {
+ sge->FlagsLength |=
+ ((uint32_t)(MPI2_SGE_FLAGS_IOC_TO_HOST) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ } else {
+ sge->FlagsLength |=
+ ((uint32_t)(MPI2_SGE_FLAGS_HOST_TO_IOC) <<
+ MPI2_SGE_FLAGS_SHIFT);
+ }
+ sge->Address.Low = saved_address_low;
+ sge->Address.High = saved_address_high;
}
cm->cm_sglsize -= len;
MPI2_SGE_SIMPLE64 sge;
/*
- * This driver always uses 64-bit address elements for
- * simplicity.
+ * This driver always uses 64-bit address elements for simplicity.
*/
- flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_ADDRESS_SIZE;
+ flags |= MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
+ MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
sge.FlagsLength = len | (flags << MPI2_SGE_FLAGS_SHIFT);
mps_from_u64(pa, &sge.Address);
}
/*
- * Set up DMA direction flags. Note that we don't support
- * bi-directional transfers, with the exception of SMP passthrough.
+ * Set up DMA direction flags. Bi-directional requests are also handled
+ * here. In that case, both direction flags will be set.
*/
sflags = 0;
if (cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) {
sflags |= MPI2_SGE_FLAGS_DIRECTION |
MPI2_SGE_FLAGS_END_OF_BUFFER;
} else if (cm->cm_flags & MPS_CM_FLAGS_DATAOUT) {
- sflags |= MPI2_SGE_FLAGS_DIRECTION;
+ sflags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
dir = BUS_DMASYNC_PREWRITE;
} else
dir = BUS_DMASYNC_PREREAD;
for (i = 0; i < nsegs; i++) {
- if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS)
- && (i != 0)) {
+ if ((cm->cm_flags & MPS_CM_FLAGS_SMP_PASS) && (i != 0)) {
sflags &= ~MPI2_SGE_FLAGS_DIRECTION;
}
error = mps_add_dmaseg(cm, segs[i].ds_addr, segs[i].ds_len,
sflags, nsegs - i);
if (error != 0) {
/* Resource shortage, roll back! */
- mps_printf(sc, "out of chain frames\n");
+ mps_dprint(sc, MPS_INFO, "out of chain frames\n");
+ cm->cm_flags |= MPS_CM_FLAGS_CHAIN_FAILED;
+ mps_complete_command(cm);
return;
}
}
}
/*
+ * This is the routine to enqueue commands ansynchronously.
* Note that the only error path here is from bus_dmamap_load(), which can
- * return EINPROGRESS if it is waiting for resources.
+ * return EINPROGRESS if it is waiting for resources. Other than this, it's
+ * assumed that if you have a command in-hand, then you have enough credits
+ * to use it.
*/
int
mps_map_command(struct mps_softc *sc, struct mps_command *cm)
}
/*
+ * This is the routine to enqueue commands synchronously. An error of
+ * EINPROGRESS from mps_map_command() is ignored since the command will
+ * be executed and enqueued automatically. Other errors come from msleep().
+ */
+int
+mps_wait_command(struct mps_softc *sc, struct mps_command *cm, int timeout)
+{
+ int error;
+
+ KKASSERT(lockstatus(&sc->mps_lock, curthread) != 0);
+
+ cm->cm_complete = NULL;
+ cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
+ error = mps_map_command(sc, cm);
+ if ((error != 0) && (error != EINPROGRESS))
+ return (error);
+ error = lksleep(cm, &sc->mps_lock, 0, "mpswait", timeout);
+ if (error == EWOULDBLOCK)
+ error = ETIMEDOUT;
+ return (error);
+}
+
+/*
+ * This is the routine to enqueue a command synchonously and poll for
+ * completion. Its use should be rare.
+ */
+int
+mps_request_polled(struct mps_softc *sc, struct mps_command *cm)
+{
+ int error, timeout = 0;
+
+ error = 0;
+
+ cm->cm_flags |= MPS_CM_FLAGS_POLLED;
+ cm->cm_complete = NULL;
+ mps_map_command(sc, cm);
+
+ while ((cm->cm_flags & MPS_CM_FLAGS_COMPLETE) == 0) {
+ mps_intr_locked(sc);
+ DELAY(50 * 1000);
+ if (timeout++ > 1000) {
+ mps_dprint(sc, MPS_FAULT, "polling failed\n");
+ error = ETIMEDOUT;
+ break;
+ }
+ }
+
+ return (error);
+}
+
+/*
* The MPT driver had a verbose interface for config pages. In this driver,
* reduce it to much simplier terms, similar to the Linux driver.
*/
cm->cm_complete = mps_config_complete;
return (mps_map_command(sc, cm));
} else {
- cm->cm_complete = NULL;
- cm->cm_flags |= MPS_CM_FLAGS_WAKEUP;
- if ((error = mps_map_command(sc, cm)) != 0)
+ error = mps_wait_command(sc, cm, 0);
+ if (error) {
+ mps_dprint(sc, MPS_FAULT,
+ "Error %d reading config page\n", error);
+ mps_free_command(sc, cm);
return (error);
- lksleep(cm, &sc->mps_lock, 0, "mpswait", 0);
+ }
mps_config_complete(sc, cm);
}
bus_dmamap_unload(sc->buffer_dmat, cm->cm_dmamap);
}
+ /*
+ * XXX KDM need to do more error recovery? This results in the
+ * device in question not getting probed.
+ */
+ if ((cm->cm_flags & MPS_CM_FLAGS_ERROR_MASK) != 0) {
+ params->status = MPI2_IOCSTATUS_BUSY;
+ goto done;
+ }
+
reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (reply == NULL) {
+ params->status = MPI2_IOCSTATUS_BUSY;
+ goto done;
+ }
params->status = reply->IOCStatus;
if (params->hdr.Ext.ExtPageType != 0) {
params->hdr.Ext.ExtPageType = reply->ExtPageType;
params->hdr.Struct.PageVersion = reply->Header.PageVersion;
}
+done:
mps_free_command(sc, cm);
if (params->callback != NULL)
params->callback(sc, params);
--- /dev/null
+/*-
+ * Copyright (c) 2011 LSI Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD: src/sys/dev/mps/mps_config.c,v 1.1 2012/01/26 18:17:21 ken Exp $
+ */
+
+/* TODO Move headers to mpsvar */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/kthread.h>
+#include <sys/taskqueue.h>
+#include <sys/bus.h>
+#include <sys/endian.h>
+#include <sys/sysctl.h>
+#include <sys/eventhandler.h>
+#include <sys/uio.h>
+#include <dev/raid/mps/mpi/mpi2_type.h>
+#include <dev/raid/mps/mpi/mpi2.h>
+#include <dev/raid/mps/mpi/mpi2_ioc.h>
+#include <dev/raid/mps/mpi/mpi2_sas.h>
+#include <dev/raid/mps/mpi/mpi2_cnfg.h>
+#include <dev/raid/mps/mpi/mpi2_init.h>
+#include <dev/raid/mps/mpi/mpi2_tool.h>
+#include <dev/raid/mps/mps_ioctl.h>
+#include <dev/raid/mps/mpsvar.h>
+
+/**
+ * mps_config_get_ioc_pg8 - obtain ioc page 8
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_ioc_pg8(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2IOCPage8_t *config_page)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ MPI2_CONFIG_PAGE_IOC_8 *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
+ request->Header.PageNumber = 8;
+ request->Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc((cm->cm_length), M_MPT2, M_ZERO | M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length, (sizeof(Mpi2IOCPage8_t))));
+
+out:
+ kfree(page, M_MPT2);
+ if (cm)
+ mps_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mps_config_get_man_pg10 - obtain Manufacturing Page 10 data and set flags
+ * accordingly. Currently, this page does not need to return to caller.
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_man_pg10(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ pMpi2ManufacturingPagePS_t page = NULL;
+ uint32_t *pPS_info;
+ uint8_t OEM_Value = 0;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+ request->Header.PageNumber = 10;
+ request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
+ request->Header.PageNumber = 10;
+ request->Header.PageVersion = MPI2_MANUFACTURING10_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc(MPS_MAN_PAGE10_SIZE, M_MPT2, M_ZERO | M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+
+ /*
+ * If OEM ID is unknown, fail the request.
+ */
+ sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
+ OEM_Value = (uint8_t)(page->ProductSpecificInfo & 0x000000FF);
+ if (OEM_Value != MPS_WD_LSI_OEM) {
+ mps_dprint(sc, MPS_FAULT, "Unknown OEM value for WarpDrive "
+ "(0x%x)\n", OEM_Value);
+ error = ENXIO;
+ goto out;
+ }
+
+ /*
+ * Set the phys disks hide/expose value.
+ */
+ pPS_info = (uint32_t *)&page->ProductSpecificInfo;
+ sc->WD_hide_expose = (uint8_t)(pPS_info[5]);
+ sc->WD_hide_expose &= MPS_WD_HIDE_EXPOSE_MASK;
+ if ((sc->WD_hide_expose != MPS_WD_HIDE_ALWAYS) &&
+ (sc->WD_hide_expose != MPS_WD_EXPOSE_ALWAYS) &&
+ (sc->WD_hide_expose != MPS_WD_HIDE_IF_VOLUME)) {
+ mps_dprint(sc, MPS_FAULT, "Unknown value for WarpDrive "
+ "hide/expose: 0x%x\n", sc->WD_hide_expose);
+ error = ENXIO;
+ goto out;
+ }
+
+out:
+ kfree(page, M_MPT2);
+ if (cm)
+ mps_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mps_base_static_config_pages - static start of day config pages.
+ * @sc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mps_base_static_config_pages(struct mps_softc *sc)
+{
+ Mpi2ConfigReply_t mpi_reply;
+ int retry;
+
+ retry = 0;
+ while (mps_config_get_ioc_pg8(sc, &mpi_reply, &sc->ioc_pg8)) {
+ retry++;
+ if (retry > 5) {
+ /* We need to Handle this situation */
+ /*FIXME*/
+ break;
+ }
+ }
+}
+
+/**
+ * mps_wd_config_pages - get info required to support WarpDrive. This needs to
+ * be called after discovery is complete to guarentee that IR info is there.
+ * @sc: per adapter object
+ *
+ * Return nothing.
+ */
+void
+mps_wd_config_pages(struct mps_softc *sc)
+{
+ Mpi2ConfigReply_t mpi_reply;
+ pMpi2RaidVolPage0_t raid_vol_pg0 = NULL;
+ Mpi2RaidPhysDiskPage0_t phys_disk_pg0;
+ pMpi2RaidVol0PhysDisk_t pRVPD;
+ uint32_t stripe_size, phys_disk_page_address;
+ uint16_t block_size;
+ uint8_t index, stripe_exp = 0, block_exp = 0;
+
+ /*
+ * Get the WD settings from manufacturing page 10 if using a WD HBA.
+ * This will be used to determine if phys disks should always be
+ * hidden, hidden only if part of a WD volume, or never hidden. Also,
+ * get the WD RAID Volume info and fail if volume does not exist or if
+ * volume does not meet the requirements for a WD volume. No retry
+ * here. Just default to HIDE ALWAYS if man Page10 fails, or clear WD
+ * Valid flag if Volume info fails.
+ */
+ sc->WD_valid_config = FALSE;
+ if (sc->mps_flags & MPS_FLAGS_WD_AVAILABLE) {
+ if (mps_config_get_man_pg10(sc, &mpi_reply)) {
+ mps_dprint(sc, MPS_FAULT,
+ "mps_config_get_man_pg10 failed! Using 0 (Hide "
+ "Always) for WarpDrive hide/expose value.\n");
+ sc->WD_hide_expose = MPS_WD_HIDE_ALWAYS;
+ }
+
+ /*
+ * Get first RAID Volume Page0 using GET_NEXT_HANDLE.
+ */
+ raid_vol_pg0 = kmalloc(sizeof(Mpi2RaidVolPage0_t) +
+ (sizeof(Mpi2RaidVol0PhysDisk_t) * MPS_MAX_DISKS_IN_VOL),
+ M_MPT2, M_ZERO | M_NOWAIT);
+ if (!raid_vol_pg0) {
+ kprintf("%s: page alloc failed\n", __func__);
+ goto out;
+ }
+
+ if (mps_config_get_raid_volume_pg0(sc, &mpi_reply, raid_vol_pg0,
+ 0x0000FFFF)) {
+ mps_dprint(sc, MPS_INFO,
+ "mps_config_get_raid_volume_pg0 failed! Assuming "
+ "WarpDrive IT mode.\n");
+ goto out;
+ }
+
+ /*
+ * Check for valid WD configuration:
+ * volume type is RAID0
+ * number of phys disks in the volume is no more than 8
+ */
+ if ((raid_vol_pg0->VolumeType != MPI2_RAID_VOL_TYPE_RAID0) ||
+ (raid_vol_pg0->NumPhysDisks > 8)) {
+ mps_dprint(sc, MPS_FAULT,
+ "Invalid WarpDrive configuration. Direct Drive I/O "
+ "will not be used.\n");
+ goto out;
+ }
+
+ /*
+ * Save the WD RAID data to be used during WD I/O.
+ */
+ sc->DD_max_lba = le64toh((uint64_t)raid_vol_pg0->MaxLBA.High <<
+ 32 | (uint64_t)raid_vol_pg0->MaxLBA.Low);
+ sc->DD_num_phys_disks = raid_vol_pg0->NumPhysDisks;
+ sc->DD_dev_handle = raid_vol_pg0->DevHandle;
+ sc->DD_stripe_size = raid_vol_pg0->StripeSize;
+ sc->DD_block_size = raid_vol_pg0->BlockSize;
+
+ /*
+ * Find power of 2 of stripe size and set this as the exponent.
+ * Fail if stripe size is 0.
+ */
+ stripe_size = raid_vol_pg0->StripeSize;
+ for (index = 0; index < 32; index++) {
+ if (stripe_size & 1)
+ break;
+ stripe_exp++;
+ stripe_size >>= 1;
+ }
+ if (index == 32) {
+ mps_dprint(sc, MPS_FAULT,
+ "RAID Volume's stripe size is 0. Direct Drive I/O "
+ "will not be used.\n");
+ goto out;
+ }
+ sc->DD_stripe_exponent = stripe_exp;
+
+ /*
+ * Find power of 2 of block size and set this as the exponent.
+ * Fail if block size is 0.
+ */
+ block_size = raid_vol_pg0->BlockSize;
+ for (index = 0; index < 16; index++) {
+ if (block_size & 1)
+ break;
+ block_exp++;
+ block_size >>= 1;
+ }
+ if (index == 16) {
+ mps_dprint(sc, MPS_FAULT,
+ "RAID Volume's block size is 0. Direct Drive I/O "
+ "will not be used.\n");
+ goto out;
+ }
+ sc->DD_block_exponent = block_exp;
+
+ /*
+ * Loop through all of the volume's Phys Disks to map the phys
+ * disk number into the columm map. This is used during Direct
+ * Drive I/O to send the request to the correct SSD.
+ */
+ pRVPD = (pMpi2RaidVol0PhysDisk_t)&raid_vol_pg0->PhysDisk;
+ for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
+ sc->DD_column_map[pRVPD->PhysDiskMap].phys_disk_num =
+ pRVPD->PhysDiskNum;
+ pRVPD++;
+ }
+
+ /*
+ * Get second RAID Volume Page0 using previous handle. This
+ * page should not exist. If it does, must not proceed with WD
+ * handling.
+ */
+ if (mps_config_get_raid_volume_pg0(sc, &mpi_reply,
+ raid_vol_pg0, (u32)raid_vol_pg0->DevHandle)) {
+ if (mpi_reply.IOCStatus !=
+ MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ mps_dprint(sc, MPS_FAULT,
+ "Multiple RAID Volume Page0! Direct Drive "
+ "I/O will not be used.\n");
+ goto out;
+ }
+ } else {
+ mps_dprint(sc, MPS_FAULT,
+ "Multiple volumes! Direct Drive I/O will not be "
+ "used.\n");
+ goto out;
+ }
+
+ /*
+ * Get RAID Volume Phys Disk Page 0 for all SSDs in the volume.
+ */
+ for (index = 0; index < raid_vol_pg0->NumPhysDisks; index++) {
+ phys_disk_page_address =
+ MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM +
+ sc->DD_column_map[index].phys_disk_num;
+ if (mps_config_get_raid_pd_pg0(sc, &mpi_reply,
+ &phys_disk_pg0, phys_disk_page_address)) {
+ mps_dprint(sc, MPS_FAULT,
+ "mps_config_get_raid_pd_pg0 failed! Direct "
+ "Drive I/O will not be used.\n");
+ goto out;
+ }
+ if (phys_disk_pg0.DevHandle == 0xFFFF) {
+ mps_dprint(sc, MPS_FAULT,
+ "Invalid Phys Disk DevHandle! Direct Drive "
+ "I/O will not be used.\n");
+ goto out;
+ }
+ sc->DD_column_map[index].dev_handle =
+ phys_disk_pg0.DevHandle;
+ }
+ sc->WD_valid_config = TRUE;
+out:
+ if (raid_vol_pg0)
+ kfree(raid_vol_pg0, M_MPT2);
+ }
+}
+
+/**
+ * mps_config_get_dpm_pg0 - obtain driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2DriverMappingPage0_t *config_page, u16 sz)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ Mpi2DriverMappingPage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ memset(config_page, 0, sz);
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->PageAddress = sc->max_dpm_entries <<
+ MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_NVRAM;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->PageAddress = sc->max_dpm_entries <<
+ MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ cm->cm_length = le16toh(request->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc(cm->cm_length, M_MPT2, M_ZERO|M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length, sz));
+out:
+ kfree(page, M_MPT2);
+ if (cm)
+ mps_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mps_config_set_dpm_pg0 - write an entry in driver persistent mapping page0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @entry_idx: entry index in DPM Page0 to be modified
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+
+int mps_config_set_dpm_pg0(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2DriverMappingPage0_t *config_page, u16 entry_idx)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->PageAddress |= htole16(entry_idx);
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_DRIVERMAPPING0_PAGEVERSION;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ request->PageAddress = 1 << MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT;
+ request->PageAddress |= htole16(entry_idx);
+ cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAOUT;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ bcopy(config_page, page, MIN(cm->cm_length,
+ (sizeof(Mpi2DriverMappingPage0_t))));
+ cm->cm_data = page;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: page written with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+out:
+ kfree(page, M_MPT2);
+ if (cm)
+ mps_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mps_config_get_sas_device_pg0 - obtain sas device page 0
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @form: GET_NEXT_HANDLE or HANDLE
+ * @handle: device handle
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_sas_device_pg0(struct mps_softc *sc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u16 handle)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ Mpi2SasDevicePage0_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ request->ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
+ request->Header.PageNumber = 0;
+ request->Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
+ request->ExtPageLength = mpi_reply->ExtPageLength;
+ request->PageAddress = htole32(form | handle);
+ cm->cm_length = le16toh(mpi_reply->ExtPageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: page read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ bcopy(page, config_page, MIN(cm->cm_length,
+ sizeof(Mpi2SasDevicePage0_t)));
+out:
+ kfree(page, M_MPT2);
+ if (cm)
+ mps_free_command(sc, cm);
+ return (error);
+}
+
+/**
+ * mps_config_get_bios_pg3 - obtain BIOS page 3
+ * @sc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mps_config_get_bios_pg3(struct mps_softc *sc, Mpi2ConfigReply_t *mpi_reply,
+ Mpi2BiosPage3_t *config_page)
+{
+ MPI2_CONFIG_REQUEST *request;
+ MPI2_CONFIG_REPLY *reply;
+ struct mps_command *cm;
+ Mpi2BiosPage3_t *page = NULL;
+ int error = 0;
+ u16 ioc_status;
+
+ mps_dprint(sc, MPS_TRACE, "%s\n", __func__);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+ request->Header.PageNumber = 3;
+ request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ cm->cm_data = NULL;
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for header completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: header read with error; iocstatus = 0x%x\n",
+ __func__, ioc_status);
+ error = ENXIO;
+ goto out;
+ }
+ /* We have to do free and alloc for the reply-free and reply-post
+ * counters to match - Need to review the reply FIFO handling.
+ */
+ mps_free_command(sc, cm);
+
+ if ((cm = mps_alloc_command(sc)) == NULL) {
+ kprintf("%s: command alloc failed @ line %d\n", __func__,
+ __LINE__);
+ error = EBUSY;
+ goto out;
+ }
+ request = (MPI2_CONFIG_REQUEST *)cm->cm_req;
+ bzero(request, sizeof(MPI2_CONFIG_REQUEST));
+ request->Function = MPI2_FUNCTION_CONFIG;
+ request->Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ request->Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
+ request->Header.PageNumber = 3;
+ request->Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
+ request->Header.PageLength = mpi_reply->Header.PageLength;
+ cm->cm_length = le16toh(mpi_reply->Header.PageLength) * 4;
+ cm->cm_sge = &request->PageBufferSGE;
+ cm->cm_sglsize = sizeof(MPI2_SGE_IO_UNION);
+ cm->cm_flags = MPS_CM_FLAGS_SGE_SIMPLE | MPS_CM_FLAGS_DATAIN;
+ cm->cm_desc.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
+ page = kmalloc(cm->cm_length, M_MPT2, M_ZERO | M_NOWAIT);
+ if (!page) {
+ kprintf("%s: page alloc failed\n", __func__);
+ error = ENOMEM;
+ goto out;
+ }
+ cm->cm_data = page;
+
+ error = mps_request_polled(sc, cm);
+ reply = (MPI2_CONFIG_REPLY *)cm->cm_reply;
+ if (error || (reply == NULL)) {
+ /* FIXME */
+ /* If the poll returns error then we need to do diag reset */
+ kprintf("%s: poll for page completed with error %d",
+ __func__, error);
+ error = ENXIO;
+ goto out;
+ }
+ ioc_status = le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
+ bcopy(reply, mpi_reply, sizeof(MPI2_CONFIG_REPLY));
+ if (ioc_status&n