From: Minep Date: Thu, 18 Aug 2022 15:31:23 +0000 (+0100) Subject: refactor: send the command with retry and error detection X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/commitdiff_plain/c4d08ac5260bb26db10bcfd9dc6fd2db60efebe9?ds=sidebyside refactor: send the command with retry and error detection chore: other refactorings --- diff --git a/lunaix-os/hal/ahci/ahci.c b/lunaix-os/hal/ahci/ahci.c index 21eaa1d..41ebc86 100644 --- a/lunaix-os/hal/ahci/ahci.c +++ b/lunaix-os/hal/ahci/ahci.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include @@ -158,8 +157,7 @@ ahci_init() /* 初始化端口,并置于就绪状态 */ port_regs[HBA_RPxCI] = 0; - // 需要通过全部置位去清空这些寄存器(相当的奇怪……) - port_regs[HBA_RPxSERR] = -1; + hba_clear_reg(port_regs[HBA_RPxSERR]); hba.ports[i] = port; @@ -176,6 +174,11 @@ ahci_init() continue; } + kprintf(KINFO "sata%d: %s (%s)\n", + i, + port->device->model, + port->device->serial_num); + block_mount_disk(port->device); } } @@ -312,16 +315,11 @@ ahci_init_device(struct hba_port* port) // mask DHR interrupt port->regs[HBA_RPxIE] &= ~HBA_PxINTR_DHR; - // 确保端口是空闲的 - wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY))); - // 预备DMA接收缓存,用于存放HBA传回的数据 uint16_t* data_in = (uint16_t*)valloc_dma(512); int slot = hba_prepare_cmd(port, &cmd_table, &cmd_header, data_in, 512); - // 清空任何待响应的中断 - port->regs[HBA_RPxIS] = 0; port->device = vzalloc(sizeof(struct hba_device)); port->device->port = port; @@ -338,14 +336,7 @@ ahci_init_device(struct hba_port* port) sata_create_fis(cmd_fis, ATA_IDENTIFY_PAKCET_DEVICE, 0, 0); } - // PxCI寄存器置位,告诉HBA这儿有个数据需要发送到SATA端口 - port->regs[HBA_RPxCI] = (1 << slot); - - wait_until(!(port->regs[HBA_RPxCI] & (1 << slot))); - - if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { - // 有错误 - sata_read_error(port); + if (!ahci_try_send(port, slot)) { goto fail; } @@ -388,7 +379,7 @@ ahci_init_device(struct hba_port* port) sata_create_fis(cmd_fis, ATA_PACKET, 512 << 8, 0); // for dev use 12 bytes cdb, READ_CAPACITY must use the 10 bytes variation. - if (port->device->cbd_size == 12) { + if (port->device->cbd_size == SCSI_CDB12) { 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); @@ -401,12 +392,7 @@ ahci_init_device(struct hba_port* port) cmd_header->transferred_size = 0; cmd_header->options |= HBA_CMDH_ATAPI; - port->regs[HBA_RPxCI] = (1 << slot); - wait_until(!(port->regs[HBA_RPxCI] & (1 << slot))); - - if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { - // 有错误 - sata_read_error(port); + if (!ahci_try_send(port, slot)) { goto fail; } @@ -414,7 +400,6 @@ ahci_init_device(struct hba_port* port) done: // reset interrupt status and unmask D2HR interrupt - port->regs[HBA_RPxIS] = -1; port->regs[HBA_RPxIE] |= HBA_PxINTR_DHR; achi_register_ops(port); @@ -424,7 +409,6 @@ done: return 1; fail: - port->regs[HBA_RPxIS] = -1; port->regs[HBA_RPxIE] |= HBA_PxINTR_DHR; vfree_dma(data_in); vfree_dma(cmd_table); diff --git a/lunaix-os/hal/ahci/ata.c b/lunaix-os/hal/ahci/ata.c index 118bf11..845f420 100644 --- a/lunaix-os/hal/ahci/ata.c +++ b/lunaix-os/hal/ahci/ata.c @@ -1,3 +1,4 @@ +#include #include #include @@ -27,12 +28,6 @@ __sata_buffer_io(struct hba_device* dev, struct hba_cmdh* header; struct hba_cmdt* table; int slot = hba_prepare_cmd(port, &table, &header, buffer, size); - int bitmask = 1 << slot; - - // 确保端口是空闲的 - wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY | HBA_PxTFD_DRQ))); - - port->regs[HBA_RPxIS] = 0; header->options |= HBA_CMDH_WRITE * (write == 1); @@ -57,26 +52,10 @@ __sata_buffer_io(struct hba_device* dev, */ fis->dev = (1 << 6); - int retries = 0; - - while (retries < MAX_RETRY) { - port->regs[HBA_RPxCI] = bitmask; - - wait_until(!(port->regs[HBA_RPxCI] & bitmask)); - - if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { - // 有错误 - sata_read_error(port); - retries++; - } else { - vfree_dma(table); - return 1; - } - } + int is_ok = ahci_try_send(port, slot); -fail: vfree_dma(table); - return 0; + return is_ok; } int diff --git a/lunaix-os/hal/ahci/atapi.c b/lunaix-os/hal/ahci/atapi.c index 76c3795..f75c1be 100644 --- a/lunaix-os/hal/ahci/atapi.c +++ b/lunaix-os/hal/ahci/atapi.c @@ -1,7 +1,7 @@ +#include #include #include #include -#include #include #include @@ -61,12 +61,6 @@ __scsi_buffer_io(struct hba_device* dev, struct hba_cmdh* header; struct hba_cmdt* table; int slot = hba_prepare_cmd(port, &table, &header, buffer, size); - int bitmask = 1 << slot; - - // 确保端口是空闲的 - wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY | HBA_PxTFD_DRQ))); - - port->regs[HBA_RPxIS] = 0; header->options |= (HBA_CMDH_WRITE * (write == 1)) | HBA_CMDH_ATAPI; @@ -77,7 +71,7 @@ __scsi_buffer_io(struct hba_device* dev, sata_create_fis(fis, ATA_PACKET, (size << 8), 0); fis->feature = 1 | ((!write) << 2); - if (port->device->cbd_size == 16) { + if (port->device->cbd_size == SCSI_CDB16) { scsi_create_packet16((struct scsi_cdb16*)cdb, write ? SCSI_WRITE_BLOCKS_16 : SCSI_READ_BLOCKS_16, lba, @@ -92,26 +86,10 @@ __scsi_buffer_io(struct hba_device* dev, // field: cdb->misc1 *((uint8_t*)cdb + 1) = 3 << 5; // RPROTECT=011b 禁用保护检查 - int retries = 0; - - while (retries < MAX_RETRY) { - port->regs[HBA_RPxCI] = bitmask; - - wait_until_expire(!(port->regs[HBA_RPxCI] & bitmask), 1000000); - - if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { - // 有错误 - sata_read_error(port); - retries++; - } else { - vfree_dma(table); - return 1; - } - } - -fail: + int is_ok = ahci_try_send(port, slot); vfree_dma(table); - return 0; + + return is_ok; } int diff --git a/lunaix-os/hal/ahci/utils.c b/lunaix-os/hal/ahci/utils.c index 664488d..96d163b 100644 --- a/lunaix-os/hal/ahci/utils.c +++ b/lunaix-os/hal/ahci/utils.c @@ -1,7 +1,11 @@ +#include #include -#include +#include +#include #include +#include + #define IDDEV_OFFMAXLBA 60 #define IDDEV_OFFMAXLBA_EXT 230 #define IDDEV_OFFLSECSIZE 117 @@ -13,12 +17,14 @@ #define IDDEV_OFFLPP 106 #define IDDEV_OFFCAPABILITIES 49 +static uint32_t cdb_size[] = { SCSI_CDB12, SCSI_CDB16, 0, 0 }; + void ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data) { dev_info->max_lba = *((uint32_t*)(data + IDDEV_OFFMAXLBA)); dev_info->block_size = *((uint32_t*)(data + IDDEV_OFFLSECSIZE)); - dev_info->cbd_size = (*data & 0x3) ? 16 : 12; + dev_info->cbd_size = cdb_size[(*data & 0x3)]; dev_info->wwn = *(uint64_t*)(data + IDDEV_OFFWWN); dev_info->block_per_sec = 1 << (*(data + IDDEV_OFFLPP) & 0xf); dev_info->alignment_offset = *(data + IDDEV_OFFALIGN) & 0x3fff; @@ -47,4 +53,36 @@ ahci_parsestr(char* str, uint16_t* reg_start, int size_word) str[j + 1] = (char)(reg & 0xff); } str[j - 1] = '\0'; + strrtrim(str); +} + +int +ahci_try_send(struct hba_port* port, int slot) +{ + int retries = 0, bitmask = 1 << slot; + + // 确保端口是空闲的 + wait_until(!(port->regs[HBA_RPxTFD] & (HBA_PxTFD_BSY | HBA_PxTFD_DRQ))); + + hba_clear_reg(port->regs[HBA_RPxIS]); + + while (retries < MAX_RETRY) { + // PxCI寄存器置位,告诉HBA这儿有个数据需要发送到SATA端口 + port->regs[HBA_RPxCI] = bitmask; + + wait_until_expire(!(port->regs[HBA_RPxCI] & bitmask), 1000000); + + port->regs[HBA_RPxCI] &= ~bitmask; // ensure CI bit is cleared + if ((port->regs[HBA_RPxTFD] & HBA_PxTFD_ERR)) { + // 有错误 + sata_read_error(port); + retries++; + } else { + break; + } + } + + hba_clear_reg(port->regs[HBA_RPxIS]); + + return retries < MAX_RETRY; } \ No newline at end of file diff --git a/lunaix-os/includes/hal/ahci/ahci.h b/lunaix-os/includes/hal/ahci/ahci.h index ec9a64f..c768510 100644 --- a/lunaix-os/includes/hal/ahci/ahci.h +++ b/lunaix-os/includes/hal/ahci/ahci.h @@ -30,4 +30,13 @@ ahci_get_port_usage(); struct hba_port* ahci_get_port(unsigned int index); +void +ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data); + +void +ahci_parsestr(char* str, uint16_t* reg_start, int size_word); + +int +ahci_try_send(struct hba_port* port, int slot); + #endif /* __LUNAIX_AHCI_H */ diff --git a/lunaix-os/includes/hal/ahci/hba.h b/lunaix-os/includes/hal/ahci/hba.h index 92a2b5a..8203ab5 100644 --- a/lunaix-os/includes/hal/ahci/hba.h +++ b/lunaix-os/includes/hal/ahci/hba.h @@ -1,7 +1,7 @@ #ifndef __LUNAIX_HBA_H #define __LUNAIX_HBA_H -#include +#include #define HBA_RCAP 0 #define HBA_RGHC 1 @@ -47,6 +47,8 @@ #define HBA_RPxSSTS_IF(x) (((x) >> 4) & 0xf) #define HBA_RPxSSTS_PHYSTATE(x) ((x)&0xf) +#define hba_clear_reg(reg) (reg) = -1 + #define HBA_DEV_SIG_ATAPI 0xeb140101 #define HBA_DEV_SIG_ATA 0x00000101 diff --git a/lunaix-os/includes/hal/ahci/sata.h b/lunaix-os/includes/hal/ahci/sata.h index dc93448..a08c5f4 100644 --- a/lunaix-os/includes/hal/ahci/sata.h +++ b/lunaix-os/includes/hal/ahci/sata.h @@ -1,7 +1,7 @@ #ifndef __LUNAIX_SATA_H #define __LUNAIX_SATA_H -#include +#include #define SATA_REG_FIS_D2H 0x34 #define SATA_REG_FIS_H2D 0x27 @@ -65,4 +65,6 @@ sata_write_buffer(struct hba_device* dev, void* buffer, uint32_t size); +void +sata_read_error(struct hba_port* port); #endif /* __LUNAIX_SATA_H */ diff --git a/lunaix-os/includes/hal/ahci/scsi.h b/lunaix-os/includes/hal/ahci/scsi.h index fee899f..a3cfe2f 100644 --- a/lunaix-os/includes/hal/ahci/scsi.h +++ b/lunaix-os/includes/hal/ahci/scsi.h @@ -62,4 +62,7 @@ scsi_write_buffer(struct hba_device* dev, void* buffer, uint32_t size); +void +scsi_parse_capacity(struct hba_device* device, uint32_t* parameter); + #endif /* __LUNAIX_ATAPI_H */ diff --git a/lunaix-os/includes/hal/ahci/utils.h b/lunaix-os/includes/hal/ahci/utils.h deleted file mode 100644 index e22a280..0000000 --- a/lunaix-os/includes/hal/ahci/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __LUNAIX_AHCI_UTILS_H -#define __LUNAIX_AHCI_UTILS_H - -#include -#include - -void -ahci_parse_dev_info(struct hba_device* dev_info, uint16_t* data); - -void -ahci_parsestr(char* str, uint16_t* reg_start, int size_word); - -void -scsi_parse_capacity(struct hba_device* device, uint32_t* parameter); - -int -sata_read_error(struct hba_port* port); - -#endif /* __LUNAIX_UTILS_H */ diff --git a/lunaix-os/includes/klibc/string.h b/lunaix-os/includes/klibc/string.h index 35fd53e..fcb0df5 100644 --- a/lunaix-os/includes/klibc/string.h +++ b/lunaix-os/includes/klibc/string.h @@ -33,4 +33,10 @@ strchr(const char* str, int character); int streq(const char* a, const char* b); +void +strrtrim(char* str); + +void* +strltrim_safe(char* str); + #endif /* __LUNAIX_STRING_H */ diff --git a/lunaix-os/libs/klibc/string/trim.c b/lunaix-os/libs/klibc/string/trim.c new file mode 100644 index 0000000..82f29bd --- /dev/null +++ b/lunaix-os/libs/klibc/string/trim.c @@ -0,0 +1,29 @@ +#include + +#define WS_CHAR(c) \ + (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r') + +void +strrtrim(char* str) +{ + size_t l = strlen(str); + while (l < (size_t)-1) { + char c = str[l]; + if (!c || WS_CHAR(c)) { + l--; + continue; + } + break; + } + str[l + 1] = '\0'; +} + +void* +strltrim_safe(char* str) +{ + size_t l = 0; + char c = 0; + while ((c = str[l++]) && WS_CHAR(c)) + ; + return strcpy(str, str + l); +} \ No newline at end of file