diff options
author | Hannes Reinecke <hare@suse.de> | 2006-03-08 06:56:14 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-03-12 10:01:13 -0500 |
commit | 7b22da38b64a32df20fdb7272deb7546045fccec (patch) | |
tree | df26d10b480b9da5e68397ad4d8c12a2e5c59fec /drivers/scsi/aic7xxx | |
parent | a382dd7c13377c8ff98f6ec59f64355653fb507e (diff) |
[SCSI] aic79xx: remove qfrozen
This patch removes the need for platform_data->qfrozen.
We're now using complete() instead of semaphores thus
simplifying ahd_freeze_simq() quite a lot.
This also fixes some deadlocks in the recovery code (again).
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aic7xxx')
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.c | 104 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aic79xx_osm.h | 5 |
2 files changed, 27 insertions, 82 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 7254ea535a16..fc393bd95f4a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c | |||
@@ -373,7 +373,6 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *, | |||
373 | struct scb *); | 373 | struct scb *); |
374 | static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, | 374 | static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, |
375 | struct scsi_cmnd *cmd); | 375 | struct scsi_cmnd *cmd); |
376 | static void ahd_linux_sem_timeout(u_long arg); | ||
377 | static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); | 376 | static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); |
378 | static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); | 377 | static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); |
379 | static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, | 378 | static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, |
@@ -453,18 +452,13 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) | |||
453 | struct ahd_softc *ahd; | 452 | struct ahd_softc *ahd; |
454 | struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); | 453 | struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); |
455 | int rtn = SCSI_MLQUEUE_HOST_BUSY; | 454 | int rtn = SCSI_MLQUEUE_HOST_BUSY; |
456 | unsigned long flags; | ||
457 | 455 | ||
458 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; | 456 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
459 | 457 | ||
460 | ahd_lock(ahd, &flags); | 458 | cmd->scsi_done = scsi_done; |
461 | if (ahd->platform_data->qfrozen == 0) { | 459 | cmd->result = CAM_REQ_INPROG << 16; |
462 | cmd->scsi_done = scsi_done; | 460 | rtn = ahd_linux_run_command(ahd, dev, cmd); |
463 | cmd->result = CAM_REQ_INPROG << 16; | ||
464 | rtn = ahd_linux_run_command(ahd, dev, cmd); | ||
465 | 461 | ||
466 | } | ||
467 | ahd_unlock(ahd, &flags); | ||
468 | return rtn; | 462 | return rtn; |
469 | } | 463 | } |
470 | 464 | ||
@@ -682,7 +676,6 @@ static int | |||
682 | ahd_linux_bus_reset(struct scsi_cmnd *cmd) | 676 | ahd_linux_bus_reset(struct scsi_cmnd *cmd) |
683 | { | 677 | { |
684 | struct ahd_softc *ahd; | 678 | struct ahd_softc *ahd; |
685 | u_long s; | ||
686 | int found; | 679 | int found; |
687 | 680 | ||
688 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; | 681 | ahd = *(struct ahd_softc **)cmd->device->host->hostdata; |
@@ -691,10 +684,8 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) | |||
691 | printf("%s: Bus reset called for cmd %p\n", | 684 | printf("%s: Bus reset called for cmd %p\n", |
692 | ahd_name(ahd), cmd); | 685 | ahd_name(ahd), cmd); |
693 | #endif | 686 | #endif |
694 | ahd_lock(ahd, &s); | ||
695 | found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', | 687 | found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', |
696 | /*initiate reset*/TRUE); | 688 | /*initiate reset*/TRUE); |
697 | ahd_unlock(ahd, &s); | ||
698 | 689 | ||
699 | if (bootverbose) | 690 | if (bootverbose) |
700 | printf("%s: SCSI bus reset delivered. " | 691 | printf("%s: SCSI bus reset delivered. " |
@@ -1194,7 +1185,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) | |||
1194 | memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); | 1185 | memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); |
1195 | ahd->platform_data->irq = AHD_LINUX_NOIRQ; | 1186 | ahd->platform_data->irq = AHD_LINUX_NOIRQ; |
1196 | ahd_lockinit(ahd); | 1187 | ahd_lockinit(ahd); |
1197 | init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); | ||
1198 | ahd->seltime = (aic79xx_seltime & 0x3) << 4; | 1188 | ahd->seltime = (aic79xx_seltime & 0x3) << 4; |
1199 | return (0); | 1189 | return (0); |
1200 | } | 1190 | } |
@@ -1443,6 +1433,9 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1443 | struct ahd_tmode_tstate *tstate; | 1433 | struct ahd_tmode_tstate *tstate; |
1444 | u_int col_idx; | 1434 | u_int col_idx; |
1445 | uint16_t mask; | 1435 | uint16_t mask; |
1436 | unsigned long flags; | ||
1437 | |||
1438 | ahd_lock(ahd, &flags); | ||
1446 | 1439 | ||
1447 | /* | 1440 | /* |
1448 | * Get an scb to use. | 1441 | * Get an scb to use. |
@@ -1458,6 +1451,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1458 | } | 1451 | } |
1459 | if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { | 1452 | if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { |
1460 | ahd->flags |= AHD_RESOURCE_SHORTAGE; | 1453 | ahd->flags |= AHD_RESOURCE_SHORTAGE; |
1454 | ahd_unlock(ahd, &flags); | ||
1461 | return SCSI_MLQUEUE_HOST_BUSY; | 1455 | return SCSI_MLQUEUE_HOST_BUSY; |
1462 | } | 1456 | } |
1463 | 1457 | ||
@@ -1583,6 +1577,8 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, | |||
1583 | scb->flags |= SCB_ACTIVE; | 1577 | scb->flags |= SCB_ACTIVE; |
1584 | ahd_queue_scb(ahd, scb); | 1578 | ahd_queue_scb(ahd, scb); |
1585 | 1579 | ||
1580 | ahd_unlock(ahd, &flags); | ||
1581 | |||
1586 | return 0; | 1582 | return 0; |
1587 | } | 1583 | } |
1588 | 1584 | ||
@@ -1618,7 +1614,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, | |||
1618 | { | 1614 | { |
1619 | char buf[80]; | 1615 | char buf[80]; |
1620 | struct scsi_target *starget; | 1616 | struct scsi_target *starget; |
1621 | struct ahd_linux_target *targ; | ||
1622 | struct info_str info; | 1617 | struct info_str info; |
1623 | struct ahd_initiator_tinfo *tinfo; | 1618 | struct ahd_initiator_tinfo *tinfo; |
1624 | struct ahd_tmode_tstate *tstate; | 1619 | struct ahd_tmode_tstate *tstate; |
@@ -1651,7 +1646,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, | |||
1651 | starget = ahd->platform_data->starget[target]; | 1646 | starget = ahd->platform_data->starget[target]; |
1652 | if (starget == NULL) | 1647 | if (starget == NULL) |
1653 | break; | 1648 | break; |
1654 | targ = scsi_transport_target_data(starget); | ||
1655 | 1649 | ||
1656 | target_ppr_options = | 1650 | target_ppr_options = |
1657 | (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) | 1651 | (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) |
@@ -1803,10 +1797,9 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) | |||
1803 | if (ahd_get_transaction_status(scb) == CAM_BDR_SENT | 1797 | if (ahd_get_transaction_status(scb) == CAM_BDR_SENT |
1804 | || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) | 1798 | || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) |
1805 | ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); | 1799 | ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); |
1806 | if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { | 1800 | |
1807 | ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; | 1801 | if (ahd->platform_data->eh_done) |
1808 | up(&ahd->platform_data->eh_sem); | 1802 | complete(ahd->platform_data->eh_done); |
1809 | } | ||
1810 | } | 1803 | } |
1811 | 1804 | ||
1812 | ahd_free_scb(ahd, scb); | 1805 | ahd_free_scb(ahd, scb); |
@@ -2030,60 +2023,16 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) | |||
2030 | cmd->scsi_done(cmd); | 2023 | cmd->scsi_done(cmd); |
2031 | } | 2024 | } |
2032 | 2025 | ||
2033 | static void | ||
2034 | ahd_linux_sem_timeout(u_long arg) | ||
2035 | { | ||
2036 | struct ahd_softc *ahd; | ||
2037 | u_long s; | ||
2038 | |||
2039 | ahd = (struct ahd_softc *)arg; | ||
2040 | |||
2041 | ahd_lock(ahd, &s); | ||
2042 | if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { | ||
2043 | ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; | ||
2044 | up(&ahd->platform_data->eh_sem); | ||
2045 | } | ||
2046 | ahd_unlock(ahd, &s); | ||
2047 | } | ||
2048 | |||
2049 | void | 2026 | void |
2050 | ahd_freeze_simq(struct ahd_softc *ahd) | 2027 | ahd_freeze_simq(struct ahd_softc *ahd) |
2051 | { | 2028 | { |
2052 | unsigned long s; | 2029 | scsi_block_requests(ahd->platform_data->host); |
2053 | |||
2054 | ahd_lock(ahd, &s); | ||
2055 | ahd->platform_data->qfrozen++; | ||
2056 | if (ahd->platform_data->qfrozen == 1) { | ||
2057 | scsi_block_requests(ahd->platform_data->host); | ||
2058 | ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, | ||
2059 | CAM_LUN_WILDCARD, SCB_LIST_NULL, | ||
2060 | ROLE_INITIATOR, CAM_REQUEUE_REQ); | ||
2061 | } | ||
2062 | ahd_unlock(ahd, &s); | ||
2063 | } | 2030 | } |
2064 | 2031 | ||
2065 | void | 2032 | void |
2066 | ahd_release_simq(struct ahd_softc *ahd) | 2033 | ahd_release_simq(struct ahd_softc *ahd) |
2067 | { | 2034 | { |
2068 | u_long s; | 2035 | scsi_unblock_requests(ahd->platform_data->host); |
2069 | int unblock_reqs; | ||
2070 | |||
2071 | unblock_reqs = 0; | ||
2072 | ahd_lock(ahd, &s); | ||
2073 | if (ahd->platform_data->qfrozen > 0) | ||
2074 | ahd->platform_data->qfrozen--; | ||
2075 | if (ahd->platform_data->qfrozen == 0) { | ||
2076 | unblock_reqs = 1; | ||
2077 | } | ||
2078 | ahd_unlock(ahd, &s); | ||
2079 | /* | ||
2080 | * There is still a race here. The mid-layer | ||
2081 | * should keep its own freeze count and use | ||
2082 | * a bottom half handler to run the queues | ||
2083 | * so we can unblock with our own lock held. | ||
2084 | */ | ||
2085 | if (unblock_reqs) | ||
2086 | scsi_unblock_requests(ahd->platform_data->host); | ||
2087 | } | 2036 | } |
2088 | 2037 | ||
2089 | static int | 2038 | static int |
@@ -2344,30 +2293,29 @@ done: | |||
2344 | if (paused) | 2293 | if (paused) |
2345 | ahd_unpause(ahd); | 2294 | ahd_unpause(ahd); |
2346 | if (wait) { | 2295 | if (wait) { |
2347 | struct timer_list timer; | 2296 | DECLARE_COMPLETION(done); |
2348 | int ret; | ||
2349 | 2297 | ||
2350 | ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; | 2298 | ahd->platform_data->eh_done = &done; |
2351 | ahd_unlock(ahd, &flags); | 2299 | ahd_unlock(ahd, &flags); |
2352 | 2300 | ||
2353 | init_timer(&timer); | ||
2354 | timer.data = (u_long)ahd; | ||
2355 | timer.expires = jiffies + (5 * HZ); | ||
2356 | timer.function = ahd_linux_sem_timeout; | ||
2357 | add_timer(&timer); | ||
2358 | printf("%s: Recovery code sleeping\n", ahd_name(ahd)); | 2301 | printf("%s: Recovery code sleeping\n", ahd_name(ahd)); |
2359 | down(&ahd->platform_data->eh_sem); | 2302 | if (!wait_for_completion_timeout(&done, 5 * HZ)) { |
2360 | printf("%s: Recovery code awake\n", ahd_name(ahd)); | 2303 | ahd_lock(ahd, &flags); |
2361 | ret = del_timer_sync(&timer); | 2304 | ahd->platform_data->eh_done = NULL; |
2362 | if (ret == 0) { | 2305 | ahd_unlock(ahd, &flags); |
2363 | printf("%s: Timer Expired (active %d)\n", | 2306 | printf("%s: Timer Expired (active %d)\n", |
2364 | ahd_name(ahd), dev->active); | 2307 | ahd_name(ahd), dev->active); |
2365 | retval = FAILED; | 2308 | retval = FAILED; |
2366 | } | 2309 | } |
2310 | printf("Recovery code awake\n"); | ||
2367 | } else | 2311 | } else |
2368 | ahd_unlock(ahd, &flags); | 2312 | ahd_unlock(ahd, &flags); |
2369 | 2313 | ||
2370 | return (retval); | 2314 | if (retval != SUCCESS) |
2315 | printf("%s: Command abort returning 0x%x\n", | ||
2316 | ahd_name(ahd), retval); | ||
2317 | |||
2318 | return retval; | ||
2371 | } | 2319 | } |
2372 | 2320 | ||
2373 | static void ahd_linux_set_width(struct scsi_target *starget, int width) | 2321 | static void ahd_linux_set_width(struct scsi_target *starget, int width) |
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 9cb101345107..599e3940db16 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h | |||
@@ -381,15 +381,12 @@ struct ahd_platform_data { | |||
381 | struct scsi_target *starget[AHD_NUM_TARGETS]; | 381 | struct scsi_target *starget[AHD_NUM_TARGETS]; |
382 | 382 | ||
383 | spinlock_t spin_lock; | 383 | spinlock_t spin_lock; |
384 | u_int qfrozen; | 384 | struct completion *eh_done; |
385 | struct semaphore eh_sem; | ||
386 | struct Scsi_Host *host; /* pointer to scsi host */ | 385 | struct Scsi_Host *host; /* pointer to scsi host */ |
387 | #define AHD_LINUX_NOIRQ ((uint32_t)~0) | 386 | #define AHD_LINUX_NOIRQ ((uint32_t)~0) |
388 | uint32_t irq; /* IRQ for this adapter */ | 387 | uint32_t irq; /* IRQ for this adapter */ |
389 | uint32_t bios_address; | 388 | uint32_t bios_address; |
390 | uint32_t mem_busaddr; /* Mem Base Addr */ | 389 | uint32_t mem_busaddr; /* Mem Base Addr */ |
391 | #define AHD_SCB_UP_EH_SEM 0x1 | ||
392 | uint32_t flags; | ||
393 | }; | 390 | }; |
394 | 391 | ||
395 | /************************** OS Utility Wrappers *******************************/ | 392 | /************************** OS Utility Wrappers *******************************/ |