aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic7xxx/aic79xx_osm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aic7xxx/aic79xx_osm.c')
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c62
1 files changed, 51 insertions, 11 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 1c8f872e2dd4..2567e29960bd 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1468,6 +1468,30 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
1468 if ((tstate->auto_negotiate & mask) != 0) { 1468 if ((tstate->auto_negotiate & mask) != 0) {
1469 scb->flags |= SCB_AUTO_NEGOTIATE; 1469 scb->flags |= SCB_AUTO_NEGOTIATE;
1470 scb->hscb->control |= MK_MESSAGE; 1470 scb->hscb->control |= MK_MESSAGE;
1471 } else if (cmd->cmnd[0] == INQUIRY
1472 && (tinfo->curr.offset != 0
1473 || tinfo->curr.width != MSG_EXT_WDTR_BUS_8_BIT
1474 || tinfo->curr.ppr_options != 0)
1475 && (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)==0) {
1476 /*
1477 * The SCSI spec requires inquiry
1478 * commands to complete without
1479 * reporting unit attention conditions.
1480 * Because of this, an inquiry command
1481 * that occurs just after a device is
1482 * reset will result in a data phase
1483 * with mismatched negotiated rates.
1484 * The core already forces a renegotiation
1485 * for reset events that are visible to
1486 * our controller or that we initiate,
1487 * but a third party device reset or a
1488 * hot-plug insertion can still cause this
1489 * issue. Therefore, we force a re-negotiation
1490 * for every inquiry command unless we
1491 * are async.
1492 */
1493 scb->flags |= SCB_NEGOTIATE;
1494 scb->hscb->control |= MK_MESSAGE;
1471 } 1495 }
1472 1496
1473 if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { 1497 if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
@@ -2058,6 +2082,7 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2058 int paused; 2082 int paused;
2059 int wait; 2083 int wait;
2060 int disconnected; 2084 int disconnected;
2085 int found;
2061 ahd_mode_state saved_modes; 2086 ahd_mode_state saved_modes;
2062 unsigned long flags; 2087 unsigned long flags;
2063 2088
@@ -2176,7 +2201,8 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2176 last_phase = ahd_inb(ahd, LASTPHASE); 2201 last_phase = ahd_inb(ahd, LASTPHASE);
2177 saved_scbptr = ahd_get_scbptr(ahd); 2202 saved_scbptr = ahd_get_scbptr(ahd);
2178 active_scbptr = saved_scbptr; 2203 active_scbptr = saved_scbptr;
2179 if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { 2204 if (disconnected && ((last_phase != P_BUSFREE) ||
2205 (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0)) {
2180 struct scb *bus_scb; 2206 struct scb *bus_scb;
2181 2207
2182 bus_scb = ahd_lookup_scb(ahd, active_scbptr); 2208 bus_scb = ahd_lookup_scb(ahd, active_scbptr);
@@ -2194,28 +2220,41 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
2194 * bus or is in the disconnected state. 2220 * bus or is in the disconnected state.
2195 */ 2221 */
2196 saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); 2222 saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
2197 if (last_phase != P_BUSFREE 2223 if (SCB_GET_TAG(pending_scb) == active_scbptr
2198 && (SCB_GET_TAG(pending_scb) == active_scbptr
2199 || (flag == SCB_DEVICE_RESET 2224 || (flag == SCB_DEVICE_RESET
2200 && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd)))) { 2225 && SCSIID_TARGET(ahd, saved_scsiid) == scmd_id(cmd))) {
2201 2226
2202 /* 2227 /*
2203 * We're active on the bus, so assert ATN 2228 * We're active on the bus, so assert ATN
2204 * and hope that the target responds. 2229 * and hope that the target responds.
2205 */ 2230 */
2206 pending_scb = ahd_lookup_scb(ahd, active_scbptr); 2231 pending_scb = ahd_lookup_scb(ahd, active_scbptr);
2207 pending_scb->flags |= SCB_RECOVERY_SCB|flag; 2232 pending_scb->flags |= SCB_RECOVERY_SCB|SCB_DEVICE_RESET;
2208 ahd_outb(ahd, MSG_OUT, HOST_MSG); 2233 ahd_outb(ahd, MSG_OUT, HOST_MSG);
2209 ahd_outb(ahd, SCSISIGO, last_phase|ATNO); 2234 ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
2210 scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n"); 2235 scmd_printk(KERN_INFO, cmd, "BDR message in message buffer\n");
2211 wait = TRUE; 2236 wait = TRUE;
2237 } else if (last_phase != P_BUSFREE
2238 && ahd_inb(ahd, SCSIPHASE) == 0) {
2239 /*
2240 * SCB is not identified, there
2241 * is no pending REQ, and the sequencer
2242 * has not seen a busfree. Looks like
2243 * a stuck connection waiting to
2244 * go busfree. Reset the bus.
2245 */
2246 found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
2247 /*Initiate Reset*/TRUE);
2248 printf("%s: Issued Channel %c Bus Reset. "
2249 "%d SCBs aborted\n", ahd_name(ahd),
2250 cmd->device->channel + 'A', found);
2212 } else if (disconnected) { 2251 } else if (disconnected) {
2213 2252
2214 /* 2253 /*
2215 * Actually re-queue this SCB in an attempt 2254 * Actually re-queue this SCB in an attempt
2216 * to select the device before it reconnects. 2255 * to select the device before it reconnects.
2217 */ 2256 */
2218 pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; 2257 pending_scb->flags |= SCB_RECOVERY_SCB|flag;
2219 ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); 2258 ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
2220 pending_scb->hscb->cdb_len = 0; 2259 pending_scb->hscb->cdb_len = 0;
2221 pending_scb->hscb->task_attribute = 0; 2260 pending_scb->hscb->task_attribute = 0;
@@ -2296,16 +2335,17 @@ done:
2296 timer.expires = jiffies + (5 * HZ); 2335 timer.expires = jiffies + (5 * HZ);
2297 timer.function = ahd_linux_sem_timeout; 2336 timer.function = ahd_linux_sem_timeout;
2298 add_timer(&timer); 2337 add_timer(&timer);
2299 printf("Recovery code sleeping\n"); 2338 printf("%s: Recovery code sleeping\n", ahd_name(ahd));
2300 down(&ahd->platform_data->eh_sem); 2339 down(&ahd->platform_data->eh_sem);
2301 printf("Recovery code awake\n"); 2340 printf("%s: Recovery code awake\n", ahd_name(ahd));
2302 ret = del_timer_sync(&timer); 2341 ret = del_timer_sync(&timer);
2303 if (ret == 0) { 2342 if (ret == 0) {
2304 printf("Timer Expired\n"); 2343 printf("%s: Timer Expired (active %d)\n",
2344 ahd_name(ahd), dev->active);
2305 retval = FAILED; 2345 retval = FAILED;
2306 } 2346 }
2307 } 2347 }
2308 ahd_unlock(ahd, &flags); 2348 ahd_unlock(ahd, &flags);
2309 return (retval); 2349 return (retval);
2310} 2350}
2311 2351