aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c66
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);