diff --git a/kexts/drivers/block/ahci/ahci.c b/kexts/drivers/block/ahci/ahci.c index c04b30c..3a6fcb2 100644 --- a/kexts/drivers/block/ahci/ahci.c +++ b/kexts/drivers/block/ahci/ahci.c @@ -47,6 +47,11 @@ static void free_cmd_table(struct hba_cmd_table *table) } kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct iovec *vec, size_t nvec) +{ + return send_ata_command_ex(dev, NULL, cmd, vec, nvec); +} + +kern_status_t send_ata_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, unsigned int cmd, struct iovec *vec, size_t nvec) { if (nvec == 0) { return KERN_OK; @@ -73,6 +78,12 @@ kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct struct fis_reg_h2d *cmdfis = (struct fis_reg_h2d*)(&cmdtbl->cfis); + if (fis) { + memcpy(cmdfis, fis, sizeof *cmdfis); + } else { + memset(cmdfis, 0x00, sizeof *cmdfis); + } + cmdfis->fis_type = FIS_TYPE_REG_H2D; cmdfis->c = 1; cmdfis->command = cmd; @@ -96,12 +107,14 @@ kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct if (port->is & HBA_PxIS_TFES) { free_cmd_table(cmdtbl); + printk("ahci: command failed"); return KERN_IO_ERROR; } } free_cmd_table(cmdtbl); if (port->is & HBA_PxIS_TFES) { + printk("ahci: command failed"); return KERN_IO_ERROR; } @@ -109,6 +122,11 @@ kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct } kern_status_t send_atapi_command(struct ahci_device *dev, struct scsi_command *cmd, struct iovec *vec, size_t nvec) +{ + return send_atapi_command_ex(dev, NULL, cmd, vec, nvec); +} + +kern_status_t send_atapi_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, struct scsi_command *cmd, struct iovec *vec, size_t nvec) { if (nvec == 0) { return KERN_OK; @@ -136,7 +154,11 @@ kern_status_t send_atapi_command(struct ahci_device *dev, struct scsi_command *c memcpy(&cmdtbl->acmd, cmd, sizeof *cmd); struct fis_reg_h2d *cmdfis = (struct fis_reg_h2d *)(&cmdtbl->cfis); - memset(cmdfis, 0x0, sizeof *cmdfis); + if (fis) { + memcpy(cmdfis, fis, sizeof *cmdfis); + } else { + memset(cmdfis, 0x0, sizeof *cmdfis); + } cmdfis->fis_type = FIS_TYPE_REG_H2D; cmdfis->c = 1; diff --git a/kexts/drivers/block/ahci/ahci.h b/kexts/drivers/block/ahci/ahci.h index 868ca14..70b731e 100644 --- a/kexts/drivers/block/ahci/ahci.h +++ b/kexts/drivers/block/ahci/ahci.h @@ -716,7 +716,9 @@ extern struct driver *ahci_driver(void); extern kern_status_t identify_ata_device(struct ahci_device *dev, struct identify_device_data *out); extern kern_status_t identify_atapi_device(struct ahci_device *dev, struct identify_device_data *out); extern kern_status_t send_ata_command(struct ahci_device *dev, unsigned int cmd, struct iovec *vec, size_t nvec); +extern kern_status_t send_ata_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, unsigned int cmd, struct iovec *vec, size_t nvec); extern kern_status_t send_atapi_command(struct ahci_device *dev, struct scsi_command *cmd, struct iovec *vec, size_t nvec); +extern kern_status_t send_atapi_command_ex(struct ahci_device *dev, struct fis_reg_h2d *fis, struct scsi_command *cmd, struct iovec *vec, size_t nvec); extern void rebase_ahci_port(struct ahci_device *dev); extern void probe_ahci_ports(struct driver *driver, struct device *controller, volatile struct hba_config *abar, diff --git a/kexts/drivers/block/ahci/ata.c b/kexts/drivers/block/ahci/ata.c new file mode 100644 index 0000000..feda1a8 --- /dev/null +++ b/kexts/drivers/block/ahci/ata.c @@ -0,0 +1,49 @@ +#include +#include "ahci.h" + +kern_status_t ata_read_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags) +{ + struct fis_reg_h2d fis = {0}; + size_t c = *count; + c &= 0xFFFF; + + fis.fis_type = FIS_TYPE_REG_H2D; + + fis.count_l = (c & 0xFFu); + fis.count_h = (c >> 8) & 0xFFu; + + fis.lba0 = offset & 0xFFu; + fis.lba1 = (offset >> 8) & 0xFFu; + fis.lba2 = (offset >> 16) & 0xFFu; + fis.lba3 = (offset >> 24) & 0xFFu; + fis.lba4 = (offset >> 32) & 0xFFu; + fis.lba5 = (offset >> 40) & 0xFFu; + + fis.device = 1 << 6; + + struct ahci_device *ahci_dev = dev->dev_priv; + kern_status_t status = send_ata_command_ex(ahci_dev, &fis, ATA_CMD_READ_DMA_EX, vec, nvec); + if (status == KERN_OK) { + *count = c; + } else { + *count = 0; + } + + return status; +} + +kern_status_t ata_write_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags) +{ + return KERN_UNSUPPORTED; +} + +kern_status_t ata_ioctl(struct device *dev, unsigned int req, void *argp) +{ + return KERN_UNSUPPORTED; +} + +struct block_device_ops ata_device_ops = { + .read_blocks = ata_read_blocks, + .write_blocks = ata_write_blocks, + .ioctl = ata_ioctl, +}; diff --git a/kexts/drivers/block/ahci/atapi.c b/kexts/drivers/block/ahci/atapi.c new file mode 100644 index 0000000..e254aed --- /dev/null +++ b/kexts/drivers/block/ahci/atapi.c @@ -0,0 +1,22 @@ +#include + +kern_status_t atapi_read_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags) +{ + return KERN_UNSUPPORTED; +} + +kern_status_t atapi_write_blocks(struct device *dev, sectors_t offset, size_t *count, struct iovec *vec, size_t nvec, socks_flags_t flags) +{ + return KERN_UNSUPPORTED; +} + +kern_status_t atapi_ioctl(struct device *dev, unsigned int req, void *argp) +{ + return KERN_UNSUPPORTED; +} + +struct block_device_ops atapi_device_ops = { + .read_blocks = atapi_read_blocks, + .write_blocks = atapi_write_blocks, + .ioctl = atapi_ioctl, +}; diff --git a/kexts/drivers/block/ahci/device.c b/kexts/drivers/block/ahci/device.c index a9eb717..c503157 100644 --- a/kexts/drivers/block/ahci/device.c +++ b/kexts/drivers/block/ahci/device.c @@ -4,6 +4,9 @@ #include #include "ahci.h" +extern struct block_device_ops ata_device_ops; +extern struct block_device_ops atapi_device_ops; + extern void create_device_from_ahci_port(int port_no, struct device *controller, volatile struct hba_port *port, int type) { struct block_device *bdev = block_device_create(); @@ -37,8 +40,9 @@ extern void create_device_from_ahci_port(int port_no, struct device *controller, } /* TODO read IDENTIFY DEVICE log to support non-512 sector sizes */ - bdev->sector_size = 512; - bdev->capacity = identity_data.user_addressable_sectors; + bdev->b_ops = &ata_device_ops; + bdev->b_sector_size = 512; + bdev->b_capacity = identity_data.user_addressable_sectors; snprintf(bdev_base->dev_model_name, sizeof bdev_base->dev_model_name, "%s", identity_data.model_number); } else if (type == AHCI_DEV_SATAPI) { @@ -62,8 +66,9 @@ extern void create_device_from_ahci_port(int port_no, struct device *controller, return; } - bdev->sector_size = big_to_host_u32(cmd_result.block_size); - bdev->capacity = big_to_host_u32(cmd_result.last_sector) + 1; + bdev->b_ops = &atapi_device_ops; + bdev->b_sector_size = big_to_host_u32(cmd_result.block_size); + bdev->b_capacity = big_to_host_u32(cmd_result.last_sector) + 1; snprintf(bdev_base->dev_model_name, sizeof bdev_base->dev_model_name, "%s", identity_data.model_number); } diff --git a/kexts/drivers/block/ahci/extension.yaml b/kexts/drivers/block/ahci/extension.yaml index 5c0fb22..e91ed78 100644 --- a/kexts/drivers/block/ahci/extension.yaml +++ b/kexts/drivers/block/ahci/extension.yaml @@ -8,4 +8,6 @@ sources: - main.c - device.c - ahci.c + - ata.c + - atapi.c - ahci.h