Add locking to mly(4) and mark MPSAFE.
- Add a per-softc mutex. - Use mutex as CAM sim lock. - Use taskqueue_thread instead of taskqueue_swi_giant. - Use callout(9) instead of timeout(9). - Use bus_*() instead of bus_space_*(). Tested by: no one
This commit is contained in:
parent
e608775202
commit
9cc63a16af
@ -88,7 +88,8 @@ static void mly_periodic(void *data);
|
||||
static int mly_immediate_command(struct mly_command *mc);
|
||||
static int mly_start(struct mly_command *mc);
|
||||
static void mly_done(struct mly_softc *sc);
|
||||
static void mly_complete(void *context, int pending);
|
||||
static void mly_complete(struct mly_softc *sc);
|
||||
static void mly_complete_handler(void *context, int pending);
|
||||
|
||||
static int mly_alloc_command(struct mly_softc *sc, struct mly_command **mcp);
|
||||
static void mly_release_command(struct mly_command *mc);
|
||||
@ -116,7 +117,7 @@ static void mly_printstate(struct mly_softc *sc);
|
||||
static void mly_print_command(struct mly_command *mc);
|
||||
static void mly_print_packet(struct mly_command *mc);
|
||||
static void mly_panic(struct mly_softc *sc, char *reason);
|
||||
static int mly_timeout(struct mly_softc *sc);
|
||||
static void mly_timeout(void *arg);
|
||||
#endif
|
||||
void mly_print_controller(int controller);
|
||||
|
||||
@ -151,7 +152,6 @@ MODULE_DEPEND(mly, cam, 1, 1, 1);
|
||||
|
||||
static struct cdevsw mly_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_flags = D_NEEDGIANT,
|
||||
.d_open = mly_user_open,
|
||||
.d_close = mly_user_close,
|
||||
.d_ioctl = mly_user_ioctl,
|
||||
@ -216,8 +216,11 @@ mly_attach(device_t dev)
|
||||
debug_called(1);
|
||||
|
||||
sc->mly_dev = dev;
|
||||
mtx_init(&sc->mly_lock, "mly", NULL, MTX_DEF);
|
||||
callout_init_mtx(&sc->mly_periodic, &sc->mly_lock, 0);
|
||||
|
||||
#ifdef MLY_DEBUG
|
||||
callout_init_mtx(&sc->mly_timeout, &sc->mly_lock, 0);
|
||||
if (device_get_unit(sc->mly_dev) == 0)
|
||||
mly_softc0 = sc;
|
||||
#endif
|
||||
@ -238,7 +241,7 @@ mly_attach(device_t dev)
|
||||
/*
|
||||
* Initialise command-completion task.
|
||||
*/
|
||||
TASK_INIT(&sc->mly_task_complete, 0, mly_complete, sc);
|
||||
TASK_INIT(&sc->mly_task_complete, 0, mly_complete_handler, sc);
|
||||
|
||||
/* disable interrupts before we start talking to the controller */
|
||||
MLY_MASK_INTERRUPTS(sc);
|
||||
@ -260,7 +263,10 @@ mly_attach(device_t dev)
|
||||
/*
|
||||
* Obtain controller feature information
|
||||
*/
|
||||
if ((error = mly_get_controllerinfo(sc)))
|
||||
MLY_LOCK(sc);
|
||||
error = mly_get_controllerinfo(sc);
|
||||
MLY_UNLOCK(sc);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@ -274,13 +280,16 @@ mly_attach(device_t dev)
|
||||
* Get the current event counter for health purposes, populate the initial
|
||||
* health status buffer.
|
||||
*/
|
||||
if ((error = mly_get_eventstatus(sc)))
|
||||
goto out;
|
||||
MLY_LOCK(sc);
|
||||
error = mly_get_eventstatus(sc);
|
||||
|
||||
/*
|
||||
* Enable memory-mailbox mode.
|
||||
*/
|
||||
if ((error = mly_enable_mmbox(sc)))
|
||||
if (error == 0)
|
||||
error = mly_enable_mmbox(sc);
|
||||
MLY_UNLOCK(sc);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
@ -297,6 +306,7 @@ mly_attach(device_t dev)
|
||||
/*
|
||||
* Mark all attached devices for rescan.
|
||||
*/
|
||||
MLY_LOCK(sc);
|
||||
mly_scan_devices(sc);
|
||||
|
||||
/*
|
||||
@ -305,6 +315,7 @@ mly_attach(device_t dev)
|
||||
* the SCSI subsystem gets to us, courtesy of the "SCSI settling delay".
|
||||
*/
|
||||
mly_periodic((void *)sc);
|
||||
MLY_UNLOCK(sc);
|
||||
|
||||
/*
|
||||
* Create the control device.
|
||||
@ -317,7 +328,7 @@ mly_attach(device_t dev)
|
||||
MLY_UNMASK_INTERRUPTS(sc);
|
||||
|
||||
#ifdef MLY_DEBUG
|
||||
timeout((timeout_t *)mly_timeout, sc, MLY_CMD_TIMEOUT * hz);
|
||||
callout_reset(&sc->mly_timeout, MLY_CMD_TIMEOUT * hz, mly_timeout, sc);
|
||||
#endif
|
||||
|
||||
out:
|
||||
@ -353,8 +364,6 @@ mly_pci_attach(struct mly_softc *sc)
|
||||
mly_printf(sc, "can't allocate register window\n");
|
||||
goto fail;
|
||||
}
|
||||
sc->mly_btag = rman_get_bustag(sc->mly_regs_resource);
|
||||
sc->mly_bhandle = rman_get_bushandle(sc->mly_regs_resource);
|
||||
|
||||
/*
|
||||
* Allocate and connect our interrupt.
|
||||
@ -365,7 +374,7 @@ mly_pci_attach(struct mly_softc *sc)
|
||||
mly_printf(sc, "can't allocate interrupt\n");
|
||||
goto fail;
|
||||
}
|
||||
if (bus_setup_intr(sc->mly_dev, sc->mly_irq, INTR_TYPE_CAM | INTR_ENTROPY, NULL, mly_intr, sc, &sc->mly_intr)) {
|
||||
if (bus_setup_intr(sc->mly_dev, sc->mly_irq, INTR_TYPE_CAM | INTR_ENTROPY | INTR_MPSAFE, NULL, mly_intr, sc, &sc->mly_intr)) {
|
||||
mly_printf(sc, "can't set up interrupt\n");
|
||||
goto fail;
|
||||
}
|
||||
@ -405,7 +414,7 @@ mly_pci_attach(struct mly_softc *sc)
|
||||
BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
|
||||
0, /* flags */
|
||||
busdma_lock_mutex, /* lockfunc */
|
||||
&Giant, /* lockarg */
|
||||
&sc->mly_lock, /* lockarg */
|
||||
&sc->mly_buffer_dmat)) {
|
||||
mly_printf(sc, "can't allocate buffer DMA tag\n");
|
||||
goto fail;
|
||||
@ -511,18 +520,25 @@ mly_shutdown(device_t dev)
|
||||
struct mly_softc *sc = device_get_softc(dev);
|
||||
|
||||
debug_called(1);
|
||||
|
||||
if (sc->mly_state & MLY_STATE_OPEN)
|
||||
|
||||
MLY_LOCK(sc);
|
||||
if (sc->mly_state & MLY_STATE_OPEN) {
|
||||
MLY_UNLOCK(sc);
|
||||
return(EBUSY);
|
||||
}
|
||||
|
||||
/* kill the periodic event */
|
||||
untimeout(mly_periodic, sc, sc->mly_periodic);
|
||||
callout_stop(&sc->mly_periodic);
|
||||
#ifdef MLY_DEBUG
|
||||
callout_stop(&sc->mly_timeout);
|
||||
#endif
|
||||
|
||||
/* flush controller */
|
||||
mly_printf(sc, "flushing cache...");
|
||||
printf("%s\n", mly_flush(sc) ? "failed" : "done");
|
||||
|
||||
MLY_MASK_INTERRUPTS(sc);
|
||||
MLY_UNLOCK(sc);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@ -538,7 +554,9 @@ mly_intr(void *arg)
|
||||
|
||||
debug_called(2);
|
||||
|
||||
MLY_LOCK(sc);
|
||||
mly_done(sc);
|
||||
MLY_UNLOCK(sc);
|
||||
};
|
||||
|
||||
/********************************************************************************
|
||||
@ -676,6 +694,13 @@ mly_free(struct mly_softc *sc)
|
||||
/* Remove the management device */
|
||||
destroy_dev(sc->mly_dev_t);
|
||||
|
||||
if (sc->mly_intr)
|
||||
bus_teardown_intr(sc->mly_dev, sc->mly_irq, sc->mly_intr);
|
||||
callout_drain(&sc->mly_periodic);
|
||||
#ifdef MLY_DEBUG
|
||||
callout_drain(&sc->mly_timeout);
|
||||
#endif
|
||||
|
||||
/* detach from CAM */
|
||||
mly_cam_detach(sc);
|
||||
|
||||
@ -711,8 +736,6 @@ mly_free(struct mly_softc *sc)
|
||||
bus_dma_tag_destroy(sc->mly_mmbox_dmat);
|
||||
|
||||
/* disconnect the interrupt handler */
|
||||
if (sc->mly_intr)
|
||||
bus_teardown_intr(sc->mly_dev, sc->mly_irq, sc->mly_intr);
|
||||
if (sc->mly_irq != NULL)
|
||||
bus_release_resource(sc->mly_dev, SYS_RES_IRQ, sc->mly_irq_rid, sc->mly_irq);
|
||||
|
||||
@ -723,6 +746,8 @@ mly_free(struct mly_softc *sc)
|
||||
/* release the register window mapping */
|
||||
if (sc->mly_regs_resource != NULL)
|
||||
bus_release_resource(sc->mly_dev, SYS_RES_MEMORY, sc->mly_regs_rid, sc->mly_regs_resource);
|
||||
|
||||
mtx_destroy(&sc->mly_lock);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -1086,6 +1111,7 @@ mly_ioctl(struct mly_softc *sc, struct mly_command_ioctl *ioctl, void **data, si
|
||||
int error;
|
||||
|
||||
debug_called(1);
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
|
||||
mc = NULL;
|
||||
if (mly_alloc_command(sc, &mc)) {
|
||||
@ -1375,6 +1401,7 @@ mly_periodic(void *data)
|
||||
int bus, target;
|
||||
|
||||
debug_called(2);
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
|
||||
/*
|
||||
* Scan devices.
|
||||
@ -1398,7 +1425,7 @@ mly_periodic(void *data)
|
||||
mly_check_event(sc);
|
||||
|
||||
/* reschedule ourselves */
|
||||
sc->mly_periodic = timeout(mly_periodic, sc, MLY_PERIODIC_INTERVAL * hz);
|
||||
callout_schedule(&sc->mly_periodic, MLY_PERIODIC_INTERVAL * hz);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -1415,21 +1442,19 @@ static int
|
||||
mly_immediate_command(struct mly_command *mc)
|
||||
{
|
||||
struct mly_softc *sc = mc->mc_sc;
|
||||
int error, s;
|
||||
int error;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
/* spinning at splcam is ugly, but we're only used during controller init */
|
||||
s = splcam();
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
if ((error = mly_start(mc))) {
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
if (sc->mly_state & MLY_STATE_INTERRUPTS_ON) {
|
||||
/* sleep on the command */
|
||||
while(!(mc->mc_flags & MLY_CMD_COMPLETE)) {
|
||||
tsleep(mc, PRIBIO, "mlywait", 0);
|
||||
mtx_sleep(mc, &sc->mly_lock, PRIBIO, "mlywait", 0);
|
||||
}
|
||||
} else {
|
||||
/* spin and collect status while we do */
|
||||
@ -1437,7 +1462,6 @@ mly_immediate_command(struct mly_command *mc)
|
||||
mly_done(mc->mc_sc);
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@ -1453,9 +1477,9 @@ mly_start(struct mly_command *mc)
|
||||
{
|
||||
struct mly_softc *sc = mc->mc_sc;
|
||||
union mly_command_packet *pkt;
|
||||
int s;
|
||||
|
||||
debug_called(2);
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
|
||||
/*
|
||||
* Set the command up for delivery to the controller.
|
||||
@ -1467,8 +1491,6 @@ mly_start(struct mly_command *mc)
|
||||
mc->mc_timestamp = time_second;
|
||||
#endif
|
||||
|
||||
s = splcam();
|
||||
|
||||
/*
|
||||
* Do we have to use the hardware mailbox?
|
||||
*/
|
||||
@ -1477,7 +1499,6 @@ mly_start(struct mly_command *mc)
|
||||
* Check to see if the controller is ready for us.
|
||||
*/
|
||||
if (MLY_IDBR_TRUE(sc, MLY_HM_CMDSENT)) {
|
||||
splx(s);
|
||||
return(EBUSY);
|
||||
}
|
||||
mc->mc_flags |= MLY_CMD_BUSY;
|
||||
@ -1494,7 +1515,6 @@ mly_start(struct mly_command *mc)
|
||||
|
||||
/* check to see if the next index is free yet */
|
||||
if (pkt->mmbox.flag != 0) {
|
||||
splx(s);
|
||||
return(EBUSY);
|
||||
}
|
||||
mc->mc_flags |= MLY_CMD_BUSY;
|
||||
@ -1502,13 +1522,11 @@ mly_start(struct mly_command *mc)
|
||||
/* copy in new command */
|
||||
bcopy(mc->mc_packet->mmbox.data, pkt->mmbox.data, sizeof(pkt->mmbox.data));
|
||||
/* barrier to ensure completion of previous write before we write the flag */
|
||||
bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0,
|
||||
BUS_SPACE_BARRIER_WRITE);
|
||||
bus_barrier(sc->mly_regs_resource, 0, 0, BUS_SPACE_BARRIER_WRITE);
|
||||
/* copy flag last */
|
||||
pkt->mmbox.flag = mc->mc_packet->mmbox.flag;
|
||||
/* barrier to ensure completion of previous write before we notify the controller */
|
||||
bus_space_barrier(sc->mly_btag, sc->mly_bhandle, 0, 0,
|
||||
BUS_SPACE_BARRIER_WRITE);
|
||||
bus_barrier(sc->mly_regs_resource, 0, 0, BUS_SPACE_BARRIER_WRITE);
|
||||
|
||||
/* signal controller, update index */
|
||||
MLY_SET_REG(sc, sc->mly_idbr, MLY_AM_CMDSENT);
|
||||
@ -1516,7 +1534,6 @@ mly_start(struct mly_command *mc)
|
||||
}
|
||||
|
||||
mly_enqueue_busy(mc);
|
||||
splx(s);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@ -1529,9 +1546,9 @@ mly_done(struct mly_softc *sc)
|
||||
struct mly_command *mc;
|
||||
union mly_status_packet *sp;
|
||||
u_int16_t slot;
|
||||
int s, worked;
|
||||
int worked;
|
||||
|
||||
s = splcam();
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
worked = 0;
|
||||
|
||||
/* pick up hardware-mailbox commands */
|
||||
@ -1589,12 +1606,11 @@ mly_done(struct mly_softc *sc)
|
||||
MLY_SET_REG(sc, sc->mly_odbr, MLY_AM_STSREADY);
|
||||
}
|
||||
|
||||
splx(s);
|
||||
if (worked) {
|
||||
if (sc->mly_state & MLY_STATE_INTERRUPTS_ON)
|
||||
taskqueue_enqueue(taskqueue_swi_giant, &sc->mly_task_complete);
|
||||
taskqueue_enqueue(taskqueue_thread, &sc->mly_task_complete);
|
||||
else
|
||||
mly_complete(sc, 0);
|
||||
mly_complete(sc);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1602,13 +1618,21 @@ mly_done(struct mly_softc *sc)
|
||||
* Process completed commands
|
||||
*/
|
||||
static void
|
||||
mly_complete(void *context, int pending)
|
||||
mly_complete_handler(void *context, int pending)
|
||||
{
|
||||
struct mly_softc *sc = (struct mly_softc *)context;
|
||||
|
||||
MLY_LOCK(sc);
|
||||
mly_complete(sc);
|
||||
MLY_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
mly_complete(struct mly_softc *sc)
|
||||
{
|
||||
struct mly_command *mc;
|
||||
void (* mc_complete)(struct mly_command *mc);
|
||||
|
||||
|
||||
debug_called(2);
|
||||
|
||||
/*
|
||||
@ -1935,15 +1959,18 @@ mly_cam_attach(struct mly_softc *sc)
|
||||
|
||||
if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc,
|
||||
device_get_unit(sc->mly_dev),
|
||||
&Giant,
|
||||
&sc->mly_lock,
|
||||
sc->mly_controllerinfo->maximum_parallel_commands,
|
||||
1, devq)) == NULL) {
|
||||
return(ENOMEM);
|
||||
}
|
||||
MLY_LOCK(sc);
|
||||
if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) {
|
||||
MLY_UNLOCK(sc);
|
||||
mly_printf(sc, "CAM XPT phsyical channel registration failed\n");
|
||||
return(ENXIO);
|
||||
}
|
||||
MLY_UNLOCK(sc);
|
||||
debug(1, "registered physical channel %d", chn);
|
||||
}
|
||||
}
|
||||
@ -1955,15 +1982,18 @@ mly_cam_attach(struct mly_softc *sc)
|
||||
for (i = 0; i < sc->mly_controllerinfo->virtual_channels_present; i++, chn++) {
|
||||
if ((sc->mly_cam_sim[chn] = cam_sim_alloc(mly_cam_action, mly_cam_poll, "mly", sc,
|
||||
device_get_unit(sc->mly_dev),
|
||||
&Giant,
|
||||
&sc->mly_lock,
|
||||
sc->mly_controllerinfo->maximum_parallel_commands,
|
||||
0, devq)) == NULL) {
|
||||
return(ENOMEM);
|
||||
}
|
||||
MLY_LOCK(sc);
|
||||
if (xpt_bus_register(sc->mly_cam_sim[chn], sc->mly_dev, chn)) {
|
||||
MLY_UNLOCK(sc);
|
||||
mly_printf(sc, "CAM XPT virtual channel registration failed\n");
|
||||
return(ENXIO);
|
||||
}
|
||||
MLY_UNLOCK(sc);
|
||||
debug(1, "registered virtual channel %d", chn);
|
||||
}
|
||||
|
||||
@ -1987,12 +2017,14 @@ mly_cam_detach(struct mly_softc *sc)
|
||||
|
||||
debug_called(1);
|
||||
|
||||
MLY_LOCK(sc);
|
||||
for (i = 0; i < sc->mly_cam_channels; i++) {
|
||||
if (sc->mly_cam_sim[i] != NULL) {
|
||||
xpt_bus_deregister(cam_sim_path(sc->mly_cam_sim[i]));
|
||||
cam_sim_free(sc->mly_cam_sim[i], 0);
|
||||
}
|
||||
}
|
||||
MLY_UNLOCK(sc);
|
||||
if (sc->mly_cam_devq != NULL)
|
||||
cam_simq_free(sc->mly_cam_devq);
|
||||
}
|
||||
@ -2030,6 +2062,7 @@ mly_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
struct mly_softc *sc = cam_sim_softc(sim);
|
||||
|
||||
debug_called(2);
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
|
||||
switch (ccb->ccb_h.func_code) {
|
||||
|
||||
@ -2173,7 +2206,6 @@ mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
struct mly_command_scsi_small *ss;
|
||||
int bus, target;
|
||||
int error;
|
||||
int s;
|
||||
|
||||
bus = cam_sim_bus(sim);
|
||||
target = csio->ccb_h.target_id;
|
||||
@ -2220,11 +2252,9 @@ mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
* Get a command, or push the ccb back to CAM and freeze the queue.
|
||||
*/
|
||||
if ((error = mly_alloc_command(sc, &mc))) {
|
||||
s = splcam();
|
||||
xpt_freeze_simq(sim, 1);
|
||||
csio->ccb_h.status |= CAM_REQUEUE_REQ;
|
||||
sc->mly_qfrzn_cnt++;
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -2270,11 +2300,9 @@ mly_cam_action_io(struct cam_sim *sim, struct ccb_scsiio *csio)
|
||||
|
||||
/* give the command to the controller */
|
||||
if ((error = mly_start(mc))) {
|
||||
s = splcam();
|
||||
xpt_freeze_simq(sim, 1);
|
||||
csio->ccb_h.status |= CAM_REQUEUE_REQ;
|
||||
sc->mly_qfrzn_cnt++;
|
||||
splx(s);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -2306,7 +2334,6 @@ mly_cam_complete(struct mly_command *mc)
|
||||
struct mly_btl *btl;
|
||||
u_int8_t cmd;
|
||||
int bus, target;
|
||||
int s;
|
||||
|
||||
debug_called(2);
|
||||
|
||||
@ -2359,12 +2386,10 @@ mly_cam_complete(struct mly_command *mc)
|
||||
break;
|
||||
}
|
||||
|
||||
s = splcam();
|
||||
if (sc->mly_qfrzn_cnt) {
|
||||
csio->ccb_h.status |= CAM_RELEASE_SIMQ;
|
||||
sc->mly_qfrzn_cnt--;
|
||||
}
|
||||
splx(s);
|
||||
|
||||
xpt_done((union ccb *)csio);
|
||||
mly_release_command(mc);
|
||||
@ -2805,7 +2830,9 @@ mly_user_open(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct mly_softc *sc = dev->si_drv1;
|
||||
|
||||
MLY_LOCK(sc);
|
||||
sc->mly_state |= MLY_STATE_OPEN;
|
||||
MLY_UNLOCK(sc);
|
||||
return(0);
|
||||
}
|
||||
|
||||
@ -2817,7 +2844,9 @@ mly_user_close(struct cdev *dev, int flags, int fmt, struct thread *td)
|
||||
{
|
||||
struct mly_softc *sc = dev->si_drv1;
|
||||
|
||||
MLY_LOCK(sc);
|
||||
sc->mly_state &= ~MLY_STATE_OPEN;
|
||||
MLY_UNLOCK(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -2855,13 +2884,16 @@ static int
|
||||
mly_user_command(struct mly_softc *sc, struct mly_user_command *uc)
|
||||
{
|
||||
struct mly_command *mc;
|
||||
int error, s;
|
||||
int error;
|
||||
|
||||
/* allocate a command */
|
||||
MLY_LOCK(sc);
|
||||
if (mly_alloc_command(sc, &mc)) {
|
||||
MLY_UNLOCK(sc);
|
||||
error = ENOMEM;
|
||||
goto out; /* XXX Linux version will wait for a command */
|
||||
}
|
||||
MLY_UNLOCK(sc);
|
||||
|
||||
/* handle data size/direction */
|
||||
mc->mc_length = (uc->DataTransferLength >= 0) ? uc->DataTransferLength : -uc->DataTransferLength;
|
||||
@ -2888,12 +2920,14 @@ mly_user_command(struct mly_softc *sc, struct mly_user_command *uc)
|
||||
mc->mc_complete = NULL;
|
||||
|
||||
/* execute the command */
|
||||
if ((error = mly_start(mc)) != 0)
|
||||
MLY_LOCK(sc);
|
||||
if ((error = mly_start(mc)) != 0) {
|
||||
MLY_UNLOCK(sc);
|
||||
goto out;
|
||||
s = splcam();
|
||||
}
|
||||
while (!(mc->mc_flags & MLY_CMD_COMPLETE))
|
||||
tsleep(mc, PRIBIO, "mlyioctl", 0);
|
||||
splx(s);
|
||||
mtx_sleep(mc, &sc->mly_lock, PRIBIO, "mlyioctl", 0);
|
||||
MLY_UNLOCK(sc);
|
||||
|
||||
/* return the data to userspace */
|
||||
if (uc->DataTransferLength > 0)
|
||||
@ -2916,8 +2950,11 @@ mly_user_command(struct mly_softc *sc, struct mly_user_command *uc)
|
||||
out:
|
||||
if (mc->mc_data != NULL)
|
||||
free(mc->mc_data, M_DEVBUF);
|
||||
if (mc != NULL)
|
||||
if (mc != NULL) {
|
||||
MLY_LOCK(sc);
|
||||
mly_release_command(mc);
|
||||
MLY_UNLOCK(sc);
|
||||
}
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -2931,32 +2968,36 @@ static int
|
||||
mly_user_health(struct mly_softc *sc, struct mly_user_health *uh)
|
||||
{
|
||||
struct mly_health_status mh;
|
||||
int error, s;
|
||||
int error;
|
||||
|
||||
/* fetch the current health status from userspace */
|
||||
if ((error = copyin(uh->HealthStatusBuffer, &mh, sizeof(mh))) != 0)
|
||||
return(error);
|
||||
|
||||
/* spin waiting for a status update */
|
||||
s = splcam();
|
||||
MLY_LOCK(sc);
|
||||
error = EWOULDBLOCK;
|
||||
while ((error != 0) && (sc->mly_event_change == mh.change_counter))
|
||||
error = tsleep(&sc->mly_event_change, PRIBIO | PCATCH, "mlyhealth", 0);
|
||||
splx(s);
|
||||
error = mtx_sleep(&sc->mly_event_change, &sc->mly_lock, PRIBIO | PCATCH,
|
||||
"mlyhealth", 0);
|
||||
mh = sc->mly_mmbox->mmm_health.status;
|
||||
MLY_UNLOCK(sc);
|
||||
|
||||
/* copy the controller's health status buffer out (there is a race here if it changes again) */
|
||||
error = copyout(&sc->mly_mmbox->mmm_health.status, uh->HealthStatusBuffer,
|
||||
sizeof(uh->HealthStatusBuffer));
|
||||
/* copy the controller's health status buffer out */
|
||||
error = copyout(&mh, uh->HealthStatusBuffer, sizeof(mh));
|
||||
return(error);
|
||||
}
|
||||
|
||||
#ifdef MLY_DEBUG
|
||||
static int
|
||||
mly_timeout(struct mly_softc *sc)
|
||||
static void
|
||||
mly_timeout(void *arg)
|
||||
{
|
||||
struct mly_softc *sc;
|
||||
struct mly_command *mc;
|
||||
int deadline;
|
||||
|
||||
sc = arg;
|
||||
MLY_ASSERT_LOCKED(sc);
|
||||
deadline = time_second - MLY_CMD_TIMEOUT;
|
||||
TAILQ_FOREACH(mc, &sc->mly_busy, mc_link) {
|
||||
if ((mc->mc_timestamp < deadline)) {
|
||||
@ -2966,8 +3007,6 @@ mly_timeout(struct mly_softc *sc)
|
||||
}
|
||||
}
|
||||
|
||||
timeout((timeout_t *)mly_timeout, sc, MLY_CMD_TIMEOUT * hz);
|
||||
|
||||
return (0);
|
||||
callout_reset(&sc->mly_timeout, MLY_CMD_TIMEOUT * hz, mly_timeout, sc);
|
||||
}
|
||||
#endif
|
||||
|
@ -59,10 +59,6 @@
|
||||
|
||||
# include <sys/taskqueue.h>
|
||||
|
||||
#ifndef INTR_ENTROPY
|
||||
# define INTR_ENTROPY 0
|
||||
#endif
|
||||
|
||||
/********************************************************************************
|
||||
********************************************************************************
|
||||
Driver Variable Definitions
|
||||
@ -161,8 +157,6 @@ struct mly_softc {
|
||||
struct cdev *mly_dev_t;
|
||||
struct resource *mly_regs_resource; /* register interface window */
|
||||
int mly_regs_rid; /* resource ID */
|
||||
bus_space_handle_t mly_bhandle; /* bus space handle */
|
||||
bus_space_tag_t mly_btag; /* bus space tag */
|
||||
bus_dma_tag_t mly_parent_dmat; /* parent DMA tag */
|
||||
bus_dma_tag_t mly_buffer_dmat; /* data buffer/command DMA tag */
|
||||
struct resource *mly_irq; /* interrupt */
|
||||
@ -195,6 +189,7 @@ struct mly_softc {
|
||||
u_int32_t mly_mmbox_status_index; /* index we next expect status at */
|
||||
|
||||
/* controller features, limits and status */
|
||||
struct mtx mly_lock;
|
||||
int mly_state;
|
||||
#define MLY_STATE_OPEN (1<<1)
|
||||
#define MLY_STATE_INTERRUPTS_ON (1<<2)
|
||||
@ -219,7 +214,7 @@ struct mly_softc {
|
||||
u_int32_t mly_event_change; /* event status change indicator */
|
||||
u_int32_t mly_event_counter; /* next event for which we anticpiate status */
|
||||
u_int32_t mly_event_waiting; /* next event the controller will post status for */
|
||||
struct callout_handle mly_periodic; /* periodic event handling */
|
||||
struct callout mly_periodic; /* periodic event handling */
|
||||
|
||||
/* CAM connection */
|
||||
struct cam_devq *mly_cam_devq; /* CAM device queue */
|
||||
@ -230,29 +225,37 @@ struct mly_softc {
|
||||
/* command-completion task */
|
||||
struct task mly_task_complete; /* deferred-completion task */
|
||||
int mly_qfrzn_cnt; /* Track simq freezes */
|
||||
|
||||
#ifdef MLY_DEBUG
|
||||
struct callout mly_timeout;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define MLY_LOCK(sc) mtx_lock(&(sc)->mly_lock)
|
||||
#define MLY_UNLOCK(sc) mtx_unlock(&(sc)->mly_lock)
|
||||
#define MLY_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mly_lock, MA_OWNED)
|
||||
|
||||
/*
|
||||
* Register access helpers.
|
||||
*/
|
||||
#define MLY_SET_REG(sc, reg, val) bus_space_write_1(sc->mly_btag, sc->mly_bhandle, reg, val)
|
||||
#define MLY_GET_REG(sc, reg) bus_space_read_1 (sc->mly_btag, sc->mly_bhandle, reg)
|
||||
#define MLY_GET_REG2(sc, reg) bus_space_read_2 (sc->mly_btag, sc->mly_bhandle, reg)
|
||||
#define MLY_GET_REG4(sc, reg) bus_space_read_4 (sc->mly_btag, sc->mly_bhandle, reg)
|
||||
#define MLY_SET_REG(sc, reg, val) bus_write_1(sc->mly_regs_resource, reg, val)
|
||||
#define MLY_GET_REG(sc, reg) bus_read_1 (sc->mly_regs_resource, reg)
|
||||
#define MLY_GET_REG2(sc, reg) bus_read_2 (sc->mly_regs_resource, reg)
|
||||
#define MLY_GET_REG4(sc, reg) bus_read_4 (sc->mly_regs_resource, reg)
|
||||
|
||||
#define MLY_SET_MBOX(sc, mbox, ptr) \
|
||||
do { \
|
||||
bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox, *((u_int32_t *)ptr)); \
|
||||
bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox + 4, *((u_int32_t *)ptr + 1)); \
|
||||
bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox + 8, *((u_int32_t *)ptr + 2)); \
|
||||
bus_space_write_4(sc->mly_btag, sc->mly_bhandle, mbox + 12, *((u_int32_t *)ptr + 3)); \
|
||||
bus_write_4(sc->mly_regs_resource, mbox, *((u_int32_t *)ptr)); \
|
||||
bus_write_4(sc->mly_regs_resource, mbox + 4, *((u_int32_t *)ptr + 1)); \
|
||||
bus_write_4(sc->mly_regs_resource, mbox + 8, *((u_int32_t *)ptr + 2)); \
|
||||
bus_write_4(sc->mly_regs_resource, mbox + 12, *((u_int32_t *)ptr + 3)); \
|
||||
} while(0);
|
||||
#define MLY_GET_MBOX(sc, mbox, ptr) \
|
||||
do { \
|
||||
*((u_int32_t *)ptr) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox); \
|
||||
*((u_int32_t *)ptr + 1) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 4); \
|
||||
*((u_int32_t *)ptr + 2) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 8); \
|
||||
*((u_int32_t *)ptr + 3) = bus_space_read_4(sc->mly_btag, sc->mly_bhandle, mbox + 12); \
|
||||
*((u_int32_t *)ptr) = bus_read_4(sc->mly_regs_resource, mbox); \
|
||||
*((u_int32_t *)ptr + 1) = bus_read_4(sc->mly_regs_resource, mbox + 4); \
|
||||
*((u_int32_t *)ptr + 2) = bus_read_4(sc->mly_regs_resource, mbox + 8); \
|
||||
*((u_int32_t *)ptr + 3) = bus_read_4(sc->mly_regs_resource, mbox + 12); \
|
||||
} while(0);
|
||||
|
||||
#define MLY_IDBR_TRUE(sc, mask) \
|
||||
@ -315,46 +318,34 @@ mly_initq_ ## name (struct mly_softc *sc) \
|
||||
static __inline void \
|
||||
mly_enqueue_ ## name (struct mly_command *mc) \
|
||||
{ \
|
||||
int s; \
|
||||
\
|
||||
s = splcam(); \
|
||||
TAILQ_INSERT_TAIL(&mc->mc_sc->mly_ ## name, mc, mc_link); \
|
||||
MLYQ_ADD(mc->mc_sc, index); \
|
||||
splx(s); \
|
||||
} \
|
||||
static __inline void \
|
||||
mly_requeue_ ## name (struct mly_command *mc) \
|
||||
{ \
|
||||
int s; \
|
||||
\
|
||||
s = splcam(); \
|
||||
TAILQ_INSERT_HEAD(&mc->mc_sc->mly_ ## name, mc, mc_link); \
|
||||
MLYQ_ADD(mc->mc_sc, index); \
|
||||
splx(s); \
|
||||
} \
|
||||
static __inline struct mly_command * \
|
||||
mly_dequeue_ ## name (struct mly_softc *sc) \
|
||||
{ \
|
||||
struct mly_command *mc; \
|
||||
int s; \
|
||||
\
|
||||
s = splcam(); \
|
||||
if ((mc = TAILQ_FIRST(&sc->mly_ ## name)) != NULL) { \
|
||||
TAILQ_REMOVE(&sc->mly_ ## name, mc, mc_link); \
|
||||
MLYQ_REMOVE(sc, index); \
|
||||
} \
|
||||
splx(s); \
|
||||
return(mc); \
|
||||
} \
|
||||
static __inline void \
|
||||
mly_remove_ ## name (struct mly_command *mc) \
|
||||
{ \
|
||||
int s; \
|
||||
\
|
||||
s = splcam(); \
|
||||
TAILQ_REMOVE(&mc->mc_sc->mly_ ## name, mc, mc_link); \
|
||||
MLYQ_REMOVE(mc->mc_sc, index); \
|
||||
splx(s); \
|
||||
} \
|
||||
struct hack
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user