diff options
| author | Doug Ambrisko <ambrisko@FreeBSD.org> | 2008-06-13 15:45:48 +0000 |
|---|---|---|
| committer | Doug Ambrisko <ambrisko@FreeBSD.org> | 2008-06-13 15:45:48 +0000 |
| commit | 29f21db7c8175664b73b9e6f742255853c28905a (patch) | |
| tree | 969abbc389b5046c94d6475a18eb3a09b04004d8 /sys/dev/mfi | |
| parent | 68830ef0a12ba3177cb6507158edf44502383007 (diff) | |
Notes
Diffstat (limited to 'sys/dev/mfi')
| -rw-r--r-- | sys/dev/mfi/mfi.c | 177 | ||||
| -rw-r--r-- | sys/dev/mfi/mfi_ioctl.h | 38 | ||||
| -rw-r--r-- | sys/dev/mfi/mfi_pci.c | 1 |
3 files changed, 201 insertions, 15 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index fa47c28c772e..69125efdebbd 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -106,6 +106,8 @@ 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, d_thread_t *); 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); @@ -126,6 +128,11 @@ TUNABLE_INT("hw.mfi.event_class", &mfi_event_class); SYSCTL_INT(_hw_mfi, OID_AUTO, event_class, CTLFLAG_RW, &mfi_event_class, 0, "event message class"); +static int mfi_max_cmds = 128; +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"); + /* Management interface */ static d_open_t mfi_open; static d_close_t mfi_close; @@ -535,7 +542,11 @@ mfi_alloc_commands(struct mfi_softc *sc) * XXX Should we allocate all the commands up front, or allocate on * demand later like 'aac' does? */ - ncmds = sc->mfi_max_fw_cmds; + ncmds = MIN(mfi_max_cmds, sc->mfi_max_fw_cmds); + if (bootverbose) + device_printf(sc->mfi_dev, "Max fw cmds= %d, sizing driver " + "pool to %d\n", sc->mfi_max_fw_cmds, ncmds); + sc->mfi_commands = malloc(sizeof(struct mfi_command) * ncmds, M_MFIBUF, M_WAITOK | M_ZERO); @@ -774,16 +785,12 @@ mfi_aen_setup(struct mfi_softc *sc, uint32_t seq_start) free(log_state, M_MFIBUF); return (error); } - /* - * Don't run them yet since we can't parse them. - * We can indirectly get the contents from - * the AEN mechanism via setting it lower then - * current. The firmware will iterate through them. - */ + /* The message log is a circular buffer */ for (seq = log_state->shutdown_seq_num; - seq <= log_state->newest_seq_num; seq++) { + seq != log_state->newest_seq_num; seq++) { mfi_get_entry(sc, seq); } + mfi_get_entry(sc, seq); } else seq = seq_start; mfi_aen_register(sc, seq, class_locale.word); @@ -2022,17 +2029,99 @@ mfi_check_command_post(struct mfi_softc *sc, struct mfi_command *cm) } static int +mfi_user_command(struct mfi_softc *sc, struct mfi_ioc_passthru *ioc) +{ + struct mfi_command *cm; + struct mfi_dcmd_frame *dcmd; + void *ioc_buf = NULL; + uint32_t context; + int error = 0, locked; + + + if (ioc->buf_size > 0) { + ioc_buf = malloc(ioc->buf_size, M_MFIBUF, M_WAITOK); + if (ioc_buf == NULL) { + return (ENOMEM); + } + error = copyin(ioc->buf, ioc_buf, ioc->buf_size); + if (error) { + device_printf(sc->mfi_dev, "failed to copyin\n"); + free(ioc_buf, M_MFIBUF); + return (error); + } + } + + locked = mfi_config_lock(sc, ioc->ioc_frame.opcode); + + mtx_lock(&sc->mfi_io_lock); + while ((cm = mfi_dequeue_free(sc)) == NULL) + msleep(mfi_user_command, &sc->mfi_io_lock, 0, "mfiioc", hz); + + /* Save context for later */ + context = cm->cm_frame->header.context; + + dcmd = &cm->cm_frame->dcmd; + bcopy(&ioc->ioc_frame, dcmd, sizeof(struct mfi_dcmd_frame)); + + cm->cm_sg = &dcmd->sgl; + cm->cm_total_frame_size = MFI_DCMD_FRAME_SIZE; + cm->cm_data = ioc_buf; + cm->cm_len = ioc->buf_size; + + /* restore context */ + cm->cm_frame->header.context = context; + + /* Cheat since we don't know if we're writing or reading */ + cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT; + + error = mfi_check_command_pre(sc, cm); + if (error) + goto out; + + error = mfi_wait_command(sc, cm); + if (error) { + device_printf(sc->mfi_dev, "ioctl failed %d\n", error); + goto out; + } + bcopy(dcmd, &ioc->ioc_frame, sizeof(struct mfi_dcmd_frame)); + mfi_check_command_post(sc, cm); +out: + mfi_release_command(cm); + mtx_unlock(&sc->mfi_io_lock); + mfi_config_unlock(sc, locked); + if (ioc->buf_size > 0) + error = copyout(ioc_buf, ioc->buf, ioc->buf_size); + if (ioc_buf) + free(ioc_buf, M_MFIBUF); + 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, d_thread_t *td) { struct mfi_softc *sc; union mfi_statrequest *ms; struct mfi_ioc_packet *ioc; +#ifdef __amd64__ + struct mfi_ioc_packet32 *ioc32; +#endif struct mfi_ioc_aen *aen; struct mfi_command *cm = NULL; uint32_t context; uint8_t *sense_ptr; uint8_t *data = NULL, *temp; int i; + struct mfi_ioc_passthru *iop = (struct mfi_ioc_passthru *)arg; +#ifdef __amd64__ + struct mfi_ioc_passthru32 *iop32 = (struct mfi_ioc_passthru32 *)arg; + struct mfi_ioc_passthru iop_swab; +#endif int error, locked; sc = dev->si_drv1; @@ -2079,8 +2168,19 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) break; } case MFI_CMD: +#ifdef __amd64__ + case MFI_CMD32: +#endif + { + devclass_t devclass; ioc = (struct mfi_ioc_packet *)arg; + int adapter; + adapter = ioc->mfi_adapter_no; + if (device_get_unit(sc->mfi_dev) == 0 && adapter != 0) { + devclass = devclass_find("mfi"); + sc = devclass_get_softc(devclass, adapter); + } mtx_lock(&sc->mfi_io_lock); if ((cm = mfi_dequeue_free(sc)) == NULL) { mtx_unlock(&sc->mfi_io_lock); @@ -2128,9 +2228,27 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) temp = data; if (cm->cm_flags & MFI_CMD_DATAOUT) { for (i = 0; i < ioc->mfi_sge_count; i++) { +#ifdef __amd64__ + if (cmd == MFI_CMD) { + /* Native */ + error = copyin(ioc->mfi_sgl[i].iov_base, + temp, + ioc->mfi_sgl[i].iov_len); + } else { + void *temp_convert; + /* 32bit */ + ioc32 = (struct mfi_ioc_packet32 *)ioc; + temp_convert = + PTRIN(ioc32->mfi_sgl[i].iov_base); + error = copyin(temp_convert, + temp, + ioc32->mfi_sgl[i].iov_len); + } +#else error = copyin(ioc->mfi_sgl[i].iov_base, temp, ioc->mfi_sgl[i].iov_len); +#endif if (error != 0) { device_printf(sc->mfi_dev, "Copy in failed\n"); @@ -2163,9 +2281,27 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td) temp = data; if (cm->cm_flags & MFI_CMD_DATAIN) { for (i = 0; i < ioc->mfi_sge_count; i++) { +#ifdef __amd64__ + if (cmd == MFI_CMD) { + /* Native */ + error = copyout(temp, + ioc->mfi_sgl[i].iov_base, + ioc->mfi_sgl[i].iov_len); + } else { + void *temp_convert; + /* 32bit */ + ioc32 = (struct mfi_ioc_packet32 *)ioc; + temp_convert = + PTRIN(ioc32->mfi_sgl[i].iov_base); + error = copyout(temp, + temp_convert, + ioc32->mfi_sgl[i].iov_len); + } +#else error = copyout(temp, ioc->mfi_sgl[i].iov_base, ioc->mfi_sgl[i].iov_len); +#endif if (error != 0) { device_printf(sc->mfi_dev, "Copy out failed\n"); @@ -2200,6 +2336,7 @@ out: } break; + } case MFI_SET_AEN: aen = (struct mfi_ioc_aen *)arg; error = mfi_aen_register(sc, aen->aen_seq_num, @@ -2248,6 +2385,21 @@ out: cmd, arg, flag, td)); break; } +#ifdef __amd64__ + case MFIIO_PASSTHRU32: + iop_swab.ioc_frame = iop32->ioc_frame; + iop_swab.buf_size = iop32->buf_size; + iop_swab.buf = PTRIN(iop32->buf); + iop = &iop_swab; + /* FALLTHROUGH */ +#endif + case MFIIO_PASSTHRU: + error = mfi_user_command(sc, iop); +#ifdef __amd64__ + if (cmd == MFIIO_PASSTHRU32) + iop32->ioc_frame = iop_swab.ioc_frame; +#endif + break; default: device_printf(sc->mfi_dev, "IOCTL 0x%lx not handled\n", cmd); error = ENOENT; @@ -2268,7 +2420,6 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa uint8_t *sense_ptr; uint32_t context; uint8_t *data = NULL, *temp; - void *temp_convert; int i; int error, locked; @@ -2327,9 +2478,7 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa temp = data; if (cm->cm_flags & MFI_CMD_DATAOUT) { for (i = 0; i < l_ioc.lioc_sge_count; i++) { - temp_convert = - (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base; - error = copyin(temp_convert, + error = copyin(PTRIN(l_ioc.lioc_sgl[i].iov_base), temp, l_ioc.lioc_sgl[i].iov_len); if (error != 0) { @@ -2364,10 +2513,8 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa temp = data; if (cm->cm_flags & MFI_CMD_DATAIN) { for (i = 0; i < l_ioc.lioc_sge_count; i++) { - temp_convert = - (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base; error = copyout(temp, - temp_convert, + PTRIN(l_ioc.lioc_sgl[i].iov_base), l_ioc.lioc_sgl[i].iov_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 40521ae88dc8..9da30725a67b 100644 --- a/sys/dev/mfi/mfi_ioctl.h +++ b/sys/dev/mfi/mfi_ioctl.h @@ -67,6 +67,23 @@ struct mfi_ioc_packet { struct iovec mfi_sgl[MAX_IOCTL_SGE]; } __packed; +#ifdef __amd64__ +struct mfi_ioc_packet32 { + uint16_t mfi_adapter_no; + uint16_t mfi_pad1; + uint32_t mfi_sgl_off; + uint32_t mfi_sge_count; + uint32_t mfi_sense_off; + uint32_t mfi_sense_len; + union { + uint8_t raw[128]; + struct mfi_frame_header hdr; + } mfi_frame; + + struct iovec32 mfi_sgl[MAX_IOCTL_SGE]; +} __packed; +#endif + struct mfi_ioc_aen { uint16_t aen_adapter_no; uint16_t aen_pad1; @@ -75,6 +92,9 @@ struct mfi_ioc_aen { } __packed; #define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet) +#ifdef __amd64__ +#define MFI_CMD32 _IOWR('M', 1, struct mfi_ioc_packet32) +#endif #define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen) #define MAX_LINUX_IOCTL_SGE 16 @@ -98,7 +118,25 @@ struct mfi_linux_ioc_packet { #endif } __packed; +struct mfi_ioc_passthru { + struct mfi_dcmd_frame ioc_frame; + uint32_t buf_size; + uint8_t *buf; +} __packed; + +#ifdef __amd64__ +struct mfi_ioc_passthru32 { + struct mfi_dcmd_frame ioc_frame; + uint32_t buf_size; + uint32_t buf; +} __packed; +#endif + #define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest) +#define MFIIO_PASSTHRU _IOWR('C', 102, struct mfi_ioc_passthru) +#ifdef __amd64__ +#define MFIIO_PASSTHRU32 _IOWR('C', 102, struct mfi_ioc_passthru32) +#endif struct mfi_linux_ioc_aen { uint16_t laen_adapter_no; diff --git a/sys/dev/mfi/mfi_pci.c b/sys/dev/mfi/mfi_pci.c index 70850089778c..3becba02b786 100644 --- a/sys/dev/mfi/mfi_pci.c +++ b/sys/dev/mfi/mfi_pci.c @@ -117,6 +117,7 @@ struct mfi_ident { {0x1000, 0x0411, 0xffff, 0xffff, MFI_FLAGS_1064R, "LSI MegaSAS 1064R"}, /* Brocton IOP */ {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"}, {0, 0, 0, 0, 0, NULL} }; |
