libata: Improve ATA queued command allocation
Improve ATA queued command allocation as follows: - For attaining a qc tag for a SAS host we need to allocate a bit in ata_port.sas_tag_allocated bitmap. However we already have a unique tag per device in range [0, ATA_MAX_QUEUE -1] in the scsi cmnd budget token, so just use that instead. - It is a bit pointless to have ata_qc_new_init() in libata-core.c since it pokes scsi internals, so inline it in ata_scsi_qc_new() (in libata-scsi.c). Also update Doc accordingly. - Use standard SCSI helpers set_host_byte() and set_status_byte() in ata_scsi_qc_new(). Christoph Hellwig originally contributed the change to inline ata_qc_new_init(). Signed-off-by: John Garry <john.garry@huawei.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
This commit is contained in:
parent
c956b92ee1
commit
4f1a22ee7b
|
@ -424,12 +424,6 @@ How commands are issued
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
Internal commands
|
Internal commands
|
||||||
First, qc is allocated and initialized using :c:func:`ata_qc_new_init`.
|
|
||||||
Although :c:func:`ata_qc_new_init` doesn't implement any wait or retry
|
|
||||||
mechanism when qc is not available, internal commands are currently
|
|
||||||
issued only during initialization and error recovery, so no other
|
|
||||||
command is active and allocation is guaranteed to succeed.
|
|
||||||
|
|
||||||
Once allocated qc's taskfile is initialized for the command to be
|
Once allocated qc's taskfile is initialized for the command to be
|
||||||
executed. qc currently has two mechanisms to notify completion. One
|
executed. qc currently has two mechanisms to notify completion. One
|
||||||
is via ``qc->complete_fn()`` callback and the other is completion
|
is via ``qc->complete_fn()`` callback and the other is completion
|
||||||
|
@ -447,11 +441,6 @@ SCSI commands
|
||||||
translated. No qc is involved in processing a simulated scmd. The
|
translated. No qc is involved in processing a simulated scmd. The
|
||||||
result is computed right away and the scmd is completed.
|
result is computed right away and the scmd is completed.
|
||||||
|
|
||||||
For a translated scmd, :c:func:`ata_qc_new_init` is invoked to allocate a
|
|
||||||
qc and the scmd is translated into the qc. SCSI midlayer's
|
|
||||||
completion notification function pointer is stored into
|
|
||||||
``qc->scsidone``.
|
|
||||||
|
|
||||||
``qc->complete_fn()`` callback is used for completion notification. ATA
|
``qc->complete_fn()`` callback is used for completion notification. ATA
|
||||||
commands use :c:func:`ata_scsi_qc_complete` while ATAPI commands use
|
commands use :c:func:`ata_scsi_qc_complete` while ATAPI commands use
|
||||||
:c:func:`atapi_qc_complete`. Both functions end up calling ``qc->scsidone``
|
:c:func:`atapi_qc_complete`. Both functions end up calling ``qc->scsidone``
|
||||||
|
|
|
@ -4566,42 +4566,6 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
|
||||||
#endif /* __BIG_ENDIAN */
|
#endif /* __BIG_ENDIAN */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ata_qc_new_init - Request an available ATA command, and initialize it
|
|
||||||
* @dev: Device from whom we request an available command structure
|
|
||||||
* @tag: tag
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* None.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
|
|
||||||
{
|
|
||||||
struct ata_port *ap = dev->link->ap;
|
|
||||||
struct ata_queued_cmd *qc;
|
|
||||||
|
|
||||||
/* no command while frozen */
|
|
||||||
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* libsas case */
|
|
||||||
if (ap->flags & ATA_FLAG_SAS_HOST) {
|
|
||||||
tag = ata_sas_allocate_tag(ap);
|
|
||||||
if (tag < 0)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
qc = __ata_qc_from_tag(ap, tag);
|
|
||||||
qc->tag = qc->hw_tag = tag;
|
|
||||||
qc->scsicmd = NULL;
|
|
||||||
qc->ap = ap;
|
|
||||||
qc->dev = dev;
|
|
||||||
|
|
||||||
ata_qc_reinit(qc);
|
|
||||||
|
|
||||||
return qc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_qc_free - free unused ata_queued_cmd
|
* ata_qc_free - free unused ata_queued_cmd
|
||||||
* @qc: Command to complete
|
* @qc: Command to complete
|
||||||
|
@ -4614,19 +4578,9 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
|
||||||
*/
|
*/
|
||||||
void ata_qc_free(struct ata_queued_cmd *qc)
|
void ata_qc_free(struct ata_queued_cmd *qc)
|
||||||
{
|
{
|
||||||
struct ata_port *ap;
|
|
||||||
unsigned int tag;
|
|
||||||
|
|
||||||
WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */
|
|
||||||
ap = qc->ap;
|
|
||||||
|
|
||||||
qc->flags = 0;
|
qc->flags = 0;
|
||||||
tag = qc->tag;
|
if (ata_tag_valid(qc->tag))
|
||||||
if (ata_tag_valid(tag)) {
|
|
||||||
qc->tag = ATA_TAG_POISON;
|
qc->tag = ATA_TAG_POISON;
|
||||||
if (ap->flags & ATA_FLAG_SAS_HOST)
|
|
||||||
ata_sas_free_tag(tag, ap);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void __ata_qc_complete(struct ata_queued_cmd *qc)
|
void __ata_qc_complete(struct ata_queued_cmd *qc)
|
||||||
|
|
|
@ -1268,31 +1268,6 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
|
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
|
||||||
|
|
||||||
int ata_sas_allocate_tag(struct ata_port *ap)
|
|
||||||
{
|
|
||||||
unsigned int max_queue = ap->host->n_tags;
|
|
||||||
unsigned int i, tag;
|
|
||||||
|
|
||||||
for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
|
|
||||||
tag = tag < max_queue ? tag : 0;
|
|
||||||
|
|
||||||
/* the last tag is reserved for internal command. */
|
|
||||||
if (ata_tag_internal(tag))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
|
|
||||||
ap->sas_last_tag = tag;
|
|
||||||
return tag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
|
|
||||||
{
|
|
||||||
clear_bit(tag, &ap->sas_tag_allocated);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sata_async_notification - SATA async notification handler
|
* sata_async_notification - SATA async notification handler
|
||||||
* @ap: ATA port where async notification is received
|
* @ap: ATA port where async notification is received
|
||||||
|
|
|
@ -638,24 +638,48 @@ EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
|
||||||
static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
|
static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
|
||||||
struct scsi_cmnd *cmd)
|
struct scsi_cmnd *cmd)
|
||||||
{
|
{
|
||||||
|
struct ata_port *ap = dev->link->ap;
|
||||||
struct ata_queued_cmd *qc;
|
struct ata_queued_cmd *qc;
|
||||||
|
int tag;
|
||||||
|
|
||||||
qc = ata_qc_new_init(dev, scsi_cmd_to_rq(cmd)->tag);
|
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
|
||||||
if (qc) {
|
goto fail;
|
||||||
qc->scsicmd = cmd;
|
|
||||||
qc->scsidone = scsi_done;
|
|
||||||
|
|
||||||
qc->sg = scsi_sglist(cmd);
|
if (ap->flags & ATA_FLAG_SAS_HOST) {
|
||||||
qc->n_elem = scsi_sg_count(cmd);
|
/*
|
||||||
|
* SAS hosts may queue > ATA_MAX_QUEUE commands so use
|
||||||
if (scsi_cmd_to_rq(cmd)->rq_flags & RQF_QUIET)
|
* unique per-device budget token as a tag.
|
||||||
qc->flags |= ATA_QCFLAG_QUIET;
|
*/
|
||||||
|
if (WARN_ON_ONCE(cmd->budget_token >= ATA_MAX_QUEUE))
|
||||||
|
goto fail;
|
||||||
|
tag = cmd->budget_token;
|
||||||
} else {
|
} else {
|
||||||
cmd->result = (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
|
tag = scsi_cmd_to_rq(cmd)->tag;
|
||||||
scsi_done(cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qc = __ata_qc_from_tag(ap, tag);
|
||||||
|
qc->tag = qc->hw_tag = tag;
|
||||||
|
qc->ap = ap;
|
||||||
|
qc->dev = dev;
|
||||||
|
|
||||||
|
ata_qc_reinit(qc);
|
||||||
|
|
||||||
|
qc->scsicmd = cmd;
|
||||||
|
qc->scsidone = scsi_done;
|
||||||
|
|
||||||
|
qc->sg = scsi_sglist(cmd);
|
||||||
|
qc->n_elem = scsi_sg_count(cmd);
|
||||||
|
|
||||||
|
if (scsi_cmd_to_rq(cmd)->rq_flags & RQF_QUIET)
|
||||||
|
qc->flags |= ATA_QCFLAG_QUIET;
|
||||||
|
|
||||||
return qc;
|
return qc;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
set_host_byte(cmd, DID_OK);
|
||||||
|
set_status_byte(cmd, SAM_STAT_TASK_SET_FULL);
|
||||||
|
scsi_done(cmd);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
|
static void ata_qc_set_pc_nbytes(struct ata_queued_cmd *qc)
|
||||||
|
|
|
@ -44,7 +44,6 @@ static inline void ata_force_cbl(struct ata_port *ap) { }
|
||||||
#endif
|
#endif
|
||||||
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
|
||||||
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
|
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
|
||||||
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
|
|
||||||
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
|
||||||
u64 block, u32 n_block, unsigned int tf_flags,
|
u64 block, u32 n_block, unsigned int tf_flags,
|
||||||
unsigned int tag, int class);
|
unsigned int tag, int class);
|
||||||
|
@ -91,18 +90,6 @@ extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
|
||||||
|
|
||||||
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
|
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
|
||||||
|
|
||||||
/* libata-sata.c */
|
|
||||||
#ifdef CONFIG_SATA_HOST
|
|
||||||
int ata_sas_allocate_tag(struct ata_port *ap);
|
|
||||||
void ata_sas_free_tag(unsigned int tag, struct ata_port *ap);
|
|
||||||
#else
|
|
||||||
static inline int ata_sas_allocate_tag(struct ata_port *ap)
|
|
||||||
{
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
}
|
|
||||||
static inline void ata_sas_free_tag(unsigned int tag, struct ata_port *ap) { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* libata-acpi.c */
|
/* libata-acpi.c */
|
||||||
#ifdef CONFIG_ATA_ACPI
|
#ifdef CONFIG_ATA_ACPI
|
||||||
extern unsigned int ata_acpi_gtf_filter;
|
extern unsigned int ata_acpi_gtf_filter;
|
||||||
|
|
|
@ -820,7 +820,6 @@ struct ata_port {
|
||||||
unsigned int cbl; /* cable type; ATA_CBL_xxx */
|
unsigned int cbl; /* cable type; ATA_CBL_xxx */
|
||||||
|
|
||||||
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE + 1];
|
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE + 1];
|
||||||
unsigned long sas_tag_allocated; /* for sas tag allocation only */
|
|
||||||
u64 qc_active;
|
u64 qc_active;
|
||||||
int nr_active_links; /* #links with active qcs */
|
int nr_active_links; /* #links with active qcs */
|
||||||
unsigned int sas_last_tag; /* track next tag hw expects */
|
unsigned int sas_last_tag; /* track next tag hw expects */
|
||||||
|
|
Loading…
Reference in New Issue