forked from Minki/linux
[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>
This commit is contained in:
parent
a382dd7c13
commit
7b22da38b6
@ -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 *))
|
|||||||
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
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@ done:
|
|||||||
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 {
|
|||||||
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 *******************************/
|
||||||
|
Loading…
Reference in New Issue
Block a user