78 lines
2.3 KiB
C
78 lines
2.3 KiB
C
#include <socks/device.h>
|
|
#include <socks/util.h>
|
|
#include <socks/printk.h>
|
|
#include <socks/libc/stdio.h>
|
|
#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);
|
|
}
|