Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9d2c3039 authored by Hannes Reinecke's avatar Hannes Reinecke Committed by Martin K. Petersen
Browse files

scsi_dh_alua: Send TEST UNIT READY to poll for transitioning



Sending a 'REPORT TARGET PORT GROUP' command is a costly operation,
as the array has to gather information about all ports.
So instead of using RTPG to poll for a status update when a port
is in transitioning we should be sending a TEST UNIT READY, and
wait for the sense code to report success.

Reviewed-by: default avatarBart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: default avatarEwan Milne <emilne@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c57168a1
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -465,6 +465,30 @@ static int alua_check_sense(struct scsi_device *sdev,
	return SCSI_RETURN_NOT_HANDLED;
}

/*
 * alua_tur - Send a TEST UNIT READY
 * @sdev: device to which the TEST UNIT READY command should be send
 *
 * Send a TEST UNIT READY to @sdev to figure out the device state
 * Returns SCSI_DH_RETRY if the sense code is NOT READY/ALUA TRANSITIONING,
 * SCSI_DH_OK if no error occurred, and SCSI_DH_IO otherwise.
 */
static int alua_tur(struct scsi_device *sdev)
{
	struct scsi_sense_hdr sense_hdr;
	int retval;

	retval = scsi_test_unit_ready(sdev, ALUA_FAILOVER_TIMEOUT * HZ,
				      ALUA_FAILOVER_RETRIES, &sense_hdr);
	if (sense_hdr.sense_key == NOT_READY &&
	    sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x0a)
		return SCSI_DH_RETRY;
	else if (retval)
		return SCSI_DH_IO;
	else
		return SCSI_DH_OK;
}

/*
 * alua_rtpg - Evaluate REPORT TARGET GROUP STATES
 * @sdev: the device to be evaluated.
@@ -732,8 +756,22 @@ static void alua_rtpg_work(struct work_struct *work)
		alua_wq = kaluad_sync_wq;
	pg->flags |= ALUA_PG_RUNNING;
	if (pg->flags & ALUA_PG_RUN_RTPG) {
		int state = pg->state;

		pg->flags &= ~ALUA_PG_RUN_RTPG;
		spin_unlock_irqrestore(&pg->lock, flags);
		if (state == TPGS_STATE_TRANSITIONING) {
			if (alua_tur(sdev) == SCSI_DH_RETRY) {
				spin_lock_irqsave(&pg->lock, flags);
				pg->flags &= ~ALUA_PG_RUNNING;
				pg->flags |= ALUA_PG_RUN_RTPG;
				spin_unlock_irqrestore(&pg->lock, flags);
				queue_delayed_work(alua_wq, &pg->rtpg_work,
						   pg->interval * HZ);
				return;
			}
			/* Send RTPG on failure or if TUR indicates SUCCESS */
		}
		err = alua_rtpg(sdev, pg);
		spin_lock_irqsave(&pg->lock, flags);
		if (err == SCSI_DH_RETRY || pg->flags & ALUA_PG_RUN_RTPG) {