diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic79xx_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 62 |
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 | ||