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

[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
Loading
Loading
Loading
Loading
+26 −78
Original line number Diff line number Diff line
@@ -373,7 +373,6 @@ static void ahd_linux_handle_scsi_status(struct ahd_softc *,
					 struct scb *);
static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
					 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 void ahd_linux_initialize_scsi_bus(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_linux_device *dev = scsi_transport_device_data(cmd->device);
	int rtn = SCSI_MLQUEUE_HOST_BUSY;
	unsigned long flags;

	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;

	ahd_lock(ahd, &flags);
	if (ahd->platform_data->qfrozen == 0) {
	cmd->scsi_done = scsi_done;
	cmd->result = CAM_REQ_INPROG << 16;
	rtn = ahd_linux_run_command(ahd, dev, cmd);

	}
	ahd_unlock(ahd, &flags);
	return rtn;
}

@@ -682,7 +676,6 @@ static int
ahd_linux_bus_reset(struct scsi_cmnd *cmd)
{
	struct ahd_softc *ahd;
	u_long s;
	int    found;

	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",
		       ahd_name(ahd), cmd);
#endif
	ahd_lock(ahd, &s);
	found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A',
				  /*initiate reset*/TRUE);
	ahd_unlock(ahd, &s);

	if (bootverbose)
		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));
	ahd->platform_data->irq = AHD_LINUX_NOIRQ;
	ahd_lockinit(ahd);
	init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
	ahd->seltime = (aic79xx_seltime & 0x3) << 4;
	return (0);
}
@@ -1443,6 +1433,9 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
	struct	 ahd_tmode_tstate *tstate;
	u_int	 col_idx;
	uint16_t mask;
	unsigned long flags;

	ahd_lock(ahd, &flags);

	/*
	 * 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) {
		ahd->flags |= AHD_RESOURCE_SHORTAGE;
		ahd_unlock(ahd, &flags);
		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;
	ahd_queue_scb(ahd, scb);

	ahd_unlock(ahd, &flags);

	return 0;
}

@@ -1618,7 +1614,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel,
	{
		char	buf[80];
		struct  scsi_target *starget;
		struct	ahd_linux_target *targ;
		struct	info_str info;
		struct	ahd_initiator_tinfo *tinfo;
		struct	ahd_tmode_tstate *tstate;
@@ -1651,7 +1646,6 @@ ahd_send_async(struct ahd_softc *ahd, char channel,
		starget = ahd->platform_data->starget[target];
		if (starget == NULL)
			break;
		targ = scsi_transport_target_data(starget);

		target_ppr_options =
			(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
		 || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
			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;
			up(&ahd->platform_data->eh_sem);
		}

		if (ahd->platform_data->eh_done)
			complete(ahd->platform_data->eh_done);
	}

	ahd_free_scb(ahd, scb);
@@ -2030,59 +2023,15 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *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
ahd_freeze_simq(struct ahd_softc *ahd)
{
	unsigned long s;

	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
ahd_release_simq(struct ahd_softc *ahd)
{
	u_long s;
	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);
}

@@ -2344,30 +2293,29 @@ done:
	if (paused)
		ahd_unpause(ahd);
	if (wait) {
		struct timer_list timer;
		int ret;
		DECLARE_COMPLETION(done);

		ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM;
		ahd->platform_data->eh_done = &done;
		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));
		down(&ahd->platform_data->eh_sem);
		printf("%s: Recovery code awake\n", ahd_name(ahd));
        	ret = del_timer_sync(&timer);
		if (ret == 0) {
		if (!wait_for_completion_timeout(&done, 5 * HZ)) {
			ahd_lock(ahd, &flags);
			ahd->platform_data->eh_done = NULL;
			ahd_unlock(ahd, &flags);
			printf("%s: Timer Expired (active %d)\n",
			       ahd_name(ahd), dev->active);
			retval = FAILED;
		}
		printf("Recovery code awake\n");
	} else
		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)
+1 −4
Original line number Diff line number Diff line
@@ -381,15 +381,12 @@ struct ahd_platform_data {
	struct scsi_target *starget[AHD_NUM_TARGETS]; 

	spinlock_t		 spin_lock;
	u_int			 qfrozen;
	struct semaphore	 eh_sem;
	struct completion	*eh_done;
	struct Scsi_Host        *host;		/* pointer to scsi host */
#define AHD_LINUX_NOIRQ	((uint32_t)~0)
	uint32_t		 irq;		/* IRQ for this adapter */
	uint32_t		 bios_address;
	uint32_t		 mem_busaddr;	/* Mem Base Addr */
#define	AHD_SCB_UP_EH_SEM 0x1
	uint32_t		 flags;
};

/************************** OS Utility Wrappers *******************************/