diff options
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_core.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 4c2b5a817111..07a86a30f676 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c | |||
@@ -1154,10 +1154,12 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) | |||
1154 | * If a target takes us into the command phase | 1154 | * If a target takes us into the command phase |
1155 | * assume that it has been externally reset and | 1155 | * assume that it has been externally reset and |
1156 | * has thus lost our previous packetized negotiation | 1156 | * has thus lost our previous packetized negotiation |
1157 | * agreement. | 1157 | * agreement. Since we have not sent an identify |
1158 | * Revert to async/narrow transfers until we | 1158 | * message and may not have fully qualified the |
1159 | * can renegotiate with the device and notify | 1159 | * connection, we change our command to TUR, assert |
1160 | * the OSM about the reset. | 1160 | * ATN and ABORT the task when we go to message in |
1161 | * phase. The OSM will see the REQUEUE_REQUEST | ||
1162 | * status and retry the command. | ||
1161 | */ | 1163 | */ |
1162 | scbid = ahd_get_scbptr(ahd); | 1164 | scbid = ahd_get_scbptr(ahd); |
1163 | scb = ahd_lookup_scb(ahd, scbid); | 1165 | scb = ahd_lookup_scb(ahd, scbid); |
@@ -1184,7 +1186,28 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) | |||
1184 | ahd_set_syncrate(ahd, &devinfo, /*period*/0, | 1186 | ahd_set_syncrate(ahd, &devinfo, /*period*/0, |
1185 | /*offset*/0, /*ppr_options*/0, | 1187 | /*offset*/0, /*ppr_options*/0, |
1186 | AHD_TRANS_ACTIVE, /*paused*/TRUE); | 1188 | AHD_TRANS_ACTIVE, /*paused*/TRUE); |
1187 | scb->flags |= SCB_EXTERNAL_RESET; | 1189 | /* Hand-craft TUR command */ |
1190 | ahd_outb(ahd, SCB_CDB_STORE, 0); | ||
1191 | ahd_outb(ahd, SCB_CDB_STORE+1, 0); | ||
1192 | ahd_outb(ahd, SCB_CDB_STORE+2, 0); | ||
1193 | ahd_outb(ahd, SCB_CDB_STORE+3, 0); | ||
1194 | ahd_outb(ahd, SCB_CDB_STORE+4, 0); | ||
1195 | ahd_outb(ahd, SCB_CDB_STORE+5, 0); | ||
1196 | ahd_outb(ahd, SCB_CDB_LEN, 6); | ||
1197 | scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); | ||
1198 | scb->hscb->control |= MK_MESSAGE; | ||
1199 | ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); | ||
1200 | ahd_outb(ahd, MSG_OUT, HOST_MSG); | ||
1201 | ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); | ||
1202 | /* | ||
1203 | * The lun is 0, regardless of the SCB's lun | ||
1204 | * as we have not sent an identify message. | ||
1205 | */ | ||
1206 | ahd_outb(ahd, SAVED_LUN, 0); | ||
1207 | ahd_outb(ahd, SEQ_FLAGS, 0); | ||
1208 | ahd_assert_atn(ahd); | ||
1209 | scb->flags &= ~SCB_PACKETIZED; | ||
1210 | scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET; | ||
1188 | ahd_freeze_devq(ahd, scb); | 1211 | ahd_freeze_devq(ahd, scb); |
1189 | ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); | 1212 | ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); |
1190 | ahd_freeze_scb(scb); | 1213 | ahd_freeze_scb(scb); |
@@ -1620,8 +1643,10 @@ ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) | |||
1620 | /* | 1643 | /* |
1621 | * Ignore external resets after a bus reset. | 1644 | * Ignore external resets after a bus reset. |
1622 | */ | 1645 | */ |
1623 | if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) | 1646 | if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) { |
1647 | ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); | ||
1624 | return; | 1648 | return; |
1649 | } | ||
1625 | 1650 | ||
1626 | /* | 1651 | /* |
1627 | * Clear bus reset flag | 1652 | * Clear bus reset flag |
@@ -2301,6 +2326,22 @@ ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) | |||
2301 | if (sent_msg == MSG_ABORT_TAG) | 2326 | if (sent_msg == MSG_ABORT_TAG) |
2302 | tag = SCB_GET_TAG(scb); | 2327 | tag = SCB_GET_TAG(scb); |
2303 | 2328 | ||
2329 | if ((scb->flags & SCB_EXTERNAL_RESET) != 0) { | ||
2330 | /* | ||
2331 | * This abort is in response to an | ||
2332 | * unexpected switch to command phase | ||
2333 | * for a packetized connection. Since | ||
2334 | * the identify message was never sent, | ||
2335 | * "saved lun" is 0. We really want to | ||
2336 | * abort only the SCB that encountered | ||
2337 | * this error, which could have a different | ||
2338 | * lun. The SCB will be retried so the OS | ||
2339 | * will see the UA after renegotiating to | ||
2340 | * packetized. | ||
2341 | */ | ||
2342 | tag = SCB_GET_TAG(scb); | ||
2343 | saved_lun = scb->hscb->lun; | ||
2344 | } | ||
2304 | found = ahd_abort_scbs(ahd, target, 'A', saved_lun, | 2345 | found = ahd_abort_scbs(ahd, target, 'A', saved_lun, |
2305 | tag, ROLE_INITIATOR, | 2346 | tag, ROLE_INITIATOR, |
2306 | CAM_REQ_ABORTED); | 2347 | CAM_REQ_ABORTED); |
@@ -7985,6 +8026,11 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) | |||
7985 | ahd_clear_fifo(ahd, 1); | 8026 | ahd_clear_fifo(ahd, 1); |
7986 | 8027 | ||
7987 | /* | 8028 | /* |
8029 | * Clear SCSI interrupt status | ||
8030 | */ | ||
8031 | ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); | ||
8032 | |||
8033 | /* | ||
7988 | * Reenable selections | 8034 | * Reenable selections |
7989 | */ | 8035 | */ |
7990 | ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); | 8036 | ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); |
@@ -8017,10 +8063,6 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) | |||
8017 | } | 8063 | } |
8018 | } | 8064 | } |
8019 | #endif | 8065 | #endif |
8020 | /* Notify the XPT that a bus reset occurred */ | ||
8021 | ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, | ||
8022 | CAM_LUN_WILDCARD, AC_BUS_RESET); | ||
8023 | |||
8024 | /* | 8066 | /* |
8025 | * Revert to async/narrow transfers until we renegotiate. | 8067 | * Revert to async/narrow transfers until we renegotiate. |
8026 | */ | 8068 | */ |
@@ -8042,6 +8084,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) | |||
8042 | } | 8084 | } |
8043 | } | 8085 | } |
8044 | 8086 | ||
8087 | /* Notify the XPT that a bus reset occurred */ | ||
8088 | ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, | ||
8089 | CAM_LUN_WILDCARD, AC_BUS_RESET); | ||
8090 | |||
8045 | ahd_restart(ahd); | 8091 | ahd_restart(ahd); |
8046 | 8092 | ||
8047 | return (found); | 8093 | return (found); |