Handle better the status codes.

Add a way to instruct the upper layer to don't bother w/ new requests if/when a device queue is full/busy or the device is unavailabale at that time
Use scsipi_inquiry_data instead of its own inquiry structure
This commit is contained in:
dante 2000-05-14 18:25:49 +00:00
parent 1937dbee6a
commit 94cd08a535
3 changed files with 185 additions and 166 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: adw.c,v 1.20 2000/05/10 21:22:34 dante Exp $ */
/* $NetBSD: adw.c,v 1.21 2000/05/14 18:25:49 dante Exp $ */
/*
* Generic driver for the Advanced Systems Inc. SCSI controllers
@ -92,6 +92,7 @@ static void adw_print_info __P((ADW_SOFTC *, int));
static int adw_poll __P((ADW_SOFTC *, struct scsipi_xfer *, int));
static void adw_timeout __P((void *));
static void adw_reset_bus __P((ADW_SOFTC *, struct scsipi_xfer *));
/******************************************************************************/
@ -566,6 +567,10 @@ adw_attach(sc)
sc->sc_dev.dv_xname, i, ADW_MAX_CARRIER);
}
/*
* Zero's the freeze_device status
*/
bzero(sc->sc_freeze_dev, sizeof(sc->sc_freeze_dev));
/*
* Initialize the adapter
@ -691,10 +696,20 @@ adw_scsi_cmd(xs)
* called with the first queue entry as our argument.
*/
if (xs == TAILQ_FIRST(&sc->sc_queue)) {
if(sc->sc_freeze_dev[xs->sc_link->scsipi_scsi.target]) {
splx(s);
return (TRY_AGAIN_LATER);
}
TAILQ_REMOVE(&sc->sc_queue, xs, adapter_q);
fromqueue = 1;
nowait = 1;
} else {
if(sc->sc_freeze_dev[xs->sc_link->scsipi_scsi.target]) {
splx(s);
xs->error = XS_DRIVER_STUFFUP;
return (TRY_AGAIN_LATER);
}
/* Polled requests can't be queued for later. */
dontqueue = xs->xs_control & XS_CTL_POLL;
@ -835,9 +850,7 @@ adw_build_req(xs, ccb, flags)
scsiqp->vsense_addr = &ccb->scsi_sense;
scsiqp->sense_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsi_sense);
/* scsiqp->sense_addr = ccb->hashkey +
offsetof(struct adw_ccb, scsi_sense);
*/ scsiqp->sense_len = sizeof(struct scsipi_sense_data);
scsiqp->sense_len = sizeof(struct scsipi_sense_data);
/*
* Build ADW_SCSI_REQ_Q for a scatter-gather buffer command.
@ -1023,17 +1036,8 @@ adw_timeout(arg)
* reinitialize the host adapter.
*/
callout_stop(&xs->xs_callout);
printf(" AGAIN. Resetting SCSI Bus\n");
AdvResetSCSIBus(sc);
while((ccb = TAILQ_LAST(&sc->sc_pending_ccb,
adw_pending_ccb)) != NULL) {
callout_stop(&ccb->xs->xs_callout);
TAILQ_REMOVE(&sc->sc_pending_ccb, ccb, chain);
TAILQ_INSERT_HEAD(&sc->sc_waiting_ccb, ccb, chain);
}
adw_queue_ccb(sc, TAILQ_FIRST(&sc->sc_waiting_ccb), 1);
adw_reset_bus(sc, xs);
splx(s);
return;
} else if (ccb->flags & CCB_ABORTING) {
@ -1108,6 +1112,27 @@ adw_timeout(arg)
}
static void
adw_reset_bus(sc, xs)
ADW_SOFTC *sc;
struct scsipi_xfer *xs;
{
ADW_CCB *ccb;
int s;
s = splbio();
AdvResetSCSIBus(sc);
while((ccb = TAILQ_LAST(&sc->sc_pending_ccb,
adw_pending_ccb)) != NULL) {
callout_stop(&ccb->xs->xs_callout);
TAILQ_REMOVE(&sc->sc_pending_ccb, ccb, chain);
TAILQ_INSERT_HEAD(&sc->sc_waiting_ccb, ccb, chain);
}
adw_queue_ccb(sc, TAILQ_FIRST(&sc->sc_waiting_ccb), 1);
splx(s);
}
/******************************************************************************/
/* Host Adapter and Peripherals Information Routines */
/******************************************************************************/
@ -1237,89 +1262,137 @@ adw_isr_callback(sc, scsiq)
* 'host_status' conatins the host adapter status.
* 'scsi_status' contains the scsi peripheral status.
*/
switch (scsiq->done_status) {
case QD_NO_ERROR:
xs->error = XS_NOERROR;
xs->resid = scsiq->data_cnt;
#ifdef ADW_DEBUG
/* Check for an underrun condition. */
if ((xs->datalen != 0) && (scsiq->data_cnt != 0) &&
(scsiq->data_cnt <= xs->datalen)) {
printf("%s: underrun condition %d bytes\n",
sc->sc_dev.dv_xname, scsiq->data_cnt);
}
#endif
if ((scsiq->cdb[0] == INQUIRY) && (scsiq->target_lun == 0)) {
if ((scsiq->host_status == QHSTA_NO_ERROR) &&
((scsiq->done_status == QD_NO_ERROR) ||
(scsiq->done_status == QD_WITH_ERROR))) {
switch (scsiq->host_status) {
case SCSI_STATUS_GOOD:
if ((scsiq->cdb[0] == INQUIRY) &&
(scsiq->target_lun == 0)) {
adw_print_info(sc, scsiq->target_id);
}
xs->error = XS_NOERROR;
xs->resid = scsiq->data_cnt;
sc->sc_freeze_dev[scsiq->target_id] = 0;
break;
case QD_WITH_ERROR:
switch (scsiq->host_status) {
case QHSTA_NO_ERROR:
switch(scsiq->scsi_status) {
case SS_CHK_CONDITION:
case SCSI_STATUS_CHECK_CONDITION:
case SCSI_STATUS_CMD_TERMINATED:
s1 = &ccb->scsi_sense;
s2 = &xs->sense.scsi_sense;
*s2 = *s1;
xs->error = XS_SENSE;
sc->sc_freeze_dev[scsiq->target_id] = 1;
break;
default:
xs->error = XS_DRIVER_STUFFUP;
#ifdef ADW_DEBUG
printf("%s: Command %d completed with error."
" SCSI Status = %d\n",
sc->sc_dev.dv_xname, scsiq->cdb[0],
scsiq->scsi_status);
#endif
xs->error = XS_BUSY;
sc->sc_freeze_dev[scsiq->target_id] = 1;
break;
}
} else if (scsiq->done_status == QD_ABORTED_BY_HOST) {
xs->error = XS_DRIVER_STUFFUP;
} else {
switch (scsiq->host_status) {
case QHSTA_M_SEL_TIMEOUT:
xs->error = XS_SELTIMEOUT;
break;
case QHSTA_M_SXFR_OFF_UFLW:
case QHSTA_M_SXFR_OFF_OFLW:
case QHSTA_M_DATA_OVER_RUN:
printf("%s: Overrun/Overflow/Underflow condition\n",
sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_SXFR_DESELECTED:
case QHSTA_M_UNEXPECTED_BUS_FREE:
printf("%s: Unexpected BUS free\n",sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_SCSI_BUS_RESET:
case QHSTA_M_SCSI_BUS_RESET_UNSOL:
printf("%s: BUS Reset\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_BUS_DEVICE_RESET:
printf("%s: Device Reset\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_QUEUE_ABORTED:
printf("%s: Queue Aborted\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_SXFR_SDMA_ERR:
case QHSTA_M_SXFR_SXFR_PERR:
case QHSTA_M_RDMA_PERR:
/*
* SCSI DMA Error. This should *NEVER* happen!
* DMA Error. This should *NEVER* happen!
*
* Lets try resetting the bus and reinitialize
* the host adapter.
*/
AdvResetSCSIBus(sc);
while((ccb = TAILQ_LAST(&sc->sc_pending_ccb,
adw_pending_ccb)) != NULL) {
callout_stop(&ccb->xs->xs_callout);
TAILQ_REMOVE(&sc->sc_pending_ccb, ccb, chain);
TAILQ_INSERT_HEAD(&sc->sc_waiting_ccb, ccb, chain);
}
adw_queue_ccb(sc, TAILQ_FIRST(&sc->sc_waiting_ccb), 1);
return;
default:
xs->error = XS_DRIVER_STUFFUP;
#ifdef ADW_DEBUG
printf("%s: Command %d completed with error."
" Host Status = %d\n",
sc->sc_dev.dv_xname, scsiq->cdb[0],
scsiq->host_status);
#endif
break;
}
printf("%s: DMA Error. Reseting bus\n",
sc->sc_dev.dv_xname);
adw_reset_bus(sc, xs);
xs->error = XS_BUSY;
break;
case QD_ABORTED_BY_HOST:
case QHSTA_M_WTM_TIMEOUT:
case QHSTA_M_SXFR_WD_TMO:
/* The SCSI bus hung in a phase */
printf("%s: Watch Dog timer expired. Reseting bus\n",
sc->sc_dev.dv_xname);
adw_reset_bus(sc, xs);
xs->error = XS_BUSY;
break;
case QHSTA_M_SXFR_XFR_PH_ERR:
printf("%s: Transfer Error\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_BAD_CMPL_STATUS_IN:
/* No command complete after a status message */
printf("%s: Bad Completion Status\n",
sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_AUTO_REQ_SENSE_FAIL:
printf("%s: Auto Sense Failed\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_INVALID_DEVICE:
printf("%s: Invalid Device\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_NO_AUTO_REQ_SENSE:
/*
* User didn't request sense, but we got a
* check condition.
*/
printf("%s: Unexpected Check Condition\n",
sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
break;
case QHSTA_M_SXFR_UNKNOWN_ERROR:
printf("%s: Unknown Error\n", sc->sc_dev.dv_xname);
xs->error = XS_DRIVER_STUFFUP;
printf("%s: Command aborted by host.\n", sc->sc_dev.dv_xname);
break;
default:
xs->error = XS_DRIVER_STUFFUP;
#ifdef ADW_DEBUG
printf("%s: Command %d completed with error."
" Done Status = %d\n",
sc->sc_dev.dv_xname, scsiq->cdb[0],
scsiq->done_status);
#endif
break;
panic("%s: Unhandled Host Status Error %x",
sc->sc_dev.dv_xname, scsiq->host_status);
}
}
TAILQ_REMOVE(&sc->sc_pending_ccb, ccb, chain);
@ -1339,9 +1412,7 @@ adw_async_callback(sc, code)
{
switch (code) {
case ADV_ASYNC_SCSI_BUS_RESET_DET:
/*
* The firmware detected a SCSI Bus reset.
*/
/* The firmware detected a SCSI Bus reset. */
printf("%s: SCSI Bus reset detected\n", sc->sc_dev.dv_xname);
break;
@ -1356,17 +1427,13 @@ adw_async_callback(sc, code)
break;
case ADV_HOST_SCSI_BUS_RESET:
/*
* Host generated SCSI bus reset occurred.
*/
/* Host generated SCSI bus reset occurred. */
printf("%s: Host generated SCSI bus reset occurred\n",
sc->sc_dev.dv_xname);
break;
case ADV_ASYNC_CARRIER_READY_FAILURE:
/*
* Carrier Ready failure.
*/
/* Carrier Ready failure. */
printf("%s: Carrier Ready failure!\n", sc->sc_dev.dv_xname);
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: adwlib.c,v 1.12 2000/05/10 21:22:34 dante Exp $ */
/* $NetBSD: adwlib.c,v 1.13 2000/05/14 18:25:49 dante Exp $ */
/*
* Low level routines for the Advanced Systems Inc. SCSI controllers chips
@ -3033,11 +3033,7 @@ ADW_SOFTC *sc;
}
/* Translate initialization return value to status value. */
if (status == 0) {
status = ADW_TRUE;
} else {
status = ADW_FALSE;
}
status = (status == 0)? ADW_TRUE : ADW_FALSE;
/*
* Restore the BIOS signature word.
@ -3248,7 +3244,7 @@ u_int32_t idle_cmd_parameter;
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
int result;
u_int16_t result;
u_int32_t i, j, s;
s = splbio();
@ -3256,8 +3252,6 @@ u_int32_t idle_cmd_parameter;
/*
* Clear the idle command status which is set by the microcode
* to a non-zero value to indicate when the command is completed.
* The non-zero result is one of the IDLE_CMD_STATUS_* values
* defined in a_advlib.h.
*/
ADW_WRITE_WORD_LRAM(iot, ioh, ASC_MC_IDLE_CMD_STATUS, (u_int16_t) 0);
@ -3318,7 +3312,7 @@ ADW_SCSI_REQ_Q *scsiq;
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
u_int8_t tid;
ADW_SCSI_INQUIRY *inq;
struct scsipi_inquiry_data *inq;
u_int16_t tidmask;
u_int16_t cfg_word;
@ -3339,12 +3333,13 @@ ADW_SCSI_REQ_Q *scsiq;
tid = scsiq->target_id;
inq = (ADW_SCSI_INQUIRY *) scsiq->vdata_addr;
inq = (struct scsipi_inquiry_data *) scsiq->vdata_addr;
/*
* WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
*/
if (inq->rsp_data_fmt < 2 && inq->ansi_apr_ver < 2) {
if (((inq->response_format & SID_RespDataFmt) < 2) /*SCSI-1 | CCS*/ &&
((inq->version & SID_ANSII) < 2)) {
return;
} else {
/*
@ -3369,7 +3364,7 @@ ADW_SCSI_REQ_Q *scsiq;
#ifdef SCSI_ADW_WDTR_DISABLE
if(!(tidmask & SCSI_ADW_WDTR_DISABLE))
#endif /* SCSI_ADW_WDTR_DISABLE */
if ((sc->wdtr_able & tidmask) && inq->WBus16) {
if ((sc->wdtr_able & tidmask) && (inq->flags3 & SID_WBus16)) {
ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_WDTR_ABLE,
cfg_word);
if ((cfg_word & tidmask) == 0) {
@ -3407,7 +3402,7 @@ ADW_SCSI_REQ_Q *scsiq;
#ifdef SCSI_ADW_SDTR_DISABLE
if(!(tidmask & SCSI_ADW_SDTR_DISABLE))
#endif /* SCSI_ADW_SDTR_DISABLE */
if ((sc->sdtr_able & tidmask) && inq->Sync) {
if ((sc->sdtr_able & tidmask) && (inq->flags3 & SID_Sync)) {
ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_SDTR_ABLE, cfg_word);
if ((cfg_word & tidmask) == 0) {
cfg_word |= tidmask;
@ -3442,7 +3437,8 @@ ADW_SCSI_REQ_Q *scsiq;
* and WDTR messages to negotiate synchronous speed
* and offset, transfer width, and protocol options.
*/
if (inq->Clocking & INQ_CLOCKING_DT_ONLY)
if ((inq->flags4 & SID_Cloacking) &
SIDV_CLOCKING_DT_ONLY)
{
ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_PPR_ABLE,
sc->ppr_able);
@ -3467,7 +3463,7 @@ ADW_SCSI_REQ_Q *scsiq;
#ifdef SCSI_ADW_TAGQ_DISABLE
if(!(tidmask & SCSI_ADW_TAGQ_DISABLE))
#endif /* SCSI_ADW_TAGQ_DISABLE */
if ((sc->tagqng_able & tidmask) && inq->CmdQue) {
if ((sc->tagqng_able & tidmask) && (inq->flags3 & SID_CmdQue)) {
ADW_READ_WORD_LRAM(iot, ioh, ASC_MC_TAGQNG_ABLE,
cfg_word);
cfg_word |= tidmask;

View File

@ -1,4 +1,4 @@
/* $NetBSD: adwlib.h,v 1.10 2000/05/10 21:22:34 dante Exp $ */
/* $NetBSD: adwlib.h,v 1.11 2000/05/14 18:25:49 dante Exp $ */
/*
* Definitions for low level routines and data structures
@ -1017,6 +1017,8 @@ typedef struct adw_softc {
TAILQ_HEAD(, scsipi_xfer) sc_queue;
int sc_freeze_dev[ADW_MAX_TID];
ADW_CALLBACK isr_callback; /* pointer to function, called in AdvISR() */
ADW_CALLBACK async_callback; /* pointer to function, called in AdvISR() */
u_int16_t bios_ctrl; /* BIOS control word, EEPROM word 12 */
@ -1134,15 +1136,15 @@ typedef struct adw_scsi_req_q {
/*
* ASC_SCSI_REQ_Q 'scsi_status' return values.
*/
#define SS_GOOD 0x00
#define SS_CHK_CONDITION 0x02
#define SS_CONDITION_MET 0x04
#define SS_TARGET_BUSY 0x08
#define SS_INTERMID 0x10
#define SS_INTERMID_COND_MET 0x14
#define SS_RSERV_CONFLICT 0x18
#define SS_CMD_TERMINATED 0x22
#define SS_QUEUE_FULL 0x28
#define SCSI_STATUS_GOOD 0x00
#define SCSI_STATUS_CHECK_CONDITION 0x02
#define SCSI_STATUS_CONDITION_MET 0x04
#define SCSI_STATUS_TARGET_BUSY 0x08
#define SCSI_STATUS_INTERMID 0x10
#define SCSI_STATUS_INTERMID_COND_MET 0x14
#define SCSI_STATUS_RSERV_CONFLICT 0x18
#define SCSI_STATUS_CMD_TERMINATED 0x22
#define SCSI_STATUS_QUEUE_FULL 0x28
/*
@ -1315,52 +1317,6 @@ do { \
*/
#define ADW_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADW_MAX_TID))
/*
* SCSI Iquiry structure
*/
#define INQ_CLOCKING_ST_ONLY 0x0
#define INQ_CLOCKING_DT_ONLY 0x1
#define INQ_CLOCKING_ST_AND_DT 0x3
typedef struct {
u_int8_t peri_dvc_type : 5; /* peripheral device type */
u_int8_t peri_qualifier : 3; /* peripheral qualifier */
u_int8_t dvc_type_modifier : 7; /* device type modifier (for SCSI I) */
u_int8_t rmb : 1; /* RMB - removable medium bit */
u_int8_t ansi_apr_ver : 3; /* ANSI approved version */
u_int8_t ecma_ver : 3; /* ECMA version */
u_int8_t iso_ver : 2; /* ISO version */
u_int8_t rsp_data_fmt : 4; /* response data format */
/* 0 SCSI 1 */
/* 1 CCS */
/* 2 SCSI-2 */
/* 3-F reserved */
u_int8_t res1 : 2; /* reserved */
u_int8_t TemIOP : 1; /* terminate I/O process bit (see 5.6.22) */
u_int8_t aenc : 1; /* asynch. event notification (processor) */
u_int8_t add_len; /* additional length */
u_int8_t res2; /* reserved */
u_int8_t res3; /* reserved */
u_int8_t StfRe : 1; /* soft reset implemented */
u_int8_t CmdQue : 1; /* command queuing */
u_int8_t res4 : 1; /* reserved */
u_int8_t Linked : 1; /* linked command for this logical unit */
u_int8_t Sync : 1; /* synchronous data transfer */
u_int8_t WBus16 : 1; /* wide bus 16 bit data transfer */
u_int8_t WBus32 : 1; /* wide bus 32 bit data transfer */
u_int8_t RelAdr : 1; /* relative addressing mode */
u_int8_t vendor_id[8]; /* vendor identification */
u_int8_t product_id[16]; /* product identification */
u_int8_t product_rev_level[4]; /* product revision level */
u_int8_t vendor_specific[20]; /* vendor specific */
u_int8_t IUS : 1; /* information unit supported */
u_int8_t QAS : 1; /* quick arbitrate supported */
u_int8_t Clocking : 2; /* clocking field */
u_int8_t res5 : 4; /* reserved */
u_int8_t res6; /* reserved */
} ADW_SCSI_INQUIRY; /* 58 bytes */
/*
* Adv Library functions available to drivers.
*/