- 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
This commit is contained in:
Doug Ambrisko 2008-11-12 22:44:50 +00:00
parent c26864e001
commit fa1e6ef4ef
5 changed files with 85 additions and 30 deletions

View File

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

View File

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

View File

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

View File

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

View File

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