Commit e6044f71 authored by Bart Van Assche's avatar Bart Van Assche Committed by Martin K. Petersen
Browse files

scsi: core: Only process PM requests if rpm_status != RPM_ACTIVE

Instead of submitting all SCSI commands submitted with scsi_execute() to a
SCSI device if rpm_status != RPM_ACTIVE, only submit RQF_PM (power
management requests) if rpm_status != RPM_ACTIVE. This patch makes the SCSI
core handle the runtime power management status (rpm_status) as it should
be handled.

Link: https://lore.kernel.org/r/20201209052951.16136-7-bvanassche@acm.org


Cc: Can Guo <cang@codeaurora.org>
Cc: Stanley Chu <stanley.chu@mediatek.com>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Ming Lei <ming.lei@redhat.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: Martin Kepplinger <martin.kepplinger@puri.sm>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarJens Axboe <axboe@kernel.dk>
Reviewed-by: default avatarCan Guo <cang@codeaurora.org>
Signed-off-by: default avatarBart Van Assche <bvanassche@acm.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent cfefd9f8
Loading
Loading
Loading
Loading
+14 −13
Original line number Diff line number Diff line
@@ -249,7 +249,8 @@ int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,

	req = blk_get_request(sdev->request_queue,
			data_direction == DMA_TO_DEVICE ?
			REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, BLK_MQ_REQ_PREEMPT);
			REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN,
			rq_flags & RQF_PM ? BLK_MQ_REQ_PM : 0);
	if (IS_ERR(req))
		return ret;
	rq = scsi_req(req);
@@ -1206,6 +1207,8 @@ static blk_status_t
scsi_device_state_check(struct scsi_device *sdev, struct request *req)
{
	switch (sdev->sdev_state) {
	case SDEV_CREATED:
		return BLK_STS_OK;
	case SDEV_OFFLINE:
	case SDEV_TRANSPORT_OFFLINE:
		/*
@@ -1232,18 +1235,18 @@ scsi_device_state_check(struct scsi_device *sdev, struct request *req)
		return BLK_STS_RESOURCE;
	case SDEV_QUIESCE:
		/*
		 * If the devices is blocked we defer normal commands.
		 * If the device is blocked we only accept power management
		 * commands.
		 */
		if (req && !(req->rq_flags & RQF_PREEMPT))
		if (req && WARN_ON_ONCE(!(req->rq_flags & RQF_PM)))
			return BLK_STS_RESOURCE;
		return BLK_STS_OK;
	default:
		/*
		 * For any other not fully online state we only allow
		 * special commands.  In particular any user initiated
		 * command is not allowed.
		 * power management commands.
		 */
		if (req && !(req->rq_flags & RQF_PREEMPT))
		if (req && !(req->rq_flags & RQF_PM))
			return BLK_STS_IOERR;
		return BLK_STS_OK;
	}
@@ -2517,15 +2520,13 @@ void sdev_evt_send_simple(struct scsi_device *sdev,
EXPORT_SYMBOL_GPL(sdev_evt_send_simple);

/**
 *	scsi_device_quiesce - Block user issued commands.
 *	scsi_device_quiesce - Block all commands except power management.
 *	@sdev:	scsi device to quiesce.
 *
 *	This works by trying to transition to the SDEV_QUIESCE state
 *	(which must be a legal transition).  When the device is in this
 *	state, only special requests will be accepted, all others will
 *	be deferred.  Since special requests may also be requeued requests,
 *	a successful return doesn't guarantee the device will be
 *	totally quiescent.
 *	state, only power management requests will be accepted, all others will
 *	be deferred.
 *
 *	Must be called with user context, may sleep.
 *
@@ -2587,12 +2588,12 @@ void scsi_device_resume(struct scsi_device *sdev)
	 * device deleted during suspend)
	 */
	mutex_lock(&sdev->state_mutex);
	if (sdev->sdev_state == SDEV_QUIESCE)
		scsi_device_set_state(sdev, SDEV_RUNNING);
	if (sdev->quiesced_by) {
		sdev->quiesced_by = NULL;
		blk_clear_pm_only(sdev->request_queue);
	}
	if (sdev->sdev_state == SDEV_QUIESCE)
		scsi_device_set_state(sdev, SDEV_RUNNING);
	mutex_unlock(&sdev->state_mutex);
}
EXPORT_SYMBOL(scsi_device_resume);