Add locking to wds(4) and mark MPSAFE.
- Add per-softc mutex. - Use mutex for CAM SIM lock. - Use bus_*() instead of inb() and outb(). - Use bus_alloc_resource_any() when reasonable. Tested by: no one
This commit is contained in:
parent
42e8c47b78
commit
c1dffb2f08
@ -159,8 +159,8 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <isa/isavar.h>
|
#include <isa/isavar.h>
|
||||||
#include <isa/pnpvar.h>
|
#include <isa/pnpvar.h>
|
||||||
|
|
||||||
#define WDSTOPHYS(wp, a) ( ((u_long)a) - ((u_long)wp->dx) + ((u_long)wp->dx_p) )
|
#define WDSTOPHYS(wp, a) ( ((uintptr_t)a) - ((uintptr_t)wp->dx) + (wp->dx_p) )
|
||||||
#define WDSTOVIRT(wp, a) ( ((char *)a) - ((char*)wp->dx_p) + ((char *)wp->dx) )
|
#define WDSTOVIRT(wp, a) ( ((a) - (wp->dx_p)) + ((char *)wp->dx) )
|
||||||
|
|
||||||
/* 0x10000 (64k) should be enough. But just to be sure... */
|
/* 0x10000 (64k) should be enough. But just to be sure... */
|
||||||
#define BUFSIZ 0x12000
|
#define BUFSIZ 0x12000
|
||||||
@ -298,8 +298,8 @@ struct wdsdx {
|
|||||||
|
|
||||||
struct wds {
|
struct wds {
|
||||||
device_t dev;
|
device_t dev;
|
||||||
|
struct mtx lock;
|
||||||
int unit;
|
int unit;
|
||||||
int addr;
|
|
||||||
int drq;
|
int drq;
|
||||||
struct cam_sim *sim; /* SIM descriptor for this card */
|
struct cam_sim *sim; /* SIM descriptor for this card */
|
||||||
struct cam_path *path; /* wildcard path for this card */
|
struct cam_path *path; /* wildcard path for this card */
|
||||||
@ -307,7 +307,7 @@ struct wds {
|
|||||||
u_int32_t data_free;
|
u_int32_t data_free;
|
||||||
u_int32_t wdsr_free;
|
u_int32_t wdsr_free;
|
||||||
struct wdsdx *dx;
|
struct wdsdx *dx;
|
||||||
struct wdsdx *dx_p; /* physical address */
|
bus_addr_t dx_p; /* physical address */
|
||||||
struct resource *port_r;
|
struct resource *port_r;
|
||||||
int port_rid;
|
int port_rid;
|
||||||
struct resource *drq_r;
|
struct resource *drq_r;
|
||||||
@ -323,7 +323,8 @@ struct wds {
|
|||||||
|
|
||||||
static int wds_probe(device_t dev);
|
static int wds_probe(device_t dev);
|
||||||
static int wds_attach(device_t dev);
|
static int wds_attach(device_t dev);
|
||||||
static void wds_intr(struct wds *wp);
|
static void wds_intr(void *arg);
|
||||||
|
static void wds_intr_locked(struct wds *wp);
|
||||||
|
|
||||||
static void wds_action(struct cam_sim * sim, union ccb * ccb);
|
static void wds_action(struct cam_sim * sim, union ccb * ccb);
|
||||||
static void wds_poll(struct cam_sim * sim);
|
static void wds_poll(struct cam_sim * sim);
|
||||||
@ -345,8 +346,8 @@ static void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat);
|
|||||||
static int wds_runsense(struct wds *wp, struct wds_req *r);
|
static int wds_runsense(struct wds *wp, struct wds_req *r);
|
||||||
static int wds_getvers(struct wds *wp);
|
static int wds_getvers(struct wds *wp);
|
||||||
|
|
||||||
static int wds_cmd(int base, u_int8_t * p, int l);
|
static int wds_cmd(struct wds *wp, u_int8_t * p, int l);
|
||||||
static void wds_wait(int reg, int mask, int val);
|
static void wds_wait(struct wds *wp, int reg, int mask, int val);
|
||||||
|
|
||||||
static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
|
static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
|
||||||
|
|
||||||
@ -455,6 +456,7 @@ static int
|
|||||||
wds_probe(device_t dev)
|
wds_probe(device_t dev)
|
||||||
{
|
{
|
||||||
struct wds *wp;
|
struct wds *wp;
|
||||||
|
unsigned long addr;
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
@ -466,14 +468,13 @@ wds_probe(device_t dev)
|
|||||||
wp->unit = device_get_unit(dev);
|
wp->unit = device_get_unit(dev);
|
||||||
wp->dev = dev;
|
wp->dev = dev;
|
||||||
|
|
||||||
wp->addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/);
|
addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/);
|
||||||
if (wp->addr == 0 || wp->addr <0x300
|
if (addr == 0 || addr <0x300 || addr > 0x3f8 || addr & 0x7) {
|
||||||
|| wp->addr > 0x3f8 || wp->addr & 0x7) {
|
device_printf(dev, "invalid port address 0x%lx\n", addr);
|
||||||
device_printf(dev, "invalid port address 0x%x\n", wp->addr);
|
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bus_set_resource(dev, SYS_RES_IOPORT, 0, wp->addr, WDS_NPORTS) < 0)
|
if (bus_set_resource(dev, SYS_RES_IOPORT, 0, addr, WDS_NPORTS) < 0)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
/* get the DRQ */
|
/* get the DRQ */
|
||||||
@ -491,9 +492,8 @@ wds_probe(device_t dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wp->port_rid = 0;
|
wp->port_rid = 0;
|
||||||
wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid,
|
wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
|
||||||
/*start*/ 0, /*end*/ ~0,
|
RF_ACTIVE);
|
||||||
/*count*/ 0, RF_ACTIVE);
|
|
||||||
if (wp->port_r == NULL)
|
if (wp->port_r == NULL)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
@ -519,32 +519,29 @@ wds_attach(device_t dev)
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
wp = (struct wds *)device_get_softc(dev);
|
wp = (struct wds *)device_get_softc(dev);
|
||||||
|
mtx_init(&wp->lock, "wds", NULL, MTX_DEF);
|
||||||
|
|
||||||
wp->port_rid = 0;
|
wp->port_rid = 0;
|
||||||
wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid,
|
wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
|
||||||
/*start*/ 0, /*end*/ ~0,
|
RF_ACTIVE);
|
||||||
/*count*/ 0, RF_ACTIVE);
|
|
||||||
if (wp->port_r == NULL)
|
if (wp->port_r == NULL)
|
||||||
return (ENXIO);
|
goto bad;
|
||||||
|
|
||||||
/* We must now release resources on error. */
|
/* We must now release resources on error. */
|
||||||
|
|
||||||
wp->drq_rid = 0;
|
wp->drq_rid = 0;
|
||||||
wp->drq_r = bus_alloc_resource(dev, SYS_RES_DRQ, &wp->drq_rid,
|
wp->drq_r = bus_alloc_resource_any(dev, SYS_RES_DRQ, &wp->drq_rid,
|
||||||
/*start*/ 0, /*end*/ ~0,
|
RF_ACTIVE);
|
||||||
/*count*/ 0, RF_ACTIVE);
|
|
||||||
if (wp->drq_r == NULL)
|
if (wp->drq_r == NULL)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
wp->intr_rid = 0;
|
wp->intr_rid = 0;
|
||||||
wp->intr_r = bus_alloc_resource(dev, SYS_RES_IRQ, &wp->intr_rid,
|
wp->intr_r = bus_alloc_resource_any(dev, SYS_RES_IRQ, &wp->intr_rid,
|
||||||
/*start*/ 0, /*end*/ ~0,
|
RF_ACTIVE);
|
||||||
/*count*/ 0, RF_ACTIVE);
|
|
||||||
if (wp->intr_r == NULL)
|
if (wp->intr_r == NULL)
|
||||||
goto bad;
|
goto bad;
|
||||||
error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY,
|
error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY |
|
||||||
NULL, (driver_intr_t *)wds_intr, (void *)wp,
|
INTR_MPSAFE, NULL, wds_intr, wp, &wp->intr_cookie);
|
||||||
&wp->intr_cookie);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
@ -557,8 +554,8 @@ wds_attach(device_t dev)
|
|||||||
/*maxsize*/ sizeof(* wp->dx),
|
/*maxsize*/ sizeof(* wp->dx),
|
||||||
/*nsegments*/ 1,
|
/*nsegments*/ 1,
|
||||||
/*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0,
|
/*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0,
|
||||||
/*lockfunc*/busdma_lock_mutex,
|
/*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant,
|
/*lockarg*/NULL,
|
||||||
&wp->bustag);
|
&wp->bustag);
|
||||||
if (error)
|
if (error)
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -607,15 +604,17 @@ wds_attach(device_t dev)
|
|||||||
goto bad;
|
goto bad;
|
||||||
|
|
||||||
sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
|
sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
|
||||||
wp->unit, &Giant, 1, 1, devq);
|
wp->unit, &wp->lock, 1, 1, devq);
|
||||||
if (sim == NULL) {
|
if (sim == NULL) {
|
||||||
cam_simq_free(devq);
|
cam_simq_free(devq);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
wp->sim = sim;
|
wp->sim = sim;
|
||||||
|
|
||||||
|
mtx_lock(&wp->lock);
|
||||||
if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
|
if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
|
||||||
cam_sim_free(sim, /* free_devq */ TRUE);
|
cam_sim_free(sim, /* free_devq */ TRUE);
|
||||||
|
mtx_unlock(&wp->lock);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
if (xpt_create_path(&pathp, /* periph */ NULL,
|
if (xpt_create_path(&pathp, /* periph */ NULL,
|
||||||
@ -623,14 +622,17 @@ wds_attach(device_t dev)
|
|||||||
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
|
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
|
||||||
xpt_bus_deregister(cam_sim_path(sim));
|
xpt_bus_deregister(cam_sim_path(sim));
|
||||||
cam_sim_free(sim, /* free_devq */ TRUE);
|
cam_sim_free(sim, /* free_devq */ TRUE);
|
||||||
|
mtx_unlock(&wp->lock);
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
mtx_unlock(&wp->lock);
|
||||||
wp->path = pathp;
|
wp->path = pathp;
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
bad:
|
bad:
|
||||||
wds_free_resources(wp);
|
wds_free_resources(wp);
|
||||||
|
mtx_destroy(&wp->lock);
|
||||||
if (error)
|
if (error)
|
||||||
return (error);
|
return (error);
|
||||||
else /* exact error is unknown */
|
else /* exact error is unknown */
|
||||||
@ -759,19 +761,29 @@ wdsr_alloc(struct wds *wp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wds_intr(struct wds *wp)
|
wds_intr(void *arg)
|
||||||
|
{
|
||||||
|
struct wds *wp;
|
||||||
|
|
||||||
|
wp = arg;
|
||||||
|
mtx_lock(&wp->lock);
|
||||||
|
wds_intr_locked(wp);
|
||||||
|
mtx_unlock(&wp->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wds_intr_locked(struct wds *wp)
|
||||||
{
|
{
|
||||||
struct wds_req *rp;
|
struct wds_req *rp;
|
||||||
struct wds_mb *in;
|
struct wds_mb *in;
|
||||||
u_int8_t stat;
|
u_int8_t stat;
|
||||||
u_int8_t c;
|
u_int8_t c;
|
||||||
int addr = wp->addr;
|
|
||||||
|
|
||||||
DBG(DBX "wds%d: interrupt [\n", wp->unit);
|
DBG(DBX "wds%d: interrupt [\n", wp->unit);
|
||||||
smallog('[');
|
smallog('[');
|
||||||
|
|
||||||
if (inb(addr + WDS_STAT) & WDS_IRQ) {
|
if (bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) {
|
||||||
c = inb(addr + WDS_IRQSTAT);
|
c = bus_read_1(wp->port_r, WDS_IRQSTAT);
|
||||||
if ((c & WDSI_MASK) == WDSI_MSVC) {
|
if ((c & WDSI_MASK) == WDSI_MSVC) {
|
||||||
c = c & ~WDSI_MASK;
|
c = c & ~WDSI_MASK;
|
||||||
in = &wp->dx->imbs[c];
|
in = &wp->dx->imbs[c];
|
||||||
@ -790,7 +802,7 @@ wds_intr(struct wds *wp)
|
|||||||
} else
|
} else
|
||||||
device_printf(wp->dev,
|
device_printf(wp->dev,
|
||||||
"weird interrupt, irqstat=0x%x\n", c);
|
"weird interrupt, irqstat=0x%x\n", c);
|
||||||
outb(addr + WDS_IRQACK, 0);
|
bus_write_1(wp->port_r, WDS_IRQACK, 0);
|
||||||
} else {
|
} else {
|
||||||
smallog('?');
|
smallog('?');
|
||||||
}
|
}
|
||||||
@ -934,12 +946,12 @@ wds_runsense(struct wds *wp, struct wds_req *r)
|
|||||||
scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
|
scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
|
||||||
r->cmd.write = 0x80;
|
r->cmd.write = 0x80;
|
||||||
|
|
||||||
outb(wp->addr + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
|
bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
|
||||||
|
|
||||||
wp->dx->ombs[r->ombn].stat = 1;
|
wp->dx->ombs[r->ombn].stat = 1;
|
||||||
c = WDSC_MSTART(r->ombn);
|
c = WDSC_MSTART(r->ombn);
|
||||||
|
|
||||||
if (wds_cmd(wp->addr, &c, sizeof c) != 0) {
|
if (wds_cmd(wp, &c, sizeof c) != 0) {
|
||||||
device_printf(wp->dev, "unable to start outgoing sense mbox\n");
|
device_printf(wp->dev, "unable to start outgoing sense mbox\n");
|
||||||
wp->dx->ombs[r->ombn].stat = 0;
|
wp->dx->ombs[r->ombn].stat = 0;
|
||||||
wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL);
|
wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL);
|
||||||
@ -958,12 +970,9 @@ static int
|
|||||||
wds_getvers(struct wds *wp)
|
wds_getvers(struct wds *wp)
|
||||||
{
|
{
|
||||||
struct wds_req *r;
|
struct wds_req *r;
|
||||||
int base;
|
|
||||||
u_int8_t c;
|
u_int8_t c;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
base = wp->addr;
|
|
||||||
|
|
||||||
r = wdsr_alloc(wp);
|
r = wdsr_alloc(wp);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
device_printf(wp->dev, "no request slot available!\n");
|
device_printf(wp->dev, "no request slot available!\n");
|
||||||
@ -978,10 +987,10 @@ wds_getvers(struct wds *wp)
|
|||||||
bzero(&r->cmd, sizeof r->cmd);
|
bzero(&r->cmd, sizeof r->cmd);
|
||||||
r->cmd.cmd = WDSX_GETFIRMREV;
|
r->cmd.cmd = WDSX_GETFIRMREV;
|
||||||
|
|
||||||
outb(base + WDS_HCR, WDSH_DRQEN);
|
bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
|
||||||
|
|
||||||
c = WDSC_MSTART(r->ombn);
|
c = WDSC_MSTART(r->ombn);
|
||||||
if (wds_cmd(base, (u_int8_t *) & c, sizeof c)) {
|
if (wds_cmd(wp, (u_int8_t *) & c, sizeof c)) {
|
||||||
device_printf(wp->dev, "version request failed\n");
|
device_printf(wp->dev, "version request failed\n");
|
||||||
wp->wdsr_free |= (1 << r->id);
|
wp->wdsr_free |= (1 << r->id);
|
||||||
wp->dx->ombs[r->ombn].stat = 0;
|
wp->dx->ombs[r->ombn].stat = 0;
|
||||||
@ -989,14 +998,14 @@ wds_getvers(struct wds *wp)
|
|||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((inb(base + WDS_STAT) & WDS_IRQ) == 0) {
|
while ((bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) == 0) {
|
||||||
DELAY(9000);
|
DELAY(9000);
|
||||||
if (++i == 100) {
|
if (++i == 100) {
|
||||||
device_printf(wp->dev, "getvers timeout\n");
|
device_printf(wp->dev, "getvers timeout\n");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wds_intr(wp);
|
wds_intr_locked(wp);
|
||||||
if (r->flags & WR_DONE) {
|
if (r->flags & WR_DONE) {
|
||||||
device_printf(wp->dev, "firmware version %d.%02d\n",
|
device_printf(wp->dev, "firmware version %d.%02d\n",
|
||||||
r->cmd.targ, r->cmd.scb[0]);
|
r->cmd.targ, r->cmd.scb[0]);
|
||||||
@ -1016,9 +1025,8 @@ wdsr_ccb_done(struct wds *wp, struct wds_req *r,
|
|||||||
/* To implement timeouts we would need to know how to abort the
|
/* To implement timeouts we would need to know how to abort the
|
||||||
* command on controller, and this is a great mystery.
|
* command on controller, and this is a great mystery.
|
||||||
* So for now we just pass the responsibility for timeouts
|
* So for now we just pass the responsibility for timeouts
|
||||||
* to the controlles itself, it does that reasonably good.
|
* to the controller itself, it does that reasonably good.
|
||||||
*/
|
*/
|
||||||
/* untimeout(_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); */
|
|
||||||
/* we're about to free a hcb, so the shortage has ended */
|
/* we're about to free a hcb, so the shortage has ended */
|
||||||
frag_free(wp, r->mask);
|
frag_free(wp, r->mask);
|
||||||
if (wp->want_wdsr && status != CAM_REQUEUE_REQ) {
|
if (wp->want_wdsr && status != CAM_REQUEUE_REQ) {
|
||||||
@ -1040,7 +1048,6 @@ wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
|
|||||||
struct wds *wp;
|
struct wds *wp;
|
||||||
struct ccb_hdr *ccb_h;
|
struct ccb_hdr *ccb_h;
|
||||||
struct wds_req *r;
|
struct wds_req *r;
|
||||||
int base;
|
|
||||||
u_int8_t c;
|
u_int8_t c;
|
||||||
int error;
|
int error;
|
||||||
int n;
|
int n;
|
||||||
@ -1072,7 +1079,6 @@ wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
|
|||||||
xpt_done((union ccb *) csio);
|
xpt_done((union ccb *) csio);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
base = wp->addr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this check is mostly for debugging purposes,
|
* this check is mostly for debugging purposes,
|
||||||
@ -1150,11 +1156,11 @@ wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
|
|||||||
|
|
||||||
scsi_ulto3b(0, r->cmd.next);
|
scsi_ulto3b(0, r->cmd.next);
|
||||||
|
|
||||||
outb(base + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
|
bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
|
||||||
|
|
||||||
c = WDSC_MSTART(r->ombn);
|
c = WDSC_MSTART(r->ombn);
|
||||||
|
|
||||||
if (wds_cmd(base, &c, sizeof c) != 0) {
|
if (wds_cmd(wp, &c, sizeof c) != 0) {
|
||||||
device_printf(wp->dev, "unable to start outgoing mbox\n");
|
device_printf(wp->dev, "unable to start outgoing mbox\n");
|
||||||
wp->dx->ombs[r->ombn].stat = 0;
|
wp->dx->ombs[r->ombn].stat = 0;
|
||||||
wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL);
|
wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL);
|
||||||
@ -1170,16 +1176,13 @@ static void
|
|||||||
wds_action(struct cam_sim * sim, union ccb * ccb)
|
wds_action(struct cam_sim * sim, union ccb * ccb)
|
||||||
{
|
{
|
||||||
int unit = cam_sim_unit(sim);
|
int unit = cam_sim_unit(sim);
|
||||||
int s;
|
|
||||||
|
|
||||||
DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
|
DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
|
||||||
switch (ccb->ccb_h.func_code) {
|
switch (ccb->ccb_h.func_code) {
|
||||||
case XPT_SCSI_IO:
|
case XPT_SCSI_IO:
|
||||||
s = splcam();
|
|
||||||
DBG(DBX "wds%d: SCSI IO entered\n", unit);
|
DBG(DBX "wds%d: SCSI IO entered\n", unit);
|
||||||
wds_scsi_io(sim, &ccb->csio);
|
wds_scsi_io(sim, &ccb->csio);
|
||||||
DBG(DBX "wds%d: SCSI IO returned\n", unit);
|
DBG(DBX "wds%d: SCSI IO returned\n", unit);
|
||||||
splx(s);
|
|
||||||
break;
|
break;
|
||||||
case XPT_RESET_BUS:
|
case XPT_RESET_BUS:
|
||||||
/* how to do it right ? */
|
/* how to do it right ? */
|
||||||
@ -1242,7 +1245,7 @@ wds_action(struct cam_sim * sim, union ccb * ccb)
|
|||||||
static void
|
static void
|
||||||
wds_poll(struct cam_sim * sim)
|
wds_poll(struct cam_sim * sim)
|
||||||
{
|
{
|
||||||
wds_intr((struct wds *)cam_sim_softc(sim));
|
wds_intr_locked(cam_sim_softc(sim));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* part of initialization done in probe() */
|
/* part of initialization done in probe() */
|
||||||
@ -1251,32 +1254,29 @@ wds_poll(struct cam_sim * sim)
|
|||||||
static int
|
static int
|
||||||
wds_preinit(struct wds *wp)
|
wds_preinit(struct wds *wp)
|
||||||
{
|
{
|
||||||
int base;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
base = wp->addr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sending a command causes the CMDRDY bit to clear.
|
* Sending a command causes the CMDRDY bit to clear.
|
||||||
*/
|
*/
|
||||||
outb(base + WDS_CMD, WDSC_NOOP);
|
bus_write_1(wp->port_r, WDS_CMD, WDSC_NOOP);
|
||||||
if (inb(base + WDS_STAT) & WDS_RDY)
|
if (bus_read_1(wp->port_r, WDS_STAT) & WDS_RDY)
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the controller exists. reset and init.
|
* the controller exists. reset and init.
|
||||||
*/
|
*/
|
||||||
outb(base + WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
|
bus_write_1(wp->port_r, WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
|
||||||
DELAY(30);
|
DELAY(30);
|
||||||
outb(base + WDS_HCR, 0);
|
bus_write_1(wp->port_r, WDS_HCR, 0);
|
||||||
|
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY)
|
||||||
break;
|
break;
|
||||||
DELAY(40000);
|
DELAY(40000);
|
||||||
}
|
}
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
|
||||||
/* probe timeout */
|
/* probe timeout */
|
||||||
return (ENXIO);
|
return (ENXIO);
|
||||||
}
|
}
|
||||||
@ -1291,23 +1291,20 @@ static int
|
|||||||
wds_init(struct wds *wp)
|
wds_init(struct wds *wp)
|
||||||
{
|
{
|
||||||
struct wds_setup init;
|
struct wds_setup init;
|
||||||
int base;
|
|
||||||
int i;
|
int i;
|
||||||
struct wds_cmd wc;
|
struct wds_cmd wc;
|
||||||
|
|
||||||
base = wp->addr;
|
bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
|
||||||
|
|
||||||
outb(base + WDS_HCR, WDSH_DRQEN);
|
|
||||||
|
|
||||||
isa_dmacascade(wp->drq);
|
isa_dmacascade(wp->drq);
|
||||||
|
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY)
|
||||||
break;
|
break;
|
||||||
DELAY(40000);
|
DELAY(40000);
|
||||||
}
|
}
|
||||||
if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
|
if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
|
||||||
/* probe timeout */
|
/* probe timeout */
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@ -1321,18 +1318,18 @@ wds_init(struct wds *wp)
|
|||||||
init.nomb = WDS_NOMB;
|
init.nomb = WDS_NOMB;
|
||||||
init.nimb = WDS_NIMB;
|
init.nimb = WDS_NIMB;
|
||||||
|
|
||||||
wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
|
wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
|
||||||
if (wds_cmd(base, (u_int8_t *) & init, sizeof init) != 0) {
|
if (wds_cmd(wp, (u_int8_t *) & init, sizeof init) != 0) {
|
||||||
device_printf(wp->dev, "wds_cmd init failed\n");
|
device_printf(wp->dev, "wds_cmd init failed\n");
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
wds_wait(base + WDS_STAT, WDS_INIT, WDS_INIT);
|
wds_wait(wp, WDS_STAT, WDS_INIT, WDS_INIT);
|
||||||
|
|
||||||
wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
|
wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
|
||||||
|
|
||||||
bzero(&wc, sizeof wc);
|
bzero(&wc, sizeof wc);
|
||||||
wc.cmd = WDSC_DISUNSOL;
|
wc.cmd = WDSC_DISUNSOL;
|
||||||
if (wds_cmd(base, (char *) &wc, sizeof wc) != 0) {
|
if (wds_cmd(wp, (char *) &wc, sizeof wc) != 0) {
|
||||||
device_printf(wp->dev, "wds_cmd init2 failed\n");
|
device_printf(wp->dev, "wds_cmd init2 failed\n");
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@ -1340,29 +1337,26 @@ wds_init(struct wds *wp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
wds_cmd(int base, u_int8_t * p, int l)
|
wds_cmd(struct wds *wp, u_int8_t * p, int l)
|
||||||
{
|
{
|
||||||
int s = splcam();
|
|
||||||
|
|
||||||
while (l--) {
|
while (l--) {
|
||||||
do {
|
do {
|
||||||
outb(base + WDS_CMD, *p);
|
bus_write_1(wp->port_r, WDS_CMD, *p);
|
||||||
wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
|
wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
|
||||||
} while (inb(base + WDS_STAT) & WDS_REJ);
|
} while (bus_read_1(wp->port_r, WDS_STAT) & WDS_REJ);
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
|
wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
|
||||||
|
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
wds_wait(int reg, int mask, int val)
|
wds_wait(struct wds *wp, int reg, int mask, int val)
|
||||||
{
|
{
|
||||||
while ((inb(reg) & mask) != val)
|
while ((bus_read_1(wp->port_r, reg) & mask) != val)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,9 +1388,9 @@ wds_print(void)
|
|||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
continue;
|
continue;
|
||||||
printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
|
printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
|
||||||
unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff,
|
unit, wp->want_wdsr, bus_read_1(wp->port_r, WDS_STAT) & 0xff,
|
||||||
(inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no",
|
(bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) ? "ready" : "no",
|
||||||
inb(wp->addr + WDS_IRQSTAT) & 0xff);
|
bus_read_1(wp->port_r, WDS_IRQSTAT) & 0xff);
|
||||||
for (i = 0; i < MAXSIMUL; i++) {
|
for (i = 0; i < MAXSIMUL; i++) {
|
||||||
r = &wp->dx->req[i];
|
r = &wp->dx->req[i];
|
||||||
if( wp->wdsr_free & (1 << r->id) ) {
|
if( wp->wdsr_free & (1 << r->id) ) {
|
||||||
|
Loading…
Reference in New Issue
Block a user