diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/mlx/mlx.c | 391 | ||||
-rw-r--r-- | sys/dev/mlx/mlx_disk.c | 2 | ||||
-rw-r--r-- | sys/dev/mlx/mlx_pci.c | 24 | ||||
-rw-r--r-- | sys/dev/mlx/mlxreg.h | 35 | ||||
-rw-r--r-- | sys/dev/mlx/mlxvar.h | 27 |
5 files changed, 305 insertions, 174 deletions
diff --git a/sys/dev/mlx/mlx.c b/sys/dev/mlx/mlx.c index ee099d2..d747158 100644 --- a/sys/dev/mlx/mlx.c +++ b/sys/dev/mlx/mlx.c @@ -89,6 +89,10 @@ static int mlx_v4_tryqueue(struct mlx_softc *sc, struct mlx_command *mc); static int mlx_v4_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status); static void mlx_v4_intaction(struct mlx_softc *sc, int action); +static int mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc); +static int mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status); +static void mlx_v5_intaction(struct mlx_softc *sc, int action); + /* * Status monitoring */ @@ -296,6 +300,11 @@ mlx_attach(struct mlx_softc *sc) sc->mlx_findcomplete = mlx_v4_findcomplete; sc->mlx_intaction = mlx_v4_intaction; break; + case MLX_IFTYPE_5: + sc->mlx_tryqueue = mlx_v5_tryqueue; + sc->mlx_findcomplete = mlx_v5_findcomplete; + sc->mlx_intaction = mlx_v5_intaction; + break; default: device_printf(sc->mlx_dev, "attaching unsupported interface version %d\n", sc->mlx_iftype); return(ENXIO); /* should never happen */ @@ -402,6 +411,12 @@ mlx_attach(struct mlx_softc *sc) device_printf(sc->mlx_dev, " *** WARNING *** Use revision 4.06 or later\n"); } break; + case MLX_IFTYPE_5: + if (sc->mlx_fwminor < 7) { + device_printf(sc->mlx_dev, " *** WARNING *** This firmware revision is not recommended\n"); + device_printf(sc->mlx_dev, " *** WARNING *** Use revision 5.07 or later\n"); + } + break; default: device_printf(sc->mlx_dev, "interface version corrupted to %d\n", sc->mlx_iftype); return(ENXIO); /* should never happen */ @@ -504,15 +519,27 @@ int mlx_detach(device_t dev) { struct mlx_softc *sc = device_get_softc(dev); - int error; + struct mlxd_softc *mlxd; + int i, s, error; debug("called"); + error = EBUSY; + s = splbio(); if (sc->mlx_state & MLX_STATE_OPEN) - return(EBUSY); + goto out; + for (i = 0; i < MLX_MAXDRIVES; i++) { + if (sc->mlx_sysdrive[i].ms_disk != 0) { + mlxd = device_get_softc(sc->mlx_sysdrive[i].ms_disk); + if (mlxd->mlxd_flags & MLXD_OPEN) { /* drive is mounted, abort detach */ + device_printf(sc->mlx_sysdrive[i].ms_disk, "still open, can't detach\n"); + goto out; + } + } + } if ((error = mlx_shutdown(dev))) - return(error); + goto out; mlx_free(sc); @@ -521,8 +548,10 @@ mlx_detach(device_t dev) */ if (--cdev_registered == 0) cdevsw_remove(&mlx_cdevsw); - - return(0); + error = 0; + out: + splx(s); + return(error); } /******************************************************************************** @@ -539,7 +568,6 @@ int mlx_shutdown(device_t dev) { struct mlx_softc *sc = device_get_softc(dev); - struct mlxd_softc *mlxd; int i, s, error; debug("called"); @@ -547,19 +575,8 @@ mlx_shutdown(device_t dev) s = splbio(); error = 0; - /* assume we're going to shut down */ sc->mlx_state |= MLX_STATE_SHUTDOWN; - for (i = 0; i < MLX_MAXDRIVES; i++) { - if (sc->mlx_sysdrive[i].ms_disk != 0) { - mlxd = device_get_softc(sc->mlx_sysdrive[i].ms_disk); - if (mlxd->mlxd_flags & MLXD_OPEN) { /* drive is mounted, abort shutdown */ - sc->mlx_state &= ~MLX_STATE_SHUTDOWN; - device_printf(sc->mlx_sysdrive[i].ms_disk, "still open, can't shutdown\n"); - error = EBUSY; - goto out; - } - } - } + sc->mlx_intaction(sc, MLX_INTACTION_DISABLE); /* flush controller */ device_printf(sc->mlx_dev, "flushing cache..."); @@ -578,8 +595,6 @@ mlx_shutdown(device_t dev) } } - bus_generic_detach(sc->mlx_dev); - out: splx(s); return(error); @@ -633,18 +648,11 @@ void mlx_intr(void *arg) { struct mlx_softc *sc = (struct mlx_softc *)arg; - int worked; debug("called"); - /* spin collecting finished commands */ - worked = 0; - while (mlx_done(sc)) - worked = 1; - - /* did we do anything? */ - if (worked) - mlx_complete(sc); + /* collect finished commands, queue anything waiting */ + mlx_done(sc); }; /******************************************************************************* @@ -763,7 +771,6 @@ mlx_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p) if ((error = device_delete_child(sc->mlx_dev, dr->ms_disk)) != 0) goto detach_out; dr->ms_disk = 0; - bus_generic_detach(sc->mlx_dev); detach_out: if (error) { @@ -910,10 +917,6 @@ mlx_submit_ioctl(struct mlx_softc *sc, struct mlx_sysdrive *drive, u_long cmd, ******************************************************************************** ********************************************************************************/ -#define MLX_PERIODIC_ISBUSY(sc) (sc->mlx_polling <= 0) -#define MLX_PERIODIC_BUSY(sc) atomic_add_int(&sc->mlx_polling, 1); -#define MLX_PERIODIC_UNBUSY(sc) atomic_subtract_int(&sc->mlx_polling, 1); - /******************************************************************************** * Fire off commands to periodically check the status of connected drives. */ @@ -953,54 +956,35 @@ mlx_periodic(void *data) /* * Run normal periodic activities? */ - } else if (MLX_PERIODIC_ISBUSY(sc)) { + } else if (time_second > (sc->mlx_lastpoll + 10)) { + sc->mlx_lastpoll = time_second; - /* time to perform a periodic status poll? XXX tuneable interval? */ - if (time_second > (sc->mlx_lastpoll + 10)) { - sc->mlx_lastpoll = time_second; - - /* for caution's sake */ - if (sc->mlx_polling < 0) { - device_printf(sc->mlx_dev, "mlx_polling < 0\n"); - atomic_set_int(&sc->mlx_polling, 0); - } - - /* - * Check controller status. - */ - MLX_PERIODIC_BUSY(sc); - mlx_enquire(sc, MLX_CMD_ENQUIRY, sizeof(struct mlx_enquiry), mlx_periodic_enquiry); + /* + * Check controller status. + * + * XXX Note that this may not actually launch a command in situations of high load. + */ + mlx_enquire(sc, MLX_CMD_ENQUIRY, sizeof(struct mlx_enquiry), mlx_periodic_enquiry); - /* - * Check system drive status. - * - * XXX This might be better left to event-driven detection, eg. I/O to an offline - * drive will detect it's offline, rebuilds etc. should detect the drive is back - * online. - */ - MLX_PERIODIC_BUSY(sc); - mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(struct mlx_enq_sys_drive) * MLX_MAXDRIVES, + /* + * Check system drive status. + * + * XXX This might be better left to event-driven detection, eg. I/O to an offline + * drive will detect it's offline, rebuilds etc. should detect the drive is back + * online. + */ + mlx_enquire(sc, MLX_CMD_ENQSYSDRIVE, sizeof(struct mlx_enq_sys_drive) * MLX_MAXDRIVES, mlx_periodic_enquiry); - } - + /* * Get drive rebuild/check status */ - if (sc->mlx_rebuild >= 0) { - MLX_PERIODIC_BUSY(sc); + if (sc->mlx_rebuild >= 0) mlx_enquire(sc, MLX_CMD_REBUILDSTAT, sizeof(struct mlx_rebuild_stat), mlx_periodic_rebuild); - } - } else { - /* - * If things are still running from the last poll, complain about it. - * - * XXX If this becomes an issue, we should have some way of telling what - * has become stuck. - */ - device_printf(sc->mlx_dev, "poll still busy (%d)\n", sc->mlx_polling); } - /* XXX check for wedged/timed out commands? */ + /* deal with possibly-missed interrupts and timed-out commands */ + mlx_done(sc); /* reschedule another poll next second or so */ sc->mlx_timeout = timeout(mlx_periodic, sc, hz); @@ -1077,14 +1061,13 @@ mlx_periodic_enquiry(struct mlx_command *mc) break; } default: + device_printf(sc->mlx_dev, "%s: unknown command 0x%x", __FUNCTION__, mc->mc_mailbox[0]); break; } out: free(mc->mc_data, M_DEVBUF); mlx_releasecmd(mc); - /* this event is done */ - MLX_PERIODIC_UNBUSY(sc); } /******************************************************************************** @@ -1100,9 +1083,6 @@ mlx_periodic_eventlog_poll(struct mlx_softc *sc) debug("called"); - /* presume we are going to create another event */ - MLX_PERIODIC_BUSY(sc); - /* get ourselves a command buffer */ error = 1; if ((mc = mlx_alloccmd(sc)) == NULL) @@ -1135,8 +1115,6 @@ mlx_periodic_eventlog_poll(struct mlx_softc *sc) mlx_releasecmd(mc); if (result != NULL) free(result, M_DEVBUF); - /* abort this event */ - MLX_PERIODIC_UNBUSY(sc); } } @@ -1169,8 +1147,8 @@ mlx_periodic_eventlog_respond(struct mlx_command *mc) debug("called"); + sc->mlx_lastevent++; /* next message... */ if (mc->mc_status == 0) { - sc->mlx_lastevent++; /* got the message OK */ /* handle event log message */ switch(el->el_type) { @@ -1222,9 +1200,6 @@ mlx_periodic_eventlog_respond(struct mlx_command *mc) /* is there another message to obtain? */ if (sc->mlx_lastevent != sc->mlx_currevent) mlx_periodic_eventlog_poll(sc); - - /* this event is done */ - MLX_PERIODIC_UNBUSY(sc); } /******************************************************************************** @@ -1255,8 +1230,6 @@ mlx_periodic_rebuild(struct mlx_command *mc) } free(mc->mc_data, M_DEVBUF); mlx_releasecmd(mc); - /* this event is done */ - MLX_PERIODIC_UNBUSY(sc); } /******************************************************************************** @@ -1443,8 +1416,8 @@ mlx_flush(struct mlx_softc *sc) /* build a flush command */ mlx_make_type2(mc, MLX_CMD_FLUSH, 0, 0, 0, 0, 0, 0, 0, 0); - /* run the command in either polled or wait mode */ - if ((sc->mlx_state & MLX_STATE_INTEN) ? mlx_wait_command(mc) : mlx_poll_command(mc)) + /* can't assume that interrupts are going to work here, so play it safe */ + if (mlx_poll_command(mc)) goto out; /* command completed OK? */ @@ -1588,6 +1561,10 @@ mlx_startio(struct mlx_softc *sc) int cmd; int s; + /* avoid reentrancy */ + if (mlx_lock_tas(sc, MLX_LOCK_STARTING)) + return; + /* spin until something prevents us from doing any work */ s = splbio(); for (;;) { @@ -1626,7 +1603,7 @@ mlx_startio(struct mlx_softc *sc) /* build a suitable I/O command (assumes 512-byte rounded transfers) */ mlxd = (struct mlxd_softc *)bp->b_dev->si_drv1; - driveno = mlxd->mlxd_drive - &sc->mlx_sysdrive[0]; + driveno = mlxd->mlxd_drive - sc->mlx_sysdrive; blkcount = (bp->b_bcount + MLX_BLKSIZE - 1) / MLX_BLKSIZE; if ((bp->b_pblkno + blkcount) > sc->mlx_sysdrive[driveno].ms_size) @@ -1654,6 +1631,7 @@ mlx_startio(struct mlx_softc *sc) s = splbio(); } splx(s); + mlx_lock_clr(sc, MLX_LOCK_STARTING); } /******************************************************************************** @@ -1875,8 +1853,7 @@ mlx_unmapcmd(struct mlx_command *mc) } /******************************************************************************** - * Try to deliver (mc) to the controller. Take care of any completed commands - * that we encounter while doing so. + * Try to deliver (mc) to the controller. * * Can be called at any interrupt level, with or without interrupts enabled. */ @@ -1884,7 +1861,7 @@ static int mlx_start(struct mlx_command *mc) { struct mlx_softc *sc = mc->mc_sc; - int i, s, done, worked; + int i, s, done; debug("called"); @@ -1893,10 +1870,10 @@ mlx_start(struct mlx_command *mc) /* mark the command as currently being processed */ mc->mc_status = MLX_STATUS_BUSY; - - /* assume we don't collect any completed commands */ - worked = 0; + /* set a default 60-second timeout XXX tunable? XXX not currently used */ + mc->mc_timeout = time_second + 60; + /* spin waiting for the mailbox */ for (i = 100000, done = 0; (i > 0) && !done; i--) { s = splbio(); @@ -1905,14 +1882,8 @@ mlx_start(struct mlx_command *mc) /* move command to work queue */ TAILQ_INSERT_TAIL(&sc->mlx_work, mc, mc_link); } - splx(s); - /* check for command completion while we're at it */ - if (mlx_done(sc)) - worked = 1; + splx(s); /* drop spl to allow completion interrupts */ } - /* check to see if we picked up any completed commands */ - if (worked) - mlx_complete(sc); /* command is enqueued */ if (done) @@ -1925,60 +1896,66 @@ mlx_start(struct mlx_command *mc) sc->mlx_busycmd[mc->mc_slot] = NULL; device_printf(sc->mlx_dev, "controller wedged (not taking commands)\n"); mc->mc_status = MLX_STATUS_WEDGED; + mlx_complete(sc); return(EIO); } /******************************************************************************** - * Look at the controller (sc) and see if a command has been completed. - * If so, move the command buffer to the done queue for later collection - * and free the slot for immediate reuse. + * Poll the controller (sc) for completed commands. + * Update command status and free slots for reuse. If any slots were freed, + * new commands may be posted. * - * Returns nonzero if anything was added to the done queue. + * Returns nonzero if one or more commands were completed. */ static int mlx_done(struct mlx_softc *sc) { struct mlx_command *mc; - int s; + int s, result; u_int8_t slot; u_int16_t status; debug("called"); - mc = NULL; - slot = 0; + result = 0; - /* poll for a completed command's identifier and status */ + /* loop collecting completed commands */ s = splbio(); - if (sc->mlx_findcomplete(sc, &slot, &status)) { - mc = sc->mlx_busycmd[slot]; /* find command */ - if (mc != NULL) { /* paranoia */ - if (mc->mc_status == MLX_STATUS_BUSY) { - mc->mc_status = status; /* save status */ - - /* free slot for reuse */ - sc->mlx_busycmd[slot] = NULL; - sc->mlx_busycmds--; + for (;;) { + /* poll for a completed command's identifier and status */ + if (sc->mlx_findcomplete(sc, &slot, &status)) { + result = 1; + mc = sc->mlx_busycmd[slot]; /* find command */ + if (mc != NULL) { /* paranoia */ + if (mc->mc_status == MLX_STATUS_BUSY) { + mc->mc_status = status; /* save status */ + + /* free slot for reuse */ + sc->mlx_busycmd[slot] = NULL; + sc->mlx_busycmds--; + } else { + device_printf(sc->mlx_dev, "duplicate done event for slot %d\n", slot); + } } else { - device_printf(sc->mlx_dev, "duplicate done event for slot %d\n", slot); - mc = NULL; + device_printf(sc->mlx_dev, "done event for nonbusy slot %d\n", slot); } } else { - device_printf(sc->mlx_dev, "done event for nonbusy slot %d\n", slot); + break; } } - splx(s); - if (mc != NULL) { - /* unmap the command's data buffer */ - mlx_unmapcmd(mc); - return(1); - } - return(0); + /* if we've completed any commands, try posting some more */ + if (result) + mlx_startio(sc); + + /* handle completion and timeouts */ + mlx_complete(sc); + + return(result); } /******************************************************************************** - * Handle completion for all commands on (sc)'s done queue. + * Perform post-completion processing for commands on (sc). */ static void mlx_complete(struct mlx_softc *sc) @@ -1988,10 +1965,14 @@ mlx_complete(struct mlx_softc *sc) debug("called"); + /* avoid reentrancy XXX might want to signal and request a restart */ + if (mlx_lock_tas(sc, MLX_LOCK_COMPLETING)) + return; + s = splbio(); count = 0; - - /* scan the list of done commands */ + + /* scan the list of busy/done commands */ mc = TAILQ_FIRST(&sc->mlx_work); while (mc != NULL) { nc = TAILQ_NEXT(mc, mc_link); @@ -2000,13 +1981,14 @@ mlx_complete(struct mlx_softc *sc) if (count++ > (sc->mlx_maxiop * 2)) panic("mlx_work list corrupt!"); - /* Skip commands that are still busy */ + /* Command has been completed in some fashion */ if (mc->mc_status != MLX_STATUS_BUSY) { - - + + /* unmap the command's data buffer */ + mlx_unmapcmd(mc); /* - * Does the command have a completion handler? - */ + * Does the command have a completion handler? + */ if (mc->mc_complete != NULL) { /* remove from list and give to handler */ TAILQ_REMOVE(&sc->mlx_work, mc, mc_link); @@ -2031,8 +2013,7 @@ mlx_complete(struct mlx_softc *sc) } splx(s); - /* queue some more work if there is any */ - mlx_startio(sc); + mlx_lock_clr(sc, MLX_LOCK_COMPLETING); } /******************************************************************************** @@ -2280,6 +2261,86 @@ mlx_v4_intaction(struct mlx_softc *sc, int action) /******************************************************************************** ******************************************************************************** + Type 5 interface accessor methods + ******************************************************************************** + ********************************************************************************/ + +/******************************************************************************** + * Try to give (mc) to the controller. Returns 1 if successful, 0 on failure + * (the controller is not ready to take a command). + * + * Must be called at splbio or in a fashion that prevents reentry. + */ +static int +mlx_v5_tryqueue(struct mlx_softc *sc, struct mlx_command *mc) +{ + int i; + + debug("called"); + + /* ready for our command? */ + if (MLX_V5_GET_IDBR(sc) & MLX_V5_IDB_EMPTY) { + /* copy mailbox data to window */ + for (i = 0; i < 13; i++) + MLX_V5_PUT_MAILBOX(sc, i, mc->mc_mailbox[i]); + + /* post command */ + MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_HWMBOX_CMD); + return(1); + } + return(0); +} + +/******************************************************************************** + * See if a command has been completed, if so acknowledge its completion + * and recover the slot number and status code. + * + * Must be called at splbio or in a fashion that prevents reentry. + */ +static int +mlx_v5_findcomplete(struct mlx_softc *sc, u_int8_t *slot, u_int16_t *status) +{ + + debug("called"); + + /* status available? */ + if (MLX_V5_GET_ODBR(sc) & MLX_V5_ODB_HWSAVAIL) { + *slot = MLX_V5_GET_STATUS_IDENT(sc); /* get command identifier */ + *status = MLX_V5_GET_STATUS(sc); /* get status */ + + /* acknowledge completion */ + MLX_V5_PUT_ODBR(sc, MLX_V5_ODB_HWMBOX_ACK); + MLX_V5_PUT_IDBR(sc, MLX_V5_IDB_SACK); + return(1); + } + return(0); +} + +/******************************************************************************** + * Enable/disable interrupts as requested. + * + * Must be called at splbio or in a fashion that prevents reentry. + */ +static void +mlx_v5_intaction(struct mlx_softc *sc, int action) +{ + debug("called"); + + switch(action) { + case MLX_INTACTION_DISABLE: + MLX_V5_PUT_IER(sc, MLX_V5_IER_DISINT); + sc->mlx_state &= ~MLX_STATE_INTEN; + break; + case MLX_INTACTION_ENABLE: + MLX_V5_PUT_IER(sc, 0); + sc->mlx_state |= MLX_STATE_INTEN; + break; + } +} + + +/******************************************************************************** + ******************************************************************************** Debugging ******************************************************************************** ********************************************************************************/ @@ -2351,37 +2412,39 @@ mlx_diagnose_command(struct mlx_command *mc) /******************************************************************************* * Return a string describing the controller (hwid) */ +static struct +{ + int hwid; + char *name; +} mlx_controller_names[] = { + {0x01, "960P/PD"}, + {0x02, "960PL"}, + {0x10, "960PG"}, + {0x11, "960PJ"}, + {0x16, "960PTL"}, + {0x20, "1164P"}, + {-1, NULL} +}; + static char * mlx_name_controller(u_int32_t hwid) { static char buf[80]; - char smbuf[16]; - char *submodel; - int nchn; - - switch(hwid & 0xff) { - case 0x01: - submodel = "P/PD"; - break; - case 0x02: - submodel = "PL"; - break; - case 0x10: - submodel = "PG"; - break; - case 0x11: - submodel = "PJ"; - break; - case 0x16: - submodel = "PTL"; - break; - default: - sprintf(smbuf, " model 0x%x", hwid & 0xff); - submodel = smbuf; - break; + char *model; + int nchn, i; + + for (i = 0, model = NULL; mlx_controller_names[i].name != NULL; i++) { + if ((hwid & 0xff) == mlx_controller_names[i].hwid) { + model = mlx_controller_names[i].name; + break; + } + } + if (model == NULL) { + sprintf(buf, " model 0x%x", hwid & 0xff); + model = buf; } nchn = (hwid >> 8) & 0xff; - sprintf(buf, "DAC960%s, %d channel%s", submodel, nchn, nchn > 1 ? "s" : ""); + sprintf(buf, "DAC%s, %d channel%s", model, nchn, nchn > 1 ? "s" : ""); return(buf); } diff --git a/sys/dev/mlx/mlx_disk.c b/sys/dev/mlx/mlx_disk.c index 26bbfae..9624a9a 100644 --- a/sys/dev/mlx/mlx_disk.c +++ b/sys/dev/mlx/mlx_disk.c @@ -277,11 +277,11 @@ mlxd_attach(device_t dev) DEVSTAT_PRIORITY_ARRAY); dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw); + dsk->si_drv1 = sc; disks_registered++; /* set maximum I/O size */ dsk->si_iosize_max = sc->mlxd_controller->mlx_maxiosize * MLX_BLKSIZE; - dsk->si_drv1 = sc; return (0); } diff --git a/sys/dev/mlx/mlx_pci.c b/sys/dev/mlx/mlx_pci.c index 673b5eb..6448a52 100644 --- a/sys/dev/mlx/mlx_pci.c +++ b/sys/dev/mlx/mlx_pci.c @@ -81,30 +81,36 @@ static driver_t mlx_pci_driver = { DRIVER_MODULE(mlx, pci, mlx_pci_driver, mlx_devclass, 0, 0); -struct +struct mlx_ident { u_int16_t vendor; u_int16_t device; + u_int16_t subvendor; + u_int16_t subdevice; int iftype; char *desc; } mlx_identifiers[] = { - {0x1069, 0x0002, MLX_IFTYPE_3, "Mylex version 3 RAID interface"}, /* Mylex v3 software interface */ - {0x1069, 0x0010, MLX_IFTYPE_4, "Mylex version 4 RAID interface"}, /* Mylex v4 software interface */ - {0, 0, 0, 0} +/* {0x1069, 0x0001, 0x0000, 0x0000, MLX_IFTYPE_2, "Mylex version 2 RAID interface"}, */ + {0x1069, 0x0002, 0x0000, 0x0000, MLX_IFTYPE_3, "Mylex version 3 RAID interface"}, + {0x1069, 0x0010, 0x0000, 0x0000, MLX_IFTYPE_4, "Mylex version 4 RAID interface"}, + {0x1011, 0x1065, 0x1069, 0x0020, MLX_IFTYPE_5, "Mylex version 5 RAID interface"}, + {0, 0, 0, 0, 0, 0} }; static int mlx_pci_probe(device_t dev) { - int i; + struct mlx_ident *m; debug("called"); - for (i = 0; mlx_identifiers[i].vendor != 0; i++) { - if ((mlx_identifiers[i].vendor == pci_get_vendor(dev)) && - (mlx_identifiers[i].device == pci_get_device(dev))) { + for (m = mlx_identifiers; m->vendor != 0; m++) { + if ((m->vendor == pci_get_vendor(dev)) && + (m->device == pci_get_device(dev)) && + ((m->subvendor == 0) || ((m->subvendor == pci_get_subvendor(dev)) && + (m->subdevice == pci_get_subdevice(dev))))) { - device_set_desc(dev, mlx_identifiers[i].desc); + device_set_desc(dev, m->desc); return(0); } } diff --git a/sys/dev/mlx/mlxreg.h b/sys/dev/mlx/mlxreg.h index 6843b3e..f50e202 100644 --- a/sys/dev/mlx/mlxreg.h +++ b/sys/dev/mlx/mlxreg.h @@ -53,6 +53,7 @@ #define MLX_STATUS_OK 0x0000 #define MLX_STATUS_RDWROFFLINE 0x0002 /* read/write claims drive is offline */ #define MLX_STATUS_WEDGED 0xdead /* controller not listening */ +#define MLX_STATUS_LOST 0xbeef /* never came back */ #define MLX_STATUS_BUSY 0xffff /* command is in controller */ /* @@ -115,6 +116,40 @@ #define MLX_V4_IER_DISINT (1<<2) /* interrupt disable bit */ /* + * Accessor defines for the V5 interface + */ +#define MLX_V5_MAILBOX 0x50 +#define MLX_V5_STATUS_IDENT 0x5d +#define MLX_V5_STATUS 0x5e +#define MLX_V5_IDBR 0x60 +#define MLX_V5_ODBR 0x61 +#define MLX_V5_IER 0x34 + +#define MLX_V5_PUT_MAILBOX(sc, idx, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_MAILBOX + idx, val) +#define MLX_V5_GET_STATUS_IDENT(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_STATUS_IDENT) +#define MLX_V5_GET_STATUS(sc) bus_space_read_2 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_STATUS) +#define MLX_V5_GET_IDBR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_IDBR) +#define MLX_V5_PUT_IDBR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_IDBR, val) +#define MLX_V5_GET_ODBR(sc) bus_space_read_1 (sc->mlx_btag, sc->mlx_bhandle, MLX_V5_ODBR) +#define MLX_V5_PUT_ODBR(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_ODBR, val) +#define MLX_V5_PUT_IER(sc, val) bus_space_write_1(sc->mlx_btag, sc->mlx_bhandle, MLX_V5_IER, val) + +#define MLX_V5_IDB_EMPTY (1<<0) /* mailbox is empty */ + +#define MLX_V5_IDB_HWMBOX_CMD (1<<0) /* posted hardware mailbox command */ +#define MLX_V5_IDB_SACK (1<<1) /* acknowledge status read */ +#define MLX_V5_IDB_MEMMBOX_CMD (1<<4) /* posted memory mailbox command */ + +#define MLX_V5_ODB_HWSAVAIL (1<<0) /* status is available for hardware mailbox */ +#define MLX_V5_ODB_MEMSAVAIL (1<<1) /* status is available for memory mailbox */ + +#define MLX_V5_ODB_HWMBOX_ACK (1<<0) /* ack status read from hardware mailbox */ +#define MLX_V5_ODB_MEMMBOX_ACK (1<<1) /* ack status read from memory mailbox */ + +#define MLX_V5_IER_DISINT (1<<2) /* interrupt disable bit */ + + +/* * Scatter-gather list format, type 1, kind 00. */ struct mlx_sgentry diff --git a/sys/dev/mlx/mlxvar.h b/sys/dev/mlx/mlxvar.h index ae1d399..04c3246 100644 --- a/sys/dev/mlx/mlxvar.h +++ b/sys/dev/mlx/mlxvar.h @@ -65,6 +65,7 @@ struct mlx_command struct mlx_softc *mc_sc; /* controller that owns us */ u_int8_t mc_slot; /* command slot we occupy */ u_int16_t mc_status; /* command completion status */ + time_t mc_timeout; /* when this command expires */ u_int8_t mc_mailbox[16]; /* command mailbox */ u_int32_t mc_sgphys; /* physical address of s/g array in controller space */ int mc_nsgent; /* number of entries in s/g map */ @@ -144,6 +145,8 @@ struct mlx_softc int mlx_check; /* if >= 0, drive is being checked */ struct mlx_pause mlx_pause; /* pending pause operation details */ + int mlx_locks; /* reentrancy avoidance */ + /* interface-specific accessor functions */ int mlx_iftype; /* interface protocol */ #define MLX_IFTYPE_3 3 @@ -157,6 +160,30 @@ struct mlx_softc }; /* + * Simple (stupid) locks. + * + * Note that these are designed to avoid reentrancy, not concurrency, and will + * need to be replaced with something better. + */ +#define MLX_LOCK_COMPLETING (1<<0) +#define MLX_LOCK_STARTING (1<<1) + +static __inline int +mlx_lock_tas(struct mlx_softc *sc, int lock) +{ + if ((sc)->mlx_locks & (lock)) + return(1); + atomic_set_int(&sc->mlx_locks, lock); + return(0); +} + +static __inline void +mlx_lock_clr(struct mlx_softc *sc, int lock) +{ + atomic_clear_int(&sc->mlx_locks, lock); +} + +/* * Interface between bus connections and driver core. */ extern void mlx_free(struct mlx_softc *sc); |