1*433d6423SLionel Sambuc /* Advanced Host Controller Interface (AHCI) driver, by D.C. van Moolenbroek 2*433d6423SLionel Sambuc * - Multithreading support by Arne Welzel 3*433d6423SLionel Sambuc * - Native Command Queuing support by Raja Appuswamy 4*433d6423SLionel Sambuc */ 5*433d6423SLionel Sambuc /* 6*433d6423SLionel Sambuc * This driver is based on the following specifications: 7*433d6423SLionel Sambuc * - Serial ATA Advanced Host Controller Interface (AHCI) 1.3 8*433d6423SLionel Sambuc * - Serial ATA Revision 2.6 9*433d6423SLionel Sambuc * - AT Attachment with Packet Interface 7 (ATA/ATAPI-7) 10*433d6423SLionel Sambuc * - ATAPI Removable Rewritable Media Devices 1.3 (SFF-8070) 11*433d6423SLionel Sambuc * 12*433d6423SLionel Sambuc * The driver supports device hot-plug, active device status tracking, 13*433d6423SLionel Sambuc * nonremovable ATA and removable ATAPI devices, custom logical sector sizes, 14*433d6423SLionel Sambuc * sector-unaligned reads, native command queuing and parallel requests to 15*433d6423SLionel Sambuc * different devices. 16*433d6423SLionel Sambuc * 17*433d6423SLionel Sambuc * It does not implement transparent failure recovery, power management, or 18*433d6423SLionel Sambuc * port multiplier support. 19*433d6423SLionel Sambuc */ 20*433d6423SLionel Sambuc /* 21*433d6423SLionel Sambuc * An AHCI controller exposes a number of ports (up to 32), each of which may 22*433d6423SLionel Sambuc * or may not have one device attached (port multipliers are not supported). 23*433d6423SLionel Sambuc * Each port is maintained independently. 24*433d6423SLionel Sambuc * 25*433d6423SLionel Sambuc * The following figure depicts the possible transitions between port states. 26*433d6423SLionel Sambuc * The NO_PORT state is not included; no transitions can be made from or to it. 27*433d6423SLionel Sambuc * 28*433d6423SLionel Sambuc * +----------+ +----------+ 29*433d6423SLionel Sambuc * | SPIN_UP | ------+ +-----> | BAD_DEV | ------------------+ 30*433d6423SLionel Sambuc * +----------+ | | +----------+ | 31*433d6423SLionel Sambuc * | | | ^ | 32*433d6423SLionel Sambuc * v v | | | 33*433d6423SLionel Sambuc * +----------+ +----------+ +----------+ +----------+ | 34*433d6423SLionel Sambuc * | NO_DEV | --> | WAIT_DEV | --> | WAIT_ID | --> | GOOD_DEV | | 35*433d6423SLionel Sambuc * +----------+ +----------+ +----------+ +----------+ | 36*433d6423SLionel Sambuc * ^ | | | | 37*433d6423SLionel Sambuc * +----------------+----------------+----------------+--------+ 38*433d6423SLionel Sambuc * 39*433d6423SLionel Sambuc * At driver startup, all physically present ports are put in SPIN_UP state. 40*433d6423SLionel Sambuc * This state differs from NO_DEV in that BDEV_OPEN calls will be deferred 41*433d6423SLionel Sambuc * until either the spin-up timer expires, or a device has been identified on 42*433d6423SLionel Sambuc * that port. This prevents early BDEV_OPEN calls from failing erroneously at 43*433d6423SLionel Sambuc * startup time if the device has not yet been able to announce its presence. 44*433d6423SLionel Sambuc * 45*433d6423SLionel Sambuc * If a device is detected, either at startup time or after hot-plug, its 46*433d6423SLionel Sambuc * signature is checked and it is identified, after which it may be determined 47*433d6423SLionel Sambuc * to be a usable ("good") device, which means that the device is considered to 48*433d6423SLionel Sambuc * be in a working state. If these steps fail, the device is marked as unusable 49*433d6423SLionel Sambuc * ("bad"). At any point in time, the device may be disconnected; the port is 50*433d6423SLionel Sambuc * then put back into NO_DEV state. 51*433d6423SLionel Sambuc * 52*433d6423SLionel Sambuc * A device in working state (GOOD_DEV) may or may not have a medium. All ATA 53*433d6423SLionel Sambuc * devices are assumed to be fixed; all ATAPI devices are assumed to have 54*433d6423SLionel Sambuc * removable media. To prevent erroneous access to switched devices and media, 55*433d6423SLionel Sambuc * the driver makes devices inaccessible until they are fully closed (the open 56*433d6423SLionel Sambuc * count is zero) when a device (hot-plug) or medium change is detected. 57*433d6423SLionel Sambuc * For hot-plug changes, access is prevented by setting the BARRIER flag until 58*433d6423SLionel Sambuc * the device is fully closed and then reopened. For medium changes, access is 59*433d6423SLionel Sambuc * prevented by not acknowledging the medium change until the device is fully 60*433d6423SLionel Sambuc * closed and reopened. Removable media are not locked in the drive while 61*433d6423SLionel Sambuc * opened, because the driver author is uncomfortable with that concept. 62*433d6423SLionel Sambuc * 63*433d6423SLionel Sambuc * Ports may leave the group of states where a device is connected (that is, 64*433d6423SLionel Sambuc * WAIT_ID, GOOD_DEV, and BAD_DEV) in two ways: either due to a hot-unplug 65*433d6423SLionel Sambuc * event, or due to a hard reset after a serious failure. For simplicity, we 66*433d6423SLionel Sambuc * we perform a hard reset after a hot-unplug event as well, so that the link 67*433d6423SLionel Sambuc * to the device is broken. Thus, in both cases, a transition to NO_DEV is 68*433d6423SLionel Sambuc * made, after which the link to the device may or may not be reestablished. 69*433d6423SLionel Sambuc * In both cases, ongoing requests are cancelled and the BARRIER flag is set. 70*433d6423SLionel Sambuc * 71*433d6423SLionel Sambuc * The following table lists for each state, whether the port is started 72*433d6423SLionel Sambuc * (PxCMD.ST is set), whether a timer is running, what the PxIE mask is to be 73*433d6423SLionel Sambuc * set to, and what BDEV_OPEN calls on this port should return. 74*433d6423SLionel Sambuc * 75*433d6423SLionel Sambuc * State Started Timer PxIE BDEV_OPEN 76*433d6423SLionel Sambuc * --------- --------- --------- --------- --------- 77*433d6423SLionel Sambuc * NO_PORT no no (none) ENXIO 78*433d6423SLionel Sambuc * SPIN_UP no yes PCE (wait) 79*433d6423SLionel Sambuc * NO_DEV no no PCE ENXIO 80*433d6423SLionel Sambuc * WAIT_DEV no yes PCE (wait) 81*433d6423SLionel Sambuc * BAD_DEV no no PRCE ENXIO 82*433d6423SLionel Sambuc * WAIT_ID yes yes PRCE+ (wait) 83*433d6423SLionel Sambuc * GOOD_DEV yes per-command PRCE+ OK 84*433d6423SLionel Sambuc * 85*433d6423SLionel Sambuc * In order to continue deferred BDEV_OPEN calls, the BUSY flag must be unset 86*433d6423SLionel Sambuc * when changing from SPIN_UP to any state but WAIT_DEV, and when changing from 87*433d6423SLionel Sambuc * WAIT_DEV to any state but WAIT_ID, and when changing from WAIT_ID to any 88*433d6423SLionel Sambuc * other state. 89*433d6423SLionel Sambuc */ 90*433d6423SLionel Sambuc /* 91*433d6423SLionel Sambuc * The maximum byte size of a single transfer (MAX_TRANSFER) is currently set 92*433d6423SLionel Sambuc * to 4MB. This limit has been chosen for a number of reasons: 93*433d6423SLionel Sambuc * - The size that can be specified in a Physical Region Descriptor (PRD) is 94*433d6423SLionel Sambuc * limited to 4MB for AHCI. Limiting the total transfer size to at most this 95*433d6423SLionel Sambuc * size implies that no I/O vector element needs to be split up across PRDs. 96*433d6423SLionel Sambuc * This means that the maximum number of needed PRDs can be predetermined. 97*433d6423SLionel Sambuc * - The limit is below what can be transferred in a single ATA request, namely 98*433d6423SLionel Sambuc * 64k sectors (i.e., at least 32MB). This means that transfer requests need 99*433d6423SLionel Sambuc * never be split up into smaller chunks, reducing implementation complexity. 100*433d6423SLionel Sambuc * - A single, static timeout can be used for transfers. Very large transfers 101*433d6423SLionel Sambuc * can legitimately take up to several minutes -- well beyond the appropriate 102*433d6423SLionel Sambuc * timeout range for small transfers. The limit obviates the need for a 103*433d6423SLionel Sambuc * timeout scheme that takes into account the transfer size. 104*433d6423SLionel Sambuc * - Similarly, the transfer limit reduces the opportunity for buggy/malicious 105*433d6423SLionel Sambuc * clients to keep the driver busy for a long time with a single request. 106*433d6423SLionel Sambuc * - The limit is high enough for all practical purposes. The transfer setup 107*433d6423SLionel Sambuc * overhead is already relatively negligible at this size, and even larger 108*433d6423SLionel Sambuc * requests will not help maximize throughput. As NR_IOREQS is currently set 109*433d6423SLionel Sambuc * to 64, the limit still allows file systems to perform I/O requests with 110*433d6423SLionel Sambuc * vectors completely filled with 64KB-blocks. 111*433d6423SLionel Sambuc */ 112*433d6423SLionel Sambuc #include <minix/drivers.h> 113*433d6423SLionel Sambuc #include <minix/blockdriver_mt.h> 114*433d6423SLionel Sambuc #include <minix/drvlib.h> 115*433d6423SLionel Sambuc #include <machine/pci.h> 116*433d6423SLionel Sambuc #include <sys/ioc_disk.h> 117*433d6423SLionel Sambuc #include <sys/mman.h> 118*433d6423SLionel Sambuc #include <assert.h> 119*433d6423SLionel Sambuc 120*433d6423SLionel Sambuc #include "ahci.h" 121*433d6423SLionel Sambuc 122*433d6423SLionel Sambuc /* Host Bus Adapter (HBA) state. */ 123*433d6423SLionel Sambuc static struct { 124*433d6423SLionel Sambuc volatile u32_t *base; /* base address of memory-mapped registers */ 125*433d6423SLionel Sambuc size_t size; /* size of memory-mapped register area */ 126*433d6423SLionel Sambuc 127*433d6423SLionel Sambuc int nr_ports; /* addressable number of ports (1..NR_PORTS) */ 128*433d6423SLionel Sambuc int nr_cmds; /* maximum number of commands per port */ 129*433d6423SLionel Sambuc int has_ncq; /* NCQ support flag */ 130*433d6423SLionel Sambuc int has_clo; /* CLO support flag */ 131*433d6423SLionel Sambuc 132*433d6423SLionel Sambuc int irq; /* IRQ number */ 133*433d6423SLionel Sambuc int hook_id; /* IRQ hook ID */ 134*433d6423SLionel Sambuc } hba_state; 135*433d6423SLionel Sambuc 136*433d6423SLionel Sambuc #define hba_read(r) (hba_state.base[r]) 137*433d6423SLionel Sambuc #define hba_write(r, v) (hba_state.base[r] = (v)) 138*433d6423SLionel Sambuc 139*433d6423SLionel Sambuc /* Port state. */ 140*433d6423SLionel Sambuc static struct port_state { 141*433d6423SLionel Sambuc int state; /* port state */ 142*433d6423SLionel Sambuc unsigned int flags; /* port flags */ 143*433d6423SLionel Sambuc 144*433d6423SLionel Sambuc volatile u32_t *reg; /* memory-mapped port registers */ 145*433d6423SLionel Sambuc 146*433d6423SLionel Sambuc u8_t *mem_base; /* primary memory buffer virtual address */ 147*433d6423SLionel Sambuc phys_bytes mem_phys; /* primary memory buffer physical address */ 148*433d6423SLionel Sambuc vir_bytes mem_size; /* primary memory buffer size */ 149*433d6423SLionel Sambuc 150*433d6423SLionel Sambuc /* the FIS, CL, CT[0] and TMP buffers are all in the primary buffer */ 151*433d6423SLionel Sambuc u32_t *fis_base; /* FIS receive buffer virtual address */ 152*433d6423SLionel Sambuc phys_bytes fis_phys; /* FIS receive buffer physical address */ 153*433d6423SLionel Sambuc u32_t *cl_base; /* command list buffer virtual address */ 154*433d6423SLionel Sambuc phys_bytes cl_phys; /* command list buffer physical address */ 155*433d6423SLionel Sambuc u8_t *ct_base[NR_CMDS]; /* command table virtual address */ 156*433d6423SLionel Sambuc phys_bytes ct_phys[NR_CMDS]; /* command table physical address */ 157*433d6423SLionel Sambuc u8_t *tmp_base; /* temporary storage buffer virtual address */ 158*433d6423SLionel Sambuc phys_bytes tmp_phys; /* temporary storage buffer physical address */ 159*433d6423SLionel Sambuc 160*433d6423SLionel Sambuc u8_t *pad_base; /* sector padding buffer virtual address */ 161*433d6423SLionel Sambuc phys_bytes pad_phys; /* sector padding buffer physical address */ 162*433d6423SLionel Sambuc vir_bytes pad_size; /* sector padding buffer size */ 163*433d6423SLionel Sambuc 164*433d6423SLionel Sambuc u64_t lba_count; /* number of valid Logical Block Addresses */ 165*433d6423SLionel Sambuc u32_t sector_size; /* medium sector size in bytes */ 166*433d6423SLionel Sambuc 167*433d6423SLionel Sambuc int open_count; /* number of times this port is opened */ 168*433d6423SLionel Sambuc 169*433d6423SLionel Sambuc int device; /* associated device number, or NO_DEVICE */ 170*433d6423SLionel Sambuc struct device part[DEV_PER_DRIVE]; /* partition bases and sizes */ 171*433d6423SLionel Sambuc struct device subpart[SUB_PER_DRIVE]; /* same for subpartitions */ 172*433d6423SLionel Sambuc 173*433d6423SLionel Sambuc minix_timer_t timer; /* port-specific timeout timer */ 174*433d6423SLionel Sambuc int left; /* number of tries left before giving up */ 175*433d6423SLionel Sambuc /* (only used for signature probing) */ 176*433d6423SLionel Sambuc 177*433d6423SLionel Sambuc int queue_depth; /* NCQ queue depth */ 178*433d6423SLionel Sambuc u32_t pend_mask; /* commands not yet complete */ 179*433d6423SLionel Sambuc struct { 180*433d6423SLionel Sambuc thread_id_t tid;/* ID of the worker thread */ 181*433d6423SLionel Sambuc minix_timer_t timer; /* timer associated with each request */ 182*433d6423SLionel Sambuc int result; /* success/failure result of the commands */ 183*433d6423SLionel Sambuc } cmd_info[NR_CMDS]; 184*433d6423SLionel Sambuc } port_state[NR_PORTS]; 185*433d6423SLionel Sambuc 186*433d6423SLionel Sambuc #define port_read(ps, r) ((ps)->reg[r]) 187*433d6423SLionel Sambuc #define port_write(ps, r, v) ((ps)->reg[r] = (v)) 188*433d6423SLionel Sambuc 189*433d6423SLionel Sambuc static int ahci_instance; /* driver instance number */ 190*433d6423SLionel Sambuc 191*433d6423SLionel Sambuc static int ahci_verbose; /* verbosity level (0..4) */ 192*433d6423SLionel Sambuc 193*433d6423SLionel Sambuc /* Timeout-related values. */ 194*433d6423SLionel Sambuc static clock_t ahci_spinup_timeout; 195*433d6423SLionel Sambuc static clock_t ahci_device_timeout; 196*433d6423SLionel Sambuc static clock_t ahci_device_delay; 197*433d6423SLionel Sambuc static unsigned int ahci_device_checks; 198*433d6423SLionel Sambuc static clock_t ahci_command_timeout; 199*433d6423SLionel Sambuc static clock_t ahci_transfer_timeout; 200*433d6423SLionel Sambuc static clock_t ahci_flush_timeout; 201*433d6423SLionel Sambuc 202*433d6423SLionel Sambuc /* Timeout environment variable names and default values. */ 203*433d6423SLionel Sambuc static struct { 204*433d6423SLionel Sambuc char *name; /* environment variable name */ 205*433d6423SLionel Sambuc u32_t default_ms; /* default in milliseconds */ 206*433d6423SLionel Sambuc clock_t *ptr; /* clock ticks value pointer */ 207*433d6423SLionel Sambuc } ahci_timevar[] = { 208*433d6423SLionel Sambuc { "ahci_init_timeout", SPINUP_TIMEOUT, &ahci_spinup_timeout }, 209*433d6423SLionel Sambuc { "ahci_device_timeout", DEVICE_TIMEOUT, &ahci_device_timeout }, 210*433d6423SLionel Sambuc { "ahci_cmd_timeout", COMMAND_TIMEOUT, &ahci_command_timeout }, 211*433d6423SLionel Sambuc { "ahci_io_timeout", TRANSFER_TIMEOUT, &ahci_transfer_timeout }, 212*433d6423SLionel Sambuc { "ahci_flush_timeout", FLUSH_TIMEOUT, &ahci_flush_timeout } 213*433d6423SLionel Sambuc }; 214*433d6423SLionel Sambuc 215*433d6423SLionel Sambuc static int ahci_map[MAX_DRIVES]; /* device-to-port mapping */ 216*433d6423SLionel Sambuc 217*433d6423SLionel Sambuc static int ahci_exiting = FALSE; /* exit after last close? */ 218*433d6423SLionel Sambuc 219*433d6423SLionel Sambuc #define BUILD_ARG(port, tag) (((port) << 8) | (tag)) 220*433d6423SLionel Sambuc #define GET_PORT(arg) ((arg) >> 8) 221*433d6423SLionel Sambuc #define GET_TAG(arg) ((arg) & 0xFF) 222*433d6423SLionel Sambuc 223*433d6423SLionel Sambuc #define dprintf(v,s) do { \ 224*433d6423SLionel Sambuc if (ahci_verbose >= (v)) \ 225*433d6423SLionel Sambuc printf s; \ 226*433d6423SLionel Sambuc } while (0) 227*433d6423SLionel Sambuc 228*433d6423SLionel Sambuc /* Convert milliseconds to clock ticks. Round up. */ 229*433d6423SLionel Sambuc #define millis_to_hz(ms) (((ms) * sys_hz() + 999) / 1000) 230*433d6423SLionel Sambuc 231*433d6423SLionel Sambuc static void port_set_cmd(struct port_state *ps, int cmd, cmd_fis_t *fis, 232*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE], prd_t *prdt, int nr_prds, int write); 233*433d6423SLionel Sambuc static void port_issue(struct port_state *ps, int cmd, clock_t timeout); 234*433d6423SLionel Sambuc static int port_exec(struct port_state *ps, int cmd, clock_t timeout); 235*433d6423SLionel Sambuc static void port_timeout(minix_timer_t *tp); 236*433d6423SLionel Sambuc static void port_disconnect(struct port_state *ps); 237*433d6423SLionel Sambuc 238*433d6423SLionel Sambuc static char *ahci_portname(struct port_state *ps); 239*433d6423SLionel Sambuc static int ahci_open(devminor_t minor, int access); 240*433d6423SLionel Sambuc static int ahci_close(devminor_t minor); 241*433d6423SLionel Sambuc static ssize_t ahci_transfer(devminor_t minor, int do_write, u64_t position, 242*433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags); 243*433d6423SLionel Sambuc static struct device *ahci_part(devminor_t minor); 244*433d6423SLionel Sambuc static void ahci_alarm(clock_t stamp); 245*433d6423SLionel Sambuc static int ahci_ioctl(devminor_t minor, unsigned long request, 246*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt); 247*433d6423SLionel Sambuc static void ahci_intr(unsigned int mask); 248*433d6423SLionel Sambuc static int ahci_device(devminor_t minor, device_id_t *id); 249*433d6423SLionel Sambuc static struct port_state *ahci_get_port(devminor_t minor); 250*433d6423SLionel Sambuc 251*433d6423SLionel Sambuc /* AHCI driver table. */ 252*433d6423SLionel Sambuc static struct blockdriver ahci_dtab = { 253*433d6423SLionel Sambuc .bdr_type = BLOCKDRIVER_TYPE_DISK, 254*433d6423SLionel Sambuc .bdr_open = ahci_open, 255*433d6423SLionel Sambuc .bdr_close = ahci_close, 256*433d6423SLionel Sambuc .bdr_transfer = ahci_transfer, 257*433d6423SLionel Sambuc .bdr_ioctl = ahci_ioctl, 258*433d6423SLionel Sambuc .bdr_part = ahci_part, 259*433d6423SLionel Sambuc .bdr_intr = ahci_intr, 260*433d6423SLionel Sambuc .bdr_alarm = ahci_alarm, 261*433d6423SLionel Sambuc .bdr_device = ahci_device 262*433d6423SLionel Sambuc }; 263*433d6423SLionel Sambuc 264*433d6423SLionel Sambuc /*===========================================================================* 265*433d6423SLionel Sambuc * atapi_exec * 266*433d6423SLionel Sambuc *===========================================================================*/ 267*433d6423SLionel Sambuc static int atapi_exec(struct port_state *ps, int cmd, 268*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE], size_t size, int write) 269*433d6423SLionel Sambuc { 270*433d6423SLionel Sambuc /* Execute an ATAPI command. Return OK or error. 271*433d6423SLionel Sambuc */ 272*433d6423SLionel Sambuc cmd_fis_t fis; 273*433d6423SLionel Sambuc prd_t prd[1]; 274*433d6423SLionel Sambuc int nr_prds = 0; 275*433d6423SLionel Sambuc 276*433d6423SLionel Sambuc assert(size <= AHCI_TMP_SIZE); 277*433d6423SLionel Sambuc 278*433d6423SLionel Sambuc /* Fill in the command table with a FIS, a packet, and if a data 279*433d6423SLionel Sambuc * transfer is requested, also a PRD. 280*433d6423SLionel Sambuc */ 281*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 282*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_PACKET; 283*433d6423SLionel Sambuc 284*433d6423SLionel Sambuc if (size > 0) { 285*433d6423SLionel Sambuc fis.cf_feat = ATA_FEAT_PACKET_DMA; 286*433d6423SLionel Sambuc if (!write && (ps->flags & FLAG_USE_DMADIR)) 287*433d6423SLionel Sambuc fis.cf_feat |= ATA_FEAT_PACKET_DMADIR; 288*433d6423SLionel Sambuc 289*433d6423SLionel Sambuc prd[0].vp_addr = ps->tmp_phys; 290*433d6423SLionel Sambuc prd[0].vp_size = size; 291*433d6423SLionel Sambuc nr_prds++; 292*433d6423SLionel Sambuc } 293*433d6423SLionel Sambuc 294*433d6423SLionel Sambuc /* Start the command, and wait for it to complete or fail. */ 295*433d6423SLionel Sambuc port_set_cmd(ps, cmd, &fis, packet, prd, nr_prds, write); 296*433d6423SLionel Sambuc 297*433d6423SLionel Sambuc return port_exec(ps, cmd, ahci_command_timeout); 298*433d6423SLionel Sambuc } 299*433d6423SLionel Sambuc 300*433d6423SLionel Sambuc /*===========================================================================* 301*433d6423SLionel Sambuc * atapi_test_unit * 302*433d6423SLionel Sambuc *===========================================================================*/ 303*433d6423SLionel Sambuc static int atapi_test_unit(struct port_state *ps, int cmd) 304*433d6423SLionel Sambuc { 305*433d6423SLionel Sambuc /* Test whether the ATAPI device and medium are ready. 306*433d6423SLionel Sambuc */ 307*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE]; 308*433d6423SLionel Sambuc 309*433d6423SLionel Sambuc memset(packet, 0, sizeof(packet)); 310*433d6423SLionel Sambuc packet[0] = ATAPI_CMD_TEST_UNIT; 311*433d6423SLionel Sambuc 312*433d6423SLionel Sambuc return atapi_exec(ps, cmd, packet, 0, FALSE); 313*433d6423SLionel Sambuc } 314*433d6423SLionel Sambuc 315*433d6423SLionel Sambuc /*===========================================================================* 316*433d6423SLionel Sambuc * atapi_request_sense * 317*433d6423SLionel Sambuc *===========================================================================*/ 318*433d6423SLionel Sambuc static int atapi_request_sense(struct port_state *ps, int cmd, int *sense) 319*433d6423SLionel Sambuc { 320*433d6423SLionel Sambuc /* Request error (sense) information from an ATAPI device, and return 321*433d6423SLionel Sambuc * the sense key. The additional sense codes are not used at this time. 322*433d6423SLionel Sambuc */ 323*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE]; 324*433d6423SLionel Sambuc int r; 325*433d6423SLionel Sambuc 326*433d6423SLionel Sambuc memset(packet, 0, sizeof(packet)); 327*433d6423SLionel Sambuc packet[0] = ATAPI_CMD_REQUEST_SENSE; 328*433d6423SLionel Sambuc packet[4] = ATAPI_REQUEST_SENSE_LEN; 329*433d6423SLionel Sambuc 330*433d6423SLionel Sambuc r = atapi_exec(ps, cmd, packet, ATAPI_REQUEST_SENSE_LEN, FALSE); 331*433d6423SLionel Sambuc 332*433d6423SLionel Sambuc if (r != OK) 333*433d6423SLionel Sambuc return r; 334*433d6423SLionel Sambuc 335*433d6423SLionel Sambuc dprintf(V_REQ, ("%s: ATAPI SENSE: sense %x ASC %x ASCQ %x\n", 336*433d6423SLionel Sambuc ahci_portname(ps), ps->tmp_base[2] & 0xF, ps->tmp_base[12], 337*433d6423SLionel Sambuc ps->tmp_base[13])); 338*433d6423SLionel Sambuc 339*433d6423SLionel Sambuc *sense = ps->tmp_base[2] & 0xF; 340*433d6423SLionel Sambuc 341*433d6423SLionel Sambuc return OK; 342*433d6423SLionel Sambuc } 343*433d6423SLionel Sambuc 344*433d6423SLionel Sambuc /*===========================================================================* 345*433d6423SLionel Sambuc * atapi_load_eject * 346*433d6423SLionel Sambuc *===========================================================================*/ 347*433d6423SLionel Sambuc static int atapi_load_eject(struct port_state *ps, int cmd, int load) 348*433d6423SLionel Sambuc { 349*433d6423SLionel Sambuc /* Load or eject a medium in an ATAPI device. 350*433d6423SLionel Sambuc */ 351*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE]; 352*433d6423SLionel Sambuc 353*433d6423SLionel Sambuc memset(packet, 0, sizeof(packet)); 354*433d6423SLionel Sambuc packet[0] = ATAPI_CMD_START_STOP; 355*433d6423SLionel Sambuc packet[4] = load ? ATAPI_START_STOP_LOAD : ATAPI_START_STOP_EJECT; 356*433d6423SLionel Sambuc 357*433d6423SLionel Sambuc return atapi_exec(ps, cmd, packet, 0, FALSE); 358*433d6423SLionel Sambuc } 359*433d6423SLionel Sambuc 360*433d6423SLionel Sambuc /*===========================================================================* 361*433d6423SLionel Sambuc * atapi_read_capacity * 362*433d6423SLionel Sambuc *===========================================================================*/ 363*433d6423SLionel Sambuc static int atapi_read_capacity(struct port_state *ps, int cmd) 364*433d6423SLionel Sambuc { 365*433d6423SLionel Sambuc /* Retrieve the LBA count and sector size of an ATAPI medium. 366*433d6423SLionel Sambuc */ 367*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE], *buf; 368*433d6423SLionel Sambuc int r; 369*433d6423SLionel Sambuc 370*433d6423SLionel Sambuc memset(packet, 0, sizeof(packet)); 371*433d6423SLionel Sambuc packet[0] = ATAPI_CMD_READ_CAPACITY; 372*433d6423SLionel Sambuc 373*433d6423SLionel Sambuc r = atapi_exec(ps, cmd, packet, ATAPI_READ_CAPACITY_LEN, FALSE); 374*433d6423SLionel Sambuc if (r != OK) 375*433d6423SLionel Sambuc return r; 376*433d6423SLionel Sambuc 377*433d6423SLionel Sambuc /* Store the number of LBA blocks and sector size. */ 378*433d6423SLionel Sambuc buf = ps->tmp_base; 379*433d6423SLionel Sambuc ps->lba_count = (u64_t) ((buf[0] << 24) | (buf[1] << 16) | 380*433d6423SLionel Sambuc (buf[2] << 8) | buf[3]) + 1; 381*433d6423SLionel Sambuc ps->sector_size = 382*433d6423SLionel Sambuc (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; 383*433d6423SLionel Sambuc 384*433d6423SLionel Sambuc if (ps->sector_size == 0 || (ps->sector_size & 1)) { 385*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: invalid medium sector size %u\n", 386*433d6423SLionel Sambuc ahci_portname(ps), ps->sector_size)); 387*433d6423SLionel Sambuc 388*433d6423SLionel Sambuc return EINVAL; 389*433d6423SLionel Sambuc } 390*433d6423SLionel Sambuc 391*433d6423SLionel Sambuc dprintf(V_INFO, 392*433d6423SLionel Sambuc ("%s: medium detected (%u byte sectors, %llu MB size)\n", 393*433d6423SLionel Sambuc ahci_portname(ps), ps->sector_size, 394*433d6423SLionel Sambuc ps->lba_count * ps->sector_size / (1024*1024))); 395*433d6423SLionel Sambuc 396*433d6423SLionel Sambuc return OK; 397*433d6423SLionel Sambuc } 398*433d6423SLionel Sambuc 399*433d6423SLionel Sambuc /*===========================================================================* 400*433d6423SLionel Sambuc * atapi_check_medium * 401*433d6423SLionel Sambuc *===========================================================================*/ 402*433d6423SLionel Sambuc static int atapi_check_medium(struct port_state *ps, int cmd) 403*433d6423SLionel Sambuc { 404*433d6423SLionel Sambuc /* Check whether a medium is present in a removable-media ATAPI device. 405*433d6423SLionel Sambuc * If a new medium is detected, get its total and sector size. Return 406*433d6423SLionel Sambuc * OK only if a usable medium is present, and an error otherwise. 407*433d6423SLionel Sambuc */ 408*433d6423SLionel Sambuc int sense; 409*433d6423SLionel Sambuc 410*433d6423SLionel Sambuc /* Perform a readiness check. */ 411*433d6423SLionel Sambuc if (atapi_test_unit(ps, cmd) != OK) { 412*433d6423SLionel Sambuc ps->flags &= ~FLAG_HAS_MEDIUM; 413*433d6423SLionel Sambuc 414*433d6423SLionel Sambuc /* If the check failed due to a unit attention condition, retry 415*433d6423SLionel Sambuc * reading the medium capacity. Otherwise, assume that there is 416*433d6423SLionel Sambuc * no medium available. 417*433d6423SLionel Sambuc */ 418*433d6423SLionel Sambuc if (atapi_request_sense(ps, cmd, &sense) != OK || 419*433d6423SLionel Sambuc sense != ATAPI_SENSE_UNIT_ATT) 420*433d6423SLionel Sambuc return ENXIO; 421*433d6423SLionel Sambuc } 422*433d6423SLionel Sambuc 423*433d6423SLionel Sambuc /* If a medium is newly detected, try reading its capacity now. */ 424*433d6423SLionel Sambuc if (!(ps->flags & FLAG_HAS_MEDIUM)) { 425*433d6423SLionel Sambuc if (atapi_read_capacity(ps, cmd) != OK) 426*433d6423SLionel Sambuc return EIO; 427*433d6423SLionel Sambuc 428*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_MEDIUM; 429*433d6423SLionel Sambuc } 430*433d6423SLionel Sambuc 431*433d6423SLionel Sambuc return OK; 432*433d6423SLionel Sambuc } 433*433d6423SLionel Sambuc 434*433d6423SLionel Sambuc /*===========================================================================* 435*433d6423SLionel Sambuc * atapi_id_check * 436*433d6423SLionel Sambuc *===========================================================================*/ 437*433d6423SLionel Sambuc static int atapi_id_check(struct port_state *ps, u16_t *buf) 438*433d6423SLionel Sambuc { 439*433d6423SLionel Sambuc /* Determine whether we support this ATAPI device based on the 440*433d6423SLionel Sambuc * identification data it returned, and store some of its properties. 441*433d6423SLionel Sambuc */ 442*433d6423SLionel Sambuc 443*433d6423SLionel Sambuc /* The device must be an ATAPI device; it must have removable media; 444*433d6423SLionel Sambuc * it must support DMA without DMADIR, or DMADIR for DMA. 445*433d6423SLionel Sambuc */ 446*433d6423SLionel Sambuc if ((buf[ATA_ID_GCAP] & (ATA_ID_GCAP_ATAPI_MASK | 447*433d6423SLionel Sambuc ATA_ID_GCAP_REMOVABLE | ATA_ID_GCAP_INCOMPLETE)) != 448*433d6423SLionel Sambuc (ATA_ID_GCAP_ATAPI | ATA_ID_GCAP_REMOVABLE) || 449*433d6423SLionel Sambuc ((buf[ATA_ID_CAP] & ATA_ID_CAP_DMA) != ATA_ID_CAP_DMA && 450*433d6423SLionel Sambuc (buf[ATA_ID_DMADIR] & (ATA_ID_DMADIR_DMADIR | 451*433d6423SLionel Sambuc ATA_ID_DMADIR_DMA)) != (ATA_ID_DMADIR_DMADIR | 452*433d6423SLionel Sambuc ATA_ID_DMADIR_DMA))) { 453*433d6423SLionel Sambuc 454*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unsupported ATAPI device\n", 455*433d6423SLionel Sambuc ahci_portname(ps))); 456*433d6423SLionel Sambuc 457*433d6423SLionel Sambuc dprintf(V_DEV, ("%s: GCAP %04x CAP %04x DMADIR %04x\n", 458*433d6423SLionel Sambuc ahci_portname(ps), buf[ATA_ID_GCAP], buf[ATA_ID_CAP], 459*433d6423SLionel Sambuc buf[ATA_ID_DMADIR])); 460*433d6423SLionel Sambuc 461*433d6423SLionel Sambuc return FALSE; 462*433d6423SLionel Sambuc } 463*433d6423SLionel Sambuc 464*433d6423SLionel Sambuc /* Remember whether to use the DMADIR flag when appropriate. */ 465*433d6423SLionel Sambuc if (buf[ATA_ID_DMADIR] & ATA_ID_DMADIR_DMADIR) 466*433d6423SLionel Sambuc ps->flags |= FLAG_USE_DMADIR; 467*433d6423SLionel Sambuc 468*433d6423SLionel Sambuc /* ATAPI CD-ROM devices are considered read-only. */ 469*433d6423SLionel Sambuc if (((buf[ATA_ID_GCAP] & ATA_ID_GCAP_TYPE_MASK) >> 470*433d6423SLionel Sambuc ATA_ID_GCAP_TYPE_SHIFT) == ATAPI_TYPE_CDROM) 471*433d6423SLionel Sambuc ps->flags |= FLAG_READONLY; 472*433d6423SLionel Sambuc 473*433d6423SLionel Sambuc if ((buf[ATA_ID_SUP1] & ATA_ID_SUP1_VALID_MASK) == ATA_ID_SUP1_VALID && 474*433d6423SLionel Sambuc !(ps->flags & FLAG_READONLY)) { 475*433d6423SLionel Sambuc /* Save write cache related capabilities of the device. It is 476*433d6423SLionel Sambuc * possible, although unlikely, that a device has support for 477*433d6423SLionel Sambuc * either of these but not both. 478*433d6423SLionel Sambuc */ 479*433d6423SLionel Sambuc if (buf[ATA_ID_SUP0] & ATA_ID_SUP0_WCACHE) 480*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_WCACHE; 481*433d6423SLionel Sambuc 482*433d6423SLionel Sambuc if (buf[ATA_ID_SUP1] & ATA_ID_SUP1_FLUSH) 483*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_FLUSH; 484*433d6423SLionel Sambuc } 485*433d6423SLionel Sambuc 486*433d6423SLionel Sambuc return TRUE; 487*433d6423SLionel Sambuc } 488*433d6423SLionel Sambuc 489*433d6423SLionel Sambuc /*===========================================================================* 490*433d6423SLionel Sambuc * atapi_transfer * 491*433d6423SLionel Sambuc *===========================================================================*/ 492*433d6423SLionel Sambuc static int atapi_transfer(struct port_state *ps, int cmd, u64_t start_lba, 493*433d6423SLionel Sambuc unsigned int count, int write, prd_t *prdt, int nr_prds) 494*433d6423SLionel Sambuc { 495*433d6423SLionel Sambuc /* Perform data transfer from or to an ATAPI device. 496*433d6423SLionel Sambuc */ 497*433d6423SLionel Sambuc cmd_fis_t fis; 498*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE]; 499*433d6423SLionel Sambuc 500*433d6423SLionel Sambuc /* Fill in a Register Host to Device FIS. */ 501*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 502*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_PACKET; 503*433d6423SLionel Sambuc fis.cf_feat = ATA_FEAT_PACKET_DMA; 504*433d6423SLionel Sambuc if (!write && (ps->flags & FLAG_USE_DMADIR)) 505*433d6423SLionel Sambuc fis.cf_feat |= ATA_FEAT_PACKET_DMADIR; 506*433d6423SLionel Sambuc 507*433d6423SLionel Sambuc /* Fill in a packet. */ 508*433d6423SLionel Sambuc memset(packet, 0, sizeof(packet)); 509*433d6423SLionel Sambuc packet[0] = write ? ATAPI_CMD_WRITE : ATAPI_CMD_READ; 510*433d6423SLionel Sambuc packet[2] = (start_lba >> 24) & 0xFF; 511*433d6423SLionel Sambuc packet[3] = (start_lba >> 16) & 0xFF; 512*433d6423SLionel Sambuc packet[4] = (start_lba >> 8) & 0xFF; 513*433d6423SLionel Sambuc packet[5] = start_lba & 0xFF; 514*433d6423SLionel Sambuc packet[6] = (count >> 24) & 0xFF; 515*433d6423SLionel Sambuc packet[7] = (count >> 16) & 0xFF; 516*433d6423SLionel Sambuc packet[8] = (count >> 8) & 0xFF; 517*433d6423SLionel Sambuc packet[9] = count & 0xFF; 518*433d6423SLionel Sambuc 519*433d6423SLionel Sambuc /* Start the command, and wait for it to complete or fail. */ 520*433d6423SLionel Sambuc port_set_cmd(ps, cmd, &fis, packet, prdt, nr_prds, write); 521*433d6423SLionel Sambuc 522*433d6423SLionel Sambuc return port_exec(ps, cmd, ahci_transfer_timeout); 523*433d6423SLionel Sambuc } 524*433d6423SLionel Sambuc 525*433d6423SLionel Sambuc /*===========================================================================* 526*433d6423SLionel Sambuc * ata_id_check * 527*433d6423SLionel Sambuc *===========================================================================*/ 528*433d6423SLionel Sambuc static int ata_id_check(struct port_state *ps, u16_t *buf) 529*433d6423SLionel Sambuc { 530*433d6423SLionel Sambuc /* Determine whether we support this ATA device based on the 531*433d6423SLionel Sambuc * identification data it returned, and store some of its properties. 532*433d6423SLionel Sambuc */ 533*433d6423SLionel Sambuc 534*433d6423SLionel Sambuc /* This must be an ATA device; it must not have removable media; 535*433d6423SLionel Sambuc * it must support LBA and DMA; it must support the FLUSH CACHE 536*433d6423SLionel Sambuc * command; it must support 48-bit addressing. 537*433d6423SLionel Sambuc */ 538*433d6423SLionel Sambuc if ((buf[ATA_ID_GCAP] & (ATA_ID_GCAP_ATA_MASK | ATA_ID_GCAP_REMOVABLE | 539*433d6423SLionel Sambuc ATA_ID_GCAP_INCOMPLETE)) != ATA_ID_GCAP_ATA || 540*433d6423SLionel Sambuc (buf[ATA_ID_CAP] & (ATA_ID_CAP_LBA | ATA_ID_CAP_DMA)) != 541*433d6423SLionel Sambuc (ATA_ID_CAP_LBA | ATA_ID_CAP_DMA) || 542*433d6423SLionel Sambuc (buf[ATA_ID_SUP1] & (ATA_ID_SUP1_VALID_MASK | 543*433d6423SLionel Sambuc ATA_ID_SUP1_FLUSH | ATA_ID_SUP1_LBA48)) != 544*433d6423SLionel Sambuc (ATA_ID_SUP1_VALID | ATA_ID_SUP1_FLUSH | ATA_ID_SUP1_LBA48)) { 545*433d6423SLionel Sambuc 546*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unsupported ATA device\n", 547*433d6423SLionel Sambuc ahci_portname(ps))); 548*433d6423SLionel Sambuc 549*433d6423SLionel Sambuc dprintf(V_DEV, ("%s: GCAP %04x CAP %04x SUP1 %04x\n", 550*433d6423SLionel Sambuc ahci_portname(ps), buf[ATA_ID_GCAP], buf[ATA_ID_CAP], 551*433d6423SLionel Sambuc buf[ATA_ID_SUP1])); 552*433d6423SLionel Sambuc 553*433d6423SLionel Sambuc return FALSE; 554*433d6423SLionel Sambuc } 555*433d6423SLionel Sambuc 556*433d6423SLionel Sambuc /* Get number of LBA blocks, and sector size. */ 557*433d6423SLionel Sambuc ps->lba_count = ((u64_t) buf[ATA_ID_LBA3] << 48) | 558*433d6423SLionel Sambuc ((u64_t) buf[ATA_ID_LBA2] << 32) | 559*433d6423SLionel Sambuc ((u64_t) buf[ATA_ID_LBA1] << 16) | 560*433d6423SLionel Sambuc (u64_t) buf[ATA_ID_LBA0]; 561*433d6423SLionel Sambuc 562*433d6423SLionel Sambuc /* Determine the queue depth of the device. */ 563*433d6423SLionel Sambuc if (hba_state.has_ncq && 564*433d6423SLionel Sambuc (buf[ATA_ID_SATA_CAP] & ATA_ID_SATA_CAP_NCQ)) { 565*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_NCQ; 566*433d6423SLionel Sambuc ps->queue_depth = 567*433d6423SLionel Sambuc (buf[ATA_ID_QDEPTH] & ATA_ID_QDEPTH_MASK) + 1; 568*433d6423SLionel Sambuc if (ps->queue_depth > hba_state.nr_cmds) 569*433d6423SLionel Sambuc ps->queue_depth = hba_state.nr_cmds; 570*433d6423SLionel Sambuc } 571*433d6423SLionel Sambuc 572*433d6423SLionel Sambuc /* For now, we only support long logical sectors. Long physical sector 573*433d6423SLionel Sambuc * support may be added later. Note that the given value is in words. 574*433d6423SLionel Sambuc */ 575*433d6423SLionel Sambuc if ((buf[ATA_ID_PLSS] & (ATA_ID_PLSS_VALID_MASK | ATA_ID_PLSS_LLS)) == 576*433d6423SLionel Sambuc (ATA_ID_PLSS_VALID | ATA_ID_PLSS_LLS)) 577*433d6423SLionel Sambuc ps->sector_size = 578*433d6423SLionel Sambuc ((buf[ATA_ID_LSS1] << 16) | buf[ATA_ID_LSS0]) << 1; 579*433d6423SLionel Sambuc else 580*433d6423SLionel Sambuc ps->sector_size = ATA_SECTOR_SIZE; 581*433d6423SLionel Sambuc 582*433d6423SLionel Sambuc if (ps->sector_size < ATA_SECTOR_SIZE) { 583*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: invalid sector size %u\n", 584*433d6423SLionel Sambuc ahci_portname(ps), ps->sector_size)); 585*433d6423SLionel Sambuc 586*433d6423SLionel Sambuc return FALSE; 587*433d6423SLionel Sambuc } 588*433d6423SLionel Sambuc 589*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_MEDIUM | FLAG_HAS_FLUSH; 590*433d6423SLionel Sambuc 591*433d6423SLionel Sambuc /* FLUSH CACHE is mandatory for ATA devices; write caches are not. */ 592*433d6423SLionel Sambuc if (buf[ATA_ID_SUP0] & ATA_ID_SUP0_WCACHE) 593*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_WCACHE; 594*433d6423SLionel Sambuc 595*433d6423SLionel Sambuc /* Check Force Unit Access capability of the device. */ 596*433d6423SLionel Sambuc if ((buf[ATA_ID_ENA2] & (ATA_ID_ENA2_VALID_MASK | ATA_ID_ENA2_FUA)) == 597*433d6423SLionel Sambuc (ATA_ID_ENA2_VALID | ATA_ID_ENA2_FUA)) 598*433d6423SLionel Sambuc ps->flags |= FLAG_HAS_FUA; 599*433d6423SLionel Sambuc 600*433d6423SLionel Sambuc return TRUE; 601*433d6423SLionel Sambuc } 602*433d6423SLionel Sambuc 603*433d6423SLionel Sambuc /*===========================================================================* 604*433d6423SLionel Sambuc * ata_transfer * 605*433d6423SLionel Sambuc *===========================================================================*/ 606*433d6423SLionel Sambuc static int ata_transfer(struct port_state *ps, int cmd, u64_t start_lba, 607*433d6423SLionel Sambuc unsigned int count, int write, int force, prd_t *prdt, int nr_prds) 608*433d6423SLionel Sambuc { 609*433d6423SLionel Sambuc /* Perform data transfer from or to an ATA device. 610*433d6423SLionel Sambuc */ 611*433d6423SLionel Sambuc cmd_fis_t fis; 612*433d6423SLionel Sambuc 613*433d6423SLionel Sambuc assert(count <= ATA_MAX_SECTORS); 614*433d6423SLionel Sambuc 615*433d6423SLionel Sambuc /* Special case for sector counts: 65536 is specified as 0. */ 616*433d6423SLionel Sambuc if (count == ATA_MAX_SECTORS) 617*433d6423SLionel Sambuc count = 0; 618*433d6423SLionel Sambuc 619*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 620*433d6423SLionel Sambuc fis.cf_dev = ATA_DEV_LBA; 621*433d6423SLionel Sambuc if (ps->flags & FLAG_HAS_NCQ) { 622*433d6423SLionel Sambuc if (write) { 623*433d6423SLionel Sambuc if (force && (ps->flags & FLAG_HAS_FUA)) 624*433d6423SLionel Sambuc fis.cf_dev |= ATA_DEV_FUA; 625*433d6423SLionel Sambuc 626*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_WRITE_FPDMA_QUEUED; 627*433d6423SLionel Sambuc } else { 628*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_READ_FPDMA_QUEUED; 629*433d6423SLionel Sambuc } 630*433d6423SLionel Sambuc } 631*433d6423SLionel Sambuc else { 632*433d6423SLionel Sambuc if (write) { 633*433d6423SLionel Sambuc if (force && (ps->flags & FLAG_HAS_FUA)) 634*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_WRITE_DMA_FUA_EXT; 635*433d6423SLionel Sambuc else 636*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_WRITE_DMA_EXT; 637*433d6423SLionel Sambuc } 638*433d6423SLionel Sambuc else { 639*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_READ_DMA_EXT; 640*433d6423SLionel Sambuc } 641*433d6423SLionel Sambuc } 642*433d6423SLionel Sambuc fis.cf_lba = start_lba & 0x00FFFFFFUL; 643*433d6423SLionel Sambuc fis.cf_lba_exp = (start_lba >> 24) & 0x00FFFFFFUL; 644*433d6423SLionel Sambuc fis.cf_sec = count & 0xFF; 645*433d6423SLionel Sambuc fis.cf_sec_exp = (count >> 8) & 0xFF; 646*433d6423SLionel Sambuc 647*433d6423SLionel Sambuc /* Start the command, and wait for it to complete or fail. */ 648*433d6423SLionel Sambuc port_set_cmd(ps, cmd, &fis, NULL /*packet*/, prdt, nr_prds, write); 649*433d6423SLionel Sambuc 650*433d6423SLionel Sambuc return port_exec(ps, cmd, ahci_transfer_timeout); 651*433d6423SLionel Sambuc } 652*433d6423SLionel Sambuc 653*433d6423SLionel Sambuc /*===========================================================================* 654*433d6423SLionel Sambuc * gen_identify * 655*433d6423SLionel Sambuc *===========================================================================*/ 656*433d6423SLionel Sambuc static int gen_identify(struct port_state *ps, int blocking) 657*433d6423SLionel Sambuc { 658*433d6423SLionel Sambuc /* Identify an ATA or ATAPI device. If the blocking flag is set, block 659*433d6423SLionel Sambuc * until the command has completed; otherwise return immediately. 660*433d6423SLionel Sambuc */ 661*433d6423SLionel Sambuc cmd_fis_t fis; 662*433d6423SLionel Sambuc prd_t prd; 663*433d6423SLionel Sambuc 664*433d6423SLionel Sambuc /* Set up a command, and a single PRD for the result. */ 665*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 666*433d6423SLionel Sambuc 667*433d6423SLionel Sambuc if (ps->flags & FLAG_ATAPI) 668*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_IDENTIFY_PACKET; 669*433d6423SLionel Sambuc else 670*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_IDENTIFY; 671*433d6423SLionel Sambuc 672*433d6423SLionel Sambuc prd.vp_addr = ps->tmp_phys; 673*433d6423SLionel Sambuc prd.vp_size = ATA_ID_SIZE; 674*433d6423SLionel Sambuc 675*433d6423SLionel Sambuc /* Start the command, and possibly wait for the result. */ 676*433d6423SLionel Sambuc port_set_cmd(ps, 0, &fis, NULL /*packet*/, &prd, 1, FALSE /*write*/); 677*433d6423SLionel Sambuc 678*433d6423SLionel Sambuc if (blocking) 679*433d6423SLionel Sambuc return port_exec(ps, 0, ahci_command_timeout); 680*433d6423SLionel Sambuc 681*433d6423SLionel Sambuc port_issue(ps, 0, ahci_command_timeout); 682*433d6423SLionel Sambuc 683*433d6423SLionel Sambuc return OK; 684*433d6423SLionel Sambuc } 685*433d6423SLionel Sambuc 686*433d6423SLionel Sambuc /*===========================================================================* 687*433d6423SLionel Sambuc * gen_flush_wcache * 688*433d6423SLionel Sambuc *===========================================================================*/ 689*433d6423SLionel Sambuc static int gen_flush_wcache(struct port_state *ps) 690*433d6423SLionel Sambuc { 691*433d6423SLionel Sambuc /* Flush the device's write cache. 692*433d6423SLionel Sambuc */ 693*433d6423SLionel Sambuc cmd_fis_t fis; 694*433d6423SLionel Sambuc 695*433d6423SLionel Sambuc /* The FLUSH CACHE command may not be supported by all (writable ATAPI) 696*433d6423SLionel Sambuc * devices. 697*433d6423SLionel Sambuc */ 698*433d6423SLionel Sambuc if (!(ps->flags & FLAG_HAS_FLUSH)) 699*433d6423SLionel Sambuc return EINVAL; 700*433d6423SLionel Sambuc 701*433d6423SLionel Sambuc /* Use the FLUSH CACHE command for both ATA and ATAPI. We are not 702*433d6423SLionel Sambuc * interested in the disk location of a failure, so there is no reason 703*433d6423SLionel Sambuc * to use the ATA-only FLUSH CACHE EXT command. Either way, the command 704*433d6423SLionel Sambuc * may indeed fail due to a disk error, in which case it should be 705*433d6423SLionel Sambuc * repeated. For now, we shift this responsibility onto the caller. 706*433d6423SLionel Sambuc */ 707*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 708*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_FLUSH_CACHE; 709*433d6423SLionel Sambuc 710*433d6423SLionel Sambuc /* Start the command, and wait for it to complete or fail. 711*433d6423SLionel Sambuc * The flush command may take longer than regular I/O commands. 712*433d6423SLionel Sambuc */ 713*433d6423SLionel Sambuc port_set_cmd(ps, 0, &fis, NULL /*packet*/, NULL /*prdt*/, 0, 714*433d6423SLionel Sambuc FALSE /*write*/); 715*433d6423SLionel Sambuc 716*433d6423SLionel Sambuc return port_exec(ps, 0, ahci_flush_timeout); 717*433d6423SLionel Sambuc } 718*433d6423SLionel Sambuc 719*433d6423SLionel Sambuc /*===========================================================================* 720*433d6423SLionel Sambuc * gen_get_wcache * 721*433d6423SLionel Sambuc *===========================================================================*/ 722*433d6423SLionel Sambuc static int gen_get_wcache(struct port_state *ps, int *val) 723*433d6423SLionel Sambuc { 724*433d6423SLionel Sambuc /* Retrieve the status of the device's write cache. 725*433d6423SLionel Sambuc */ 726*433d6423SLionel Sambuc int r; 727*433d6423SLionel Sambuc 728*433d6423SLionel Sambuc /* Write caches are not mandatory. */ 729*433d6423SLionel Sambuc if (!(ps->flags & FLAG_HAS_WCACHE)) 730*433d6423SLionel Sambuc return EINVAL; 731*433d6423SLionel Sambuc 732*433d6423SLionel Sambuc /* Retrieve information about the device. */ 733*433d6423SLionel Sambuc if ((r = gen_identify(ps, TRUE /*blocking*/)) != OK) 734*433d6423SLionel Sambuc return r; 735*433d6423SLionel Sambuc 736*433d6423SLionel Sambuc /* Return the current setting. */ 737*433d6423SLionel Sambuc *val = !!(((u16_t *) ps->tmp_base)[ATA_ID_ENA0] & ATA_ID_ENA0_WCACHE); 738*433d6423SLionel Sambuc 739*433d6423SLionel Sambuc return OK; 740*433d6423SLionel Sambuc } 741*433d6423SLionel Sambuc 742*433d6423SLionel Sambuc /*===========================================================================* 743*433d6423SLionel Sambuc * gen_set_wcache * 744*433d6423SLionel Sambuc *===========================================================================*/ 745*433d6423SLionel Sambuc static int gen_set_wcache(struct port_state *ps, int enable) 746*433d6423SLionel Sambuc { 747*433d6423SLionel Sambuc /* Enable or disable the device's write cache. 748*433d6423SLionel Sambuc */ 749*433d6423SLionel Sambuc cmd_fis_t fis; 750*433d6423SLionel Sambuc clock_t timeout; 751*433d6423SLionel Sambuc 752*433d6423SLionel Sambuc /* Write caches are not mandatory. */ 753*433d6423SLionel Sambuc if (!(ps->flags & FLAG_HAS_WCACHE)) 754*433d6423SLionel Sambuc return EINVAL; 755*433d6423SLionel Sambuc 756*433d6423SLionel Sambuc /* Disabling the write cache causes a (blocking) cache flush. Cache 757*433d6423SLionel Sambuc * flushes may take much longer than regular commands. 758*433d6423SLionel Sambuc */ 759*433d6423SLionel Sambuc timeout = enable ? ahci_command_timeout : ahci_flush_timeout; 760*433d6423SLionel Sambuc 761*433d6423SLionel Sambuc /* Set up a command. */ 762*433d6423SLionel Sambuc memset(&fis, 0, sizeof(fis)); 763*433d6423SLionel Sambuc fis.cf_cmd = ATA_CMD_SET_FEATURES; 764*433d6423SLionel Sambuc fis.cf_feat = enable ? ATA_SF_EN_WCACHE : ATA_SF_DI_WCACHE; 765*433d6423SLionel Sambuc 766*433d6423SLionel Sambuc /* Start the command, and wait for it to complete or fail. */ 767*433d6423SLionel Sambuc port_set_cmd(ps, 0, &fis, NULL /*packet*/, NULL /*prdt*/, 0, 768*433d6423SLionel Sambuc FALSE /*write*/); 769*433d6423SLionel Sambuc 770*433d6423SLionel Sambuc return port_exec(ps, 0, timeout); 771*433d6423SLionel Sambuc } 772*433d6423SLionel Sambuc 773*433d6423SLionel Sambuc /*===========================================================================* 774*433d6423SLionel Sambuc * ct_set_fis * 775*433d6423SLionel Sambuc *===========================================================================*/ 776*433d6423SLionel Sambuc static vir_bytes ct_set_fis(u8_t *ct, cmd_fis_t *fis, unsigned int tag) 777*433d6423SLionel Sambuc { 778*433d6423SLionel Sambuc /* Fill in the Frame Information Structure part of a command table, 779*433d6423SLionel Sambuc * and return the resulting FIS size (in bytes). We only support the 780*433d6423SLionel Sambuc * command Register - Host to Device FIS type. 781*433d6423SLionel Sambuc */ 782*433d6423SLionel Sambuc 783*433d6423SLionel Sambuc memset(ct, 0, ATA_H2D_SIZE); 784*433d6423SLionel Sambuc ct[ATA_FIS_TYPE] = ATA_FIS_TYPE_H2D; 785*433d6423SLionel Sambuc ct[ATA_H2D_FLAGS] = ATA_H2D_FLAGS_C; 786*433d6423SLionel Sambuc ct[ATA_H2D_CMD] = fis->cf_cmd; 787*433d6423SLionel Sambuc ct[ATA_H2D_LBA_LOW] = fis->cf_lba & 0xFF; 788*433d6423SLionel Sambuc ct[ATA_H2D_LBA_MID] = (fis->cf_lba >> 8) & 0xFF; 789*433d6423SLionel Sambuc ct[ATA_H2D_LBA_HIGH] = (fis->cf_lba >> 16) & 0xFF; 790*433d6423SLionel Sambuc ct[ATA_H2D_DEV] = fis->cf_dev; 791*433d6423SLionel Sambuc ct[ATA_H2D_LBA_LOW_EXP] = fis->cf_lba_exp & 0xFF; 792*433d6423SLionel Sambuc ct[ATA_H2D_LBA_MID_EXP] = (fis->cf_lba_exp >> 8) & 0xFF; 793*433d6423SLionel Sambuc ct[ATA_H2D_LBA_HIGH_EXP] = (fis->cf_lba_exp >> 16) & 0xFF; 794*433d6423SLionel Sambuc ct[ATA_H2D_CTL] = fis->cf_ctl; 795*433d6423SLionel Sambuc 796*433d6423SLionel Sambuc if (ATA_IS_FPDMA_CMD(fis->cf_cmd)) { 797*433d6423SLionel Sambuc ct[ATA_H2D_FEAT] = fis->cf_sec; 798*433d6423SLionel Sambuc ct[ATA_H2D_FEAT_EXP] = fis->cf_sec_exp; 799*433d6423SLionel Sambuc ct[ATA_H2D_SEC] = tag << ATA_SEC_TAG_SHIFT; 800*433d6423SLionel Sambuc ct[ATA_H2D_SEC_EXP] = 0; 801*433d6423SLionel Sambuc } else { 802*433d6423SLionel Sambuc ct[ATA_H2D_FEAT] = fis->cf_feat; 803*433d6423SLionel Sambuc ct[ATA_H2D_FEAT_EXP] = fis->cf_feat_exp; 804*433d6423SLionel Sambuc ct[ATA_H2D_SEC] = fis->cf_sec; 805*433d6423SLionel Sambuc ct[ATA_H2D_SEC_EXP] = fis->cf_sec_exp; 806*433d6423SLionel Sambuc } 807*433d6423SLionel Sambuc 808*433d6423SLionel Sambuc return ATA_H2D_SIZE; 809*433d6423SLionel Sambuc } 810*433d6423SLionel Sambuc 811*433d6423SLionel Sambuc /*===========================================================================* 812*433d6423SLionel Sambuc * ct_set_packet * 813*433d6423SLionel Sambuc *===========================================================================*/ 814*433d6423SLionel Sambuc static void ct_set_packet(u8_t *ct, u8_t packet[ATAPI_PACKET_SIZE]) 815*433d6423SLionel Sambuc { 816*433d6423SLionel Sambuc /* Fill in the packet part of a command table. 817*433d6423SLionel Sambuc */ 818*433d6423SLionel Sambuc 819*433d6423SLionel Sambuc memcpy(&ct[AHCI_CT_PACKET_OFF], packet, ATAPI_PACKET_SIZE); 820*433d6423SLionel Sambuc } 821*433d6423SLionel Sambuc 822*433d6423SLionel Sambuc /*===========================================================================* 823*433d6423SLionel Sambuc * ct_set_prdt * 824*433d6423SLionel Sambuc *===========================================================================*/ 825*433d6423SLionel Sambuc static void ct_set_prdt(u8_t *ct, prd_t *prdt, int nr_prds) 826*433d6423SLionel Sambuc { 827*433d6423SLionel Sambuc /* Fill in the PRDT part of a command table. 828*433d6423SLionel Sambuc */ 829*433d6423SLionel Sambuc u32_t *p; 830*433d6423SLionel Sambuc int i; 831*433d6423SLionel Sambuc 832*433d6423SLionel Sambuc p = (u32_t *) &ct[AHCI_CT_PRDT_OFF]; 833*433d6423SLionel Sambuc 834*433d6423SLionel Sambuc for (i = 0; i < nr_prds; i++, prdt++) { 835*433d6423SLionel Sambuc *p++ = prdt->vp_addr; 836*433d6423SLionel Sambuc *p++ = 0; 837*433d6423SLionel Sambuc *p++ = 0; 838*433d6423SLionel Sambuc *p++ = prdt->vp_size - 1; 839*433d6423SLionel Sambuc } 840*433d6423SLionel Sambuc } 841*433d6423SLionel Sambuc 842*433d6423SLionel Sambuc /*===========================================================================* 843*433d6423SLionel Sambuc * port_set_cmd * 844*433d6423SLionel Sambuc *===========================================================================*/ 845*433d6423SLionel Sambuc static void port_set_cmd(struct port_state *ps, int cmd, cmd_fis_t *fis, 846*433d6423SLionel Sambuc u8_t packet[ATAPI_PACKET_SIZE], prd_t *prdt, int nr_prds, int write) 847*433d6423SLionel Sambuc { 848*433d6423SLionel Sambuc /* Prepare the given command for execution, by constructing a command 849*433d6423SLionel Sambuc * table and setting up a command list entry pointing to the table. 850*433d6423SLionel Sambuc */ 851*433d6423SLionel Sambuc u8_t *ct; 852*433d6423SLionel Sambuc u32_t *cl; 853*433d6423SLionel Sambuc vir_bytes size; 854*433d6423SLionel Sambuc 855*433d6423SLionel Sambuc /* Set a port-specific flag that tells us if the command being 856*433d6423SLionel Sambuc * processed is a NCQ command or not. 857*433d6423SLionel Sambuc */ 858*433d6423SLionel Sambuc if (ATA_IS_FPDMA_CMD(fis->cf_cmd)) { 859*433d6423SLionel Sambuc ps->flags |= FLAG_NCQ_MODE; 860*433d6423SLionel Sambuc } else { 861*433d6423SLionel Sambuc assert(!ps->pend_mask); 862*433d6423SLionel Sambuc ps->flags &= ~FLAG_NCQ_MODE; 863*433d6423SLionel Sambuc } 864*433d6423SLionel Sambuc 865*433d6423SLionel Sambuc /* Construct a command table, consisting of a command FIS, optionally 866*433d6423SLionel Sambuc * a packet, and optionally a number of PRDs (making up the actual PRD 867*433d6423SLionel Sambuc * table). 868*433d6423SLionel Sambuc */ 869*433d6423SLionel Sambuc ct = ps->ct_base[cmd]; 870*433d6423SLionel Sambuc 871*433d6423SLionel Sambuc assert(ct != NULL); 872*433d6423SLionel Sambuc assert(nr_prds <= NR_PRDS); 873*433d6423SLionel Sambuc 874*433d6423SLionel Sambuc size = ct_set_fis(ct, fis, cmd); 875*433d6423SLionel Sambuc 876*433d6423SLionel Sambuc if (packet != NULL) 877*433d6423SLionel Sambuc ct_set_packet(ct, packet); 878*433d6423SLionel Sambuc 879*433d6423SLionel Sambuc ct_set_prdt(ct, prdt, nr_prds); 880*433d6423SLionel Sambuc 881*433d6423SLionel Sambuc /* Construct a command list entry, pointing to the command's table. 882*433d6423SLionel Sambuc * Current assumptions: callers always provide a Register - Host to 883*433d6423SLionel Sambuc * Device type FIS, and all non-NCQ commands are prefetchable. 884*433d6423SLionel Sambuc */ 885*433d6423SLionel Sambuc cl = &ps->cl_base[cmd * AHCI_CL_ENTRY_DWORDS]; 886*433d6423SLionel Sambuc 887*433d6423SLionel Sambuc memset(cl, 0, AHCI_CL_ENTRY_SIZE); 888*433d6423SLionel Sambuc cl[0] = (nr_prds << AHCI_CL_PRDTL_SHIFT) | 889*433d6423SLionel Sambuc ((!ATA_IS_FPDMA_CMD(fis->cf_cmd) && 890*433d6423SLionel Sambuc (nr_prds > 0 || packet != NULL)) ? AHCI_CL_PREFETCHABLE : 0) | 891*433d6423SLionel Sambuc (write ? AHCI_CL_WRITE : 0) | 892*433d6423SLionel Sambuc ((packet != NULL) ? AHCI_CL_ATAPI : 0) | 893*433d6423SLionel Sambuc ((size / sizeof(u32_t)) << AHCI_CL_CFL_SHIFT); 894*433d6423SLionel Sambuc cl[2] = ps->ct_phys[cmd]; 895*433d6423SLionel Sambuc } 896*433d6423SLionel Sambuc 897*433d6423SLionel Sambuc /*===========================================================================* 898*433d6423SLionel Sambuc * port_finish_cmd * 899*433d6423SLionel Sambuc *===========================================================================*/ 900*433d6423SLionel Sambuc static void port_finish_cmd(struct port_state *ps, int cmd, int result) 901*433d6423SLionel Sambuc { 902*433d6423SLionel Sambuc /* Finish a command that has either succeeded or failed. 903*433d6423SLionel Sambuc */ 904*433d6423SLionel Sambuc 905*433d6423SLionel Sambuc assert(cmd < ps->queue_depth); 906*433d6423SLionel Sambuc 907*433d6423SLionel Sambuc dprintf(V_REQ, ("%s: command %d %s\n", ahci_portname(ps), 908*433d6423SLionel Sambuc cmd, (result == RESULT_SUCCESS) ? "succeeded" : "failed")); 909*433d6423SLionel Sambuc 910*433d6423SLionel Sambuc /* Update the command result, and clear it from the pending list. */ 911*433d6423SLionel Sambuc ps->cmd_info[cmd].result = result; 912*433d6423SLionel Sambuc 913*433d6423SLionel Sambuc assert(ps->pend_mask & (1 << cmd)); 914*433d6423SLionel Sambuc ps->pend_mask &= ~(1 << cmd); 915*433d6423SLionel Sambuc 916*433d6423SLionel Sambuc /* Wake up the thread, unless it is the main thread. This can happen 917*433d6423SLionel Sambuc * during initialization, as the gen_identify function is called by the 918*433d6423SLionel Sambuc * main thread itself. 919*433d6423SLionel Sambuc */ 920*433d6423SLionel Sambuc if (ps->state != STATE_WAIT_ID) 921*433d6423SLionel Sambuc blockdriver_mt_wakeup(ps->cmd_info[cmd].tid); 922*433d6423SLionel Sambuc } 923*433d6423SLionel Sambuc 924*433d6423SLionel Sambuc /*===========================================================================* 925*433d6423SLionel Sambuc * port_fail_cmds * 926*433d6423SLionel Sambuc *===========================================================================*/ 927*433d6423SLionel Sambuc static void port_fail_cmds(struct port_state *ps) 928*433d6423SLionel Sambuc { 929*433d6423SLionel Sambuc /* Fail all ongoing commands for a device. 930*433d6423SLionel Sambuc */ 931*433d6423SLionel Sambuc int i; 932*433d6423SLionel Sambuc 933*433d6423SLionel Sambuc for (i = 0; ps->pend_mask != 0 && i < ps->queue_depth; i++) 934*433d6423SLionel Sambuc if (ps->pend_mask & (1 << i)) 935*433d6423SLionel Sambuc port_finish_cmd(ps, i, RESULT_FAILURE); 936*433d6423SLionel Sambuc } 937*433d6423SLionel Sambuc 938*433d6423SLionel Sambuc /*===========================================================================* 939*433d6423SLionel Sambuc * port_check_cmds * 940*433d6423SLionel Sambuc *===========================================================================*/ 941*433d6423SLionel Sambuc static void port_check_cmds(struct port_state *ps) 942*433d6423SLionel Sambuc { 943*433d6423SLionel Sambuc /* Check what commands have completed, and finish them. 944*433d6423SLionel Sambuc */ 945*433d6423SLionel Sambuc u32_t mask, done; 946*433d6423SLionel Sambuc int i; 947*433d6423SLionel Sambuc 948*433d6423SLionel Sambuc /* See which commands have completed. */ 949*433d6423SLionel Sambuc if (ps->flags & FLAG_NCQ_MODE) 950*433d6423SLionel Sambuc mask = port_read(ps, AHCI_PORT_SACT); 951*433d6423SLionel Sambuc else 952*433d6423SLionel Sambuc mask = port_read(ps, AHCI_PORT_CI); 953*433d6423SLionel Sambuc 954*433d6423SLionel Sambuc /* Wake up threads corresponding to completed commands. */ 955*433d6423SLionel Sambuc done = ps->pend_mask & ~mask; 956*433d6423SLionel Sambuc 957*433d6423SLionel Sambuc for (i = 0; i < ps->queue_depth; i++) 958*433d6423SLionel Sambuc if (done & (1 << i)) 959*433d6423SLionel Sambuc port_finish_cmd(ps, i, RESULT_SUCCESS); 960*433d6423SLionel Sambuc } 961*433d6423SLionel Sambuc 962*433d6423SLionel Sambuc /*===========================================================================* 963*433d6423SLionel Sambuc * port_find_cmd * 964*433d6423SLionel Sambuc *===========================================================================*/ 965*433d6423SLionel Sambuc static int port_find_cmd(struct port_state *ps) 966*433d6423SLionel Sambuc { 967*433d6423SLionel Sambuc /* Find a free command tag to queue the current request. 968*433d6423SLionel Sambuc */ 969*433d6423SLionel Sambuc int i; 970*433d6423SLionel Sambuc 971*433d6423SLionel Sambuc for (i = 0; i < ps->queue_depth; i++) 972*433d6423SLionel Sambuc if (!(ps->pend_mask & (1 << i))) 973*433d6423SLionel Sambuc break; 974*433d6423SLionel Sambuc 975*433d6423SLionel Sambuc /* We should always be able to find a free slot, since a thread runs 976*433d6423SLionel Sambuc * only when it is free, and thus, only because a slot is available. 977*433d6423SLionel Sambuc */ 978*433d6423SLionel Sambuc assert(i < ps->queue_depth); 979*433d6423SLionel Sambuc 980*433d6423SLionel Sambuc return i; 981*433d6423SLionel Sambuc } 982*433d6423SLionel Sambuc 983*433d6423SLionel Sambuc /*===========================================================================* 984*433d6423SLionel Sambuc * port_get_padbuf * 985*433d6423SLionel Sambuc *===========================================================================*/ 986*433d6423SLionel Sambuc static int port_get_padbuf(struct port_state *ps, size_t size) 987*433d6423SLionel Sambuc { 988*433d6423SLionel Sambuc /* Make available a temporary buffer for use by this port. Enlarge the 989*433d6423SLionel Sambuc * previous buffer if applicable and necessary, potentially changing 990*433d6423SLionel Sambuc * its physical address. 991*433d6423SLionel Sambuc */ 992*433d6423SLionel Sambuc 993*433d6423SLionel Sambuc if (ps->pad_base != NULL && ps->pad_size >= size) 994*433d6423SLionel Sambuc return OK; 995*433d6423SLionel Sambuc 996*433d6423SLionel Sambuc if (ps->pad_base != NULL) 997*433d6423SLionel Sambuc free_contig(ps->pad_base, ps->pad_size); 998*433d6423SLionel Sambuc 999*433d6423SLionel Sambuc ps->pad_size = size; 1000*433d6423SLionel Sambuc ps->pad_base = alloc_contig(ps->pad_size, 0, &ps->pad_phys); 1001*433d6423SLionel Sambuc 1002*433d6423SLionel Sambuc if (ps->pad_base == NULL) { 1003*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unable to allocate a padding buffer of " 1004*433d6423SLionel Sambuc "size %lu\n", ahci_portname(ps), 1005*433d6423SLionel Sambuc (unsigned long) size)); 1006*433d6423SLionel Sambuc 1007*433d6423SLionel Sambuc return ENOMEM; 1008*433d6423SLionel Sambuc } 1009*433d6423SLionel Sambuc 1010*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: allocated padding buffer of size %lu\n", 1011*433d6423SLionel Sambuc ahci_portname(ps), (unsigned long) size)); 1012*433d6423SLionel Sambuc 1013*433d6423SLionel Sambuc return OK; 1014*433d6423SLionel Sambuc } 1015*433d6423SLionel Sambuc 1016*433d6423SLionel Sambuc /*===========================================================================* 1017*433d6423SLionel Sambuc * sum_iovec * 1018*433d6423SLionel Sambuc *===========================================================================*/ 1019*433d6423SLionel Sambuc static int sum_iovec(struct port_state *ps, endpoint_t endpt, 1020*433d6423SLionel Sambuc iovec_s_t *iovec, int nr_req, vir_bytes *total) 1021*433d6423SLionel Sambuc { 1022*433d6423SLionel Sambuc /* Retrieve the total size of the given I/O vector. Check for alignment 1023*433d6423SLionel Sambuc * requirements along the way. Return OK (and the total request size) 1024*433d6423SLionel Sambuc * or an error. 1025*433d6423SLionel Sambuc */ 1026*433d6423SLionel Sambuc vir_bytes size, bytes; 1027*433d6423SLionel Sambuc int i; 1028*433d6423SLionel Sambuc 1029*433d6423SLionel Sambuc bytes = 0; 1030*433d6423SLionel Sambuc 1031*433d6423SLionel Sambuc for (i = 0; i < nr_req; i++) { 1032*433d6423SLionel Sambuc size = iovec[i].iov_size; 1033*433d6423SLionel Sambuc 1034*433d6423SLionel Sambuc if (size == 0 || (size & 1) || size > LONG_MAX) { 1035*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: bad size %lu in iovec from %d\n", 1036*433d6423SLionel Sambuc ahci_portname(ps), size, endpt)); 1037*433d6423SLionel Sambuc return EINVAL; 1038*433d6423SLionel Sambuc } 1039*433d6423SLionel Sambuc 1040*433d6423SLionel Sambuc bytes += size; 1041*433d6423SLionel Sambuc 1042*433d6423SLionel Sambuc if (bytes > LONG_MAX) { 1043*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: iovec size overflow from %d\n", 1044*433d6423SLionel Sambuc ahci_portname(ps), endpt)); 1045*433d6423SLionel Sambuc return EINVAL; 1046*433d6423SLionel Sambuc } 1047*433d6423SLionel Sambuc } 1048*433d6423SLionel Sambuc 1049*433d6423SLionel Sambuc *total = bytes; 1050*433d6423SLionel Sambuc return OK; 1051*433d6423SLionel Sambuc } 1052*433d6423SLionel Sambuc 1053*433d6423SLionel Sambuc /*===========================================================================* 1054*433d6423SLionel Sambuc * setup_prdt * 1055*433d6423SLionel Sambuc *===========================================================================*/ 1056*433d6423SLionel Sambuc static int setup_prdt(struct port_state *ps, endpoint_t endpt, 1057*433d6423SLionel Sambuc iovec_s_t *iovec, int nr_req, vir_bytes size, vir_bytes lead, 1058*433d6423SLionel Sambuc int write, prd_t *prdt) 1059*433d6423SLionel Sambuc { 1060*433d6423SLionel Sambuc /* Convert (the first part of) an I/O vector to a Physical Region 1061*433d6423SLionel Sambuc * Descriptor Table describing array that can later be used to set the 1062*433d6423SLionel Sambuc * command's real PRDT. The resulting table as a whole should be 1063*433d6423SLionel Sambuc * sector-aligned; leading and trailing local buffers may have to be 1064*433d6423SLionel Sambuc * used for padding as appropriate. Return the number of PRD entries, 1065*433d6423SLionel Sambuc * or a negative error code. 1066*433d6423SLionel Sambuc */ 1067*433d6423SLionel Sambuc struct vumap_vir vvec[NR_PRDS]; 1068*433d6423SLionel Sambuc size_t bytes, trail; 1069*433d6423SLionel Sambuc int i, r, pcount, nr_prds = 0; 1070*433d6423SLionel Sambuc 1071*433d6423SLionel Sambuc if (lead > 0) { 1072*433d6423SLionel Sambuc /* Allocate a buffer for the data we don't want. */ 1073*433d6423SLionel Sambuc if ((r = port_get_padbuf(ps, ps->sector_size)) != OK) 1074*433d6423SLionel Sambuc return r; 1075*433d6423SLionel Sambuc 1076*433d6423SLionel Sambuc prdt[nr_prds].vp_addr = ps->pad_phys; 1077*433d6423SLionel Sambuc prdt[nr_prds].vp_size = lead; 1078*433d6423SLionel Sambuc nr_prds++; 1079*433d6423SLionel Sambuc } 1080*433d6423SLionel Sambuc 1081*433d6423SLionel Sambuc /* The sum of lead, size, trail has to be sector-aligned. */ 1082*433d6423SLionel Sambuc trail = (ps->sector_size - (lead + size)) % ps->sector_size; 1083*433d6423SLionel Sambuc 1084*433d6423SLionel Sambuc /* Get the physical addresses of the given buffers. */ 1085*433d6423SLionel Sambuc for (i = 0; i < nr_req && size > 0; i++) { 1086*433d6423SLionel Sambuc bytes = MIN(iovec[i].iov_size, size); 1087*433d6423SLionel Sambuc 1088*433d6423SLionel Sambuc if (endpt == SELF) 1089*433d6423SLionel Sambuc vvec[i].vv_addr = (vir_bytes) iovec[i].iov_grant; 1090*433d6423SLionel Sambuc else 1091*433d6423SLionel Sambuc vvec[i].vv_grant = iovec[i].iov_grant; 1092*433d6423SLionel Sambuc 1093*433d6423SLionel Sambuc vvec[i].vv_size = bytes; 1094*433d6423SLionel Sambuc 1095*433d6423SLionel Sambuc size -= bytes; 1096*433d6423SLionel Sambuc } 1097*433d6423SLionel Sambuc 1098*433d6423SLionel Sambuc pcount = i; 1099*433d6423SLionel Sambuc 1100*433d6423SLionel Sambuc if ((r = sys_vumap(endpt, vvec, i, 0, write ? VUA_READ : VUA_WRITE, 1101*433d6423SLionel Sambuc &prdt[nr_prds], &pcount)) != OK) { 1102*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unable to map memory from %d (%d)\n", 1103*433d6423SLionel Sambuc ahci_portname(ps), endpt, r)); 1104*433d6423SLionel Sambuc return r; 1105*433d6423SLionel Sambuc } 1106*433d6423SLionel Sambuc 1107*433d6423SLionel Sambuc assert(pcount > 0 && pcount <= i); 1108*433d6423SLionel Sambuc 1109*433d6423SLionel Sambuc /* Make sure all buffers are physically contiguous and word-aligned. */ 1110*433d6423SLionel Sambuc for (i = 0; i < pcount; i++) { 1111*433d6423SLionel Sambuc if (vvec[i].vv_size != prdt[nr_prds].vp_size) { 1112*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: non-contiguous memory from %d\n", 1113*433d6423SLionel Sambuc ahci_portname(ps), endpt)); 1114*433d6423SLionel Sambuc return EINVAL; 1115*433d6423SLionel Sambuc } 1116*433d6423SLionel Sambuc 1117*433d6423SLionel Sambuc if (prdt[nr_prds].vp_addr & 1) { 1118*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: bad physical address from %d\n", 1119*433d6423SLionel Sambuc ahci_portname(ps), endpt)); 1120*433d6423SLionel Sambuc return EINVAL; 1121*433d6423SLionel Sambuc } 1122*433d6423SLionel Sambuc 1123*433d6423SLionel Sambuc nr_prds++; 1124*433d6423SLionel Sambuc } 1125*433d6423SLionel Sambuc 1126*433d6423SLionel Sambuc if (trail > 0) { 1127*433d6423SLionel Sambuc assert(nr_prds < NR_PRDS); 1128*433d6423SLionel Sambuc prdt[nr_prds].vp_addr = ps->pad_phys + lead; 1129*433d6423SLionel Sambuc prdt[nr_prds].vp_size = trail; 1130*433d6423SLionel Sambuc nr_prds++; 1131*433d6423SLionel Sambuc } 1132*433d6423SLionel Sambuc 1133*433d6423SLionel Sambuc return nr_prds; 1134*433d6423SLionel Sambuc } 1135*433d6423SLionel Sambuc 1136*433d6423SLionel Sambuc /*===========================================================================* 1137*433d6423SLionel Sambuc * port_transfer * 1138*433d6423SLionel Sambuc *===========================================================================*/ 1139*433d6423SLionel Sambuc static ssize_t port_transfer(struct port_state *ps, u64_t pos, u64_t eof, 1140*433d6423SLionel Sambuc endpoint_t endpt, iovec_s_t *iovec, int nr_req, int write, int flags) 1141*433d6423SLionel Sambuc { 1142*433d6423SLionel Sambuc /* Perform an I/O transfer on a port. 1143*433d6423SLionel Sambuc */ 1144*433d6423SLionel Sambuc prd_t prdt[NR_PRDS]; 1145*433d6423SLionel Sambuc vir_bytes size, lead; 1146*433d6423SLionel Sambuc unsigned int count, nr_prds; 1147*433d6423SLionel Sambuc u64_t start_lba; 1148*433d6423SLionel Sambuc int r, cmd; 1149*433d6423SLionel Sambuc 1150*433d6423SLionel Sambuc /* Get the total request size from the I/O vector. */ 1151*433d6423SLionel Sambuc if ((r = sum_iovec(ps, endpt, iovec, nr_req, &size)) != OK) 1152*433d6423SLionel Sambuc return r; 1153*433d6423SLionel Sambuc 1154*433d6423SLionel Sambuc dprintf(V_REQ, ("%s: %s for %lu bytes at pos %llx\n", 1155*433d6423SLionel Sambuc ahci_portname(ps), write ? "write" : "read", size, pos)); 1156*433d6423SLionel Sambuc 1157*433d6423SLionel Sambuc assert(ps->state == STATE_GOOD_DEV); 1158*433d6423SLionel Sambuc assert(ps->flags & FLAG_HAS_MEDIUM); 1159*433d6423SLionel Sambuc assert(ps->sector_size > 0); 1160*433d6423SLionel Sambuc 1161*433d6423SLionel Sambuc /* Limit the maximum size of a single transfer. 1162*433d6423SLionel Sambuc * See the comments at the top of this file for details. 1163*433d6423SLionel Sambuc */ 1164*433d6423SLionel Sambuc if (size > MAX_TRANSFER) 1165*433d6423SLionel Sambuc size = MAX_TRANSFER; 1166*433d6423SLionel Sambuc 1167*433d6423SLionel Sambuc /* If necessary, reduce the request size so that the request does not 1168*433d6423SLionel Sambuc * extend beyond the end of the partition. The caller already 1169*433d6423SLionel Sambuc * guarantees that the starting position lies within the partition. 1170*433d6423SLionel Sambuc */ 1171*433d6423SLionel Sambuc if (pos + size > eof) 1172*433d6423SLionel Sambuc size = (vir_bytes) (eof - pos); 1173*433d6423SLionel Sambuc 1174*433d6423SLionel Sambuc start_lba = pos / ps->sector_size; 1175*433d6423SLionel Sambuc lead = (vir_bytes) (pos % ps->sector_size); 1176*433d6423SLionel Sambuc count = (lead + size + ps->sector_size - 1) / ps->sector_size; 1177*433d6423SLionel Sambuc 1178*433d6423SLionel Sambuc /* Position must be word-aligned for read requests, and sector-aligned 1179*433d6423SLionel Sambuc * for write requests. We do not support read-modify-write for writes. 1180*433d6423SLionel Sambuc */ 1181*433d6423SLionel Sambuc if ((lead & 1) || (write && lead != 0)) { 1182*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unaligned position from %d\n", 1183*433d6423SLionel Sambuc ahci_portname(ps), endpt)); 1184*433d6423SLionel Sambuc return EINVAL; 1185*433d6423SLionel Sambuc } 1186*433d6423SLionel Sambuc 1187*433d6423SLionel Sambuc /* Write requests must be sector-aligned. Word alignment of the size is 1188*433d6423SLionel Sambuc * already guaranteed by sum_iovec(). 1189*433d6423SLionel Sambuc */ 1190*433d6423SLionel Sambuc if (write && (size % ps->sector_size) != 0) { 1191*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: unaligned size %lu from %d\n", 1192*433d6423SLionel Sambuc ahci_portname(ps), size, endpt)); 1193*433d6423SLionel Sambuc return EINVAL; 1194*433d6423SLionel Sambuc } 1195*433d6423SLionel Sambuc 1196*433d6423SLionel Sambuc /* Create a vector of physical addresses and sizes for the transfer. */ 1197*433d6423SLionel Sambuc nr_prds = r = setup_prdt(ps, endpt, iovec, nr_req, size, lead, write, 1198*433d6423SLionel Sambuc prdt); 1199*433d6423SLionel Sambuc 1200*433d6423SLionel Sambuc if (r < 0) return r; 1201*433d6423SLionel Sambuc 1202*433d6423SLionel Sambuc /* Perform the actual transfer. */ 1203*433d6423SLionel Sambuc cmd = port_find_cmd(ps); 1204*433d6423SLionel Sambuc 1205*433d6423SLionel Sambuc if (ps->flags & FLAG_ATAPI) 1206*433d6423SLionel Sambuc r = atapi_transfer(ps, cmd, start_lba, count, write, prdt, 1207*433d6423SLionel Sambuc nr_prds); 1208*433d6423SLionel Sambuc else 1209*433d6423SLionel Sambuc r = ata_transfer(ps, cmd, start_lba, count, write, 1210*433d6423SLionel Sambuc !!(flags & BDEV_FORCEWRITE), prdt, nr_prds); 1211*433d6423SLionel Sambuc 1212*433d6423SLionel Sambuc if (r != OK) return r; 1213*433d6423SLionel Sambuc 1214*433d6423SLionel Sambuc return size; 1215*433d6423SLionel Sambuc } 1216*433d6423SLionel Sambuc 1217*433d6423SLionel Sambuc /*===========================================================================* 1218*433d6423SLionel Sambuc * port_hardreset * 1219*433d6423SLionel Sambuc *===========================================================================*/ 1220*433d6423SLionel Sambuc static void port_hardreset(struct port_state *ps) 1221*433d6423SLionel Sambuc { 1222*433d6423SLionel Sambuc /* Perform a port-level (hard) reset on the given port. 1223*433d6423SLionel Sambuc */ 1224*433d6423SLionel Sambuc 1225*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_INIT); 1226*433d6423SLionel Sambuc 1227*433d6423SLionel Sambuc micro_delay(COMRESET_DELAY * 1000); /* COMRESET_DELAY is in ms */ 1228*433d6423SLionel Sambuc 1229*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SCTL, AHCI_PORT_SCTL_DET_NONE); 1230*433d6423SLionel Sambuc } 1231*433d6423SLionel Sambuc 1232*433d6423SLionel Sambuc /*===========================================================================* 1233*433d6423SLionel Sambuc * port_override * 1234*433d6423SLionel Sambuc *===========================================================================*/ 1235*433d6423SLionel Sambuc static void port_override(struct port_state *ps) 1236*433d6423SLionel Sambuc { 1237*433d6423SLionel Sambuc /* Override the port's BSY and/or DRQ flags. This may only be done 1238*433d6423SLionel Sambuc * prior to starting the port. 1239*433d6423SLionel Sambuc */ 1240*433d6423SLionel Sambuc u32_t cmd; 1241*433d6423SLionel Sambuc 1242*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 1243*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_CLO); 1244*433d6423SLionel Sambuc 1245*433d6423SLionel Sambuc SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CLO), 1246*433d6423SLionel Sambuc PORTREG_DELAY); 1247*433d6423SLionel Sambuc 1248*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: overridden\n", ahci_portname(ps))); 1249*433d6423SLionel Sambuc } 1250*433d6423SLionel Sambuc 1251*433d6423SLionel Sambuc /*===========================================================================* 1252*433d6423SLionel Sambuc * port_start * 1253*433d6423SLionel Sambuc *===========================================================================*/ 1254*433d6423SLionel Sambuc static void port_start(struct port_state *ps) 1255*433d6423SLionel Sambuc { 1256*433d6423SLionel Sambuc /* Start the given port, allowing for the execution of commands and the 1257*433d6423SLionel Sambuc * transfer of data on that port. 1258*433d6423SLionel Sambuc */ 1259*433d6423SLionel Sambuc u32_t cmd; 1260*433d6423SLionel Sambuc 1261*433d6423SLionel Sambuc /* Reset status registers. */ 1262*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SERR, ~0); 1263*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IS, ~0); 1264*433d6423SLionel Sambuc 1265*433d6423SLionel Sambuc /* Start the port. */ 1266*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 1267*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_ST); 1268*433d6423SLionel Sambuc 1269*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: started\n", ahci_portname(ps))); 1270*433d6423SLionel Sambuc } 1271*433d6423SLionel Sambuc 1272*433d6423SLionel Sambuc /*===========================================================================* 1273*433d6423SLionel Sambuc * port_stop * 1274*433d6423SLionel Sambuc *===========================================================================*/ 1275*433d6423SLionel Sambuc static void port_stop(struct port_state *ps) 1276*433d6423SLionel Sambuc { 1277*433d6423SLionel Sambuc /* Stop the given port, if not already stopped. 1278*433d6423SLionel Sambuc */ 1279*433d6423SLionel Sambuc u32_t cmd; 1280*433d6423SLionel Sambuc 1281*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 1282*433d6423SLionel Sambuc 1283*433d6423SLionel Sambuc if (cmd & (AHCI_PORT_CMD_CR | AHCI_PORT_CMD_ST)) { 1284*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_ST); 1285*433d6423SLionel Sambuc 1286*433d6423SLionel Sambuc SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_CR), 1287*433d6423SLionel Sambuc PORTREG_DELAY); 1288*433d6423SLionel Sambuc 1289*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: stopped\n", ahci_portname(ps))); 1290*433d6423SLionel Sambuc } 1291*433d6423SLionel Sambuc } 1292*433d6423SLionel Sambuc 1293*433d6423SLionel Sambuc /*===========================================================================* 1294*433d6423SLionel Sambuc * port_restart * 1295*433d6423SLionel Sambuc *===========================================================================*/ 1296*433d6423SLionel Sambuc static void port_restart(struct port_state *ps) 1297*433d6423SLionel Sambuc { 1298*433d6423SLionel Sambuc /* Restart a port after a fatal error has occurred. 1299*433d6423SLionel Sambuc */ 1300*433d6423SLionel Sambuc 1301*433d6423SLionel Sambuc /* Fail all outstanding commands. */ 1302*433d6423SLionel Sambuc port_fail_cmds(ps); 1303*433d6423SLionel Sambuc 1304*433d6423SLionel Sambuc /* Stop the port. */ 1305*433d6423SLionel Sambuc port_stop(ps); 1306*433d6423SLionel Sambuc 1307*433d6423SLionel Sambuc /* If the BSY and/or DRQ flags are set, reset the port. */ 1308*433d6423SLionel Sambuc if (port_read(ps, AHCI_PORT_TFD) & 1309*433d6423SLionel Sambuc (AHCI_PORT_TFD_STS_BSY | AHCI_PORT_TFD_STS_DRQ)) { 1310*433d6423SLionel Sambuc 1311*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: port reset\n", ahci_portname(ps))); 1312*433d6423SLionel Sambuc 1313*433d6423SLionel Sambuc /* To keep this driver simple, we do not transparently recover 1314*433d6423SLionel Sambuc * ongoing requests. Instead, we mark the failing device as 1315*433d6423SLionel Sambuc * disconnected, and reset it. If the reset succeeds, the 1316*433d6423SLionel Sambuc * device (or, perhaps, eventually, another device) will come 1317*433d6423SLionel Sambuc * back up. Any current and future requests to this port will 1318*433d6423SLionel Sambuc * be failed until the port is fully closed and reopened. 1319*433d6423SLionel Sambuc */ 1320*433d6423SLionel Sambuc port_disconnect(ps); 1321*433d6423SLionel Sambuc 1322*433d6423SLionel Sambuc /* Trigger a port reset. */ 1323*433d6423SLionel Sambuc port_hardreset(ps); 1324*433d6423SLionel Sambuc 1325*433d6423SLionel Sambuc return; 1326*433d6423SLionel Sambuc } 1327*433d6423SLionel Sambuc 1328*433d6423SLionel Sambuc /* Start the port. */ 1329*433d6423SLionel Sambuc port_start(ps); 1330*433d6423SLionel Sambuc } 1331*433d6423SLionel Sambuc 1332*433d6423SLionel Sambuc /*===========================================================================* 1333*433d6423SLionel Sambuc * print_string * 1334*433d6423SLionel Sambuc *===========================================================================*/ 1335*433d6423SLionel Sambuc static void print_string(u16_t *buf, int start, int end) 1336*433d6423SLionel Sambuc { 1337*433d6423SLionel Sambuc /* Print a string that is stored as little-endian words and padded with 1338*433d6423SLionel Sambuc * trailing spaces. 1339*433d6423SLionel Sambuc */ 1340*433d6423SLionel Sambuc int i, last = 0; 1341*433d6423SLionel Sambuc 1342*433d6423SLionel Sambuc while (end >= start && buf[end] == 0x2020) end--; 1343*433d6423SLionel Sambuc 1344*433d6423SLionel Sambuc if (end >= start && (buf[end] & 0xFF) == 0x20) end--, last++; 1345*433d6423SLionel Sambuc 1346*433d6423SLionel Sambuc for (i = start; i <= end; i++) 1347*433d6423SLionel Sambuc printf("%c%c", buf[i] >> 8, buf[i] & 0xFF); 1348*433d6423SLionel Sambuc 1349*433d6423SLionel Sambuc if (last) 1350*433d6423SLionel Sambuc printf("%c", buf[i] >> 8); 1351*433d6423SLionel Sambuc } 1352*433d6423SLionel Sambuc 1353*433d6423SLionel Sambuc /*===========================================================================* 1354*433d6423SLionel Sambuc * port_id_check * 1355*433d6423SLionel Sambuc *===========================================================================*/ 1356*433d6423SLionel Sambuc static void port_id_check(struct port_state *ps, int success) 1357*433d6423SLionel Sambuc { 1358*433d6423SLionel Sambuc /* The device identification command has either completed or timed out. 1359*433d6423SLionel Sambuc * Decide whether this device is usable or not, and store some of its 1360*433d6423SLionel Sambuc * properties. 1361*433d6423SLionel Sambuc */ 1362*433d6423SLionel Sambuc u16_t *buf; 1363*433d6423SLionel Sambuc 1364*433d6423SLionel Sambuc assert(ps->state == STATE_WAIT_ID); 1365*433d6423SLionel Sambuc 1366*433d6423SLionel Sambuc ps->flags &= ~FLAG_BUSY; 1367*433d6423SLionel Sambuc cancel_timer(&ps->cmd_info[0].timer); 1368*433d6423SLionel Sambuc 1369*433d6423SLionel Sambuc if (!success) { 1370*433d6423SLionel Sambuc if (!(ps->flags & FLAG_ATAPI) && 1371*433d6423SLionel Sambuc port_read(ps, AHCI_PORT_SIG) != ATA_SIG_ATA) { 1372*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: may not be ATA, trying ATAPI\n", 1373*433d6423SLionel Sambuc ahci_portname(ps))); 1374*433d6423SLionel Sambuc 1375*433d6423SLionel Sambuc ps->flags |= FLAG_ATAPI; 1376*433d6423SLionel Sambuc 1377*433d6423SLionel Sambuc (void) gen_identify(ps, FALSE /*blocking*/); 1378*433d6423SLionel Sambuc return; 1379*433d6423SLionel Sambuc } 1380*433d6423SLionel Sambuc 1381*433d6423SLionel Sambuc dprintf(V_ERR, 1382*433d6423SLionel Sambuc ("%s: unable to identify\n", ahci_portname(ps))); 1383*433d6423SLionel Sambuc } 1384*433d6423SLionel Sambuc 1385*433d6423SLionel Sambuc /* If the identify command itself succeeded, check the results and 1386*433d6423SLionel Sambuc * store some properties. 1387*433d6423SLionel Sambuc */ 1388*433d6423SLionel Sambuc if (success) { 1389*433d6423SLionel Sambuc buf = (u16_t *) ps->tmp_base; 1390*433d6423SLionel Sambuc 1391*433d6423SLionel Sambuc if (ps->flags & FLAG_ATAPI) 1392*433d6423SLionel Sambuc success = atapi_id_check(ps, buf); 1393*433d6423SLionel Sambuc else 1394*433d6423SLionel Sambuc success = ata_id_check(ps, buf); 1395*433d6423SLionel Sambuc } 1396*433d6423SLionel Sambuc 1397*433d6423SLionel Sambuc /* If the device has not been identified successfully, mark it as an 1398*433d6423SLionel Sambuc * unusable device. 1399*433d6423SLionel Sambuc */ 1400*433d6423SLionel Sambuc if (!success) { 1401*433d6423SLionel Sambuc port_stop(ps); 1402*433d6423SLionel Sambuc 1403*433d6423SLionel Sambuc ps->state = STATE_BAD_DEV; 1404*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE); 1405*433d6423SLionel Sambuc 1406*433d6423SLionel Sambuc return; 1407*433d6423SLionel Sambuc } 1408*433d6423SLionel Sambuc 1409*433d6423SLionel Sambuc /* The device has been identified successfully, and hence usable. */ 1410*433d6423SLionel Sambuc ps->state = STATE_GOOD_DEV; 1411*433d6423SLionel Sambuc 1412*433d6423SLionel Sambuc /* Print some information about the device. */ 1413*433d6423SLionel Sambuc if (ahci_verbose >= V_INFO) { 1414*433d6423SLionel Sambuc printf("%s: ATA%s, ", ahci_portname(ps), 1415*433d6423SLionel Sambuc (ps->flags & FLAG_ATAPI) ? "PI" : ""); 1416*433d6423SLionel Sambuc print_string(buf, 27, 46); 1417*433d6423SLionel Sambuc if (ahci_verbose >= V_DEV) { 1418*433d6423SLionel Sambuc printf(" ("); 1419*433d6423SLionel Sambuc print_string(buf, 10, 19); 1420*433d6423SLionel Sambuc printf(", "); 1421*433d6423SLionel Sambuc print_string(buf, 23, 26); 1422*433d6423SLionel Sambuc printf(")"); 1423*433d6423SLionel Sambuc } 1424*433d6423SLionel Sambuc 1425*433d6423SLionel Sambuc if (ps->flags & FLAG_HAS_MEDIUM) 1426*433d6423SLionel Sambuc printf(", %u byte sectors, %llu MB size", 1427*433d6423SLionel Sambuc ps->sector_size, 1428*433d6423SLionel Sambuc ps->lba_count * ps->sector_size / (1024*1024)); 1429*433d6423SLionel Sambuc 1430*433d6423SLionel Sambuc printf("\n"); 1431*433d6423SLionel Sambuc } 1432*433d6423SLionel Sambuc } 1433*433d6423SLionel Sambuc 1434*433d6423SLionel Sambuc /*===========================================================================* 1435*433d6423SLionel Sambuc * port_connect * 1436*433d6423SLionel Sambuc *===========================================================================*/ 1437*433d6423SLionel Sambuc static void port_connect(struct port_state *ps) 1438*433d6423SLionel Sambuc { 1439*433d6423SLionel Sambuc /* A device has been found to be attached to this port. Start the port, 1440*433d6423SLionel Sambuc * and do timed polling for its signature to become available. 1441*433d6423SLionel Sambuc */ 1442*433d6423SLionel Sambuc u32_t status, sig; 1443*433d6423SLionel Sambuc 1444*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: device connected\n", ahci_portname(ps))); 1445*433d6423SLionel Sambuc 1446*433d6423SLionel Sambuc port_start(ps); 1447*433d6423SLionel Sambuc 1448*433d6423SLionel Sambuc /* The next check covers a purely hypothetical race condition, where 1449*433d6423SLionel Sambuc * the device would disappear right before we try to start it. This is 1450*433d6423SLionel Sambuc * possible because we have to clear PxSERR, and with that, the DIAG.N 1451*433d6423SLionel Sambuc * bit. Double-check the port status, and if it is not as we expect, 1452*433d6423SLionel Sambuc * infer a disconnection. 1453*433d6423SLionel Sambuc */ 1454*433d6423SLionel Sambuc status = port_read(ps, AHCI_PORT_SSTS) & AHCI_PORT_SSTS_DET_MASK; 1455*433d6423SLionel Sambuc 1456*433d6423SLionel Sambuc if (status != AHCI_PORT_SSTS_DET_PHY) { 1457*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: device vanished!\n", ahci_portname(ps))); 1458*433d6423SLionel Sambuc 1459*433d6423SLionel Sambuc port_stop(ps); 1460*433d6423SLionel Sambuc 1461*433d6423SLionel Sambuc ps->state = STATE_NO_DEV; 1462*433d6423SLionel Sambuc ps->flags &= ~FLAG_BUSY; 1463*433d6423SLionel Sambuc 1464*433d6423SLionel Sambuc return; 1465*433d6423SLionel Sambuc } 1466*433d6423SLionel Sambuc 1467*433d6423SLionel Sambuc /* Clear all state flags except the busy flag, which may be relevant if 1468*433d6423SLionel Sambuc * a BDEV_OPEN call is waiting for the device to become ready; the 1469*433d6423SLionel Sambuc * barrier flag, which prevents access to the device until it is 1470*433d6423SLionel Sambuc * completely closed and (re)opened; and, the thread suspension flag. 1471*433d6423SLionel Sambuc */ 1472*433d6423SLionel Sambuc ps->flags &= (FLAG_BUSY | FLAG_BARRIER | FLAG_SUSPENDED); 1473*433d6423SLionel Sambuc 1474*433d6423SLionel Sambuc /* Check the port's signature. We only use the signature to speed up 1475*433d6423SLionel Sambuc * identification; we will try both ATA and ATAPI if the signature is 1476*433d6423SLionel Sambuc * neither ATA nor ATAPI. 1477*433d6423SLionel Sambuc */ 1478*433d6423SLionel Sambuc sig = port_read(ps, AHCI_PORT_SIG); 1479*433d6423SLionel Sambuc 1480*433d6423SLionel Sambuc if (sig == ATA_SIG_ATAPI) 1481*433d6423SLionel Sambuc ps->flags |= FLAG_ATAPI; 1482*433d6423SLionel Sambuc 1483*433d6423SLionel Sambuc /* Attempt to identify the device. Do this using continuation, because 1484*433d6423SLionel Sambuc * we may already be called from port_wait() here, and could end up 1485*433d6423SLionel Sambuc * confusing the timer expiration procedure. 1486*433d6423SLionel Sambuc */ 1487*433d6423SLionel Sambuc ps->state = STATE_WAIT_ID; 1488*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_MASK); 1489*433d6423SLionel Sambuc 1490*433d6423SLionel Sambuc (void) gen_identify(ps, FALSE /*blocking*/); 1491*433d6423SLionel Sambuc } 1492*433d6423SLionel Sambuc 1493*433d6423SLionel Sambuc /*===========================================================================* 1494*433d6423SLionel Sambuc * port_disconnect * 1495*433d6423SLionel Sambuc *===========================================================================*/ 1496*433d6423SLionel Sambuc static void port_disconnect(struct port_state *ps) 1497*433d6423SLionel Sambuc { 1498*433d6423SLionel Sambuc /* The device has detached from this port. It has already been stopped. 1499*433d6423SLionel Sambuc */ 1500*433d6423SLionel Sambuc 1501*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: device disconnected\n", ahci_portname(ps))); 1502*433d6423SLionel Sambuc 1503*433d6423SLionel Sambuc ps->state = STATE_NO_DEV; 1504*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PCE); 1505*433d6423SLionel Sambuc ps->flags &= ~FLAG_BUSY; 1506*433d6423SLionel Sambuc 1507*433d6423SLionel Sambuc /* Fail any ongoing request. The caller may already have done this. */ 1508*433d6423SLionel Sambuc port_fail_cmds(ps); 1509*433d6423SLionel Sambuc 1510*433d6423SLionel Sambuc /* Block any further access until the device is completely closed and 1511*433d6423SLionel Sambuc * reopened. This prevents arbitrary I/O to a newly plugged-in device 1512*433d6423SLionel Sambuc * without upper layers noticing. 1513*433d6423SLionel Sambuc */ 1514*433d6423SLionel Sambuc ps->flags |= FLAG_BARRIER; 1515*433d6423SLionel Sambuc 1516*433d6423SLionel Sambuc /* Inform the blockdriver library to reduce the number of threads. */ 1517*433d6423SLionel Sambuc blockdriver_mt_set_workers(ps->device, 1); 1518*433d6423SLionel Sambuc } 1519*433d6423SLionel Sambuc 1520*433d6423SLionel Sambuc /*===========================================================================* 1521*433d6423SLionel Sambuc * port_dev_check * 1522*433d6423SLionel Sambuc *===========================================================================*/ 1523*433d6423SLionel Sambuc static void port_dev_check(struct port_state *ps) 1524*433d6423SLionel Sambuc { 1525*433d6423SLionel Sambuc /* Perform device detection by means of polling. 1526*433d6423SLionel Sambuc */ 1527*433d6423SLionel Sambuc u32_t status, tfd; 1528*433d6423SLionel Sambuc 1529*433d6423SLionel Sambuc assert(ps->state == STATE_WAIT_DEV); 1530*433d6423SLionel Sambuc 1531*433d6423SLionel Sambuc status = port_read(ps, AHCI_PORT_SSTS) & AHCI_PORT_SSTS_DET_MASK; 1532*433d6423SLionel Sambuc 1533*433d6423SLionel Sambuc dprintf(V_DEV, ("%s: polled status %u\n", ahci_portname(ps), status)); 1534*433d6423SLionel Sambuc 1535*433d6423SLionel Sambuc switch (status) { 1536*433d6423SLionel Sambuc case AHCI_PORT_SSTS_DET_PHY: 1537*433d6423SLionel Sambuc tfd = port_read(ps, AHCI_PORT_TFD); 1538*433d6423SLionel Sambuc 1539*433d6423SLionel Sambuc /* If a Phy connection has been established, and the BSY and 1540*433d6423SLionel Sambuc * DRQ flags are cleared, the device is ready. 1541*433d6423SLionel Sambuc */ 1542*433d6423SLionel Sambuc if (!(tfd & (AHCI_PORT_TFD_STS_BSY | AHCI_PORT_TFD_STS_DRQ))) { 1543*433d6423SLionel Sambuc port_connect(ps); 1544*433d6423SLionel Sambuc 1545*433d6423SLionel Sambuc return; 1546*433d6423SLionel Sambuc } 1547*433d6423SLionel Sambuc 1548*433d6423SLionel Sambuc /* fall-through */ 1549*433d6423SLionel Sambuc case AHCI_PORT_SSTS_DET_DET: 1550*433d6423SLionel Sambuc /* A device has been detected, but it is not ready yet. Try for 1551*433d6423SLionel Sambuc * a while before giving up. This may take seconds. 1552*433d6423SLionel Sambuc */ 1553*433d6423SLionel Sambuc if (ps->left > 0) { 1554*433d6423SLionel Sambuc ps->left--; 1555*433d6423SLionel Sambuc set_timer(&ps->cmd_info[0].timer, ahci_device_delay, 1556*433d6423SLionel Sambuc port_timeout, BUILD_ARG(ps - port_state, 0)); 1557*433d6423SLionel Sambuc return; 1558*433d6423SLionel Sambuc } 1559*433d6423SLionel Sambuc } 1560*433d6423SLionel Sambuc 1561*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: device not ready\n", ahci_portname(ps))); 1562*433d6423SLionel Sambuc 1563*433d6423SLionel Sambuc /* We get here on timeout, and if the HBA reports that there is no 1564*433d6423SLionel Sambuc * device present at all. In all cases, we change to another state. 1565*433d6423SLionel Sambuc */ 1566*433d6423SLionel Sambuc if (status == AHCI_PORT_SSTS_DET_PHY) { 1567*433d6423SLionel Sambuc /* Some devices may not correctly clear BSY/DRQ. Upon timeout, 1568*433d6423SLionel Sambuc * if we can override these flags, do so and start the 1569*433d6423SLionel Sambuc * identification process anyway. 1570*433d6423SLionel Sambuc */ 1571*433d6423SLionel Sambuc if (hba_state.has_clo) { 1572*433d6423SLionel Sambuc port_override(ps); 1573*433d6423SLionel Sambuc 1574*433d6423SLionel Sambuc port_connect(ps); 1575*433d6423SLionel Sambuc 1576*433d6423SLionel Sambuc return; 1577*433d6423SLionel Sambuc } 1578*433d6423SLionel Sambuc 1579*433d6423SLionel Sambuc /* A device is present and initialized, but not ready. */ 1580*433d6423SLionel Sambuc ps->state = STATE_BAD_DEV; 1581*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PRCE); 1582*433d6423SLionel Sambuc } else { 1583*433d6423SLionel Sambuc /* A device may or may not be present, but it does not appear 1584*433d6423SLionel Sambuc * to be ready in any case. Ignore it until the next device 1585*433d6423SLionel Sambuc * initialization event. 1586*433d6423SLionel Sambuc */ 1587*433d6423SLionel Sambuc ps->state = STATE_NO_DEV; 1588*433d6423SLionel Sambuc ps->flags &= ~FLAG_BUSY; 1589*433d6423SLionel Sambuc } 1590*433d6423SLionel Sambuc } 1591*433d6423SLionel Sambuc 1592*433d6423SLionel Sambuc /*===========================================================================* 1593*433d6423SLionel Sambuc * port_intr * 1594*433d6423SLionel Sambuc *===========================================================================*/ 1595*433d6423SLionel Sambuc static void port_intr(struct port_state *ps) 1596*433d6423SLionel Sambuc { 1597*433d6423SLionel Sambuc /* Process an interrupt on this port. 1598*433d6423SLionel Sambuc */ 1599*433d6423SLionel Sambuc u32_t smask, emask; 1600*433d6423SLionel Sambuc int success; 1601*433d6423SLionel Sambuc 1602*433d6423SLionel Sambuc if (ps->state == STATE_NO_PORT) { 1603*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: interrupt for invalid port!\n", 1604*433d6423SLionel Sambuc ahci_portname(ps))); 1605*433d6423SLionel Sambuc 1606*433d6423SLionel Sambuc return; 1607*433d6423SLionel Sambuc } 1608*433d6423SLionel Sambuc 1609*433d6423SLionel Sambuc smask = port_read(ps, AHCI_PORT_IS); 1610*433d6423SLionel Sambuc emask = smask & port_read(ps, AHCI_PORT_IE); 1611*433d6423SLionel Sambuc 1612*433d6423SLionel Sambuc /* Clear the interrupt flags that we saw were set. */ 1613*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IS, smask); 1614*433d6423SLionel Sambuc 1615*433d6423SLionel Sambuc dprintf(V_REQ, ("%s: interrupt (%08x)\n", ahci_portname(ps), smask)); 1616*433d6423SLionel Sambuc 1617*433d6423SLionel Sambuc /* Check if any commands have completed. */ 1618*433d6423SLionel Sambuc port_check_cmds(ps); 1619*433d6423SLionel Sambuc 1620*433d6423SLionel Sambuc if (emask & AHCI_PORT_IS_PCS) { 1621*433d6423SLionel Sambuc /* Clear the X diagnostics bit to clear this interrupt. */ 1622*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SERR, AHCI_PORT_SERR_DIAG_X); 1623*433d6423SLionel Sambuc 1624*433d6423SLionel Sambuc dprintf(V_DEV, ("%s: device attached\n", ahci_portname(ps))); 1625*433d6423SLionel Sambuc 1626*433d6423SLionel Sambuc switch (ps->state) { 1627*433d6423SLionel Sambuc case STATE_SPIN_UP: 1628*433d6423SLionel Sambuc case STATE_NO_DEV: 1629*433d6423SLionel Sambuc /* Reportedly, a device has shown up. Start polling its 1630*433d6423SLionel Sambuc * status until it has become ready. 1631*433d6423SLionel Sambuc */ 1632*433d6423SLionel Sambuc 1633*433d6423SLionel Sambuc if (ps->state == STATE_SPIN_UP) 1634*433d6423SLionel Sambuc cancel_timer(&ps->cmd_info[0].timer); 1635*433d6423SLionel Sambuc 1636*433d6423SLionel Sambuc ps->state = STATE_WAIT_DEV; 1637*433d6423SLionel Sambuc ps->left = ahci_device_checks; 1638*433d6423SLionel Sambuc 1639*433d6423SLionel Sambuc port_dev_check(ps); 1640*433d6423SLionel Sambuc 1641*433d6423SLionel Sambuc break; 1642*433d6423SLionel Sambuc 1643*433d6423SLionel Sambuc case STATE_WAIT_DEV: 1644*433d6423SLionel Sambuc /* Nothing else to do. */ 1645*433d6423SLionel Sambuc break; 1646*433d6423SLionel Sambuc 1647*433d6423SLionel Sambuc default: 1648*433d6423SLionel Sambuc /* Impossible. */ 1649*433d6423SLionel Sambuc assert(0); 1650*433d6423SLionel Sambuc } 1651*433d6423SLionel Sambuc } else if (emask & AHCI_PORT_IS_PRCS) { 1652*433d6423SLionel Sambuc /* Clear the N diagnostics bit to clear this interrupt. */ 1653*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SERR, AHCI_PORT_SERR_DIAG_N); 1654*433d6423SLionel Sambuc 1655*433d6423SLionel Sambuc dprintf(V_DEV, ("%s: device detached\n", ahci_portname(ps))); 1656*433d6423SLionel Sambuc 1657*433d6423SLionel Sambuc switch (ps->state) { 1658*433d6423SLionel Sambuc case STATE_WAIT_ID: 1659*433d6423SLionel Sambuc case STATE_GOOD_DEV: 1660*433d6423SLionel Sambuc /* The device is no longer ready. Stop the port, cancel 1661*433d6423SLionel Sambuc * ongoing requests, and disconnect the device. 1662*433d6423SLionel Sambuc */ 1663*433d6423SLionel Sambuc port_stop(ps); 1664*433d6423SLionel Sambuc 1665*433d6423SLionel Sambuc /* fall-through */ 1666*433d6423SLionel Sambuc case STATE_BAD_DEV: 1667*433d6423SLionel Sambuc port_disconnect(ps); 1668*433d6423SLionel Sambuc 1669*433d6423SLionel Sambuc /* The device has become unusable to us at this point. 1670*433d6423SLionel Sambuc * Reset the port to make sure that once the device (or 1671*433d6423SLionel Sambuc * another device) becomes usable again, we will get a 1672*433d6423SLionel Sambuc * PCS interrupt as well. 1673*433d6423SLionel Sambuc */ 1674*433d6423SLionel Sambuc port_hardreset(ps); 1675*433d6423SLionel Sambuc 1676*433d6423SLionel Sambuc break; 1677*433d6423SLionel Sambuc 1678*433d6423SLionel Sambuc default: 1679*433d6423SLionel Sambuc /* Impossible. */ 1680*433d6423SLionel Sambuc assert(0); 1681*433d6423SLionel Sambuc } 1682*433d6423SLionel Sambuc } else if (smask & AHCI_PORT_IS_MASK) { 1683*433d6423SLionel Sambuc /* We assume that any other interrupt indicates command 1684*433d6423SLionel Sambuc * completion or (command or device) failure. Unfortunately, if 1685*433d6423SLionel Sambuc * an NCQ command failed, we cannot easily determine which one 1686*433d6423SLionel Sambuc * it was. For that reason, after completing all successfully 1687*433d6423SLionel Sambuc * finished commands (above), we fail all other outstanding 1688*433d6423SLionel Sambuc * commands and restart the port. This can possibly be improved 1689*433d6423SLionel Sambuc * later by obtaining per-command status results from the HBA. 1690*433d6423SLionel Sambuc */ 1691*433d6423SLionel Sambuc 1692*433d6423SLionel Sambuc success = !(port_read(ps, AHCI_PORT_TFD) & 1693*433d6423SLionel Sambuc (AHCI_PORT_TFD_STS_ERR | AHCI_PORT_TFD_STS_DF)); 1694*433d6423SLionel Sambuc 1695*433d6423SLionel Sambuc /* Check now for failure. There are fatal failures, and there 1696*433d6423SLionel Sambuc * are failures that set the TFD.STS.ERR field using a D2H 1697*433d6423SLionel Sambuc * FIS. In both cases, we just restart the port, failing all 1698*433d6423SLionel Sambuc * commands in the process. 1699*433d6423SLionel Sambuc */ 1700*433d6423SLionel Sambuc if ((port_read(ps, AHCI_PORT_TFD) & 1701*433d6423SLionel Sambuc (AHCI_PORT_TFD_STS_ERR | AHCI_PORT_TFD_STS_DF)) || 1702*433d6423SLionel Sambuc (smask & AHCI_PORT_IS_RESTART)) { 1703*433d6423SLionel Sambuc port_restart(ps); 1704*433d6423SLionel Sambuc } 1705*433d6423SLionel Sambuc 1706*433d6423SLionel Sambuc /* If we were waiting for ID verification, check now. */ 1707*433d6423SLionel Sambuc if (ps->state == STATE_WAIT_ID) 1708*433d6423SLionel Sambuc port_id_check(ps, success); 1709*433d6423SLionel Sambuc } 1710*433d6423SLionel Sambuc } 1711*433d6423SLionel Sambuc 1712*433d6423SLionel Sambuc /*===========================================================================* 1713*433d6423SLionel Sambuc * port_timeout * 1714*433d6423SLionel Sambuc *===========================================================================*/ 1715*433d6423SLionel Sambuc static void port_timeout(minix_timer_t *tp) 1716*433d6423SLionel Sambuc { 1717*433d6423SLionel Sambuc /* A timeout has occurred on this port. Figure out what the timeout is 1718*433d6423SLionel Sambuc * for, and take appropriate action. 1719*433d6423SLionel Sambuc */ 1720*433d6423SLionel Sambuc struct port_state *ps; 1721*433d6423SLionel Sambuc int port, cmd; 1722*433d6423SLionel Sambuc 1723*433d6423SLionel Sambuc port = GET_PORT(tmr_arg(tp)->ta_int); 1724*433d6423SLionel Sambuc cmd = GET_TAG(tmr_arg(tp)->ta_int); 1725*433d6423SLionel Sambuc 1726*433d6423SLionel Sambuc assert(port >= 0 && port < hba_state.nr_ports); 1727*433d6423SLionel Sambuc 1728*433d6423SLionel Sambuc ps = &port_state[port]; 1729*433d6423SLionel Sambuc 1730*433d6423SLionel Sambuc /* Regardless of the outcome of this timeout, wake up the thread if it 1731*433d6423SLionel Sambuc * is suspended. This applies only during the initialization. 1732*433d6423SLionel Sambuc */ 1733*433d6423SLionel Sambuc if (ps->flags & FLAG_SUSPENDED) { 1734*433d6423SLionel Sambuc assert(cmd == 0); 1735*433d6423SLionel Sambuc blockdriver_mt_wakeup(ps->cmd_info[0].tid); 1736*433d6423SLionel Sambuc } 1737*433d6423SLionel Sambuc 1738*433d6423SLionel Sambuc /* If detection of a device after startup timed out, give up on initial 1739*433d6423SLionel Sambuc * detection and only look for hot plug events from now on. 1740*433d6423SLionel Sambuc */ 1741*433d6423SLionel Sambuc if (ps->state == STATE_SPIN_UP) { 1742*433d6423SLionel Sambuc /* One exception: if the PCS interrupt bit is set here, then we 1743*433d6423SLionel Sambuc * are probably running on VirtualBox, which is currently not 1744*433d6423SLionel Sambuc * always raising interrupts when setting interrupt bits (!). 1745*433d6423SLionel Sambuc */ 1746*433d6423SLionel Sambuc if (port_read(ps, AHCI_PORT_IS) & AHCI_PORT_IS_PCS) { 1747*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: bad controller, no interrupt\n", 1748*433d6423SLionel Sambuc ahci_portname(ps))); 1749*433d6423SLionel Sambuc 1750*433d6423SLionel Sambuc ps->state = STATE_WAIT_DEV; 1751*433d6423SLionel Sambuc ps->left = ahci_device_checks; 1752*433d6423SLionel Sambuc 1753*433d6423SLionel Sambuc port_dev_check(ps); 1754*433d6423SLionel Sambuc 1755*433d6423SLionel Sambuc return; 1756*433d6423SLionel Sambuc } else { 1757*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: spin-up timeout\n", 1758*433d6423SLionel Sambuc ahci_portname(ps))); 1759*433d6423SLionel Sambuc 1760*433d6423SLionel Sambuc /* If the busy flag is set, a BDEV_OPEN request is 1761*433d6423SLionel Sambuc * waiting for the detection to finish; clear the busy 1762*433d6423SLionel Sambuc * flag to return an error to the caller. 1763*433d6423SLionel Sambuc */ 1764*433d6423SLionel Sambuc ps->state = STATE_NO_DEV; 1765*433d6423SLionel Sambuc ps->flags &= ~FLAG_BUSY; 1766*433d6423SLionel Sambuc } 1767*433d6423SLionel Sambuc 1768*433d6423SLionel Sambuc return; 1769*433d6423SLionel Sambuc } 1770*433d6423SLionel Sambuc 1771*433d6423SLionel Sambuc /* If we are waiting for a device to become connected and initialized, 1772*433d6423SLionel Sambuc * check now. 1773*433d6423SLionel Sambuc */ 1774*433d6423SLionel Sambuc if (ps->state == STATE_WAIT_DEV) { 1775*433d6423SLionel Sambuc port_dev_check(ps); 1776*433d6423SLionel Sambuc 1777*433d6423SLionel Sambuc return; 1778*433d6423SLionel Sambuc } 1779*433d6423SLionel Sambuc 1780*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: timeout\n", ahci_portname(ps))); 1781*433d6423SLionel Sambuc 1782*433d6423SLionel Sambuc /* Restart the port, failing all current commands. */ 1783*433d6423SLionel Sambuc port_restart(ps); 1784*433d6423SLionel Sambuc 1785*433d6423SLionel Sambuc /* Finish up the identify operation. */ 1786*433d6423SLionel Sambuc if (ps->state == STATE_WAIT_ID) 1787*433d6423SLionel Sambuc port_id_check(ps, FALSE); 1788*433d6423SLionel Sambuc } 1789*433d6423SLionel Sambuc 1790*433d6423SLionel Sambuc /*===========================================================================* 1791*433d6423SLionel Sambuc * port_wait * 1792*433d6423SLionel Sambuc *===========================================================================*/ 1793*433d6423SLionel Sambuc static void port_wait(struct port_state *ps) 1794*433d6423SLionel Sambuc { 1795*433d6423SLionel Sambuc /* Suspend the current thread until the given port is no longer busy, 1796*433d6423SLionel Sambuc * due to either command completion or timeout. 1797*433d6423SLionel Sambuc */ 1798*433d6423SLionel Sambuc 1799*433d6423SLionel Sambuc ps->flags |= FLAG_SUSPENDED; 1800*433d6423SLionel Sambuc 1801*433d6423SLionel Sambuc while (ps->flags & FLAG_BUSY) 1802*433d6423SLionel Sambuc blockdriver_mt_sleep(); 1803*433d6423SLionel Sambuc 1804*433d6423SLionel Sambuc ps->flags &= ~FLAG_SUSPENDED; 1805*433d6423SLionel Sambuc } 1806*433d6423SLionel Sambuc 1807*433d6423SLionel Sambuc /*===========================================================================* 1808*433d6423SLionel Sambuc * port_issue * 1809*433d6423SLionel Sambuc *===========================================================================*/ 1810*433d6423SLionel Sambuc static void port_issue(struct port_state *ps, int cmd, clock_t timeout) 1811*433d6423SLionel Sambuc { 1812*433d6423SLionel Sambuc /* Issue a command to the port, and set a timer to trigger a timeout 1813*433d6423SLionel Sambuc * if the command takes too long to complete. 1814*433d6423SLionel Sambuc */ 1815*433d6423SLionel Sambuc 1816*433d6423SLionel Sambuc /* Set the corresponding NCQ command bit, if applicable. */ 1817*433d6423SLionel Sambuc if (ps->flags & FLAG_HAS_NCQ) 1818*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_SACT, 1 << cmd); 1819*433d6423SLionel Sambuc 1820*433d6423SLionel Sambuc /* Make sure that the compiler does not delay any previous write 1821*433d6423SLionel Sambuc * operations until after the write to the command issue register. 1822*433d6423SLionel Sambuc */ 1823*433d6423SLionel Sambuc __insn_barrier(); 1824*433d6423SLionel Sambuc 1825*433d6423SLionel Sambuc /* Tell the controller that a new command is ready. */ 1826*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CI, 1 << cmd); 1827*433d6423SLionel Sambuc 1828*433d6423SLionel Sambuc /* Update pending commands. */ 1829*433d6423SLionel Sambuc ps->pend_mask |= 1 << cmd; 1830*433d6423SLionel Sambuc 1831*433d6423SLionel Sambuc /* Set a timer in case the command does not complete at all. */ 1832*433d6423SLionel Sambuc set_timer(&ps->cmd_info[cmd].timer, timeout, port_timeout, 1833*433d6423SLionel Sambuc BUILD_ARG(ps - port_state, cmd)); 1834*433d6423SLionel Sambuc } 1835*433d6423SLionel Sambuc 1836*433d6423SLionel Sambuc /*===========================================================================* 1837*433d6423SLionel Sambuc * port_exec * 1838*433d6423SLionel Sambuc *===========================================================================*/ 1839*433d6423SLionel Sambuc static int port_exec(struct port_state *ps, int cmd, clock_t timeout) 1840*433d6423SLionel Sambuc { 1841*433d6423SLionel Sambuc /* Execute a command on a port, wait for the command to complete or for 1842*433d6423SLionel Sambuc * a timeout, and return whether the command succeeded or not. 1843*433d6423SLionel Sambuc */ 1844*433d6423SLionel Sambuc 1845*433d6423SLionel Sambuc port_issue(ps, cmd, timeout); 1846*433d6423SLionel Sambuc 1847*433d6423SLionel Sambuc /* Put the thread to sleep until a timeout or a command completion 1848*433d6423SLionel Sambuc * happens. Earlier, we used to call port_wait which set the suspended 1849*433d6423SLionel Sambuc * flag. We now abandon it since the flag has to work on a per-thread, 1850*433d6423SLionel Sambuc * and hence per-tag basis and not on a per-port basis. Instead, we 1851*433d6423SLionel Sambuc * retain that call only to defer open calls during device/driver 1852*433d6423SLionel Sambuc * initialization. Instead, we call sleep here directly. Before 1853*433d6423SLionel Sambuc * sleeping, we register the thread. 1854*433d6423SLionel Sambuc */ 1855*433d6423SLionel Sambuc ps->cmd_info[cmd].tid = blockdriver_mt_get_tid(); 1856*433d6423SLionel Sambuc 1857*433d6423SLionel Sambuc blockdriver_mt_sleep(); 1858*433d6423SLionel Sambuc 1859*433d6423SLionel Sambuc /* Cancelling a timer that just triggered, does no harm. */ 1860*433d6423SLionel Sambuc cancel_timer(&ps->cmd_info[cmd].timer); 1861*433d6423SLionel Sambuc 1862*433d6423SLionel Sambuc assert(!(ps->flags & FLAG_BUSY)); 1863*433d6423SLionel Sambuc 1864*433d6423SLionel Sambuc dprintf(V_REQ, ("%s: end of command -- %s\n", ahci_portname(ps), 1865*433d6423SLionel Sambuc (ps->cmd_info[cmd].result == RESULT_FAILURE) ? 1866*433d6423SLionel Sambuc "failure" : "success")); 1867*433d6423SLionel Sambuc 1868*433d6423SLionel Sambuc if (ps->cmd_info[cmd].result == RESULT_FAILURE) 1869*433d6423SLionel Sambuc return EIO; 1870*433d6423SLionel Sambuc 1871*433d6423SLionel Sambuc return OK; 1872*433d6423SLionel Sambuc } 1873*433d6423SLionel Sambuc 1874*433d6423SLionel Sambuc /*===========================================================================* 1875*433d6423SLionel Sambuc * port_alloc * 1876*433d6423SLionel Sambuc *===========================================================================*/ 1877*433d6423SLionel Sambuc static void port_alloc(struct port_state *ps) 1878*433d6423SLionel Sambuc { 1879*433d6423SLionel Sambuc /* Allocate memory for the given port, and enable FIS receipt. We try 1880*433d6423SLionel Sambuc * to cram everything into one 4K-page in order to limit memory usage 1881*433d6423SLionel Sambuc * as much as possible. More memory may be allocated on demand later, 1882*433d6423SLionel Sambuc * but allocation failure should be fatal only here. Note that we do 1883*433d6423SLionel Sambuc * not allocate memory for sector padding here, because we do not know 1884*433d6423SLionel Sambuc * the device's sector size yet. 1885*433d6423SLionel Sambuc */ 1886*433d6423SLionel Sambuc size_t fis_off, tmp_off, ct_off; int i; 1887*433d6423SLionel Sambuc size_t ct_offs[NR_CMDS]; 1888*433d6423SLionel Sambuc u32_t cmd; 1889*433d6423SLionel Sambuc 1890*433d6423SLionel Sambuc fis_off = AHCI_CL_SIZE + AHCI_FIS_SIZE - 1; 1891*433d6423SLionel Sambuc fis_off -= fis_off % AHCI_FIS_SIZE; 1892*433d6423SLionel Sambuc 1893*433d6423SLionel Sambuc tmp_off = fis_off + AHCI_FIS_SIZE + AHCI_TMP_ALIGN - 1; 1894*433d6423SLionel Sambuc tmp_off -= tmp_off % AHCI_TMP_ALIGN; 1895*433d6423SLionel Sambuc 1896*433d6423SLionel Sambuc /* Allocate memory for all the commands. */ 1897*433d6423SLionel Sambuc ct_off = tmp_off + AHCI_TMP_SIZE; 1898*433d6423SLionel Sambuc for (i = 0; i < NR_CMDS; i++) { 1899*433d6423SLionel Sambuc ct_off += AHCI_CT_ALIGN - 1; 1900*433d6423SLionel Sambuc ct_off -= ct_off % AHCI_CT_ALIGN; 1901*433d6423SLionel Sambuc ct_offs[i] = ct_off; 1902*433d6423SLionel Sambuc ps->mem_size = ct_off + AHCI_CT_SIZE; 1903*433d6423SLionel Sambuc ct_off = ps->mem_size; 1904*433d6423SLionel Sambuc } 1905*433d6423SLionel Sambuc 1906*433d6423SLionel Sambuc ps->mem_base = alloc_contig(ps->mem_size, AC_ALIGN4K, &ps->mem_phys); 1907*433d6423SLionel Sambuc if (ps->mem_base == NULL) 1908*433d6423SLionel Sambuc panic("unable to allocate port memory"); 1909*433d6423SLionel Sambuc memset(ps->mem_base, 0, ps->mem_size); 1910*433d6423SLionel Sambuc 1911*433d6423SLionel Sambuc ps->cl_base = (u32_t *) ps->mem_base; 1912*433d6423SLionel Sambuc ps->cl_phys = ps->mem_phys; 1913*433d6423SLionel Sambuc assert(ps->cl_phys % AHCI_CL_SIZE == 0); 1914*433d6423SLionel Sambuc 1915*433d6423SLionel Sambuc ps->fis_base = (u32_t *) (ps->mem_base + fis_off); 1916*433d6423SLionel Sambuc ps->fis_phys = ps->mem_phys + fis_off; 1917*433d6423SLionel Sambuc assert(ps->fis_phys % AHCI_FIS_SIZE == 0); 1918*433d6423SLionel Sambuc 1919*433d6423SLionel Sambuc ps->tmp_base = (u8_t *) (ps->mem_base + tmp_off); 1920*433d6423SLionel Sambuc ps->tmp_phys = ps->mem_phys + tmp_off; 1921*433d6423SLionel Sambuc assert(ps->tmp_phys % AHCI_TMP_ALIGN == 0); 1922*433d6423SLionel Sambuc 1923*433d6423SLionel Sambuc for (i = 0; i < NR_CMDS; i++) { 1924*433d6423SLionel Sambuc ps->ct_base[i] = ps->mem_base + ct_offs[i]; 1925*433d6423SLionel Sambuc ps->ct_phys[i] = ps->mem_phys + ct_offs[i]; 1926*433d6423SLionel Sambuc assert(ps->ct_phys[i] % AHCI_CT_ALIGN == 0); 1927*433d6423SLionel Sambuc } 1928*433d6423SLionel Sambuc 1929*433d6423SLionel Sambuc /* Tell the controller about some of the physical addresses. */ 1930*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_FBU, 0); 1931*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_FB, ps->fis_phys); 1932*433d6423SLionel Sambuc 1933*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CLBU, 0); 1934*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CLB, ps->cl_phys); 1935*433d6423SLionel Sambuc 1936*433d6423SLionel Sambuc /* Enable FIS receive. */ 1937*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 1938*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_FRE); 1939*433d6423SLionel Sambuc 1940*433d6423SLionel Sambuc ps->pad_base = NULL; 1941*433d6423SLionel Sambuc ps->pad_size = 0; 1942*433d6423SLionel Sambuc } 1943*433d6423SLionel Sambuc 1944*433d6423SLionel Sambuc /*===========================================================================* 1945*433d6423SLionel Sambuc * port_free * 1946*433d6423SLionel Sambuc *===========================================================================*/ 1947*433d6423SLionel Sambuc static void port_free(struct port_state *ps) 1948*433d6423SLionel Sambuc { 1949*433d6423SLionel Sambuc /* Disable FIS receipt for the given port, and free previously 1950*433d6423SLionel Sambuc * allocated memory. 1951*433d6423SLionel Sambuc */ 1952*433d6423SLionel Sambuc u32_t cmd; 1953*433d6423SLionel Sambuc int i; 1954*433d6423SLionel Sambuc 1955*433d6423SLionel Sambuc /* Disable FIS receive. */ 1956*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 1957*433d6423SLionel Sambuc 1958*433d6423SLionel Sambuc if (cmd & (AHCI_PORT_CMD_FR | AHCI_PORT_CMD_FRE)) { 1959*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd & ~AHCI_PORT_CMD_FRE); 1960*433d6423SLionel Sambuc 1961*433d6423SLionel Sambuc SPIN_UNTIL(!(port_read(ps, AHCI_PORT_CMD) & AHCI_PORT_CMD_FR), 1962*433d6423SLionel Sambuc PORTREG_DELAY); 1963*433d6423SLionel Sambuc } 1964*433d6423SLionel Sambuc 1965*433d6423SLionel Sambuc if (ps->pad_base != NULL) 1966*433d6423SLionel Sambuc free_contig(ps->pad_base, ps->pad_size); 1967*433d6423SLionel Sambuc 1968*433d6423SLionel Sambuc /* The first command table is part of the primary memory page. */ 1969*433d6423SLionel Sambuc for (i = 1; i < hba_state.nr_cmds; i++) 1970*433d6423SLionel Sambuc if (ps->ct_base[i] != NULL) 1971*433d6423SLionel Sambuc free_contig(ps->ct_base[i], AHCI_CT_SIZE); 1972*433d6423SLionel Sambuc 1973*433d6423SLionel Sambuc free_contig(ps->mem_base, ps->mem_size); 1974*433d6423SLionel Sambuc } 1975*433d6423SLionel Sambuc 1976*433d6423SLionel Sambuc /*===========================================================================* 1977*433d6423SLionel Sambuc * port_init * 1978*433d6423SLionel Sambuc *===========================================================================*/ 1979*433d6423SLionel Sambuc static void port_init(struct port_state *ps) 1980*433d6423SLionel Sambuc { 1981*433d6423SLionel Sambuc /* Initialize the given port. 1982*433d6423SLionel Sambuc */ 1983*433d6423SLionel Sambuc u32_t cmd; 1984*433d6423SLionel Sambuc int i; 1985*433d6423SLionel Sambuc 1986*433d6423SLionel Sambuc /* Initialize the port state structure. */ 1987*433d6423SLionel Sambuc ps->queue_depth = 1; 1988*433d6423SLionel Sambuc ps->state = STATE_SPIN_UP; 1989*433d6423SLionel Sambuc ps->flags = FLAG_BUSY; 1990*433d6423SLionel Sambuc ps->sector_size = 0; 1991*433d6423SLionel Sambuc ps->open_count = 0; 1992*433d6423SLionel Sambuc ps->pend_mask = 0; 1993*433d6423SLionel Sambuc for (i = 0; i < NR_CMDS; i++) 1994*433d6423SLionel Sambuc init_timer(&ps->cmd_info[i].timer); 1995*433d6423SLionel Sambuc 1996*433d6423SLionel Sambuc ps->reg = (u32_t *) ((u8_t *) hba_state.base + 1997*433d6423SLionel Sambuc AHCI_MEM_BASE_SIZE + AHCI_MEM_PORT_SIZE * (ps - port_state)); 1998*433d6423SLionel Sambuc 1999*433d6423SLionel Sambuc /* Allocate memory for the port. */ 2000*433d6423SLionel Sambuc port_alloc(ps); 2001*433d6423SLionel Sambuc 2002*433d6423SLionel Sambuc /* Just listen for device connection events for now. */ 2003*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_IE, AHCI_PORT_IE_PCE); 2004*433d6423SLionel Sambuc 2005*433d6423SLionel Sambuc /* Enable device spin-up for HBAs that support staggered spin-up. 2006*433d6423SLionel Sambuc * This is a no-op for HBAs that do not support it. 2007*433d6423SLionel Sambuc */ 2008*433d6423SLionel Sambuc cmd = port_read(ps, AHCI_PORT_CMD); 2009*433d6423SLionel Sambuc port_write(ps, AHCI_PORT_CMD, cmd | AHCI_PORT_CMD_SUD); 2010*433d6423SLionel Sambuc 2011*433d6423SLionel Sambuc /* Trigger a port reset. */ 2012*433d6423SLionel Sambuc port_hardreset(ps); 2013*433d6423SLionel Sambuc 2014*433d6423SLionel Sambuc set_timer(&ps->cmd_info[0].timer, ahci_spinup_timeout, 2015*433d6423SLionel Sambuc port_timeout, BUILD_ARG(ps - port_state, 0)); 2016*433d6423SLionel Sambuc } 2017*433d6423SLionel Sambuc 2018*433d6423SLionel Sambuc /*===========================================================================* 2019*433d6423SLionel Sambuc * ahci_probe * 2020*433d6423SLionel Sambuc *===========================================================================*/ 2021*433d6423SLionel Sambuc static int ahci_probe(int skip) 2022*433d6423SLionel Sambuc { 2023*433d6423SLionel Sambuc /* Find a matching PCI device. 2024*433d6423SLionel Sambuc */ 2025*433d6423SLionel Sambuc int r, devind; 2026*433d6423SLionel Sambuc u16_t vid, did; 2027*433d6423SLionel Sambuc 2028*433d6423SLionel Sambuc pci_init(); 2029*433d6423SLionel Sambuc 2030*433d6423SLionel Sambuc r = pci_first_dev(&devind, &vid, &did); 2031*433d6423SLionel Sambuc if (r <= 0) 2032*433d6423SLionel Sambuc return -1; 2033*433d6423SLionel Sambuc 2034*433d6423SLionel Sambuc while (skip--) { 2035*433d6423SLionel Sambuc r = pci_next_dev(&devind, &vid, &did); 2036*433d6423SLionel Sambuc if (r <= 0) 2037*433d6423SLionel Sambuc return -1; 2038*433d6423SLionel Sambuc } 2039*433d6423SLionel Sambuc 2040*433d6423SLionel Sambuc pci_reserve(devind); 2041*433d6423SLionel Sambuc 2042*433d6423SLionel Sambuc return devind; 2043*433d6423SLionel Sambuc } 2044*433d6423SLionel Sambuc 2045*433d6423SLionel Sambuc /*===========================================================================* 2046*433d6423SLionel Sambuc * ahci_reset * 2047*433d6423SLionel Sambuc *===========================================================================*/ 2048*433d6423SLionel Sambuc static void ahci_reset(void) 2049*433d6423SLionel Sambuc { 2050*433d6423SLionel Sambuc /* Reset the HBA. Do not enable AHCI mode afterwards. 2051*433d6423SLionel Sambuc */ 2052*433d6423SLionel Sambuc u32_t ghc; 2053*433d6423SLionel Sambuc 2054*433d6423SLionel Sambuc ghc = hba_read(AHCI_HBA_GHC); 2055*433d6423SLionel Sambuc 2056*433d6423SLionel Sambuc hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE); 2057*433d6423SLionel Sambuc 2058*433d6423SLionel Sambuc hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_HR); 2059*433d6423SLionel Sambuc 2060*433d6423SLionel Sambuc SPIN_UNTIL(!(hba_read(AHCI_HBA_GHC) & AHCI_HBA_GHC_HR), RESET_DELAY); 2061*433d6423SLionel Sambuc 2062*433d6423SLionel Sambuc if (hba_read(AHCI_HBA_GHC) & AHCI_HBA_GHC_HR) 2063*433d6423SLionel Sambuc panic("unable to reset HBA"); 2064*433d6423SLionel Sambuc } 2065*433d6423SLionel Sambuc 2066*433d6423SLionel Sambuc /*===========================================================================* 2067*433d6423SLionel Sambuc * ahci_init * 2068*433d6423SLionel Sambuc *===========================================================================*/ 2069*433d6423SLionel Sambuc static void ahci_init(int devind) 2070*433d6423SLionel Sambuc { 2071*433d6423SLionel Sambuc /* Initialize the device. 2072*433d6423SLionel Sambuc */ 2073*433d6423SLionel Sambuc u32_t base, size, cap, ghc, mask; 2074*433d6423SLionel Sambuc int r, port, ioflag; 2075*433d6423SLionel Sambuc 2076*433d6423SLionel Sambuc if ((r = pci_get_bar(devind, PCI_BAR_6, &base, &size, &ioflag)) != OK) 2077*433d6423SLionel Sambuc panic("unable to retrieve BAR: %d", r); 2078*433d6423SLionel Sambuc 2079*433d6423SLionel Sambuc if (ioflag) 2080*433d6423SLionel Sambuc panic("invalid BAR type"); 2081*433d6423SLionel Sambuc 2082*433d6423SLionel Sambuc /* There must be at least one port, and at most NR_PORTS ports. Limit 2083*433d6423SLionel Sambuc * the actual total number of ports to the size of the exposed area. 2084*433d6423SLionel Sambuc */ 2085*433d6423SLionel Sambuc if (size < AHCI_MEM_BASE_SIZE + AHCI_MEM_PORT_SIZE) 2086*433d6423SLionel Sambuc panic("HBA memory size too small: %u", size); 2087*433d6423SLionel Sambuc 2088*433d6423SLionel Sambuc size = MIN(size, AHCI_MEM_BASE_SIZE + AHCI_MEM_PORT_SIZE * NR_PORTS); 2089*433d6423SLionel Sambuc 2090*433d6423SLionel Sambuc hba_state.nr_ports = (size - AHCI_MEM_BASE_SIZE) / AHCI_MEM_PORT_SIZE; 2091*433d6423SLionel Sambuc 2092*433d6423SLionel Sambuc /* Map the register area into local memory. */ 2093*433d6423SLionel Sambuc hba_state.base = (u32_t *) vm_map_phys(SELF, (void *) base, size); 2094*433d6423SLionel Sambuc hba_state.size = size; 2095*433d6423SLionel Sambuc if (hba_state.base == MAP_FAILED) 2096*433d6423SLionel Sambuc panic("unable to map HBA memory"); 2097*433d6423SLionel Sambuc 2098*433d6423SLionel Sambuc /* Retrieve, allocate and enable the controller's IRQ. */ 2099*433d6423SLionel Sambuc hba_state.irq = pci_attr_r8(devind, PCI_ILR); 2100*433d6423SLionel Sambuc hba_state.hook_id = 0; 2101*433d6423SLionel Sambuc 2102*433d6423SLionel Sambuc if ((r = sys_irqsetpolicy(hba_state.irq, 0, &hba_state.hook_id)) != OK) 2103*433d6423SLionel Sambuc panic("unable to register IRQ: %d", r); 2104*433d6423SLionel Sambuc 2105*433d6423SLionel Sambuc if ((r = sys_irqenable(&hba_state.hook_id)) != OK) 2106*433d6423SLionel Sambuc panic("unable to enable IRQ: %d", r); 2107*433d6423SLionel Sambuc 2108*433d6423SLionel Sambuc /* Reset the HBA. */ 2109*433d6423SLionel Sambuc ahci_reset(); 2110*433d6423SLionel Sambuc 2111*433d6423SLionel Sambuc /* Enable AHCI and interrupts. */ 2112*433d6423SLionel Sambuc ghc = hba_read(AHCI_HBA_GHC); 2113*433d6423SLionel Sambuc hba_write(AHCI_HBA_GHC, ghc | AHCI_HBA_GHC_AE | AHCI_HBA_GHC_IE); 2114*433d6423SLionel Sambuc 2115*433d6423SLionel Sambuc /* Limit the maximum number of commands to the controller's value. */ 2116*433d6423SLionel Sambuc /* Note that we currently use only one command anyway. */ 2117*433d6423SLionel Sambuc cap = hba_read(AHCI_HBA_CAP); 2118*433d6423SLionel Sambuc hba_state.has_ncq = !!(cap & AHCI_HBA_CAP_SNCQ); 2119*433d6423SLionel Sambuc hba_state.has_clo = !!(cap & AHCI_HBA_CAP_SCLO); 2120*433d6423SLionel Sambuc hba_state.nr_cmds = MIN(NR_CMDS, 2121*433d6423SLionel Sambuc ((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1); 2122*433d6423SLionel Sambuc 2123*433d6423SLionel Sambuc dprintf(V_INFO, ("AHCI%u: HBA v%d.%d%d, %ld ports, %ld commands, " 2124*433d6423SLionel Sambuc "%s queuing, IRQ %d\n", 2125*433d6423SLionel Sambuc ahci_instance, 2126*433d6423SLionel Sambuc (int) (hba_read(AHCI_HBA_VS) >> 16), 2127*433d6423SLionel Sambuc (int) ((hba_read(AHCI_HBA_VS) >> 8) & 0xFF), 2128*433d6423SLionel Sambuc (int) (hba_read(AHCI_HBA_VS) & 0xFF), 2129*433d6423SLionel Sambuc ((cap >> AHCI_HBA_CAP_NP_SHIFT) & AHCI_HBA_CAP_NP_MASK) + 1, 2130*433d6423SLionel Sambuc ((cap >> AHCI_HBA_CAP_NCS_SHIFT) & AHCI_HBA_CAP_NCS_MASK) + 1, 2131*433d6423SLionel Sambuc hba_state.has_ncq ? "supports" : "no", hba_state.irq)); 2132*433d6423SLionel Sambuc 2133*433d6423SLionel Sambuc dprintf(V_INFO, ("AHCI%u: CAP %08x, CAP2 %08x, PI %08x\n", 2134*433d6423SLionel Sambuc ahci_instance, cap, hba_read(AHCI_HBA_CAP2), 2135*433d6423SLionel Sambuc hba_read(AHCI_HBA_PI))); 2136*433d6423SLionel Sambuc 2137*433d6423SLionel Sambuc /* Initialize each of the implemented ports. We ignore CAP.NP. */ 2138*433d6423SLionel Sambuc mask = hba_read(AHCI_HBA_PI); 2139*433d6423SLionel Sambuc 2140*433d6423SLionel Sambuc for (port = 0; port < hba_state.nr_ports; port++) { 2141*433d6423SLionel Sambuc port_state[port].device = NO_DEVICE; 2142*433d6423SLionel Sambuc port_state[port].state = STATE_NO_PORT; 2143*433d6423SLionel Sambuc 2144*433d6423SLionel Sambuc if (mask & (1 << port)) 2145*433d6423SLionel Sambuc port_init(&port_state[port]); 2146*433d6423SLionel Sambuc } 2147*433d6423SLionel Sambuc } 2148*433d6423SLionel Sambuc 2149*433d6423SLionel Sambuc /*===========================================================================* 2150*433d6423SLionel Sambuc * ahci_stop * 2151*433d6423SLionel Sambuc *===========================================================================*/ 2152*433d6423SLionel Sambuc static void ahci_stop(void) 2153*433d6423SLionel Sambuc { 2154*433d6423SLionel Sambuc /* Disable AHCI, and clean up resources to the extent possible. 2155*433d6423SLionel Sambuc */ 2156*433d6423SLionel Sambuc struct port_state *ps; 2157*433d6423SLionel Sambuc int r, port; 2158*433d6423SLionel Sambuc 2159*433d6423SLionel Sambuc for (port = 0; port < hba_state.nr_ports; port++) { 2160*433d6423SLionel Sambuc ps = &port_state[port]; 2161*433d6423SLionel Sambuc 2162*433d6423SLionel Sambuc if (ps->state != STATE_NO_PORT) { 2163*433d6423SLionel Sambuc port_stop(ps); 2164*433d6423SLionel Sambuc 2165*433d6423SLionel Sambuc port_free(ps); 2166*433d6423SLionel Sambuc } 2167*433d6423SLionel Sambuc } 2168*433d6423SLionel Sambuc 2169*433d6423SLionel Sambuc ahci_reset(); 2170*433d6423SLionel Sambuc 2171*433d6423SLionel Sambuc if ((r = vm_unmap_phys(SELF, (void *) hba_state.base, 2172*433d6423SLionel Sambuc hba_state.size)) != OK) 2173*433d6423SLionel Sambuc panic("unable to unmap HBA memory: %d", r); 2174*433d6423SLionel Sambuc 2175*433d6423SLionel Sambuc if ((r = sys_irqrmpolicy(&hba_state.hook_id)) != OK) 2176*433d6423SLionel Sambuc panic("unable to deregister IRQ: %d", r); 2177*433d6423SLionel Sambuc } 2178*433d6423SLionel Sambuc 2179*433d6423SLionel Sambuc /*===========================================================================* 2180*433d6423SLionel Sambuc * ahci_alarm * 2181*433d6423SLionel Sambuc *===========================================================================*/ 2182*433d6423SLionel Sambuc static void ahci_alarm(clock_t stamp) 2183*433d6423SLionel Sambuc { 2184*433d6423SLionel Sambuc /* Process an alarm. 2185*433d6423SLionel Sambuc */ 2186*433d6423SLionel Sambuc 2187*433d6423SLionel Sambuc /* Call the port-specific handler for each port that timed out. */ 2188*433d6423SLionel Sambuc expire_timers(stamp); 2189*433d6423SLionel Sambuc } 2190*433d6423SLionel Sambuc 2191*433d6423SLionel Sambuc /*===========================================================================* 2192*433d6423SLionel Sambuc * ahci_intr * 2193*433d6423SLionel Sambuc *===========================================================================*/ 2194*433d6423SLionel Sambuc static void ahci_intr(unsigned int UNUSED(mask)) 2195*433d6423SLionel Sambuc { 2196*433d6423SLionel Sambuc /* Process an interrupt. 2197*433d6423SLionel Sambuc */ 2198*433d6423SLionel Sambuc struct port_state *ps; 2199*433d6423SLionel Sambuc u32_t mask; 2200*433d6423SLionel Sambuc int r, port; 2201*433d6423SLionel Sambuc 2202*433d6423SLionel Sambuc /* Handle an interrupt for each port that has the interrupt bit set. */ 2203*433d6423SLionel Sambuc mask = hba_read(AHCI_HBA_IS); 2204*433d6423SLionel Sambuc 2205*433d6423SLionel Sambuc for (port = 0; port < hba_state.nr_ports; port++) { 2206*433d6423SLionel Sambuc if (mask & (1 << port)) { 2207*433d6423SLionel Sambuc ps = &port_state[port]; 2208*433d6423SLionel Sambuc 2209*433d6423SLionel Sambuc port_intr(ps); 2210*433d6423SLionel Sambuc 2211*433d6423SLionel Sambuc /* After processing an interrupt, wake up the device 2212*433d6423SLionel Sambuc * thread if it is suspended and now no longer busy. 2213*433d6423SLionel Sambuc */ 2214*433d6423SLionel Sambuc if ((ps->flags & (FLAG_SUSPENDED | FLAG_BUSY)) == 2215*433d6423SLionel Sambuc FLAG_SUSPENDED) 2216*433d6423SLionel Sambuc blockdriver_mt_wakeup(ps->cmd_info[0].tid); 2217*433d6423SLionel Sambuc } 2218*433d6423SLionel Sambuc } 2219*433d6423SLionel Sambuc 2220*433d6423SLionel Sambuc /* Clear the bits that we processed. */ 2221*433d6423SLionel Sambuc hba_write(AHCI_HBA_IS, mask); 2222*433d6423SLionel Sambuc 2223*433d6423SLionel Sambuc /* Reenable the interrupt. */ 2224*433d6423SLionel Sambuc if ((r = sys_irqenable(&hba_state.hook_id)) != OK) 2225*433d6423SLionel Sambuc panic("unable to enable IRQ: %d", r); 2226*433d6423SLionel Sambuc } 2227*433d6423SLionel Sambuc 2228*433d6423SLionel Sambuc /*===========================================================================* 2229*433d6423SLionel Sambuc * ahci_get_params * 2230*433d6423SLionel Sambuc *===========================================================================*/ 2231*433d6423SLionel Sambuc static void ahci_get_params(void) 2232*433d6423SLionel Sambuc { 2233*433d6423SLionel Sambuc /* Retrieve and parse parameters passed to this driver, except the 2234*433d6423SLionel Sambuc * device-to-port mapping, which has to be parsed later. 2235*433d6423SLionel Sambuc */ 2236*433d6423SLionel Sambuc long v; 2237*433d6423SLionel Sambuc unsigned int i; 2238*433d6423SLionel Sambuc 2239*433d6423SLionel Sambuc /* Find out which driver instance we are. */ 2240*433d6423SLionel Sambuc v = 0; 2241*433d6423SLionel Sambuc (void) env_parse("instance", "d", 0, &v, 0, 255); 2242*433d6423SLionel Sambuc ahci_instance = (int) v; 2243*433d6423SLionel Sambuc 2244*433d6423SLionel Sambuc /* Initialize the verbosity level. */ 2245*433d6423SLionel Sambuc v = V_ERR; 2246*433d6423SLionel Sambuc (void) env_parse("ahci_verbose", "d", 0, &v, V_NONE, V_REQ); 2247*433d6423SLionel Sambuc ahci_verbose = (int) v; 2248*433d6423SLionel Sambuc 2249*433d6423SLionel Sambuc /* Initialize timeout-related values. */ 2250*433d6423SLionel Sambuc for (i = 0; i < sizeof(ahci_timevar) / sizeof(ahci_timevar[0]); i++) { 2251*433d6423SLionel Sambuc v = ahci_timevar[i].default_ms; 2252*433d6423SLionel Sambuc 2253*433d6423SLionel Sambuc (void) env_parse(ahci_timevar[i].name, "d", 0, &v, 1, 2254*433d6423SLionel Sambuc LONG_MAX); 2255*433d6423SLionel Sambuc 2256*433d6423SLionel Sambuc *ahci_timevar[i].ptr = millis_to_hz(v); 2257*433d6423SLionel Sambuc } 2258*433d6423SLionel Sambuc 2259*433d6423SLionel Sambuc ahci_device_delay = millis_to_hz(DEVICE_DELAY); 2260*433d6423SLionel Sambuc ahci_device_checks = (ahci_device_timeout + ahci_device_delay - 1) / 2261*433d6423SLionel Sambuc ahci_device_delay; 2262*433d6423SLionel Sambuc } 2263*433d6423SLionel Sambuc 2264*433d6423SLionel Sambuc /*===========================================================================* 2265*433d6423SLionel Sambuc * ahci_set_mapping * 2266*433d6423SLionel Sambuc *===========================================================================*/ 2267*433d6423SLionel Sambuc static void ahci_set_mapping(void) 2268*433d6423SLionel Sambuc { 2269*433d6423SLionel Sambuc /* Construct a mapping from device nodes to port numbers. 2270*433d6423SLionel Sambuc */ 2271*433d6423SLionel Sambuc char key[16], val[32], *p; 2272*433d6423SLionel Sambuc unsigned int port; 2273*433d6423SLionel Sambuc int i, j; 2274*433d6423SLionel Sambuc 2275*433d6423SLionel Sambuc /* Start off with a mapping that includes implemented ports only, in 2276*433d6423SLionel Sambuc * order. We choose this mapping over an identity mapping to maximize 2277*433d6423SLionel Sambuc * the chance that the user will be able to access the first MAX_DRIVES 2278*433d6423SLionel Sambuc * devices. Note that we can only do this after initializing the HBA. 2279*433d6423SLionel Sambuc */ 2280*433d6423SLionel Sambuc for (i = j = 0; i < NR_PORTS && j < MAX_DRIVES; i++) 2281*433d6423SLionel Sambuc if (port_state[i].state != STATE_NO_PORT) 2282*433d6423SLionel Sambuc ahci_map[j++] = i; 2283*433d6423SLionel Sambuc 2284*433d6423SLionel Sambuc for ( ; j < MAX_DRIVES; j++) 2285*433d6423SLionel Sambuc ahci_map[j] = NO_PORT; 2286*433d6423SLionel Sambuc 2287*433d6423SLionel Sambuc /* See if the user specified a custom mapping. Unlike all other 2288*433d6423SLionel Sambuc * configuration options, this is a per-instance setting. 2289*433d6423SLionel Sambuc */ 2290*433d6423SLionel Sambuc strlcpy(key, "ahci0_map", sizeof(key)); 2291*433d6423SLionel Sambuc key[4] += ahci_instance; 2292*433d6423SLionel Sambuc 2293*433d6423SLionel Sambuc if (env_get_param(key, val, sizeof(val)) == OK) { 2294*433d6423SLionel Sambuc /* Parse the mapping, which is assumed to be a comma-separated 2295*433d6423SLionel Sambuc * list of zero-based port numbers. 2296*433d6423SLionel Sambuc */ 2297*433d6423SLionel Sambuc p = val; 2298*433d6423SLionel Sambuc 2299*433d6423SLionel Sambuc for (i = 0; i < MAX_DRIVES; i++) { 2300*433d6423SLionel Sambuc if (*p) { 2301*433d6423SLionel Sambuc port = (unsigned int) strtoul(p, &p, 0); 2302*433d6423SLionel Sambuc 2303*433d6423SLionel Sambuc if (*p) p++; 2304*433d6423SLionel Sambuc 2305*433d6423SLionel Sambuc ahci_map[i] = port % NR_PORTS; 2306*433d6423SLionel Sambuc } 2307*433d6423SLionel Sambuc else ahci_map[i] = NO_PORT; 2308*433d6423SLionel Sambuc } 2309*433d6423SLionel Sambuc } 2310*433d6423SLionel Sambuc 2311*433d6423SLionel Sambuc /* Create a reverse mapping. */ 2312*433d6423SLionel Sambuc for (i = 0; i < MAX_DRIVES; i++) 2313*433d6423SLionel Sambuc if ((j = ahci_map[i]) != NO_PORT) 2314*433d6423SLionel Sambuc port_state[j].device = i; 2315*433d6423SLionel Sambuc } 2316*433d6423SLionel Sambuc 2317*433d6423SLionel Sambuc /*===========================================================================* 2318*433d6423SLionel Sambuc * sef_cb_init_fresh * 2319*433d6423SLionel Sambuc *===========================================================================*/ 2320*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *UNUSED(info)) 2321*433d6423SLionel Sambuc { 2322*433d6423SLionel Sambuc /* Initialize the driver. 2323*433d6423SLionel Sambuc */ 2324*433d6423SLionel Sambuc int devind; 2325*433d6423SLionel Sambuc 2326*433d6423SLionel Sambuc /* Get command line parameters. */ 2327*433d6423SLionel Sambuc ahci_get_params(); 2328*433d6423SLionel Sambuc 2329*433d6423SLionel Sambuc /* Probe for recognized devices, skipping matches as appropriate. */ 2330*433d6423SLionel Sambuc devind = ahci_probe(ahci_instance); 2331*433d6423SLionel Sambuc 2332*433d6423SLionel Sambuc if (devind < 0) 2333*433d6423SLionel Sambuc panic("no matching device found"); 2334*433d6423SLionel Sambuc 2335*433d6423SLionel Sambuc /* Initialize the device we found. */ 2336*433d6423SLionel Sambuc ahci_init(devind); 2337*433d6423SLionel Sambuc 2338*433d6423SLionel Sambuc /* Create a mapping from device nodes to port numbers. */ 2339*433d6423SLionel Sambuc ahci_set_mapping(); 2340*433d6423SLionel Sambuc 2341*433d6423SLionel Sambuc /* Announce that we are up. */ 2342*433d6423SLionel Sambuc blockdriver_announce(type); 2343*433d6423SLionel Sambuc 2344*433d6423SLionel Sambuc return OK; 2345*433d6423SLionel Sambuc } 2346*433d6423SLionel Sambuc 2347*433d6423SLionel Sambuc /*===========================================================================* 2348*433d6423SLionel Sambuc * sef_cb_signal_handler * 2349*433d6423SLionel Sambuc *===========================================================================*/ 2350*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo) 2351*433d6423SLionel Sambuc { 2352*433d6423SLionel Sambuc /* In case of a termination signal, shut down this driver. 2353*433d6423SLionel Sambuc */ 2354*433d6423SLionel Sambuc int port; 2355*433d6423SLionel Sambuc 2356*433d6423SLionel Sambuc if (signo != SIGTERM) return; 2357*433d6423SLionel Sambuc 2358*433d6423SLionel Sambuc /* If any ports are still opened, assume that the system is being shut 2359*433d6423SLionel Sambuc * down, and stay up until the last device has been closed. 2360*433d6423SLionel Sambuc */ 2361*433d6423SLionel Sambuc ahci_exiting = TRUE; 2362*433d6423SLionel Sambuc 2363*433d6423SLionel Sambuc for (port = 0; port < hba_state.nr_ports; port++) 2364*433d6423SLionel Sambuc if (port_state[port].open_count > 0) 2365*433d6423SLionel Sambuc return; 2366*433d6423SLionel Sambuc 2367*433d6423SLionel Sambuc /* If not, stop the driver and exit immediately. */ 2368*433d6423SLionel Sambuc ahci_stop(); 2369*433d6423SLionel Sambuc 2370*433d6423SLionel Sambuc exit(0); 2371*433d6423SLionel Sambuc } 2372*433d6423SLionel Sambuc 2373*433d6423SLionel Sambuc /*===========================================================================* 2374*433d6423SLionel Sambuc * sef_local_startup * 2375*433d6423SLionel Sambuc *===========================================================================*/ 2376*433d6423SLionel Sambuc static void sef_local_startup(void) 2377*433d6423SLionel Sambuc { 2378*433d6423SLionel Sambuc /* Set callbacks and initialize the System Event Framework (SEF). 2379*433d6423SLionel Sambuc */ 2380*433d6423SLionel Sambuc 2381*433d6423SLionel Sambuc /* Register init callbacks. */ 2382*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh); 2383*433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init_fresh); 2384*433d6423SLionel Sambuc 2385*433d6423SLionel Sambuc /* Register signal callbacks. */ 2386*433d6423SLionel Sambuc sef_setcb_signal_handler(sef_cb_signal_handler); 2387*433d6423SLionel Sambuc 2388*433d6423SLionel Sambuc /* Let SEF perform startup. */ 2389*433d6423SLionel Sambuc sef_startup(); 2390*433d6423SLionel Sambuc } 2391*433d6423SLionel Sambuc 2392*433d6423SLionel Sambuc /*===========================================================================* 2393*433d6423SLionel Sambuc * ahci_portname * 2394*433d6423SLionel Sambuc *===========================================================================*/ 2395*433d6423SLionel Sambuc static char *ahci_portname(struct port_state *ps) 2396*433d6423SLionel Sambuc { 2397*433d6423SLionel Sambuc /* Return a printable name for the given port. Whenever we can, print a 2398*433d6423SLionel Sambuc * "Dx" device number rather than a "Pxx" port number, because the user 2399*433d6423SLionel Sambuc * may not be aware of the mapping currently in use. 2400*433d6423SLionel Sambuc */ 2401*433d6423SLionel Sambuc static char name[] = "AHCI0-P00"; 2402*433d6423SLionel Sambuc 2403*433d6423SLionel Sambuc name[4] = '0' + ahci_instance; 2404*433d6423SLionel Sambuc 2405*433d6423SLionel Sambuc if (ps->device == NO_DEVICE) { 2406*433d6423SLionel Sambuc name[6] = 'P'; 2407*433d6423SLionel Sambuc name[7] = '0' + (ps - port_state) / 10; 2408*433d6423SLionel Sambuc name[8] = '0' + (ps - port_state) % 10; 2409*433d6423SLionel Sambuc } 2410*433d6423SLionel Sambuc else { 2411*433d6423SLionel Sambuc name[6] = 'D'; 2412*433d6423SLionel Sambuc name[7] = '0' + ps->device; 2413*433d6423SLionel Sambuc name[8] = 0; 2414*433d6423SLionel Sambuc } 2415*433d6423SLionel Sambuc 2416*433d6423SLionel Sambuc return name; 2417*433d6423SLionel Sambuc } 2418*433d6423SLionel Sambuc 2419*433d6423SLionel Sambuc /*===========================================================================* 2420*433d6423SLionel Sambuc * ahci_map_minor * 2421*433d6423SLionel Sambuc *===========================================================================*/ 2422*433d6423SLionel Sambuc static struct port_state *ahci_map_minor(devminor_t minor, struct device **dvp) 2423*433d6423SLionel Sambuc { 2424*433d6423SLionel Sambuc /* Map a minor device number to a port and a pointer to the partition's 2425*433d6423SLionel Sambuc * device structure. Return NULL if this minor device number does not 2426*433d6423SLionel Sambuc * identify an actual device. 2427*433d6423SLionel Sambuc */ 2428*433d6423SLionel Sambuc struct port_state *ps; 2429*433d6423SLionel Sambuc int port; 2430*433d6423SLionel Sambuc 2431*433d6423SLionel Sambuc ps = NULL; 2432*433d6423SLionel Sambuc 2433*433d6423SLionel Sambuc if (minor >= 0 && minor < NR_MINORS) { 2434*433d6423SLionel Sambuc port = ahci_map[minor / DEV_PER_DRIVE]; 2435*433d6423SLionel Sambuc 2436*433d6423SLionel Sambuc if (port == NO_PORT) 2437*433d6423SLionel Sambuc return NULL; 2438*433d6423SLionel Sambuc 2439*433d6423SLionel Sambuc ps = &port_state[port]; 2440*433d6423SLionel Sambuc *dvp = &ps->part[minor % DEV_PER_DRIVE]; 2441*433d6423SLionel Sambuc } 2442*433d6423SLionel Sambuc else if ((unsigned) (minor -= MINOR_d0p0s0) < NR_SUBDEVS) { 2443*433d6423SLionel Sambuc port = ahci_map[minor / SUB_PER_DRIVE]; 2444*433d6423SLionel Sambuc 2445*433d6423SLionel Sambuc if (port == NO_PORT) 2446*433d6423SLionel Sambuc return NULL; 2447*433d6423SLionel Sambuc 2448*433d6423SLionel Sambuc ps = &port_state[port]; 2449*433d6423SLionel Sambuc *dvp = &ps->subpart[minor % SUB_PER_DRIVE]; 2450*433d6423SLionel Sambuc } 2451*433d6423SLionel Sambuc 2452*433d6423SLionel Sambuc return ps; 2453*433d6423SLionel Sambuc } 2454*433d6423SLionel Sambuc 2455*433d6423SLionel Sambuc /*===========================================================================* 2456*433d6423SLionel Sambuc * ahci_part * 2457*433d6423SLionel Sambuc *===========================================================================*/ 2458*433d6423SLionel Sambuc static struct device *ahci_part(devminor_t minor) 2459*433d6423SLionel Sambuc { 2460*433d6423SLionel Sambuc /* Return a pointer to the partition information structure of the given 2461*433d6423SLionel Sambuc * minor device. 2462*433d6423SLionel Sambuc */ 2463*433d6423SLionel Sambuc struct device *dv; 2464*433d6423SLionel Sambuc 2465*433d6423SLionel Sambuc if (ahci_map_minor(minor, &dv) == NULL) 2466*433d6423SLionel Sambuc return NULL; 2467*433d6423SLionel Sambuc 2468*433d6423SLionel Sambuc return dv; 2469*433d6423SLionel Sambuc } 2470*433d6423SLionel Sambuc 2471*433d6423SLionel Sambuc /*===========================================================================* 2472*433d6423SLionel Sambuc * ahci_open * 2473*433d6423SLionel Sambuc *===========================================================================*/ 2474*433d6423SLionel Sambuc static int ahci_open(devminor_t minor, int access) 2475*433d6423SLionel Sambuc { 2476*433d6423SLionel Sambuc /* Open a device. 2477*433d6423SLionel Sambuc */ 2478*433d6423SLionel Sambuc struct port_state *ps; 2479*433d6423SLionel Sambuc int r; 2480*433d6423SLionel Sambuc 2481*433d6423SLionel Sambuc ps = ahci_get_port(minor); 2482*433d6423SLionel Sambuc 2483*433d6423SLionel Sambuc /* Only one open request can be processed at a time, due to the fact 2484*433d6423SLionel Sambuc * that it is an exclusive operation. The thread that handles this call 2485*433d6423SLionel Sambuc * can therefore freely register itself at slot zero. 2486*433d6423SLionel Sambuc */ 2487*433d6423SLionel Sambuc ps->cmd_info[0].tid = blockdriver_mt_get_tid(); 2488*433d6423SLionel Sambuc 2489*433d6423SLionel Sambuc /* If we are still in the process of initializing this port or device, 2490*433d6423SLionel Sambuc * wait for completion of that phase first. 2491*433d6423SLionel Sambuc */ 2492*433d6423SLionel Sambuc if (ps->flags & FLAG_BUSY) 2493*433d6423SLionel Sambuc port_wait(ps); 2494*433d6423SLionel Sambuc 2495*433d6423SLionel Sambuc /* The device may only be opened if it is now properly functioning. */ 2496*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV) 2497*433d6423SLionel Sambuc return ENXIO; 2498*433d6423SLionel Sambuc 2499*433d6423SLionel Sambuc /* Some devices may only be opened in read-only mode. */ 2500*433d6423SLionel Sambuc if ((ps->flags & FLAG_READONLY) && (access & BDEV_W_BIT)) 2501*433d6423SLionel Sambuc return EACCES; 2502*433d6423SLionel Sambuc 2503*433d6423SLionel Sambuc if (ps->open_count == 0) { 2504*433d6423SLionel Sambuc /* The first open request. Clear the barrier flag, if set. */ 2505*433d6423SLionel Sambuc ps->flags &= ~FLAG_BARRIER; 2506*433d6423SLionel Sambuc 2507*433d6423SLionel Sambuc /* Recheck media only when nobody is using the device. */ 2508*433d6423SLionel Sambuc if ((ps->flags & FLAG_ATAPI) && 2509*433d6423SLionel Sambuc (r = atapi_check_medium(ps, 0)) != OK) 2510*433d6423SLionel Sambuc return r; 2511*433d6423SLionel Sambuc 2512*433d6423SLionel Sambuc /* After rechecking the media, the partition table must always 2513*433d6423SLionel Sambuc * be read. This is also a convenient time to do it for 2514*433d6423SLionel Sambuc * nonremovable devices. Start by resetting the partition 2515*433d6423SLionel Sambuc * tables and setting the working size of the entire device. 2516*433d6423SLionel Sambuc */ 2517*433d6423SLionel Sambuc memset(ps->part, 0, sizeof(ps->part)); 2518*433d6423SLionel Sambuc memset(ps->subpart, 0, sizeof(ps->subpart)); 2519*433d6423SLionel Sambuc 2520*433d6423SLionel Sambuc ps->part[0].dv_size = ps->lba_count * ps->sector_size; 2521*433d6423SLionel Sambuc 2522*433d6423SLionel Sambuc partition(&ahci_dtab, ps->device * DEV_PER_DRIVE, P_PRIMARY, 2523*433d6423SLionel Sambuc !!(ps->flags & FLAG_ATAPI)); 2524*433d6423SLionel Sambuc 2525*433d6423SLionel Sambuc blockdriver_mt_set_workers(ps->device, ps->queue_depth); 2526*433d6423SLionel Sambuc } 2527*433d6423SLionel Sambuc else { 2528*433d6423SLionel Sambuc /* If the barrier flag is set, deny new open requests until the 2529*433d6423SLionel Sambuc * device is fully closed first. 2530*433d6423SLionel Sambuc */ 2531*433d6423SLionel Sambuc if (ps->flags & FLAG_BARRIER) 2532*433d6423SLionel Sambuc return ENXIO; 2533*433d6423SLionel Sambuc } 2534*433d6423SLionel Sambuc 2535*433d6423SLionel Sambuc ps->open_count++; 2536*433d6423SLionel Sambuc 2537*433d6423SLionel Sambuc return OK; 2538*433d6423SLionel Sambuc } 2539*433d6423SLionel Sambuc 2540*433d6423SLionel Sambuc /*===========================================================================* 2541*433d6423SLionel Sambuc * ahci_close * 2542*433d6423SLionel Sambuc *===========================================================================*/ 2543*433d6423SLionel Sambuc static int ahci_close(devminor_t minor) 2544*433d6423SLionel Sambuc { 2545*433d6423SLionel Sambuc /* Close a device. 2546*433d6423SLionel Sambuc */ 2547*433d6423SLionel Sambuc struct port_state *ps; 2548*433d6423SLionel Sambuc int port; 2549*433d6423SLionel Sambuc 2550*433d6423SLionel Sambuc ps = ahci_get_port(minor); 2551*433d6423SLionel Sambuc 2552*433d6423SLionel Sambuc /* Decrease the open count. */ 2553*433d6423SLionel Sambuc if (ps->open_count <= 0) { 2554*433d6423SLionel Sambuc dprintf(V_ERR, ("%s: closing already-closed port\n", 2555*433d6423SLionel Sambuc ahci_portname(ps))); 2556*433d6423SLionel Sambuc 2557*433d6423SLionel Sambuc return EINVAL; 2558*433d6423SLionel Sambuc } 2559*433d6423SLionel Sambuc 2560*433d6423SLionel Sambuc ps->open_count--; 2561*433d6423SLionel Sambuc 2562*433d6423SLionel Sambuc if (ps->open_count > 0) 2563*433d6423SLionel Sambuc return OK; 2564*433d6423SLionel Sambuc 2565*433d6423SLionel Sambuc /* The device is now fully closed. That also means that the threads for 2566*433d6423SLionel Sambuc * this device are not needed anymore, so we reduce the count to one. 2567*433d6423SLionel Sambuc */ 2568*433d6423SLionel Sambuc blockdriver_mt_set_workers(ps->device, 1); 2569*433d6423SLionel Sambuc 2570*433d6423SLionel Sambuc if (ps->state == STATE_GOOD_DEV && !(ps->flags & FLAG_BARRIER)) { 2571*433d6423SLionel Sambuc dprintf(V_INFO, ("%s: flushing write cache\n", 2572*433d6423SLionel Sambuc ahci_portname(ps))); 2573*433d6423SLionel Sambuc 2574*433d6423SLionel Sambuc (void) gen_flush_wcache(ps); 2575*433d6423SLionel Sambuc } 2576*433d6423SLionel Sambuc 2577*433d6423SLionel Sambuc /* If the entire driver has been told to terminate, check whether all 2578*433d6423SLionel Sambuc * devices are now closed. If so, tell libblockdriver to quit after 2579*433d6423SLionel Sambuc * replying to the close request. 2580*433d6423SLionel Sambuc */ 2581*433d6423SLionel Sambuc if (ahci_exiting) { 2582*433d6423SLionel Sambuc for (port = 0; port < hba_state.nr_ports; port++) 2583*433d6423SLionel Sambuc if (port_state[port].open_count > 0) 2584*433d6423SLionel Sambuc break; 2585*433d6423SLionel Sambuc 2586*433d6423SLionel Sambuc if (port == hba_state.nr_ports) { 2587*433d6423SLionel Sambuc ahci_stop(); 2588*433d6423SLionel Sambuc 2589*433d6423SLionel Sambuc blockdriver_mt_terminate(); 2590*433d6423SLionel Sambuc } 2591*433d6423SLionel Sambuc } 2592*433d6423SLionel Sambuc 2593*433d6423SLionel Sambuc return OK; 2594*433d6423SLionel Sambuc } 2595*433d6423SLionel Sambuc 2596*433d6423SLionel Sambuc /*===========================================================================* 2597*433d6423SLionel Sambuc * ahci_transfer * 2598*433d6423SLionel Sambuc *===========================================================================*/ 2599*433d6423SLionel Sambuc static ssize_t ahci_transfer(devminor_t minor, int do_write, u64_t position, 2600*433d6423SLionel Sambuc endpoint_t endpt, iovec_t *iovec, unsigned int count, int flags) 2601*433d6423SLionel Sambuc { 2602*433d6423SLionel Sambuc /* Perform data transfer on the selected device. 2603*433d6423SLionel Sambuc */ 2604*433d6423SLionel Sambuc struct port_state *ps; 2605*433d6423SLionel Sambuc struct device *dv; 2606*433d6423SLionel Sambuc u64_t pos, eof; 2607*433d6423SLionel Sambuc 2608*433d6423SLionel Sambuc ps = ahci_get_port(minor); 2609*433d6423SLionel Sambuc dv = ahci_part(minor); 2610*433d6423SLionel Sambuc 2611*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV || (ps->flags & FLAG_BARRIER)) 2612*433d6423SLionel Sambuc return EIO; 2613*433d6423SLionel Sambuc 2614*433d6423SLionel Sambuc if (count > NR_IOREQS) 2615*433d6423SLionel Sambuc return EINVAL; 2616*433d6423SLionel Sambuc 2617*433d6423SLionel Sambuc /* Check for basic end-of-partition condition: if the start position of 2618*433d6423SLionel Sambuc * the request is outside the partition, return success immediately. 2619*433d6423SLionel Sambuc * The size of the request is obtained, and possibly reduced, later. 2620*433d6423SLionel Sambuc */ 2621*433d6423SLionel Sambuc if (position >= dv->dv_size) 2622*433d6423SLionel Sambuc return OK; 2623*433d6423SLionel Sambuc 2624*433d6423SLionel Sambuc pos = dv->dv_base + position; 2625*433d6423SLionel Sambuc eof = dv->dv_base + dv->dv_size; 2626*433d6423SLionel Sambuc 2627*433d6423SLionel Sambuc return port_transfer(ps, pos, eof, endpt, (iovec_s_t *) iovec, count, 2628*433d6423SLionel Sambuc do_write, flags); 2629*433d6423SLionel Sambuc } 2630*433d6423SLionel Sambuc 2631*433d6423SLionel Sambuc /*===========================================================================* 2632*433d6423SLionel Sambuc * ahci_ioctl * 2633*433d6423SLionel Sambuc *===========================================================================*/ 2634*433d6423SLionel Sambuc static int ahci_ioctl(devminor_t minor, unsigned long request, 2635*433d6423SLionel Sambuc endpoint_t endpt, cp_grant_id_t grant, endpoint_t UNUSED(user_endpt)) 2636*433d6423SLionel Sambuc { 2637*433d6423SLionel Sambuc /* Process I/O control requests. 2638*433d6423SLionel Sambuc */ 2639*433d6423SLionel Sambuc struct port_state *ps; 2640*433d6423SLionel Sambuc int r, val; 2641*433d6423SLionel Sambuc 2642*433d6423SLionel Sambuc ps = ahci_get_port(minor); 2643*433d6423SLionel Sambuc 2644*433d6423SLionel Sambuc switch (request) { 2645*433d6423SLionel Sambuc case DIOCEJECT: 2646*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV || (ps->flags & FLAG_BARRIER)) 2647*433d6423SLionel Sambuc return EIO; 2648*433d6423SLionel Sambuc 2649*433d6423SLionel Sambuc if (!(ps->flags & FLAG_ATAPI)) 2650*433d6423SLionel Sambuc return EINVAL; 2651*433d6423SLionel Sambuc 2652*433d6423SLionel Sambuc return atapi_load_eject(ps, 0, FALSE /*load*/); 2653*433d6423SLionel Sambuc 2654*433d6423SLionel Sambuc case DIOCOPENCT: 2655*433d6423SLionel Sambuc return sys_safecopyto(endpt, grant, 0, 2656*433d6423SLionel Sambuc (vir_bytes) &ps->open_count, sizeof(ps->open_count)); 2657*433d6423SLionel Sambuc 2658*433d6423SLionel Sambuc case DIOCFLUSH: 2659*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV || (ps->flags & FLAG_BARRIER)) 2660*433d6423SLionel Sambuc return EIO; 2661*433d6423SLionel Sambuc 2662*433d6423SLionel Sambuc return gen_flush_wcache(ps); 2663*433d6423SLionel Sambuc 2664*433d6423SLionel Sambuc case DIOCSETWC: 2665*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV || (ps->flags & FLAG_BARRIER)) 2666*433d6423SLionel Sambuc return EIO; 2667*433d6423SLionel Sambuc 2668*433d6423SLionel Sambuc if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &val, 2669*433d6423SLionel Sambuc sizeof(val))) != OK) 2670*433d6423SLionel Sambuc return r; 2671*433d6423SLionel Sambuc 2672*433d6423SLionel Sambuc return gen_set_wcache(ps, val); 2673*433d6423SLionel Sambuc 2674*433d6423SLionel Sambuc case DIOCGETWC: 2675*433d6423SLionel Sambuc if (ps->state != STATE_GOOD_DEV || (ps->flags & FLAG_BARRIER)) 2676*433d6423SLionel Sambuc return EIO; 2677*433d6423SLionel Sambuc 2678*433d6423SLionel Sambuc if ((r = gen_get_wcache(ps, &val)) != OK) 2679*433d6423SLionel Sambuc return r; 2680*433d6423SLionel Sambuc 2681*433d6423SLionel Sambuc return sys_safecopyto(endpt, grant, 0, (vir_bytes) &val, 2682*433d6423SLionel Sambuc sizeof(val)); 2683*433d6423SLionel Sambuc } 2684*433d6423SLionel Sambuc 2685*433d6423SLionel Sambuc return ENOTTY; 2686*433d6423SLionel Sambuc } 2687*433d6423SLionel Sambuc 2688*433d6423SLionel Sambuc /*===========================================================================* 2689*433d6423SLionel Sambuc * ahci_device * 2690*433d6423SLionel Sambuc *===========================================================================*/ 2691*433d6423SLionel Sambuc static int ahci_device(devminor_t minor, device_id_t *id) 2692*433d6423SLionel Sambuc { 2693*433d6423SLionel Sambuc /* Map a minor device number to a device ID. 2694*433d6423SLionel Sambuc */ 2695*433d6423SLionel Sambuc struct port_state *ps; 2696*433d6423SLionel Sambuc struct device *dv; 2697*433d6423SLionel Sambuc 2698*433d6423SLionel Sambuc if ((ps = ahci_map_minor(minor, &dv)) == NULL) 2699*433d6423SLionel Sambuc return ENXIO; 2700*433d6423SLionel Sambuc 2701*433d6423SLionel Sambuc *id = ps->device; 2702*433d6423SLionel Sambuc 2703*433d6423SLionel Sambuc return OK; 2704*433d6423SLionel Sambuc } 2705*433d6423SLionel Sambuc 2706*433d6423SLionel Sambuc /*===========================================================================* 2707*433d6423SLionel Sambuc * ahci_get_port * 2708*433d6423SLionel Sambuc *===========================================================================*/ 2709*433d6423SLionel Sambuc static struct port_state *ahci_get_port(devminor_t minor) 2710*433d6423SLionel Sambuc { 2711*433d6423SLionel Sambuc /* Get the port structure associated with the given minor device. 2712*433d6423SLionel Sambuc * Called only from worker threads, so the minor device is already 2713*433d6423SLionel Sambuc * guaranteed to map to a port. 2714*433d6423SLionel Sambuc */ 2715*433d6423SLionel Sambuc struct port_state *ps; 2716*433d6423SLionel Sambuc struct device *dv; 2717*433d6423SLionel Sambuc 2718*433d6423SLionel Sambuc if ((ps = ahci_map_minor(minor, &dv)) == NULL) 2719*433d6423SLionel Sambuc panic("device mapping for minor %d disappeared", minor); 2720*433d6423SLionel Sambuc 2721*433d6423SLionel Sambuc return ps; 2722*433d6423SLionel Sambuc } 2723*433d6423SLionel Sambuc 2724*433d6423SLionel Sambuc /*===========================================================================* 2725*433d6423SLionel Sambuc * main * 2726*433d6423SLionel Sambuc *===========================================================================*/ 2727*433d6423SLionel Sambuc int main(int argc, char **argv) 2728*433d6423SLionel Sambuc { 2729*433d6423SLionel Sambuc /* Driver task. 2730*433d6423SLionel Sambuc */ 2731*433d6423SLionel Sambuc 2732*433d6423SLionel Sambuc env_setargs(argc, argv); 2733*433d6423SLionel Sambuc sef_local_startup(); 2734*433d6423SLionel Sambuc 2735*433d6423SLionel Sambuc blockdriver_mt_task(&ahci_dtab); 2736*433d6423SLionel Sambuc 2737*433d6423SLionel Sambuc return 0; 2738*433d6423SLionel Sambuc } 2739