X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Faic7xxx%2Faic7xxx_osm.c;h=051970efba6803a0486e6b6a8b09573d71201b07;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=2c801672d8bba5f425628360170c638beb69e195;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 2c801672d..051970efb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -373,6 +373,7 @@ static void ahc_linux_handle_scsi_status(struct ahc_softc *, struct scb *); static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd); +static void ahc_linux_sem_timeout(u_long arg); static void ahc_linux_freeze_simq(struct ahc_softc *ahc); static void ahc_linux_release_simq(struct ahc_softc *ahc); static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); @@ -1192,6 +1193,7 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); ahc->platform_data->irq = AHC_LINUX_NOIRQ; ahc_lockinit(ahc); + init_MUTEX_LOCKED(&ahc->platform_data->eh_sem); ahc->seltime = (aic7xxx_seltime & 0x3) << 4; ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; if (aic7xxx_pci_parity == 0) @@ -1828,9 +1830,10 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) if (ahc_get_transaction_status(scb) == CAM_BDR_SENT || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED) ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); - - if (ahc->platform_data->eh_done) - complete(ahc->platform_data->eh_done); + if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) { + ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE; + up(&ahc->platform_data->eh_sem); + } } ahc_free_scb(ahc, scb); @@ -2036,6 +2039,22 @@ ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) cmd->scsi_done(cmd); } +static void +ahc_linux_sem_timeout(u_long arg) +{ + struct ahc_softc *ahc; + u_long s; + + ahc = (struct ahc_softc *)arg; + + ahc_lock(ahc, &s); + if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) { + ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE; + up(&ahc->platform_data->eh_sem); + } + ahc_unlock(ahc, &s); +} + static void ahc_linux_freeze_simq(struct ahc_softc *ahc) { @@ -2336,21 +2355,25 @@ done: if (paused) ahc_unpause(ahc); if (wait) { - DECLARE_COMPLETION(done); + struct timer_list timer; + int ret; - ahc->platform_data->eh_done = &done; + ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE; ahc_unlock(ahc, &flags); + init_timer(&timer); + timer.data = (u_long)ahc; + timer.expires = jiffies + (5 * HZ); + timer.function = ahc_linux_sem_timeout; + add_timer(&timer); printf("Recovery code sleeping\n"); - if (!wait_for_completion_timeout(&done, 5 * HZ)) { - ahc_lock(ahc, &flags); - ahc->platform_data->eh_done = NULL; - ahc_unlock(ahc, &flags); - + down(&ahc->platform_data->eh_sem); + printf("Recovery code awake\n"); + ret = del_timer_sync(&timer); + if (ret == 0) { printf("Timer Expired\n"); retval = FAILED; } - printf("Recovery code awake\n"); } else ahc_unlock(ahc, &flags); return (retval);