Add support for management apps. Work around an apparent firmware bug that
results in hung i/o if more than 128 commands are scheduled for an array.
This commit is contained in:
parent
404b160361
commit
0929b66905
@ -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);
|
||||
|
||||
@ -2017,6 +2028,80 @@ 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)
|
||||
{
|
||||
@ -2029,6 +2114,11 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
|
||||
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;
|
||||
@ -2253,6 +2343,21 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
|
||||
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;
|
||||
@ -2273,7 +2378,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;
|
||||
|
||||
@ -2332,9 +2436,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) {
|
||||
@ -2369,10 +2471,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,
|
||||
|
@ -98,7 +98,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;
|
||||
|
Loading…
Reference in New Issue
Block a user