Commit 7b22da38 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by James Bottomley

[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: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent a382dd7c
...@@ -373,7 +373,6 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *, ...@@ -373,7 +373,6 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *,
struct scb *); struct scb *);
static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
struct scsi_cmnd *cmd); struct scsi_cmnd *cmd);
static void ahd_linux_sem_timeout(u_long arg);
static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag);
static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, 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,18 +452,13 @@ ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *))
struct ahd_softc *ahd; struct ahd_softc *ahd;
struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device);
int rtn = SCSI_MLQUEUE_HOST_BUSY; int rtn = SCSI_MLQUEUE_HOST_BUSY;
unsigned long flags;
ahd = *(struct ahd_softc **)cmd->device->host->hostdata; ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
ahd_lock(ahd, &flags); cmd->scsi_done = scsi_done;
if (ahd->platform_data->qfrozen == 0) { cmd->result = CAM_REQ_INPROG << 16;
cmd->scsi_done = scsi_done; rtn = ahd_linux_run_command(ahd, dev, cmd);
cmd->result = CAM_REQ_INPROG << 16;
rtn = ahd_linux_run_command(ahd, dev, cmd);
}
ahd_unlock(ahd, &flags);
return rtn; return rtn;
} }
...@@ -682,7 +676,6 @@ static int ...@@ -682,7 +676,6 @@ static int
ahd_linux_bus_reset(struct scsi_cmnd *cmd) ahd_linux_bus_reset(struct scsi_cmnd *cmd)
{ {
struct ahd_softc *ahd; struct ahd_softc *ahd;
u_long s;
int found; int found;
ahd = *(struct ahd_softc **)cmd->device->host->hostdata; ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
...@@ -691,10 +684,8 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) ...@@ -691,10 +684,8 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd)
printf("%s: Bus reset called for cmd %p\n", printf("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd); ahd_name(ahd), cmd);
#endif #endif
ahd_lock(ahd, &s);
found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A',
/*initiate reset*/TRUE); /*initiate reset*/TRUE);
ahd_unlock(ahd, &s);
if (bootverbose) if (bootverbose)
printf("%s: SCSI bus reset delivered. " printf("%s: SCSI bus reset delivered. "
...@@ -1194,7 +1185,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) ...@@ -1194,7 +1185,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
ahd->platform_data->irq = AHD_LINUX_NOIRQ; ahd->platform_data->irq = AHD_LINUX_NOIRQ;
ahd_lockinit(ahd); ahd_lockinit(ahd);
init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
ahd->seltime = (aic79xx_seltime & 0x3) << 4; ahd->seltime = (aic79xx_seltime & 0x3) << 4;
return (0); return (0);
} }
...@@ -1443,6 +1433,9 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, ...@@ -1443,6 +1433,9 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
struct ahd_tmode_tstate *tstate; struct ahd_tmode_tstate *tstate;
u_int col_idx; u_int col_idx;
uint16_t mask; uint16_t mask;
unsigned long flags;
ahd_lock(ahd, &flags);
/* /*
* Get an scb to use. * Get an scb to use.
...@@ -1458,6 +1451,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, ...@@ -1458,6 +1451,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
} }
if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
ahd->flags |= AHD_RESOURCE_SHORTAGE; ahd->flags |= AHD_RESOURCE_SHORTAGE;
ahd_unlock(ahd, &flags);
return SCSI_MLQUEUE_HOST_BUSY; return SCSI_MLQUEUE_HOST_BUSY;
} }
...@@ -1583,6 +1577,8 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, ...@@ -1583,6 +1577,8 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
scb->flags |= SCB_ACTIVE; scb->flags |= SCB_ACTIVE;
ahd_queue_scb(ahd, scb); ahd_queue_scb(ahd, scb);
ahd_unlock(ahd, &flags);
return 0; return 0;
} }
...@@ -1618,7 +1614,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, ...@@ -1618,7 +1614,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel,
{ {
char buf[80]; char buf[80];
struct scsi_target *starget; struct scsi_target *starget;
struct ahd_linux_target *targ;
struct info_str info; struct info_str info;
struct ahd_initiator_tinfo *tinfo; struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate; struct ahd_tmode_tstate *tstate;
...@@ -1651,7 +1646,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel, ...@@ -1651,7 +1646,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel,
starget = ahd->platform_data->starget[target]; starget = ahd->platform_data->starget[target];
if (starget == NULL) if (starget == NULL)
break; break;
targ = scsi_transport_target_data(starget);
target_ppr_options = target_ppr_options =
(spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0)
...@@ -1803,10 +1797,9 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) ...@@ -1803,10 +1797,9 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb)
if (ahd_get_transaction_status(scb) == CAM_BDR_SENT if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
|| ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; if (ahd->platform_data->eh_done)
up(&ahd->platform_data->eh_sem); complete(ahd->platform_data->eh_done);
}
} }
ahd_free_scb(ahd, scb); ahd_free_scb(ahd, scb);
...@@ -2030,60 +2023,16 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) ...@@ -2030,60 +2023,16 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd)
cmd->scsi_done(cmd); cmd->scsi_done(cmd);
} }
static void
ahd_linux_sem_timeout(u_long arg)
{
struct ahd_softc *ahd;
u_long s;
ahd = (struct ahd_softc *)arg;
ahd_lock(ahd, &s);
if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
up(&ahd->platform_data->eh_sem);
}
ahd_unlock(ahd, &s);
}
void void
ahd_freeze_simq(struct ahd_softc *ahd) ahd_freeze_simq(struct ahd_softc *ahd)
{ {
unsigned long s; scsi_block_requests(ahd->platform_data->host);
ahd_lock(ahd, &s);
ahd->platform_data->qfrozen++;
if (ahd->platform_data->qfrozen == 1) {
scsi_block_requests(ahd->platform_data->host);
ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
CAM_LUN_WILDCARD, SCB_LIST_NULL,
ROLE_INITIATOR, CAM_REQUEUE_REQ);
}
ahd_unlock(ahd, &s);
} }
void void
ahd_release_simq(struct ahd_softc *ahd) ahd_release_simq(struct ahd_softc *ahd)
{ {
u_long s; scsi_unblock_requests(ahd->platform_data->host);
int unblock_reqs;
unblock_reqs = 0;
ahd_lock(ahd, &s);
if (ahd->platform_data->qfrozen > 0)
ahd->platform_data->qfrozen--;
if (ahd->platform_data->qfrozen == 0) {
unblock_reqs = 1;
}
ahd_unlock(ahd, &s);
/*
* There is still a race here. The mid-layer
* should keep its own freeze count and use
* a bottom half handler to run the queues
* so we can unblock with our own lock held.
*/
if (unblock_reqs)
scsi_unblock_requests(ahd->platform_data->host);
} }
static int static int
...@@ -2344,30 +2293,29 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) ...@@ -2344,30 +2293,29 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag)
if (paused) if (paused)
ahd_unpause(ahd); ahd_unpause(ahd);
if (wait) { if (wait) {
struct timer_list timer; DECLARE_COMPLETION(done);
int ret;
ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; ahd->platform_data->eh_done = &done;
ahd_unlock(ahd, &flags); ahd_unlock(ahd, &flags);
init_timer(&timer);
timer.data = (u_long)ahd;
timer.expires = jiffies + (5 * HZ);
timer.function = ahd_linux_sem_timeout;
add_timer(&timer);
printf("%s: Recovery code sleeping\n", ahd_name(ahd)); printf("%s: Recovery code sleeping\n", ahd_name(ahd));
down(&ahd->platform_data->eh_sem); if (!wait_for_completion_timeout(&done, 5 * HZ)) {
printf("%s: Recovery code awake\n", ahd_name(ahd)); ahd_lock(ahd, &flags);
ret = del_timer_sync(&timer); ahd->platform_data->eh_done = NULL;
if (ret == 0) { ahd_unlock(ahd, &flags);
printf("%s: Timer Expired (active %d)\n", printf("%s: Timer Expired (active %d)\n",
ahd_name(ahd), dev->active); ahd_name(ahd), dev->active);
retval = FAILED; retval = FAILED;
} }
printf("Recovery code awake\n");
} else } else
ahd_unlock(ahd, &flags); ahd_unlock(ahd, &flags);
return (retval); if (retval != SUCCESS)
printf("%s: Command abort returning 0x%x\n",
ahd_name(ahd), retval);
return retval;
} }
static void ahd_linux_set_width(struct scsi_target *starget, int width) static void ahd_linux_set_width(struct scsi_target *starget, int width)
......
...@@ -381,15 +381,12 @@ struct ahd_platform_data { ...@@ -381,15 +381,12 @@ struct ahd_platform_data {
struct scsi_target *starget[AHD_NUM_TARGETS]; struct scsi_target *starget[AHD_NUM_TARGETS];
spinlock_t spin_lock; spinlock_t spin_lock;
u_int qfrozen; struct completion *eh_done;
struct semaphore eh_sem;
struct Scsi_Host *host; /* pointer to scsi host */ struct Scsi_Host *host; /* pointer to scsi host */
#define AHD_LINUX_NOIRQ ((uint32_t)~0) #define AHD_LINUX_NOIRQ ((uint32_t)~0)
uint32_t irq; /* IRQ for this adapter */ uint32_t irq; /* IRQ for this adapter */
uint32_t bios_address; uint32_t bios_address;
uint32_t mem_busaddr; /* Mem Base Addr */ uint32_t mem_busaddr; /* Mem Base Addr */
#define AHD_SCB_UP_EH_SEM 0x1
uint32_t flags;
}; };
/************************** OS Utility Wrappers *******************************/ /************************** OS Utility Wrappers *******************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment