From nobody Wed Apr 8 11:50:29 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6BC4EFA3741 for ; Tue, 25 Oct 2022 10:11:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232354AbiJYKLh (ORCPT ); Tue, 25 Oct 2022 06:11:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232072AbiJYKKn (ORCPT ); Tue, 25 Oct 2022 06:10:43 -0400 Received: from frasgout.his.huawei.com (frasgout.his.huawei.com [185.176.79.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F385122BF8; Tue, 25 Oct 2022 03:03:35 -0700 (PDT) Received: from fraeml703-chm.china.huawei.com (unknown [172.18.147.206]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4MxSCm4KSQz67mY4; Tue, 25 Oct 2022 18:02:12 +0800 (CST) Received: from lhrpeml500003.china.huawei.com (7.191.162.67) by fraeml703-chm.china.huawei.com (10.206.15.52) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.2375.31; Tue, 25 Oct 2022 12:03:33 +0200 Received: from localhost.localdomain (10.69.192.58) by lhrpeml500003.china.huawei.com (7.191.162.67) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.31; Tue, 25 Oct 2022 11:03:30 +0100 From: John Garry To: , , , , , , , CC: , , , , , , , John Garry Subject: [PATCH RFC v3 5/7] ata: libata: Queue ATA internal commands as requests Date: Tue, 25 Oct 2022 18:32:54 +0800 Message-ID: <1666693976-181094-6-git-send-email-john.garry@huawei.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1666693976-181094-1-git-send-email-john.garry@huawei.com> References: <1666693976-181094-1-git-send-email-john.garry@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.69.192.58] X-ClientProxiedBy: dggems704-chm.china.huawei.com (10.3.19.181) To lhrpeml500003.china.huawei.com (7.191.162.67) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Follow the normal path for requests and queue through the block layer. Since we now have a scsi_cmnd for every ATA queued command, we can delete ata_port.qcmd[]. The ATA queue command iterators are fixed to use the blk-mq tagset iters. For libsas it's hard to differentiate between a reserved request which is a libata internal command and SATA "tmf". Normally we can use the sas_task "is dev sata" check, but that does not work. For now just check the rq->end_io pointer. At this point all libsas sas_task should have a rq associated, so let's WARN just in case. Signed-off-by: John Garry --- drivers/ata/libata-core.c | 141 +++++++++++++++------------- drivers/ata/libata-eh.c | 11 ++- drivers/ata/libata-sata.c | 2 +- drivers/ata/libata-scsi.c | 5 +- drivers/scsi/libsas/sas_scsi_host.c | 15 ++- include/linux/libata.h | 48 +++++++++- include/scsi/libsas.h | 8 +- 7 files changed, 151 insertions(+), 79 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index d3ce5c383f3a..72bb1b629264 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1440,9 +1440,21 @@ EXPORT_SYMBOL_GPL(ata_id_xfermask); =20 static void ata_qc_complete_internal(struct ata_queued_cmd *qc) { - struct completion *waiting =3D qc->private_data; + struct scsi_cmnd *scmd =3D qc->scsicmd; + + scsi_done(scmd); +} + +static enum rq_end_io_ret ata_internal_end_rq(struct request *rq, + blk_status_t error) +{ + struct completion *waiting =3D rq->end_io_data; + + rq->end_io_data =3D (void *)(uintptr_t)error; =20 complete(waiting); + + return RQ_END_IO_NONE; } =20 /** @@ -1450,9 +1462,9 @@ static void ata_qc_complete_internal(struct ata_queue= d_cmd *qc) * @dev: Device to which the command is sent * @tf: Taskfile registers for the command and the result * @cdb: CDB for packet command + * @buf: Data buffer of the command + * @buflen: Length of data buffer * @dma_dir: Data transfer direction of the command - * @sgl: sg list for the data buffer of the command - * @n_elem: Number of sg entries * @timeout: Timeout in msecs (0 for default) * * Executes libata internal command with timeout. @tf contains @@ -1469,50 +1481,65 @@ static void ata_qc_complete_internal(struct ata_que= ued_cmd *qc) */ static unsigned ata_exec_internal_sg(struct ata_device *dev, struct ata_taskfile *tf, const u8 *cdb, - int dma_dir, struct scatterlist *sgl, - unsigned int n_elem, unsigned int timeout) + int dma_dir, void *buf, + unsigned int buflen, unsigned int timeout) { struct ata_link *link =3D dev->link; struct ata_port *ap =3D link->ap; + struct scsi_device *sdev =3D dev->sdev; u8 command =3D tf->command; int auto_timeout =3D 0; struct ata_queued_cmd *qc; - unsigned int preempted_tag; - u32 preempted_sactive; - u64 preempted_qc_active; - int preempted_nr_active_links; DECLARE_COMPLETION_ONSTACK(wait); unsigned long flags; unsigned int err_mask; - int rc; + struct scsi_cmnd *scmd; + struct request *rq; =20 - spin_lock_irqsave(ap->lock, flags); + if (!sdev) + return AC_ERR_OTHER; =20 - /* no internal command while frozen */ - if (ap->pflags & ATA_PFLAG_FROZEN) { - spin_unlock_irqrestore(ap->lock, flags); - return AC_ERR_SYSTEM; + rq =3D scsi_alloc_request(sdev->request_queue, + dma_dir =3D=3D DMA_TO_DEVICE ? + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, + BLK_MQ_REQ_RESERVED); + if (IS_ERR(rq)) + return AC_ERR_OTHER; + + + if (!timeout) { + if (ata_probe_timeout) + timeout =3D ata_probe_timeout * 1000; + else { + timeout =3D ata_internal_cmd_timeout(dev, command); + auto_timeout =3D 1; + } } =20 - /* initialize internal qc */ - qc =3D __ata_qc_from_tag(ap, ATA_TAG_INTERNAL); + scmd =3D blk_mq_rq_to_pdu(rq); + scmd->allowed =3D 0; + rq->timeout =3D msecs_to_jiffies(timeout); + rq->rq_flags |=3D RQF_QUIET; + scmd->device =3D sdev; + + qc =3D ata_scmd_to_qc(scmd); + + if (buflen) { + int ret =3D blk_rq_map_kern(sdev->request_queue, rq, + buf, buflen, GFP_NOIO); + if (ret) { + blk_mq_free_request(rq); + return AC_ERR_OTHER; + } + } =20 qc->tag =3D ATA_TAG_INTERNAL; qc->hw_tag =3D 0; - qc->scsicmd =3D NULL; + qc->scsicmd =3D scmd; qc->ap =3D ap; qc->dev =3D dev; ata_qc_reinit(qc); =20 - preempted_tag =3D link->active_tag; - preempted_sactive =3D link->sactive; - preempted_qc_active =3D ap->qc_active; - preempted_nr_active_links =3D ap->nr_active_links; - link->active_tag =3D ATA_TAG_POISON; - link->sactive =3D 0; - ap->qc_active =3D 0; - ap->nr_active_links =3D 0; - /* prepare & issue qc */ qc->tf =3D *tf; if (cdb) @@ -1525,44 +1552,26 @@ static unsigned ata_exec_internal_sg(struct ata_dev= ice *dev, =20 qc->flags |=3D ATA_QCFLAG_RESULT_TF; qc->dma_dir =3D dma_dir; - if (dma_dir !=3D DMA_NONE) { - unsigned int i, buflen =3D 0; - struct scatterlist *sg; - - for_each_sg(sgl, sg, n_elem, i) - buflen +=3D sg->length; =20 - ata_sg_init(qc, sgl, n_elem); - qc->nbytes =3D buflen; - } - - qc->private_data =3D &wait; + qc->private_data =3D ap; qc->complete_fn =3D ata_qc_complete_internal; =20 - ata_qc_issue(qc); + rq->end_io_data =3D &wait; + rq->end_io =3D ata_internal_end_rq; =20 - spin_unlock_irqrestore(ap->lock, flags); - - if (!timeout) { - if (ata_probe_timeout) - timeout =3D ata_probe_timeout * 1000; - else { - timeout =3D ata_internal_cmd_timeout(dev, command); - auto_timeout =3D 1; - } - } + blk_execute_rq_nowait(rq, true); =20 if (ap->ops->error_handler) ata_eh_release(ap); =20 - rc =3D wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout)); + wait_for_completion(&wait); =20 if (ap->ops->error_handler) ata_eh_acquire(ap); =20 ata_sff_flush_pio_task(ap); =20 - if (!rc) { + if (rq->rq_flags & RQF_TIMED_OUT) { spin_lock_irqsave(ap->lock, flags); =20 /* We're racing with irq here. If we lose, the @@ -1610,13 +1619,15 @@ static unsigned ata_exec_internal_sg(struct ata_dev= ice *dev, err_mask =3D qc->err_mask; =20 ata_qc_free(qc); - link->active_tag =3D preempted_tag; - link->sactive =3D preempted_sactive; - ap->qc_active =3D preempted_qc_active; - ap->nr_active_links =3D preempted_nr_active_links; + link->active_tag =3D link->preempted_tag; + link->sactive =3D link->preempted_sactive; + ap->qc_active =3D ap->preempted_qc_active; + ap->nr_active_links =3D ap->preempted_nr_active_links; =20 spin_unlock_irqrestore(ap->lock, flags); =20 + blk_mq_free_request(rq); + if ((err_mask & AC_ERR_TIMEOUT) && auto_timeout) ata_internal_cmd_timed_out(dev, command); =20 @@ -1647,18 +1658,20 @@ unsigned ata_exec_internal(struct ata_device *dev, int dma_dir, void *buf, unsigned int buflen, unsigned int timeout) { - struct scatterlist *psg =3D NULL, sg; - unsigned int n_elem =3D 0; + /* buf may not be aligned, so copy to/from an aligned buffer */ + void *tmpbuf =3D kmemdup(buf, buflen, GFP_KERNEL); + unsigned res; =20 - if (dma_dir !=3D DMA_NONE) { - WARN_ON(!buf); - sg_init_one(&sg, buf, buflen); - psg =3D &sg; - n_elem++; - } + if (!tmpbuf) + return AC_ERR_OTHER; =20 - return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem, + res =3D ata_exec_internal_sg(dev, tf, cdb, dma_dir, tmpbuf, buflen, timeout); + + memcpy(buf, tmpbuf, buflen); + kfree(tmpbuf); + + return res; } =20 /** diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 1ed5b1b64792..f25f60dff5a2 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -604,6 +604,9 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host,= struct ata_port *ap, struct ata_queued_cmd *qc; =20 ata_qc_for_each_raw(ap, qc, i) { + if (!qc) + continue; + if (qc->flags & ATA_QCFLAG_ACTIVE && qc->scsicmd =3D=3D scmd) break; @@ -1946,7 +1949,7 @@ static void ata_eh_link_autopsy(struct ata_link *link) all_err_mask |=3D ehc->i.err_mask; =20 ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!qc || (qc->flags & ATA_QCFLAG_FAILED) || ata_dev_phys_link(qc->dev) !=3D link) continue; =20 @@ -2223,7 +2226,7 @@ static void ata_eh_link_report(struct ata_link *link) desc =3D ehc->i.desc; =20 ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!qc || !(qc->flags & ATA_QCFLAG_FAILED) || ata_dev_phys_link(qc->dev) !=3D link || ((qc->flags & ATA_QCFLAG_QUIET) && qc->err_mask =3D=3D AC_ERR_DEV)) @@ -2289,7 +2292,7 @@ static void ata_eh_link_report(struct ata_link *link) char data_buf[20] =3D ""; char cdb_buf[70] =3D ""; =20 - if (!(qc->flags & ATA_QCFLAG_FAILED) || + if (!qc || !(qc->flags & ATA_QCFLAG_FAILED) || ata_dev_phys_link(qc->dev) !=3D link || !qc->err_mask) continue; =20 @@ -3795,7 +3798,7 @@ void ata_eh_finish(struct ata_port *ap) =20 /* retry or finish qcs */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!qc || !(qc->flags & ATA_QCFLAG_FAILED)) continue; =20 if (qc->err_mask) { diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index e8b828c56542..f03feccb22df 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -1432,7 +1432,7 @@ void ata_eh_analyze_ncq_error(struct ata_link *link) =20 /* has LLDD analyzed already? */ ata_qc_for_each_raw(ap, qc, tag) { - if (!(qc->flags & ATA_QCFLAG_FAILED)) + if (!qc || !(qc->flags & ATA_QCFLAG_FAILED)) continue; =20 if (qc->err_mask) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index cbf266c9d4c2..64c6ab33cdc8 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -657,7 +657,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct at= a_device *dev, tag =3D scsi_cmd_to_rq(cmd)->tag; } =20 - qc =3D __ata_qc_from_tag(ap, tag); + qc =3D ata_scmd_to_qc(cmd); qc->tag =3D qc->hw_tag =3D tag; qc->ap =3D ap; qc->dev =3D dev; @@ -4007,7 +4007,8 @@ unsigned int ata_scsi_queue_internal(struct scsi_cmnd= *scmd, goto did_err; =20 /* initialize internal qc */ - qc =3D __ata_qc_from_tag(ap, ATA_TAG_INTERNAL); + qc =3D ata_scmd_to_qc(scmd); + qc->scsicmd =3D scmd; link->preempted_tag =3D link->active_tag; link->preempted_sactive =3D link->sactive; ap->preempted_qc_active =3D ap->qc_active; diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_= scsi_host.c index 9d2122e65fba..008f57931a57 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c @@ -163,8 +163,21 @@ int sas_queuecommand_internal(struct Scsi_Host *shost,= struct scsi_cmnd *cmnd) struct sas_ha_struct *ha =3D SHOST_TO_SAS_HA(shost); struct sas_internal *i =3D to_sas_internal(ha->core.shost->transportt); struct request *rq =3D blk_mq_rq_from_pdu(cmnd); - struct sas_task *task =3D rq->end_io_data; + struct sas_task *task; + + /* uh, I can't see a better check for now */ + if (rq->end_io !=3D sas_blk_end_sync_rq) { + struct ata_queued_cmd *qc =3D ata_scmd_to_qc(cmnd); + struct ata_port *ap =3D qc->ap; + int res; + + spin_lock_irq(ap->lock); + res =3D ata_sas_queuecmd(cmnd, ap); + spin_unlock_irq(ap->lock); + return res; + } =20 + task =3D rq->end_io_data; ASSIGN_SAS_TASK(cmnd, task); =20 return i->dft->lldd_execute_task(task, GFP_KERNEL); diff --git a/include/linux/libata.h b/include/linux/libata.h index d5a15d1a5c4d..613a8b644306 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -818,7 +819,6 @@ struct ata_port { unsigned int udma_mask; unsigned int cbl; /* cable type; ATA_CBL_xxx */ =20 - struct ata_queued_cmd qcmd[ATA_MAX_QUEUE + 1]; u64 qc_active; int nr_active_links; /* #links with active qcs */ =20 @@ -1398,6 +1398,7 @@ extern const struct attribute_group *ata_common_sdev_= groups[]; .max_sectors =3D ATA_MAX_SECTORS_LBA48,\ .reserved_queuecommand =3D ata_internal_queuecommand,\ .cmd_size =3D sizeof(struct ata_queued_cmd),\ + .nr_reserved_cmds =3D 1,\ .reserved_timedout =3D ata_internal_timeout,\ .init_cmd_priv =3D ata_init_cmd_priv =20 @@ -1750,11 +1751,52 @@ static inline void ata_qc_set_polling(struct ata_qu= eued_cmd *qc) qc->tf.ctl |=3D ATA_NIEN; } =20 +static inline struct ata_queued_cmd *ata_scmd_to_qc(struct scsi_cmnd *scmd) +{ + return (struct ata_queued_cmd *)(scmd + 1); +} + +struct ata_iter_data { + unsigned int tag; + struct ata_queued_cmd **qc; +}; + +static inline bool ata_check_qc_inflight(struct request *rq, void *priv) +{ + struct ata_iter_data *data =3D priv; + struct scsi_cmnd *scmd =3D blk_mq_rq_to_pdu(rq); + struct ata_queued_cmd *qc =3D ata_scmd_to_qc(scmd); + + if (qc->tag =3D=3D data->tag) { + *(data->qc) =3D qc; + return false; + } + + return true; +} + static inline struct ata_queued_cmd *__ata_qc_from_tag(struct ata_port *ap, unsigned int tag) { - if (ata_tag_valid(tag)) - return &ap->qcmd[tag]; + struct ata_link *link; + struct Scsi_Host *shost =3D ap->scsi_host; + + ata_for_each_link(link, ap, EDGE) { + struct ata_device *dev; + + ata_for_each_dev(dev, link, ALL) { + struct ata_queued_cmd *qc =3D NULL; + struct ata_iter_data data =3D { + .tag =3D tag, + .qc =3D &qc, + }; + blk_mq_tagset_busy_iter(&shost->tag_set, + ata_check_qc_inflight, &data); + if (qc) + return qc; + } + } + return NULL; } =20 diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h index f903be5895a9..0272116d73fc 100644 --- a/include/scsi/libsas.h +++ b/include/scsi/libsas.h @@ -644,15 +644,15 @@ static inline struct request *sas_task_find_rq(struct= sas_task *task) { struct scsi_cmnd *scmd; =20 - if (!task->slow_task && task->task_proto & SAS_PROTOCOL_STP_ALL) { + if (task->slow_task || !(task->task_proto & SAS_PROTOCOL_STP_ALL)) { + scmd =3D task->uldd_task; + } else { struct ata_queued_cmd *qc =3D task->uldd_task; =20 scmd =3D qc ? qc->scsicmd : NULL; - } else { - scmd =3D task->uldd_task; } =20 - if (!scmd) + if (WARN_ON_ONCE(!scmd)) return NULL; =20 return scsi_cmd_to_rq(scmd); --=20 2.35.3