summaryrefslogtreecommitdiffstats
path: root/sys/dev/mfi
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2008-11-12 22:44:50 +0000
committerambrisko <ambrisko@FreeBSD.org>2008-11-12 22:44:50 +0000
commit13c44404b238af1070b494b7d268a4aa4a5a0ee0 (patch)
tree756bc15fb68d3f863768b7bbe9a5a9aabe238f27 /sys/dev/mfi
parent8a2e5505edb61903e9ed697c4bc6e3479b9b0147 (diff)
downloadFreeBSD-src-13c44404b238af1070b494b7d268a4aa4a5a0ee0.zip
FreeBSD-src-13c44404b238af1070b494b7d268a4aa4a5a0ee0.tar.gz
- Fix from jhb for failing I/O request when bus_dmamap_load fails.
- Fix to ioctl path in which the length could be 0 which means no data in/out from LSI. - Fix to ioctl path in which the data in the sense data space of the ioctl packet is a really a pointer to some location in user-space. From LSI re-worked a bit by me. - Add HW support for next gen cards from LSI. Thanks to LSI for their support! Submitted by: jhb, LSI MFC after: 3 days
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r--sys/dev/mfi/mfi.c72
-rw-r--r--sys/dev/mfi/mfi_ioctl.h10
-rw-r--r--sys/dev/mfi/mfi_pci.c23
-rw-r--r--sys/dev/mfi/mfireg.h9
-rw-r--r--sys/dev/mfi/mfivar.h1
5 files changed, 85 insertions, 30 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index ea269cb..5f1bf55 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -163,7 +163,11 @@ static void
mfi_enable_intr_ppc(struct mfi_softc *sc)
{
MFI_WRITE4(sc, MFI_ODCR0, 0xFFFFFFFF);
- MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
+ if (sc->mfi_flags & MFI_FLAGS_1078) {
+ MFI_WRITE4(sc, MFI_OMSK, ~MFI_1078_EIM);
+ } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+ MFI_WRITE4(sc, MFI_OMSK, ~MFI_GEN2_EIM);
+ }
}
static int32_t
@@ -171,14 +175,14 @@ mfi_read_fw_status_xscale(struct mfi_softc *sc)
{
return MFI_READ4(sc, MFI_OMSG0);
}
-
+
static int32_t
mfi_read_fw_status_ppc(struct mfi_softc *sc)
{
return MFI_READ4(sc, MFI_OSP0);
}
-static int
+static int
mfi_check_clear_intr_xscale(struct mfi_softc *sc)
{
int32_t status;
@@ -191,26 +195,33 @@ mfi_check_clear_intr_xscale(struct mfi_softc *sc)
return 0;
}
-static int
+static int
mfi_check_clear_intr_ppc(struct mfi_softc *sc)
{
int32_t status;
status = MFI_READ4(sc, MFI_OSTS);
- if (!status)
- return 1;
+ if (sc->mfi_flags & MFI_FLAGS_1078) {
+ if (!(status & MFI_1078_RM)) {
+ return 1;
+ }
+ } else if (sc->mfi_flags & MFI_FLAGS_GEN2) {
+ if (!(status & MFI_GEN2_RM)) {
+ return 1;
+ }
+ }
MFI_WRITE4(sc, MFI_ODCR0, status);
return 0;
}
-static void
+static void
mfi_issue_cmd_xscale(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
{
MFI_WRITE4(sc, MFI_IQP,(bus_add >>3)|frame_cnt);
}
-
-static void
+
+static void
mfi_issue_cmd_ppc(struct mfi_softc *sc,uint32_t bus_add,uint32_t frame_cnt)
{
MFI_WRITE4(sc, MFI_IQP, (bus_add |frame_cnt <<1)|1 );
@@ -1399,6 +1410,8 @@ mfi_bio_complete(struct mfi_command *cm)
device_printf(sc->mfi_dev, "I/O error, status= %d "
"scsi_status= %d\n", hdr->cmd_status, hdr->scsi_status);
mfi_print_sense(cm->cm_sc, cm->cm_sense);
+ } else if (cm->cm_error != 0) {
+ bio->bio_flags |= BIO_ERROR;
}
mfi_release_command(cm);
@@ -1815,6 +1828,9 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm)
case MFI_DCMD_CFG_ADD:
mfi_ldprobe(sc);
break;
+ case MFI_DCMD_CFG_FOREIGN_IMPORT:
+ mfi_ldprobe(sc);
+ break;
}
}
@@ -1904,7 +1920,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
struct mfi_ioc_aen *aen;
struct mfi_command *cm = NULL;
uint32_t context;
- uint8_t *sense_ptr;
+ union mfi_sense_ptr sense_ptr;
uint8_t *data = NULL, *temp;
int i;
struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg;
@@ -1986,8 +2002,9 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
context = cm->cm_frame->header.context;
bcopy(ioc->mfi_frame.raw, cm->cm_frame,
- 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
- cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
+ 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ cm->cm_total_frame_size = (sizeof(union mfi_sgl)
+ * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
if (ioc->mfi_sge_count) {
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
@@ -2001,7 +2018,8 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
if (cm->cm_flags == 0)
cm->cm_flags |= MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
cm->cm_len = cm->cm_frame->header.data_len;
- if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ if (cm->cm_len &&
+ (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
M_WAITOK | M_ZERO);
if (cm->cm_data == NULL) {
@@ -2102,10 +2120,12 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
}
if (ioc->mfi_sense_len) {
- /* copy out sense */
- sense_ptr = &((struct mfi_ioc_packet*)arg)
- ->mfi_frame.raw[0];
- error = copyout(cm->cm_sense, sense_ptr,
+ /* get user-space sense ptr then copy out sense */
+ bcopy(&((struct mfi_ioc_packet*)arg)
+ ->mfi_frame.raw[ioc->mfi_sense_off],
+ &sense_ptr.sense_ptr_data[0],
+ sizeof(sense_ptr.sense_ptr_data));
+ error = copyout(cm->cm_sense, sense_ptr.user_space,
ioc->mfi_sense_len);
if (error != 0) {
device_printf(sc->mfi_dev,
@@ -2207,7 +2227,7 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
struct mfi_linux_ioc_aen l_aen;
struct mfi_command *cm = NULL;
struct mfi_aen *mfi_aen_entry;
- uint8_t *sense_ptr;
+ union mfi_sense_ptr sense_ptr;
uint32_t context;
uint8_t *data = NULL, *temp;
int i;
@@ -2241,7 +2261,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
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_total_frame_size = (sizeof(union mfi_sgl)
+ * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
if (l_ioc.lioc_sge_count)
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
@@ -2251,7 +2272,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
cm->cm_flags |= MFI_CMD_DATAOUT;
cm->cm_len = cm->cm_frame->header.data_len;
- if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ if (cm->cm_len &&
+ (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT))) {
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
M_WAITOK | M_ZERO);
if (cm->cm_data == NULL) {
@@ -2316,10 +2338,12 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
}
if (l_ioc.lioc_sense_len) {
- /* copy out sense */
- sense_ptr = &((struct mfi_linux_ioc_packet*)arg)
- ->lioc_frame.raw[0];
- error = copyout(cm->cm_sense, sense_ptr,
+ /* get user-space sense ptr then copy out sense */
+ bcopy(&((struct mfi_linux_ioc_packet*)arg)
+ ->lioc_frame.raw[l_ioc.lioc_sense_off],
+ &sense_ptr.sense_ptr_data[0],
+ sizeof(sense_ptr.sense_ptr_data));
+ error = copyout(cm->cm_sense, sense_ptr.user_space,
l_ioc.lioc_sense_len);
if (error != 0) {
device_printf(sc->mfi_dev,
diff --git a/sys/dev/mfi/mfi_ioctl.h b/sys/dev/mfi/mfi_ioctl.h
index 9da3072..22973d7f 100644
--- a/sys/dev/mfi/mfi_ioctl.h
+++ b/sys/dev/mfi/mfi_ioctl.h
@@ -50,6 +50,16 @@ union mfi_statrequest {
struct mfi_qstat ms_qstat;
};
+#define MAX_SPACE_FOR_SENSE_PTR 32
+union mfi_sense_ptr {
+ uint8_t sense_ptr_data[MAX_SPACE_FOR_SENSE_PTR];
+ void *user_space;
+ struct {
+ uint32_t low;
+ uint32_t high;
+ } addr;
+} __packed;
+
#define MAX_IOCTL_SGE 16
struct mfi_ioc_packet {
diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c
index 3becba0..deef9ba 100644
--- a/sys/dev/mfi/mfi_pci.c
+++ b/sys/dev/mfi/mfi_pci.c
@@ -118,7 +118,14 @@ struct mfi_ident {
{0x1000, 0x0413, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Verde ZCR */
{0x1028, 0x0015, 0xffff, 0xffff, MFI_FLAGS_1064R, "Dell PERC 5/i"},
{0x1000, 0x0060, 0x1028, 0xffff, MFI_FLAGS_1078, "Dell PERC 6"},
- {0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"},
+ {0x1000, 0x0060, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"},
+ {0x1000, 0x0079, 0x1028, 0x1f15, MFI_FLAGS_GEN2, "Dell PERC 607E Adapter"},
+ {0x1000, 0x0079, 0x1028, 0x1f16, MFI_FLAGS_GEN2, "Dell PERC 607I Adapter"},
+ {0x1000, 0x0079, 0x1028, 0x1f17, MFI_FLAGS_GEN2, "Dell PERC 607I Integrated"},
+ {0x1000, 0x0079, 0x1028, 0x1f18, MFI_FLAGS_GEN2, "Dell PERC 607I Modular"},
+ {0x1000, 0x0078, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"},
+ {0x1000, 0x0079, 0xffff, 0xffff, MFI_FLAGS_GEN2, "LSI MegaSAS Gen2"},
+ {0x1000, 0x007c, 0xffff, 0xffff, MFI_FLAGS_1078, "LSI MegaSAS 1078"},
{0, 0, 0, 0, 0, NULL}
};
@@ -163,6 +170,8 @@ mfi_pci_attach(device_t dev)
sc = device_get_softc(dev);
bzero(sc, sizeof(*sc));
sc->mfi_dev = dev;
+ m = mfi_find_ident(dev);
+ sc->mfi_flags = m->flags;
/* Verify that the adapter can be set up in PCI space */
command = pci_read_config(dev, PCIR_COMMAND, 2);
@@ -179,7 +188,14 @@ mfi_pci_attach(device_t dev)
}
/* Allocate PCI registers */
- sc->mfi_regs_rid = PCIR_BAR(0);
+ if ((sc->mfi_flags & MFI_FLAGS_1064R) ||
+ (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 */
+ sc->mfi_regs_rid = PCIR_BAR(1);
+ }
if ((sc->mfi_regs_resource = bus_alloc_resource_any(sc->mfi_dev,
SYS_RES_MEMORY, &sc->mfi_regs_rid, RF_ACTIVE)) == NULL) {
device_printf(dev, "Cannot allocate PCI registers\n");
@@ -206,9 +222,6 @@ mfi_pci_attach(device_t dev)
goto out;
}
- m = mfi_find_ident(dev);
- sc->mfi_flags = m->flags;
-
error = mfi_attach(sc);
out:
if (error) {
diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h
index c546026..be56b48 100644
--- a/sys/dev/mfi/mfireg.h
+++ b/sys/dev/mfi/mfireg.h
@@ -89,10 +89,16 @@ __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 */
+/*
+ * GEN2 specific changes
+ */
+#define MFI_GEN2_EIM 0x00000005 /* GEN2 enable interrupt mask */
+#define MFI_GEN2_RM 0x00000001 /* reply GEN2 message interrupt */
+
/* Bits for MFI_OSTS */
#define MFI_OSTS_INTR_VALID 0x00000002
@@ -153,6 +159,7 @@ typedef enum {
MFI_DCMD_CFG_READ = 0x04010000,
MFI_DCMD_CFG_ADD = 0x04020000,
MFI_DCMD_CFG_CLEAR = 0x04030000,
+ MFI_DCMD_CFG_FOREIGN_IMPORT = 0x04060400,
MFI_DCMD_CLUSTER = 0x08000000,
MFI_DCMD_CLUSTER_RESET_ALL = 0x08010100,
MFI_DCMD_CLUSTER_RESET_LD = 0x08010200
diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h
index f6b633b..2738b73 100644
--- a/sys/dev/mfi/mfivar.h
+++ b/sys/dev/mfi/mfivar.h
@@ -133,6 +133,7 @@ struct mfi_softc {
#define MFI_FLAGS_STOP (1<<3)
#define MFI_FLAGS_1064R (1<<4)
#define MFI_FLAGS_1078 (1<<5)
+#define MFI_FLAGS_GEN2 (1<<6)
struct mfi_hwcomms *mfi_comms;
TAILQ_HEAD(,mfi_command) mfi_free;
OpenPOWER on IntegriCloud