#include #include #include #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(); if (!bdev) { return; } struct device *bdev_base = block_device_base(bdev); struct ahci_device *ahci_dev = kmalloc(sizeof *ahci_dev, VM_NORMAL); if (!ahci_dev) { device_deref(bdev_base); return; } ahci_dev->port = port; ahci_dev->port_no = port_no; ahci_dev->type = type; bdev_base->dev_priv = ahci_dev; rebase_ahci_port(ahci_dev); snprintf(bdev_base->dev_name, sizeof bdev_base->dev_name, "ahci%d", port_no); if (type == AHCI_DEV_SATA) { struct identify_device_data identity_data = {0}; kern_status_t status = identify_ata_device(ahci_dev, &identity_data); if (status != KERN_OK) { kfree(ahci_dev); device_deref(bdev_base); return; } /* TODO read IDENTIFY DEVICE log to support non-512 sector sizes */ 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) { struct identify_device_data identity_data = {0}; kern_status_t status = identify_atapi_device(ahci_dev, &identity_data); if (status != KERN_OK) { kfree(ahci_dev); device_deref(bdev_base); return; } struct scsi_command cmd = {0}; cmd.cmd = SCSI_CMD_READ_CAPACITY; struct scsi_read_capacity_data cmd_result = {0}; struct iovec vec = { .io_buf = &cmd_result, .io_len = sizeof cmd_result }; status = send_atapi_command(ahci_dev, &cmd, &vec, 1); if (status != KERN_OK) { printk("ahci: failed to contact ATAPI device: %s", kern_status_string(status)); return; } 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); } device_register(bdev_base, ahci_driver(), controller); }