summaryrefslogtreecommitdiffstats
path: root/sys/dev/mfi
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2012-03-30 23:05:48 +0000
committerambrisko <ambrisko@FreeBSD.org>2012-03-30 23:05:48 +0000
commitaf288dfa91cb30ed7346d095af475eacf258fcee (patch)
treee1b865ec95e3c7d85bba7e6ba5c14bc2630a1809 /sys/dev/mfi
parent8251950705577f472f1a2c4052195c05c3e41d32 (diff)
parent096734a154b76780bd2761cf8e196c6fd4e0562d (diff)
downloadFreeBSD-src-af288dfa91cb30ed7346d095af475eacf258fcee.zip
FreeBSD-src-af288dfa91cb30ed7346d095af475eacf258fcee.tar.gz
MFhead_mfi r227068
First cut of new HW support from LSI and merge into FreeBSD. Supports Drake Skinny and ThunderBolt cards. MFhead_mfi r227574 Style MFhead_mfi r227579 Use bus_addr_t instead of uintXX_t. MFhead_mfi r227580 MSI support MFhead_mfi r227612 More bus_addr_t and remove "#ifdef __amd64__". MFhead_mfi r227905 Improved timeout support from Scott. MFhead_mfi r228108 Make file. MFhead_mfi r228208 Fixed botched merge of Skinny support and enhanced handling in call back routine. MFhead_mfi r228279 Remove superfluous !TAILQ_EMPTY() checks before TAILQ_FOREACH(). MFhead_mfi r228310 Move mfi_decode_evt() to taskqueue. MFhead_mfi r228320 Implement MFI_DEBUG for 64bit S/G lists. MFhead_mfi r231988 Restore structure layout by reverting the array header to use [0] instead of [1]. MFhead_mfi r232412 Put wildcard pattern later in the match table. MFhead_mfi r232413 Use lower case for hexadecimal numbers to match surrounding style. MFhead_mfi r232414 Add more Thunderbolt variants. MFhead_mfi r232888 Don't act on events prior to boot or when shutting down. Add hw.mfi.detect_jbod_change to enable or disable acting on JBOD type of disks being added on insert and removed on removing. Switch hw.mfi.msi to 1 by default since it works better on newer cards. MFhead_mfi r233016 Release driver lock before taking Giant when deleting children. Use TAILQ_FOREACH_SAFE when items can be deleted. Make code a little simplier to follow. Fix a couple more style issues. MFhead_mfi r233620 Update mfi_spare/mfi_array with the actual number of elements for array_ref and pd. Change these max. #define names to avoid name space collisions. This will require an update to mfiutil It avoids mfiutil having to do a magic calculation. Add a note and #define to state that a "SYSTEM" disk is really what the firmware calls a "JBOD" drive. Thanks to the many that helped, LSI for the initial code drop, mav, delphij, jhb, sbruno that all helped with code and testing.
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r--sys/dev/mfi/mfi.c1445
-rw-r--r--sys/dev/mfi/mfi_cam.c6
-rw-r--r--sys/dev/mfi/mfi_debug.c20
-rw-r--r--sys/dev/mfi/mfi_disk.c21
-rw-r--r--sys/dev/mfi/mfi_ioctl.h17
-rw-r--r--sys/dev/mfi/mfi_linux.c1
-rw-r--r--sys/dev/mfi/mfi_pci.c39
-rw-r--r--sys/dev/mfi/mfi_syspd.c276
-rw-r--r--sys/dev/mfi/mfi_tbolt.c1345
-rw-r--r--sys/dev/mfi/mfireg.h659
-rw-r--r--sys/dev/mfi/mfivar.h199
11 files changed, 3767 insertions, 261 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index e55d7da..60ec822 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -53,6 +53,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
#include "opt_mfi.h"
#include <sys/param.h>
@@ -72,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include <sys/uio.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
@@ -79,10 +81,11 @@ __FBSDID("$FreeBSD$");
#include <dev/mfi/mfireg.h>
#include <dev/mfi/mfi_ioctl.h>
#include <dev/mfi/mfivar.h>
+#include <sys/interrupt.h>
+#include <sys/priority.h>
static int mfi_alloc_commands(struct mfi_softc *);
static int mfi_comms_init(struct mfi_softc *);
-static int mfi_wait_command(struct mfi_softc *, struct mfi_command *);
static int mfi_get_controller_info(struct mfi_softc *);
static int mfi_get_log_state(struct mfi_softc *,
struct mfi_evt_log_state **);
@@ -93,29 +96,39 @@ static void mfi_data_cb(void *, bus_dma_segment_t *, int, int);
static void mfi_startup(void *arg);
static void mfi_intr(void *arg);
static void mfi_ldprobe(struct mfi_softc *sc);
+static void mfi_syspdprobe(struct mfi_softc *sc);
+static void mfi_handle_evt(void *context, int pending);
static int mfi_aen_register(struct mfi_softc *sc, int seq, int locale);
static void mfi_aen_complete(struct mfi_command *);
-static int mfi_aen_setup(struct mfi_softc *, uint32_t);
static int mfi_add_ld(struct mfi_softc *sc, int);
static void mfi_add_ld_complete(struct mfi_command *);
+static int mfi_add_sys_pd(struct mfi_softc *sc, int);
+static void mfi_add_sys_pd_complete(struct mfi_command *);
static struct mfi_command * mfi_bio_command(struct mfi_softc *);
static void mfi_bio_complete(struct mfi_command *);
-static int mfi_mapcmd(struct mfi_softc *, struct mfi_command *);
+static struct mfi_command *mfi_build_ldio(struct mfi_softc *,struct bio*);
+static struct mfi_command *mfi_build_syspdio(struct mfi_softc *,struct bio*);
static int mfi_send_frame(struct mfi_softc *, struct mfi_command *);
-static void mfi_complete(struct mfi_softc *, struct mfi_command *);
static int mfi_abort(struct mfi_softc *, struct mfi_command *);
static int mfi_linux_ioctl_int(struct cdev *, u_long, caddr_t, int, struct thread *);
static void mfi_timeout(void *);
static int mfi_user_command(struct mfi_softc *,
struct mfi_ioc_passthru *);
-static void mfi_enable_intr_xscale(struct mfi_softc *sc);
-static void mfi_enable_intr_ppc(struct mfi_softc *sc);
-static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc);
-static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc);
-static int mfi_check_clear_intr_xscale(struct mfi_softc *sc);
-static int mfi_check_clear_intr_ppc(struct mfi_softc *sc);
-static void mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
-static void mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+static void mfi_enable_intr_xscale(struct mfi_softc *sc);
+static void mfi_enable_intr_ppc(struct mfi_softc *sc);
+static int32_t mfi_read_fw_status_xscale(struct mfi_softc *sc);
+static int32_t mfi_read_fw_status_ppc(struct mfi_softc *sc);
+static int mfi_check_clear_intr_xscale(struct mfi_softc *sc);
+static int mfi_check_clear_intr_ppc(struct mfi_softc *sc);
+static void mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add,
+ uint32_t frame_cnt);
+static void mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
+ uint32_t frame_cnt);
+static int mfi_config_lock(struct mfi_softc *sc, uint32_t opcode);
+static void mfi_config_unlock(struct mfi_softc *sc, int locked);
+static int mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm);
+static void mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm);
+static int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm);
SYSCTL_NODE(_hw, OID_AUTO, mfi, CTLFLAG_RD, 0, "MFI driver parameters");
static int mfi_event_locale = MFI_EVT_LOCALE_ALL;
@@ -133,6 +146,11 @@ TUNABLE_INT("hw.mfi.max_cmds", &mfi_max_cmds);
SYSCTL_INT(_hw_mfi, OID_AUTO, max_cmds, CTLFLAG_RD, &mfi_max_cmds,
0, "Max commands");
+static int mfi_detect_jbod_change = 1;
+TUNABLE_INT("hw.mfi.detect_jbod_change", &mfi_detect_jbod_change);
+SYSCTL_INT(_hw_mfi, OID_AUTO, detect_jbod_change, CTLFLAG_RW,
+ &mfi_detect_jbod_change, 0, "Detect a change to a JBOD");
+
/* Management interface */
static d_open_t mfi_open;
static d_close_t mfi_close;
@@ -152,6 +170,7 @@ static struct cdevsw mfi_cdevsw = {
MALLOC_DEFINE(M_MFIBUF, "mfibuf", "Buffers for the MFI driver");
#define MFI_INQ_LENGTH SHORT_INQUIRY_LENGTH
+struct mfi_skinny_dma_info mfi_skinny;
static void
mfi_enable_intr_xscale(struct mfi_softc *sc)
@@ -162,12 +181,17 @@ mfi_enable_intr_xscale(struct mfi_softc *sc)
static void
mfi_enable_intr_ppc(struct mfi_softc *sc)
{
- MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
if (sc->mfi_flags & MFI_FLAGS_1078) {
+ MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
- } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+ }
+ else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+ MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
}
+ else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+ MFI_WRITE4(sc, MFI_OMSK, ~0x00000001);
+ }
}
static int32_t
@@ -205,35 +229,51 @@ mfi_check_clear_intr_ppc(struct mfi_softc *sc)
if (!(status & MFI_1078_RM)) {
return 1;
}
- } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+ }
+ else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
if (!(status & MFI_GEN2_RM)) {
return 1;
}
}
-
- MFI_WRITE4(sc, MFI_ODCR0, status);
+ else if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+ if (!(status & MFI_SKINNY_RM)) {
+ return 1;
+ }
+ }
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+ MFI_WRITE4(sc, MFI_OSTS, status);
+ else
+ MFI_WRITE4(sc, MFI_ODCR0, status);
return 0;
}
static void
-mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+mfi_issue_cmd_xscale(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
{
MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
}
static void
-mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
+mfi_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add, uint32_t frame_cnt)
{
- MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+ MFI_WRITE4(sc, MFI_IQPL, (bus_add | frame_cnt <<1)|1 );
+ MFI_WRITE4(sc, MFI_IQPH, 0x00000000);
+ } else {
+ MFI_WRITE4(sc, MFI_IQP, (bus_add | frame_cnt <<1)|1 );
+ }
}
-static int
+int
mfi_transition_firmware(struct mfi_softc *sc)
{
uint32_t fw_state, cur_state;
int max_wait, i;
+ uint32_t cur_abs_reg_val = 0;
+ uint32_t prev_abs_reg_val = 0;
- fw_state = sc->mfi_read_fw_status(sc)& MFI_FWSTATE_MASK;
+ cur_abs_reg_val = sc->mfi_read_fw_status(sc);
+ fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
while (fw_state != MFI_FWSTATE_READY) {
if (bootverbose)
device_printf(sc->mfi_dev, "Waiting for firmware to "
@@ -244,38 +284,60 @@ mfi_transition_firmware(struct mfi_softc *sc)
device_printf(sc->mfi_dev, "Firmware fault\n");
return (ENXIO);
case MFI_FWSTATE_WAIT_HANDSHAKE:
- MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
- max_wait = 2;
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
+ MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
+ else
+ MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_CLEAR_HANDSHAKE);
+ max_wait = MFI_RESET_WAIT_TIME;
break;
case MFI_FWSTATE_OPERATIONAL:
- MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
- max_wait = 10;
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
+ MFI_WRITE4(sc, MFI_SKINNY_IDB, 7);
+ else
+ MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_READY);
+ max_wait = MFI_RESET_WAIT_TIME;
break;
case MFI_FWSTATE_UNDEFINED:
case MFI_FWSTATE_BB_INIT:
- max_wait = 2;
+ max_wait = MFI_RESET_WAIT_TIME;
+ break;
+ case MFI_FWSTATE_FW_INIT_2:
+ max_wait = MFI_RESET_WAIT_TIME;
break;
case MFI_FWSTATE_FW_INIT:
- case MFI_FWSTATE_DEVICE_SCAN:
case MFI_FWSTATE_FLUSH_CACHE:
- max_wait = 20;
+ max_wait = MFI_RESET_WAIT_TIME;
+ break;
+ case MFI_FWSTATE_DEVICE_SCAN:
+ max_wait = MFI_RESET_WAIT_TIME; /* wait for 180 seconds */
+ prev_abs_reg_val = cur_abs_reg_val;
break;
case MFI_FWSTATE_BOOT_MESSAGE_PENDING:
- MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
- max_wait = 10;
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY || sc->mfi_flags & MFI_FLAGS_TBOLT)
+ MFI_WRITE4(sc, MFI_SKINNY_IDB, MFI_FWINIT_HOTPLUG);
+ else
+ MFI_WRITE4(sc, MFI_IDB, MFI_FWINIT_HOTPLUG);
+ max_wait = MFI_RESET_WAIT_TIME;
break;
default:
- device_printf(sc->mfi_dev,"Unknown firmware state %#x\n",
+ device_printf(sc->mfi_dev, "Unknown firmware state %#x\n",
fw_state);
return (ENXIO);
}
for (i = 0; i < (max_wait * 10); i++) {
- fw_state = sc->mfi_read_fw_status(sc) & MFI_FWSTATE_MASK;
+ cur_abs_reg_val = sc->mfi_read_fw_status(sc);
+ fw_state = cur_abs_reg_val & MFI_FWSTATE_MASK;
if (fw_state == cur_state)
DELAY(100000);
else
break;
}
+ if (fw_state == MFI_FWSTATE_DEVICE_SCAN) {
+ /* Check the device scanning progress */
+ if (prev_abs_reg_val != cur_abs_reg_val) {
+ continue;
+ }
+ }
if (fw_state == cur_state) {
device_printf(sc->mfi_dev, "Firmware stuck in state "
"%#x\n", fw_state);
@@ -286,26 +348,35 @@ mfi_transition_firmware(struct mfi_softc *sc)
}
static void
-mfi_addr32_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
+mfi_addr_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
{
- uint32_t *addr;
+ bus_addr_t *addr;
addr = arg;
*addr = segs[0].ds_addr;
}
+
int
mfi_attach(struct mfi_softc *sc)
{
uint32_t status;
int error, commsz, framessz, sensesz;
int frames, unit, max_fw_sge;
+ uint32_t tb_mem_size = 0;
- device_printf(sc->mfi_dev, "Megaraid SAS driver Ver 3.00 \n");
+ if (sc == NULL)
+ return EINVAL;
+
+ device_printf(sc->mfi_dev, "Megaraid SAS driver Ver %s \n",
+ MEGASAS_VERSION);
mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF);
sx_init(&sc->mfi_config_lock, "MFI config");
TAILQ_INIT(&sc->mfi_ld_tqh);
+ TAILQ_INIT(&sc->mfi_syspd_tqh);
+ TAILQ_INIT(&sc->mfi_evt_queue);
+ TASK_INIT(&sc->mfi_evt_task, 0, mfi_handle_evt, sc);
TAILQ_INIT(&sc->mfi_aen_pids);
TAILQ_INIT(&sc->mfi_cam_ccbq);
@@ -314,15 +385,29 @@ mfi_attach(struct mfi_softc *sc)
mfi_initq_busy(sc);
mfi_initq_bio(sc);
+ sc->adpreset = 0;
+ sc->last_seq_num = 0;
+ sc->disableOnlineCtrlReset = 1;
+ sc->issuepend_done = 1;
+ sc->hw_crit_error = 0;
+
if (sc->mfi_flags & MFI_FLAGS_1064R) {
sc->mfi_enable_intr = mfi_enable_intr_xscale;
sc->mfi_read_fw_status = mfi_read_fw_status_xscale;
sc->mfi_check_clear_intr = mfi_check_clear_intr_xscale;
sc->mfi_issue_cmd = mfi_issue_cmd_xscale;
- }
- else {
+ } else if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
+ sc->mfi_enable_intr = mfi_tbolt_enable_intr_ppc;
+ sc->mfi_disable_intr = mfi_tbolt_disable_intr_ppc;
+ sc->mfi_read_fw_status = mfi_tbolt_read_fw_status_ppc;
+ sc->mfi_check_clear_intr = mfi_tbolt_check_clear_intr_ppc;
+ sc->mfi_issue_cmd = mfi_tbolt_issue_cmd_ppc;
+ sc->mfi_adp_reset = mfi_tbolt_adp_reset;
+ sc->mfi_tbolt = 1;
+ TAILQ_INIT(&sc->mfi_cmd_tbolt_tqh);
+ } else {
sc->mfi_enable_intr = mfi_enable_intr_ppc;
- sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
+ sc->mfi_read_fw_status = mfi_read_fw_status_ppc;
sc->mfi_check_clear_intr = mfi_check_clear_intr_ppc;
sc->mfi_issue_cmd = mfi_issue_cmd_ppc;
}
@@ -335,6 +420,32 @@ mfi_attach(struct mfi_softc *sc)
return (ENXIO);
}
+ /* Start: LSIP200113393 */
+ if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsize */
+ 1, /* msegments */
+ MEGASAS_MAX_NAME*sizeof(bus_addr_t), /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->verbuf_h_dmat)) {
+ device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmat DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->verbuf_h_dmat, (void **)&sc->verbuf,
+ BUS_DMA_NOWAIT, &sc->verbuf_h_dmamap)) {
+ device_printf(sc->mfi_dev, "Cannot allocate verbuf_h_dmamap memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t));
+ bus_dmamap_load(sc->verbuf_h_dmat, sc->verbuf_h_dmamap,
+ sc->verbuf, MEGASAS_MAX_NAME*sizeof(bus_addr_t),
+ mfi_addr_cb, &sc->verbuf_h_busaddr, 0);
+ /* End: LSIP200113393 */
+
/*
* Get information needed for sizing the contiguous memory for the
* frame pool. Size down the sgl parameter since we know that
@@ -347,6 +458,100 @@ mfi_attach(struct mfi_softc *sc)
max_fw_sge = (status & MFI_FWSTATE_MAXSGL_MASK) >> 16;
sc->mfi_max_sge = min(max_fw_sge, ((MFI_MAXPHYS / PAGE_SIZE) + 1));
+ /* ThunderBolt Support get the contiguous memory */
+
+ if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
+ mfi_tbolt_init_globals(sc);
+ device_printf(sc->mfi_dev, "MaxCmd = %x MaxSgl = %x state = %x \n",
+ sc->mfi_max_fw_cmds, sc->mfi_max_sge, status);
+ tb_mem_size = mfi_tbolt_get_memory_requirement(sc);
+
+ if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ tb_mem_size, /* maxsize */
+ 1, /* msegments */
+ tb_mem_size, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->mfi_tb_dmat)) {
+ device_printf(sc->mfi_dev, "Cannot allocate comms DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->mfi_tb_dmat, (void **)&sc->request_message_pool,
+ BUS_DMA_NOWAIT, &sc->mfi_tb_dmamap)) {
+ device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->request_message_pool, tb_mem_size);
+ bus_dmamap_load(sc->mfi_tb_dmat, sc->mfi_tb_dmamap,
+ sc->request_message_pool, tb_mem_size, mfi_addr_cb, &sc->mfi_tb_busaddr, 0);
+
+ /* For ThunderBolt memory init */
+ if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
+ 0x100, 0, /* alignmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MFI_FRAME_SIZE, /* maxsize */
+ 1, /* msegments */
+ MFI_FRAME_SIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->mfi_tb_init_dmat)) {
+ device_printf(sc->mfi_dev, "Cannot allocate init DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->mfi_tb_init_dmat, (void **)&sc->mfi_tb_init,
+ BUS_DMA_NOWAIT, &sc->mfi_tb_init_dmamap)) {
+ device_printf(sc->mfi_dev, "Cannot allocate init memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->mfi_tb_init, MFI_FRAME_SIZE);
+ bus_dmamap_load(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap,
+ sc->mfi_tb_init, MFI_FRAME_SIZE, mfi_addr_cb,
+ &sc->mfi_tb_init_busaddr, 0);
+ if (mfi_tbolt_init_desc_pool(sc, sc->request_message_pool,
+ tb_mem_size)) {
+ device_printf(sc->mfi_dev,
+ "Thunderbolt pool preparation error\n");
+ return 0;
+ }
+
+ /*
+ Allocate DMA memory mapping for MPI2 IOC Init descriptor,
+ we are taking it diffrent from what we have allocated for Request
+ and reply descriptors to avoid confusion later
+ */
+ tb_mem_size = sizeof(struct MPI2_IOC_INIT_REQUEST);
+ if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ tb_mem_size, /* maxsize */
+ 1, /* msegments */
+ tb_mem_size, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->mfi_tb_ioc_init_dmat)) {
+ device_printf(sc->mfi_dev,
+ "Cannot allocate comms DMA tag\n");
+ return (ENOMEM);
+ }
+ if (bus_dmamem_alloc(sc->mfi_tb_ioc_init_dmat,
+ (void **)&sc->mfi_tb_ioc_init_desc,
+ BUS_DMA_NOWAIT, &sc->mfi_tb_ioc_init_dmamap)) {
+ device_printf(sc->mfi_dev, "Cannot allocate comms memory\n");
+ return (ENOMEM);
+ }
+ bzero(sc->mfi_tb_ioc_init_desc, tb_mem_size);
+ bus_dmamap_load(sc->mfi_tb_ioc_init_dmat, sc->mfi_tb_ioc_init_dmamap,
+ sc->mfi_tb_ioc_init_desc, tb_mem_size, mfi_addr_cb,
+ &sc->mfi_tb_ioc_init_busaddr, 0);
+ }
/*
* Create the dma tag for data buffers. Used both for block I/O
* and for various internal data queries.
@@ -396,8 +601,7 @@ mfi_attach(struct mfi_softc *sc)
}
bzero(sc->mfi_comms, commsz);
bus_dmamap_load(sc->mfi_comms_dmat, sc->mfi_comms_dmamap,
- sc->mfi_comms, commsz, mfi_addr32_cb, &sc->mfi_comms_busaddr, 0);
-
+ sc->mfi_comms, commsz, mfi_addr_cb, &sc->mfi_comms_busaddr, 0);
/*
* Allocate DMA memory for the command frames. Keep them in the
* lower 4GB for efficiency. Calculate the size of the commands at
@@ -414,6 +618,8 @@ mfi_attach(struct mfi_softc *sc)
} else {
sc->mfi_sge_size = sizeof(struct mfi_sg32);
}
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+ sc->mfi_sge_size = sizeof(struct mfi_sg_skinny);
frames = (sc->mfi_sge_size * sc->mfi_max_sge - 1) / MFI_FRAME_SIZE + 2;
sc->mfi_cmd_size = frames * MFI_FRAME_SIZE;
framessz = sc->mfi_cmd_size * sc->mfi_max_fw_cmds;
@@ -438,8 +644,7 @@ mfi_attach(struct mfi_softc *sc)
}
bzero(sc->mfi_frames, framessz);
bus_dmamap_load(sc->mfi_frames_dmat, sc->mfi_frames_dmamap,
- sc->mfi_frames, framessz, mfi_addr32_cb, &sc->mfi_frames_busaddr,0);
-
+ sc->mfi_frames, framessz, mfi_addr_cb, &sc->mfi_frames_busaddr,0);
/*
* Allocate DMA memory for the frame sense data. Keep them in the
* lower 4GB for efficiency
@@ -465,32 +670,47 @@ mfi_attach(struct mfi_softc *sc)
return (ENOMEM);
}
bus_dmamap_load(sc->mfi_sense_dmat, sc->mfi_sense_dmamap,
- sc->mfi_sense, sensesz, mfi_addr32_cb, &sc->mfi_sense_busaddr, 0);
-
+ sc->mfi_sense, sensesz, mfi_addr_cb, &sc->mfi_sense_busaddr, 0);
if ((error = mfi_alloc_commands(sc)) != 0)
return (error);
- if ((error = mfi_comms_init(sc)) != 0)
- return (error);
+ /* Before moving the FW to operational state, check whether
+ * hostmemory is required by the FW or not
+ */
- if ((error = mfi_get_controller_info(sc)) != 0)
- return (error);
+ /* ThunderBolt MFI_IOC2 INIT */
+ if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
+ sc->mfi_disable_intr(sc);
+ if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0) {
+ device_printf(sc->mfi_dev,
+ "TB Init has failed with error %d\n",error);
+ return error;
+ }
- mtx_lock(&sc->mfi_io_lock);
- if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
- mtx_unlock(&sc->mfi_io_lock);
- return (error);
- }
- mtx_unlock(&sc->mfi_io_lock);
+ if ((error = mfi_tbolt_alloc_cmd(sc)) != 0)
+ return error;
+ if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
+ INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr_tbolt, sc,
+ &sc->mfi_intr)) {
+ device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
+ return (EINVAL);
+ }
+ sc->mfi_enable_intr(sc);
+ sc->map_id = 0;
+ } else {
+ if ((error = mfi_comms_init(sc)) != 0)
+ return (error);
- /*
- * Set up the interrupt handler.
- */
- if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq, INTR_MPSAFE|INTR_TYPE_BIO,
- NULL, mfi_intr, sc, &sc->mfi_intr)) {
- device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
- return (EINVAL);
+ if (bus_setup_intr(sc->mfi_dev, sc->mfi_irq,
+ INTR_MPSAFE|INTR_TYPE_BIO, NULL, mfi_intr, sc, &sc->mfi_intr)) {
+ device_printf(sc->mfi_dev, "Cannot set up interrupt\n");
+ return (EINVAL);
+ }
+ sc->mfi_enable_intr(sc);
}
+ if ((error = mfi_get_controller_info(sc)) != 0)
+ return (error);
+ sc->disableOnlineCtrlReset = 0;
/* Register a config hook to probe the bus for arrays */
sc->mfi_ich.ich_func = mfi_startup;
@@ -500,6 +720,10 @@ mfi_attach(struct mfi_softc *sc)
"hook\n");
return (EINVAL);
}
+ if ((error = mfi_aen_setup(sc, 0), 0) != 0) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (error);
+ }
/*
* Register a shutdown handler.
@@ -571,8 +795,11 @@ mfi_alloc_commands(struct mfi_softc *sc)
cm->cm_sc = sc;
cm->cm_index = i;
if (bus_dmamap_create(sc->mfi_buffer_dmat, 0,
- &cm->cm_dmamap) == 0)
+ &cm->cm_dmamap) == 0) {
+ mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ }
else
break;
sc->mfi_total_cmds++;
@@ -587,6 +814,8 @@ mfi_release_command(struct mfi_command *cm)
struct mfi_frame_header *hdr;
uint32_t *hdr_data;
+ mtx_assert(&cm->cm_sc->mfi_io_lock, MA_OWNED);
+
/*
* Zero out the important fields of the frame, but make sure the
* context field is preserved. For efficiency, handle the fields
@@ -611,24 +840,31 @@ mfi_release_command(struct mfi_command *cm)
cm->cm_data = NULL;
cm->cm_sg = 0;
cm->cm_total_frame_size = 0;
+ cm->retry_for_fw_reset = 0;
mfi_enqueue_free(cm);
}
static int
-mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode,
- void **bufp, size_t bufsize)
+mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp,
+ uint32_t opcode, void **bufp, size_t bufsize)
{
struct mfi_command *cm;
struct mfi_dcmd_frame *dcmd;
void *buf = NULL;
-
+ uint32_t context = 0;
+
mtx_assert(&sc->mfi_io_lock, MA_OWNED);
-
+
cm = mfi_dequeue_free(sc);
if (cm == NULL)
return (EBUSY);
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+
if ((bufsize > 0) && (bufp != NULL)) {
if (*bufp == NULL) {
buf = malloc(bufsize, M_MFIBUF, M_NOWAIT|M_ZERO);
@@ -648,6 +884,7 @@ mfi_dcmd_command(struct mfi_softc *sc, struct mfi_command **cmp, uint32_t opcode
dcmd->header.timeout = 0;
dcmd->header.flags = 0;
dcmd->header.data_len = bufsize;
+ dcmd->header.scsi_status = 0;
dcmd->opcode = opcode;
cm->cm_sg = &dcmd->sgl;
cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE;
@@ -669,11 +906,17 @@ mfi_comms_init(struct mfi_softc *sc)
struct mfi_init_frame *init;
struct mfi_init_qinfo *qinfo;
int error;
+ uint32_t context = 0;
mtx_lock(&sc->mfi_io_lock);
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+
/*
* Abuse the SG list area of the frame to hold the init_qinfo
* object;
@@ -734,9 +977,11 @@ mfi_get_controller_info(struct mfi_softc *sc)
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
- max_sectors_1 = (1 << ci->stripe_sz_ops.min) * ci->max_strips_per_io;
+ max_sectors_1 = (1 << ci->stripe_sz_ops.max) * ci->max_strips_per_io;
max_sectors_2 = ci->max_request_size;
sc->mfi_max_io = min(max_sectors_1, max_sectors_2);
+ sc->disableOnlineCtrlReset =
+ ci->properties.OnOffProperties.disableOnlineCtrlReset;
out:
if (ci)
@@ -753,6 +998,7 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
struct mfi_command *cm = NULL;
int error;
+ mtx_lock(&sc->mfi_io_lock);
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_GETINFO,
(void **)log_state, sizeof(**log_state));
if (error)
@@ -771,11 +1017,12 @@ mfi_get_log_state(struct mfi_softc *sc, struct mfi_evt_log_state **log_state)
out:
if (cm)
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
return (error);
}
-static int
+int
mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
{
struct mfi_evt_log_state *log_state = NULL;
@@ -789,6 +1036,7 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
if (seq_start == 0) {
error = mfi_get_log_state(sc, &log_state);
+ sc->mfi_boot_seq_num = log_state->boot_seq_num;
if (error) {
if (log_state)
free(log_state, M_MFIBUF);
@@ -810,7 +1058,7 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start)
return 0;
}
-static int
+int
mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
{
@@ -883,6 +1131,64 @@ mfi_free(struct mfi_softc *sc)
if (sc->mfi_comms_dmat != NULL)
bus_dma_tag_destroy(sc->mfi_comms_dmat);
+ /* ThunderBolt contiguous memory free here */
+ if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
+ if (sc->mfi_tb_busaddr != 0)
+ bus_dmamap_unload(sc->mfi_tb_dmat, sc->mfi_tb_dmamap);
+ if (sc->request_message_pool != NULL)
+ bus_dmamem_free(sc->mfi_tb_dmat, sc->request_message_pool,
+ sc->mfi_tb_dmamap);
+ if (sc->mfi_tb_dmat != NULL)
+ bus_dma_tag_destroy(sc->mfi_tb_dmat);
+
+ /* Version buffer memory free */
+ /* Start LSIP200113393 */
+ if (sc->verbuf_h_busaddr != 0)
+ bus_dmamap_unload(sc->verbuf_h_dmat, sc->verbuf_h_dmamap);
+ if (sc->verbuf != NULL)
+ bus_dmamem_free(sc->verbuf_h_dmat, sc->verbuf,
+ sc->verbuf_h_dmamap);
+ if (sc->verbuf_h_dmat != NULL)
+ bus_dma_tag_destroy(sc->verbuf_h_dmat);
+
+ /* End LSIP200113393 */
+ /* ThunderBolt INIT packet memory Free */
+ if (sc->mfi_tb_init_busaddr != 0)
+ bus_dmamap_unload(sc->mfi_tb_init_dmat, sc->mfi_tb_init_dmamap);
+ if (sc->mfi_tb_init != NULL)
+ bus_dmamem_free(sc->mfi_tb_init_dmat, sc->mfi_tb_init,
+ sc->mfi_tb_init_dmamap);
+ if (sc->mfi_tb_init_dmat != NULL)
+ bus_dma_tag_destroy(sc->mfi_tb_init_dmat);
+
+ /* ThunderBolt IOC Init Desc memory free here */
+ if (sc->mfi_tb_ioc_init_busaddr != 0)
+ bus_dmamap_unload(sc->mfi_tb_ioc_init_dmat,
+ sc->mfi_tb_ioc_init_dmamap);
+ if (sc->mfi_tb_ioc_init_desc != NULL)
+ bus_dmamem_free(sc->mfi_tb_ioc_init_dmat,
+ sc->mfi_tb_ioc_init_desc,
+ sc->mfi_tb_ioc_init_dmamap);
+ if (sc->mfi_tb_ioc_init_dmat != NULL)
+ bus_dma_tag_destroy(sc->mfi_tb_ioc_init_dmat);
+ for (int i = 0; i < sc->mfi_max_fw_cmds; i++) {
+ if (sc->mfi_cmd_pool_tbolt != NULL) {
+ if (sc->mfi_cmd_pool_tbolt[i] != NULL) {
+ free(sc->mfi_cmd_pool_tbolt[i],
+ M_MFIBUF);
+ sc->mfi_cmd_pool_tbolt[i] = NULL;
+ }
+ }
+ }
+ if (sc->mfi_cmd_pool_tbolt != NULL) {
+ free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
+ sc->mfi_cmd_pool_tbolt = NULL;
+ }
+ if (sc->request_desc_pool != NULL) {
+ free(sc->request_desc_pool, M_MFIBUF);
+ sc->request_desc_pool = NULL;
+ }
+ }
if (sc->mfi_buffer_dmat != NULL)
bus_dma_tag_destroy(sc->mfi_buffer_dmat);
if (sc->mfi_parent_dmat != NULL)
@@ -909,6 +1215,8 @@ mfi_startup(void *arg)
sx_xlock(&sc->mfi_config_lock);
mtx_lock(&sc->mfi_io_lock);
mfi_ldprobe(sc);
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY)
+ mfi_syspdprobe(sc);
mtx_unlock(&sc->mfi_io_lock);
sx_xunlock(&sc->mfi_config_lock);
}
@@ -925,12 +1233,7 @@ mfi_intr(void *arg)
if (sc->mfi_check_clear_intr(sc))
return;
- /*
- * Do a dummy read to flush the interrupt ACK that we just performed,
- * ensuring that everything is really, truly consistent.
- */
- (void)sc->mfi_read_fw_status(sc);
-
+restart:
pi = sc->mfi_comms->hw_pi;
ci = sc->mfi_comms->hw_ci;
mtx_lock(&sc->mfi_io_lock);
@@ -955,6 +1258,14 @@ mfi_intr(void *arg)
mfi_startio(sc);
mtx_unlock(&sc->mfi_io_lock);
+ /*
+ * Dummy read to flush the bus; this ensures that the indexes are up
+ * to date. Restart processing if more commands have come it.
+ */
+ (void)sc->mfi_read_fw_status(sc);
+ if (pi != sc->mfi_comms->hw_pi)
+ goto restart;
+
return;
}
@@ -975,6 +1286,9 @@ mfi_shutdown(struct mfi_softc *sc)
if (sc->mfi_aen_cm != NULL)
mfi_abort(sc, sc->mfi_aen_cm);
+ if (sc->map_update_cmd != NULL)
+ mfi_abort(sc, sc->map_update_cmd);
+
dcmd = &cm->cm_frame->dcmd;
dcmd->header.flags = MFI_FRAME_DIR_NONE;
cm->cm_flags = MFI_CMD_POLLED;
@@ -990,6 +1304,81 @@ mfi_shutdown(struct mfi_softc *sc)
}
static void
+mfi_syspdprobe(struct mfi_softc *sc)
+{
+ struct mfi_frame_header *hdr;
+ struct mfi_command *cm = NULL;
+ struct mfi_pd_list *pdlist = NULL;
+ struct mfi_system_pd *syspd, *tmp;
+ int error, i, found;
+
+ sx_assert(&sc->mfi_config_lock, SA_XLOCKED);
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ /* Add SYSTEM PD's */
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_LIST_QUERY,
+ (void **)&pdlist, sizeof(*pdlist));
+ if (error){
+ device_printf(sc->mfi_dev,
+ "Error while forming SYSTEM PD list\n");
+ goto out;
+ }
+
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+ cm->cm_frame->dcmd.mbox[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST;
+ cm->cm_frame->dcmd.mbox[1] = 0;
+ if (mfi_mapcmd(sc, cm) != 0) {
+ device_printf(sc->mfi_dev,
+ "Failed to get syspd device listing\n");
+ goto out;
+ }
+ bus_dmamap_sync(sc->mfi_buffer_dmat,cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+ hdr = &cm->cm_frame->header;
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ device_printf(sc->mfi_dev,
+ "MFI_DCMD_PD_LIST_QUERY failed %x\n", hdr->cmd_status);
+ goto out;
+ }
+ /* Get each PD and add it to the system */
+ for (i = 0; i < pdlist->count; i++) {
+ if (pdlist->addr[i].device_id ==
+ pdlist->addr[i].encl_device_id)
+ continue;
+ found = 0;
+ TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
+ if (syspd->pd_id == pdlist->addr[i].device_id)
+ found = 1;
+ }
+ if (found == 0)
+ mfi_add_sys_pd(sc, pdlist->addr[i].device_id);
+ }
+ /* Delete SYSPD's whose state has been changed */
+ TAILQ_FOREACH_SAFE(syspd, &sc->mfi_syspd_tqh, pd_link, tmp) {
+ found = 0;
+ for (i = 0; i < pdlist->count; i++) {
+ if (syspd->pd_id == pdlist->addr[i].device_id)
+ found = 1;
+ }
+ if (found == 0) {
+ printf("DELETE\n");
+ mtx_unlock(&sc->mfi_io_lock);
+ mtx_lock(&Giant);
+ device_delete_child(sc->mfi_dev, syspd->pd_dev);
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+ }
+ }
+out:
+ if (pdlist)
+ free(pdlist, M_MFIBUF);
+ if (cm)
+ mfi_release_command(cm);
+
+ return;
+}
+
+static void
mfi_ldprobe(struct mfi_softc *sc)
{
struct mfi_frame_header *hdr;
@@ -1083,10 +1472,124 @@ format_class(int8_t class)
static void
mfi_decode_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
{
+ struct mfi_system_pd *syspd = NULL;
device_printf(sc->mfi_dev, "%d (%s/0x%04x/%s) - %s\n", detail->seq,
format_timestamp(detail->time), detail->evt_class.members.locale,
- format_class(detail->evt_class.members.evt_class), detail->description);
+ format_class(detail->evt_class.members.evt_class),
+ detail->description);
+
+ /* Don't act on old AEN's or while shutting down */
+ if (detail->seq < sc->mfi_boot_seq_num || sc->mfi_detaching)
+ return;
+
+ switch (detail->arg_type) {
+ case MR_EVT_ARGS_NONE:
+ if (detail->code == MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED) {
+ device_printf(sc->mfi_dev, "HostBus scan raised\n");
+ if (mfi_detect_jbod_change) {
+ /*
+ * Probe for new SYSPD's and Delete
+ * invalid SYSPD's
+ */
+ sx_xlock(&sc->mfi_config_lock);
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_syspdprobe(sc);
+ mtx_unlock(&sc->mfi_io_lock);
+ sx_xunlock(&sc->mfi_config_lock);
+ }
+ }
+ break;
+ case MR_EVT_ARGS_LD_STATE:
+ /* During load time driver reads all the events starting
+ * from the one that has been logged after shutdown. Avoid
+ * these old events.
+ */
+ if (detail->args.ld_state.new_state == MFI_LD_STATE_OFFLINE ) {
+ /* Remove the LD */
+ struct mfi_disk *ld;
+ TAILQ_FOREACH(ld, &sc->mfi_ld_tqh, ld_link) {
+ if (ld->ld_id ==
+ detail->args.ld_state.ld.target_id)
+ break;
+ }
+ /*
+ Fix: for kernel panics when SSCD is removed
+ KASSERT(ld != NULL, ("volume dissappeared"));
+ */
+ if (ld != NULL) {
+ mtx_lock(&Giant);
+ device_delete_child(sc->mfi_dev, ld->ld_dev);
+ mtx_unlock(&Giant);
+ }
+ }
+ break;
+ case MR_EVT_ARGS_PD:
+ if (detail->code == MR_EVT_PD_REMOVED) {
+ if (mfi_detect_jbod_change) {
+ /*
+ * If the removed device is a SYSPD then
+ * delete it
+ */
+ TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,
+ pd_link) {
+ if (syspd->pd_id ==
+ detail->args.pd.device_id) {
+ mtx_lock(&Giant);
+ device_delete_child(
+ sc->mfi_dev,
+ syspd->pd_dev);
+ mtx_unlock(&Giant);
+ break;
+ }
+ }
+ }
+ }
+ if (detail->code == MR_EVT_PD_INSERTED) {
+ if (mfi_detect_jbod_change) {
+ /* Probe for new SYSPD's */
+ sx_xlock(&sc->mfi_config_lock);
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_syspdprobe(sc);
+ mtx_unlock(&sc->mfi_io_lock);
+ sx_xunlock(&sc->mfi_config_lock);
+ }
+ }
+ break;
+ }
+}
+
+static void
+mfi_queue_evt(struct mfi_softc *sc, struct mfi_evt_detail *detail)
+{
+ struct mfi_evt_queue_elm *elm;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ elm = malloc(sizeof(*elm), M_MFIBUF, M_NOWAIT|M_ZERO);
+ if (elm == NULL)
+ return;
+ memcpy(&elm->detail, detail, sizeof(*detail));
+ TAILQ_INSERT_TAIL(&sc->mfi_evt_queue, elm, link);
+ taskqueue_enqueue(taskqueue_swi, &sc->mfi_evt_task);
+}
+
+static void
+mfi_handle_evt(void *context, int pending)
+{
+ TAILQ_HEAD(,mfi_evt_queue_elm) queue;
+ struct mfi_softc *sc;
+ struct mfi_evt_queue_elm *elm;
+
+ sc = context;
+ TAILQ_INIT(&queue);
+ mtx_lock(&sc->mfi_io_lock);
+ TAILQ_CONCAT(&queue, &sc->mfi_evt_queue, link);
+ mtx_unlock(&sc->mfi_io_lock);
+ while ((elm = TAILQ_FIRST(&queue)) != NULL) {
+ TAILQ_REMOVE(&queue, elm, link);
+ mfi_decode_evt(sc, &elm->detail);
+ free(elm, M_MFIBUF);
+ }
}
static int
@@ -1112,12 +1615,16 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
< current_aen.members.evt_class)
current_aen.members.evt_class =
prior_aen.members.evt_class;
+ mtx_lock(&sc->mfi_io_lock);
mfi_abort(sc, sc->mfi_aen_cm);
+ mtx_unlock(&sc->mfi_io_lock);
}
}
+ mtx_lock(&sc->mfi_io_lock);
error = mfi_dcmd_command(sc, &cm, MFI_DCMD_CTRL_EVENT_WAIT,
(void **)&ed, sizeof(*ed));
+ mtx_unlock(&sc->mfi_io_lock);
if (error) {
goto out;
}
@@ -1128,10 +1635,13 @@ mfi_aen_register(struct mfi_softc *sc, int seq, int locale)
cm->cm_flags = MFI_CMD_DATAIN;
cm->cm_complete = mfi_aen_complete;
+ sc->last_seq_num = seq;
sc->mfi_aen_cm = cm;
+ mtx_lock(&sc->mfi_io_lock);
mfi_enqueue_ready(cm);
mfi_startio(sc);
+ mtx_unlock(&sc->mfi_io_lock);
out:
return (error);
@@ -1147,6 +1657,8 @@ mfi_aen_complete(struct mfi_command *cm)
int seq = 0, aborted = 0;
sc = cm->cm_sc;
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
hdr = &cm->cm_frame->header;
if (sc->mfi_aen_cm == NULL)
@@ -1163,13 +1675,10 @@ mfi_aen_complete(struct mfi_command *cm)
selwakeup(&sc->mfi_select);
}
detail = cm->cm_data;
- /*
- * XXX If this function is too expensive or is recursive, then
- * events should be put onto a queue and processed later.
- */
- mfi_decode_evt(sc, detail);
+ mfi_queue_evt(sc, detail);
seq = detail->seq + 1;
- TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link, tmp) {
+ TAILQ_FOREACH_SAFE(mfi_aen_entry, &sc->mfi_aen_pids, aen_link,
+ tmp) {
TAILQ_REMOVE(&sc->mfi_aen_pids, mfi_aen_entry,
aen_link);
PROC_LOCK(mfi_aen_entry->p);
@@ -1186,7 +1695,9 @@ mfi_aen_complete(struct mfi_command *cm)
/* set it up again so the driver can catch more events */
if (!aborted) {
+ mtx_unlock(&sc->mfi_io_lock);
mfi_aen_setup(sc, seq);
+ mtx_lock(&sc->mfi_io_lock);
}
}
@@ -1212,10 +1723,13 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
return (ENOMEM);
for (seq = start_seq;;) {
+ mtx_lock(&sc->mfi_io_lock);
if ((cm = mfi_dequeue_free(sc)) == NULL) {
free(el, M_MFIBUF);
+ mtx_unlock(&sc->mfi_io_lock);
return (EBUSY);
}
+ mtx_unlock(&sc->mfi_io_lock);
dcmd = &cm->cm_frame->dcmd;
bzero(dcmd->mbox, MFI_MBOX_SIZE);
@@ -1231,29 +1745,38 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
cm->cm_data = el;
cm->cm_len = size;
+ mtx_lock(&sc->mfi_io_lock);
if ((error = mfi_mapcmd(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Failed to get controller entries\n");
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
break;
}
+ mtx_unlock(&sc->mfi_io_lock);
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
BUS_DMASYNC_POSTREAD);
bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
if (dcmd->header.cmd_status == MFI_STAT_NOT_FOUND) {
+ mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
break;
}
if (dcmd->header.cmd_status != MFI_STAT_OK) {
device_printf(sc->mfi_dev,
"Error %d fetching controller entries\n",
dcmd->header.cmd_status);
+ mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
break;
}
+ mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
for (i = 0; i < el->count; i++) {
/*
@@ -1269,7 +1792,9 @@ mfi_parse_entries(struct mfi_softc *sc, int start_seq, int stop_seq)
else if (el->event[i].seq < start_seq)
break;
}
- mfi_decode_evt(sc, &el->event[i]);
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_queue_evt(sc, &el->event[i]);
+ mtx_unlock(&sc->mfi_io_lock);
}
seq = el->event[el->count - 1].seq + 1;
}
@@ -1306,8 +1831,13 @@ mfi_add_ld(struct mfi_softc *sc, int id)
free(ld_info, M_MFIBUF);
return (0);
}
-
- mfi_add_ld_complete(cm);
+ if (ld_info->ld_config.params.isSSCD != 1)
+ mfi_add_ld_complete(cm);
+ else {
+ mfi_release_command(cm);
+ if (ld_info) /* SSCD drives ld_info free here */
+ free(ld_info, M_MFIBUF);
+ }
return (0);
}
@@ -1347,22 +1877,183 @@ mfi_add_ld_complete(struct mfi_command *cm)
mtx_lock(&sc->mfi_io_lock);
}
+static int mfi_add_sys_pd(struct mfi_softc *sc, int id)
+{
+ struct mfi_command *cm;
+ struct mfi_dcmd_frame *dcmd = NULL;
+ struct mfi_pd_info *pd_info = NULL;
+ int error;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ error = mfi_dcmd_command(sc, &cm, MFI_DCMD_PD_GET_INFO,
+ (void **)&pd_info, sizeof(*pd_info));
+ if (error) {
+ device_printf(sc->mfi_dev,
+ "Failed to allocated for MFI_DCMD_PD_GET_INFO %d\n",
+ error);
+ if (pd_info)
+ free(pd_info, M_MFIBUF);
+ return (error);
+ }
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_POLLED;
+ dcmd = &cm->cm_frame->dcmd;
+ dcmd->mbox[0]=id;
+ dcmd->header.scsi_status = 0;
+ dcmd->header.pad0 = 0;
+ if (mfi_mapcmd(sc, cm) != 0) {
+ device_printf(sc->mfi_dev,
+ "Failed to get physical drive info %d\n", id);
+ free(pd_info, M_MFIBUF);
+ return (0);
+ }
+ bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+ mfi_add_sys_pd_complete(cm);
+ return (0);
+}
+
+static void
+mfi_add_sys_pd_complete(struct mfi_command *cm)
+{
+ struct mfi_frame_header *hdr;
+ struct mfi_pd_info *pd_info;
+ struct mfi_softc *sc;
+ device_t child;
+
+ sc = cm->cm_sc;
+ hdr = &cm->cm_frame->header;
+ pd_info = cm->cm_private;
+
+ if (hdr->cmd_status != MFI_STAT_OK) {
+ free(pd_info, M_MFIBUF);
+ mfi_release_command(cm);
+ return;
+ }
+ if (pd_info->fw_state != MFI_PD_STATE_SYSTEM) {
+ device_printf(sc->mfi_dev, "PD=%x is not SYSTEM PD\n",
+ pd_info->ref.v.device_id);
+ free(pd_info, M_MFIBUF);
+ mfi_release_command(cm);
+ return;
+ }
+ mfi_release_command(cm);
+
+ mtx_unlock(&sc->mfi_io_lock);
+ mtx_lock(&Giant);
+ if ((child = device_add_child(sc->mfi_dev, "mfisyspd", -1)) == NULL) {
+ device_printf(sc->mfi_dev, "Failed to add system pd\n");
+ free(pd_info, M_MFIBUF);
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+ return;
+ }
+
+ device_set_ivars(child, pd_info);
+ device_set_desc(child, "MFI System PD");
+ bus_generic_attach(sc->mfi_dev);
+ mtx_unlock(&Giant);
+ mtx_lock(&sc->mfi_io_lock);
+}
static struct mfi_command *
mfi_bio_command(struct mfi_softc *sc)
{
- struct mfi_io_frame *io;
- struct mfi_command *cm;
struct bio *bio;
- int flags, blkcount;
+ struct mfi_command *cm = NULL;
- if ((cm = mfi_dequeue_free(sc)) == NULL)
+ /*reserving two commands to avoid starvation for IOCTL*/
+ if (sc->mfi_qstat[MFIQ_FREE].q_length < 2){
return (NULL);
-
+ }
if ((bio = mfi_dequeue_bio(sc)) == NULL) {
- mfi_release_command(cm);
return (NULL);
}
+ if ((uintptr_t)bio->bio_driver2 == MFI_LD_IO) {
+ cm = mfi_build_ldio(sc, bio);
+ } else if ((uintptr_t) bio->bio_driver2 == MFI_SYS_PD_IO) {
+ cm = mfi_build_syspdio(sc, bio);
+ }
+ if (!cm)
+ mfi_enqueue_bio(sc, bio);
+ return cm;
+}
+static struct mfi_command *
+mfi_build_syspdio(struct mfi_softc *sc, struct bio *bio)
+{
+ struct mfi_command *cm;
+ struct mfi_pass_frame *pass;
+ int flags = 0, blkcount = 0;
+ uint32_t context = 0;
+
+ if ((cm = mfi_dequeue_free(sc)) == NULL)
+ return (NULL);
+
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+ pass = &cm->cm_frame->pass;
+ bzero(pass->cdb, 16);
+ pass->header.cmd = MFI_CMD_PD_SCSI_IO;
+ switch (bio->bio_cmd & 0x03) {
+ case BIO_READ:
+#define SCSI_READ 0x28
+ pass->cdb[0] = SCSI_READ;
+ flags = MFI_CMD_DATAIN;
+ break;
+ case BIO_WRITE:
+#define SCSI_WRITE 0x2a
+ pass->cdb[0] = SCSI_WRITE;
+ flags = MFI_CMD_DATAOUT;
+ break;
+ default:
+ panic("Invalid bio command");
+ }
+ /* Cheat with the sector length to avoid a non-constant division */
+ blkcount = (bio->bio_bcount + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
+ /* Fill the LBA and Transfer length in CDB */
+ pass->cdb[2] = (bio->bio_pblkno & 0xff000000) >> 24;
+ pass->cdb[3] = (bio->bio_pblkno & 0x00ff0000) >> 16;
+ pass->cdb[4] = (bio->bio_pblkno & 0x0000ff00) >> 8;
+ pass->cdb[5] = bio->bio_pblkno & 0x000000ff;
+ pass->cdb[7] = (blkcount & 0xff00) >> 8;
+ pass->cdb[8] = (blkcount & 0x00ff);
+ pass->header.target_id = (uintptr_t)bio->bio_driver1;
+ pass->header.timeout = 0;
+ pass->header.flags = 0;
+ pass->header.scsi_status = 0;
+ pass->header.sense_len = MFI_SENSE_LEN;
+ pass->header.data_len = bio->bio_bcount;
+ pass->header.cdb_len = 10;
+ pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
+ pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
+ cm->cm_complete = mfi_bio_complete;
+ cm->cm_private = bio;
+ cm->cm_data = bio->bio_data;
+ cm->cm_len = bio->bio_bcount;
+ cm->cm_sg = &pass->sgl;
+ cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+ cm->cm_flags = flags;
+ return (cm);
+}
+
+static struct mfi_command *
+mfi_build_ldio(struct mfi_softc *sc, struct bio *bio)
+{
+ struct mfi_io_frame *io;
+ struct mfi_command *cm;
+ int flags, blkcount;
+ uint32_t context = 0;
+
+ if ((cm = mfi_dequeue_free(sc)) == NULL)
+ return (NULL);
+
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
io = &cm->cm_frame->io;
switch (bio->bio_cmd & 0x03) {
case BIO_READ:
@@ -1382,10 +2073,11 @@ mfi_bio_command(struct mfi_softc *sc)
io->header.target_id = (uintptr_t)bio->bio_driver1;
io->header.timeout = 0;
io->header.flags = 0;
+ io->header.scsi_status = 0;
io->header.sense_len = MFI_SENSE_LEN;
io->header.data_len = blkcount;
- io->sense_addr_lo = cm->cm_sense_busaddr;
- io->sense_addr_hi = 0;
+ io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
+ io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
io->lba_hi = (bio->bio_pblkno & 0xffffffff00000000) >> 32;
io->lba_lo = bio->bio_pblkno & 0xffffffff;
cm->cm_complete = mfi_bio_complete;
@@ -1458,14 +2150,14 @@ mfi_startio(struct mfi_softc *sc)
}
}
-static int
+int
mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
{
int error, polled;
mtx_assert(&sc->mfi_io_lock, MA_OWNED);
- if (cm->cm_data != NULL) {
+ if ((cm->cm_data != NULL) && (cm->cm_frame->header.cmd != MFI_CMD_STP )) {
polled = (cm->cm_flags & MFI_CMD_POLLED) ? BUS_DMA_NOWAIT : 0;
error = bus_dmamap_load(sc->mfi_buffer_dmat, cm->cm_dmamap,
cm->cm_data, cm->cm_len, mfi_data_cb, cm, polled);
@@ -1474,7 +2166,10 @@ mfi_mapcmd(struct mfi_softc *sc, struct mfi_command *cm)
return (0);
}
} else {
- error = mfi_send_frame(sc, cm);
+ if (sc->MFA_enabled)
+ error = mfi_tbolt_send_frame(sc, cm);
+ else
+ error = mfi_send_frame(sc, cm);
}
return (error);
@@ -1488,6 +2183,7 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
union mfi_sgl *sgl;
struct mfi_softc *sc;
int i, j, first, dir;
+ int sge_size;
cm = (struct mfi_command *)arg;
sc = cm->cm_sc;
@@ -1500,34 +2196,54 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
mfi_complete(sc, cm);
return;
}
-
- j = 0;
- if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
- first = cm->cm_stp_len;
- if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
- sgl->sg32[j].addr = segs[0].ds_addr;
- sgl->sg32[j++].len = first;
- } else {
- sgl->sg64[j].addr = segs[0].ds_addr;
- sgl->sg64[j++].len = first;
- }
- } else
- first = 0;
- if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
+ /* Use IEEE sgl only for IO's on a SKINNY controller
+ * For other commands on a SKINNY controller use either
+ * sg32 or sg64 based on the sizeof(bus_addr_t).
+ * Also calculate the total frame size based on the type
+ * of SGL used.
+ */
+ if (((cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) ||
+ (cm->cm_frame->header.cmd == MFI_CMD_LD_READ) ||
+ (cm->cm_frame->header.cmd == MFI_CMD_LD_WRITE)) &&
+ (sc->mfi_flags & MFI_FLAGS_SKINNY)) {
for (i = 0; i < nsegs; i++) {
- sgl->sg32[j].addr = segs[i].ds_addr + first;
- sgl->sg32[j++].len = segs[i].ds_len - first;
- first = 0;
+ sgl->sg_skinny[i].addr = segs[i].ds_addr;
+ sgl->sg_skinny[i].len = segs[i].ds_len;
+ sgl->sg_skinny[i].flag = 0;
}
+ hdr->flags |= MFI_FRAME_IEEE_SGL | MFI_FRAME_SGL64;
+ sge_size = sizeof(struct mfi_sg_skinny);
+ hdr->sg_count = nsegs;
} else {
- for (i = 0; i < nsegs; i++) {
- sgl->sg64[j].addr = segs[i].ds_addr + first;
- sgl->sg64[j++].len = segs[i].ds_len - first;
+ j = 0;
+ if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
+ first = cm->cm_stp_len;
+ if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
+ sgl->sg32[j].addr = segs[0].ds_addr;
+ sgl->sg32[j++].len = first;
+ } else {
+ sgl->sg64[j].addr = segs[0].ds_addr;
+ sgl->sg64[j++].len = first;
+ }
+ } else
first = 0;
+ if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
+ for (i = 0; i < nsegs; i++) {
+ sgl->sg32[j].addr = segs[i].ds_addr + first;
+ sgl->sg32[j++].len = segs[i].ds_len - first;
+ first = 0;
+ }
+ } else {
+ for (i = 0; i < nsegs; i++) {
+ sgl->sg64[j].addr = segs[i].ds_addr + first;
+ sgl->sg64[j++].len = segs[i].ds_len - first;
+ first = 0;
+ }
+ hdr->flags |= MFI_FRAME_SGL64;
}
- hdr->flags |= MFI_FRAME_SGL64;
+ hdr->sg_count = j;
+ sge_size = sc->mfi_sge_size;
}
- hdr->sg_count = j;
dir = 0;
if (cm->cm_flags & MFI_CMD_DATAIN) {
@@ -1538,8 +2254,6 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
dir |= BUS_DMASYNC_PREWRITE;
hdr->flags |= MFI_FRAME_DIR_WRITE;
}
- if (cm->cm_frame->header.cmd == MFI_CMD_STP)
- dir |= BUS_DMASYNC_PREWRITE;
bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap, dir);
cm->cm_flags |= MFI_CMD_MAPPED;
@@ -1552,7 +2266,10 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
cm->cm_total_frame_size += (sc->mfi_sge_size * nsegs);
cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
- mfi_send_frame(sc, cm);
+ if (sc->MFA_enabled)
+ mfi_tbolt_send_frame(sc, cm);
+ else
+ mfi_send_frame(sc, cm);
return;
}
@@ -1588,7 +2305,7 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
if (cm->cm_extra_frames > 7)
cm->cm_extra_frames = 7;
- sc->mfi_issue_cmd(sc,cm->cm_frame_busaddr,cm->cm_extra_frames);
+ sc->mfi_issue_cmd(sc, cm->cm_frame_busaddr, cm->cm_extra_frames);
if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
return (0);
@@ -1603,14 +2320,15 @@ mfi_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
if (hdr->cmd_status == MFI_STAT_INVALID_STATUS) {
device_printf(sc->mfi_dev, "Frame %p timed out "
- "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
+ "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
return (ETIMEDOUT);
}
return (0);
}
-static void
+
+void
mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
{
int dir;
@@ -1642,6 +2360,7 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
struct mfi_command *cm;
struct mfi_abort_frame *abort;
int i = 0;
+ uint32_t context = 0;
mtx_assert(&sc->mfi_io_lock, MA_OWNED);
@@ -1649,21 +2368,30 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
return (EBUSY);
}
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+
abort = &cm->cm_frame->abort;
abort->header.cmd = MFI_CMD_ABORT;
abort->header.flags = 0;
+ abort->header.scsi_status = 0;
abort->abort_context = cm_abort->cm_frame->header.context;
- abort->abort_mfi_addr_lo = cm_abort->cm_frame_busaddr;
- abort->abort_mfi_addr_hi = 0;
+ abort->abort_mfi_addr_lo = (uint32_t)cm_abort->cm_frame_busaddr;
+ abort->abort_mfi_addr_hi =
+ (uint32_t)((uint64_t)cm_abort->cm_frame_busaddr >> 32);
cm->cm_data = NULL;
cm->cm_flags = MFI_CMD_POLLED;
- sc->mfi_aen_cm->cm_aen_abort = 1;
+ if (sc->mfi_aen_cm)
+ sc->mfi_aen_cm->cm_aen_abort = 1;
mfi_mapcmd(sc, cm);
mfi_release_command(cm);
while (i < 5 && sc->mfi_aen_cm != NULL) {
- msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort", 5 * hz);
+ msleep(&sc->mfi_aen_cm, &sc->mfi_io_lock, 0, "mfiabort",
+ 5 * hz);
i++;
}
@@ -1671,24 +2399,32 @@ mfi_abort(struct mfi_softc *sc, struct mfi_command *cm_abort)
}
int
-mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
+mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
+ int len)
{
struct mfi_command *cm;
struct mfi_io_frame *io;
int error;
+ uint32_t context = 0;
if ((cm = mfi_dequeue_free(sc)) == NULL)
return (EBUSY);
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+
io = &cm->cm_frame->io;
io->header.cmd = MFI_CMD_LD_WRITE;
io->header.target_id = id;
io->header.timeout = 0;
io->header.flags = 0;
+ io->header.scsi_status = 0;
io->header.sense_len = MFI_SENSE_LEN;
io->header.data_len = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
- io->sense_addr_lo = cm->cm_sense_busaddr;
- io->sense_addr_hi = 0;
+ io->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
+ io->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
io->lba_hi = (lba & 0xffffffff00000000) >> 32;
io->lba_lo = lba & 0xffffffff;
cm->cm_data = virt;
@@ -1706,6 +2442,53 @@ mfi_dump_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt, int len)
return (error);
}
+int
+mfi_dump_syspd_blocks(struct mfi_softc *sc, int id, uint64_t lba, void *virt,
+ int len)
+{
+ struct mfi_command *cm;
+ struct mfi_pass_frame *pass;
+ int error;
+ int blkcount = 0;
+
+ if ((cm = mfi_dequeue_free(sc)) == NULL)
+ return (EBUSY);
+
+ pass = &cm->cm_frame->pass;
+ bzero(pass->cdb, 16);
+ pass->header.cmd = MFI_CMD_PD_SCSI_IO;
+ pass->cdb[0] = SCSI_WRITE;
+ pass->cdb[2] = (lba & 0xff000000) >> 24;
+ pass->cdb[3] = (lba & 0x00ff0000) >> 16;
+ pass->cdb[4] = (lba & 0x0000ff00) >> 8;
+ pass->cdb[5] = (lba & 0x000000ff);
+ blkcount = (len + MFI_SECTOR_LEN - 1) / MFI_SECTOR_LEN;
+ pass->cdb[7] = (blkcount & 0xff00) >> 8;
+ pass->cdb[8] = (blkcount & 0x00ff);
+ pass->header.target_id = id;
+ pass->header.timeout = 0;
+ pass->header.flags = 0;
+ pass->header.scsi_status = 0;
+ pass->header.sense_len = MFI_SENSE_LEN;
+ pass->header.data_len = len;
+ pass->header.cdb_len = 10;
+ pass->sense_addr_lo = (uint32_t)cm->cm_sense_busaddr;
+ pass->sense_addr_hi = (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
+ cm->cm_data = virt;
+ cm->cm_len = len;
+ cm->cm_sg = &pass->sgl;
+ cm->cm_total_frame_size = MFI_PASS_FRAME_SIZE;
+ cm->cm_flags = MFI_CMD_POLLED | MFI_CMD_DATAOUT;
+
+ error = mfi_mapcmd(sc, cm);
+ bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
+ mfi_release_command(cm);
+
+ return (error);
+}
+
static int
mfi_open(struct cdev *dev, int flags, int fmt, struct thread *td)
{
@@ -1771,12 +2554,18 @@ mfi_config_unlock(struct mfi_softc *sc, int locked)
sx_xunlock(&sc->mfi_config_lock);
}
-/* Perform pre-issue checks on commands from userland and possibly veto them. */
+/*
+ * Perform pre-issue checks on commands from userland and possibly veto
+ * them.
+ */
static int
mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
{
struct mfi_disk *ld, *ld2;
int error;
+ struct mfi_system_pd *syspd = NULL;
+ uint16_t syspd_id;
+ uint16_t *mbox;
mtx_assert(&sc->mfi_io_lock, MA_OWNED);
error = 0;
@@ -1805,6 +2594,20 @@ mfi_check_command_pre(struct mfi_softc *sc, struct mfi_command *cm)
}
}
break;
+ case MFI_DCMD_PD_STATE_SET:
+ mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
+ syspd_id = mbox[0];
+ if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
+ TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh, pd_link) {
+ if (syspd->pd_id == syspd_id)
+ break;
+ }
+ }
+ else
+ break;
+ if (syspd)
+ error = mfi_syspd_disable(syspd);
+ break;
default:
break;
}
@@ -1816,6 +2619,9 @@ static void
mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
{
struct mfi_disk *ld, *ldn;
+ struct mfi_system_pd *syspd = NULL;
+ uint16_t syspd_id;
+ uint16_t *mbox;
switch (cm->cm_frame->dcmd.opcode) {
case MFI_DCMD_LD_DELETE:
@@ -1853,9 +2659,158 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
case MFI_DCMD_CFG_FOREIGN_IMPORT:
mfi_ldprobe(sc);
break;
+ case MFI_DCMD_PD_STATE_SET:
+ mbox = (uint16_t *) cm->cm_frame->dcmd.mbox;
+ syspd_id = mbox[0];
+ if (mbox[2] == MFI_PD_STATE_UNCONFIGURED_GOOD) {
+ TAILQ_FOREACH(syspd, &sc->mfi_syspd_tqh,pd_link) {
+ if (syspd->pd_id == syspd_id)
+ break;
+ }
+ }
+ else
+ break;
+ /* If the transition fails then enable the syspd again */
+ if (syspd && cm->cm_frame->header.cmd_status != MFI_STAT_OK)
+ mfi_syspd_enable(syspd);
+ break;
}
}
+static int mfi_check_for_sscd(struct mfi_softc *sc, struct mfi_command *cm)
+{
+ struct mfi_config_data *conf_data=(struct mfi_config_data *)cm->cm_data;
+ struct mfi_command *ld_cm = NULL;
+ struct mfi_ld_info *ld_info = NULL;
+ int error = 0;
+
+ if ((cm->cm_frame->dcmd.opcode == MFI_DCMD_CFG_ADD) &&
+ (conf_data->ld[0].params.isSSCD == 1)){
+ error = 1;
+ } else if (cm->cm_frame->dcmd.opcode == MFI_DCMD_LD_DELETE) {
+ error = mfi_dcmd_command (sc, &ld_cm, MFI_DCMD_LD_GET_INFO,
+ (void **)&ld_info, sizeof(*ld_info));
+ if (error){
+ device_printf(sc->mfi_dev, "Failed to allocate"
+ "MFI_DCMD_LD_GET_INFO %d", error);
+ if (ld_info)
+ free(ld_info, M_MFIBUF);
+ return 0;
+ }
+ ld_cm->cm_flags = MFI_CMD_DATAIN;
+ ld_cm->cm_frame->dcmd.mbox[0]= cm->cm_frame->dcmd.mbox[0];
+ ld_cm->cm_frame->header.target_id = cm->cm_frame->dcmd.mbox[0];
+ if (mfi_wait_command(sc, ld_cm) != 0){
+ device_printf(sc->mfi_dev, "failed to get log drv\n");
+ mfi_release_command(ld_cm);
+ free(ld_info, M_MFIBUF);
+ return 0;
+ }
+
+ if (ld_cm->cm_frame->header.cmd_status != MFI_STAT_OK) {
+ free(ld_info, M_MFIBUF);
+ mfi_release_command(ld_cm);
+ return 0;
+ }
+ else
+ ld_info = (struct mfi_ld_info *)ld_cm->cm_private;
+
+ if (ld_info->ld_config.params.isSSCD == 1)
+ error = 1;
+
+ mfi_release_command(ld_cm);
+ free(ld_info, M_MFIBUF);
+
+ }
+ return error;
+}
+
+static int
+mfi_stp_cmd(struct mfi_softc *sc, struct mfi_command *cm,caddr_t arg)
+{
+ uint8_t i;
+ struct mfi_ioc_packet *ioc;
+ ioc = (struct mfi_ioc_packet *)arg;
+ int sge_size, error;
+ struct megasas_sge *kern_sge;
+
+ memset(sc->kbuff_arr, 0, sizeof(sc->kbuff_arr));
+ kern_sge =(struct megasas_sge *) ((uintptr_t)cm->cm_frame + ioc->mfi_sgl_off);
+ cm->cm_frame->header.sg_count = ioc->mfi_sge_count;
+
+ if (sizeof(bus_addr_t) == 8) {
+ cm->cm_frame->header.flags |= MFI_FRAME_SGL64;
+ cm->cm_extra_frames = 2;
+ sge_size = sizeof(struct mfi_sg64);
+ } else {
+ cm->cm_extra_frames = (cm->cm_total_frame_size - 1) / MFI_FRAME_SIZE;
+ sge_size = sizeof(struct mfi_sg32);
+ }
+
+ cm->cm_total_frame_size += (sge_size * ioc->mfi_sge_count);
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ if (bus_dma_tag_create( sc->mfi_parent_dmat, /* parent */
+ 1, 0, /* algnmnt, boundary */
+ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ ioc->mfi_sgl[i].iov_len,/* maxsize */
+ 2, /* nsegments */
+ ioc->mfi_sgl[i].iov_len,/* maxsegsize */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &sc->mfi_kbuff_arr_dmat[i])) {
+ device_printf(sc->mfi_dev,
+ "Cannot allocate mfi_kbuff_arr_dmat tag\n");
+ return (ENOMEM);
+ }
+
+ if (bus_dmamem_alloc(sc->mfi_kbuff_arr_dmat[i],
+ (void **)&sc->kbuff_arr[i], BUS_DMA_NOWAIT,
+ &sc->mfi_kbuff_arr_dmamap[i])) {
+ device_printf(sc->mfi_dev,
+ "Cannot allocate mfi_kbuff_arr_dmamap memory\n");
+ return (ENOMEM);
+ }
+
+ bus_dmamap_load(sc->mfi_kbuff_arr_dmat[i],
+ sc->mfi_kbuff_arr_dmamap[i], sc->kbuff_arr[i],
+ ioc->mfi_sgl[i].iov_len, mfi_addr_cb,
+ &sc->mfi_kbuff_arr_busaddr[i], 0);
+
+ if (!sc->kbuff_arr[i]) {
+ device_printf(sc->mfi_dev,
+ "Could not allocate memory for kbuff_arr info\n");
+ return -1;
+ }
+ kern_sge[i].phys_addr = sc->mfi_kbuff_arr_busaddr[i];
+ kern_sge[i].length = ioc->mfi_sgl[i].iov_len;
+
+ if (sizeof(bus_addr_t) == 8) {
+ cm->cm_frame->stp.sgl.sg64[i].addr =
+ kern_sge[i].phys_addr;
+ cm->cm_frame->stp.sgl.sg64[i].len =
+ ioc->mfi_sgl[i].iov_len;
+ } else {
+ cm->cm_frame->stp.sgl.sg32[i].len =
+ kern_sge[i].phys_addr;
+ cm->cm_frame->stp.sgl.sg32[i].len =
+ ioc->mfi_sgl[i].iov_len;
+ }
+
+ error = copyin(ioc->mfi_sgl[i].iov_base,
+ sc->kbuff_arr[i],
+ ioc->mfi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev, "Copy in failed\n");
+ return error;
+ }
+ }
+
+ cm->cm_flags |=MFI_CMD_MAPPED;
+ return 0;
+}
+
static int
mfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc)
{
@@ -1924,11 +2879,7 @@ out:
return (error);
}
-#ifdef __amd64__
#define PTRIN(p) ((void *)(uintptr_t)(p))
-#else
-#define PTRIN(p) (p)
-#endif
static int
mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
@@ -1936,26 +2887,35 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
struct mfi_softc *sc;
union mfi_statrequest *ms;
struct mfi_ioc_packet *ioc;
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
struct mfi_ioc_packet32 *ioc32;
#endif
struct mfi_ioc_aen *aen;
struct mfi_command *cm = NULL;
- uint32_t context;
+ uint32_t context = 0;
union mfi_sense_ptr sense_ptr;
- uint8_t *data = NULL, *temp, *addr;
+ uint8_t *data = NULL, *temp, *addr, skip_pre_post = 0;
size_t len;
- int i;
+ int i, res;
struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg;
struct mfi_ioc_passthru iop_swab;
#endif
int error, locked;
-
+ union mfi_sgl *sgl;
sc = dev->si_drv1;
error = 0;
+ if (sc->adpreset)
+ return EBUSY;
+
+ if (sc->hw_crit_error)
+ return EBUSY;
+
+ if (sc->issuepend_done == 0)
+ return EBUSY;
+
switch (cmd) {
case MFIIO_STATS:
ms = (union mfi_statrequest *)arg;
@@ -1997,7 +2957,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
break;
}
case MFI_CMD:
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
case MFI_CMD32:
#endif
{
@@ -2023,15 +2983,19 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
* will clobber some data
*/
context = cm->cm_frame->header.context;
+ cm->cm_frame->header.context = cm->cm_index;
bcopy(ioc->mfi_frame.raw, cm->cm_frame,
- 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ 2 * MEGAMFI_FRAME_SIZE);
cm->cm_total_frame_size = (sizeof(union mfi_sgl)
* ioc->mfi_sge_count) + ioc->mfi_sgl_off;
+ cm->cm_frame->header.scsi_status = 0;
+ cm->cm_frame->header.pad0 = 0;
if (ioc->mfi_sge_count) {
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
}
+ sgl = cm->cm_sg;
cm->cm_flags = 0;
if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
cm->cm_flags |= MFI_CMD_DATAIN;
@@ -2042,12 +3006,12 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
cm->cm_len = cm->cm_frame->header.data_len;
if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
if (cmd == MFI_CMD) {
#endif
/* Native */
cm->cm_stp_len = ioc->mfi_sgl[0].iov_len;
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
} else {
/* 32bit on 64bit */
ioc32 = (struct mfi_ioc_packet32 *)ioc;
@@ -2071,84 +3035,97 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
/* restore header context */
cm->cm_frame->header.context = context;
- temp = data;
- if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
- (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
- for (i = 0; i < ioc->mfi_sge_count; i++) {
-#ifdef __amd64__
- if (cmd == MFI_CMD) {
+ if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
+ res = mfi_stp_cmd(sc, cm, arg);
+ if (res != 0)
+ goto out;
+ } else {
+ temp = data;
+ if ((cm->cm_flags & MFI_CMD_DATAOUT) ||
+ (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+#ifdef COMPAT_FREEBSD32
+ if (cmd == MFI_CMD) {
#endif
- /* Native */
- addr = ioc->mfi_sgl[i].iov_base;
- len = ioc->mfi_sgl[i].iov_len;
-#ifdef __amd64__
- } else {
- /* 32bit on 64bit */
- ioc32 = (struct mfi_ioc_packet32 *)ioc;
- addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
- len = ioc32->mfi_sgl[i].iov_len;
- }
+ /* Native */
+ addr = ioc->mfi_sgl[i].iov_base;
+ len = ioc->mfi_sgl[i].iov_len;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ /* 32bit on 64bit */
+ ioc32 = (struct mfi_ioc_packet32 *)ioc;
+ addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
+ len = ioc32->mfi_sgl[i].iov_len;
+ }
#endif
- error = copyin(addr, temp, len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy in failed\n");
- goto out;
+ error = copyin(addr, temp, len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed\n");
+ goto out;
+ }
+ temp = &temp[len];
}
- temp = &temp[len];
}
}
if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
- locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
+ locked = mfi_config_lock(sc,
+ cm->cm_frame->dcmd.opcode);
if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
- cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
- cm->cm_frame->pass.sense_addr_hi = 0;
+ cm->cm_frame->pass.sense_addr_lo =
+ (uint32_t)cm->cm_sense_busaddr;
+ cm->cm_frame->pass.sense_addr_hi =
+ (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
}
-
mtx_lock(&sc->mfi_io_lock);
- error = mfi_check_command_pre(sc, cm);
- if (error) {
- mtx_unlock(&sc->mfi_io_lock);
- goto out;
+ skip_pre_post = mfi_check_for_sscd (sc, cm);
+ if (!skip_pre_post) {
+ error = mfi_check_command_pre(sc, cm);
+ if (error) {
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
}
-
if ((error = mfi_wait_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller polled failed\n");
mtx_unlock(&sc->mfi_io_lock);
goto out;
}
-
- mfi_check_command_post(sc, cm);
+ if (!skip_pre_post) {
+ mfi_check_command_post(sc, cm);
+ }
mtx_unlock(&sc->mfi_io_lock);
- temp = data;
- if ((cm->cm_flags & MFI_CMD_DATAIN) ||
- (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
- for (i = 0; i < ioc->mfi_sge_count; i++) {
-#ifdef __amd64__
- if (cmd == MFI_CMD) {
+ if (cm->cm_frame->header.cmd != MFI_CMD_STP) {
+ temp = data;
+ if ((cm->cm_flags & MFI_CMD_DATAIN) ||
+ (cm->cm_frame->header.cmd == MFI_CMD_STP)) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+#ifdef COMPAT_FREEBSD32
+ if (cmd == MFI_CMD) {
#endif
- /* Native */
- addr = ioc->mfi_sgl[i].iov_base;
- len = ioc->mfi_sgl[i].iov_len;
-#ifdef __amd64__
- } else {
- /* 32bit on 64bit */
- ioc32 = (struct mfi_ioc_packet32 *)ioc;
- addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
- len = ioc32->mfi_sgl[i].iov_len;
- }
+ /* Native */
+ addr = ioc->mfi_sgl[i].iov_base;
+ len = ioc->mfi_sgl[i].iov_len;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ /* 32bit on 64bit */
+ ioc32 = (struct mfi_ioc_packet32 *)ioc;
+ addr = PTRIN(ioc32->mfi_sgl[i].iov_base);
+ len = ioc32->mfi_sgl[i].iov_len;
+ }
#endif
- error = copyout(temp, addr, len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy out failed\n");
- goto out;
+ error = copyout(temp, addr, len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ temp = &temp[len];
}
- temp = &temp[len];
}
}
@@ -2157,7 +3134,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td
bcopy(&ioc->mfi_frame.raw[ioc->mfi_sense_off],
&sense_ptr.sense_ptr_data[0],
sizeof(sense_ptr.sense_ptr_data));
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
if (cmd != MFI_CMD) {
/*
* not 64bit native so zero out any address
@@ -2179,6 +3156,26 @@ out:
mfi_config_unlock(sc, locked);
if (data)
free(data, M_MFIBUF);
+ if (cm->cm_frame->header.cmd == MFI_CMD_STP) {
+ for (i = 0; i < 2; i++) {
+ if (sc->kbuff_arr[i]) {
+ if (sc->mfi_kbuff_arr_busaddr != 0)
+ bus_dmamap_unload(
+ sc->mfi_kbuff_arr_dmat[i],
+ sc->mfi_kbuff_arr_dmamap[i]
+ );
+ if (sc->kbuff_arr[i] != NULL)
+ bus_dmamem_free(
+ sc->mfi_kbuff_arr_dmat[i],
+ sc->kbuff_arr[i],
+ sc->mfi_kbuff_arr_dmamap[i]
+ );
+ if (sc->mfi_kbuff_arr_dmat[i] != NULL)
+ bus_dma_tag_destroy(
+ sc->mfi_kbuff_arr_dmat[i]);
+ }
+ }
+ }
if (cm) {
mtx_lock(&sc->mfi_io_lock);
mfi_release_command(cm);
@@ -2235,7 +3232,7 @@ out:
cmd, arg, flag, td));
break;
}
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
case MFIIO_PASSTHRU32:
iop_swab.ioc_frame = iop32->ioc_frame;
iop_swab.buf_size = iop32->buf_size;
@@ -2245,7 +3242,7 @@ out:
#endif
case MFIIO_PASSTHRU:
error = mfi_user_command(sc, iop);
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
if (cmd == MFIIO_PASSTHRU32)
iop32->ioc_frame = iop_swab.ioc_frame;
#endif
@@ -2268,7 +3265,7 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct
struct mfi_command *cm = NULL;
struct mfi_aen *mfi_aen_entry;
union mfi_sense_ptr sense_ptr;
- uint32_t context;
+ uint32_t context = 0;
uint8_t *data = NULL, *temp;
int i;
int error, locked;
@@ -2303,6 +3300,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct
2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
cm->cm_total_frame_size = (sizeof(union mfi_sgl)
* l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
+ cm->cm_frame->header.scsi_status = 0;
+ cm->cm_frame->header.pad0 = 0;
if (l_ioc.lioc_sge_count)
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
@@ -2346,8 +3345,10 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct
locked = mfi_config_lock(sc, cm->cm_frame->dcmd.opcode);
if (cm->cm_frame->header.cmd == MFI_CMD_PD_SCSI_IO) {
- cm->cm_frame->pass.sense_addr_lo = cm->cm_sense_busaddr;
- cm->cm_frame->pass.sense_addr_hi = 0;
+ cm->cm_frame->pass.sense_addr_lo =
+ (uint32_t)cm->cm_sense_busaddr;
+ cm->cm_frame->pass.sense_addr_hi =
+ (uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32);
}
mtx_lock(&sc->mfi_io_lock);
@@ -2486,7 +3487,6 @@ mfi_poll(struct cdev *dev, int poll_events, struct thread *td)
return revents;
}
-
static void
mfi_dump_all(void)
{
@@ -2514,8 +3514,8 @@ mfi_dump_all(void)
TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
if (cm->cm_timestamp < deadline) {
device_printf(sc->mfi_dev,
- "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
- (int)(time_uptime - cm->cm_timestamp));
+ "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
+ cm, (int)(time_uptime - cm->cm_timestamp));
MFI_PRINT_CMD(cm);
timedout++;
}
@@ -2541,17 +3541,28 @@ mfi_timeout(void *data)
int timedout = 0;
deadline = time_uptime - MFI_CMD_TIMEOUT;
+ if (sc->adpreset == 0) {
+ if (!mfi_tbolt_reset(sc)) {
+ callout_reset(&sc->mfi_watchdog_callout, MFI_CMD_TIMEOUT * hz, mfi_timeout, sc);
+ return;
+ }
+ }
mtx_lock(&sc->mfi_io_lock);
TAILQ_FOREACH(cm, &sc->mfi_busy, cm_link) {
if (sc->mfi_aen_cm == cm)
continue;
if ((sc->mfi_aen_cm != cm) && (cm->cm_timestamp < deadline)) {
- device_printf(sc->mfi_dev,
- "COMMAND %p TIMEOUT AFTER %d SECONDS\n", cm,
- (int)(time_uptime - cm->cm_timestamp));
- MFI_PRINT_CMD(cm);
- MFI_VALIDATE_CMD(sc, cm);
- timedout++;
+ if (sc->adpreset != 0 && sc->issuepend_done == 0) {
+ cm->cm_timestamp = time_uptime;
+ } else {
+ device_printf(sc->mfi_dev,
+ "COMMAND %p TIMEOUT AFTER %d SECONDS\n",
+ cm, (int)(time_uptime - cm->cm_timestamp)
+ );
+ MFI_PRINT_CMD(cm);
+ MFI_VALIDATE_CMD(sc, cm);
+ timedout++;
+ }
}
}
diff --git a/sys/dev/mfi/mfi_cam.c b/sys/dev/mfi/mfi_cam.c
index aa76a10..f9bef0c 100644
--- a/sys/dev/mfi/mfi_cam.c
+++ b/sys/dev/mfi/mfi_cam.c
@@ -270,12 +270,18 @@ mfip_start(void *data)
struct mfip_softc *sc;
struct mfi_pass_frame *pt;
struct mfi_command *cm;
+ uint32_t context = 0;
sc = ccbh->ccb_mfip_ptr;
if ((cm = mfi_dequeue_free(sc->mfi_sc)) == NULL)
return (NULL);
+ /* Zero out the MFI frame */
+ context = cm->cm_frame->header.context;
+ bzero(cm->cm_frame, sizeof(union mfi_frame));
+ cm->cm_frame->header.context = context;
+
pt = &cm->cm_frame->pass;
pt->header.cmd = MFI_CMD_PD_SCSI_IO;
pt->header.cmd_status = 0;
diff --git a/sys/dev/mfi/mfi_debug.c b/sys/dev/mfi/mfi_debug.c
index 8fe7778..d6f4c9a 100644
--- a/sys/dev/mfi/mfi_debug.c
+++ b/sys/dev/mfi/mfi_debug.c
@@ -63,7 +63,8 @@ mfi_print_frame_flags(device_t dev, uint32_t flags)
"\2SGL64"
"\3SENSE64"
"\4WRITE"
- "\5READ");
+ "\5READ"
+ "\6IEEESGL");
}
static void
@@ -73,7 +74,15 @@ mfi_print_sgl(struct mfi_frame_header *hdr, union mfi_sgl *sgl, int count)
printf("SG List:\n");
for (i = 0; i < count; i++) {
- if (hdr->flags & MFI_FRAME_SGL64) {
+ if (hdr->flags & MFI_FRAME_IEEE_SGL) {
+ printf("0x%lx:%06d ", (u_long)sgl->sg_skinny[i].addr,
+ sgl->sg_skinny[i].len);
+ columns += 26;
+ if (columns > 77) {
+ printf("\n");
+ columns = 0;
+ }
+ } else if (hdr->flags & MFI_FRAME_SGL64) {
printf("0x%lx:%06d ", (u_long)sgl->sg64[i].addr,
sgl->sg64[i].len);
columns += 26;
@@ -240,7 +249,12 @@ mfi_validate_sg(struct mfi_softc *sc, struct mfi_command *cm,
hdr = &cm->cm_frame->header;
count = 0;
for (i = 0; i < hdr->sg_count; i++) {
- count += cm->cm_sg->sg32[i].len;
+ if (hdr->flags & MFI_FRAME_IEEE_SGL)
+ count += cm->cm_sg->sg_skinny[i].len;
+ else if (hdr->flags & MFI_FRAME_SGL64)
+ count += cm->cm_sg->sg64[i].len;
+ else
+ count += cm->cm_sg->sg32[i].len;
}
/*
count++;
diff --git a/sys/dev/mfi/mfi_disk.c b/sys/dev/mfi/mfi_disk.c
index ad656d3c..15c9d76 100644
--- a/sys/dev/mfi/mfi_disk.c
+++ b/sys/dev/mfi/mfi_disk.c
@@ -224,7 +224,7 @@ mfi_disk_disable(struct mfi_disk *sc)
if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
if (sc->ld_controller->mfi_delete_busy_volumes)
return (0);
- device_printf(sc->ld_dev, "Unable to delete busy device\n");
+ device_printf(sc->ld_dev, "Unable to delete busy ld device\n");
return (EBUSY);
}
sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
@@ -246,6 +246,7 @@ mfi_disk_strategy(struct bio *bio)
struct mfi_softc *controller;
sc = bio->bio_disk->d_drv1;
+ controller = sc->ld_controller;
if (sc == NULL) {
bio->bio_error = EINVAL;
@@ -255,8 +256,24 @@ mfi_disk_strategy(struct bio *bio)
return;
}
- controller = sc->ld_controller;
+ if (controller->adpreset){
+ bio->bio_error = EBUSY;
+ return;
+ }
+
+ if (controller->hw_crit_error){
+ bio->bio_error = EBUSY;
+ return;
+ }
+
+ if (controller->issuepend_done == 0){
+ bio->bio_error = EBUSY;
+ return;
+ }
+
bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
+ /* Mark it as LD IO */
+ bio->bio_driver2 = (void *)MFI_LD_IO;
mtx_lock(&controller->mfi_io_lock);
mfi_enqueue_bio(controller, bio);
mfi_startio(controller);
diff --git a/sys/dev/mfi/mfi_ioctl.h b/sys/dev/mfi/mfi_ioctl.h
index 48e9c7f..e420017 100644
--- a/sys/dev/mfi/mfi_ioctl.h
+++ b/sys/dev/mfi/mfi_ioctl.h
@@ -28,13 +28,18 @@
__FBSDID("$FreeBSD$");
#include <dev/mfi/mfireg.h>
+#include <machine/bus.h>
-#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
struct iovec32 {
u_int32_t iov_base;
int iov_len;
};
-#endif
+
+struct megasas_sge
+{
+ bus_addr_t phys_addr;
+ uint32_t length;
+};
#define MFIQ_FREE 0
#define MFIQ_BIO 1
@@ -79,7 +84,7 @@ struct mfi_ioc_packet {
struct iovec mfi_sgl[MAX_IOCTL_SGE];
} __packed;
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
struct mfi_ioc_packet32 {
uint16_t mfi_adapter_no;
uint16_t mfi_pad1;
@@ -104,7 +109,7 @@ struct mfi_ioc_aen {
} __packed;
#define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet)
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
#define MFI_CMD32 _IOWR('M', 1, struct mfi_ioc_packet32)
#endif
#define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen)
@@ -136,7 +141,7 @@ struct mfi_ioc_passthru {
uint8_t *buf;
} __packed;
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
struct mfi_ioc_passthru32 {
struct mfi_dcmd_frame ioc_frame;
uint32_t buf_size;
@@ -146,7 +151,7 @@ struct mfi_ioc_passthru32 {
#define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest)
#define MFIIO_PASSTHRU _IOWR('C', 102, struct mfi_ioc_passthru)
-#ifdef __amd64__
+#ifdef COMPAT_FREEBSD32
#define MFIIO_PASSTHRU32 _IOWR('C', 102, struct mfi_ioc_passthru32)
#endif
diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c
index 12135ff..3328a66 100644
--- a/sys/dev/mfi/mfi_linux.c
+++ b/sys/dev/mfi/mfi_linux.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/file.h>
#include <sys/proc.h>
+#include <machine/bus.h>
#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
#include <machine/../linux32/linux.h>
diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c
index 30db74b..5f757da 100644
--- a/sys/dev/mfi/mfi_pci.c
+++ b/sys/dev/mfi/mfi_pci.c
@@ -107,7 +107,7 @@ static devclass_t mfi_devclass;
DRIVER_MODULE(mfi, pci, mfi_pci_driver, mfi_devclass, 0, 0);
MODULE_VERSION(mfi, 1);
-static int mfi_msi = 0;
+static int mfi_msi = 1;
TUNABLE_INT("hw.mfi.msi", &mfi_msi);
SYSCTL_INT(_hw_mfi, OID_AUTO, msi, CTLFLAG_RDTUN, &mfi_msi, 0,
"Enable use of MSI interrupts");
@@ -120,14 +120,28 @@ struct mfi_ident {
int flags;
const char *desc;
} mfi_identifiers[] = {
+ {0x1000, 0x005b, 0x1028, 0x1f2d, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H810 Adapter"},
+ {0x1000, 0x005b, 0x1028, 0x1f30, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Embedded"},
+ {0x1000, 0x005b, 0x1028, 0x1f31, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Adapter"},
+ {0x1000, 0x005b, 0x1028, 0x1f33, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Mini (blades)"},
+ {0x1000, 0x005b, 0x1028, 0x1f34, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710P Mini (monolithics)"},
+ {0x1000, 0x005b, 0x1028, 0x1f35, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Adapter"},
+ {0x1000, 0x005b, 0x1028, 0x1f37, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Mini (blades)"},
+ {0x1000, 0x005b, 0x1028, 0x1f38, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Dell PERC H710 Mini (monolithics)"},
+ {0x1000, 0x005b, 0x8086, 0x9265, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Intel (R) RAID Controller RS25DB080"},
+ {0x1000, 0x005b, 0x8086, 0x9285, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "Intel (R) RAID Controller RS25NB008"},
+ {0x1000, 0x005b, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "ThunderBolt"},
{0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078, "Dell PERC 6"},
{0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"},
+ {0x1000, 0x0071, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
+ {0x1000, 0x0073, 0xffff, 0xffff, MFI_FLAGS_SKINNY, "Drake Skinny"},
{0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"},
{0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2, "Dell PERC H800 Adapter"},
{0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2, "Dell PERC H700 Adapter"},
{0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2, "Dell PERC H700 Integrated"},
{0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2, "Dell PERC H700 Modular"},
{0x1000, 0x0079, 0x1028, 0x1f19, MFI_FLAGS_GEN2, "Dell PERC H700"},
+ {0x1000, 0x0079, 0x1028, 0x1f1a, MFI_FLAGS_GEN2, "Dell PERC H800 Proto Adapter"},
{0x1000, 0x0079, 0x1028, 0x1f1b, MFI_FLAGS_GEN2, "Dell PERC H800"},
{0x1000, 0x0079, 0x1028, 0xffff, MFI_FLAGS_GEN2, "Dell PERC Gen2"},
{0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"},
@@ -201,8 +215,11 @@ mfi_pci_attach(device_t dev)
(sc->mfi_flags & MFI_FLAGS_1078)) {
/* 1068/1078: Memory mapped BAR is at offset 0x10 */
sc->mfi_regs_rid = PCIR_BAR(0);
- } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
- /* GEN2: Memory mapped BAR is at offset 0x14 */
+ }
+ else if ((sc->mfi_flags & MFI_FLAGS_GEN2) ||
+ (sc->mfi_flags & MFI_FLAGS_SKINNY) ||
+ (sc->mfi_flags & MFI_FLAGS_TBOLT)) {
+ /* Gen2/Skinny: Memory mapped BAR is at offset 0x14 */
sc->mfi_regs_rid = PCIR_BAR(1);
}
if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev,
@@ -259,8 +276,8 @@ static int
mfi_pci_detach(device_t dev)
{
struct mfi_softc *sc;
- struct mfi_disk *ld;
- int error;
+ int error, devcount, i;
+ device_t *devlist;
sc = device_get_softc(dev);
@@ -274,13 +291,13 @@ mfi_pci_detach(device_t dev)
sc->mfi_detaching = 1;
mtx_unlock(&sc->mfi_io_lock);
- while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
- if ((error = device_delete_child(dev, ld->ld_dev)) != 0) {
- sc->mfi_detaching = 0;
- sx_xunlock(&sc->mfi_config_lock);
- return (error);
- }
+ if ((error = device_get_children(sc->mfi_dev, &devlist, &devcount)) != 0) {
+ sx_xunlock(&sc->mfi_config_lock);
+ return error;
}
+ for (i = 0; i < devcount; i++)
+ device_delete_child(sc->mfi_dev, devlist[i]);
+ free(devlist, M_TEMP);
sx_xunlock(&sc->mfi_config_lock);
EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);
diff --git a/sys/dev/mfi/mfi_syspd.c b/sys/dev/mfi/mfi_syspd.c
new file mode 100644
index 0000000..a8a8b24
--- /dev/null
+++ b/sys/dev/mfi/mfi_syspd.c
@@ -0,0 +1,276 @@
+/*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Copyright 1994-2009 The FreeBSD Project.
+ * All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mfi.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <sys/bio.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+#include <geom/geom_disk.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/md_var.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+static int mfi_syspd_probe(device_t dev);
+static int mfi_syspd_attach(device_t dev);
+static int mfi_syspd_detach(device_t dev);
+
+static disk_open_t mfi_syspd_open;
+static disk_close_t mfi_syspd_close;
+static disk_strategy_t mfi_syspd_strategy;
+static dumper_t mfi_syspd_dump;
+
+static devclass_t mfi_syspd_devclass;
+
+static device_method_t mfi_syspd_methods[] = {
+ DEVMETHOD(device_probe, mfi_syspd_probe),
+ DEVMETHOD(device_attach, mfi_syspd_attach),
+ DEVMETHOD(device_detach, mfi_syspd_detach),
+ { 0, 0 }
+};
+
+static driver_t mfi_syspd_driver = {
+ "mfisyspd",
+ mfi_syspd_methods,
+ sizeof(struct mfi_system_pd)
+};
+
+DRIVER_MODULE(mfisyspd, mfi, mfi_syspd_driver, mfi_syspd_devclass, 0, 0);
+
+static int
+mfi_syspd_probe(device_t dev)
+{
+
+ return (0);
+}
+
+static int
+mfi_syspd_attach(device_t dev)
+{
+ struct mfi_system_pd *sc;
+ struct mfi_pd_info *pd_info;
+ uint64_t sectors;
+ uint32_t secsize;
+
+ sc = device_get_softc(dev);
+ pd_info = device_get_ivars(dev);
+
+ sc->pd_dev = dev;
+ sc->pd_id = pd_info->ref.v.device_id;
+ sc->pd_unit = device_get_unit(dev);
+ sc->pd_info = pd_info;
+ sc->pd_controller = device_get_softc(device_get_parent(dev));
+ sc->pd_flags = 0;
+
+ sectors = pd_info->raw_size;
+ secsize = MFI_SECTOR_LEN;
+ mtx_lock(&sc->pd_controller->mfi_io_lock);
+ TAILQ_INSERT_TAIL(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link);
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+ device_printf(dev, "%juMB (%ju sectors) SYSPD volume\n",
+ sectors / (1024 * 1024 / secsize), sectors);
+ sc->pd_disk = disk_alloc();
+ sc->pd_disk->d_drv1 = sc;
+ sc->pd_disk->d_maxsize = sc->pd_controller->mfi_max_io * secsize;
+ sc->pd_disk->d_name = "mfisyspd";
+ sc->pd_disk->d_open = mfi_syspd_open;
+ sc->pd_disk->d_close = mfi_syspd_close;
+ sc->pd_disk->d_strategy = mfi_syspd_strategy;
+ sc->pd_disk->d_dump = mfi_syspd_dump;
+ sc->pd_disk->d_unit = sc->pd_unit;
+ sc->pd_disk->d_sectorsize = secsize;
+ sc->pd_disk->d_mediasize = sectors * secsize;
+ if (sc->pd_disk->d_mediasize >= (1 * 1024 * 1024)) {
+ sc->pd_disk->d_fwheads = 255;
+ sc->pd_disk->d_fwsectors = 63;
+ } else {
+ sc->pd_disk->d_fwheads = 64;
+ sc->pd_disk->d_fwsectors = 32;
+ }
+ disk_create(sc->pd_disk, DISK_VERSION);
+
+ device_printf(dev, " SYSPD volume attached\n");
+ return (0);
+}
+
+static int
+mfi_syspd_detach(device_t dev)
+{
+ struct mfi_system_pd *sc;
+
+ sc = device_get_softc(dev);
+ device_printf(dev, "Detaching syspd\n");
+ mtx_lock(&sc->pd_controller->mfi_io_lock);
+ if (((sc->pd_disk->d_flags & DISKFLAG_OPEN) ||
+ (sc->pd_flags & MFI_DISK_FLAGS_OPEN)) &&
+ (sc->pd_controller->mfi_keep_deleted_volumes ||
+ sc->pd_controller->mfi_detaching)) {
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+ device_printf(dev, "Cant detach syspd\n");
+ return (EBUSY);
+ }
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+
+ disk_destroy(sc->pd_disk);
+ mtx_lock(&sc->pd_controller->mfi_io_lock);
+ TAILQ_REMOVE(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link);
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+ free(sc->pd_info, M_MFIBUF);
+ return (0);
+}
+
+static int
+mfi_syspd_open(struct disk *dp)
+{
+ struct mfi_system_pd *sc;
+ int error;
+
+ sc = dp->d_drv1;
+ mtx_lock(&sc->pd_controller->mfi_io_lock);
+ if (sc->pd_flags & MFI_DISK_FLAGS_DISABLED)
+ error = ENXIO;
+ else {
+ sc->pd_flags |= MFI_DISK_FLAGS_OPEN;
+ error = 0;
+ }
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+ return (error);
+}
+
+static int
+mfi_syspd_close(struct disk *dp)
+{
+ struct mfi_system_pd *sc;
+
+ sc = dp->d_drv1;
+ mtx_lock(&sc->pd_controller->mfi_io_lock);
+ sc->pd_flags &= ~MFI_DISK_FLAGS_OPEN;
+ mtx_unlock(&sc->pd_controller->mfi_io_lock);
+
+ return (0);
+}
+
+int
+mfi_syspd_disable(struct mfi_system_pd *sc)
+{
+
+ device_printf(sc->pd_dev, "syspd disable \n");
+ mtx_assert(&sc->pd_controller->mfi_io_lock, MA_OWNED);
+ if (sc->pd_flags & MFI_DISK_FLAGS_OPEN) {
+ if (sc->pd_controller->mfi_delete_busy_volumes)
+ return (0);
+ device_printf(sc->pd_dev,
+ "Unable to delete busy syspd device\n");
+ return (EBUSY);
+ }
+ sc->pd_flags |= MFI_DISK_FLAGS_DISABLED;
+ return (0);
+}
+
+void
+mfi_syspd_enable(struct mfi_system_pd *sc)
+{
+
+ device_printf(sc->pd_dev, "syspd enable \n");
+ mtx_assert(&sc->pd_controller->mfi_io_lock, MA_OWNED);
+ sc->pd_flags &= ~MFI_DISK_FLAGS_DISABLED;
+}
+
+static void
+mfi_syspd_strategy(struct bio *bio)
+{
+ struct mfi_system_pd *sc;
+ struct mfi_softc *controller;
+
+ sc = bio->bio_disk->d_drv1;
+
+ if (sc == NULL) {
+ bio->bio_error = EINVAL;
+ bio->bio_flags |= BIO_ERROR;
+ bio->bio_resid = bio->bio_bcount;
+ biodone(bio);
+ return;
+ }
+
+ controller = sc->pd_controller;
+ bio->bio_driver1 = (void *)(uintptr_t)sc->pd_id;
+ /* Mark it as system PD IO */
+ bio->bio_driver2 = (void *)MFI_SYS_PD_IO;
+ mtx_lock(&controller->mfi_io_lock);
+ mfi_enqueue_bio(controller, bio);
+ mfi_startio(controller);
+ mtx_unlock(&controller->mfi_io_lock);
+ return;
+}
+
+static int
+mfi_syspd_dump(void *arg, void *virt, vm_offset_t phys, off_t offset,
+ size_t len)
+{
+ struct mfi_system_pd *sc;
+ struct mfi_softc *parent_sc;
+ struct disk *dp;
+ int error;
+
+ dp = arg;
+ sc = dp->d_drv1;
+ parent_sc = sc->pd_controller;
+
+ if (len > 0) {
+ if ((error = mfi_dump_syspd_blocks(parent_sc,
+ sc->pd_id, offset / MFI_SECTOR_LEN, virt, len)) != 0)
+ return (error);
+ } else {
+ /* mfi_sync_cache(parent_sc, sc->ld_id); */
+ }
+ return (0);
+}
diff --git a/sys/dev/mfi/mfi_tbolt.c b/sys/dev/mfi/mfi_tbolt.c
new file mode 100644
index 0000000..aa9fb77
--- /dev/null
+++ b/sys/dev/mfi/mfi_tbolt.c
@@ -0,0 +1,1345 @@
+ /*-
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Copyright 1994-2009 The FreeBSD Project.
+ * All rights reserved.
+ *
+ * 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 FREEBSD PROJECT``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 FREEBSD PROJECT 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_mfi.h"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/selinfo.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/bio.h>
+#include <sys/ioccom.h>
+#include <sys/eventhandler.h>
+#include <sys/callout.h>
+#include <sys/uio.h>
+#include <machine/bus.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+#include <dev/mfi/mfivar.h>
+
+struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc *sc);
+union mfi_mpi2_request_descriptor *
+mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index);
+void mfi_tbolt_complete_cmd(struct mfi_softc *sc);
+int mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
+ struct mfi_cmd_tbolt *cmd);
+static inline void mfi_tbolt_return_cmd(struct mfi_softc *sc,
+ struct mfi_cmd_tbolt *cmd);
+union mfi_mpi2_request_descriptor *mfi_tbolt_build_mpt_cmd(struct mfi_softc
+ *sc, struct mfi_command *cmd);
+uint8_t
+mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd);
+union mfi_mpi2_request_descriptor *mfi_build_and_issue_cmd(struct mfi_softc
+ *sc, struct mfi_command *mfi_cmd);
+int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd);
+void mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
+ struct mfi_cmd_tbolt *cmd);
+static int mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command
+ *mfi_cmd, pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd);
+static int mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command
+ *mfi_cmd, uint8_t *cdb);
+void
+map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
+ uint8_t ext_status);
+static void mfi_issue_pending_cmds_again (struct mfi_softc *sc);
+static void mfi_kill_hba (struct mfi_softc *sc);
+static void mfi_process_fw_state_chg_isr(void *arg);
+uint8_t mfi_tbolt_get_map_info(struct mfi_softc *sc);
+
+#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000008)
+
+void
+mfi_tbolt_enable_intr_ppc(struct mfi_softc *sc)
+{
+ MFI_WRITE4(sc, MFI_OMSK, ~MFI_FUSION_ENABLE_INTERRUPT_MASK);
+ MFI_READ4(sc, MFI_OMSK);
+}
+
+void
+mfi_tbolt_disable_intr_ppc(struct mfi_softc *sc)
+{
+ MFI_WRITE4(sc, MFI_OMSK, 0xFFFFFFFF);
+ MFI_READ4(sc, MFI_OMSK);
+}
+
+int32_t
+mfi_tbolt_read_fw_status_ppc(struct mfi_softc *sc)
+{
+ return MFI_READ4(sc, MFI_OSP0);
+}
+
+int32_t
+mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *sc)
+{
+ int32_t status, mfi_status = 0;
+
+ status = MFI_READ4(sc, MFI_OSTS);
+
+ if (status & 1) {
+ MFI_WRITE4(sc, MFI_OSTS, status);
+ MFI_READ4(sc, MFI_OSTS);
+ if (status & MFI_STATE_CHANGE_INTERRUPT) {
+ mfi_status |= MFI_FIRMWARE_STATE_CHANGE;
+ }
+
+ return mfi_status;
+ }
+ if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK))
+ return 1;
+
+ MFI_READ4(sc, MFI_OSTS);
+ return 0;
+}
+
+
+void
+mfi_tbolt_issue_cmd_ppc(struct mfi_softc *sc, bus_addr_t bus_add,
+ uint32_t frame_cnt)
+{
+ bus_add |= (MFI_REQ_DESCRIPT_FLAGS_MFA
+ << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ MFI_WRITE4(sc, MFI_IQPL, (uint32_t)bus_add);
+ MFI_WRITE4(sc, MFI_IQPH, (uint32_t)((uint64_t)bus_add >> 32));
+}
+
+/**
+ * mfi_tbolt_adp_reset - For controller reset
+ * @regs: MFI register set
+ */
+int mfi_tbolt_adp_reset(struct mfi_softc *sc)
+{
+ int retry = 0, i = 0;
+ int HostDiag;
+
+ MFI_WRITE4(sc, MFI_WSR, 0xF);
+ MFI_WRITE4(sc, MFI_WSR, 4);
+ MFI_WRITE4(sc, MFI_WSR, 0xB);
+ MFI_WRITE4(sc, MFI_WSR, 2);
+ MFI_WRITE4(sc, MFI_WSR, 7);
+ MFI_WRITE4(sc, MFI_WSR, 0xD);
+
+ for (i = 0; i < 10000; i++) ;
+
+ HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
+
+ while (!( HostDiag & DIAG_WRITE_ENABLE)) {
+ for (i = 0; i < 1000; i++);
+ HostDiag = (uint32_t)MFI_READ4(sc, MFI_HDR);
+ device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
+ "hostdiag=%x\n", retry, HostDiag);
+
+ if (retry++ >= 100)
+ return 1;
+ }
+
+ device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: HostDiag=%x\n", HostDiag);
+
+ MFI_WRITE4(sc, MFI_HDR, (HostDiag | DIAG_RESET_ADAPTER));
+
+ for (i=0; i < 10; i++) {
+ for (i = 0; i < 10000; i++);
+ }
+
+ HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
+ while (HostDiag & DIAG_RESET_ADAPTER) {
+ for (i = 0; i < 1000; i++) ;
+ HostDiag = (uint32_t)MFI_READ4(sc, MFI_RSR);
+ device_printf(sc->mfi_dev, "ADP_RESET_TBOLT: retry time=%x, "
+ "hostdiag=%x\n", retry, HostDiag);
+
+ if (retry++ >= 1000)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ *******************************************************************************************
+ * Description:
+ * This routine initialize Thunderbolt specific device information
+ *******************************************************************************************
+ */
+void mfi_tbolt_init_globals(struct mfi_softc *sc)
+{
+ /* Initialize single reply size and Message size */
+ sc->reply_size = MEGASAS_THUNDERBOLT_REPLY_SIZE;
+ sc->raid_io_msg_size = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
+
+ /*
+ * Calculating how many SGEs allowed in a allocated main message
+ * (size of the Message - Raid SCSI IO message size(except SGE))
+ * / size of SGE
+ * (0x100 - (0x90 - 0x10)) / 0x10 = 8
+ */
+ sc->max_SGEs_in_main_message =
+ (uint8_t)((sc->raid_io_msg_size
+ - (sizeof(struct mfi_mpi2_request_raid_scsi_io)
+ - sizeof(MPI2_SGE_IO_UNION))) / sizeof(MPI2_SGE_IO_UNION));
+ /*
+ * (Command frame size allocaed in SRB ext - Raid SCSI IO message size)
+ * / size of SGL ;
+ * (1280 - 256) / 16 = 64
+ */
+ sc->max_SGEs_in_chain_message = (MR_COMMAND_SIZE
+ - sc->raid_io_msg_size) / sizeof(MPI2_SGE_IO_UNION);
+ /*
+ * (0x08-1) + 0x40 = 0x47 - 0x01 = 0x46 one is left for command
+ * colscing
+ */
+ sc->mfi_max_sge = (sc->max_SGEs_in_main_message - 1)
+ + sc->max_SGEs_in_chain_message - 1;
+ /*
+ * This is the offset in number of 4 * 32bit words to the next chain
+ * (0x100 - 0x10)/0x10 = 0xF(15)
+ */
+ sc->chain_offset_value_for_main_message = (sc->raid_io_msg_size
+ - sizeof(MPI2_SGE_IO_UNION))/16;
+ sc->chain_offset_value_for_mpt_ptmsg
+ = offsetof(struct mfi_mpi2_request_raid_scsi_io, SGL)/16;
+ sc->mfi_cmd_pool_tbolt = NULL;
+ sc->request_desc_pool = NULL;
+}
+
+/*
+ ****************************************************************************
+ * Description:
+ * This function calculates the memory requirement for Thunderbolt
+ * controller
+ * Return Value:
+ * Total required memory in bytes
+ ****************************************************************************
+ */
+
+uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *sc)
+{
+ uint32_t size;
+ size = MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT; /* for Alignment */
+ size += sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1);
+ size += sc->reply_size * sc->mfi_max_fw_cmds;
+ /* this is for SGL's */
+ size += MEGASAS_MAX_SZ_CHAIN_FRAME * sc->mfi_max_fw_cmds;
+ return size;
+}
+
+/*
+ ****************************************************************************
+ * Description:
+ * This function will prepare message pools for the Thunderbolt controller
+ * Arguments:
+ * DevExt - HBA miniport driver's adapter data storage structure
+ * pMemLocation - start of the memory allocated for Thunderbolt.
+ * Return Value:
+ * TRUE if successful
+ * FALSE if failed
+ ****************************************************************************
+ */
+int mfi_tbolt_init_desc_pool(struct mfi_softc *sc, uint8_t* mem_location,
+ uint32_t tbolt_contg_length)
+{
+ uint32_t offset = 0;
+ uint8_t *addr = mem_location;
+
+ /* Request Descriptor Base physical Address */
+
+ /* For Request Decriptors Virtual Memory */
+ /* Initialise the aligned IO Frames Virtual Memory Pointer */
+ if (((uintptr_t)addr) & (0xFF)) {
+ addr = &addr[sc->raid_io_msg_size];
+ addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
+ sc->request_message_pool_align = addr;
+ } else
+ sc->request_message_pool_align = addr;
+
+ offset = sc->request_message_pool_align - sc->request_message_pool;
+ sc->request_msg_busaddr = sc->mfi_tb_busaddr + offset;
+
+ /* DJA XXX should this be bus dma ??? */
+ /* Skip request message pool */
+ addr = &addr[sc->raid_io_msg_size * (sc->mfi_max_fw_cmds + 1)];
+ /* Reply Frame Pool is initialized */
+ sc->reply_frame_pool = (struct mfi_mpi2_reply_header *) addr;
+ if (((uintptr_t)addr) & (0xFF)) {
+ addr = &addr[sc->reply_size];
+ addr = (uint8_t *)((uintptr_t)addr & (~0xFF));
+ }
+ sc->reply_frame_pool_align
+ = (struct mfi_mpi2_reply_header *)addr;
+
+ offset = (uintptr_t)sc->reply_frame_pool_align
+ - (uintptr_t)sc->request_message_pool;
+ sc->reply_frame_busaddr = sc->mfi_tb_busaddr + offset;
+
+ /* Skip Reply Frame Pool */
+ addr += sc->reply_size * sc->mfi_max_fw_cmds;
+ sc->reply_pool_limit = addr;
+
+ /* initializing reply address to 0xFFFFFFFF */
+ memset((uint8_t *)sc->reply_frame_pool, 0xFF,
+ (sc->reply_size * sc->mfi_max_fw_cmds));
+
+ offset = sc->reply_size * sc->mfi_max_fw_cmds;
+ sc->sg_frame_busaddr = sc->reply_frame_busaddr + offset;
+ /* initialize the last_reply_idx to 0 */
+ sc->last_reply_idx = 0;
+ offset = (sc->sg_frame_busaddr + (MEGASAS_MAX_SZ_CHAIN_FRAME *
+ sc->mfi_max_fw_cmds)) - sc->mfi_tb_busaddr;
+ if (offset > tbolt_contg_length)
+ device_printf(sc->mfi_dev, "Error:Initialized more than "
+ "allocated\n");
+ return 0;
+}
+
+/*
+ ****************************************************************************
+ * Description:
+ * This routine prepare and issue INIT2 frame to the Firmware
+ ****************************************************************************
+ */
+
+int
+mfi_tbolt_init_MFI_queue(struct mfi_softc *sc)
+{
+ struct MPI2_IOC_INIT_REQUEST *mpi2IocInit;
+ struct mfi_init_frame *mfi_init;
+ uintptr_t offset = 0;
+ bus_addr_t phyAddress;
+ MFI_ADDRESS *mfiAddressTemp;
+ struct mfi_command *cm;
+ int error;
+
+ mpi2IocInit = (struct MPI2_IOC_INIT_REQUEST *)sc->mfi_tb_ioc_init_desc;
+ /* Check if initialization is already completed */
+ if (sc->MFA_enabled) {
+ return 1;
+ }
+
+ mtx_lock(&sc->mfi_io_lock);
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (EBUSY);
+ }
+ cm->cm_frame = (union mfi_frame *)((uintptr_t)sc->mfi_tb_init);
+ cm->cm_frame_busaddr = sc->mfi_tb_init_busaddr;
+ cm->cm_dmamap = sc->mfi_tb_init_dmamap;
+ cm->cm_frame->header.context = 0;
+ cm->cm_sc = sc;
+ cm->cm_index = 0;
+
+ /*
+ * Abuse the SG list area of the frame to hold the init_qinfo
+ * object;
+ */
+ mfi_init = &cm->cm_frame->init;
+
+ bzero(mpi2IocInit, sizeof(struct MPI2_IOC_INIT_REQUEST));
+ mpi2IocInit->Function = MPI2_FUNCTION_IOC_INIT;
+ mpi2IocInit->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
+
+ /* set MsgVersion and HeaderVersion host driver was built with */
+ mpi2IocInit->MsgVersion = MPI2_VERSION;
+ mpi2IocInit->HeaderVersion = MPI2_HEADER_VERSION;
+ mpi2IocInit->SystemRequestFrameSize = sc->raid_io_msg_size/4;
+ mpi2IocInit->ReplyDescriptorPostQueueDepth
+ = (uint16_t)sc->mfi_max_fw_cmds;
+ mpi2IocInit->ReplyFreeQueueDepth = 0; /* Not supported by MR. */
+
+ /* Get physical address of reply frame pool */
+ offset = (uintptr_t) sc->reply_frame_pool_align
+ - (uintptr_t)sc->request_message_pool;
+ phyAddress = sc->mfi_tb_busaddr + offset;
+ mfiAddressTemp =
+ (MFI_ADDRESS *)&mpi2IocInit->ReplyDescriptorPostQueueAddress;
+ mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
+ mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
+
+ /* Get physical address of request message pool */
+ offset = sc->request_message_pool_align - sc->request_message_pool;
+ phyAddress = sc->mfi_tb_busaddr + offset;
+ mfiAddressTemp = (MFI_ADDRESS *)&mpi2IocInit->SystemRequestFrameBaseAddress;
+ mfiAddressTemp->u.addressLow = (uint32_t)phyAddress;
+ mfiAddressTemp->u.addressHigh = (uint32_t)((uint64_t)phyAddress >> 32);
+ mpi2IocInit->ReplyFreeQueueAddress = 0; /* Not supported by MR. */
+ mpi2IocInit->TimeStamp = time_uptime;
+
+ if (sc->verbuf) {
+ snprintf((char *)sc->verbuf, strlen(MEGASAS_VERSION) + 2, "%s\n",
+ MEGASAS_VERSION);
+ mfi_init->driver_ver_lo = (uint32_t)sc->verbuf_h_busaddr;
+ mfi_init->driver_ver_hi =
+ (uint32_t)((uint64_t)sc->verbuf_h_busaddr >> 32);
+ }
+ /* Get the physical address of the mpi2 ioc init command */
+ phyAddress = sc->mfi_tb_ioc_init_busaddr;
+ mfi_init->qinfo_new_addr_lo = (uint32_t)phyAddress;
+ mfi_init->qinfo_new_addr_hi = (uint32_t)((uint64_t)phyAddress >> 32);
+ mfi_init->header.flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+ mfi_init->header.cmd = MFI_CMD_INIT;
+ mfi_init->header.data_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
+ mfi_init->header.cmd_status = MFI_STAT_INVALID_STATUS;
+
+ cm->cm_data = NULL;
+ cm->cm_flags |= MFI_CMD_POLLED;
+ cm->cm_timestamp = time_uptime;
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev, "failed to send IOC init2 "
+ "command %d at %lx\n", error, (long)cm->cm_frame_busaddr);
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ return (error);
+ }
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+
+ if (mfi_init->header.cmd_status == 0) {
+ sc->MFA_enabled = 1;
+ }
+ else {
+ device_printf(sc->mfi_dev, "Init command Failed %x\n",
+ mfi_init->header.cmd_status);
+ return 1;
+ }
+
+ return 0;
+
+}
+
+int mfi_tbolt_alloc_cmd(struct mfi_softc *sc)
+{
+ struct mfi_cmd_tbolt *cmd;
+ bus_addr_t io_req_base_phys;
+ uint8_t *io_req_base;
+ int i = 0, j = 0, offset = 0;
+
+ /*
+ * sc->mfi_cmd_pool_tbolt is an array of struct mfi_cmd_tbolt pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ sc->request_desc_pool = malloc(sizeof(
+ union mfi_mpi2_request_descriptor) * sc->mfi_max_fw_cmds,
+ M_MFIBUF, M_NOWAIT|M_ZERO);
+ sc->mfi_cmd_pool_tbolt = malloc(sizeof(struct mfi_cmd_tbolt*)
+ * sc->mfi_max_fw_cmds, M_MFIBUF, M_NOWAIT|M_ZERO);
+
+ if (!sc->mfi_cmd_pool_tbolt) {
+ device_printf(sc->mfi_dev, "out of memory. Could not alloc "
+ "memory for cmd_list_fusion\n");
+ return 1;
+ }
+
+ for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
+ sc->mfi_cmd_pool_tbolt[i] = malloc(sizeof(
+ struct mfi_cmd_tbolt),M_MFIBUF, M_NOWAIT|M_ZERO);
+
+ if (!sc->mfi_cmd_pool_tbolt[i]) {
+ device_printf(sc->mfi_dev, "Could not alloc cmd list "
+ "fusion\n");
+
+ for (j = 0; j < i; j++)
+ free(sc->mfi_cmd_pool_tbolt[j], M_MFIBUF);
+
+ free(sc->mfi_cmd_pool_tbolt, M_MFIBUF);
+ sc->mfi_cmd_pool_tbolt = NULL;
+ }
+ }
+
+ /*
+ * The first 256 bytes (SMID 0) is not used. Don't add to the cmd
+ *list
+ */
+ io_req_base = sc->request_message_pool_align
+ + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
+ io_req_base_phys = sc->request_msg_busaddr
+ + MEGASAS_THUNDERBOLT_NEW_MSG_SIZE;
+
+ /*
+ * Add all the commands to command pool (instance->cmd_pool)
+ */
+ /* SMID 0 is reserved. Set SMID/index from 1 */
+
+ for (i = 0; i < sc->mfi_max_fw_cmds; i++) {
+ cmd = sc->mfi_cmd_pool_tbolt[i];
+ offset = MEGASAS_THUNDERBOLT_NEW_MSG_SIZE * i;
+ cmd->index = i + 1;
+ cmd->request_desc = (union mfi_mpi2_request_descriptor *)
+ (sc->request_desc_pool + i);
+ cmd->io_request = (struct mfi_mpi2_request_raid_scsi_io *)
+ (io_req_base + offset);
+ cmd->io_request_phys_addr = io_req_base_phys + offset;
+ cmd->sg_frame = (MPI2_SGE_IO_UNION *)(sc->reply_pool_limit
+ + i * MEGASAS_MAX_SZ_CHAIN_FRAME);
+ cmd->sg_frame_phys_addr = sc->sg_frame_busaddr + i
+ * MEGASAS_MAX_SZ_CHAIN_FRAME;
+
+ TAILQ_INSERT_TAIL(&(sc->mfi_cmd_tbolt_tqh), cmd, next);
+ }
+ return 0;
+}
+
+int mfi_tbolt_reset(struct mfi_softc *sc)
+{
+ uint32_t fw_state;
+
+ mtx_lock(&sc->mfi_io_lock);
+ if (atomic_read(&sc->fw_reset_no_pci_access)) {
+ device_printf(sc->mfi_dev, "NO PCI ACCESS\n");
+ mtx_unlock(&sc->mfi_io_lock);
+ return 1;
+ }
+
+ if (sc->hw_crit_error) {
+ device_printf(sc->mfi_dev, "HW CRITICAL ERROR\n");
+ mtx_unlock(&sc->mfi_io_lock);
+ return 1;
+ }
+
+ if (sc->mfi_flags & MFI_FLAGS_TBOLT) {
+ fw_state = sc->mfi_read_fw_status(sc);
+ if ((fw_state & MFI_FWSTATE_FAULT) == MFI_FWSTATE_FAULT) {
+ if ((sc->disableOnlineCtrlReset == 0)
+ && (sc->adpreset == 0)) {
+ device_printf(sc->mfi_dev, "Adapter RESET "
+ "condition is detected\n");
+ sc->adpreset = 1;
+ sc->issuepend_done = 0;
+ sc->MFA_enabled = 0;
+ sc->last_reply_idx = 0;
+ mfi_process_fw_state_chg_isr((void *) sc);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+ return 0;
+ }
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+ return 1;
+}
+
+/*
+ * mfi_intr_tbolt - isr entry point
+ */
+void mfi_intr_tbolt(void *arg)
+{
+ struct mfi_softc *sc = (struct mfi_softc *)arg;
+
+ if (sc->mfi_check_clear_intr(sc) == 1) {
+ return;
+ }
+ if (sc->mfi_detaching)
+ return;
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_tbolt_complete_cmd(sc);
+ if (sc->mfi_flags & MFI_FLAGS_QFRZN)
+ sc->mfi_flags &= ~MFI_FLAGS_QFRZN;
+ mfi_startio(sc);
+ mtx_unlock(&sc->mfi_io_lock);
+ return;
+}
+
+/**
+ * map_cmd_status - Maps FW cmd status to OS cmd status
+ * @cmd : Pointer to cmd
+ * @status : status of cmd returned by FW
+ * @ext_status : ext status of cmd returned by FW
+ */
+
+void
+map_tbolt_cmd_status(struct mfi_command *mfi_cmd, uint8_t status,
+ uint8_t ext_status)
+{
+
+ switch (status) {
+
+ case MFI_STAT_OK:
+ mfi_cmd->cm_frame->header.cmd_status = 0;
+ mfi_cmd->cm_frame->dcmd.header.cmd_status = 0;
+ break;
+
+ case MFI_STAT_SCSI_IO_FAILED:
+ case MFI_STAT_LD_INIT_IN_PROGRESS:
+ mfi_cmd->cm_frame->header.cmd_status = status;
+ mfi_cmd->cm_frame->header.scsi_status = ext_status;
+ mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
+ mfi_cmd->cm_frame->dcmd.header.scsi_status
+ = ext_status;
+ break;
+
+ case MFI_STAT_SCSI_DONE_WITH_ERROR:
+ mfi_cmd->cm_frame->header.cmd_status = ext_status;
+ mfi_cmd->cm_frame->dcmd.header.cmd_status = ext_status;
+ break;
+
+ case MFI_STAT_LD_OFFLINE:
+ case MFI_STAT_DEVICE_NOT_FOUND:
+ mfi_cmd->cm_frame->header.cmd_status = status;
+ mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
+ break;
+
+ default:
+ mfi_cmd->cm_frame->header.cmd_status = status;
+ mfi_cmd->cm_frame->dcmd.header.cmd_status = status;
+ break;
+ }
+}
+
+/**
+ * mfi_tbolt_return_cmd - Return a cmd to free command pool
+ * @instance: Adapter soft state
+ * @cmd: Command packet to be returned to free command pool
+ */
+static inline void
+mfi_tbolt_return_cmd(struct mfi_softc *sc, struct mfi_cmd_tbolt *cmd)
+{
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ TAILQ_INSERT_TAIL(&sc->mfi_cmd_tbolt_tqh, cmd, next);
+}
+
+void mfi_tbolt_complete_cmd(struct mfi_softc *sc)
+{
+ struct mfi_mpi2_reply_header *desc, *reply_desc;
+ struct mfi_command *cmd_mfi; /* For MFA Cmds */
+ struct mfi_cmd_tbolt *cmd_tbolt;
+ uint16_t smid;
+ uint8_t reply_descript_type;
+ struct mfi_mpi2_request_raid_scsi_io *scsi_io_req;
+ uint32_t status, extStatus;
+ uint16_t num_completed;
+ union desc_value val;
+
+ desc = (struct mfi_mpi2_reply_header *)
+ ((uintptr_t)sc->reply_frame_pool_align
+ + sc->last_reply_idx * sc->reply_size);
+ reply_desc = desc;
+
+ if (!reply_desc)
+ device_printf(sc->mfi_dev, "reply desc is NULL!!\n");
+
+ reply_descript_type = reply_desc->ReplyFlags
+ & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ return;
+
+ num_completed = 0;
+ val.word = ((union mfi_mpi2_reply_descriptor *)desc)->words;
+
+ /* Read Reply descriptor */
+ while ((val.u.low != 0xFFFFFFFF) && (val.u.high != 0xFFFFFFFF)) {
+
+ smid = reply_desc->SMID;
+ if (!smid || smid > sc->mfi_max_fw_cmds + 1) {
+ device_printf(sc->mfi_dev, "smid is %x. Cannot "
+ "proceed. Returning \n", smid);
+ return;
+ }
+
+ cmd_tbolt = sc->mfi_cmd_pool_tbolt[smid - 1];
+ cmd_mfi = &sc->mfi_commands[cmd_tbolt->sync_cmd_idx];
+ scsi_io_req = cmd_tbolt->io_request;
+
+ /* Check if internal commands */
+ status = cmd_mfi->cm_frame->dcmd.header.cmd_status;
+ extStatus = cmd_mfi->cm_frame->dcmd.header.scsi_status;
+
+ switch (scsi_io_req->Function) {
+ case MPI2_FUNCTION_LD_IO_REQUEST:
+ /* Regular Path IO. */
+ /* Map the Fw Error Status. */
+ map_tbolt_cmd_status(cmd_mfi, status,
+ extStatus);
+ if ((cmd_mfi->cm_frame->dcmd.opcode
+ == MFI_DCMD_LD_MAP_GET_INFO)
+ && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) {
+ if (cmd_mfi->cm_frame->header.cmd_status
+ != 0)
+ device_printf(sc->mfi_dev,
+ "map sync failed\n");
+ else {
+ sc->map_id++;
+ device_printf(sc->mfi_dev,
+ "map sync completed\n");
+ mfi_release_command(cmd_mfi);
+ }
+ }
+ if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY)
+ == MFI_ON_MFIQ_BUSY
+ && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) {
+ /* BHARAT poll workaround */
+ mfi_remove_busy(cmd_mfi);
+ cmd_mfi->cm_error = 0;
+ mfi_complete(sc, cmd_mfi);
+ }
+ mfi_tbolt_return_cmd(sc, cmd_tbolt);
+ break;
+ case MPI2_FUNCTION_PASSTHRU_IO_REQUEST:
+ map_tbolt_cmd_status(cmd_mfi, status, extStatus);
+ if ((cmd_mfi->cm_frame->dcmd.opcode
+ == MFI_DCMD_LD_MAP_GET_INFO)
+ && (cmd_mfi->cm_frame->dcmd.mbox[1] == 1)) {
+ if (cmd_mfi->cm_frame->header.cmd_status != 0)
+ device_printf(sc->mfi_dev,
+ "map sync failed\n");
+ else {
+ sc->map_id++;
+ device_printf(sc->mfi_dev,
+ "map sync completed\n");
+ mfi_release_command(cmd_mfi);
+ }
+ }
+ if ((cmd_mfi->cm_flags & MFI_ON_MFIQ_BUSY)
+ == MFI_ON_MFIQ_BUSY
+ && (cmd_mfi->cm_flags & MFI_CMD_POLLED) == 0) {
+ /* BHARAT poll workaround */
+ mfi_remove_busy(cmd_mfi);
+ cmd_mfi->cm_error = 0;
+ mfi_complete(sc, cmd_mfi);
+ }
+ mfi_tbolt_return_cmd(sc, cmd_tbolt);
+ break;
+ }
+
+ sc->last_reply_idx++;
+ if (sc->last_reply_idx >= sc->mfi_max_fw_cmds) {
+ MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
+ sc->last_reply_idx = 0;
+ }
+ /*set it back to all 0xfff.*/
+ ((union mfi_mpi2_reply_descriptor*)desc)->words =
+ ~((uint64_t)0x00);
+
+ num_completed++;
+
+ /* Get the next reply descriptor */
+ desc = (struct mfi_mpi2_reply_header *)
+ ((uintptr_t)sc->reply_frame_pool_align
+ + sc->last_reply_idx * sc->reply_size);
+ reply_desc = desc;
+ val.word = ((union mfi_mpi2_reply_descriptor*)desc)->words;
+ reply_descript_type = reply_desc->ReplyFlags
+ & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
+ if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
+ break;
+ }
+
+ if (!num_completed)
+ return;
+
+ /* update replyIndex to FW */
+ if (sc->last_reply_idx)
+ MFI_WRITE4(sc, MFI_RPI, sc->last_reply_idx);
+
+ return;
+}
+
+/**
+ * mfi_get_cmd - Get a command from the free pool
+ * @instance: Adapter soft state
+ *
+ * Returns a free command from the pool
+ */
+
+struct mfi_cmd_tbolt *mfi_tbolt_get_cmd(struct mfi_softc
+ *sc)
+{
+ struct mfi_cmd_tbolt *cmd = NULL;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+
+ cmd = TAILQ_FIRST(&sc->mfi_cmd_tbolt_tqh);
+ TAILQ_REMOVE(&sc->mfi_cmd_tbolt_tqh, cmd, next);
+ memset((uint8_t *)cmd->sg_frame, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
+ memset((uint8_t *)cmd->io_request, 0,
+ MEGASAS_THUNDERBOLT_NEW_MSG_SIZE);
+ return cmd;
+}
+
+union mfi_mpi2_request_descriptor *
+mfi_tbolt_get_request_descriptor(struct mfi_softc *sc, uint16_t index)
+{
+ uint8_t *p;
+
+ if (index >= sc->mfi_max_fw_cmds) {
+ device_printf(sc->mfi_dev, "Invalid SMID (0x%x)request "
+ "for descriptor\n", index);
+ return NULL;
+ }
+ p = sc->request_desc_pool + sizeof(union mfi_mpi2_request_descriptor)
+ * index;
+ memset(p, 0, sizeof(union mfi_mpi2_request_descriptor));
+ return (union mfi_mpi2_request_descriptor *)p;
+}
+
+
+/* Used to build IOCTL cmd */
+uint8_t
+mfi_build_mpt_pass_thru(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
+{
+ MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain;
+ struct mfi_mpi2_request_raid_scsi_io *io_req;
+ struct mfi_cmd_tbolt *cmd;
+
+ cmd = mfi_tbolt_get_cmd(sc);
+ if (!cmd)
+ return EBUSY;
+ mfi_cmd->cm_extra_frames = cmd->index; /* Frame count used as SMID */
+ cmd->sync_cmd_idx = mfi_cmd->cm_index;
+ io_req = cmd->io_request;
+ mpi25_ieee_chain = (MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain;
+
+ io_req->Function = MPI2_FUNCTION_PASSTHRU_IO_REQUEST;
+ io_req->SGLOffset0 = offsetof(struct mfi_mpi2_request_raid_scsi_io,
+ SGL) / 4;
+ io_req->ChainOffset = sc->chain_offset_value_for_mpt_ptmsg;
+
+ mpi25_ieee_chain->Address = mfi_cmd->cm_frame_busaddr;
+
+ /*
+ In MFI pass thru, nextChainOffset will always be zero to
+ indicate the end of the chain.
+ */
+ mpi25_ieee_chain->Flags= MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT
+ | MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
+
+ /* setting the length to the maximum length */
+ mpi25_ieee_chain->Length = 1024;
+
+ return 0;
+}
+
+void
+mfi_tbolt_build_ldio(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
+ struct mfi_cmd_tbolt *cmd)
+{
+ uint32_t start_lba_lo = 0, start_lba_hi = 0, device_id;
+ struct mfi_mpi2_request_raid_scsi_io *io_request;
+ struct IO_REQUEST_INFO io_info;
+
+ device_id = mfi_cmd->cm_frame->io.header.target_id;
+ io_request = cmd->io_request;
+ io_request->RaidContext.TargetID = device_id;
+ io_request->RaidContext.Status = 0;
+ io_request->RaidContext.exStatus =0;
+
+ start_lba_lo = mfi_cmd->cm_frame->io.lba_lo;
+ start_lba_hi = mfi_cmd->cm_frame->io.lba_hi;
+
+ memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO));
+ io_info.ldStartBlock = ((uint64_t)start_lba_hi << 32) | start_lba_lo;
+ io_info.numBlocks = mfi_cmd->cm_frame->io.header.data_len;
+ io_info.ldTgtId = device_id;
+ if ((mfi_cmd->cm_frame->header.flags & MFI_FRAME_DIR_READ) ==
+ MFI_FRAME_DIR_READ)
+ io_info.isRead = 1;
+
+ io_request->RaidContext.timeoutValue
+ = MFI_FUSION_FP_DEFAULT_TIMEOUT;
+ io_request->Function = MPI2_FUNCTION_LD_IO_REQUEST;
+ io_request->DevHandle = device_id;
+ cmd->request_desc->header.RequestFlags
+ = (MFI_REQ_DESCRIPT_FLAGS_LD_IO
+ << MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ if ((io_request->IoFlags == 6) && (io_info.numBlocks == 0))
+ io_request->RaidContext.RegLockLength = 0x100;
+ io_request->DataLength = mfi_cmd->cm_frame->io.header.data_len
+ * MFI_SECTOR_LEN;
+}
+
+int mfi_tbolt_is_ldio(struct mfi_command *mfi_cmd)
+{
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_READ
+ || mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ return 1;
+ else
+ return 0;
+}
+
+int
+mfi_tbolt_build_io(struct mfi_softc *sc, struct mfi_command *mfi_cmd, struct mfi_cmd_tbolt *cmd)
+{
+ uint32_t device_id;
+ uint32_t sge_count;
+ uint8_t cdb[32], cdb_len;
+
+ memset(cdb, 0, 32);
+ struct mfi_mpi2_request_raid_scsi_io *io_request = cmd->io_request;
+
+ device_id = mfi_cmd->cm_frame->header.target_id;
+
+ /* Have to build CDB here for TB as BSD don't have a scsi layer */
+ if ((cdb_len = mfi_tbolt_build_cdb(sc, mfi_cmd, cdb)) == 1)
+ return 1;
+
+ /* Just the CDB length,rest of the Flags are zero */
+ io_request->IoFlags = cdb_len;
+ memcpy(io_request->CDB.CDB32, cdb, 32);
+
+ if (mfi_tbolt_is_ldio(mfi_cmd))
+ mfi_tbolt_build_ldio(sc, mfi_cmd , cmd);
+ else
+ return 1;
+
+ /*
+ * Construct SGL
+ */
+ sge_count = mfi_tbolt_make_sgl(sc, mfi_cmd,
+ (pMpi25IeeeSgeChain64_t) &io_request->SGL, cmd);
+ if (sge_count > sc->mfi_max_sge) {
+ device_printf(sc->mfi_dev, "Error. sge_count (0x%x) exceeds "
+ "max (0x%x) allowed\n", sge_count, sc->mfi_max_sge);
+ return 1;
+ }
+ io_request->RaidContext.numSGE = sge_count;
+ io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ io_request->Control = MPI2_SCSIIO_CONTROL_WRITE;
+ else
+ io_request->Control = MPI2_SCSIIO_CONTROL_READ;
+
+ io_request->SGLOffset0 = offsetof(
+ struct mfi_mpi2_request_raid_scsi_io, SGL)/4;
+
+ io_request->SenseBufferLowAddress = mfi_cmd->cm_sense_busaddr;
+ io_request->SenseBufferLength = MFI_SENSE_LEN;
+ return 0;
+}
+
+static int
+mfi_tbolt_build_cdb(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
+ uint8_t *cdb)
+{
+ uint32_t lba_lo, lba_hi, num_lba;
+ uint8_t cdb_len;
+
+ if (mfi_cmd == NULL || cdb == NULL)
+ return 1;
+ num_lba = mfi_cmd->cm_frame->io.header.data_len;
+ lba_lo = mfi_cmd->cm_frame->io.lba_lo;
+ lba_hi = mfi_cmd->cm_frame->io.lba_hi;
+
+ if ((num_lba <= 0xFF) && (lba_lo <= 0x1FFFFF)) {
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ /* Read 6 or Write 6 */
+ cdb[0] = (uint8_t) (0x0A);
+ else
+ cdb[0] = (uint8_t) (0x08);
+
+ cdb[4] = (uint8_t) num_lba;
+ cdb[3] = (uint8_t) (lba_lo & 0xFF);
+ cdb[2] = (uint8_t) (lba_lo >> 8);
+ cdb[1] = (uint8_t) ((lba_lo >> 16) & 0x1F);
+ cdb_len = 6;
+ }
+ else if ((num_lba <= 0xFFFF) && (lba_lo <= 0xFFFFFFFF)) {
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ /* Read 10 or Write 10 */
+ cdb[0] = (uint8_t) (0x2A);
+ else
+ cdb[0] = (uint8_t) (0x28);
+ cdb[8] = (uint8_t) (num_lba & 0xFF);
+ cdb[7] = (uint8_t) (num_lba >> 8);
+ cdb[5] = (uint8_t) (lba_lo & 0xFF);
+ cdb[4] = (uint8_t) (lba_lo >> 8);
+ cdb[3] = (uint8_t) (lba_lo >> 16);
+ cdb[2] = (uint8_t) (lba_lo >> 24);
+ cdb_len = 10;
+ }
+ else if ((num_lba > 0xFFFF) && (lba_hi == 0)) {
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ /* Read 12 or Write 12 */
+ cdb[0] = (uint8_t) (0xAA);
+ else
+ cdb[0] = (uint8_t) (0xA8);
+ cdb[9] = (uint8_t) (num_lba & 0xFF);
+ cdb[8] = (uint8_t) (num_lba >> 8);
+ cdb[7] = (uint8_t) (num_lba >> 16);
+ cdb[6] = (uint8_t) (num_lba >> 24);
+ cdb[5] = (uint8_t) (lba_lo & 0xFF);
+ cdb[4] = (uint8_t) (lba_lo >> 8);
+ cdb[3] = (uint8_t) (lba_lo >> 16);
+ cdb[2] = (uint8_t) (lba_lo >> 24);
+ cdb_len = 12;
+ } else {
+ if (mfi_cmd->cm_frame->header.cmd == MFI_CMD_LD_WRITE)
+ cdb[0] = (uint8_t) (0x8A);
+ else
+ cdb[0] = (uint8_t) (0x88);
+ cdb[13] = (uint8_t) (num_lba & 0xFF);
+ cdb[12] = (uint8_t) (num_lba >> 8);
+ cdb[11] = (uint8_t) (num_lba >> 16);
+ cdb[10] = (uint8_t) (num_lba >> 24);
+ cdb[9] = (uint8_t) (lba_lo & 0xFF);
+ cdb[8] = (uint8_t) (lba_lo >> 8);
+ cdb[7] = (uint8_t) (lba_lo >> 16);
+ cdb[6] = (uint8_t) (lba_lo >> 24);
+ cdb[5] = (uint8_t) (lba_hi & 0xFF);
+ cdb[4] = (uint8_t) (lba_hi >> 8);
+ cdb[3] = (uint8_t) (lba_hi >> 16);
+ cdb[2] = (uint8_t) (lba_hi >> 24);
+ cdb_len = 16;
+ }
+ return cdb_len;
+}
+
+static int
+mfi_tbolt_make_sgl(struct mfi_softc *sc, struct mfi_command *mfi_cmd,
+ pMpi25IeeeSgeChain64_t sgl_ptr, struct mfi_cmd_tbolt *cmd)
+{
+ uint8_t i, sg_processed, sg_to_process;
+ uint8_t sge_count, sge_idx;
+ union mfi_sgl *os_sgl;
+
+ /*
+ * Return 0 if there is no data transfer
+ */
+ if (!mfi_cmd->cm_sg || !mfi_cmd->cm_len) {
+ device_printf(sc->mfi_dev, "Buffer empty \n");
+ return 0;
+ }
+ os_sgl = mfi_cmd->cm_sg;
+ sge_count = mfi_cmd->cm_frame->header.sg_count;
+
+ if (sge_count > sc->mfi_max_sge) {
+ device_printf(sc->mfi_dev, "sgl ptr %p sg_cnt %d \n",
+ os_sgl, sge_count);
+ return sge_count;
+ }
+
+ if (sge_count > sc->max_SGEs_in_main_message)
+ /* One element to store the chain info */
+ sge_idx = sc->max_SGEs_in_main_message - 1;
+ else
+ sge_idx = sge_count;
+
+ for (i = 0; i < sge_idx; i++) {
+ /*
+ * For 32bit BSD we are getting 32 bit SGL's from OS
+ * but FW only take 64 bit SGL's so copying from 32 bit
+ * SGL's to 64.
+ */
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+ sgl_ptr->Length = os_sgl->sg_skinny[i].len;
+ sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
+ } else {
+ sgl_ptr->Length = os_sgl->sg32[i].len;
+ sgl_ptr->Address = os_sgl->sg32[i].addr;
+ }
+ sgl_ptr->Flags = 0;
+ sgl_ptr++;
+ cmd->io_request->ChainOffset = 0;
+ }
+
+ sg_processed = i;
+
+ if (sg_processed < sge_count) {
+ pMpi25IeeeSgeChain64_t sg_chain;
+ sg_to_process = sge_count - sg_processed;
+ cmd->io_request->ChainOffset =
+ sc->chain_offset_value_for_main_message;
+ sg_chain = sgl_ptr;
+ /* Prepare chain element */
+ sg_chain->NextChainOffset = 0;
+ sg_chain->Flags = (MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT |
+ MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
+ sg_chain->Length = (sizeof(MPI2_SGE_IO_UNION) *
+ (sge_count - sg_processed));
+ sg_chain->Address = cmd->sg_frame_phys_addr;
+ sgl_ptr = (pMpi25IeeeSgeChain64_t)cmd->sg_frame;
+ for (; i < sge_count; i++) {
+ if (sc->mfi_flags & MFI_FLAGS_SKINNY) {
+ sgl_ptr->Length = os_sgl->sg_skinny[i].len;
+ sgl_ptr->Address = os_sgl->sg_skinny[i].addr;
+ } else {
+ sgl_ptr->Length = os_sgl->sg32[i].len;
+ sgl_ptr->Address = os_sgl->sg32[i].addr;
+ }
+ sgl_ptr->Flags = 0;
+ sgl_ptr++;
+ }
+ }
+ return sge_count;
+}
+
+union mfi_mpi2_request_descriptor *
+mfi_build_and_issue_cmd(struct mfi_softc *sc, struct mfi_command *mfi_cmd)
+{
+ struct mfi_cmd_tbolt *cmd;
+ union mfi_mpi2_request_descriptor *req_desc = NULL;
+ uint16_t index;
+ cmd = mfi_tbolt_get_cmd(sc);
+ if (!cmd)
+ return NULL;
+ mfi_cmd->cm_extra_frames = cmd->index;
+ cmd->sync_cmd_idx = mfi_cmd->cm_index;
+
+ index = cmd->index;
+ req_desc = mfi_tbolt_get_request_descriptor(sc, index-1);
+ if (mfi_tbolt_build_io(sc, mfi_cmd, cmd))
+ return NULL;
+ req_desc->header.SMID = index;
+ return req_desc;
+}
+
+union mfi_mpi2_request_descriptor *
+mfi_tbolt_build_mpt_cmd(struct mfi_softc *sc, struct mfi_command *cmd)
+{
+ union mfi_mpi2_request_descriptor *req_desc = NULL;
+ uint16_t index;
+ if (mfi_build_mpt_pass_thru(sc, cmd)) {
+ device_printf(sc->mfi_dev, "Couldn't build MFI pass thru "
+ "cmd\n");
+ return NULL;
+ }
+ /* For fusion the frame_count variable is used for SMID */
+ index = cmd->cm_extra_frames;
+
+ req_desc = mfi_tbolt_get_request_descriptor(sc, index - 1);
+ if (!req_desc)
+ return NULL;
+
+ bzero(req_desc, sizeof(req_desc));
+ req_desc->header.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ req_desc->header.SMID = index;
+ return req_desc;
+}
+
+int
+mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm)
+{
+ struct mfi_frame_header *hdr;
+ uint8_t *cdb;
+ union mfi_mpi2_request_descriptor *req_desc = NULL;
+ int tm = MFI_POLL_TIMEOUT_SECS * 1000;
+
+ hdr = &cm->cm_frame->header;
+ cdb = cm->cm_frame->pass.cdb;
+ if (sc->adpreset)
+ return 1;
+ if ((cm->cm_flags & MFI_CMD_POLLED) == 0) {
+ cm->cm_timestamp = time_uptime;
+ mfi_enqueue_busy(cm);
+ }
+ else {
+ hdr->cmd_status = 0xff;
+ hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+ }
+
+ if (hdr->cmd == MFI_CMD_PD_SCSI_IO) {
+ /* check for inquiry commands coming from CLI */
+ if (cdb[0] != 0x28 || cdb[0] != 0x2A) {
+ if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) ==
+ NULL) {
+ device_printf(sc->mfi_dev, "Mapping from MFI "
+ "to MPT Failed \n");
+ return 1;
+ }
+ }
+ else
+ device_printf(sc->mfi_dev, "DJA NA XXX SYSPDIO\n");
+ }
+ else if (hdr->cmd == MFI_CMD_LD_SCSI_IO ||
+ hdr->cmd == MFI_CMD_LD_READ || hdr->cmd == MFI_CMD_LD_WRITE) {
+ if ((req_desc = mfi_build_and_issue_cmd(sc, cm)) == NULL) {
+ device_printf(sc->mfi_dev, "LDIO Failed \n");
+ return 1;
+ }
+ } else
+ if ((req_desc = mfi_tbolt_build_mpt_cmd(sc, cm)) == NULL) {
+ device_printf(sc->mfi_dev, "Mapping from MFI to MPT "
+ "Failed\n");
+ return 1;
+ }
+ MFI_WRITE4(sc, MFI_ILQP, (req_desc->words & 0xFFFFFFFF));
+ MFI_WRITE4(sc, MFI_IHQP, (req_desc->words >>0x20));
+
+ if ((cm->cm_flags & MFI_CMD_POLLED) == 0)
+ return 0;
+
+ /* This is a polled command, so busy-wait for it to complete. */
+ while (hdr->cmd_status == 0xff) {
+ DELAY(1000);
+ tm -= 1;
+ if (tm <= 0)
+ break;
+ }
+
+ if (hdr->cmd_status == 0xff) {
+ device_printf(sc->mfi_dev, "Frame %p timed out "
+ "command 0x%X\n", hdr, cm->cm_frame->dcmd.opcode);
+ return (ETIMEDOUT);
+ }
+ return 0;
+}
+
+static void mfi_issue_pending_cmds_again (struct mfi_softc *sc)
+{
+ struct mfi_command *cm, *tmp;
+
+ mtx_assert(&sc->mfi_io_lock, MA_OWNED);
+ TAILQ_FOREACH_REVERSE_SAFE(cm, &sc->mfi_busy, BUSYQ, cm_link, tmp) {
+
+ cm->retry_for_fw_reset++;
+
+ /*
+ * If a command has continuously been tried multiple times
+ * and causing a FW reset condition, no further recoveries
+ * should be performed on the controller
+ */
+ if (cm->retry_for_fw_reset == 3) {
+ device_printf(sc->mfi_dev, "megaraid_sas: command %d "
+ "was tried multiple times during adapter reset"
+ "Shutting down the HBA\n", cm->cm_index);
+ mfi_kill_hba(sc);
+ sc->hw_crit_error = 1;
+ return;
+ }
+
+ if ((cm->cm_flags & MFI_ON_MFIQ_BUSY) != 0) {
+ struct mfi_cmd_tbolt *cmd;
+ mfi_remove_busy(cm);
+ cmd = sc->mfi_cmd_pool_tbolt[cm->cm_extra_frames -
+ 1 ];
+ mfi_tbolt_return_cmd(sc, cmd);
+ if ((cm->cm_flags & MFI_ON_MFIQ_MASK) == 0) {
+ if (cm->cm_frame->dcmd.opcode !=
+ MFI_DCMD_CTRL_EVENT_WAIT) {
+ device_printf(sc->mfi_dev,
+ "APJ ****requeue command %d \n",
+ cm->cm_index);
+ mfi_requeue_ready(cm);
+ }
+ }
+ else
+ mfi_release_command(cm);
+ }
+ }
+ mfi_startio(sc);
+}
+
+static void mfi_kill_hba (struct mfi_softc *sc)
+{
+ if (sc->mfi_flags & MFI_FLAGS_TBOLT)
+ MFI_WRITE4 (sc, 0x00,MFI_STOP_ADP);
+ else
+ MFI_WRITE4 (sc, MFI_IDB,MFI_STOP_ADP);
+}
+
+static void mfi_process_fw_state_chg_isr(void *arg)
+{
+ struct mfi_softc *sc= (struct mfi_softc *)arg;
+ struct mfi_cmd_tbolt *cmd;
+ int error, status;
+
+ if (sc->adpreset == 1) {
+ device_printf(sc->mfi_dev, "First stage of FW reset "
+ "initiated...\n");
+
+ sc->mfi_adp_reset(sc);
+ sc->mfi_enable_intr(sc);
+
+ device_printf(sc->mfi_dev, "First stage of reset complete, "
+ "second stage initiated...\n");
+
+ sc->adpreset = 2;
+
+ /* waiting for about 20 second before start the second init */
+ for (int wait = 0; wait < 20000; wait++)
+ DELAY(1000);
+ device_printf(sc->mfi_dev, "Second stage of FW reset "
+ "initiated...\n");
+ while ((status = MFI_READ4(sc, MFI_RSR)) & 0x04);
+
+ sc->mfi_disable_intr(sc);
+
+ /* We expect the FW state to be READY */
+ if (mfi_transition_firmware(sc)) {
+ device_printf(sc->mfi_dev, "controller is not in "
+ "ready state\n");
+ mfi_kill_hba(sc);
+ sc->hw_crit_error= 1;
+ return ;
+ }
+ if ((error = mfi_tbolt_init_MFI_queue(sc)) != 0)
+ return;
+
+ mtx_lock(&sc->mfi_io_lock);
+
+ sc->mfi_enable_intr(sc);
+ sc->adpreset = 0;
+ free(sc->mfi_aen_cm->cm_data, M_MFIBUF);
+ mfi_remove_busy(sc->mfi_aen_cm);
+ cmd = sc->mfi_cmd_pool_tbolt[sc->mfi_aen_cm->cm_extra_frames
+ - 1];
+ mfi_tbolt_return_cmd(sc, cmd);
+ if (sc->mfi_aen_cm) {
+ mfi_release_command(sc->mfi_aen_cm);
+ sc->mfi_aen_cm = NULL;
+ }
+ if (sc->map_update_cmd) {
+ mfi_release_command(sc->map_update_cmd);
+ sc->map_update_cmd = NULL;
+ }
+ mfi_issue_pending_cmds_again(sc);
+
+ /*
+ * Issue pending command can result in adapter being marked
+ * dead because of too many re-tries. Check for that
+ * condition before clearing the reset condition on the FW
+ */
+ if (!sc->hw_crit_error) {
+ /*
+ * Initiate AEN (Asynchronous Event Notification)
+ */
+ mfi_aen_setup(sc, sc->last_seq_num);
+ sc->issuepend_done = 1;
+ device_printf(sc->mfi_dev, "second stage of reset "
+ "complete, FW is ready now.\n");
+ } else {
+ device_printf(sc->mfi_dev, "second stage of reset "
+ "never completed, hba was marked offline.\n");
+ }
+ } else {
+ device_printf(sc->mfi_dev, "mfi_process_fw_state_chg_isr "
+ "called with unhandled value:%d\n", sc->adpreset);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+}
diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h
index f005c37..627b759 100644
--- a/sys/dev/mfi/mfireg.h
+++ b/sys/dev/mfi/mfireg.h
@@ -64,7 +64,7 @@ __FBSDID("$FreeBSD$");
* reason why this interface should be limited to just SAS. In any case, LSI
* seems to also call this interface 'MFI', so that will be used here.
*/
-
+#define MEGAMFI_FRAME_SIZE 64
/*
* Start with the register set. All registers are 32 bits wide.
* The usual Intel IOP style setup.
@@ -83,25 +83,50 @@ __FBSDID("$FreeBSD$");
#define MFI_OQP 0x44 /* Outbound queue port */
/*
+* ThunderBolt specific Register
+*/
+
+#define MFI_RPI 0x6c /* reply_post_host_index */
+#define MFI_ILQP 0xc0 /* inbound_low_queue_port */
+#define MFI_IHQP 0xc4 /* inbound_high_queue_port */
+
+/*
* 1078 specific related register
*/
#define MFI_ODR0 0x9c /* outbound doorbell register0 */
#define MFI_ODCR0 0xa0 /* outbound doorbell clear register0 */
#define MFI_OSP0 0xb0 /* outbound scratch pad0 */
#define MFI_1078_EIM 0x80000004 /* 1078 enable intrrupt mask */
-#define MFI_RMI 0x2 /* reply message interrupt */
+#define MFI_RMI 0x2 /* reply message interrupt */
#define MFI_1078_RM 0x80000000 /* reply 1078 message interrupt */
#define MFI_ODC 0x4 /* outbound doorbell change interrupt */
+/* OCR registers */
+#define MFI_WSR 0x004 /* write sequence register */
+#define MFI_HDR 0x008 /* host diagnostic register */
+#define MFI_RSR 0x3c3 /* Reset Status Register */
+
/*
* GEN2 specific changes
*/
#define MFI_GEN2_EIM 0x00000005 /* GEN2 enable interrupt mask */
#define MFI_GEN2_RM 0x00000001 /* reply GEN2 message interrupt */
+/*
+ * skinny specific changes
+ */
+#define MFI_SKINNY_IDB 0x00 /* Inbound doorbell is at 0x00 for skinny */
+#define MFI_IQPL 0x000000c0
+#define MFI_IQPH 0x000000c4
+#define MFI_SKINNY_RM 0x00000001 /* reply skinny message interrupt */
+
/* Bits for MFI_OSTS */
#define MFI_OSTS_INTR_VALID 0x00000002
+/* OCR specific flags */
+#define MFI_FIRMWARE_STATE_CHANGE 0x00000002
+#define MFI_STATE_CHANGE_INTERRUPT 0x00000004 /* MFI state change interrrupt */
+
/*
* Firmware state values. Found in OMSG0 during initialization.
*/
@@ -119,6 +144,16 @@ __FBSDID("$FreeBSD$");
#define MFI_FWSTATE_FAULT 0xf0000000
#define MFI_FWSTATE_MAXSGL_MASK 0x00ff0000
#define MFI_FWSTATE_MAXCMD_MASK 0x0000ffff
+#define MFI_FWSTATE_HOSTMEMREQD_MASK 0x08000000
+#define MFI_FWSTATE_BOOT_MESSAGE_PENDING 0x90000000
+#define MFI_RESET_REQUIRED 0x00000001
+
+/* ThunderBolt Support */
+#define MFI_FWSTATE_TB_MASK 0xf0000000
+#define MFI_FWSTATE_TB_RESET 0x00000000
+#define MFI_FWSTATE_TB_READY 0x10000000
+#define MFI_FWSTATE_TB_OPERATIONAL 0x20000000
+#define MFI_FWSTATE_TB_FAULT 0x40000000
/*
* Control bits to drive the card to ready state. These go into the IDB
@@ -130,6 +165,12 @@ __FBSDID("$FreeBSD$");
#define MFI_FWINIT_CLEAR_HANDSHAKE 0x00000008 /* Respond to WAIT_HANDSHAKE */
#define MFI_FWINIT_HOTPLUG 0x00000010
+/* ADP reset flags */
+#define MFI_STOP_ADP 0x00000020
+#define MFI_ADP_RESET 0x00000040
+#define DIAG_WRITE_ENABLE 0x00000080
+#define DIAG_RESET_ADAPTER 0x00000004
+
/* MFI Commands */
typedef enum {
MFI_CMD_INIT = 0x00,
@@ -146,6 +187,7 @@ typedef enum {
/* Direct commands */
typedef enum {
MFI_DCMD_CTRL_GETINFO = 0x01010000,
+ MFI_DCMD_CTRL_MFI_HOST_MEM_ALLOC =0x0100e100,
MFI_DCMD_CTRL_MFC_DEFAULTS_GET =0x010e0201,
MFI_DCMD_CTRL_MFC_DEFAULTS_SET =0x010e0202,
MFI_DCMD_CTRL_FLUSHCACHE = 0x01101000,
@@ -164,6 +206,7 @@ typedef enum {
MFI_DCMD_FLASH_FW_FLASH = 0x010f0300,
MFI_DCMD_FLASH_FW_CLOSE = 0x010f0400,
MFI_DCMD_PD_GET_LIST = 0x02010000,
+ MFI_DCMD_PD_LIST_QUERY = 0x02010100,
MFI_DCMD_PD_GET_INFO = 0x02020000,
MFI_DCMD_PD_STATE_SET = 0x02030100,
MFI_DCMD_PD_REBUILD_START = 0x02040100,
@@ -173,6 +216,8 @@ typedef enum {
MFI_DCMD_PD_GET_PROGRESS = 0x02060000,
MFI_DCMD_PD_LOCATE_START = 0x02070100,
MFI_DCMD_PD_LOCATE_STOP = 0x02070200,
+ MFI_DCMD_LD_MAP_GET_INFO = 0x0300e101,
+ MFI_DCMD_LD_SYNC = 0x0300e102,
MFI_DCMD_LD_GET_LIST = 0x03010000,
MFI_DCMD_LD_GET_INFO = 0x03020000,
MFI_DCMD_LD_GET_PROP = 0x03030000,
@@ -183,7 +228,7 @@ typedef enum {
MFI_DCMD_CFG_ADD = 0x04020000,
MFI_DCMD_CFG_CLEAR = 0x04030000,
MFI_DCMD_CFG_MAKE_SPARE = 0x04040000,
- MFI_DCMD_CFG_REMOVE_SPARE = 0x04050000,
+ MFI_DCMD_CFG_REMOVE_SPARE = 0x04050000,
MFI_DCMD_CFG_FOREIGN_IMPORT = 0x04060400,
MFI_DCMD_BBU_GET_STATUS = 0x05010000,
MFI_DCMD_BBU_GET_CAPACITY_INFO =0x05020000,
@@ -213,6 +258,36 @@ typedef enum {
#define MFI_FRAME_DIR_WRITE 0x0008
#define MFI_FRAME_DIR_READ 0x0010
#define MFI_FRAME_DIR_BOTH 0x0018
+#define MFI_FRAME_IEEE_SGL 0x0020
+
+/* ThunderBolt Specific */
+
+/*
+ * Pre-TB command size and TB command size.
+ * We will be checking it at the load time for the time being
+ */
+#define MR_COMMAND_SIZE (MFI_FRAME_SIZE*20) /* 1280 bytes */
+
+#define MEGASAS_THUNDERBOLT_MSG_ALLIGNMENT 256
+/*
+ * We are defining only 128 byte message to reduce memory move over head
+ * and also it will reduce the SRB extension size by 128byte compared with
+ * 256 message size
+ */
+#define MEGASAS_THUNDERBOLT_NEW_MSG_SIZE 256
+#define MEGASAS_THUNDERBOLT_MAX_COMMANDS 1024
+#define MEGASAS_THUNDERBOLT_MAX_REPLY_COUNT 1024
+#define MEGASAS_THUNDERBOLT_REPLY_SIZE 8
+#define MEGASAS_THUNDERBOLT_MAX_CHAIN_COUNT 1
+#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
+
+#define MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
+#define MPI2_FUNCTION_LD_IO_REQUEST 0xF1
+
+#define MR_INTERNAL_MFI_FRAMES_SMID 1
+#define MR_CTRL_EVENT_WAIT_SMID 2
+#define MR_INTERNAL_DRIVER_RESET_SMID 3
+
/* MFI Status codes */
typedef enum {
@@ -325,6 +400,10 @@ typedef enum {
MR_EVT_ARGS_ECC
} mfi_evt_args;
+#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
+#define MR_EVT_PD_REMOVED 0x0070
+#define MR_EVT_PD_INSERTED 0x005b
+
typedef enum {
MR_LD_CACHE_WRITE_BACK = 0x01,
MR_LD_CACHE_WRITE_ADAPTIVE = 0x02,
@@ -352,6 +431,15 @@ typedef enum {
MR_PD_CACHE_DISABLE = 2
} mfi_pd_cache;
+typedef enum {
+ MR_PD_QUERY_TYPE_ALL = 0,
+ MR_PD_QUERY_TYPE_STATE = 1,
+ MR_PD_QUERY_TYPE_POWER_STATE = 2,
+ MR_PD_QUERY_TYPE_MEDIA_TYPE = 3,
+ MR_PD_QUERY_TYPE_SPEED = 4,
+ MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5 /*query for system drives */
+} mfi_pd_query_type;
+
/*
* Other propertities and definitions
*/
@@ -384,9 +472,16 @@ struct mfi_sg64 {
uint32_t len;
} __packed;
+struct mfi_sg_skinny {
+ uint64_t addr;
+ uint32_t len;
+ uint32_t flag;
+} __packed;
+
union mfi_sgl {
- struct mfi_sg32 sg32[1];
- struct mfi_sg64 sg64[1];
+ struct mfi_sg32 sg32[1];
+ struct mfi_sg64 sg64[1];
+ struct mfi_sg_skinny sg_skinny[1];
} __packed;
/* Message frames. All messages have a common header */
@@ -400,6 +495,10 @@ struct mfi_frame_header {
uint8_t cdb_len;
uint8_t sg_count;
uint32_t context;
+ /*
+ * pad0 is MSI Specific. Not used by Driver. Zero the value before
+ * sending the command to f/w.
+ */
uint32_t pad0;
uint16_t flags;
#define MFI_FRAME_DATAOUT 0x08
@@ -414,9 +513,29 @@ struct mfi_init_frame {
uint32_t qinfo_new_addr_hi;
uint32_t qinfo_old_addr_lo;
uint32_t qinfo_old_addr_hi;
- uint32_t reserved[6];
+ // Start LSIP200113393
+ uint32_t driver_ver_lo; /*28h */
+ uint32_t driver_ver_hi; /*2Ch */
+
+ uint32_t reserved[4];
+ // End LSIP200113393
} __packed;
+/*
+ * Define MFI Address Context union.
+ */
+#ifdef MFI_ADDRESS_IS_uint64_t
+ typedef uint64_t MFI_ADDRESS;
+#else
+ typedef union _MFI_ADDRESS {
+ struct {
+ uint32_t addressLow;
+ uint32_t addressHigh;
+ } u;
+ uint64_t address;
+ } MFI_ADDRESS, *PMFI_ADDRESS;
+#endif
+
#define MFI_IO_FRAME_SIZE 40
struct mfi_io_frame {
struct mfi_frame_header header;
@@ -447,10 +566,11 @@ struct mfi_dcmd_frame {
struct mfi_abort_frame {
struct mfi_frame_header header;
uint32_t abort_context;
- uint32_t pad;
+ /* pad is changed to reserved.*/
+ uint32_t reserved0;
uint32_t abort_mfi_addr_lo;
uint32_t abort_mfi_addr_hi;
- uint32_t reserved[6];
+ uint32_t reserved1[6];
} __packed;
struct mfi_smp_frame {
@@ -475,6 +595,7 @@ struct mfi_stp_frame {
union mfi_frame {
struct mfi_frame_header header;
struct mfi_init_frame init;
+ /* ThunderBolt Initialization */
struct mfi_io_frame io;
struct mfi_pass_frame pass;
struct mfi_dcmd_frame dcmd;
@@ -524,7 +645,61 @@ struct mfi_ctrl_props {
uint16_t ecc_bucket_leak_rate;
uint8_t restore_hotspare_on_insertion;
uint8_t expose_encl_devices;
- uint8_t reserved[38];
+ uint8_t maintainPdFailHistory;
+ uint8_t disallowHostRequestReordering;
+ /* set TRUE to abort CC on detecting an inconsistency */
+ uint8_t abortCCOnError;
+ /* load balance mode (MR_LOAD_BALANCE_MODE) */
+ uint8_t loadBalanceMode;
+ /*
+ * 0 - use auto detect logic of backplanes like SGPIO, i2c SEP using
+ * h/w mechansim like GPIO pins
+ * 1 - disable auto detect SGPIO,
+ * 2 - disable i2c SEP auto detect
+ * 3 - disable both auto detect
+ */
+ uint8_t disableAutoDetectBackplane;
+ /*
+ * % of source LD to be reserved for a VDs snapshot in snapshot
+ * repository, for metadata and user data: 1=5%, 2=10%, 3=15% and so on
+ */
+ uint8_t snapVDSpace;
+
+ /*
+ * Add properties that can be controlled by a bit in the following
+ * structure.
+ */
+ struct {
+ /* set TRUE to disable copyBack (0=copback enabled) */
+ uint32_t copyBackDisabled :1;
+ uint32_t SMARTerEnabled :1;
+ uint32_t prCorrectUnconfiguredAreas :1;
+ uint32_t useFdeOnly :1;
+ uint32_t disableNCQ :1;
+ uint32_t SSDSMARTerEnabled :1;
+ uint32_t SSDPatrolReadEnabled :1;
+ uint32_t enableSpinDownUnconfigured :1;
+ uint32_t autoEnhancedImport :1;
+ uint32_t enableSecretKeyControl :1;
+ uint32_t disableOnlineCtrlReset :1;
+ uint32_t allowBootWithPinnedCache :1;
+ uint32_t disableSpinDownHS :1;
+ uint32_t enableJBOD :1;
+ uint32_t reserved :18;
+ } OnOffProperties;
+ /*
+ * % of source LD to be reserved for auto snapshot in snapshot
+ * repository, for metadata and user data: 1=5%, 2=10%, 3=15% and so on.
+ */
+ uint8_t autoSnapVDSpace;
+ /*
+ * Snapshot writeable VIEWs capacity as a % of source LD capacity:
+ * 0=READ only, 1=5%, 2=10%, 3=15% and so on.
+ */
+ uint8_t viewSpace;
+ /* # of idle minutes before device is spun down (0=use FW defaults) */
+ uint16_t spinDownTime;
+ uint8_t reserved[24];
} __packed;
/* PCI information about the card. */
@@ -964,10 +1139,11 @@ struct mfi_pd_address {
uint64_t sas_addr[2];
} __packed;
+#define MAX_SYS_PDS 240
struct mfi_pd_list {
uint32_t size;
uint32_t count;
- struct mfi_pd_address addr[0];
+ struct mfi_pd_address addr[MAX_SYS_PDS];
} __packed;
enum mfi_pd_state {
@@ -982,6 +1158,12 @@ enum mfi_pd_state {
MFI_PD_STATE_SYSTEM = 0x40
};
+/*
+ * "SYSTEM" disk appears to be "JBOD" support from the RAID controller.
+ * Adding a #define to denote this.
+ */
+#define MFI_PD_STATE_JBOD MFI_PD_STATE_SYSTEM
+
union mfi_ld_ref {
struct {
uint8_t target_id;
@@ -1040,7 +1222,9 @@ struct mfi_ld_params {
#define MFI_LD_PARAMS_INIT_QUICK 1
#define MFI_LD_PARAMS_INIT_FULL 2
uint8_t is_consistent;
- uint8_t reserved[23];
+ uint8_t reserved1[6];
+ uint8_t isSSCD;
+ uint8_t reserved2[16];
} __packed;
struct mfi_ld_progress {
@@ -1081,7 +1265,7 @@ struct mfi_ld_info {
uint8_t reserved2[16];
} __packed;
-#define MAX_ARRAYS 16
+#define MFI_MAX_ARRAYS 16
struct mfi_spare {
union mfi_pd_ref ref;
uint8_t spare_type;
@@ -1090,9 +1274,10 @@ struct mfi_spare {
#define MFI_SPARE_ENCL_AFFINITY (1 << 2)
uint8_t reserved[2];
uint8_t array_count;
- uint16_t array_ref[MAX_ARRAYS];
+ uint16_t array_ref[MFI_MAX_ARRAYS];
} __packed;
+#define MFI_MAX_ROW_SIZE 32
struct mfi_array {
uint64_t size;
uint8_t num_drives;
@@ -1106,7 +1291,7 @@ struct mfi_array {
uint8_t pd;
uint8_t slot;
} encl;
- } pd[0];
+ } pd[MFI_MAX_ROW_SIZE];
} __packed;
struct mfi_config_data {
@@ -1182,7 +1367,7 @@ struct mfi_bbu_status {
uint8_t battery_type;
#define MFI_BBU_TYPE_NONE 0
#define MFI_BBU_TYPE_IBBU 1
-#define MFI_BBU_TYPE_BBU 2
+#define MFI_BBU_TYPE_BBU 2
uint8_t reserved;
uint16_t voltage;
int16_t current;
@@ -1230,6 +1415,450 @@ struct mfi_pr_properties {
uint32_t clear_freq;
};
+/* ThunderBolt support */
+
+/*
+ * Raid Context structure which describes MegaRAID specific IO Paramenters
+ * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames
+ */
+typedef struct _MPI2_SCSI_IO_VENDOR_UNIQUE {
+ uint16_t resvd0; /* 0x00 - 0x01 */
+ uint16_t timeoutValue; /* 0x02 - 0x03 */
+ uint8_t regLockFlags;
+ uint8_t armId;
+ uint16_t TargetID; /* 0x06 - 0x07 */
+
+ uint64_t RegLockLBA; /* 0x08 - 0x0F */
+
+ uint32_t RegLockLength; /* 0x10 - 0x13 */
+
+ uint16_t SMID; /* 0x14 - 0x15 nextLMId */
+ uint8_t exStatus; /* 0x16 */
+ uint8_t Status; /* 0x17 status */
+
+ uint8_t RAIDFlags; /* 0x18 */
+ uint8_t numSGE; /* 0x19 numSge */
+ uint16_t configSeqNum; /* 0x1A - 0x1B */
+ uint8_t spanArm; /* 0x1C */
+ uint8_t resvd2[3]; /* 0x1D - 0x1F */
+} MPI2_SCSI_IO_VENDOR_UNIQUE, MPI25_SCSI_IO_VENDOR_UNIQUE;
+
+/*****************************************************************************
+*
+* Message Functions
+*
+*****************************************************************************/
+
+#define NA_MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
+#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */
+#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
+#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */
+#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */
+#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */
+#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */
+#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */
+#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */
+#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */
+#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */
+#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */
+#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */
+#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */
+#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */
+#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */
+#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */
+#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */
+#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */
+#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */
+#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */
+#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */
+#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */
+#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
+#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 */
+
+/* Doorbell functions */
+#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
+#define MPI2_FUNCTION_HANDSHAKE (0x42)
+
+/*****************************************************************************
+*
+* MPI Version Definitions
+*
+*****************************************************************************/
+
+#define MPI2_VERSION_MAJOR (0x02)
+#define MPI2_VERSION_MINOR (0x00)
+#define MPI2_VERSION_MAJOR_MASK (0xFF00)
+#define MPI2_VERSION_MAJOR_SHIFT (8)
+#define MPI2_VERSION_MINOR_MASK (0x00FF)
+#define MPI2_VERSION_MINOR_SHIFT (0)
+#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
+ MPI2_VERSION_MINOR)
+
+#define MPI2_VERSION_02_00 (0x0200)
+
+/* versioning for this MPI header set */
+#define MPI2_HEADER_VERSION_UNIT (0x10)
+#define MPI2_HEADER_VERSION_DEV (0x00)
+#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
+#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
+#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
+#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
+#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \
+ MPI2_HEADER_VERSION_DEV)
+
+
+/* IOCInit Request message */
+struct MPI2_IOC_INIT_REQUEST {
+ uint8_t WhoInit; /* 0x00 */
+ uint8_t Reserved1; /* 0x01 */
+ uint8_t ChainOffset; /* 0x02 */
+ uint8_t Function; /* 0x03 */
+ uint16_t Reserved2; /* 0x04 */
+ uint8_t Reserved3; /* 0x06 */
+ uint8_t MsgFlags; /* 0x07 */
+ uint8_t VP_ID; /* 0x08 */
+ uint8_t VF_ID; /* 0x09 */
+ uint16_t Reserved4; /* 0x0A */
+ uint16_t MsgVersion; /* 0x0C */
+ uint16_t HeaderVersion; /* 0x0E */
+ uint32_t Reserved5; /* 0x10 */
+ uint16_t Reserved6; /* 0x14 */
+ uint8_t Reserved7; /* 0x16 */
+ uint8_t HostMSIxVectors; /* 0x17 */
+ uint16_t Reserved8; /* 0x18 */
+ uint16_t SystemRequestFrameSize; /* 0x1A */
+ uint16_t ReplyDescriptorPostQueueDepth; /* 0x1C */
+ uint16_t ReplyFreeQueueDepth; /* 0x1E */
+ uint32_t SenseBufferAddressHigh; /* 0x20 */
+ uint32_t SystemReplyAddressHigh; /* 0x24 */
+ uint64_t SystemRequestFrameBaseAddress; /* 0x28 */
+ uint64_t ReplyDescriptorPostQueueAddress;/* 0x30 */
+ uint64_t ReplyFreeQueueAddress; /* 0x38 */
+ uint64_t TimeStamp; /* 0x40 */
+};
+
+/* WhoInit values */
+#define MPI2_WHOINIT_NOT_INITIALIZED (0x00)
+#define MPI2_WHOINIT_SYSTEM_BIOS (0x01)
+#define MPI2_WHOINIT_ROM_BIOS (0x02)
+#define MPI2_WHOINIT_PCI_PEER (0x03)
+#define MPI2_WHOINIT_HOST_DRIVER (0x04)
+#define MPI2_WHOINIT_MANUFACTURER (0x05)
+
+struct MPI2_SGE_CHAIN_UNION {
+ uint16_t Length;
+ uint8_t NextChainOffset;
+ uint8_t Flags;
+ union {
+ uint32_t Address32;
+ uint64_t Address64;
+ } u;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE32 {
+ uint32_t Address;
+ uint32_t FlagsLength;
+};
+
+struct MPI2_IEEE_SGE_SIMPLE64 {
+ uint64_t Address;
+ uint32_t Length;
+ uint16_t Reserved1;
+ uint8_t Reserved2;
+ uint8_t Flags;
+};
+
+typedef union _MPI2_IEEE_SGE_SIMPLE_UNION {
+ struct MPI2_IEEE_SGE_SIMPLE32 Simple32;
+ struct MPI2_IEEE_SGE_SIMPLE64 Simple64;
+} MPI2_IEEE_SGE_SIMPLE_UNION;
+
+typedef struct _MPI2_SGE_SIMPLE_UNION {
+ uint32_t FlagsLength;
+ union {
+ uint32_t Address32;
+ uint64_t Address64;
+ } u;
+} MPI2_SGE_SIMPLE_UNION;
+
+/****************************************************************************
+* IEEE SGE field definitions and masks
+****************************************************************************/
+
+/* Flags field bit definitions */
+
+#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80)
+
+#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24)
+
+#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF)
+
+/* Element Type */
+
+#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00)
+#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
+
+/* 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_IOCPLB_ADDR (0x02)
+#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
+
+/* Address Size */
+
+#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
+#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
+
+/*******************/
+/* SCSI IO Control bits */
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000)
+#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
+
+#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
+#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
+#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
+#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
+#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000)
+
+#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800)
+#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11)
+
+#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
+#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
+#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100)
+#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
+#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400)
+
+#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0)
+#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000)
+#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040)
+#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080)
+
+/*******************/
+
+typedef struct {
+ uint8_t CDB[20]; /* 0x00 */
+ uint32_t PrimaryReferenceTag; /* 0x14 */
+ uint16_t PrimaryApplicationTag; /* 0x18 */
+ uint16_t PrimaryApplicationTagMask; /* 0x1A */
+ uint32_t TransferLength; /* 0x1C */
+} MPI2_SCSI_IO_CDB_EEDP32;
+
+
+typedef union _MPI2_IEEE_SGE_CHAIN_UNION {
+ struct MPI2_IEEE_SGE_SIMPLE32 Chain32;
+ struct MPI2_IEEE_SGE_SIMPLE64 Chain64;
+} MPI2_IEEE_SGE_CHAIN_UNION;
+
+typedef union _MPI2_SIMPLE_SGE_UNION {
+ MPI2_SGE_SIMPLE_UNION MpiSimple;
+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
+} MPI2_SIMPLE_SGE_UNION;
+
+typedef union _MPI2_SGE_IO_UNION {
+ MPI2_SGE_SIMPLE_UNION MpiSimple;
+ struct MPI2_SGE_CHAIN_UNION MpiChain;
+ MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
+ MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
+} MPI2_SGE_IO_UNION;
+
+typedef union {
+ uint8_t CDB32[32];
+ MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
+ MPI2_SGE_SIMPLE_UNION SGE;
+} MPI2_SCSI_IO_CDB_UNION;
+
+
+/* MPI 2.5 SGLs */
+
+#define MPI25_IEEE_SGE_FLAGS_END_OF_LIST (0x40)
+
+typedef struct _MPI25_IEEE_SGE_CHAIN64 {
+ uint64_t Address;
+ uint32_t Length;
+ uint16_t Reserved1;
+ uint8_t NextChainOffset;
+ uint8_t Flags;
+} MPI25_IEEE_SGE_CHAIN64, *pMpi25IeeeSgeChain64_t;
+
+/* use MPI2_IEEE_SGE_FLAGS_ defines for the Flags field */
+
+
+/********/
+
+/*
+ * RAID SCSI IO Request Message
+ * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST
+ */
+struct mfi_mpi2_request_raid_scsi_io {
+ uint16_t DevHandle; /* 0x00 */
+ uint8_t ChainOffset; /* 0x02 */
+ uint8_t Function; /* 0x03 */
+ uint16_t Reserved1; /* 0x04 */
+ uint8_t Reserved2; /* 0x06 */
+ uint8_t MsgFlags; /* 0x07 */
+ uint8_t VP_ID; /* 0x08 */
+ uint8_t VF_ID; /* 0x09 */
+ uint16_t Reserved3; /* 0x0A */
+ uint32_t SenseBufferLowAddress; /* 0x0C */
+ uint16_t SGLFlags; /* 0x10 */
+ uint8_t SenseBufferLength; /* 0x12 */
+ uint8_t Reserved4; /* 0x13 */
+ uint8_t SGLOffset0; /* 0x14 */
+ uint8_t SGLOffset1; /* 0x15 */
+ uint8_t SGLOffset2; /* 0x16 */
+ uint8_t SGLOffset3; /* 0x17 */
+ uint32_t SkipCount; /* 0x18 */
+ uint32_t DataLength; /* 0x1C */
+ uint32_t BidirectionalDataLength; /* 0x20 */
+ uint16_t IoFlags; /* 0x24 */
+ uint16_t EEDPFlags; /* 0x26 */
+ uint32_t EEDPBlockSize; /* 0x28 */
+ uint32_t SecondaryReferenceTag; /* 0x2C */
+ uint16_t SecondaryApplicationTag; /* 0x30 */
+ uint16_t ApplicationTagTranslationMask; /* 0x32 */
+ uint8_t LUN[8]; /* 0x34 */
+ uint32_t Control; /* 0x3C */
+ MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
+ MPI2_SCSI_IO_VENDOR_UNIQUE RaidContext; /* 0x60 */
+ MPI2_SGE_IO_UNION SGL; /* 0x80 */
+} __packed;
+
+/*
+ * MPT RAID MFA IO Descriptor.
+ */
+typedef struct _MFI_RAID_MFA_IO_DESCRIPTOR {
+ uint32_t RequestFlags : 8;
+ uint32_t MessageAddress1 : 24; /* bits 31:8*/
+ uint32_t MessageAddress2; /* bits 61:32 */
+} MFI_RAID_MFA_IO_REQUEST_DESCRIPTOR,*PMFI_RAID_MFA_IO_REQUEST_DESCRIPTOR;
+
+struct mfi_mpi2_request_header {
+ uint8_t RequestFlags; /* 0x00 */
+ uint8_t MSIxIndex; /* 0x01 */
+ uint16_t SMID; /* 0x02 */
+ uint16_t LMID; /* 0x04 */
+};
+
+/* defines for the RequestFlags field */
+#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
+#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
+#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
+#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08)
+#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
+
+#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
+
+struct mfi_mpi2_request_high_priority {
+ struct mfi_mpi2_request_header header;
+ uint16_t reserved;
+};
+
+struct mfi_mpi2_request_scsi_io {
+ struct mfi_mpi2_request_header header;
+ uint16_t scsi_io_dev_handle;
+};
+
+struct mfi_mpi2_request_scsi_target {
+ struct mfi_mpi2_request_header header;
+ uint16_t scsi_target_io_index;
+};
+
+/* Request Descriptors */
+union mfi_mpi2_request_descriptor {
+ struct mfi_mpi2_request_header header;
+ struct mfi_mpi2_request_high_priority high_priority;
+ struct mfi_mpi2_request_scsi_io scsi_io;
+ struct mfi_mpi2_request_scsi_target scsi_target;
+ uint64_t words;
+};
+
+
+struct mfi_mpi2_reply_header {
+ uint8_t ReplyFlags; /* 0x00 */
+ uint8_t MSIxIndex; /* 0x01 */
+ uint16_t SMID; /* 0x02 */
+};
+
+/* defines for the ReplyFlags field */
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
+#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
+
+/* values for marking a reply descriptor as unused */
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF)
+#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF)
+
+struct mfi_mpi2_reply_default {
+ struct mfi_mpi2_reply_header header;
+ uint32_t DescriptorTypeDependent2;
+};
+
+struct mfi_mpi2_reply_address {
+ struct mfi_mpi2_reply_header header;
+ uint32_t ReplyFrameAddress;
+};
+
+struct mfi_mpi2_reply_scsi_io {
+ struct mfi_mpi2_reply_header header;
+ uint16_t TaskTag; /* 0x04 */
+ uint16_t Reserved1; /* 0x06 */
+};
+
+struct mfi_mpi2_reply_target_assist {
+ struct mfi_mpi2_reply_header header;
+ uint8_t SequenceNumber; /* 0x04 */
+ uint8_t Reserved1; /* 0x04 */
+ uint16_t IoIndex; /* 0x06 */
+};
+
+struct mfi_mpi2_reply_target_cmd_buffer {
+ struct mfi_mpi2_reply_header header;
+ uint8_t SequenceNumber; /* 0x04 */
+ uint8_t Flags; /* 0x04 */
+ uint16_t InitiatorDevHandle; /* 0x06 */
+ uint16_t IoIndex; /* 0x06 */
+};
+
+struct mfi_mpi2_reply_raid_accel {
+ struct mfi_mpi2_reply_header header;
+ uint8_t SequenceNumber; /* 0x04 */
+ uint32_t Reserved; /* 0x04 */
+};
+
+/* union of Reply Descriptors */
+union mfi_mpi2_reply_descriptor {
+ struct mfi_mpi2_reply_header header;
+ struct mfi_mpi2_reply_scsi_io scsi_io;
+ struct mfi_mpi2_reply_target_assist target_assist;
+ struct mfi_mpi2_reply_target_cmd_buffer target_cmd;
+ struct mfi_mpi2_reply_raid_accel raid_accel;
+ struct mfi_mpi2_reply_default reply_default;
+ uint64_t words;
+};
+
+struct IO_REQUEST_INFO {
+ uint64_t ldStartBlock;
+ uint32_t numBlocks;
+ uint16_t ldTgtId;
+ uint8_t isRead;
+ uint16_t devHandle;
+ uint64_t pdBlock;
+ uint8_t fpOkForIo;
+};
+
#define MFI_SCSI_MAX_TARGETS 128
#define MFI_SCSI_MAX_LUNS 8
#define MFI_SCSI_INITIATOR_ID 255
diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h
index 9fcd0d9..061dfd5 100644
--- a/sys/dev/mfi/mfivar.h
+++ b/sys/dev/mfi/mfivar.h
@@ -59,6 +59,10 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/sx.h>
+#include <sys/types.h>
+#include <sys/taskqueue.h>
+#include <machine/atomic.h>
+
/*
* SCSI structures and definitions are used from here, but no linking
* requirements are made to CAM.
@@ -70,6 +74,8 @@ struct mfi_hwcomms {
uint32_t hw_ci;
uint32_t hw_reply_q[1];
};
+#define MEGASAS_MAX_NAME 32
+#define MEGASAS_VERSION "4.23"
struct mfi_softc;
struct disk;
@@ -80,9 +86,9 @@ struct mfi_command {
time_t cm_timestamp;
struct mfi_softc *cm_sc;
union mfi_frame *cm_frame;
- uint32_t cm_frame_busaddr;
+ bus_addr_t cm_frame_busaddr;
struct mfi_sense *cm_sense;
- uint32_t cm_sense_busaddr;
+ bus_addr_t cm_sense_busaddr;
bus_dmamap_t cm_dmamap;
union mfi_sgl *cm_sg;
void *cm_data;
@@ -101,6 +107,7 @@ struct mfi_command {
#define MFI_ON_MFIQ_BUSY (1<<7)
#define MFI_ON_MFIQ_MASK ((1<<5)|(1<<6)|(1<<7))
int cm_aen_abort;
+ uint8_t retry_for_fw_reset;
void (* cm_complete)(struct mfi_command *cm);
void *cm_private;
int cm_index;
@@ -120,11 +127,42 @@ struct mfi_disk {
#define MFI_DISK_FLAGS_DISABLED 0x02
};
+struct mfi_system_pd {
+ TAILQ_ENTRY(mfi_system_pd) pd_link;
+ device_t pd_dev;
+ int pd_id;
+ int pd_unit;
+ struct mfi_softc *pd_controller;
+ struct mfi_pd_info *pd_info;
+ struct disk *pd_disk;
+ int pd_flags;
+};
+
+struct mfi_evt_queue_elm {
+ TAILQ_ENTRY(mfi_evt_queue_elm) link;
+ struct mfi_evt_detail detail;
+};
+
struct mfi_aen {
TAILQ_ENTRY(mfi_aen) aen_link;
struct proc *p;
};
+struct mfi_skinny_dma_info {
+ bus_dma_tag_t dmat[514];
+ bus_dmamap_t dmamap[514];
+ uint32_t mem[514];
+ int noofmaps;
+};
+
+struct mfi_cmd_tbolt;
+typedef struct {
+ volatile unsigned int val;
+} atomic_t;
+
+#define atomic_read(v) ((v)->val)
+#define atomic_set(v,i) ((v)->val - (i))
+
struct mfi_softc {
device_t mfi_dev;
int mfi_flags;
@@ -135,11 +173,22 @@ struct mfi_softc {
#define MFI_FLAGS_1064R (1<<4)
#define MFI_FLAGS_1078 (1<<5)
#define MFI_FLAGS_GEN2 (1<<6)
+#define MFI_FLAGS_SKINNY (1<<7)
+#define MFI_FLAGS_TBOLT (1<<8)
+ // Start: LSIP200113393
+ bus_dma_tag_t verbuf_h_dmat;
+ bus_dmamap_t verbuf_h_dmamap;
+ uint32_t verbuf_h_busaddr;
+ uint32_t *verbuf;
+ void *kbuff_arr[MAX_IOCTL_SGE];
+ bus_dma_tag_t mfi_kbuff_arr_dmat[2];
+ bus_dmamap_t mfi_kbuff_arr_dmamap[2];
+ bus_addr_t mfi_kbuff_arr_busaddr[2];
struct mfi_hwcomms *mfi_comms;
TAILQ_HEAD(,mfi_command) mfi_free;
TAILQ_HEAD(,mfi_command) mfi_ready;
- TAILQ_HEAD(,mfi_command) mfi_busy;
+ TAILQ_HEAD(BUSYQ,mfi_command) mfi_busy;
struct bio_queue_head mfi_bioq;
struct mfi_qstat mfi_qstat[MFIQ_COUNT];
@@ -153,17 +202,27 @@ struct mfi_softc {
bus_dma_tag_t mfi_comms_dmat;
bus_dmamap_t mfi_comms_dmamap;
- uint32_t mfi_comms_busaddr;
+ bus_addr_t mfi_comms_busaddr;
bus_dma_tag_t mfi_frames_dmat;
bus_dmamap_t mfi_frames_dmamap;
- uint32_t mfi_frames_busaddr;
+ bus_addr_t mfi_frames_busaddr;
union mfi_frame *mfi_frames;
+ bus_dma_tag_t mfi_tb_init_dmat;
+ bus_dmamap_t mfi_tb_init_dmamap;
+ bus_addr_t mfi_tb_init_busaddr;
+ bus_addr_t mfi_tb_ioc_init_busaddr;
+ union mfi_frame *mfi_tb_init;
+
+ TAILQ_HEAD(,mfi_evt_queue_elm) mfi_evt_queue;
+ struct task mfi_evt_task;
TAILQ_HEAD(,mfi_aen) mfi_aen_pids;
struct mfi_command *mfi_aen_cm;
+ struct mfi_command *mfi_skinny_cm;
uint32_t mfi_aen_triggered;
uint32_t mfi_poll_waiting;
+ uint32_t mfi_boot_seq_num;
struct selinfo mfi_select;
int mfi_delete_busy_volumes;
int mfi_keep_deleted_volumes;
@@ -180,6 +239,14 @@ struct mfi_softc {
struct intr_config_hook mfi_ich;
eventhandler_tag eh;
+ /* OCR flags */
+ atomic_t fw_reset_no_pci_access;
+ uint8_t adpreset;
+ uint8_t issuepend_done;
+ uint8_t disableOnlineCtrlReset;
+ uint32_t mfiStatus;
+ uint32_t last_seq_num;
+ uint32_t volatile hw_crit_error;
/*
* Allocation for the command array. Used as an indexable array to
@@ -196,7 +263,7 @@ struct mfi_softc {
*/
int mfi_max_fw_cmds;
/*
- * How many S/G elements we'll ever actually use
+ * How many S/G elements we'll ever actually use
*/
int mfi_max_sge;
/*
@@ -215,6 +282,7 @@ struct mfi_softc {
uint32_t mfi_max_io;
TAILQ_HEAD(,mfi_disk) mfi_ld_tqh;
+ TAILQ_HEAD(,mfi_system_pd) mfi_syspd_tqh;
eventhandler_tag mfi_eh;
struct cdev *mfi_cdev;
@@ -226,9 +294,98 @@ struct mfi_softc {
/* Controller type specific interfaces */
void (*mfi_enable_intr)(struct mfi_softc *sc);
+ void (*mfi_disable_intr)(struct mfi_softc *sc);
int32_t (*mfi_read_fw_status)(struct mfi_softc *sc);
int (*mfi_check_clear_intr)(struct mfi_softc *sc);
- void (*mfi_issue_cmd)(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
+ void (*mfi_issue_cmd)(struct mfi_softc *sc, bus_addr_t bus_add,
+ uint32_t frame_cnt);
+ int (*mfi_adp_reset)(struct mfi_softc *sc);
+ int (*mfi_adp_check_reset)(struct mfi_softc *sc);
+
+ /* ThunderBolt */
+ uint32_t mfi_tbolt;
+ uint32_t MFA_enabled;
+ uint64_t map_id;
+ struct mfi_command *map_update_cmd;
+ /* Single Reply structure size */
+ uint16_t reply_size;
+ /* Singler message size. */
+ uint16_t raid_io_msg_size;
+ TAILQ_HEAD(TB, mfi_cmd_tbolt) mfi_cmd_tbolt_tqh;
+ /* ThunderBolt base contiguous memory mapping. */
+ bus_dma_tag_t mfi_tb_dmat;
+ bus_dmamap_t mfi_tb_dmamap;
+ bus_addr_t mfi_tb_busaddr;
+ /* ThunderBolt Contiguous DMA memory Mapping */
+ uint8_t * request_message_pool;
+ uint8_t * request_message_pool_align;
+ uint8_t * request_desc_pool;
+ //uint32_t request_desc_busaddr;
+ bus_addr_t request_msg_busaddr;
+ bus_addr_t reply_frame_busaddr;
+ bus_addr_t sg_frame_busaddr;
+ /* ThunderBolt IOC Init Descriptor */
+ bus_dma_tag_t mfi_tb_ioc_init_dmat;
+ bus_dmamap_t mfi_tb_ioc_init_dmamap;
+ uint8_t * mfi_tb_ioc_init_desc;
+ struct mfi_cmd_tbolt **mfi_cmd_pool_tbolt;
+ /* Virtual address of reply Frame Pool */
+ struct mfi_mpi2_reply_header* reply_frame_pool;
+ struct mfi_mpi2_reply_header* reply_frame_pool_align;
+
+ /* Last reply frame address */
+ uint8_t * reply_pool_limit;
+ uint16_t last_reply_idx;
+ uint8_t max_SGEs_in_chain_message;
+ uint8_t max_SGEs_in_main_message;
+ uint8_t chain_offset_value_for_main_message;
+ uint8_t chain_offset_value_for_mpt_ptmsg;
+};
+
+union desc_value {
+ uint64_t word;
+ struct {
+ uint32_t low;
+ uint32_t high;
+ }u;
+};
+
+// TODO find the right definition
+#define XXX_MFI_CMD_OP_INIT2 0x9
+/*
+ * Request descriptor types
+ */
+#define MFI_REQ_DESCRIPT_FLAGS_LD_IO 0x7
+#define MFI_REQ_DESCRIPT_FLAGS_MFA 0x1
+#define MFI_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 0x1
+#define MFI_FUSION_FP_DEFAULT_TIMEOUT 0x14
+#define MFI_LOAD_BALANCE_FLAG 0x1
+#define MFI_DCMD_MBOX_PEND_FLAG 0x1
+
+//#define MR_PROT_INFO_TYPE_CONTROLLER 0x08
+#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f
+#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9
+#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB
+#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18
+#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20
+#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60
+#define MEGASAS_EEDPBLOCKSIZE 512
+struct mfi_cmd_tbolt {
+ union mfi_mpi2_request_descriptor *request_desc;
+ struct mfi_mpi2_request_raid_scsi_io *io_request;
+ bus_addr_t io_request_phys_addr;
+ bus_addr_t sg_frame_phys_addr;
+ bus_addr_t sense_phys_addr;
+ MPI2_SGE_IO_UNION *sg_frame;
+ uint8_t *sense;
+ TAILQ_ENTRY(mfi_cmd_tbolt) next;
+ /*
+ * Context for a MFI frame.
+ * Used to get the mfi cmd from list when a MFI cmd is completed
+ */
+ uint32_t sync_cmd_idx;
+ uint16_t index;
+ uint8_t status;
};
extern int mfi_attach(struct mfi_softc *);
@@ -239,6 +396,30 @@ extern void mfi_disk_complete(struct bio *);
extern int mfi_disk_disable(struct mfi_disk *);
extern void mfi_disk_enable(struct mfi_disk *);
extern int mfi_dump_blocks(struct mfi_softc *, int id, uint64_t, void *, int);
+extern int mfi_syspd_disable(struct mfi_system_pd *);
+extern void mfi_syspd_enable(struct mfi_system_pd *);
+extern int mfi_dump_syspd_blocks(struct mfi_softc *, int id, uint64_t, void *,
+ int);
+extern int mfi_transition_firmware(struct mfi_softc *sc);
+extern int mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start);
+extern void mfi_complete(struct mfi_softc *sc, struct mfi_command *cm);
+extern int mfi_mapcmd(struct mfi_softc *sc,struct mfi_command *cm);
+extern int mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm);
+extern void mfi_tbolt_enable_intr_ppc(struct mfi_softc *);
+extern void mfi_tbolt_disable_intr_ppc(struct mfi_softc *);
+extern int32_t mfi_tbolt_read_fw_status_ppc(struct mfi_softc *);
+extern int32_t mfi_tbolt_check_clear_intr_ppc(struct mfi_softc *);
+extern void mfi_tbolt_issue_cmd_ppc(struct mfi_softc *, bus_addr_t, uint32_t);
+extern void mfi_tbolt_init_globals(struct mfi_softc*);
+extern uint32_t mfi_tbolt_get_memory_requirement(struct mfi_softc *);
+extern int mfi_tbolt_init_desc_pool(struct mfi_softc *, uint8_t *, uint32_t);
+extern int mfi_tbolt_init_MFI_queue(struct mfi_softc *);
+extern void mfi_intr_tbolt(void *arg);
+extern int mfi_tbolt_alloc_cmd(struct mfi_softc *sc);
+extern int mfi_tbolt_send_frame(struct mfi_softc *sc, struct mfi_command *cm);
+extern int mfi_tbolt_adp_reset(struct mfi_softc *sc);
+extern int mfi_tbolt_reset(struct mfi_softc *sc);
+extern int mfi_tbolt_sync_map_info(struct mfi_softc *sc);
#define MFIQ_ADD(sc, qname) \
do { \
@@ -397,7 +578,11 @@ mfi_print_sense(struct mfi_softc *sc, void *sense)
MALLOC_DECLARE(M_MFIBUF);
SYSCTL_DECL(_hw_mfi);
+#define MFI_RESET_WAIT_TIME 180
#define MFI_CMD_TIMEOUT 30
+#define MFI_SYS_PD_IO 0
+#define MFI_LD_IO 1
+#define SKINNY_MEMORY 0x02000000
#define MFI_MAXPHYS (128 * 1024)
#ifdef MFI_DEBUG
OpenPOWER on IntegriCloud