e73a5e8e80
scsi_host_find_tag() is used by the drivers to return a scsi command based on the command tag. Typically it's used from the interrupt handler to fetch the command associated with a value returned from hardware. Some drivers like fnic or qla4xxx, however, also use it also to traverse outstanding commands. With the current implementation scsi_host_find_tag() will return commands even if they are not started (i.e. passed to the driver). This will result in random errors with those drivers. With this patch scsi_host_find_tag() will only return 'started' commands (i.e. commands which have been passed to the drivers) thus avoiding the above issue. The other use cases will be unaffected as the interrupt handler naturally will only ever return 'started' requests. Link: https://lore.kernel.org/r/20200622063022.67891-1-hare@suse.de Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
44 lines
993 B
C
44 lines
993 B
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _SCSI_SCSI_TCQ_H
|
|
#define _SCSI_SCSI_TCQ_H
|
|
|
|
#include <linux/blkdev.h>
|
|
#include <scsi/scsi_cmnd.h>
|
|
#include <scsi/scsi_device.h>
|
|
#include <scsi/scsi_host.h>
|
|
|
|
#define SCSI_NO_TAG (-1) /* identify no tag in use */
|
|
|
|
|
|
#ifdef CONFIG_BLOCK
|
|
/**
|
|
* scsi_host_find_tag - find the tagged command by host
|
|
* @shost: pointer to scsi_host
|
|
* @tag: tag
|
|
*
|
|
* Note: for devices using multiple hardware queues tag must have been
|
|
* generated by blk_mq_unique_tag().
|
|
**/
|
|
static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
|
|
int tag)
|
|
{
|
|
struct request *req = NULL;
|
|
u16 hwq;
|
|
|
|
if (tag == SCSI_NO_TAG)
|
|
return NULL;
|
|
|
|
hwq = blk_mq_unique_tag_to_hwq(tag);
|
|
if (hwq < shost->tag_set.nr_hw_queues) {
|
|
req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq],
|
|
blk_mq_unique_tag_to_tag(tag));
|
|
}
|
|
|
|
if (!req || !blk_mq_request_started(req))
|
|
return NULL;
|
|
return blk_mq_rq_to_pdu(req);
|
|
}
|
|
|
|
#endif /* CONFIG_BLOCK */
|
|
#endif /* _SCSI_SCSI_TCQ_H */
|