Commit f749d8b7 authored by Don Brace's avatar Don Brace Committed by Martin K. Petersen
Browse files

scsi: hpsa: Correct dev cmds outstanding for retried cmds

Prevent incrementing device->commands_outstanding for ioaccel command
retries that are driver initiated.  If the command goes through the retry
path, the device->commands_outstanding counter has already accounted for
the number of commands outstanding to the device.  Only commands going
through function hpsa_cmd_resolve_events decrement this counter.

 - ioaccel commands go to either HBA disks or to logical volumes comprised
   of SSDs.

The extra increment is causing device resets to hang.

 - Resets wait for all device outstanding commands to complete before
   returning.

Replace unused field abort_pending with retry_pending. This is a
maintenance driver so these changes have the least impact/risk.

Link: https://lore.kernel.org/r/161342801747.29388.13045495968308188518.stgit@brunhilda


Tested-by: default avatarJoe Szczypek <jszczype@redhat.com>
Reviewed-by: default avatarScott Benesh <scott.benesh@microchip.com>
Reviewed-by: default avatarScott Teel <scott.teel@microchip.com>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarDon Brace <don.brace@microchip.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent aaf15f8c
Loading
Loading
Loading
Loading
+44 −7
Original line number Diff line number Diff line
@@ -1151,7 +1151,10 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
{
	dial_down_lockup_detection_during_fw_flash(h, c);
	atomic_inc(&h->commands_outstanding);
	if (c->device)
	/*
	 * Check to see if the command is being retried.
	 */
	if (c->device && !c->retry_pending)
		atomic_inc(&c->device->commands_outstanding);

	reply_queue = h->reply_map[raw_smp_processor_id()];
@@ -5567,7 +5570,8 @@ static inline void hpsa_cmd_partial_init(struct ctlr_info *h, int index,
}

static int hpsa_ioaccel_submit(struct ctlr_info *h,
		struct CommandList *c, struct scsi_cmnd *cmd)
		struct CommandList *c, struct scsi_cmnd *cmd,
		bool retry)
{
	struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
	int rc = IO_ACCEL_INELIGIBLE;
@@ -5584,18 +5588,22 @@ static int hpsa_ioaccel_submit(struct ctlr_info *h,
	cmd->host_scribble = (unsigned char *) c;

	if (dev->offload_enabled) {
		hpsa_cmd_init(h, c->cmdindex, c);
		hpsa_cmd_init(h, c->cmdindex, c); /* Zeroes out all fields */
		c->cmd_type = CMD_SCSI;
		c->scsi_cmd = cmd;
		c->device = dev;
		if (retry) /* Resubmit but do not increment device->commands_outstanding. */
			c->retry_pending = true;
		rc = hpsa_scsi_ioaccel_raid_map(h, c);
		if (rc < 0)     /* scsi_dma_map failed. */
			rc = SCSI_MLQUEUE_HOST_BUSY;
	} else if (dev->hba_ioaccel_enabled) {
		hpsa_cmd_init(h, c->cmdindex, c);
		hpsa_cmd_init(h, c->cmdindex, c); /* Zeroes out all fields */
		c->cmd_type = CMD_SCSI;
		c->scsi_cmd = cmd;
		c->device = dev;
		if (retry) /* Resubmit but do not increment device->commands_outstanding. */
			c->retry_pending = true;
		rc = hpsa_scsi_ioaccel_direct_map(h, c);
		if (rc < 0)     /* scsi_dma_map failed. */
			rc = SCSI_MLQUEUE_HOST_BUSY;
@@ -5628,7 +5636,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)

		if (c2->error_data.serv_response ==
				IOACCEL2_STATUS_SR_TASK_COMP_SET_FULL) {
			rc = hpsa_ioaccel_submit(h, c, cmd);
			/* Resubmit with the retry_pending flag set. */
			rc = hpsa_ioaccel_submit(h, c, cmd, true);
			if (rc == 0)
				return;
			if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -5644,6 +5653,15 @@ static void hpsa_command_resubmit_worker(struct work_struct *work)
		}
	}
	hpsa_cmd_partial_init(c->h, c->cmdindex, c);
	/*
	 * Here we have not come in though queue_command, so we
	 * can set the retry_pending flag to true for a driver initiated
	 * retry attempt (I.E. not a SML retry).
	 * I.E. We are submitting a driver initiated retry.
	 * Note: hpsa_ciss_submit does not zero out the command fields like
	 *       ioaccel submit does.
	 */
	c->retry_pending = true;
	if (hpsa_ciss_submit(c->h, c, cmd, dev)) {
		/*
		 * If we get here, it means dma mapping failed. Try
@@ -5706,11 +5724,16 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
	/*
	 * Call alternate submit routine for I/O accelerated commands.
	 * Retries always go down the normal I/O path.
	 * Note: If cmd->retries is non-zero, then this is a SML
	 *       initiated retry and not a driver initiated retry.
	 *       This command has been obtained from cmd_tagged_alloc
	 *       and is therefore a brand-new command.
	 */
	if (likely(cmd->retries == 0 &&
			!blk_rq_is_passthrough(cmd->request) &&
			h->acciopath_status)) {
		rc = hpsa_ioaccel_submit(h, c, cmd);
		/* Submit with the retry_pending flag unset. */
		rc = hpsa_ioaccel_submit(h, c, cmd, false);
		if (rc == 0)
			return 0;
		if (rc == SCSI_MLQUEUE_HOST_BUSY) {
@@ -6105,6 +6128,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
 * at init, and managed by cmd_tagged_alloc() and cmd_tagged_free() using the
 * block request tag as an index into a table of entries.  cmd_tagged_free() is
 * the complement, although cmd_free() may be called instead.
 * This function is only called for new requests from queue_command.
 */
static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
					    struct scsi_cmnd *scmd)
@@ -6139,8 +6163,14 @@ static struct CommandList *cmd_tagged_alloc(struct ctlr_info *h,
	}

	atomic_inc(&c->refcount);

	hpsa_cmd_partial_init(h, idx, c);

	/*
	 * This is a new command obtained from queue_command so
	 * there have not been any driver initiated retry attempts.
	 */
	c->retry_pending = false;

	return c;
}

@@ -6208,6 +6238,13 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
	}
	hpsa_cmd_partial_init(h, i, c);
	c->device = NULL;

	/*
	 * cmd_alloc is for "internal" commands and they are never
	 * retried.
	 */
	c->retry_pending = false;

	return c;
}

+1 −1
Original line number Diff line number Diff line
@@ -448,7 +448,7 @@ struct CommandList {
	 */
	struct hpsa_scsi_dev_t *phys_disk;

	int abort_pending;
	bool retry_pending;
	struct hpsa_scsi_dev_t *device;
	atomic_t refcount; /* Must be last to avoid memset in hpsa_cmd_init() */
} __aligned(COMMANDLIST_ALIGNMENT);