summaryrefslogtreecommitdiffstats
path: root/sys/dev/advansys
diff options
context:
space:
mode:
authorgibbs <gibbs@FreeBSD.org>2000-03-02 00:08:35 +0000
committergibbs <gibbs@FreeBSD.org>2000-03-02 00:08:35 +0000
commita4d1a0ddb743a661a5422bdfba856eecdf6cdbd3 (patch)
treeec1a32a2babc2af9e360d30d054b21961ea6c631 /sys/dev/advansys
parentca682fe52708ec3cc63d2df5bced0405d8f4d409 (diff)
downloadFreeBSD-src-a4d1a0ddb743a661a5422bdfba856eecdf6cdbd3.zip
FreeBSD-src-a4d1a0ddb743a661a5422bdfba856eecdf6cdbd3.tar.gz
adv_pci.c:
adw_pci.c: Update comments describing supported chips/cards. adwcam.c: adwlib.c: adwlib.h: Handle more error return codes from the firmware. Break out the bus reset code into its own function. Usa a constant for the bus reset hold delay. Fix an interrupt race problem in adw_idle_cmd_send by incorporating the poll loop for command completion. Approved by: jkh@FreeBSDorg
Diffstat (limited to 'sys/dev/advansys')
-rw-r--r--sys/dev/advansys/adv_pci.c17
-rw-r--r--sys/dev/advansys/adw_pci.c2
-rw-r--r--sys/dev/advansys/adwcam.c107
-rw-r--r--sys/dev/advansys/adwlib.c66
-rw-r--r--sys/dev/advansys/adwlib.h22
5 files changed, 115 insertions, 99 deletions
diff --git a/sys/dev/advansys/adv_pci.c b/sys/dev/advansys/adv_pci.c
index 5e14528..1dbd340 100644
--- a/sys/dev/advansys/adv_pci.c
+++ b/sys/dev/advansys/adv_pci.c
@@ -12,20 +12,21 @@
* ABP930 - Bus-Master PCI (16 CDB) *
* ABP930U - Bus-Master PCI Ultra (16 CDB)
* ABP930UA - Bus-Master PCI Ultra (16 CDB)
- * ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
* ABP960 - Bus-Master PCI MAC/PC (16 CDB) **
- * ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
- * ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
- * ABP3960UA - Bus-Master PCI MAC/PC (240 CDB)
+ * ABP960U - Bus-Master PCI MAC/PC (16 CDB) **
*
* Single Channel Products:
- * ABP940 - Bus-Master PCI (240 CDB)
- * ABP940U - Bus-Master PCI Ultra (240 CDB)
- * ABP970 - Bus-Master PCI MAC/PC (240 CDB)
- * ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ * ABP940 - Bus-Master PCI (240 CDB)
+ * ABP940U - Bus-Master PCI Ultra (240 CDB)
+ * ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
+ * ABP3960UA - Bus-Master PCI MAC/PC (240 CDB)
+ * ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+ * ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
*
* Dual Channel Products:
* ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+ * ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+ * ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
* ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
*
* Footnotes:
diff --git a/sys/dev/advansys/adw_pci.c b/sys/dev/advansys/adw_pci.c
index a7aaab2..3089a15 100644
--- a/sys/dev/advansys/adw_pci.c
+++ b/sys/dev/advansys/adw_pci.c
@@ -4,7 +4,9 @@
*
* ABP[3]940UW - Bus-Master PCI Ultra-Wide (253 CDB)
* ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB/Channel)
+ * ABP970UW - Bus-Master PCI Ultra-Wide (253 CDB)
* ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+ * ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
*
* Copyright (c) 1998, 1999, 2000 Justin Gibbs.
* All rights reserved.
diff --git a/sys/dev/advansys/adwcam.c b/sys/dev/advansys/adwcam.c
index b64a60a..a3427fc 100644
--- a/sys/dev/advansys/adwcam.c
+++ b/sys/dev/advansys/adwcam.c
@@ -78,6 +78,7 @@
u_long adw_unit;
+static __inline cam_status adwccbstatus(union ccb*);
static __inline struct acb* adwgetacb(struct adw_softc *adw);
static __inline void adwfreeacb(struct adw_softc *adw,
struct acb *acb);
@@ -101,6 +102,12 @@ static void adw_handle_device_reset(struct adw_softc *adw,
static void adw_handle_bus_reset(struct adw_softc *adw,
int initiated);
+static __inline cam_status
+adwccbstatus(union ccb* ccb)
+{
+ return (ccb->ccb_h.status & CAM_STATUS_MASK);
+}
+
static __inline struct acb*
adwgetacb(struct adw_softc *adw)
{
@@ -324,7 +331,7 @@ adwexecuteacb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
splx(s);
return;
}
-
+
acb->state |= ACB_ACTIVE;
ccb->ccb_h.status |= CAM_SIM_QUEUED;
LIST_INSERT_HEAD(&adw->pending_ccbs, &ccb->ccb_h, sim_links.le);
@@ -393,7 +400,7 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
switch (csio->tag_action) {
case MSG_SIMPLE_Q_TAG:
- acb->queue.scsi_cntl = 0;
+ acb->queue.scsi_cntl = ADW_QSC_SIMPLE_Q_TAG;
break;
case MSG_HEAD_OF_Q_TAG:
acb->queue.scsi_cntl = ADW_QSC_HEAD_OF_Q_TAG;
@@ -401,6 +408,9 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
case MSG_ORDERED_Q_TAG:
acb->queue.scsi_cntl = ADW_QSC_ORDERED_Q_TAG;
break;
+ default:
+ acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
+ break;
}
} else
acb->queue.scsi_cntl = ADW_QSC_NO_TAGMSG;
@@ -498,9 +508,8 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
{
adw_idle_cmd_status_t status;
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
- ccb->ccb_h.target_id);
- status = adw_idle_cmd_wait(adw);
+ status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
+ ccb->ccb_h.target_id);
if (status == ADW_IDLE_CMD_SUCCESS) {
ccb->ccb_h.status = CAM_REQ_CMP;
if (bootverbose) {
@@ -748,28 +757,17 @@ adw_action(struct cam_sim *sim, union ccb *ccb)
}
case XPT_RESET_BUS: /* Reset the specified SCSI bus */
{
- adw_idle_cmd_status_t status;
+ int failure;
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
- /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS) {
+ failure = adw_reset_bus(adw);
+ if (failure != 0) {
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- xpt_done(ccb);
- break;
- }
- DELAY(100);
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS) {
- ccb->ccb_h.status = CAM_REQ_CMP_ERR;
- xpt_done(ccb);
- break;
- }
- ccb->ccb_h.status = CAM_REQ_CMP;
- if (bootverbose) {
- xpt_print_path(adw->path);
- printf("Bus Reset Delivered\n");
+ } else {
+ if (bootverbose) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset Delivered\n");
+ }
+ ccb->ccb_h.status = CAM_REQ_CMP;
}
xpt_done(ccb);
break;
@@ -1385,8 +1383,16 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
case QHSTA_M_UNEXPECTED_BUS_FREE:
ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
break;
+ case QHSTA_M_SCSI_BUS_RESET:
+ case QHSTA_M_SCSI_BUS_RESET_UNSOL:
+ ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
+ break;
+ case QHSTA_M_BUS_DEVICE_RESET:
+ ccb->ccb_h.status = CAM_BDR_SENT;
+ break;
case QHSTA_M_QUEUE_ABORTED:
/* BDR or Bus Reset */
+ printf("Saw Queue Aborted\n");
ccb->ccb_h.status = adw->last_reset;
break;
case QHSTA_M_SXFR_SDMA_ERR:
@@ -1397,23 +1403,10 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
case QHSTA_M_WTM_TIMEOUT:
case QHSTA_M_SXFR_WD_TMO:
{
- adw_idle_cmd_status_t status;
-
/* The SCSI bus hung in a phase */
- ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
- /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS)
- panic("%s: Bus Reset during WD timeout failed",
- adw_name(adw));
- DELAY(100);
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END,
- /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS)
- panic("%s: Bus Reset during WD timeout failed",
- adw_name(adw));
+ xpt_print_path(adw->path);
+ printf("Watch Dog timer expired. Reseting bus\n");
+ adw_reset_bus(adw);
break;
}
case QHSTA_M_SXFR_XFR_PH_ERR:
@@ -1445,6 +1438,11 @@ adwprocesserror(struct adw_softc *adw, struct acb *acb)
/* NOTREACHED */
}
}
+ if ((acb->state & ACB_RECOVERY_ACB) != 0) {
+ if (ccb->ccb_h.status == CAM_SCSI_BUS_RESET
+ || ccb->ccb_h.status == CAM_BDR_SENT)
+ ccb->ccb_h.status = CAM_CMD_TIMEOUT;
+ }
if (ccb->ccb_h.status != CAM_REQ_CMP) {
xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
ccb->ccb_h.status |= CAM_DEV_QFRZN;
@@ -1460,6 +1458,7 @@ adwtimeout(void *arg)
union ccb *ccb;
struct adw_softc *adw;
adw_idle_cmd_status_t status;
+ int target_id;
int s;
acb = (struct acb *)arg;
@@ -1478,29 +1477,21 @@ adwtimeout(void *arg)
return;
}
+ acb->state |= ACB_RECOVERY_ACB;
+ target_id = ccb->ccb_h.target_id;
+
/* Attempt a BDR first */
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
- ccb->ccb_h.target_id);
+ status = adw_idle_cmd_send(adw, ADW_IDLE_CMD_DEVICE_RESET,
+ ccb->ccb_h.target_id);
splx(s);
- status = adw_idle_cmd_wait(adw);
if (status == ADW_IDLE_CMD_SUCCESS) {
printf("%s: BDR Delivered. No longer in timeout\n",
adw_name(adw));
- adw_handle_device_reset(adw, ccb->ccb_h.target_id);
+ adw_handle_device_reset(adw, target_id);
} else {
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START,
- /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS)
- panic("%s: Bus Reset during timeout failed",
- adw_name(adw));
- DELAY(100);
- adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END,
- /*param*/0);
- status = adw_idle_cmd_wait(adw);
- if (status != ADW_IDLE_CMD_SUCCESS)
- panic("%s: Bus Reset during timeout failed",
- adw_name(adw));
+ adw_reset_bus(adw);
+ xpt_print_path(adw->path);
+ printf("Bus Reset Delivered. No longer in timeout\n");
}
}
diff --git a/sys/dev/advansys/adwlib.c b/sys/dev/advansys/adwlib.c
index bbce9f9..b829dec 100644
--- a/sys/dev/advansys/adwlib.c
+++ b/sys/dev/advansys/adwlib.c
@@ -190,6 +190,32 @@ adw_reset_chip(struct adw_softc *adw)
}
/*
+ * Reset the SCSI bus.
+ */
+int
+adw_reset_bus(struct adw_softc *adw)
+{
+ adw_idle_cmd_status_t status;
+
+ status =
+ adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_START, /*param*/0);
+ if (status != ADW_IDLE_CMD_SUCCESS) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset start attempt failed\n");
+ return (1);
+ }
+ DELAY(ADW_BUS_RESET_HOLD_DELAY_US);
+ status =
+ adw_idle_cmd_send(adw, ADW_IDLE_CMD_SCSI_RESET_END, /*param*/0);
+ if (status != ADW_IDLE_CMD_SUCCESS) {
+ xpt_print_path(adw->path);
+ printf("Bus Reset end attempt failed\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
* Read the specified EEPROM location
*/
static u_int16_t
@@ -818,22 +844,22 @@ adw_hshk_cfg_period_factor(u_int tinfo)
}
/*
- * Send an idle command to the chip and optionally wait for completion.
+ * Send an idle command to the chip and wait for completion.
*/
-void
+adw_idle_cmd_status_t
adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
{
- int s;
-
- adw->idle_command_cmp = 0;
+ u_int timeout;
+ adw_idle_cmd_status_t status;
+ int s;
s = splcam();
- if (adw->idle_cmd != ADW_IDLE_CMD_COMPLETED)
- printf("%s: Warning! Overlapped Idle Commands Attempted\n",
- adw_name(adw));
- adw->idle_cmd = cmd;
- adw->idle_cmd_param = parameter;
+ /*
+ * Clear the idle command status which is set by the microcode
+ * to a non-zero value to indicate when the command is completed.
+ */
+ adw_lram_write_16(adw, ADW_MC_IDLE_CMD_STATUS, 0);
/*
* Write the idle command value after the idle command parameter
@@ -841,37 +867,25 @@ adw_idle_cmd_send(struct adw_softc *adw, adw_idle_cmd_t cmd, u_int parameter)
* followed, the microcode may process the idle command before the
* parameters have been written to LRAM.
*/
- adw_lram_write_16(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter);
+ adw_lram_write_32(adw, ADW_MC_IDLE_CMD_PARAMETER, parameter);
adw_lram_write_16(adw, ADW_MC_IDLE_CMD, cmd);
/*
* Tickle the RISC to tell it to process the idle command.
*/
adw_tickle_risc(adw, ADW_TICKLE_B);
- splx(s);
-}
-
-/* Wait for an idle command to complete */
-adw_idle_cmd_status_t
-adw_idle_cmd_wait(struct adw_softc *adw)
-{
- u_int timeout;
- adw_idle_cmd_status_t status;
- int s;
/* Wait for up to 10 seconds for the command to complete */
- timeout = 10000;
+ timeout = 5000000;
while (--timeout) {
- s = splcam();
status = adw_lram_read_16(adw, ADW_MC_IDLE_CMD_STATUS);
- splx(s);
if (status != 0)
break;
- DELAY(1000);
+ DELAY(20);
}
if (timeout == 0)
panic("%s: Idle Command Timed Out!\n", adw_name(adw));
- adw->idle_cmd = ADW_IDLE_CMD_COMPLETED;
+ splx(s);
return (status);
}
diff --git a/sys/dev/advansys/adwlib.h b/sys/dev/advansys/adwlib.h
index d32bfb9..c470c10 100644
--- a/sys/dev/advansys/adwlib.h
+++ b/sys/dev/advansys/adwlib.h
@@ -342,11 +342,18 @@ typedef enum {
QHSTA_M_SXFR_DESELECTED = 0x22, /* Deselected */
QHSTA_M_SXFR_XFR_PH_ERR = 0x24, /* Transfer Phase Error */
QHSTA_M_SXFR_UNKNOWN_ERROR = 0x25, /* SXFR_STATUS Unknown Error */
+ QHSTA_M_SCSI_BUS_RESET = 0x30, /* Request aborted from SBR */
+ QHSTA_M_SCSI_BUS_RESET_UNSOL= 0x31, /* Request aborted from unsol. SBR*/
+ QHSTA_M_BUS_DEVICE_RESET = 0x32, /* Request aborted from BDR */
+ QHSTA_M_DIRECTION_ERR = 0x35, /* Data Phase mismatch */
+ QHSTA_M_DIRECTION_ERR_HUNG = 0x36, /* Data Phase mismatch - bus hang */
QHSTA_M_WTM_TIMEOUT = 0x41,
QHSTA_M_BAD_CMPL_STATUS_IN = 0x42,
QHSTA_M_NO_AUTO_REQ_SENSE = 0x43,
QHSTA_M_AUTO_REQ_SENSE_FAIL = 0x44,
- QHSTA_M_INVALID_DEVICE = 0x45 /* Bad target ID */
+ QHSTA_M_INVALID_DEVICE = 0x45, /* Bad target ID */
+ QHSTA_M_FROZEN_TIDQ = 0x46, /* TID Queue frozen. */
+ QHSTA_M_SGBACKUP_ERROR = 0x47 /* Scatter-Gather backup error */
} host_status_t;
typedef enum {
@@ -380,6 +387,7 @@ struct adw_scsi_req_q {
#define ADW_QSC_NO_SYNC 0x04
#define ADW_QSC_NO_WIDE 0x08
#define ADW_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR */
+#define ADW_QSC_SIMPLE_Q_TAG 0x00
#define ADW_QSC_HEAD_OF_Q_TAG 0x40
#define ADW_QSC_ORDERED_Q_TAG 0x80
u_int8_t done_status; /* Completion status. */
@@ -405,7 +413,8 @@ struct adw_scsi_req_q {
typedef enum {
ACB_FREE = 0x00,
ACB_ACTIVE = 0x01,
- ACB_RELEASE_SIMQ = 0x02
+ ACB_RELEASE_SIMQ = 0x02,
+ ACB_RECOVERY_ACB = 0x04
} acb_state;
struct acb {
@@ -542,6 +551,8 @@ struct adw_eeprom
#define ADW_EEP_DVC_CTL_BEGIN (offsetof(struct adw_eeprom, oem_name)/2)
#define ADW_EEP_MAX_WORD_ADDR (sizeof(struct adw_eeprom)/2)
+#define ADW_BUS_RESET_HOLD_DELAY_US 100
+
typedef enum {
ADW_CHIP_NONE,
ADW_CHIP_ASC3550, /* Ultra-Wide IC */
@@ -636,9 +647,6 @@ struct adw_softc
char* name;
cam_status last_reset; /* Last reset type */
u_int16_t bios_ctrl;
- adw_idle_cmd_t idle_cmd;
- u_int idle_cmd_param;
- volatile int idle_command_cmp;
u_int16_t user_wdtr;
u_int16_t user_sdtr[4]; /* A nibble per-device */
u_int16_t user_tagenb;
@@ -806,6 +814,7 @@ carrierbtov(struct adw_softc *adw, u_int32_t baddr)
/* Intialization */
int adw_find_signature(struct adw_softc *adw);
void adw_reset_chip(struct adw_softc *adw);
+int adw_reset_bus(struct adw_softc *adw);
u_int16_t adw_eeprom_read(struct adw_softc *adw, struct adw_eeprom *buf);
void adw_eeprom_write(struct adw_softc *adw, struct adw_eeprom *buf);
int adw_init_chip(struct adw_softc *adw, u_int term_scsicfg1);
@@ -819,9 +828,8 @@ u_int adw_find_period(struct adw_softc *adw, u_int mc_sdtr);
u_int adw_hshk_cfg_period_factor(u_int tinfo);
/* Idle Commands */
-void adw_idle_cmd_send(struct adw_softc *adw, u_int cmd,
+adw_idle_cmd_status_t adw_idle_cmd_send(struct adw_softc *adw, u_int cmd,
u_int parameter);
-adw_idle_cmd_status_t adw_idle_cmd_wait(struct adw_softc *adw);
/* SCSI Transaction Processing */
static __inline void adw_send_acb(struct adw_softc *adw, struct acb *acb,
OpenPOWER on IntegriCloud