@samitouri / QOSamiQemu / commits / 619c2da19a

hw/ufs: Keep MCQ SQs alive while requests are outstanding

MCQ requests are allocated with their SQ, but can remain in flight on the CQ list or in the SCSI layer after leaving the SQ free list. Reject runtime SQ deletion while any request is still outstanding, and use separate teardown helpers so device exit can still release MCQ queues after child devices have been unrealized. Fixes: 5c079578d2e ("hw/ufs: Add support MCQ of UFSHCI 4.0") Cc: qemu-stable@nongnu.org Signed-off-by: Jeuk Kim <jeuk20.kim@samsung.com>

Jeuk Kim committed May 6, 2026 at 13:50 UTC 619c2da19a05668dabe7912afb789e50b8635c4d
2 files changed +43 -7
hw/ufs/trace-events
+1
@@ -44,6 +44,7 @@ ufs_err_mcq_create_sq_invalid_size(uint8_t qid) "invalid mcq sq size for sqid %"
44 ufs_err_mcq_create_sq_already_exists(uint8_t qid) "mcq sqid %"PRIu8 "already exists"
45 ufs_err_mcq_delete_sq_invalid_sqid(uint8_t qid) "invalid mcq sqid %"PRIu8""
46 ufs_err_mcq_delete_sq_not_exists(uint8_t qid) "mcq sqid %"PRIu8 "not exists"
47 +ufs_err_mcq_delete_sq_busy(uint8_t qid) "mcq sqid %"PRIu8" has outstanding requests"
48 ufs_err_mcq_create_cq_invalid_cqid(uint8_t qid) "invalid mcq cqid %"PRIu8""
49 ufs_err_mcq_create_cq_invalid_size(uint8_t qid) "invalid mcq cq size for cqid %"PRIu8""
50 ufs_err_mcq_create_cq_already_exists(uint8_t qid) "mcq cqid %"PRIu8 "already exists"
hw/ufs/ufs.c
+42 -7
@@ -556,6 +556,31 @@ static bool ufs_mcq_create_sq(UfsHc *u, uint8_t qid, uint32_t attr)
556 return true;
557 }
558
559 +static bool ufs_mcq_sq_has_outstanding_req(UfsSq *sq)
560 +{
561 + UfsRequest *req;
562 + uint16_t free_reqs = 0;
563 +
564 + QTAILQ_FOREACH(req, &sq->req_list, entry)
565 + {
566 + free_reqs++;
567 + }
568 +
569 + return free_reqs != sq->size;
570 +}
571 +
572 +static void ufs_mcq_free_sq(UfsSq *sq)
573 +{
574 + qemu_bh_delete(sq->bh);
575 +
576 + for (int i = 0; i < sq->size; i++) {
577 + ufs_clear_req(&sq->req[i]);
578 + }
579 +
580 + g_free(sq->req);
581 + g_free(sq);
582 +}
583 +
584 static bool ufs_mcq_delete_sq(UfsHc *u, uint8_t qid)
585 {
586 UfsSq *sq;
@@ -572,9 +597,12 @@ static bool ufs_mcq_delete_sq(UfsHc *u, uint8_t qid)
597
598 sq = u->sq[qid];
599
575 - qemu_bh_delete(sq->bh);
576 - g_free(sq->req);
577 - g_free(sq);
600 + if (ufs_mcq_sq_has_outstanding_req(sq)) {
601 + trace_ufs_err_mcq_delete_sq_busy(qid);
602 + return false;
603 + }
604 +
605 + ufs_mcq_free_sq(sq);
606 u->sq[qid] = NULL;
607 return true;
608 }
@@ -617,6 +645,12 @@ static bool ufs_mcq_create_cq(UfsHc *u, uint8_t qid, uint32_t attr)
645 return true;
646 }
647
648 +static void ufs_mcq_free_cq(UfsCq *cq)
649 +{
650 + qemu_bh_delete(cq->bh);
651 + g_free(cq);
652 +}
653 +
654 static bool ufs_mcq_delete_cq(UfsHc *u, uint8_t qid)
655 {
656 UfsCq *cq;
@@ -640,8 +674,7 @@ static bool ufs_mcq_delete_cq(UfsHc *u, uint8_t qid)
674
675 cq = u->cq[qid];
676
643 - qemu_bh_delete(cq->bh);
644 - g_free(cq);
677 + ufs_mcq_free_cq(cq);
678 u->cq[qid] = NULL;
679 return true;
680 }
@@ -1884,12 +1917,14 @@ static void ufs_exit(PCIDevice *pci_dev)
1917
1918 for (int i = 0; i < ARRAY_SIZE(u->sq); i++) {
1919 if (u->sq[i]) {
1887 - ufs_mcq_delete_sq(u, i);
1920 + ufs_mcq_free_sq(u->sq[i]);
1921 + u->sq[i] = NULL;
1922 }
1923 }
1924 for (int i = 0; i < ARRAY_SIZE(u->cq); i++) {
1925 if (u->cq[i]) {
1892 - ufs_mcq_delete_cq(u, i);
1926 + ufs_mcq_free_cq(u->cq[i]);
1927 + u->cq[i] = NULL;
1928 }
1929 }
1930 }