diff mbox series

[03/22] scsi: add scsi_{get,put}_internal_cmd() helper

Message ID 20200625140124.17201-4-hare@suse.de (mailing list archive)
State Superseded
Headers show
Series scsi: enable reserved commands for LLDDs | expand

Commit Message

Hannes Reinecke June 25, 2020, 2:01 p.m. UTC
Add helper functions to allow LLDDs to allocate and free
internal commands.

Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/scsi/scsi_lib.c    | 41 +++++++++++++++++++++++++++++++++++++++++
 include/scsi/scsi_device.h |  3 +++
 2 files changed, 44 insertions(+)

Comments

Bart Van Assche June 28, 2020, 3:48 a.m. UTC | #1
On 2020-06-25 07:01, Hannes Reinecke wrote:
> +/**
> + * scsi_get_internal_cmd - allocate an intenral SCSI command
                                          ^^^^^^^^
                                          internal?
> + * @sdev: SCSI device from which to allocate the command
> + * @data_direction: Data direction for the allocated command
> + * @op_flags: request allocation flags
> + *
> + * Allocates a SCSI command for internal LLDD use.
> + */
> +struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
> +					int data_direction, int op_flags)

How about using enum dma_data_direction for data_direction and unsigned
int, or even better, a new __bitwise type for op_flags?

> +{
> +	struct request *rq;
> +	struct scsi_cmnd *scmd;
> +	blk_mq_req_flags_t flags = 0;
> +	unsigned int op = REQ_INTERNAL | op_flags;
> +
> +	op |= (data_direction == DMA_TO_DEVICE) ?
> +		REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN;
> +	rq = blk_mq_alloc_request(sdev->request_queue, op, flags);
> +	if (IS_ERR(rq))
> +		return NULL;
> +	scmd = blk_mq_rq_to_pdu(rq);
> +	scmd->request = rq;
> +	scmd->device = sdev;
> +	return scmd;
> +}
> +EXPORT_SYMBOL_GPL(scsi_get_internal_cmd);

Since the 'flags' variable always has the value 0, can it be left out?

> +/**
> + * scsi_put_internal_cmd - free an internal SCSI command
> + * @scmd: SCSI command to be freed
> + */
> +void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
> +{
> +	struct request *rq = blk_mq_rq_from_pdu(scmd);
> +
> +	if (blk_rq_is_internal(rq))
> +		blk_mq_free_request(rq);
> +}
> +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);

How about triggering a warning for the !blk_rq_is_internal(rq) case
instead of silently ignoring regular SCSI commands?

Thanks,

Bart.
Hannes Reinecke June 28, 2020, 9:02 a.m. UTC | #2
On 6/28/20 5:48 AM, Bart Van Assche wrote:
> On 2020-06-25 07:01, Hannes Reinecke wrote:
>> +/**
>> + * scsi_get_internal_cmd - allocate an intenral SCSI command
>                                            ^^^^^^^^
>                                            internal?
>> + * @sdev: SCSI device from which to allocate the command
>> + * @data_direction: Data direction for the allocated command
>> + * @op_flags: request allocation flags
>> + *
>> + * Allocates a SCSI command for internal LLDD use.
>> + */
>> +struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
>> +					int data_direction, int op_flags)
> 
> How about using enum dma_data_direction for data_direction and unsigned
> int, or even better, a new __bitwise type for op_flags?
> 
Okay for data direction, but converting op_flags into __bitwise (or even 
a new type) should be relegated to a different patchset.

>> +{
>> +	struct request *rq;
>> +	struct scsi_cmnd *scmd;
>> +	blk_mq_req_flags_t flags = 0;
>> +	unsigned int op = REQ_INTERNAL | op_flags;
>> +
>> +	op |= (data_direction == DMA_TO_DEVICE) ?
>> +		REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN;
>> +	rq = blk_mq_alloc_request(sdev->request_queue, op, flags);
>> +	if (IS_ERR(rq))
>> +		return NULL;
>> +	scmd = blk_mq_rq_to_pdu(rq);
>> +	scmd->request = rq;
>> +	scmd->device = sdev;
>> +	return scmd;
>> +}
>> +EXPORT_SYMBOL_GPL(scsi_get_internal_cmd);
> 
> Since the 'flags' variable always has the value 0, can it be left out?
> 
Yep, true.

>> +/**
>> + * scsi_put_internal_cmd - free an internal SCSI command
>> + * @scmd: SCSI command to be freed
>> + */
>> +void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
>> +{
>> +	struct request *rq = blk_mq_rq_from_pdu(scmd);
>> +
>> +	if (blk_rq_is_internal(rq))
>> +		blk_mq_free_request(rq);
>> +}
>> +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);
> 
> How about triggering a warning for the !blk_rq_is_internal(rq) case
> instead of silently ignoring regular SCSI commands?
> 
That's by design.
Some drivers have a common routine for freeing up commands, so it'd be 
quite tricky to separate these two cases out at the driver level.
So it's far easier to call the common routine for all commands, and
let this function do the right thing for all commands.

Cheers,

Hannes
Bart Van Assche June 28, 2020, 3:08 p.m. UTC | #3
On 2020-06-28 02:02, Hannes Reinecke wrote:
> On 6/28/20 5:48 AM, Bart Van Assche wrote:
>> On 2020-06-25 07:01, Hannes Reinecke wrote:
>>> +struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
>>> +                    int data_direction, int op_flags)
>>
>> How about using enum dma_data_direction for data_direction and unsigned
>> int, or even better, a new __bitwise type for op_flags?
>>
> Okay for data direction, but converting op_flags into __bitwise (or even
> a new type) should be relegated to a different patchset.

OK.

>>> +/**
>>> + * scsi_put_internal_cmd - free an internal SCSI command
>>> + * @scmd: SCSI command to be freed
>>> + */
>>> +void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
>>> +{
>>> +    struct request *rq = blk_mq_rq_from_pdu(scmd);
>>> +
>>> +    if (blk_rq_is_internal(rq))
>>> +        blk_mq_free_request(rq);
>>> +}
>>> +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);
>>
>> How about triggering a warning for the !blk_rq_is_internal(rq) case
>> instead of silently ignoring regular SCSI commands?
>>
> That's by design.
> Some drivers have a common routine for freeing up commands, so it'd be
> quite tricky to separate these two cases out at the driver level.
> So it's far easier to call the common routine for all commands, and
> let this function do the right thing for all commands.

That sounds fair to me, but is an example available in this patch series
of a call to scsi_put_internal_cmd() from such a common routine? It
seems to me that all calls to scsi_put_internal_cmd() introduced in this
patch series happen from code paths that handle internal commands only?

Thanks,

Bart.
Hannes Reinecke June 29, 2020, 6:32 a.m. UTC | #4
On 6/28/20 5:08 PM, Bart Van Assche wrote:
> On 2020-06-28 02:02, Hannes Reinecke wrote:
>> On 6/28/20 5:48 AM, Bart Van Assche wrote:
>>> On 2020-06-25 07:01, Hannes Reinecke wrote:
>>>> +struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
>>>> +                    int data_direction, int op_flags)
>>>
>>> How about using enum dma_data_direction for data_direction and unsigned
>>> int, or even better, a new __bitwise type for op_flags?
>>>
>> Okay for data direction, but converting op_flags into __bitwise (or even
>> a new type) should be relegated to a different patchset.
> 
> OK.
> 
>>>> +/**
>>>> + * scsi_put_internal_cmd - free an internal SCSI command
>>>> + * @scmd: SCSI command to be freed
>>>> + */
>>>> +void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
>>>> +{
>>>> +    struct request *rq = blk_mq_rq_from_pdu(scmd);
>>>> +
>>>> +    if (blk_rq_is_internal(rq))
>>>> +        blk_mq_free_request(rq);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);
>>>
>>> How about triggering a warning for the !blk_rq_is_internal(rq) case
>>> instead of silently ignoring regular SCSI commands?
>>>
>> That's by design.
>> Some drivers have a common routine for freeing up commands, so it'd be
>> quite tricky to separate these two cases out at the driver level.
>> So it's far easier to call the common routine for all commands, and
>> let this function do the right thing for all commands.
> 
> That sounds fair to me, but is an example available in this patch series
> of a call to scsi_put_internal_cmd() from such a common routine? It
> seems to me that all calls to scsi_put_internal_cmd() introduced in this
> patch series happen from code paths that handle internal commands only?
> 
aacraid.
The function aac_fib_free() is called unconditionally for every fib, and 
doesn't have the means to differentiate between 'normal' and 'internal' 
commands.

Cheers,

Hannes
John Garry June 29, 2020, 2:24 p.m. UTC | #5
On 29/06/2020 07:32, Hannes Reinecke wrote:
>>
>> That sounds fair to me, but is an example available in this patch series
>> of a call to scsi_put_internal_cmd() from such a common routine? It
>> seems to me that all calls to scsi_put_internal_cmd() introduced in this
>> patch series happen from code paths that handle internal commands only?
>>

Ah, I commented on the same thing in your latest series.

> aacraid.
> The function aac_fib_free() is called unconditionally for every fib, and 
> doesn't have the means to differentiate between 'normal' and 'internal' 
> commands.
> 
Surely some fib structure flag could be set in aac_fib_alloc() for this.

Thanks
Bart Van Assche June 29, 2020, 2:38 p.m. UTC | #6
On 2020-06-28 23:32, Hannes Reinecke wrote:
> On 6/28/20 5:08 PM, Bart Van Assche wrote:
>> On 2020-06-28 02:02, Hannes Reinecke wrote:
>>> On 6/28/20 5:48 AM, Bart Van Assche wrote:
>>>> On 2020-06-25 07:01, Hannes Reinecke wrote:
>>>>> +/**
>>>>> + * scsi_put_internal_cmd - free an internal SCSI command
>>>>> + * @scmd: SCSI command to be freed
>>>>> + */
>>>>> +void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
>>>>> +{
>>>>> +    struct request *rq = blk_mq_rq_from_pdu(scmd);
>>>>> +
>>>>> +    if (blk_rq_is_internal(rq))
>>>>> +        blk_mq_free_request(rq);
>>>>> +}
>>>>> +EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);
>>>>
>>>> How about triggering a warning for the !blk_rq_is_internal(rq) case
>>>> instead of silently ignoring regular SCSI commands?
>>>>
>>> That's by design.
>>> Some drivers have a common routine for freeing up commands, so it'd be
>>> quite tricky to separate these two cases out at the driver level.
>>> So it's far easier to call the common routine for all commands, and
>>> let this function do the right thing for all commands.
>>
>> That sounds fair to me, but is an example available in this patch series
>> of a call to scsi_put_internal_cmd() from such a common routine? It
>> seems to me that all calls to scsi_put_internal_cmd() introduced in this
>> patch series happen from code paths that handle internal commands only?
>>
> aacraid.
> The function aac_fib_free() is called unconditionally for every fib, and
> doesn't have the means to differentiate between 'normal' and 'internal'
> commands.

Please make scsi_put_internal_cmd() complain if it is invoked for
anything else than an internal command and surround the
scsi_put_internal_cmd() call in aacraid with if (blk_rq_is_internal(rq))
{ ... }.

Thanks,

Bart.
diff mbox series

Patch

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 0ba7a65e7c8d..bd378e1bd3fc 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1903,6 +1903,47 @@  void scsi_mq_destroy_tags(struct Scsi_Host *shost)
 	blk_mq_free_tag_set(&shost->tag_set);
 }
 
+/**
+ * scsi_get_internal_cmd - allocate an intenral SCSI command
+ * @sdev: SCSI device from which to allocate the command
+ * @data_direction: Data direction for the allocated command
+ * @op_flags: request allocation flags
+ *
+ * Allocates a SCSI command for internal LLDD use.
+ */
+struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
+					int data_direction, int op_flags)
+{
+	struct request *rq;
+	struct scsi_cmnd *scmd;
+	blk_mq_req_flags_t flags = 0;
+	unsigned int op = REQ_INTERNAL | op_flags;
+
+	op |= (data_direction == DMA_TO_DEVICE) ?
+		REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN;
+	rq = blk_mq_alloc_request(sdev->request_queue, op, flags);
+	if (IS_ERR(rq))
+		return NULL;
+	scmd = blk_mq_rq_to_pdu(rq);
+	scmd->request = rq;
+	scmd->device = sdev;
+	return scmd;
+}
+EXPORT_SYMBOL_GPL(scsi_get_internal_cmd);
+
+/**
+ * scsi_put_internal_cmd - free an internal SCSI command
+ * @scmd: SCSI command to be freed
+ */
+void scsi_put_internal_cmd(struct scsi_cmnd *scmd)
+{
+	struct request *rq = blk_mq_rq_from_pdu(scmd);
+
+	if (blk_rq_is_internal(rq))
+		blk_mq_free_request(rq);
+}
+EXPORT_SYMBOL_GPL(scsi_put_internal_cmd);
+
 /**
  * scsi_device_from_queue - return sdev associated with a request_queue
  * @q: The request queue to return the sdev from
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index bc5909033d13..bd1e52213d65 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -460,6 +460,9 @@  static inline int scsi_execute_req(struct scsi_device *sdev,
 	return scsi_execute(sdev, cmd, data_direction, buffer,
 		bufflen, NULL, sshdr, timeout, retries,  0, 0, resid);
 }
+struct scsi_cmnd *scsi_get_internal_cmd(struct scsi_device *sdev,
+					int data_direction, int op_flags);
+void scsi_put_internal_cmd(struct scsi_cmnd *scmd);
 extern void sdev_disable_disk_events(struct scsi_device *sdev);
 extern void sdev_enable_disk_events(struct scsi_device *sdev);
 extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t);