version 1.39, 2000/12/17 19:35:23 |
version 1.39.2.3, 2001/11/14 19:14:54 |
|
|
* disk has. Use these to disklabel your disk in an appropriate manner |
* disk has. Use these to disklabel your disk in an appropriate manner |
*/ |
*/ |
|
|
|
#include <sys/cdefs.h> |
|
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#include <sys/types.h> |
#include <sys/types.h> |
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
Line 196 struct sea_softc { |
|
Line 199 struct sea_softc { |
|
caddr_t maddr_cr_sr; /* Address of control and status reg */ |
caddr_t maddr_cr_sr; /* Address of control and status reg */ |
caddr_t maddr_dr; /* Address of data register */ |
caddr_t maddr_dr; /* Address of data register */ |
|
|
struct scsipi_link sc_link; /* prototype for subdevs */ |
|
struct scsipi_adapter sc_adapter; |
struct scsipi_adapter sc_adapter; |
|
struct scsipi_channel sc_channel; |
|
|
TAILQ_HEAD(, sea_scb) free_list, ready_list, nexus_list; |
TAILQ_HEAD(, sea_scb) free_list, ready_list, nexus_list; |
struct sea_scb *nexus; /* currently connected command */ |
struct sea_scb *nexus; /* currently connected command */ |
int numscbs; /* number of scsi control blocks */ |
int numscbs; /* number of scsi control blocks */ |
Line 273 static const char *bases[] = { |
|
Line 277 static const char *bases[] = { |
|
#endif |
#endif |
|
|
int seaintr __P((void *)); |
int seaintr __P((void *)); |
int sea_scsi_cmd __P((struct scsipi_xfer *)); |
void sea_scsipi_request __P((struct scsipi_channel *, |
|
scsipi_adapter_req_t, void *)); |
void sea_timeout __P((void *)); |
void sea_timeout __P((void *)); |
void sea_done __P((struct sea_softc *, struct sea_scb *)); |
void sea_done __P((struct sea_softc *, struct sea_scb *)); |
struct sea_scb *sea_get_scb __P((struct sea_softc *, int)); |
struct sea_scb *sea_get_scb __P((struct sea_softc *, int)); |
Line 289 int sea_transfer_pio __P((struct sea_sof |
|
Line 294 int sea_transfer_pio __P((struct sea_sof |
|
int *count, u_char **data)); |
int *count, u_char **data)); |
int sea_abort __P((struct sea_softc *, struct sea_scb *scb)); |
int sea_abort __P((struct sea_softc *, struct sea_scb *scb)); |
|
|
/* the below structure is so we have a default dev struct for our link struct */ |
void sea_grow_scb __P((struct sea_softc *)); |
struct scsipi_device sea_dev = { |
|
NULL, /* use default error handler */ |
|
NULL, /* have a queue, served by this */ |
|
NULL, /* have no async handler */ |
|
NULL, /* Use default 'done' routine */ |
|
}; |
|
|
|
int seaprobe __P((struct device *, struct cfdata *, void *)); |
int seaprobe __P((struct device *, struct cfdata *, void *)); |
void seaattach __P((struct device *, struct device *, void *)); |
void seaattach __P((struct device *, struct device *, void *)); |
Line 356 seaprobe(parent, match, aux) |
|
Line 355 seaprobe(parent, match, aux) |
|
|
|
/* check board type */ /* No way to define this through config */ |
/* check board type */ /* No way to define this through config */ |
for (i = 0; i < nsignatures; i++) |
for (i = 0; i < nsignatures; i++) |
if (!bcmp(maddr + signatures[i].offset, |
if (!memcmp(maddr + signatures[i].offset, |
signatures[i].signature, signatures[i].length)) { |
signatures[i].signature, signatures[i].length)) { |
type = signatures[i].type; |
type = signatures[i].type; |
break; |
break; |
Line 392 seaattach(parent, self, aux) |
|
Line 391 seaattach(parent, self, aux) |
|
{ |
{ |
struct isa_attach_args *ia = aux; |
struct isa_attach_args *ia = aux; |
struct sea_softc *sea = (void *)self; |
struct sea_softc *sea = (void *)self; |
|
struct scsipi_adapter *adapt = &sea->sc_adapter; |
|
struct scsipi_channel *chan = &sea->sc_channel; |
int i; |
int i; |
|
|
sea->maddr = ISA_HOLE_VADDR(ia->ia_maddr); |
sea->maddr = ISA_HOLE_VADDR(ia->ia_maddr); |
|
|
/* check board type */ /* No way to define this through config */ |
/* check board type */ /* No way to define this through config */ |
for (i = 0; i < nsignatures; i++) |
for (i = 0; i < nsignatures; i++) |
if (!bcmp(sea->maddr + signatures[i].offset, |
if (!memcmp(sea->maddr + signatures[i].offset, |
signatures[i].signature, signatures[i].length)) { |
signatures[i].signature, signatures[i].length)) { |
sea->type = signatures[i].type; |
sea->type = signatures[i].type; |
break; |
break; |
Line 440 seaattach(parent, self, aux) |
|
Line 441 seaattach(parent, self, aux) |
|
sea_init(sea); |
sea_init(sea); |
|
|
/* |
/* |
* Fill in the adapter. |
* Fill in the scsipi_adapter. |
*/ |
*/ |
sea->sc_adapter.scsipi_cmd = sea_scsi_cmd; |
memset(adapt, 0, sizeof(*adapt)); |
sea->sc_adapter.scsipi_minphys = minphys; |
adapt->adapt_dev = &sea->sc_dev; |
|
adapt->adapt_nchannels = 1; |
|
adapt->adapt_openings = sea->numscbs; |
|
adapt->adapt_max_periph = 1; |
|
adapt->adapt_request = sea_scsipi_request; |
|
adapt->adapt_minphys = minphys; |
|
|
/* |
/* |
* fill in the prototype scsipi_link. |
* Fill in the scsipi_channel. |
*/ |
*/ |
sea->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE; |
memset(chan, 0, sizeof(*chan)); |
sea->sc_link.adapter_softc = sea; |
chan->chan_adapter = adapt; |
sea->sc_link.scsipi_scsi.adapter_target = sea->our_id; |
chan->chan_bustype = &scsi_bustype; |
sea->sc_link.adapter = &sea->sc_adapter; |
chan->chan_channel = 0; |
sea->sc_link.device = &sea_dev; |
chan->chan_ntargets = 8; |
sea->sc_link.openings = 1; |
chan->chan_nluns = 8; |
sea->sc_link.scsipi_scsi.max_target = 7; |
chan->chan_id = sea->our_id; |
sea->sc_link.scsipi_scsi.max_lun = 7; |
chan->chan_flags = SCSIPI_CHAN_CANGROW; |
sea->sc_link.type = BUS_SCSI; |
|
|
|
printf("\n"); |
printf("\n"); |
|
|
Line 466 seaattach(parent, self, aux) |
|
Line 471 seaattach(parent, self, aux) |
|
/* |
/* |
* ask the adapter what subunits are present |
* ask the adapter what subunits are present |
*/ |
*/ |
config_found(self, &sea->sc_link, scsiprint); |
config_found(self, &sea->sc_channel, scsiprint); |
} |
} |
|
|
/* |
/* |
|
|
* start a scsi operation given the command and the data address. Also needs |
* start a scsi operation given the command and the data address. Also needs |
* the unit, target and lu. |
* the unit, target and lu. |
*/ |
*/ |
int |
void |
sea_scsi_cmd(xs) |
sea_scsipi_request(chan, req, arg) |
struct scsipi_xfer *xs; |
struct scsipi_channel *chan; |
|
scsipi_adapter_req_t req; |
|
void *arg; |
{ |
{ |
struct scsipi_link *sc_link = xs->sc_link; |
struct scsipi_xfer *xs; |
struct sea_softc *sea = sc_link->adapter_softc; |
struct scsipi_periph *periph; |
|
struct sea_softc *sea = (void *)chan->chan_adapter->adapt_dev; |
struct sea_scb *scb; |
struct sea_scb *scb; |
int flags; |
int flags; |
int s; |
int s; |
|
|
SC_DEBUG(sc_link, SDEV_DB2, ("sea_scsi_cmd\n")); |
switch (req) { |
|
case ADAPTER_REQ_RUN_XFER: |
flags = xs->xs_control; |
xs = arg; |
if ((scb = sea_get_scb(sea, flags)) == NULL) { |
periph = xs->xs_periph; |
xs->error = XS_DRIVER_STUFFUP; |
flags = xs->xs_control; |
return TRY_AGAIN_LATER; |
|
} |
SC_DEBUG(periph, SCSIPI_DB2, ("sea_scsipi_requeset\n")); |
scb->flags = SCB_ACTIVE; |
|
scb->xs = xs; |
/* XXX Reset not implemented. */ |
|
if (flags & XS_CTL_RESET) { |
|
printf("%s: resetting\n", sea->sc_dev.dv_xname); |
|
xs->error = XS_DRIVER_STUFFUP; |
|
scsipi_done(xs); |
|
return; |
|
} |
|
|
if (flags & XS_CTL_RESET) { |
/* Get an SCB to use. */ |
|
scb = sea_get_scb(sea, flags); |
|
#ifdef DIAGNOSTIC |
/* |
/* |
* Try to send a reset command to the card. |
* This should never happen as we track the resources |
* XXX Not implemented. |
* in the mid-layer. |
*/ |
*/ |
printf("%s: resetting\n", sea->sc_dev.dv_xname); |
if (scb == NULL) { |
xs->error = XS_DRIVER_STUFFUP; |
scsipi_printaddr(periph); |
return COMPLETE; |
printf("unable to allocate scb\n"); |
} |
panic("sea_scsipi_request"); |
|
} |
|
#endif |
|
|
/* |
scb->flags = SCB_ACTIVE; |
* Put all the arguments for the xfer in the scb |
scb->xs = xs; |
*/ |
|
scb->datalen = xs->datalen; |
/* |
scb->data = xs->data; |
* Put all the arguments for the xfer in the scb |
|
*/ |
|
scb->datalen = xs->datalen; |
|
scb->data = xs->data; |
|
|
#ifdef SEA_DEBUGQUEUE |
#ifdef SEA_DEBUGQUEUE |
sea_queue_length(sea); |
sea_queue_length(sea); |
#endif |
#endif |
|
|
s = splbio(); |
s = splbio(); |
|
|
sea_send_scb(sea, scb); |
sea_send_scb(sea, scb); |
|
|
/* |
if ((flags & XS_CTL_POLL) == 0) { |
* Usually return SUCCESSFULLY QUEUED |
callout_reset(&scb->xs->xs_callout, |
*/ |
(xs->timeout * hz) / 1000, sea_timeout, scb); |
if ((flags & XS_CTL_POLL) == 0) { |
splx(s); |
callout_reset(&scb->xs->xs_callout, (xs->timeout * hz) / 1000, |
return; |
sea_timeout, scb); |
} |
splx(s); |
|
return SUCCESSFULLY_QUEUED; |
|
} |
|
|
|
splx(s); |
splx(s); |
|
|
/* |
/* |
* If we can't use interrupts, poll on completion |
* If we can't use interrupts, poll on completion |
*/ |
*/ |
if (sea_poll(sea, xs, xs->timeout)) { |
if (sea_poll(sea, xs, xs->timeout)) { |
sea_timeout(scb); |
|
if (sea_poll(sea, xs, 2000)) |
|
sea_timeout(scb); |
sea_timeout(scb); |
|
if (sea_poll(sea, xs, 2000)) |
|
sea_timeout(scb); |
|
} |
|
return; |
|
|
|
case ADAPTER_REQ_GROW_RESOURCES: |
|
sea_grow_scb(sea); |
|
return; |
|
|
|
case ADAPTER_REQ_SET_XFER_MODE: |
|
{ |
|
struct scsipi_xfer_mode *xm = arg; |
|
|
|
/* |
|
* We don't support sync or wide or tagged queueing, |
|
* so announce that now. |
|
*/ |
|
xm->xm_mode = 0; |
|
xm->xm_period = 0; |
|
xm->xm_offset = 0; |
|
scsipi_async_event(chan, ASYNC_EVENT_XFER_MODE, xm); |
|
return; |
|
} |
} |
} |
return COMPLETE; |
|
} |
} |
|
|
/* |
/* |
Line 631 sea_get_scb(sea, flags) |
|
Line 669 sea_get_scb(sea, flags) |
|
struct sea_scb *scb; |
struct sea_scb *scb; |
|
|
s = splbio(); |
s = splbio(); |
|
if ((scb = TAILQ_FIRST(&sea->free_list)) != NULL) |
/* |
TAILQ_REMOVE(&sea->free_list, scb, chain); |
* If we can and have to, sleep waiting for one to come free |
|
* but only if we can't allocate a new one. |
|
*/ |
|
for (;;) { |
|
scb = sea->free_list.tqh_first; |
|
if (scb) { |
|
TAILQ_REMOVE(&sea->free_list, scb, chain); |
|
break; |
|
} |
|
if (sea->numscbs < SEA_SCB_MAX) { |
|
scb = (struct sea_scb *) malloc(sizeof(struct sea_scb), |
|
M_TEMP, M_NOWAIT); |
|
if (scb) { |
|
bzero(scb, sizeof(struct sea_scb)); |
|
sea->numscbs++; |
|
} else |
|
printf("%s: can't malloc scb\n", |
|
sea->sc_dev.dv_xname); |
|
break; |
|
} |
|
if ((flags & XS_CTL_NOSLEEP) != 0) |
|
break; |
|
tsleep(&sea->free_list, PRIBIO, "seascb", 0); |
|
} |
|
|
|
splx(s); |
splx(s); |
return scb; |
|
|
return (scb); |
} |
} |
|
|
/* |
/* |
Line 687 sea_send_scb(sea, scb) |
|
Line 701 sea_send_scb(sea, scb) |
|
* adapter in a system. Both sea_scsi_cmd and sea_intr will try to start it in |
* adapter in a system. Both sea_scsi_cmd and sea_intr will try to start it in |
* case it is not running. |
* case it is not running. |
*/ |
*/ |
|
|
void |
void |
sea_main() |
sea_main() |
{ |
{ |
|
|
*/ |
*/ |
for (scb = sea->ready_list.tqh_first; scb; |
for (scb = sea->ready_list.tqh_first; scb; |
scb = scb->chain.tqe_next) { |
scb = scb->chain.tqe_next) { |
if (!(sea->busy[scb->xs->sc_link->scsipi_scsi.target] & |
if (!(sea->busy[scb->xs->xs_periph->periph_target] & |
(1 << scb->xs->sc_link->scsipi_scsi.lun))) { |
(1 << scb->xs->xs_periph->periph_lun))) { |
TAILQ_REMOVE(&sea->ready_list, scb, |
TAILQ_REMOVE(&sea->ready_list, scb, |
chain); |
chain); |
|
|
|
|
main_running = 0; |
main_running = 0; |
} |
} |
|
|
|
/* |
|
* Allocate an scb and add it to the free list. |
|
* We are called at splbio. |
|
*/ |
|
void |
|
sea_grow_scb(sea) |
|
struct sea_softc *sea; |
|
{ |
|
struct sea_scb *scb; |
|
|
|
if (sea->numscbs == SEA_SCB_MAX) { |
|
sea->sc_channel.chan_flags &= ~SCSIPI_CHAN_CANGROW; |
|
return; |
|
} |
|
|
|
scb = malloc(sizeof(struct sea_scb), M_DEVBUF, M_NOWAIT); |
|
if (scb == NULL) |
|
return; |
|
|
|
memset(scb, 0, sizeof(struct sea_scb)); |
|
|
|
TAILQ_INSERT_TAIL(&sea->free_list, scb, chain); |
|
sea->numscbs++; |
|
sea->sc_adapter.adapt_openings++; |
|
} |
void |
void |
sea_free_scb(sea, scb, flags) |
sea_free_scb(sea, scb, flags) |
struct sea_softc *sea; |
struct sea_softc *sea; |
Line 793 sea_free_scb(sea, scb, flags) |
|
Line 833 sea_free_scb(sea, scb, flags) |
|
int s; |
int s; |
|
|
s = splbio(); |
s = splbio(); |
|
|
scb->flags = SCB_FREE; |
scb->flags = SCB_FREE; |
TAILQ_INSERT_HEAD(&sea->free_list, scb, chain); |
TAILQ_INSERT_HEAD(&sea->free_list, scb, chain); |
|
|
/* |
|
* If there were none, wake anybody waiting for one to come free, |
|
* starting with queued entries. |
|
*/ |
|
if (!scb->chain.tqe_next) |
|
wakeup((caddr_t)&sea->free_list); |
|
|
|
splx(s); |
splx(s); |
} |
} |
|
|
Line 813 sea_timeout(arg) |
|
Line 844 sea_timeout(arg) |
|
{ |
{ |
struct sea_scb *scb = arg; |
struct sea_scb *scb = arg; |
struct scsipi_xfer *xs = scb->xs; |
struct scsipi_xfer *xs = scb->xs; |
struct scsipi_link *sc_link = xs->sc_link; |
struct scsipi_periph *periph = xs->xs_periph; |
struct sea_softc *sea = sc_link->adapter_softc; |
struct sea_softc *sea = |
|
(void *)periph->periph_channel->chan_adapter->adapt_dev; |
int s; |
int s; |
|
|
scsi_print_addr(sc_link); |
scsipi_printaddr(periph); |
printf("timed out"); |
printf("timed out"); |
|
|
s = splbio(); |
s = splbio(); |
Line 830 sea_timeout(arg) |
|
Line 862 sea_timeout(arg) |
|
if (scb->flags & SCB_ABORTED) { |
if (scb->flags & SCB_ABORTED) { |
/* abort timed out */ |
/* abort timed out */ |
printf(" AGAIN\n"); |
printf(" AGAIN\n"); |
scb->xs->retries = 0; |
scb->xs->xs_retries = 0; |
scb->flags |= SCB_ABORTED; |
scb->flags |= SCB_ABORTED; |
sea_done(sea, scb); |
sea_done(sea, scb); |
} else { |
} else { |
Line 911 sea_reselect(sea) |
|
Line 943 sea_reselect(sea) |
|
*/ |
*/ |
for (scb = sea->nexus_list.tqh_first; scb; |
for (scb = sea->nexus_list.tqh_first; scb; |
scb = scb->chain.tqe_next) |
scb = scb->chain.tqe_next) |
if (target_mask == (1 << scb->xs->sc_link->scsipi_scsi.target) && |
if (target_mask == (1 << scb->xs->xs_periph->periph_target) && |
lun == scb->xs->sc_link->scsipi_scsi.lun) { |
lun == scb->xs->xs_periph->periph_lun) { |
TAILQ_REMOVE(&sea->nexus_list, scb, |
TAILQ_REMOVE(&sea->nexus_list, scb, |
chain); |
chain); |
break; |
break; |
Line 1062 sea_select(sea, scb) |
|
Line 1094 sea_select(sea, scb) |
|
} |
} |
|
|
delay(2); |
delay(2); |
DATA = (u_char)((1 << scb->xs->sc_link->scsipi_scsi.target) | |
DATA = (u_char)((1 << scb->xs->xs_periph->periph_target) | |
sea->our_id_mask); |
sea->our_id_mask); |
CONTROL = |
CONTROL = |
#ifdef SEA_NOMSGS |
#ifdef SEA_NOMSGS |
Line 1105 sea_select(sea, scb) |
|
Line 1137 sea_select(sea, scb) |
|
* (THIS IS NOT AN ERROR!) |
* (THIS IS NOT AN ERROR!) |
*/ |
*/ |
} else { |
} else { |
msg[0] = MSG_IDENTIFY(scb->xs->sc_link->scsipi_scsi.lun, 1); |
msg[0] = MSG_IDENTIFY(scb->xs->xs_periph->periph_lun, 1); |
len = 1; |
len = 1; |
data = msg; |
data = msg; |
phase = PH_MSGOUT; |
phase = PH_MSGOUT; |
Line 1117 sea_select(sea, scb) |
|
Line 1149 sea_select(sea, scb) |
|
sea->sc_dev.dv_xname); |
sea->sc_dev.dv_xname); |
|
|
sea->nexus = scb; |
sea->nexus = scb; |
sea->busy[scb->xs->sc_link->scsipi_scsi.target] |= |
sea->busy[scb->xs->xs_periph->periph_target] |= |
1 << scb->xs->sc_link->scsipi_scsi.lun; |
1 << scb->xs->xs_periph->periph_lun; |
/* This assignment should depend on possibility to send a message to target. */ |
/* This assignment should depend on possibility to send a message to target. */ |
CONTROL = BASE_CMD | CMD_DRVR_ENABLE; |
CONTROL = BASE_CMD | CMD_DRVR_ENABLE; |
/* XXX Reset pointer in command? */ |
/* XXX Reset pointer in command? */ |
Line 1209 sea_done(sea, scb) |
|
Line 1241 sea_done(sea, scb) |
|
if (scb->flags & SCB_ERROR) |
if (scb->flags & SCB_ERROR) |
xs->error = XS_DRIVER_STUFFUP; |
xs->error = XS_DRIVER_STUFFUP; |
} |
} |
xs->xs_status |= XS_STS_DONE; |
|
sea_free_scb(sea, scb, xs->xs_control); |
sea_free_scb(sea, scb, xs->xs_control); |
scsipi_done(xs); |
scsipi_done(xs); |
} |
} |
Line 1379 sea_information_transfer(sea) |
|
Line 1410 sea_information_transfer(sea) |
|
s = splbio(); |
s = splbio(); |
sea->nexus = NULL; |
sea->nexus = NULL; |
splx(s); |
splx(s); |
sea->busy[scb->xs->sc_link->scsipi_scsi.target] &= |
sea->busy[scb->xs->xs_periph->periph_target] &= |
~(1 << scb->xs->sc_link->scsipi_scsi.lun); |
~(1 << scb->xs->xs_periph->periph_lun); |
CONTROL = BASE_CMD; |
CONTROL = BASE_CMD; |
sea_done(sea, scb); |
sea_done(sea, scb); |
return; |
return; |
case MSG_MESSAGE_REJECT: |
case MSG_MESSAGE_REJECT: |
printf("%s: message_reject recieved\n", |
printf("%s: message_reject received\n", |
sea->sc_dev.dv_xname); |
sea->sc_dev.dv_xname); |
break; |
break; |
case MSG_DISCONNECT: |
case MSG_DISCONNECT: |
Line 1421 sea_information_transfer(sea) |
|
Line 1452 sea_information_transfer(sea) |
|
printf("%s: sent message abort to target\n", |
printf("%s: sent message abort to target\n", |
sea->sc_dev.dv_xname); |
sea->sc_dev.dv_xname); |
s = splbio(); |
s = splbio(); |
sea->busy[scb->xs->sc_link->scsipi_scsi.target] &= |
sea->busy[scb->xs->xs_periph->periph_target] &= |
~(1 << scb->xs->sc_link->scsipi_scsi.lun); |
~(1 << scb->xs->xs_periph->periph_lun); |
sea->nexus = NULL; |
sea->nexus = NULL; |
scb->flags = SCB_ABORTED; |
scb->flags = SCB_ABORTED; |
splx(s); |
splx(s); |