aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHannes Reinecke <hare@suse.de>2006-03-08 06:58:16 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-03-12 10:05:18 -0500
commit6902f41610d631f74cfca7c61eac7b0950dd8990 (patch)
treeee084da4fdd3fff54982e79034ee2a284c57cc3c
parent1ede5f9fe59ea245ad0ba859cfb08ac5814f6269 (diff)
[SCSI] aic79xx: Update error recovery
This patch updates the error recovery. Routines for TARGET RESET and ABORT COMMAND are split up as the logic is quite dissimilar. Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c325
1 files changed, 201 insertions, 124 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index cb5f7af606ed..00d48a0fb7e1 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -373,7 +373,7 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *,
373 struct scb *); 373 struct scb *);
374static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, 374static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
375 struct scsi_cmnd *cmd); 375 struct scsi_cmnd *cmd);
376static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); 376static int ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd);
377static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); 377static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
378static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, 378static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,
379 struct ahd_devinfo *devinfo); 379 struct ahd_devinfo *devinfo);
@@ -648,10 +648,9 @@ static int
648ahd_linux_abort(struct scsi_cmnd *cmd) 648ahd_linux_abort(struct scsi_cmnd *cmd)
649{ 649{
650 int error; 650 int error;
651
652 error = ahd_linux_queue_abort_cmd(cmd);
651 653
652 error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT);
653 if (error != 0)
654 printf("aic79xx_abort returns 0x%x\n", error);
655 return error; 654 return error;
656} 655}
657 656
@@ -661,12 +660,97 @@ ahd_linux_abort(struct scsi_cmnd *cmd)
661static int 660static int
662ahd_linux_dev_reset(struct scsi_cmnd *cmd) 661ahd_linux_dev_reset(struct scsi_cmnd *cmd)
663{ 662{
664 int error; 663 struct ahd_softc *ahd;
664 struct ahd_linux_device *dev;
665 struct scb *reset_scb;
666 u_int cdb_byte;
667 int retval = SUCCESS;
668 int paused;
669 int wait;
670 struct ahd_initiator_tinfo *tinfo;
671 struct ahd_tmode_tstate *tstate;
672 unsigned long flags;
673 DECLARE_COMPLETION(done);
665 674
666 error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); 675 reset_scb = NULL;
667 if (error != 0) 676 paused = FALSE;
668 printf("aic79xx_dev_reset returns 0x%x\n", error); 677 wait = FALSE;
669 return error; 678 ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
679
680 scmd_printk(KERN_INFO, cmd,
681 "Attempting to queue a TARGET RESET message:");
682
683 printf("CDB:");
684 for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
685 printf(" 0x%x", cmd->cmnd[cdb_byte]);
686 printf("\n");
687
688 /*
689 * Determine if we currently own this command.
690 */
691 dev = scsi_transport_device_data(cmd->device);
692
693 if (dev == NULL) {
694 /*
695 * No target device for this command exists,
696 * so we must not still own the command.
697 */
698 scmd_printk(KERN_INFO, cmd, "Is not an active device\n");
699 return SUCCESS;
700 }
701
702 /*
703 * Generate us a new SCB
704 */
705 reset_scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX);
706 if (!reset_scb) {
707 scmd_printk(KERN_INFO, cmd, "No SCB available\n");
708 return FAILED;
709 }
710
711 tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
712 cmd->device->id, &tstate);
713 reset_scb->io_ctx = cmd;
714 reset_scb->platform_data->dev = dev;
715 reset_scb->sg_count = 0;
716 ahd_set_residual(reset_scb, 0);
717 ahd_set_sense_residual(reset_scb, 0);
718 reset_scb->platform_data->xfer_len = 0;
719 reset_scb->hscb->control = 0;
720 reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd);
721 reset_scb->hscb->lun = cmd->device->lun;
722 reset_scb->hscb->cdb_len = 0;
723 reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET;
724 reset_scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;
725 if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
726 reset_scb->flags |= SCB_PACKETIZED;
727 } else {
728 reset_scb->hscb->control |= MK_MESSAGE;
729 }
730 dev->openings--;
731 dev->active++;
732 dev->commands_issued++;
733
734 ahd_lock(ahd, &flags);
735
736 LIST_INSERT_HEAD(&ahd->pending_scbs, reset_scb, pending_links);
737 ahd_queue_scb(ahd, reset_scb);
738
739 ahd->platform_data->eh_done = &done;
740 ahd_unlock(ahd, &flags);
741
742 printf("%s: Device reset code sleeping\n", ahd_name(ahd));
743 if (!wait_for_completion_timeout(&done, 5 * HZ)) {
744 ahd_lock(ahd, &flags);
745 ahd->platform_data->eh_done = NULL;
746 ahd_unlock(ahd, &flags);
747 printf("%s: Device reset timer expired (active %d)\n",
748 ahd_name(ahd), dev->active);
749 retval = FAILED;
750 }
751 printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
752
753 return (retval);
670} 754}
671 755
672/* 756/*
@@ -1891,72 +1975,108 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
1891static void 1975static void
1892ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) 1976ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
1893{ 1977{
1978 int status;
1979 int new_status = DID_OK;
1980 int do_fallback = 0;
1981 int scsi_status;
1982
1894 /* 1983 /*
1895 * Map CAM error codes into Linux Error codes. We 1984 * Map CAM error codes into Linux Error codes. We
1896 * avoid the conversion so that the DV code has the 1985 * avoid the conversion so that the DV code has the
1897 * full error information available when making 1986 * full error information available when making
1898 * state change decisions. 1987 * state change decisions.
1899 */ 1988 */
1900 { 1989
1901 uint32_t status; 1990 status = ahd_cmd_get_transaction_status(cmd);
1902 u_int new_status; 1991 switch (status) {
1903 1992 case CAM_REQ_INPROG:
1904 status = ahd_cmd_get_transaction_status(cmd); 1993 case CAM_REQ_CMP:
1905 switch (status) { 1994 new_status = DID_OK;
1906 case CAM_REQ_INPROG: 1995 break;
1907 case CAM_REQ_CMP: 1996 case CAM_AUTOSENSE_FAIL:
1908 case CAM_SCSI_STATUS_ERROR: 1997 new_status = DID_ERROR;
1909 new_status = DID_OK; 1998 /* Fallthrough */
1910 break; 1999 case CAM_SCSI_STATUS_ERROR:
1911 case CAM_REQ_ABORTED: 2000 scsi_status = ahd_cmd_get_scsi_status(cmd);
1912 new_status = DID_ABORT; 2001
1913 break; 2002 switch(scsi_status) {
1914 case CAM_BUSY: 2003 case SCSI_STATUS_CMD_TERMINATED:
1915 new_status = DID_BUS_BUSY; 2004 case SCSI_STATUS_CHECK_COND:
1916 break; 2005 if ((cmd->result >> 24) != DRIVER_SENSE) {
1917 case CAM_REQ_INVALID: 2006 do_fallback = 1;
1918 case CAM_PATH_INVALID: 2007 } else {
1919 new_status = DID_BAD_TARGET; 2008 struct scsi_sense_data *sense;
1920 break; 2009
1921 case CAM_SEL_TIMEOUT: 2010 sense = (struct scsi_sense_data *)
1922 new_status = DID_NO_CONNECT; 2011 &cmd->sense_buffer;
1923 break; 2012 if (sense->extra_len >= 5 &&
1924 case CAM_SCSI_BUS_RESET: 2013 (sense->add_sense_code == 0x47
1925 case CAM_BDR_SENT: 2014 || sense->add_sense_code == 0x48))
1926 new_status = DID_RESET; 2015 do_fallback = 1;
1927 break; 2016 }
1928 case CAM_UNCOR_PARITY:
1929 new_status = DID_PARITY;
1930 break;
1931 case CAM_CMD_TIMEOUT:
1932 new_status = DID_TIME_OUT;
1933 break;
1934 case CAM_UA_ABORT:
1935 case CAM_REQ_CMP_ERR:
1936 case CAM_AUTOSENSE_FAIL:
1937 case CAM_NO_HBA:
1938 case CAM_DATA_RUN_ERR:
1939 case CAM_UNEXP_BUSFREE:
1940 case CAM_SEQUENCE_FAIL:
1941 case CAM_CCB_LEN_ERR:
1942 case CAM_PROVIDE_FAIL:
1943 case CAM_REQ_TERMIO:
1944 case CAM_UNREC_HBA_ERROR:
1945 case CAM_REQ_TOO_BIG:
1946 new_status = DID_ERROR;
1947 break;
1948 case CAM_REQUEUE_REQ:
1949 new_status = DID_REQUEUE;
1950 break; 2017 break;
1951 default: 2018 default:
1952 /* We should never get here */
1953 new_status = DID_ERROR;
1954 break; 2019 break;
1955 } 2020 }
2021 break;
2022 case CAM_REQ_ABORTED:
2023 new_status = DID_ABORT;
2024 break;
2025 case CAM_BUSY:
2026 new_status = DID_BUS_BUSY;
2027 break;
2028 case CAM_REQ_INVALID:
2029 case CAM_PATH_INVALID:
2030 new_status = DID_BAD_TARGET;
2031 break;
2032 case CAM_SEL_TIMEOUT:
2033 new_status = DID_NO_CONNECT;
2034 break;
2035 case CAM_SCSI_BUS_RESET:
2036 case CAM_BDR_SENT:
2037 new_status = DID_RESET;
2038 break;
2039 case CAM_UNCOR_PARITY:
2040 new_status = DID_PARITY;
2041 do_fallback = 1;
2042 break;
2043 case CAM_CMD_TIMEOUT:
2044 new_status = DID_TIME_OUT;
2045 do_fallback = 1;
2046 break;
2047 case CAM_REQ_CMP_ERR:
2048 case CAM_UNEXP_BUSFREE:
2049 case CAM_DATA_RUN_ERR:
2050 new_status = DID_ERROR;
2051 do_fallback = 1;
2052 break;
2053 case CAM_UA_ABORT:
2054 case CAM_NO_HBA:
2055 case CAM_SEQUENCE_FAIL:
2056 case CAM_CCB_LEN_ERR:
2057 case CAM_PROVIDE_FAIL:
2058 case CAM_REQ_TERMIO:
2059 case CAM_UNREC_HBA_ERROR:
2060 case CAM_REQ_TOO_BIG:
2061 new_status = DID_ERROR;
2062 break;
2063 case CAM_REQUEUE_REQ:
2064 new_status = DID_REQUEUE;
2065 break;
2066 default:
2067 /* We should never get here */
2068 new_status = DID_ERROR;
2069 break;
2070 }
1956 2071
1957 ahd_cmd_set_transaction_status(cmd, new_status); 2072 if (do_fallback) {
2073 printf("%s: device overrun (status %x) on %d:%d:%d\n",
2074 ahd_name(ahd), status, cmd->device->channel,
2075 cmd->device->id, cmd->device->lun);
1958 } 2076 }
1959 2077
2078 ahd_cmd_set_transaction_status(cmd, new_status);
2079
1960 cmd->scsi_done(cmd); 2080 cmd->scsi_done(cmd);
1961} 2081}
1962 2082
@@ -1973,7 +2093,7 @@ ahd_release_simq(struct ahd_softc *ahd)
1973} 2093}
1974 2094
1975static int 2095static int
1976ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) 2096ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd)
1977{ 2097{
1978 struct ahd_softc *ahd; 2098 struct ahd_softc *ahd;
1979 struct ahd_linux_device *dev; 2099 struct ahd_linux_device *dev;
@@ -1988,7 +2108,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
1988 int paused; 2108 int paused;
1989 int wait; 2109 int wait;
1990 int disconnected; 2110 int disconnected;
1991 int found;
1992 ahd_mode_state saved_modes; 2111 ahd_mode_state saved_modes;
1993 unsigned long flags; 2112 unsigned long flags;
1994 2113
@@ -1998,8 +2117,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
1998 ahd = *(struct ahd_softc **)cmd->device->host->hostdata; 2117 ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
1999 2118
2000 scmd_printk(KERN_INFO, cmd, 2119 scmd_printk(KERN_INFO, cmd,
2001 "Attempting to queue a%s message:", 2120 "Attempting to queue an ABORT message:");
2002 flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
2003 2121
2004 printf("CDB:"); 2122 printf("CDB:");
2005 for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) 2123 for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
@@ -2035,19 +2153,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2035 break; 2153 break;
2036 } 2154 }
2037 2155
2038 if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {
2039
2040 /* Any SCB for this device will do for a target reset */
2041 LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
2042 if (ahd_match_scb(ahd, pending_scb,
2043 scmd_id(cmd),
2044 scmd_channel(cmd) + 'A',
2045 CAM_LUN_WILDCARD,
2046 SCB_LIST_NULL, ROLE_INITIATOR))
2047 break;
2048 }
2049 }
2050
2051 if (pending_scb == NULL) { 2156 if (pending_scb == NULL) {
2052 scmd_printk(KERN_INFO, cmd, "Command not found\n"); 2157 scmd_printk(KERN_INFO, cmd, "Command not found\n");
2053 goto no_cmd; 2158 goto no_cmd;
@@ -2081,25 +2186,17 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2081 ahd_dump_card_state(ahd); 2186 ahd_dump_card_state(ahd);
2082 2187
2083 disconnected = TRUE; 2188 disconnected = TRUE;
2084 if (flag == SCB_ABORT) { 2189 if (ahd_search_qinfifo(ahd, cmd->device->id,
2085 if (ahd_search_qinfifo(ahd, cmd->device->id, 2190 cmd->device->channel + 'A',
2086 cmd->device->channel + 'A', 2191 cmd->device->lun,
2087 cmd->device->lun, 2192 pending_scb->hscb->tag,
2088 pending_scb->hscb->tag, 2193 ROLE_INITIATOR, CAM_REQ_ABORTED,
2089 ROLE_INITIATOR, CAM_REQ_ABORTED, 2194 SEARCH_COMPLETE) > 0) {
2090 SEARCH_COMPLETE) > 0) { 2195 printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
2091 printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", 2196 ahd_name(ahd), cmd->device->channel,
2092 ahd_name(ahd), cmd->device->channel, 2197 cmd->device->id, cmd->device->lun);
2093 cmd->device->id, cmd->device->lun); 2198 retval = SUCCESS;
2094 retval = SUCCESS; 2199 goto done;
2095 goto done;
2096 }
2097 } else if (ahd_search_qinfifo(ahd, cmd->device->id,
2098 cmd->device->channel + 'A',
2099 cmd->device->lun, pending_scb->hscb->tag,
2100 ROLE_INITIATOR, /*status*/0,
2101 SEARCH_COUNT) > 0) {
2102 disconnected = FALSE;
2103 } 2200 }
2104 2201
2105 saved_modes = ahd_save_modes(ahd); 2202 saved_modes = ahd_save_modes(ahd);
@@ -2107,17 +2204,12 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2107 last_phase = ahd_inb(ahd, LASTPHASE); 2204 last_phase = ahd_inb(ahd, LASTPHASE);
2108 saved_scbptr = ahd_get_scbptr(ahd); 2205 saved_scbptr = ahd_get_scbptr(ahd);
2109 active_scbptr = saved_scbptr; 2206 active_scbptr = saved_scbptr;
2110 if (disconnected && ((last_phase != P_BUSFREE) || 2207 if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
2111 (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0)) {
2112 struct scb *bus_scb; 2208 struct scb *bus_scb;
2113 2209
2114 bus_scb = ahd_lookup_scb(ahd, active_scbptr); 2210 bus_scb = ahd_lookup_scb(ahd, active_scbptr);
2115 if (bus_scb == pending_scb) 2211 if (bus_scb == pending_scb)
2116 disconnected = FALSE; 2212 disconnected = FALSE;
2117 else if (flag != SCB_ABORT
2118 && ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid
2119 && ahd_inb(ahd, SAVED_LUN) == SCB_GET_LUN(pending_scb))
2120 disconnected = FALSE;
2121 } 2213 }
2122 2214
2123 /* 2215 /*
@@ -2126,41 +2218,26 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2126 * bus or is in the disconnected state. 2218 * bus or is in the disconnected state.
2127 */ 2219 */
2128 saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 2220 saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
2129 if (SCB_GET_TAG(pending_scb) == active_scbptr 2221 if (last_phase != P_BUSFREE
2130 || (flag == SCB_DEVICE_RESET 2222 && SCB_GET_TAG(pending_scb) == active_scbptr) {
2131 && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd))) {
2132 2223
2133 /* 2224 /*
2134 * We're active on the bus, so assert ATN 2225 * We're active on the bus, so assert ATN
2135 * and hope that the target responds. 2226 * and hope that the target responds.
2136 */ 2227 */
2137 pending_scb = ahd_lookup_scb(ahd, active_scbptr); 2228 pending_scb = ahd_lookup_scb(ahd, active_scbptr);
2138 pending_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET; 2229 pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
2139 ahd_outb(ahd, MSG_OUT, HOST_MSG); 2230 ahd_outb(ahd, MSG_OUT, HOST_MSG);
2140 ahd_outb(ahd, SCSISIGO, last_phase|ATNO); 2231 ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
2141 scmd_printk(KERN_INFO, cmd, "BDR message in message buffer\n"); 2232 scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n");
2142 wait = TRUE; 2233 wait = TRUE;
2143 } else if (last_phase != P_BUSFREE
2144 && ahd_inb(ahd, SCSIPHASE) == 0) {
2145 /*
2146 * SCB is not identified, there
2147 * is no pending REQ, and the sequencer
2148 * has not seen a busfree. Looks like
2149 * a stuck connection waiting to
2150 * go busfree. Reset the bus.
2151 */
2152 found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
2153 /*Initiate Reset*/TRUE);
2154 printf("%s: Issued Channel %c Bus Reset. "
2155 "%d SCBs aborted\n", ahd_name(ahd),
2156 cmd->device->channel + 'A', found);
2157 } else if (disconnected) { 2234 } else if (disconnected) {
2158 2235
2159 /* 2236 /*
2160 * Actually re-queue this SCB in an attempt 2237 * Actually re-queue this SCB in an attempt
2161 * to select the device before it reconnects. 2238 * to select the device before it reconnects.
2162 */ 2239 */
2163 pending_scb->flags |= SCB_RECOVERY_SCB|flag; 2240 pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
2164 ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); 2241 ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
2165 pending_scb->hscb->cdb_len = 0; 2242 pending_scb->hscb->cdb_len = 0;
2166 pending_scb->hscb->task_attribute = 0; 2243 pending_scb->hscb->task_attribute = 0;