aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/advansys/advlib.c
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>2000-01-14 03:33:38 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>2000-01-14 03:33:38 +0000
commit9c0b8410b8e0ba1b2bfb7902b1737b14d8a68fe4 (patch)
tree466b58478a195571fb1568926068da7f8fa3882b /sys/dev/advansys/advlib.c
parent01779872245462cd3d3ed68618775e77c321d06b (diff)
downloadsrc-9c0b8410b8e0ba1b2bfb7902b1737b14d8a68fe4.tar.gz
src-9c0b8410b8e0ba1b2bfb7902b1737b14d8a68fe4.zip
adv_pci.c:
Update list of supported products. Adjust probe message to include the ASC3030. advansys.c: Fix a long standing bug in the error recovery strategy. In order to keep recovery simple, we freeze the SIMQ, stopping the XPT from submitting new requests. Unfortunately, we also will freeze the SIMQ if bus_dmamap_load blocks or we run out of controller resources. On cards with limited resources it was possible to freeze the SIM a second time and never unfreeze it. Now we more carefully track our exception state so we never freeze the SIMQ more than once. Don't rely on pointers fitting in a 32bit field stored in the per-transaction data structures on the card. Use an index to an array of transaction mapping structures instead. This should allow this driver to work on the Alpha. Deal with the ASC3030 which is almost idistinguishable from the ASC3050. Unfortunately the ASC3030 does not work at Ultra speeds, so if we can't find an eeprom, we must assume that ultra is disabled. The SIIG cards using the 3030 do not have eeproms. As a side effect, we now honor the ultra disable bit in the eeprom if it is present. Don't bother attempting to write corrected eeprom data back to the eeprom. We can function just fine if the data is corrupted and I'd rather not risk messing up the user's eeprom. Modify the interrupt handler to catch latched external bus rests. Dynamically determine the maximum number of S/G elements we can map at a single time. The nature of the firmware interface for these cards makes this value dependent on the number of "queues" the card can support. advlib.c: advlib.h: advmcode.c: advmcode.h: Synchronize with the latest firmware image released in the Linux Advansys driver.
Notes
Notes: svn path=/head/; revision=55945
Diffstat (limited to 'sys/dev/advansys/advlib.c')
-rw-r--r--sys/dev/advansys/advlib.c90
1 files changed, 53 insertions, 37 deletions
diff --git a/sys/dev/advansys/advlib.c b/sys/dev/advansys/advlib.c
index ad5469f31978..9bbf33d9cc10 100644
--- a/sys/dev/advansys/advlib.c
+++ b/sys/dev/advansys/advlib.c
@@ -1,7 +1,7 @@
/*
* Low level routines for the Advanced Systems Inc. SCSI controllers chips
*
- * Copyright (c) 1996-1997 Justin Gibbs.
+ * Copyright (c) 1996-1997, 1999-2000 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -234,7 +234,6 @@ static void adv_enable_interrupt(struct adv_softc *adv);
static void adv_toggle_irq_act(struct adv_softc *adv);
/* Chip Control */
-static int adv_stop_chip(struct adv_softc *adv);
static int adv_host_req_chip_halt(struct adv_softc *adv);
static void adv_set_chip_ih(struct adv_softc *adv, u_int16_t ins_code);
#if UNUSED
@@ -536,19 +535,25 @@ adv_set_eeprom_config(struct adv_softc *adv,
}
int
-adv_reset_chip_and_scsi_bus(struct adv_softc *adv)
+adv_reset_chip(struct adv_softc *adv, int reset_bus)
{
adv_stop_chip(adv);
- ADV_OUTB(adv, ADV_CHIP_CTRL,
- ADV_CC_CHIP_RESET | ADV_CC_SCSI_RESET | ADV_CC_HALT);
- DELAY(200 * 1000);
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT
+ | (reset_bus ? ADV_CC_SCSI_RESET : 0));
+ DELAY(60);
adv_set_chip_ih(adv, ADV_INS_RFLAG_WTM);
adv_set_chip_ih(adv, ADV_INS_HALT);
- ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
+ if (reset_bus)
+ ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_CHIP_RESET | ADV_CC_HALT);
+
ADV_OUTB(adv, ADV_CHIP_CTRL, ADV_CC_HALT);
- DELAY(200 * 1000);
+ if (reset_bus)
+ DELAY(200 * 1000);
+
+ ADV_OUTW(adv, ADV_CHIP_STATUS, ADV_CIW_CLR_SCSI_RESET_INT);
+ ADV_OUTW(adv, ADV_CHIP_STATUS, 0);
return (adv_is_chip_halted(adv));
}
@@ -712,7 +717,7 @@ adv_execute_scsi_queue(struct adv_softc *adv, struct adv_scsi_q *scsiq,
panic("adv_execute_scsi_queue: "
"Queue with too many segs.");
- if (adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) {
+ if ((adv->type & (ADV_ISA | ADV_VL | ADV_EISA)) != 0) {
int i;
for (i = 0; i < sg_entry_cnt_minus_one; i++) {
@@ -819,15 +824,14 @@ adv_copy_lram_doneq(struct adv_softc *adv, u_int16_t q_addr,
scsiq->extra_bytes = (val >> 8) & 0xFF;
/*
- * XXX
- * Due to a bug in accessing LRAM on the 940UA, we only pull
- * the low 16bits of residual information. In the future, we'll
- * want to allow transfers larger than 64K, but hopefully we'll
- * get a new firmware revision from AdvanSys that address this
- * problem before we up the transfer size.
+ * Due to a bug in accessing LRAM on the 940UA, the residual
+ * is split into separate high and low 16bit quantities.
*/
scsiq->remain_bytes =
adv_read_lram_16(adv, q_addr + ADV_SCSIQ_DW_REMAIN_XFER_CNT);
+ scsiq->remain_bytes |=
+ adv_read_lram_16(adv, q_addr + ADV_SCSIQ_W_ALT_DC1) << 16;
+
/*
* XXX Is this just a safeguard or will the counter really
* have bogus upper bits?
@@ -955,10 +959,11 @@ adv_isr_chip_halted(struct adv_softc *adv)
adv_handle_extmsg_in(adv, halt_q_addr, q_cntl,
target_mask, tid_no);
} else if (int_halt_code == ADV_HALT_CHK_CONDITION) {
- struct adv_target_transinfo* tinfo;
- union ccb *ccb;
- u_int8_t tag_code;
- u_int8_t q_status;
+ struct adv_target_transinfo* tinfo;
+ union ccb *ccb;
+ u_int32_t cinfo_index;
+ u_int8_t tag_code;
+ u_int8_t q_status;
tinfo = &adv->tinfo[tid_no];
q_cntl |= QC_REQ_SENSE;
@@ -995,8 +1000,9 @@ adv_isr_chip_halted(struct adv_softc *adv)
/*
* Freeze the devq until we can handle the sense condition.
*/
- ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr
- + ADV_SCSIQ_D_CCBPTR);
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
ccb->ccb_h.status |= CAM_DEV_QFRZN;
adv_abort_ccb(adv, tid_no, ADV_TIX_TO_LUN(target_ix),
@@ -1033,11 +1039,13 @@ adv_isr_chip_halted(struct adv_softc *adv)
} else if (int_halt_code == ADV_HALT_SS_QUEUE_FULL) {
u_int8_t scsi_status;
union ccb *ccb;
+ u_int32_t cinfo_index;
scsi_status = adv_read_lram_8(adv, halt_q_addr
+ ADV_SCSIQ_SCSI_STATUS);
- ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr
- + ADV_SCSIQ_D_CCBPTR);
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
ccb->ccb_h.status |= CAM_DEV_QFRZN|CAM_SCSI_STATUS_ERROR;
ccb->csio.scsi_status = SCSI_STATUS_QUEUE_FULL;
@@ -1047,6 +1055,8 @@ adv_isr_chip_halted(struct adv_softc *adv)
scsi_busy = adv_read_lram_8(adv, ADVV_SCSIBUSY_B);
scsi_busy &= ~target_mask;
adv_write_lram_8(adv, ADVV_SCSIBUSY_B, scsi_busy);
+ } else {
+ printf("Unhandled Halt Code %x\n", int_halt_code);
}
adv_write_lram_16(adv, ADVV_HALTCODE_W, 0);
}
@@ -1556,7 +1566,7 @@ adv_start_execution(struct adv_softc *adv)
}
}
-static int
+int
adv_stop_chip(struct adv_softc *adv)
{
u_int8_t cc_val;
@@ -1869,15 +1879,17 @@ adv_handle_extmsg_in(struct adv_softc *adv, u_int16_t halt_q_addr,
if ((ext_msg.msg_type == MSG_EXTENDED)
&& (ext_msg.msg_req == MSG_EXT_SDTR)
&& (ext_msg.msg_len == MSG_EXT_SDTR_LEN)) {
- union ccb *ccb;
- struct adv_target_transinfo* tinfo;
+ union ccb *ccb;
+ struct adv_target_transinfo* tinfo;
+ u_int32_t cinfo_index;
u_int period;
u_int offset;
int sdtr_accept;
u_int8_t orig_offset;
- ccb = (union ccb *) adv_read_lram_32(adv, halt_q_addr
- + ADV_SCSIQ_D_CCBPTR);
+ cinfo_index =
+ adv_read_lram_32(adv, halt_q_addr + ADV_SCSIQ_D_CINFO_IDX);
+ ccb = adv->ccb_infos[cinfo_index].ccb;
tinfo = &adv->tinfo[tid_no];
sdtr_accept = TRUE;
@@ -1966,23 +1978,25 @@ adv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
target_ix = ADV_TIDLUN_TO_IX(target, lun);
count = 0;
for (q_no = ADV_MIN_ACTIVE_QNO; q_no <= adv->max_openings; q_no++) {
+ struct adv_ccb_info *ccb_info;
q_addr = ADV_QNO_TO_QADDR(q_no);
adv_copy_lram_doneq(adv, q_addr, scsiq, adv->max_dma_count);
+ ccb_info = &adv->ccb_infos[scsiq->d2.ccb_index];
if (((scsiq->q_status & QS_READY) != 0)
&& ((scsiq->q_status & QS_ABORTED) == 0)
&& ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)
&& (scsiq->d2.target_ix == target_ix)
&& (queued_only == 0
|| !(scsiq->q_status & (QS_DISC1|QS_DISC2|QS_BUSY|QS_DONE)))
- && (ccb == NULL || (ccb == (union ccb *)scsiq->d2.ccb_ptr))) {
+ && (ccb == NULL || (ccb == ccb_info->ccb))) {
union ccb *aborted_ccb;
struct adv_ccb_info *cinfo;
scsiq->q_status |= QS_ABORTED;
adv_write_lram_8(adv, q_addr + ADV_SCSIQ_B_STATUS,
scsiq->q_status);
- aborted_ccb = (union ccb *)scsiq->d2.ccb_ptr;
+ aborted_ccb = ccb_info->ccb;
/* Don't clobber earlier error codes */
if ((aborted_ccb->ccb_h.status & CAM_STATUS_MASK)
== CAM_REQ_INPROG)
@@ -1997,19 +2011,21 @@ adv_abort_ccb(struct adv_softc *adv, int target, int lun, union ccb *ccb,
}
int
-adv_reset_bus(struct adv_softc *adv)
+adv_reset_bus(struct adv_softc *adv, int initiate_bus_reset)
{
int count;
int i;
union ccb *ccb;
- adv_reset_chip_and_scsi_bus(adv);
+ i = 200;
+ while ((ADV_INW(adv, ADV_CHIP_STATUS) & ADV_CSW_SCSI_RESET_ACTIVE) != 0
+ && i--)
+ DELAY(1000);
+ adv_reset_chip(adv, initiate_bus_reset);
adv_reinit_lram(adv);
- for (i = 0; i <= ADV_MAX_TID; i++) {
- if (adv->fix_asyn_xfer & (0x01 << i))
- adv_set_sdtr_reg_at_id(adv, i,
- ASYN_SDTR_DATA_FIX_PCI_REV_AB);
- }
+ for (i = 0; i <= ADV_MAX_TID; i++)
+ adv_set_syncrate(adv, NULL, i, /*period*/0,
+ /*offset*/0, ADV_TRANS_CUR);
ADV_OUTW(adv, ADV_REG_PROG_COUNTER, ADV_MCODE_START_ADDR);
/* Tell the XPT layer that a bus reset occured */