fix: READ_CAPACITY command for 12 bytes CDB SCSI device.
authorMinep <zelong56@gmail.com>
Thu, 18 Aug 2022 11:34:03 +0000 (12:34 +0100)
committerMinep <zelong56@gmail.com>
Thu, 18 Aug 2022 12:36:48 +0000 (13:36 +0100)
fix: PACKET command hangs in Virtualbox when try to write readonly drive.
fix: possible null pointer dereference in pcache_commit_all.
chore: attach cdrom into QEMU's IDE bus.

lunaix-os/config/make-debug-tool
lunaix-os/hal/ahci/ahci.c
lunaix-os/hal/ahci/ata.c
lunaix-os/hal/ahci/atapi.c
lunaix-os/includes/hal/ahci/hba.h
lunaix-os/includes/hal/ahci/scsi.h
lunaix-os/kernel/fs/pcache.c
lunaix-os/makefile

index 2376ede1090d1800590496e495bec09d81e035df..061cbc05cd3f3d2c01bfc0878dc23cb272c0fc92 100644 (file)
@@ -9,6 +9,8 @@ QEMU_OPTIONS := -s -S -m 1G \
                                -d cpu_reset \
                                -d trace:ide_dma_cb \
                                -drive id=disk,file="machine/disk0.vdi",if=none \
+                               -drive id=cdrom,file="$(BUILD_DIR)/$(OS_ISO)",readonly=on,if=none,format=raw \
                                -device ahci,id=ahci \
                                -device ide-hd,drive=disk,bus=ahci.0 \
+                               -device ide-cd,drive=cdrom,bus=ahci.1 \
                                -monitor telnet::$(QEMU_MON_PORT),server,nowait &
\ No newline at end of file
index a04bca7e2551661566e04bc3ca188e73f1dbee33..21eaa1df12aeeef891e6011e853c4591cf8cdd85 100644 (file)
@@ -172,7 +172,8 @@ ahci_init()
         port_regs[HBA_RPxCMD] |= HBA_PxCMD_ST;
 
         if (!ahci_init_device(port)) {
-            kprintf(KERROR "fail to init device");
+            kprintf(KERROR "init fail: 0x%x@p%d\n", port->regs[HBA_RPxSIG], i);
+            continue;
         }
 
         block_mount_disk(port->device);
@@ -383,12 +384,20 @@ ahci_init_device(struct hba_port* port)
             * SATA AHCI HBA Spec, Section 5.3.7
             * SCSI Command Reference Manual, Section 3.26
     */
-    struct scsi_cdb16* cdb16 = (struct scsi_cdb16*)cmd_table->atapi_cmd;
 
     sata_create_fis(cmd_fis, ATA_PACKET, 512 << 8, 0);
-    scsi_create_packet16(cdb16, SCSI_READ_CAPACITY_16, 0, 512);
 
-    cdb16->misc1 = 0x10; // service action
+    // for dev use 12 bytes cdb, READ_CAPACITY must use the 10 bytes variation.
+    if (port->device->cbd_size == 12) {
+        struct scsi_cdb12* cdb12 = (struct scsi_cdb12*)cmd_table->atapi_cmd;
+        // ugly tricks to construct 10 byte cdb from 12 byte cdb
+        scsi_create_packet12(cdb12, SCSI_READ_CAPACITY_10, 0, 512 << 8);
+    } else {
+        struct scsi_cdb16* cdb16 = (struct scsi_cdb16*)cmd_table->atapi_cmd;
+        scsi_create_packet16(cdb16, SCSI_READ_CAPACITY_16, 0, 512);
+        cdb16->misc1 = 0x10; // service action
+    }
+
     cmd_header->transferred_size = 0;
     cmd_header->options |= HBA_CMDH_ATAPI;
 
index a77e03b4a87535ee0929911e2a57a5b7485a8a18..118bf1196a8697b6e4a001f66c2196d9e900a3d3 100644 (file)
@@ -9,8 +9,9 @@ void
 sata_read_error(struct hba_port* port)
 {
     uint32_t tfd = port->regs[HBA_RPxTFD];
-    port->device->last_error = (tfd >> 8) & 0xff;
-    port->device->last_status = tfd & 0xff;
+    port->device->last_result.sense_key = (tfd & 0xf000) >> 12;
+    port->device->last_result.error = (tfd & 0x0f00) >> 8;
+    port->device->last_result.status = tfd & 0x00ff;
 }
 
 int
index 85c3bab056291fc0542a4b871d3a27e6708427b5..76c379571e538424d41754c46d479655fb62331b 100644 (file)
@@ -37,8 +37,15 @@ scsi_create_packet16(struct scsi_cdb16* cdb,
 void
 scsi_parse_capacity(struct hba_device* device, uint32_t* parameter)
 {
-    device->max_lba = SCSI_FLIP(*(parameter + 1));
-    device->block_size = SCSI_FLIP(*(parameter + 2));
+    if (device->cbd_size == SCSI_CDB16) {
+        device->max_lba =
+          SCSI_FLIP(*(parameter + 1)) | (SCSI_FLIP(*parameter) << 32);
+        device->block_size = SCSI_FLIP(*(parameter + 2));
+    } else {
+        // for READ_CAPACITY(10)
+        device->max_lba = SCSI_FLIP(*(parameter));
+        device->block_size = SCSI_FLIP(*(parameter + 1));
+    }
 }
 
 int
@@ -90,7 +97,7 @@ __scsi_buffer_io(struct hba_device* dev,
     while (retries < MAX_RETRY) {
         port->regs[HBA_RPxCI] = bitmask;
 
-        wait_until(!(port->regs[HBA_RPxCI] & bitmask));
+        wait_until_expire(!(port->regs[HBA_RPxCI] & bitmask), 1000000);
 
         if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) {
             // 有错误
index c868c6ff1e740c70323ae2783626cb9b960f41b9..92a2b5a382518417f423a3f8ecce38416d318dd7 100644 (file)
@@ -33,6 +33,8 @@
 #define HBA_PxINTR_DMA (1 << 2)
 #define HBA_PxINTR_DHR (1)
 #define HBA_PxINTR_DPS (1 << 5)
+#define HBA_PxINTR_TFEE (1 << 30)
+#define HBA_PxINTR_IFE (1 << 27)
 #define HBA_PxTFD_ERR (1)
 #define HBA_PxTFD_BSY (1 << 7)
 #define HBA_PxTFD_DRQ (1 << 3)
@@ -100,8 +102,13 @@ struct hba_device
     uint32_t block_size;
     uint64_t wwn;
     uint8_t cbd_size;
-    uint8_t last_error;
-    uint8_t last_status;
+    struct
+    {
+        uint8_t sense_key;
+        uint8_t error;
+        uint8_t status;
+        uint8_t reserve;
+    } last_result;
     uint32_t alignment_offset;
     uint32_t block_per_sec;
     uint32_t capabilities;
index 0635614abec7d7bfd696a929e5ee980a1aaa7076..fee899fa916ebb72b9b2c347537ce9ebf89ef94c 100644 (file)
@@ -14,6 +14,9 @@
 #define SCSI_WRITE_BLOCKS_16 0x8a
 #define SCSI_WRITE_BLOCKS_12 0xaa
 
+#define SCSI_CDB16 16
+#define SCSI_CDB12 12
+
 struct scsi_cdb12
 {
     uint8_t opcode;
index 9d883f90485402f702617dbd8a721040315d925b..8ef8fc8aa4359a95a15d8653d0d361f6a8bc0ff3 100644 (file)
@@ -189,6 +189,10 @@ pcache_commit(struct v_inode* inode, struct pcache_pg* page)
 void
 pcache_commit_all(struct v_inode* inode)
 {
+    if (!inode->pg_cache) {
+        return;
+    }
+
     struct pcache* cache = inode->pg_cache;
     struct pcache_pg *pos, *n;
 
index 879304b38d92c155836316dccd879d81bc14f4b5..20de158c0bf57ad9cf353d21a00a71796870ba0d 100644 (file)
@@ -51,20 +51,20 @@ clean:
        @sleep 1
 
 run: $(BUILD_DIR)/$(OS_ISO)
-       @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS)
+       @qemu-system-i386 $(QEMU_OPTIONS)
        @sleep 1
        @telnet 127.0.0.1 $(QEMU_MON_PORT)
 
 debug-qemu: all-debug
        @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
-       @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS)
+       @qemu-system-i386 $(QEMU_OPTIONS)
        @sleep 1
        @$(QEMU_MON_TERM) -- telnet 127.0.0.1 $(QEMU_MON_PORT)
        @gdb -s $(BUILD_DIR)/kernel.dbg -ex "target remote localhost:1234"
 
 debug-qemu-vscode: all-debug
        @i686-elf-objcopy --only-keep-debug $(BIN_DIR)/$(OS_BIN) $(BUILD_DIR)/kernel.dbg
-       @qemu-system-i386 -cdrom $(BUILD_DIR)/$(OS_ISO) $(QEMU_OPTIONS)
+       @qemu-system-i386 $(QEMU_OPTIONS)
        @sleep 0.5
        @telnet 127.0.0.1 $(QEMU_MON_PORT)