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); |
