First cut at updating mfi(4) to support newer LSI MegaRAID SAS cards.

Specifically, add support for "Drake Skinny" and "ThunderBolt" LSI
cards.

Initial code was supplied by LSI under BSD license.  Several improvements
were done by myself.  Such things like making it work in a static kernel,
be able to boot of the RAID, performance improvements.  I removed some
fairly complicated code that seemed to directly access the disks under
the firmware.  It doesn't seem to be needed and significantly slowed
down the performance of the driver and caused tons of sense errors to
be reported.

This code is being checked in this area so others can help me get it into
shape to commit into the FreeBSD tree.  Assistance has been volunteered
by iXsystems.

We might want to re-work the JBOD attachment that creates /dev/mfisyspd?
node for each disk.

Performance is faster then prior cards.  It works okay with WITNESS
and INVARIANTS on amd64 and i386.  I recall seeing a use after
free time bug with FreeBSD 8 and a Drake Skinny card with WITNESS
and INVARIANTS on.

First task is get all of the new structures to be named in FreeBSD
style format.

Next is probably to deal with the 64bit addressing changes that are
mostly around the #ifdef __amd64__ checks.

Thanks to LSI for providing the initial code.

Obtained from:	LSI
This commit is contained in:
Doug Ambrisko 2011-11-04 02:34:52 +00:00
parent a73cbbef8a
commit 0d9a4ef39c
12 changed files with 3798 additions and 205 deletions

View File

@ -1410,6 +1410,8 @@ dev/mfi/mfi.c optional mfi
dev/mfi/mfi_debug.c optional mfi
dev/mfi/mfi_pci.c optional mfi pci
dev/mfi/mfi_disk.c optional mfi
dev/mfi/mfi_syspd.c optional mfi
dev/mfi/mfi_tbolt.c optional mfi
dev/mfi/mfi_linux.c optional mfi compat_linux
dev/mfi/mfi_cam.c optional mfip scbus
dev/mii/acphy.c optional miibus | acphy

File diff suppressed because it is too large Load Diff

View File

@ -269,12 +269,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;

View File

@ -223,7 +223,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;
@ -245,6 +245,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;
@ -254,8 +255,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);

View File

@ -28,6 +28,7 @@
__FBSDID("$FreeBSD$");
#include <dev/mfi/mfireg.h>
#include <machine/bus.h>
#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
struct iovec32 {
@ -36,6 +37,12 @@ struct iovec32 {
};
#endif
struct megasas_sge
{
bus_addr_t phys_addr;
uint32_t length;
};
#define MFIQ_FREE 0
#define MFIQ_BIO 1
#define MFIQ_READY 2

View File

@ -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>

View File

@ -115,14 +115,20 @@ struct mfi_ident {
int flags;
const char *desc;
} mfi_identifiers[] = {
{0x1000, 0x005B, 0xffff, 0xffff, MFI_FLAGS_SKINNY| MFI_FLAGS_TBOLT, "ThunderBolt"},
{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, 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"},
@ -196,8 +202,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,
@ -240,8 +249,10 @@ static int
mfi_pci_detach(device_t dev)
{
struct mfi_softc *sc;
struct mfi_disk *ld;
int error;
//struct mfi_disk *ld;
//struct mfi_system_pd *syspd = NULL;
int error, devcount, i;
device_t *devlist;
sc = device_get_softc(dev);
@ -254,14 +265,41 @@ mfi_pci_detach(device_t dev)
}
sc->mfi_detaching = 1;
mtx_unlock(&sc->mfi_io_lock);
/*
BHARAT: Fixed Kernel Corruption while unloading the driver
*/
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);
/*
BHARAT: Following code causes Kernel corruption during
multiple driver load/unload, this cleanup code was not
getting called up in normal run hence OS was maintaining stale dev
entries which were resulting to crash, so added above
cleanup code.
*/
while ((ld = TAILQ_FIRST(&sc->mfi_ld_tqh)) != NULL) {
/*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(!TAILQ_EMPTY(&sc->mfi_syspd_tqh))
while ((syspd = TAILQ_FIRST(&sc->mfi_syspd_tqh)) != NULL) {
if ((error = device_delete_child(dev,syspd->pd_dev)) != 0) {
sc->mfi_detaching = 0;
sx_xunlock(&sc->mfi_config_lock);
return (error);
}
}*/
sx_xunlock(&sc->mfi_config_lock);
EVENTHANDLER_DEREGISTER(shutdown_final, sc->mfi_eh);

294
sys/dev/mfi/mfi_syspd.c Normal file
View File

@ -0,0 +1,294 @@
/*-
* 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: src/sys/dev/mfi/mfi_pddisk.c,v 1.2.2.6 2007/08/24 17:29:18 jhb Exp $");
#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/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;
}
#if 0
void
mfi_disk_complete(struct bio *bio)
{
struct mfi_system_pd *sc;
struct mfi_frame_header *hdr;
sc = bio->bio_disk->d_drv1;
hdr = bio->bio_driver1;
if (bio->bio_flags & BIO_ERROR) {
if (bio->bio_error == 0)
bio->bio_error = EIO;
disk_err(bio, "hard error", -1, 1);
} else {
bio->bio_resid = 0;
}
biodone(bio);
}
#endif
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);
}

1410
sys/dev/mfi/mfi_tbolt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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.
@ -82,6 +82,14 @@ __FBSDID("$FreeBSD$");
#define MFI_IQP 0x40 /* Inbound queue port */
#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
*/
@ -89,19 +97,42 @@ __FBSDID("$FreeBSD$");
#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 */
/*
* 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,7 +150,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
* register.
@ -130,6 +170,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 +192,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 +211,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 +221,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,
@ -213,6 +263,32 @@ 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
//TODO remove this and place the right AEN
#define MR_EVT_LD_FAST_PATH_IO_STATUS_CHANGED (0xFFFF)
#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 {
@ -352,6 +428,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
*/
@ -373,6 +458,8 @@ typedef enum {
/* Allow for speedier math calculations */
#define MFI_SECTOR_LEN 512
/* Scatter Gather elements */
/* Scatter Gather elements */
struct mfi_sg32 {
uint32_t addr;
@ -384,9 +471,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 +494,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 +512,30 @@ 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,43 @@ 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;
uint8_t abortCCOnError; // set TRUE to abort CC on detecting an inconsistency
uint8_t loadBalanceMode;// load balance mode (MR_LOAD_BALANCE_MODE)
uint8_t disableAutoDetectBackplane; // 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 snapVDSpace; // % 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
/*
* Add properties that can be controlled by a bit in the following structure.
*/
struct {
uint32_t copyBackDisabled :1; // set TRUE to disable copyBack (0=copback enabled)
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;
uint8_t autoSnapVDSpace; // % 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 viewSpace; // snapshot writeable VIEWs capacity as a % of source LD capacity. 0=READ only
// 1=5%, 2=10%, 3=15% and so on
uint16_t spinDownTime; // # of idle minutes before device is spun down (0=use FW defaults)
uint8_t reserved[24];
} __packed;
/* PCI information about the card. */
@ -964,10 +1121,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 {
@ -1040,7 +1198,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 +1241,7 @@ struct mfi_ld_info {
uint8_t reserved2[16];
} __packed;
#define MAX_ARRAYS 16
#define MAX_ARRAYS 128
struct mfi_spare {
union mfi_pd_ref ref;
uint8_t spare_type;
@ -1118,9 +1278,9 @@ struct mfi_config_data {
uint16_t spares_count;
uint16_t spares_size;
uint8_t reserved[16];
struct mfi_array array[0];
struct mfi_ld_config ld[0];
struct mfi_spare spare[0];
struct mfi_array array[1];
struct mfi_ld_config ld[1];
struct mfi_spare spare[1];
} __packed;
struct mfi_bbu_capacity_info {
@ -1230,6 +1390,470 @@ 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; //nextLMId; // 0x14 - 0x15
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;
/*** DJA *****/
/*****************************************************************************
*
* 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

View File

@ -59,6 +59,9 @@ __FBSDID("$FreeBSD$");
#include <sys/lock.h>
#include <sys/sx.h>
#include <sys/types.h>
#include <machine/atomic.h>
/*
* SCSI structures and definitions are used from here, but no linking
* requirements are made to CAM.
@ -70,6 +73,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 +85,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 +106,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 +126,36 @@ 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_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 +166,26 @@ 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];
#if defined (__amd64__)
uint64_t mfi_kbuff_arr_busaddr[2];
#else
uint32_t mfi_kbuff_arr_busaddr[2];
#endif
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,15 +199,35 @@ struct mfi_softc {
bus_dma_tag_t mfi_comms_dmat;
bus_dmamap_t mfi_comms_dmamap;
#if defined(__amd64__)
uint64_t mfi_comms_busaddr;
#else
uint32_t mfi_comms_busaddr;
#endif
bus_dma_tag_t mfi_frames_dmat;
bus_dmamap_t mfi_frames_dmamap;
#if defined(__amd64__)
uint64_t mfi_frames_busaddr;
#else
uint32_t mfi_frames_busaddr;
#endif
union mfi_frame *mfi_frames;
bus_dma_tag_t mfi_tb_init_dmat;
bus_dmamap_t mfi_tb_init_dmamap;
#if defined(__amd64__)
uint64_t mfi_tb_init_busaddr;
uint64_t mfi_tb_ioc_init_busaddr;
#else
uint32_t mfi_tb_init_busaddr;
uint32_t mfi_tb_ioc_init_busaddr;
#endif
union mfi_frame *mfi_tb_init;
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;
struct selinfo mfi_select;
@ -180,6 +246,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
@ -215,6 +289,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 +301,107 @@ 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);
#if defined(__amd64__)
void (*mfi_issue_cmd)(struct mfi_softc *sc,uint64_t bus_add,uint32_t frame_cnt);
#else
void (*mfi_issue_cmd)(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt);
#endif
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;
//Thunderbolt Related structure members
uint16_t reply_size; // Single Reply structure size
uint16_t raid_io_msg_size; // Singler message size
TAILQ_HEAD(TB, mfi_cmd_tbolt) mfi_cmd_tbolt_tqh;
bus_dma_tag_t mfi_tb_dmat; // ThunderBolt base contiguous memory mapping
bus_dmamap_t mfi_tb_dmamap;
#if defined(__amd64__)
uint64_t mfi_tb_busaddr;
#else
uint32_t mfi_tb_busaddr;
#endif
uint8_t * request_message_pool; // ThunderBolt Contiguous DMA memory Mapping
uint8_t * request_message_pool_align;
uint8_t * request_desc_pool;
//uint32_t request_desc_busaddr;
#if defined(__amd64__)
uint64_t request_msg_busaddr;
uint64_t reply_frame_busaddr;
uint64_t sg_frame_busaddr;
#else
uint32_t request_msg_busaddr;
uint32_t reply_frame_busaddr;
uint32_t sg_frame_busaddr;
#endif
bus_dma_tag_t mfi_tb_ioc_init_dmat; // ThunderBolt IOC Init Descriptor
bus_dmamap_t mfi_tb_ioc_init_dmamap;
uint8_t * mfi_tb_ioc_init_desc;
struct mfi_cmd_tbolt **mfi_cmd_pool_tbolt;
struct mfi_mpi2_reply_header* reply_frame_pool; // Virtual address of reply Frame Pool
struct mfi_mpi2_reply_header* reply_frame_pool_align;
uint8_t * reply_pool_limit; // Last reply frame address
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;
uint64_t fast_path_io_AEN_data;
uint8_t shutdown_issued;
};
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;
uintptr_t io_request_phys_addr;
uintptr_t sg_frame_phys_addr;
uintptr_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 +412,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 { \
@ -396,7 +593,11 @@ mfi_print_sense(struct mfi_softc *sc, void *sense)
MALLOC_DECLARE(M_MFIBUF);
#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

View File

@ -9,7 +9,7 @@ SUBDIR+= mfi_linux
.endif
KMOD= mfi
SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c
SRCS= mfi.c mfi_pci.c mfi_disk.c mfi_debug.c mfi_syspd.c mfi_tbolt.c
SRCS+= opt_mfi.h opt_cam.h
SRCS+= device_if.h bus_if.h pci_if.h