From 0cd3c1e7d0201cf9e4dbcac1e0179604f4461062 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Wed, 26 Mar 2025 13:24:08 +0100 Subject: scsi: fix typo in setup_read_ext() This clears the 6th byte of cmd twice rather than setting the 9th byte to 0. Fix it. The only other command that sets the 9th byte is the 64-bit read, so this likely never caused issues in practise. Signed-off-by: Caleb Connolly Reviewed-by: Neil Armstrong --- drivers/scsi/scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index cd0b84c0622..34ac47c03ab 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -90,7 +90,7 @@ static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start, pccb->cmd[6] = 0; pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; pccb->cmd[8] = (unsigned char)blocks & 0xff; - pccb->cmd[6] = 0; + pccb->cmd[9] = 0; pccb->cmdlen = 10; pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", -- cgit v1.3.1 From ffe4e6ab42d2534302be825e49a2d085acf80f30 Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Wed, 26 Mar 2025 13:24:09 +0100 Subject: scsi: sync cache on write We don't have a mechanism to safely shutdown block devices prior to a baord reset or driver removal. Prevent data loss by synchronizing the SCSI cache after every write. In particular this solves the issue of capsule updates looping on some devices because the board resets immediately after deleting the capsule file and this write wouldn't be flushed in time. This may impact NAND wear, but should be negligible given the usecases for disk write in U-Boot. Signed-off-by: Caleb Connolly Reviewed-by: Neil Armstrong --- drivers/scsi/scsi.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 34ac47c03ab..3e556540cae 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -78,6 +78,23 @@ static void scsi_setup_inquiry(struct scsi_cmd *pccb) pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ } +static void scsi_setup_sync_cache(struct scsi_cmd *pccb, lbaint_t start, + unsigned short blocks) +{ + pccb->cmd[0] = SCSI_SYNC_CACHE; + pccb->cmd[1] = 0; + pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff; + pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff; + pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff; + pccb->cmd[5] = (unsigned char)start & 0xff; + pccb->cmd[6] = 0; + pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff; + pccb->cmd[8] = (unsigned char)blocks & 0xff; + pccb->cmd[9] = 0; + pccb->cmdlen = 10; + pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */ +} + static void scsi_setup_read_ext(struct scsi_cmd *pccb, lbaint_t start, unsigned short blocks) { @@ -240,6 +257,12 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, } buf_addr += pccb->datalen; } while (blks != 0); + + /* Flush the SCSI cache so we don't lose data on board reset. */ + scsi_setup_sync_cache(pccb, 0, 0); + if (scsi_exec(bdev, pccb)) + scsi_print_error(pccb); + debug("%s: end startblk " LBAF ", blccnt %x buffer %lX\n", __func__, start, smallblks, buf_addr); return blkcnt; -- cgit v1.3.1 From 77c13f30b67c1a30b33b4dd4820c5a2528c3a3bb Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Wed, 26 Mar 2025 13:24:10 +0100 Subject: ata: ahci: implement SCSI_SYNC_CACHE The SCSI layer now issues a SYNC_CACHE command after every write to ensure there is no data loss due to a board reset after write. Implement support for this command and remove the same logic from the ATA write path to be consistent with other SCSI backends. Ranges are not supported and the whole cache will be flushed in all cases. This was done per iteration in ata_scsiop_read_write(), but it's not clear why this was the case, calling it once for the entire write ought to achieve the same result. Signed-off-by: Caleb Connolly Reviewed-by: Neil Armstrong --- drivers/ata/ahci.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8058d5ff1c3..deb91efd6d2 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -736,17 +736,6 @@ static int ata_scsiop_read_write(struct ahci_uc_priv *uc_priv, is_write ? "WRITE" : "READ"); return -EIO; } - - /* If this transaction is a write, do a following flush. - * Writes in u-boot are so rare, and the logic to know when is - * the last write and do a flush only there is sufficiently - * difficult. Just do a flush after every write. This incurs, - * usually, one extra flush when the rare writes do happen. - */ - if (is_write) { - if (-EIO == ata_io_flush(uc_priv, pccb->target)) - return -EIO; - } user_buffer += transfer_size; user_buffer_size -= transfer_size; blocks -= now_blocks; @@ -846,6 +835,9 @@ static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) case SCSI_INQUIRY: ret = ata_scsiop_inquiry(uc_priv, pccb); break; + case SCSI_SYNC_CACHE: + ret = ata_io_flush(uc_priv, pccb->target); + break; default: printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]); return -ENOTSUPP; -- cgit v1.3.1