1/* 2 * Copyright (c) 2016 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10 11#include <inttypes.h> 12#include <devif/backends/blk/ahci_devq.h> 13#include "ahcid.h" 14#include "test.h" 15 16void* dq = NULL; 17struct waitset disk_ws; 18 19static struct ahci_disk* ad; 20static volatile bool driver_initialized = false; 21static struct device_mem hbabar; 22static struct waitset_chanstate *chan = NULL; 23 24 25struct device_id { 26 uint16_t vendor; 27 uint16_t device; 28}; 29 30static void interrupt_handler(void *arg) 31{ 32 ahci_interrupt_handler(dq); 33 34#ifdef DISABLE_INTERRUPTS 35 assert(chan != NULL); 36 assert(dq != NULL); 37 errval_t err = waitset_chan_register(&disk_ws, chan, MKCLOSURE(interrupt_handler, dq)); 38 if (err_is_fail(err) && err_no(err) == LIB_ERR_CHAN_ALREADY_REGISTERED) { 39 printf("Got actual interrupt?\n"); 40 } 41 else if (err_is_fail(err)) { 42 USER_PANIC_ERR(err, "Can't register our dummy channel."); 43 } 44 err = waitset_chan_trigger(chan); 45 if (err_is_fail(err)) { 46 USER_PANIC_ERR(err, "trigger failed."); 47 } 48#endif 49 50} 51 52static void do_ahci_init(void *arg, struct device_mem* bar_info, int nr_allocated_bars) 53{ 54 // Although the AHCI specification requires the AHCI memory region to be in 55 // BAR 5 (BAR 0 to 4 are used for legacy IDE mode) the QEMU AHCI emulation 56 // incorrectly uses BAR 0. Because of this, ahcid consults both BAR 0 and 57 // BAR 5 to find the HBA's memory mapped I/O region. 58 // Since two BARs between 0-5 are I/O ports they are not passed to use by PCI. 59 60 if (nr_allocated_bars == 1) { 61 memcpy(&hbabar, &bar_info[0], sizeof(struct device_mem)); 62 } else if (nr_allocated_bars == 3) { 63 memcpy(&hbabar, &bar_info[2], sizeof(struct device_mem)); 64 } else { 65 printf("Strange device... not supported\n"); 66 abort(); 67 } 68 69 errval_t err = blk_ahci_init(&hbabar, &ad); 70 if (err_is_fail(err)) { 71 USER_PANIC_ERR(err, "AHCI HBA init failed."); 72 } 73 74 struct ahci_queue* q; 75 err = ahci_create(&q, ad, 0); 76 if (err_is_fail(err)) { 77 USER_PANIC_ERR(err, "ahci_queue create failed."); 78 } 79 80 dq = (struct devq*) q; 81 82#ifdef DISABLE_INTERRUPTS 83 waitset_init(&disk_ws); 84 85 // Hack: Why don't interrupts work? 86 chan = malloc(sizeof(struct waitset_chanstate)); 87 waitset_chanstate_init(chan, CHANTYPE_AHCI); 88 89 err = waitset_chan_register(&disk_ws, chan, MKCLOSURE(interrupt_handler, dq)); 90 if (err_is_fail(err)) { 91 USER_PANIC_ERR(err, "waitset_chan_regster failed."); 92 } 93 err = waitset_chan_trigger(chan); 94 if (err_is_fail(err)) { 95 USER_PANIC_ERR(err, "trigger failed."); 96 } 97#endif 98 99 driver_initialized = true; 100} 101 102static void ahci_reregister_handler(void *arg) 103{ 104 errval_t err; 105 struct device_id *dev_id = arg; 106 err = pci_reregister_irq_for_device(PCI_CLASS_MASS_STORAGE, PCI_SUB_SATA, 107 PCI_DONT_CARE, dev_id->vendor, dev_id->device, PCI_DONT_CARE, PCI_DONT_CARE, 108 PCI_DONT_CARE, interrupt_handler, NULL, 109 ahci_reregister_handler, dev_id); 110 if (err_is_fail(err)) { 111 DEBUG_ERR(err, "pci_reregister_irq_for_device"); 112 } 113 114 return; 115} 116 117int main(int argc, char **argv) 118{ 119 int r; 120 r = skb_client_connect(); 121 assert(err_is_ok(r)); 122 r = pci_client_connect(); 123 assert(err_is_ok(r)); 124 125 if (argc >= 3) { 126 printf("Got %s as vendor_id:device_id\n", argv[argc-1]); 127 uint64_t vendor_id, device_id; 128 vendor_id = strtol(argv[argc-1], NULL, 16); 129 device_id = strtol(argv[argc-1]+5, NULL, 16); 130 131 struct device_id *dev_id = malloc(sizeof(*dev_id)); 132 dev_id->vendor = vendor_id; 133 dev_id->device = device_id; 134 135 r = pci_register_driver_movable_irq(do_ahci_init, NULL, PCI_CLASS_MASS_STORAGE, 136 PCI_SUB_SATA, PCI_DONT_CARE, vendor_id, device_id, 137 PCI_DONT_CARE, PCI_DONT_CARE, PCI_DONT_CARE, 138 interrupt_handler, NULL, 139 ahci_reregister_handler, dev_id); 140 if (err_is_fail(r)) { 141 printf("Couldn't register device %04"PRIx64":%04"PRIx64": %s\n", vendor_id, 142 device_id, err_getstring(r)); 143 return 1; 144 } 145 printf("AHCID: registered device %04"PRIx64":%04"PRIx64"\n", vendor_id, device_id); 146 } 147 else { 148 printf("usage: ahcid <vendor id>:<device id>\n"); 149 exit(1); 150 } 151 assert(driver_initialized); 152 153#ifdef TESTING 154 printf("Initialized driver, running tests:\n"); 155 if (argc < 4) { 156 return 1; 157 } 158 if (strcmp(argv[2], "read|write") == 0) { 159 test_runner(2, AhciTest_READ, AhciTest_WRITE); 160 } 161 if (strcmp(argv[2], "read") == 0) { 162 test_runner(1, AhciTest_READ); 163 } 164 if (strcmp(argv[2], "write") == 0) { 165 test_runner(1, AhciTest_WRITE); 166 } 167 if (strcmp(argv[2], "verify") == 0) { 168 test_runner(1, AhciTest_VERIFY); 169 } 170#endif 171} 172