diff options
-rw-r--r-- | sys/dev/advansys/adv_pci.c | 17 | ||||
-rw-r--r-- | sys/dev/advansys/adw_pci.c | 2 | ||||
-rw-r--r-- | sys/dev/advansys/adwcam.c | 107 | ||||
-rw-r--r-- | sys/dev/advansys/adwlib.c | 66 | ||||
-rw-r--r-- | sys/dev/advansys/adwlib.h | 22 |
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, |