From 24b691f7111d3c0dcbe192f203a94b883de680de Mon Sep 17 00:00:00 2001 From: mav Date: Thu, 12 Mar 2015 13:40:02 +0000 Subject: MFC r271146,271201,271207,271261,271457,272606,277100,277126,278034,279320, 279573: Sync AHCI driver with HEAD. Due to code reorganization in r271146 and many previous reordered merges it is problematic to merge those revisions separately. --- sys/conf/files | 5 +- sys/dev/ahci/ahci.c | 893 +++++++++++----------------------------------- sys/dev/ahci/ahci.h | 87 ++++- sys/dev/ahci/ahci_pci.c | 522 +++++++++++++++++++++++++++ sys/dev/ahci/ahciem.c | 4 +- sys/modules/ahci/Makefile | 2 +- 6 files changed, 815 insertions(+), 698 deletions(-) create mode 100644 sys/dev/ahci/ahci_pci.c diff --git a/sys/conf/files b/sys/conf/files index ae19e91..11ebd01 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -621,8 +621,9 @@ dev/aha/aha.c optional aha dev/aha/aha_isa.c optional aha isa dev/aha/aha_mca.c optional aha mca dev/ahb/ahb.c optional ahb eisa -dev/ahci/ahci.c optional ahci pci -dev/ahci/ahciem.c optional ahci pci +dev/ahci/ahci.c optional ahci +dev/ahci/ahciem.c optional ahci +dev/ahci/ahci_pci.c optional ahci pci dev/aic/aic.c optional aic dev/aic/aic_pccard.c optional aic pccard dev/aic7xxx/ahc_eisa.c optional ahc eisa diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 402810d..e05dd70 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -41,8 +41,6 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include #include "ahci.h" #include @@ -52,12 +50,9 @@ __FBSDID("$FreeBSD$"); #include /* local prototypes */ -static int ahci_setup_interrupt(device_t dev); static void ahci_intr(void *data); static void ahci_intr_one(void *data); static void ahci_intr_one_edge(void *data); -static int ahci_suspend(device_t dev); -static int ahci_resume(device_t dev); static int ahci_ch_init(device_t dev); static int ahci_ch_deinit(device_t dev); static int ahci_ch_suspend(device_t dev); @@ -66,408 +61,108 @@ static void ahci_ch_pm(void *arg); static void ahci_ch_intr(void *arg); static void ahci_ch_intr_direct(void *arg); static void ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus); -static int ahci_ctlr_reset(device_t dev); -static int ahci_ctlr_setup(device_t dev); -static void ahci_begin_transaction(device_t dev, union ccb *ccb); +static void ahci_begin_transaction(struct ahci_channel *ch, union ccb *ccb); static void ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error); static void ahci_execute_transaction(struct ahci_slot *slot); static void ahci_timeout(struct ahci_slot *slot); static void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et); -static int ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag); +static int ahci_setup_fis(struct ahci_channel *ch, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag); static void ahci_dmainit(device_t dev); static void ahci_dmasetupc_cb(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static void ahci_dmafini(device_t dev); static void ahci_slotsalloc(device_t dev); static void ahci_slotsfree(device_t dev); -static void ahci_reset(device_t dev); -static void ahci_start(device_t dev, int fbs); -static void ahci_stop(device_t dev); -static void ahci_clo(device_t dev); -static void ahci_start_fr(device_t dev); -static void ahci_stop_fr(device_t dev); +static void ahci_reset(struct ahci_channel *ch); +static void ahci_start(struct ahci_channel *ch, int fbs); +static void ahci_stop(struct ahci_channel *ch); +static void ahci_clo(struct ahci_channel *ch); +static void ahci_start_fr(struct ahci_channel *ch); +static void ahci_stop_fr(struct ahci_channel *ch); static int ahci_sata_connect(struct ahci_channel *ch); -static int ahci_sata_phy_reset(device_t dev); -static int ahci_wait_ready(device_t dev, int t, int t0); +static int ahci_sata_phy_reset(struct ahci_channel *ch); +static int ahci_wait_ready(struct ahci_channel *ch, int t, int t0); -static void ahci_issue_recovery(device_t dev); -static void ahci_process_read_log(device_t dev, union ccb *ccb); -static void ahci_process_request_sense(device_t dev, union ccb *ccb); +static void ahci_issue_recovery(struct ahci_channel *ch); +static void ahci_process_read_log(struct ahci_channel *ch, union ccb *ccb); +static void ahci_process_request_sense(struct ahci_channel *ch, union ccb *ccb); static void ahciaction(struct cam_sim *sim, union ccb *ccb); static void ahcipoll(struct cam_sim *sim); static MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driver data buffers"); -static const struct { - uint32_t id; - uint8_t rev; - const char *name; - int quirks; -#define AHCI_Q_NOFORCE 1 -#define AHCI_Q_NOPMP 2 -#define AHCI_Q_NONCQ 4 -#define AHCI_Q_1CH 8 -#define AHCI_Q_2CH 16 -#define AHCI_Q_4CH 32 -#define AHCI_Q_EDGEIS 64 -#define AHCI_Q_SATA2 128 -#define AHCI_Q_NOBSYRES 256 -#define AHCI_Q_NOAA 512 -#define AHCI_Q_NOCOUNT 1024 -#define AHCI_Q_ALTSIG 2048 -#define AHCI_Q_NOMSI 4096 - -#define AHCI_Q_BIT_STRING \ - "\020" \ - "\001NOFORCE" \ - "\002NOPMP" \ - "\003NONCQ" \ - "\0041CH" \ - "\0052CH" \ - "\0064CH" \ - "\007EDGEIS" \ - "\010SATA2" \ - "\011NOBSYRES" \ - "\012NOAA" \ - "\013NOCOUNT" \ - "\014ALTSIG" \ - "\015NOMSI" -} ahci_ids[] = { - {0x43801002, 0x00, "AMD SB600", AHCI_Q_NOMSI}, - {0x43901002, 0x00, "AMD SB7x0/SB8x0/SB9x0", 0}, - {0x43911002, 0x00, "AMD SB7x0/SB8x0/SB9x0", 0}, - {0x43921002, 0x00, "AMD SB7x0/SB8x0/SB9x0", 0}, - {0x43931002, 0x00, "AMD SB7x0/SB8x0/SB9x0", 0}, - {0x43941002, 0x00, "AMD SB7x0/SB8x0/SB9x0", 0}, - {0x43951002, 0x00, "AMD SB8x0/SB9x0", 0}, - {0x78001022, 0x00, "AMD Hudson-2", 0}, - {0x78011022, 0x00, "AMD Hudson-2", 0}, - {0x78021022, 0x00, "AMD Hudson-2", 0}, - {0x78031022, 0x00, "AMD Hudson-2", 0}, - {0x78041022, 0x00, "AMD Hudson-2", 0}, - {0x06111b21, 0x00, "ASMedia ASM2106", 0}, - {0x06121b21, 0x00, "ASMedia ASM1061", 0}, - {0x26528086, 0x00, "Intel ICH6", AHCI_Q_NOFORCE}, - {0x26538086, 0x00, "Intel ICH6M", AHCI_Q_NOFORCE}, - {0x26818086, 0x00, "Intel ESB2", 0}, - {0x26828086, 0x00, "Intel ESB2", 0}, - {0x26838086, 0x00, "Intel ESB2", 0}, - {0x27c18086, 0x00, "Intel ICH7", 0}, - {0x27c38086, 0x00, "Intel ICH7", 0}, - {0x27c58086, 0x00, "Intel ICH7M", 0}, - {0x27c68086, 0x00, "Intel ICH7M", 0}, - {0x28218086, 0x00, "Intel ICH8", 0}, - {0x28228086, 0x00, "Intel ICH8", 0}, - {0x28248086, 0x00, "Intel ICH8", 0}, - {0x28298086, 0x00, "Intel ICH8M", 0}, - {0x282a8086, 0x00, "Intel ICH8M", 0}, - {0x29228086, 0x00, "Intel ICH9", 0}, - {0x29238086, 0x00, "Intel ICH9", 0}, - {0x29248086, 0x00, "Intel ICH9", 0}, - {0x29258086, 0x00, "Intel ICH9", 0}, - {0x29278086, 0x00, "Intel ICH9", 0}, - {0x29298086, 0x00, "Intel ICH9M", 0}, - {0x292a8086, 0x00, "Intel ICH9M", 0}, - {0x292b8086, 0x00, "Intel ICH9M", 0}, - {0x292c8086, 0x00, "Intel ICH9M", 0}, - {0x292f8086, 0x00, "Intel ICH9M", 0}, - {0x294d8086, 0x00, "Intel ICH9", 0}, - {0x294e8086, 0x00, "Intel ICH9M", 0}, - {0x3a058086, 0x00, "Intel ICH10", 0}, - {0x3a228086, 0x00, "Intel ICH10", 0}, - {0x3a258086, 0x00, "Intel ICH10", 0}, - {0x3b228086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x3b238086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x3b258086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x3b298086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x3b2c8086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x3b2f8086, 0x00, "Intel 5 Series/3400 Series", 0}, - {0x1c028086, 0x00, "Intel Cougar Point", 0}, - {0x1c038086, 0x00, "Intel Cougar Point", 0}, - {0x1c048086, 0x00, "Intel Cougar Point", 0}, - {0x1c058086, 0x00, "Intel Cougar Point", 0}, - {0x1d028086, 0x00, "Intel Patsburg", 0}, - {0x1d048086, 0x00, "Intel Patsburg", 0}, - {0x1d068086, 0x00, "Intel Patsburg", 0}, - {0x28268086, 0x00, "Intel Patsburg (RAID)", 0}, - {0x1e028086, 0x00, "Intel Panther Point", 0}, - {0x1e038086, 0x00, "Intel Panther Point", 0}, - {0x1e048086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1e058086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1e068086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1e078086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1e0e8086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1e0f8086, 0x00, "Intel Panther Point (RAID)", 0}, - {0x1f228086, 0x00, "Intel Avoton", 0}, - {0x1f238086, 0x00, "Intel Avoton", 0}, - {0x1f248086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f258086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f268086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f278086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f2e8086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f2f8086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f328086, 0x00, "Intel Avoton", 0}, - {0x1f338086, 0x00, "Intel Avoton", 0}, - {0x1f348086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f358086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f368086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f378086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f3e8086, 0x00, "Intel Avoton (RAID)", 0}, - {0x1f3f8086, 0x00, "Intel Avoton (RAID)", 0}, - {0x23a38086, 0x00, "Intel Coleto Creek", 0}, - {0x28238086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x28278086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x8c028086, 0x00, "Intel Lynx Point", 0}, - {0x8c038086, 0x00, "Intel Lynx Point", 0}, - {0x8c048086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c058086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c068086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c078086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c0e8086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c0f8086, 0x00, "Intel Lynx Point (RAID)", 0}, - {0x8c828086, 0x00, "Intel Wildcat Point", 0}, - {0x8c838086, 0x00, "Intel Wildcat Point", 0}, - {0x8c848086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8c858086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8c868086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8c878086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8c8e8086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8c8f8086, 0x00, "Intel Wildcat Point (RAID)", 0}, - {0x8d028086, 0x00, "Intel Wellsburg", 0}, - {0x8d048086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x8d068086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x8d628086, 0x00, "Intel Wellsburg", 0}, - {0x8d648086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x8d668086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x8d6e8086, 0x00, "Intel Wellsburg (RAID)", 0}, - {0x9c028086, 0x00, "Intel Lynx Point-LP", 0}, - {0x9c038086, 0x00, "Intel Lynx Point-LP", 0}, - {0x9c048086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x9c058086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x9c068086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x9c078086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x9c0e8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x9c0f8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, - {0x23238086, 0x00, "Intel DH89xxCC", 0}, - {0x2360197b, 0x00, "JMicron JMB360", 0}, - {0x2361197b, 0x00, "JMicron JMB361", AHCI_Q_NOFORCE}, - {0x2362197b, 0x00, "JMicron JMB362", 0}, - {0x2363197b, 0x00, "JMicron JMB363", AHCI_Q_NOFORCE}, - {0x2365197b, 0x00, "JMicron JMB365", AHCI_Q_NOFORCE}, - {0x2366197b, 0x00, "JMicron JMB366", AHCI_Q_NOFORCE}, - {0x2368197b, 0x00, "JMicron JMB368", AHCI_Q_NOFORCE}, - {0x611111ab, 0x00, "Marvell 88SE6111", AHCI_Q_NOFORCE | AHCI_Q_1CH | - AHCI_Q_EDGEIS}, - {0x612111ab, 0x00, "Marvell 88SE6121", AHCI_Q_NOFORCE | AHCI_Q_2CH | - AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, - {0x614111ab, 0x00, "Marvell 88SE6141", AHCI_Q_NOFORCE | AHCI_Q_4CH | - AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, - {0x614511ab, 0x00, "Marvell 88SE6145", AHCI_Q_NOFORCE | AHCI_Q_4CH | - AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, - {0x91201b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS}, - {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_ALTSIG}, - {0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2}, - {0x91251b4b, 0x00, "Marvell 88SE9125", 0}, - {0x91281b4b, 0x00, "Marvell 88SE9128", AHCI_Q_ALTSIG}, - {0x91301b4b, 0x00, "Marvell 88SE9130", AHCI_Q_ALTSIG}, - {0x91721b4b, 0x00, "Marvell 88SE9172", 0}, - {0x91821b4b, 0x00, "Marvell 88SE9182", 0}, - {0x91831b4b, 0x00, "Marvell 88SS9183", 0}, - {0x91a01b4b, 0x00, "Marvell 88SE91Ax", 0}, - {0x92151b4b, 0x00, "Marvell 88SE9215", 0}, - {0x92201b4b, 0x00, "Marvell 88SE9220", AHCI_Q_ALTSIG}, - {0x92301b4b, 0x00, "Marvell 88SE9230", AHCI_Q_ALTSIG}, - {0x92351b4b, 0x00, "Marvell 88SE9235", 0}, - {0x06201103, 0x00, "HighPoint RocketRAID 620", 0}, - {0x06201b4b, 0x00, "HighPoint RocketRAID 620", 0}, - {0x06221103, 0x00, "HighPoint RocketRAID 622", 0}, - {0x06221b4b, 0x00, "HighPoint RocketRAID 622", 0}, - {0x06401103, 0x00, "HighPoint RocketRAID 640", 0}, - {0x06401b4b, 0x00, "HighPoint RocketRAID 640", 0}, - {0x06441103, 0x00, "HighPoint RocketRAID 644", 0}, - {0x06441b4b, 0x00, "HighPoint RocketRAID 644", 0}, - {0x06411103, 0x00, "HighPoint RocketRAID 640L", 0}, - {0x06421103, 0x00, "HighPoint RocketRAID 642L", 0}, - {0x06451103, 0x00, "HighPoint RocketRAID 644L", 0}, - {0x044c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x044d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x044e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x044f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x045c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x045d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x045e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x045f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, - {0x055010de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055110de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055210de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055310de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055510de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055610de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055710de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055810de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055910de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055A10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x055B10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x058410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, - {0x07f010de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f110de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f210de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f310de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f410de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f510de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f610de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f710de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f810de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07f910de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07fa10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x07fb10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, - {0x0ad010de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad110de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad210de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad310de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad410de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad510de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad610de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad710de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad810de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ad910de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ada10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0adb10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, - {0x0ab410de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0ab510de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0ab610de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0ab710de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0ab810de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0ab910de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0aba10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0abb10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0abc10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0abd10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0abe10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0abf10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, - {0x0d8410de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8510de, 0x00, "NVIDIA MCP89", AHCI_Q_NOFORCE|AHCI_Q_NOAA}, - {0x0d8610de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8710de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8810de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8910de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8a10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8b10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8c10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8d10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8e10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x0d8f10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, - {0x3781105a, 0x00, "Promise TX8660", 0}, - {0x33491106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, - {0x62871106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, - {0x11841039, 0x00, "SiS 966", 0}, - {0x11851039, 0x00, "SiS 968", 0}, - {0x01861039, 0x00, "SiS 968", 0}, - {0x00000000, 0x00, NULL, 0} -}; - #define recovery_type spriv_field0 #define RECOVERY_NONE 0 #define RECOVERY_READ_LOG 1 #define RECOVERY_REQUEST_SENSE 2 #define recovery_slot spriv_field1 -static int force_ahci = 1; -TUNABLE_INT("hw.ahci.force", &force_ahci); - -static int -ahci_probe(device_t dev) +int +ahci_ctlr_setup(device_t dev) { - char buf[64]; - int i, valid = 0; - uint32_t devid = pci_get_devid(dev); - uint8_t revid = pci_get_revid(dev); - - /* - * Ensure it is not a PCI bridge (some vendors use - * the same PID and VID in PCI bridge and AHCI cards). - */ - if (pci_get_class(dev) == PCIC_BRIDGE) - return (ENXIO); - - /* Is this a possible AHCI candidate? */ - if (pci_get_class(dev) == PCIC_STORAGE && - pci_get_subclass(dev) == PCIS_STORAGE_SATA && - pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0) - valid = 1; - /* Is this a known AHCI chip? */ - for (i = 0; ahci_ids[i].id != 0; i++) { - if (ahci_ids[i].id == devid && - ahci_ids[i].rev <= revid && - (valid || (force_ahci == 1 && - !(ahci_ids[i].quirks & AHCI_Q_NOFORCE)))) { - /* Do not attach JMicrons with single PCI function. */ - if (pci_get_vendor(dev) == 0x197b && - (pci_read_config(dev, 0xdf, 1) & 0x40) == 0) - return (ENXIO); - snprintf(buf, sizeof(buf), "%s AHCI SATA controller", - ahci_ids[i].name); - device_set_desc_copy(dev, buf); - return (BUS_PROBE_VENDOR); + struct ahci_controller *ctlr = device_get_softc(dev); + /* Clear interrupts */ + ATA_OUTL(ctlr->r_mem, AHCI_IS, ATA_INL(ctlr->r_mem, AHCI_IS)); + /* Configure CCC */ + if (ctlr->ccc) { + ATA_OUTL(ctlr->r_mem, AHCI_CCCP, ATA_INL(ctlr->r_mem, AHCI_PI)); + ATA_OUTL(ctlr->r_mem, AHCI_CCCC, + (ctlr->ccc << AHCI_CCCC_TV_SHIFT) | + (4 << AHCI_CCCC_CC_SHIFT) | + AHCI_CCCC_EN); + ctlr->cccv = (ATA_INL(ctlr->r_mem, AHCI_CCCC) & + AHCI_CCCC_INT_MASK) >> AHCI_CCCC_INT_SHIFT; + if (bootverbose) { + device_printf(dev, + "CCC with %dms/4cmd enabled on vector %d\n", + ctlr->ccc, ctlr->cccv); } } - if (!valid) - return (ENXIO); - device_set_desc_copy(dev, "AHCI SATA controller"); - return (BUS_PROBE_VENDOR); + /* Enable AHCI interrupts */ + ATA_OUTL(ctlr->r_mem, AHCI_GHC, + ATA_INL(ctlr->r_mem, AHCI_GHC) | AHCI_GHC_IE); + return (0); } -static int -ahci_ata_probe(device_t dev) +int +ahci_ctlr_reset(device_t dev) { - char buf[64]; - int i; - uint32_t devid = pci_get_devid(dev); - uint8_t revid = pci_get_revid(dev); + struct ahci_controller *ctlr = device_get_softc(dev); + int timeout; - if ((intptr_t)device_get_ivars(dev) >= 0) + /* Enable AHCI mode */ + ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE); + /* Reset AHCI controller */ + ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE|AHCI_GHC_HR); + for (timeout = 1000; timeout > 0; timeout--) { + DELAY(1000); + if ((ATA_INL(ctlr->r_mem, AHCI_GHC) & AHCI_GHC_HR) == 0) + break; + } + if (timeout == 0) { + device_printf(dev, "AHCI controller reset failure\n"); return (ENXIO); - /* Is this a known AHCI chip? */ - for (i = 0; ahci_ids[i].id != 0; i++) { - if (ahci_ids[i].id == devid && - ahci_ids[i].rev <= revid) { - snprintf(buf, sizeof(buf), "%s AHCI SATA controller", - ahci_ids[i].name); - device_set_desc_copy(dev, buf); - return (BUS_PROBE_VENDOR); - } } - device_set_desc_copy(dev, "AHCI SATA controller"); - return (BUS_PROBE_VENDOR); + /* Reenable AHCI mode */ + ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE); + return (0); } -static int + +int ahci_attach(device_t dev) { struct ahci_controller *ctlr = device_get_softc(dev); - device_t child; - int error, unit, speed, i; - u_int u; - uint32_t devid = pci_get_devid(dev); - uint8_t revid = pci_get_revid(dev); + int error, i, u, speed, unit; u_int32_t version; + device_t child; ctlr->dev = dev; - i = 0; - while (ahci_ids[i].id != 0 && - (ahci_ids[i].id != devid || - ahci_ids[i].rev > revid)) - i++; - ctlr->quirks = ahci_ids[i].quirks; + ctlr->ccc = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "ccc", &ctlr->ccc); - /* if we have a memory BAR(5) we are likely on an AHCI part */ - ctlr->r_rid = PCIR_BAR(5); - if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &ctlr->r_rid, RF_ACTIVE))) - return (ENXIO); + /* Setup our own memory management for channels. */ ctlr->sc_iomem.rm_start = rman_get_start(ctlr->r_mem); ctlr->sc_iomem.rm_end = rman_get_end(ctlr->r_mem); @@ -483,13 +178,6 @@ ahci_attach(device_t dev) rman_fini(&ctlr->sc_iomem); return (error); } - pci_enable_busmaster(dev); - /* Reset controller */ - if ((error = ahci_ctlr_reset(dev)) != 0) { - bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); - rman_fini(&ctlr->sc_iomem); - return (error); - }; /* Get the HW capabilities */ version = ATA_INL(ctlr->r_mem, AHCI_VS); ctlr->caps = ATA_INL(ctlr->r_mem, AHCI_CAP); @@ -541,13 +229,16 @@ ahci_attach(device_t dev) } ahci_ctlr_setup(dev); + /* Setup interrupts. */ if ((error = ahci_setup_interrupt(dev)) != 0) { bus_dma_tag_destroy(ctlr->dma_tag); - bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); + bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, + ctlr->r_mem); rman_fini(&ctlr->sc_iomem); return (error); } + i = 0; for (u = ctlr->ichannels; u != 0; u >>= 1) i += (u & 1); @@ -627,7 +318,7 @@ ahci_attach(device_t dev) return (0); } -static int +int ahci_detach(device_t dev) { struct ahci_controller *ctlr = device_get_softc(dev); @@ -645,7 +336,6 @@ ahci_detach(device_t dev) ctlr->irqs[i].r_irq_rid, ctlr->irqs[i].r_irq); } } - pci_release_msi(dev); bus_dma_tag_destroy(ctlr->dma_tag); /* Free memory. */ rman_fini(&ctlr->sc_iomem); @@ -654,109 +344,12 @@ ahci_detach(device_t dev) return (0); } -static int -ahci_ctlr_reset(device_t dev) -{ - struct ahci_controller *ctlr = device_get_softc(dev); - int timeout; - - if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == 0x28298086 && - (pci_read_config(dev, 0x92, 1) & 0xfe) == 0x04) - pci_write_config(dev, 0x92, 0x01, 1); - /* Enable AHCI mode */ - ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE); - /* Reset AHCI controller */ - ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE|AHCI_GHC_HR); - for (timeout = 1000; timeout > 0; timeout--) { - DELAY(1000); - if ((ATA_INL(ctlr->r_mem, AHCI_GHC) & AHCI_GHC_HR) == 0) - break; - } - if (timeout == 0) { - device_printf(dev, "AHCI controller reset failure\n"); - return (ENXIO); - } - /* Reenable AHCI mode */ - ATA_OUTL(ctlr->r_mem, AHCI_GHC, AHCI_GHC_AE); - return (0); -} - -static int -ahci_ctlr_setup(device_t dev) -{ - struct ahci_controller *ctlr = device_get_softc(dev); - /* Clear interrupts */ - ATA_OUTL(ctlr->r_mem, AHCI_IS, ATA_INL(ctlr->r_mem, AHCI_IS)); - /* Configure CCC */ - if (ctlr->ccc) { - ATA_OUTL(ctlr->r_mem, AHCI_CCCP, ATA_INL(ctlr->r_mem, AHCI_PI)); - ATA_OUTL(ctlr->r_mem, AHCI_CCCC, - (ctlr->ccc << AHCI_CCCC_TV_SHIFT) | - (4 << AHCI_CCCC_CC_SHIFT) | - AHCI_CCCC_EN); - ctlr->cccv = (ATA_INL(ctlr->r_mem, AHCI_CCCC) & - AHCI_CCCC_INT_MASK) >> AHCI_CCCC_INT_SHIFT; - if (bootverbose) { - device_printf(dev, - "CCC with %dms/4cmd enabled on vector %d\n", - ctlr->ccc, ctlr->cccv); - } - } - /* Enable AHCI interrupts */ - ATA_OUTL(ctlr->r_mem, AHCI_GHC, - ATA_INL(ctlr->r_mem, AHCI_GHC) | AHCI_GHC_IE); - return (0); -} - -static int -ahci_suspend(device_t dev) -{ - struct ahci_controller *ctlr = device_get_softc(dev); - - bus_generic_suspend(dev); - /* Disable interupts, so the state change(s) doesn't trigger */ - ATA_OUTL(ctlr->r_mem, AHCI_GHC, - ATA_INL(ctlr->r_mem, AHCI_GHC) & (~AHCI_GHC_IE)); - return (0); -} - -static int -ahci_resume(device_t dev) -{ - int res; - - if ((res = ahci_ctlr_reset(dev)) != 0) - return (res); - ahci_ctlr_setup(dev); - return (bus_generic_resume(dev)); -} - -static int +int ahci_setup_interrupt(device_t dev) { struct ahci_controller *ctlr = device_get_softc(dev); int i; - ctlr->msi = 2; - /* Process hints. */ - if (ctlr->quirks & AHCI_Q_NOMSI) - ctlr->msi = 0; - resource_int_value(device_get_name(dev), - device_get_unit(dev), "msi", &ctlr->msi); - ctlr->numirqs = 1; - if (ctlr->msi < 0) - ctlr->msi = 0; - else if (ctlr->msi == 1) - ctlr->msi = min(1, pci_msi_count(dev)); - else if (ctlr->msi > 1) { - ctlr->msi = 2; - ctlr->numirqs = pci_msi_count(dev); - } - /* Allocate MSI if needed/present. */ - if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) { - ctlr->msi = 0; - ctlr->numirqs = 1; - } /* Check for single MSI vector fallback. */ if (ctlr->numirqs > 1 && (ATA_INL(ctlr->r_mem, AHCI_GHC) & AHCI_GHC_MRSM) != 0) { @@ -775,7 +368,9 @@ ahci_setup_interrupt(device_t dev) for (i = 0; i < ctlr->numirqs; i++) { ctlr->irqs[i].ctlr = ctlr; ctlr->irqs[i].r_irq_rid = i + (ctlr->msi ? 1 : 0); - if (ctlr->numirqs == 1 || i >= ctlr->channels || + if (ctlr->channels == 1 && !ctlr->ccc && ctlr->msi) + ctlr->irqs[i].mode = AHCI_IRQ_MODE_ONE; + else if (ctlr->numirqs == 1 || i >= ctlr->channels || (ctlr->ccc && i == ctlr->cccv)) ctlr->irqs[i].mode = AHCI_IRQ_MODE_ALL; else if (i == ctlr->numirqs - 1) @@ -880,9 +475,9 @@ ahci_intr_one_edge(void *data) ctlr->interrupt[unit].function(arg); } -static struct resource * +struct resource * ahci_alloc_resource(device_t dev, device_t child, int type, int *rid, - u_long start, u_long end, u_long count, u_int flags) + u_long start, u_long end, u_long count, u_int flags) { struct ahci_controller *ctlr = device_get_softc(dev); struct resource *res; @@ -931,9 +526,9 @@ ahci_alloc_resource(device_t dev, device_t child, int type, int *rid, return (res); } -static int +int ahci_release_resource(device_t dev, device_t child, int type, int rid, - struct resource *r) + struct resource *r) { switch (type) { @@ -948,10 +543,10 @@ ahci_release_resource(device_t dev, device_t child, int type, int rid, return (EINVAL); } -static int +int ahci_setup_intr(device_t dev, device_t child, struct resource *irq, - int flags, driver_filter_t *filter, driver_intr_t *function, - void *argument, void **cookiep) + int flags, driver_filter_t *filter, driver_intr_t *function, + void *argument, void **cookiep) { struct ahci_controller *ctlr = device_get_softc(dev); int unit = (intptr_t)device_get_ivars(child); @@ -965,9 +560,9 @@ ahci_setup_intr(device_t dev, device_t child, struct resource *irq, return (0); } -static int +int ahci_teardown_intr(device_t dev, device_t child, struct resource *irq, - void *cookie) + void *cookie) { struct ahci_controller *ctlr = device_get_softc(dev); int unit = (intptr_t)device_get_ivars(child); @@ -977,7 +572,7 @@ ahci_teardown_intr(device_t dev, device_t child, struct resource *irq, return (0); } -static int +int ahci_print_child(device_t dev, device_t child) { int retval, channel; @@ -990,7 +585,7 @@ ahci_print_child(device_t dev, device_t child) return (retval); } -static int +int ahci_child_location_str(device_t dev, device_t child, char *buf, size_t buflen) { @@ -1002,7 +597,7 @@ ahci_child_location_str(device_t dev, device_t child, char *buf, return (0); } -static bus_dma_tag_t +bus_dma_tag_t ahci_get_dma_tag(device_t dev, device_t child) { struct ahci_controller *ctlr = device_get_softc(dev); @@ -1010,51 +605,6 @@ ahci_get_dma_tag(device_t dev, device_t child) return (ctlr->dma_tag); } -devclass_t ahci_devclass; -static device_method_t ahci_methods[] = { - DEVMETHOD(device_probe, ahci_probe), - DEVMETHOD(device_attach, ahci_attach), - DEVMETHOD(device_detach, ahci_detach), - DEVMETHOD(device_suspend, ahci_suspend), - DEVMETHOD(device_resume, ahci_resume), - DEVMETHOD(bus_print_child, ahci_print_child), - DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), - DEVMETHOD(bus_release_resource, ahci_release_resource), - DEVMETHOD(bus_setup_intr, ahci_setup_intr), - DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), - DEVMETHOD(bus_child_location_str, ahci_child_location_str), - DEVMETHOD(bus_get_dma_tag, ahci_get_dma_tag), - DEVMETHOD_END -}; -static driver_t ahci_driver = { - "ahci", - ahci_methods, - sizeof(struct ahci_controller) -}; -DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, NULL, NULL); -static device_method_t ahci_ata_methods[] = { - DEVMETHOD(device_probe, ahci_ata_probe), - DEVMETHOD(device_attach, ahci_attach), - DEVMETHOD(device_detach, ahci_detach), - DEVMETHOD(device_suspend, ahci_suspend), - DEVMETHOD(device_resume, ahci_resume), - DEVMETHOD(bus_print_child, ahci_print_child), - DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), - DEVMETHOD(bus_release_resource, ahci_release_resource), - DEVMETHOD(bus_setup_intr, ahci_setup_intr), - DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), - DEVMETHOD(bus_child_location_str, ahci_child_location_str), - DEVMETHOD_END -}; -static driver_t ahci_ata_driver = { - "ahci", - ahci_ata_methods, - sizeof(struct ahci_controller) -}; -DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, NULL, NULL); -MODULE_VERSION(ahci, 1); -MODULE_DEPEND(ahci, cam, 1, 1, 1); - static int ahci_ch_probe(device_t dev) { @@ -1077,20 +627,21 @@ ahci_ch_attach(device_t dev) ch->caps = ctlr->caps; ch->caps2 = ctlr->caps2; ch->quirks = ctlr->quirks; + ch->vendorid = ctlr->vendorid; + ch->deviceid = ctlr->deviceid; + ch->subvendorid = ctlr->subvendorid; + ch->subdeviceid = ctlr->subdeviceid; ch->numslots = ((ch->caps & AHCI_CAP_NCS) >> AHCI_CAP_NCS_SHIFT) + 1; mtx_init(&ch->mtx, "AHCI channel lock", NULL, MTX_DEF); + ch->pm_level = 0; resource_int_value(device_get_name(dev), device_get_unit(dev), "pm_level", &ch->pm_level); STAILQ_INIT(&ch->doneq); if (ch->pm_level > 3) callout_init_mtx(&ch->pm_timer, &ch->mtx, 0); callout_init_mtx(&ch->reset_timer, &ch->mtx, 0); - /* Limit speed for my onboard JMicron external port. - * It is not eSATA really. */ - if (pci_get_devid(ctlr->dev) == 0x2363197b && - pci_get_subvendor(ctlr->dev) == 0x1043 && - pci_get_subdevice(ctlr->dev) == 0x81e4 && - ch->unit == 0) + /* JMicron external ports (0) sometimes limited */ + if ((ctlr->quirks & AHCI_Q_SATA1_UNIT0) && ch->unit == 0) sata_rev = 1; if (ch->quirks & AHCI_Q_SATA2) sata_rev = 2; @@ -1117,8 +668,8 @@ ahci_ch_attach(device_t dev) return (ENXIO); ahci_dmainit(dev); ahci_slotsalloc(dev); - ahci_ch_init(dev); mtx_lock(&ch->mtx); + ahci_ch_init(dev); rid = ATA_IRQ_RID; if (!(ch->r_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE))) { @@ -1128,7 +679,7 @@ ahci_ch_attach(device_t dev) } if ((bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS, NULL, ctlr->direct ? ahci_ch_intr_direct : ahci_ch_intr, - dev, &ch->ih))) { + ch, &ch->ih))) { device_printf(dev, "Unable to setup interrupt\n"); error = ENXIO; goto err1; @@ -1157,7 +708,7 @@ ahci_ch_attach(device_t dev) } /* Construct SIM entry */ ch->sim = cam_sim_alloc(ahciaction, ahcipoll, "ahcich", ch, - device_get_unit(dev), &ch->mtx, + device_get_unit(dev), (struct mtx *)&ch->mtx, min(2, ch->numslots), (ch->caps & AHCI_CAP_SNCQ) ? ch->numslots : 0, devq); @@ -1181,7 +732,7 @@ ahci_ch_attach(device_t dev) if (ch->pm_level > 3) { callout_reset(&ch->pm_timer, (ch->pm_level == 4) ? hz / 1000 : hz / 8, - ahci_ch_pm, dev); + ahci_ch_pm, ch); } mtx_unlock(&ch->mtx); return (0); @@ -1251,8 +802,8 @@ ahci_ch_init(device_t dev) (AHCI_P_CMD_ACTIVE | AHCI_P_CMD_POD | AHCI_P_CMD_SUD | ((ch->pm_level == 2 || ch->pm_level == 3) ? AHCI_P_CMD_ALPE : 0) | ((ch->pm_level > 2) ? AHCI_P_CMD_ASP : 0 ))); - ahci_start_fr(dev); - ahci_start(dev, 1); + ahci_start_fr(ch); + ahci_start(ch, 1); return (0); } @@ -1264,8 +815,8 @@ ahci_ch_deinit(device_t dev) /* Disable port interrupts. */ ATA_OUTL(ch->r_mem, AHCI_P_IE, 0); /* Reset command register. */ - ahci_stop(dev); - ahci_stop_fr(dev); + ahci_stop(ch); + ahci_stop_fr(ch); ATA_OUTL(ch->r_mem, AHCI_P_CMD, 0); /* Allow everything, including partial and slumber modes. */ ATA_OUTL(ch->r_mem, AHCI_P_SCTL, 0); @@ -1304,7 +855,7 @@ ahci_ch_resume(device_t dev) mtx_lock(&ch->mtx); ahci_ch_init(dev); - ahci_reset(dev); + ahci_reset(ch); xpt_release_simq(ch->sim, TRUE); mtx_unlock(&ch->mtx); return (0); @@ -1410,14 +961,12 @@ ahci_dmafini(device_t dev) bus_dmamap_unload(ch->dma.rfis_tag, ch->dma.rfis_map); bus_dmamem_free(ch->dma.rfis_tag, ch->dma.rfis, ch->dma.rfis_map); ch->dma.rfis_bus = 0; - ch->dma.rfis_map = NULL; ch->dma.rfis = NULL; } if (ch->dma.work_bus) { bus_dmamap_unload(ch->dma.work_tag, ch->dma.work_map); bus_dmamem_free(ch->dma.work_tag, ch->dma.work, ch->dma.work_map); ch->dma.work_bus = 0; - ch->dma.work_map = NULL; ch->dma.work = NULL; } if (ch->dma.work_tag) { @@ -1437,7 +986,7 @@ ahci_slotsalloc(device_t dev) for (i = 0; i < ch->numslots; i++) { struct ahci_slot *slot = &ch->slot[i]; - slot->dev = dev; + slot->ch = ch; slot->slot = i; slot->state = AHCI_SLOT_EMPTY; slot->ccb = NULL; @@ -1467,9 +1016,8 @@ ahci_slotsfree(device_t dev) } static int -ahci_phy_check_events(device_t dev, u_int32_t serr) +ahci_phy_check_events(struct ahci_channel *ch, u_int32_t serr) { - struct ahci_channel *ch = device_get_softc(dev); if (((ch->pm_level == 0) && (serr & ATA_SE_PHY_CHANGED)) || ((ch->pm_level != 0 || ch->listening) && (serr & ATA_SE_EXCHANGED))) { @@ -1478,11 +1026,11 @@ ahci_phy_check_events(device_t dev, u_int32_t serr) if (bootverbose) { if ((status & ATA_SS_DET_MASK) != ATA_SS_DET_NO_DEVICE) - device_printf(dev, "CONNECT requested\n"); + device_printf(ch->dev, "CONNECT requested\n"); else - device_printf(dev, "DISCONNECT requested\n"); + device_printf(ch->dev, "DISCONNECT requested\n"); } - ahci_reset(dev); + ahci_reset(ch); if ((ccb = xpt_alloc_ccb_nowait()) == NULL) return (0); if (xpt_create_path(&ccb->ccb_h.path, NULL, @@ -1498,11 +1046,11 @@ ahci_phy_check_events(device_t dev, u_int32_t serr) } static void -ahci_cpd_check_events(device_t dev) +ahci_cpd_check_events(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t status; union ccb *ccb; + device_t dev; if (ch->pm_level == 0) return; @@ -1512,12 +1060,13 @@ ahci_cpd_check_events(device_t dev) return; if (bootverbose) { + dev = ch->dev; if (status & AHCI_P_CMD_CPS) { device_printf(dev, "COLD CONNECT requested\n"); } else device_printf(dev, "COLD DISCONNECT requested\n"); } - ahci_reset(dev); + ahci_reset(ch); if ((ccb = xpt_alloc_ccb_nowait()) == NULL) return; if (xpt_create_path(&ccb->ccb_h.path, NULL, cam_sim_path(ch->sim), @@ -1529,16 +1078,15 @@ ahci_cpd_check_events(device_t dev) } static void -ahci_notify_events(device_t dev, u_int32_t status) +ahci_notify_events(struct ahci_channel *ch, u_int32_t status) { - struct ahci_channel *ch = device_get_softc(dev); struct cam_path *dpath; int i; if (ch->caps & AHCI_CAP_SSNTF) ATA_OUTL(ch->r_mem, AHCI_P_SNTF, status); if (bootverbose) - device_printf(dev, "SNTF 0x%04x\n", status); + device_printf(ch->dev, "SNTF 0x%04x\n", status); for (i = 0; i < 16; i++) { if ((status & (1 << i)) == 0) continue; @@ -1567,8 +1115,7 @@ ahci_done(struct ahci_channel *ch, union ccb *ccb) static void ahci_ch_intr(void *arg) { - device_t dev = (device_t)arg; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = (struct ahci_channel *)arg; uint32_t istatus; /* Read interrupt statuses. */ @@ -1584,8 +1131,7 @@ ahci_ch_intr(void *arg) static void ahci_ch_intr_direct(void *arg) { - device_t dev = (device_t)arg; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = (struct ahci_channel *)arg; struct ccb_hdr *ccb_h; uint32_t istatus; STAILQ_HEAD(, ccb_hdr) tmp_doneq = STAILQ_HEAD_INITIALIZER(tmp_doneq); @@ -1614,8 +1160,7 @@ ahci_ch_intr_direct(void *arg) static void ahci_ch_pm(void *arg) { - device_t dev = (device_t)arg; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = (struct ahci_channel *)arg; uint32_t work; if (ch->numrslots != 0) @@ -1631,7 +1176,6 @@ ahci_ch_pm(void *arg) static void ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus) { - device_t dev = ch->dev; uint32_t cstatus, serr = 0, sntf = 0, ok, err; enum ahci_err_type et; int i, ccs, port, reset = 0; @@ -1673,12 +1217,12 @@ ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus) serr = ATA_INL(ch->r_mem, AHCI_P_SERR); if (serr) { ATA_OUTL(ch->r_mem, AHCI_P_SERR, serr); - reset = ahci_phy_check_events(dev, serr); + reset = ahci_phy_check_events(ch, serr); } } /* Process cold presence detection events */ if ((istatus & AHCI_P_IX_CPD) && !reset) - ahci_cpd_check_events(dev); + ahci_cpd_check_events(ch); /* Process command errors */ if (istatus & (AHCI_P_IX_OF | AHCI_P_IX_IF | AHCI_P_IX_HBD | AHCI_P_IX_HBF | AHCI_P_IX_TFE)) { @@ -1773,14 +1317,13 @@ ahci_ch_intr_main(struct ahci_channel *ch, uint32_t istatus) } /* Process NOTIFY events */ if (sntf) - ahci_notify_events(dev, sntf); + ahci_notify_events(ch, sntf); } /* Must be called with channel locked. */ static int -ahci_check_collision(device_t dev, union ccb *ccb) +ahci_check_collision(struct ahci_channel *ch, union ccb *ccb) { - struct ahci_channel *ch = device_get_softc(dev); int t = ccb->ccb_h.target_id; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && @@ -1829,9 +1372,8 @@ ahci_check_collision(device_t dev, union ccb *ccb) /* Must be called with channel locked. */ static void -ahci_begin_transaction(device_t dev, union ccb *ccb) +ahci_begin_transaction(struct ahci_channel *ch, union ccb *ccb) { - struct ahci_channel *ch = device_get_softc(dev); struct ahci_slot *slot; int tag, tags; @@ -1840,14 +1382,14 @@ ahci_begin_transaction(device_t dev, union ccb *ccb) if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & CAM_ATAIO_FPDMA)) tags = ch->curr[ccb->ccb_h.target_id].tags; - tag = ch->lastslot; - while (1) { - if (tag >= tags) - tag = 0; - if (ch->slot[tag].state == AHCI_SLOT_EMPTY) - break; - tag++; - }; + if (ch->lastslot + 1 < tags) + tag = ffs(~(ch->oslots >> (ch->lastslot + 1))); + else + tag = 0; + if (tag == 0 || tag + ch->lastslot >= tags) + tag = ffs(~ch->oslots) - 1; + else + tag += ch->lastslot; ch->lastslot = tag; /* Occupy chosen slot. */ slot = &ch->slot[tag]; @@ -1856,7 +1398,7 @@ ahci_begin_transaction(device_t dev, union ccb *ccb) if (ch->numrslots == 0 && ch->pm_level > 3) callout_stop(&ch->pm_timer); /* Update channel stats. */ - ch->oslots |= (1 << slot->slot); + ch->oslots |= (1 << tag); ch->numrslots++; ch->numrslotspd[ccb->ccb_h.target_id]++; if ((ccb->ccb_h.func_code == XPT_ATA_IO) && @@ -1867,14 +1409,15 @@ ahci_begin_transaction(device_t dev, union ccb *ccb) } if ((ccb->ccb_h.func_code == XPT_ATA_IO) && (ccb->ataio.cmd.flags & (CAM_ATAIO_CONTROL | CAM_ATAIO_NEEDRESULT))) - ch->aslots |= (1 << slot->slot); - slot->dma.nsegs = 0; + ch->aslots |= (1 << tag); if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) { slot->state = AHCI_SLOT_LOADING; bus_dmamap_load_ccb(ch->dma.data_tag, slot->dma.data_map, ccb, ahci_dmasetprd, slot, 0); - } else + } else { + slot->dma.nsegs = 0; ahci_execute_transaction(slot); + } } /* Locked by busdma engine. */ @@ -1882,13 +1425,13 @@ static void ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error) { struct ahci_slot *slot = arg; - struct ahci_channel *ch = device_get_softc(slot->dev); + struct ahci_channel *ch = slot->ch; struct ahci_cmd_tab *ctp; struct ahci_dma_prd *prd; int i; if (error) { - device_printf(slot->dev, "DMA load error\n"); + device_printf(ch->dev, "DMA load error\n"); ahci_end_transaction(slot, AHCI_ERR_INVALID); return; } @@ -1913,8 +1456,7 @@ ahci_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error) static void ahci_execute_transaction(struct ahci_slot *slot) { - device_t dev = slot->dev; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = slot->ch; struct ahci_cmd_tab *ctp; struct ahci_cmd_list *clp; union ccb *ccb = slot->ccb; @@ -1927,7 +1469,7 @@ ahci_execute_transaction(struct ahci_slot *slot) ctp = (struct ahci_cmd_tab *) (ch->dma.work + AHCI_CT_OFFSET + (AHCI_CT_SIZE * slot->slot)); /* Setup the FIS for this request */ - if (!(fis_size = ahci_setup_fis(dev, ctp, ccb, slot->slot))) { + if (!(fis_size = ahci_setup_fis(ch, ctp, ccb, slot->slot))) { device_printf(ch->dev, "Setting up SATA FIS failed\n"); ahci_end_transaction(slot, AHCI_ERR_INVALID); return; @@ -1948,9 +1490,9 @@ ahci_execute_transaction(struct ahci_slot *slot) if (ccb->ataio.cmd.control & ATA_A_RESET) { softreset = 1; /* Kick controller into sane state */ - ahci_stop(dev); - ahci_clo(dev); - ahci_start(dev, 0); + ahci_stop(ch); + ahci_clo(ch); + ahci_start(ch, 0); clp->cmd_flags |= AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY; } else { softreset = 2; @@ -2003,7 +1545,7 @@ ahci_execute_transaction(struct ahci_slot *slot) } /* Workaround for ATI SB600/SB700 chipsets. */ if (ccb->ccb_h.target_id == 15 && - pci_get_vendor(device_get_parent(dev)) == 0x1002 && + (ch->quirks & AHCI_Q_ATI_PMP_BUG) && (ATA_INL(ch->r_mem, AHCI_P_IS) & AHCI_P_IX_IPM)) { et = AHCI_ERR_TIMEOUT; break; @@ -2018,6 +1560,7 @@ ahci_execute_transaction(struct ahci_slot *slot) * this wait. */ if ((ch->quirks & AHCI_Q_NOBSYRES) == 0 && + (ch->quirks & AHCI_Q_ATI_PMP_BUG) == 0 && softreset == 2 && et == AHCI_ERR_NONE) { while ((val = fis[2]) & ATA_S_BUSY) { DELAY(10); @@ -2027,9 +1570,9 @@ ahci_execute_transaction(struct ahci_slot *slot) } if (timeout && (count >= timeout)) { - device_printf(dev, "Poll timeout on slot %d port %d\n", + device_printf(ch->dev, "Poll timeout on slot %d port %d\n", slot->slot, port); - device_printf(dev, "is %08x cs %08x ss %08x " + device_printf(ch->dev, "is %08x cs %08x ss %08x " "rs %08x tfd %02x serr %08x cmd %08x\n", ATA_INL(ch->r_mem, AHCI_P_IS), ATA_INL(ch->r_mem, AHCI_P_CI), @@ -2054,9 +1597,8 @@ ahci_execute_transaction(struct ahci_slot *slot) /* Must be called with channel locked. */ static void -ahci_process_timeout(device_t dev) +ahci_process_timeout(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); int i; mtx_assert(&ch->mtx, MA_OWNED); @@ -2071,9 +1613,8 @@ ahci_process_timeout(device_t dev) /* Must be called with channel locked. */ static void -ahci_rearm_timeout(device_t dev) +ahci_rearm_timeout(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); int i; mtx_assert(&ch->mtx, MA_OWNED); @@ -2095,8 +1636,8 @@ ahci_rearm_timeout(device_t dev) static void ahci_timeout(struct ahci_slot *slot) { - device_t dev = slot->dev; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = slot->ch; + device_t dev = ch->dev; uint32_t sstatus; int ccs; int i; @@ -2163,7 +1704,7 @@ ahci_timeout(struct ahci_slot *slot) xpt_freeze_simq(ch->sim, 1); ch->toslots |= (1 << slot->slot); if ((ch->rslots & ~ch->toslots) == 0) - ahci_process_timeout(dev); + ahci_process_timeout(ch); else device_printf(dev, " ... waiting for slots %08x\n", ch->rslots & ~ch->toslots); @@ -2174,8 +1715,7 @@ ahci_timeout(struct ahci_slot *slot) static void ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) { - device_t dev = slot->dev; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = slot->ch; union ccb *ccb = slot->ccb; struct ahci_cmd_list *clp; int lastto; @@ -2333,15 +1873,15 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) (ccb->ataio.cmd.control & ATA_A_RESET) && et == AHCI_ERR_NONE) { ccb->ataio.cmd.control &= ~ATA_A_RESET; - ahci_begin_transaction(dev, ccb); + ahci_begin_transaction(ch, ccb); return; } /* If it was our READ LOG command - process it. */ if (ccb->ccb_h.recovery_type == RECOVERY_READ_LOG) { - ahci_process_read_log(dev, ccb); + ahci_process_read_log(ch, ccb); /* If it was our REQUEST SENSE command - process it. */ } else if (ccb->ccb_h.recovery_type == RECOVERY_REQUEST_SENSE) { - ahci_process_request_sense(dev, ccb); + ahci_process_request_sense(ch, ccb); /* If it was NCQ or ATAPI command error, put result on hold. */ } else if (et == AHCI_ERR_NCQ || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR && @@ -2354,27 +1894,27 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) if (ch->rslots == 0) { /* if there was fatal error - reset port. */ if (ch->toslots != 0 || ch->fatalerr) { - ahci_reset(dev); + ahci_reset(ch); } else { /* if we have slots in error, we can reinit port. */ if (ch->eslots != 0) { - ahci_stop(dev); - ahci_clo(dev); - ahci_start(dev, 1); + ahci_stop(ch); + ahci_clo(ch); + ahci_start(ch, 1); } /* if there commands on hold, we can do READ LOG. */ if (!ch->recoverycmd && ch->numhslots) - ahci_issue_recovery(dev); + ahci_issue_recovery(ch); } /* If all the rest of commands are in timeout - give them chance. */ } else if ((ch->rslots & ~ch->toslots) == 0 && et != AHCI_ERR_TIMEOUT) - ahci_rearm_timeout(dev); + ahci_rearm_timeout(ch); /* Unfreeze frozen command. */ - if (ch->frozen && !ahci_check_collision(dev, ch->frozen)) { + if (ch->frozen && !ahci_check_collision(ch, ch->frozen)) { union ccb *fccb = ch->frozen; ch->frozen = NULL; - ahci_begin_transaction(dev, fccb); + ahci_begin_transaction(ch, fccb); xpt_release_simq(ch->sim, TRUE); } /* Start PM timer. */ @@ -2386,9 +1926,8 @@ ahci_end_transaction(struct ahci_slot *slot, enum ahci_err_type et) } static void -ahci_issue_recovery(device_t dev) +ahci_issue_recovery(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); union ccb *ccb; struct ccb_ataio *ataio; struct ccb_scsiio *csio; @@ -2401,7 +1940,7 @@ ahci_issue_recovery(device_t dev) } ccb = xpt_alloc_ccb_nowait(); if (ccb == NULL) { - device_printf(dev, "Unable to allocate recovery command\n"); + device_printf(ch->dev, "Unable to allocate recovery command\n"); completeall: /* We can't do anything -- complete held commands. */ for (i = 0; i < ch->numslots; i++) { @@ -2413,7 +1952,7 @@ completeall: ch->hold[i] = NULL; ch->numhslots--; } - ahci_reset(dev); + ahci_reset(ch); return; } ccb->ccb_h = ch->hold[i]->ccb_h; /* Reuse old header. */ @@ -2427,7 +1966,7 @@ completeall: ataio->data_ptr = malloc(512, M_AHCI, M_NOWAIT); if (ataio->data_ptr == NULL) { xpt_free_ccb(ccb); - device_printf(dev, + device_printf(ch->dev, "Unable to allocate memory for READ LOG command\n"); goto completeall; } @@ -2459,13 +1998,12 @@ completeall: /* Freeze SIM while doing recovery. */ ch->recoverycmd = 1; xpt_freeze_simq(ch->sim, 1); - ahci_begin_transaction(dev, ccb); + ahci_begin_transaction(ch, ccb); } static void -ahci_process_read_log(device_t dev, union ccb *ccb) +ahci_process_read_log(struct ahci_channel *ch, union ccb *ccb) { - struct ahci_channel *ch = device_get_softc(dev); uint8_t *data; struct ata_res *res; int i; @@ -2503,9 +2041,9 @@ ahci_process_read_log(device_t dev, union ccb *ccb) } } else { if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) - device_printf(dev, "Error while READ LOG EXT\n"); + device_printf(ch->dev, "Error while READ LOG EXT\n"); else if ((data[0] & 0x80) == 0) { - device_printf(dev, "Non-queued command error in READ LOG EXT\n"); + device_printf(ch->dev, "Non-queued command error in READ LOG EXT\n"); } for (i = 0; i < ch->numslots; i++) { if (!ch->hold[i]) @@ -2523,9 +2061,8 @@ ahci_process_read_log(device_t dev, union ccb *ccb) } static void -ahci_process_request_sense(device_t dev, union ccb *ccb) +ahci_process_request_sense(struct ahci_channel *ch, union ccb *ccb) { - struct ahci_channel *ch = device_get_softc(dev); int i; ch->recoverycmd = 0; @@ -2545,9 +2082,8 @@ ahci_process_request_sense(device_t dev, union ccb *ccb) } static void -ahci_start(device_t dev, int fbs) +ahci_start(struct ahci_channel *ch, int fbs) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; /* Clear SATA error register */ @@ -2568,9 +2104,8 @@ ahci_start(device_t dev, int fbs) } static void -ahci_stop(device_t dev) +ahci_stop(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; int timeout; @@ -2582,7 +2117,7 @@ ahci_stop(device_t dev) do { DELAY(10); if (timeout++ > 50000) { - device_printf(dev, "stopping AHCI engine failed\n"); + device_printf(ch->dev, "stopping AHCI engine failed\n"); break; } } while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CR); @@ -2590,9 +2125,8 @@ ahci_stop(device_t dev) } static void -ahci_clo(device_t dev) +ahci_clo(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; int timeout; @@ -2605,7 +2139,7 @@ ahci_clo(device_t dev) do { DELAY(10); if (timeout++ > 50000) { - device_printf(dev, "executing CLO failed\n"); + device_printf(ch->dev, "executing CLO failed\n"); break; } } while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_CLO); @@ -2613,9 +2147,8 @@ ahci_clo(device_t dev) } static void -ahci_stop_fr(device_t dev) +ahci_stop_fr(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; int timeout; @@ -2627,16 +2160,15 @@ ahci_stop_fr(device_t dev) do { DELAY(10); if (timeout++ > 50000) { - device_printf(dev, "stopping AHCI FR engine failed\n"); + device_printf(ch->dev, "stopping AHCI FR engine failed\n"); break; } } while (ATA_INL(ch->r_mem, AHCI_P_CMD) & AHCI_P_CMD_FR); } static void -ahci_start_fr(device_t dev) +ahci_start_fr(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); u_int32_t cmd; /* Start FIS reception on this channel */ @@ -2645,9 +2177,8 @@ ahci_start_fr(device_t dev) } static int -ahci_wait_ready(device_t dev, int t, int t0) +ahci_wait_ready(struct ahci_channel *ch, int t, int t0) { - struct ahci_channel *ch = device_get_softc(dev); int timeout = 0; uint32_t val; @@ -2655,7 +2186,7 @@ ahci_wait_ready(device_t dev, int t, int t0) (ATA_S_BUSY | ATA_S_DRQ)) { if (timeout > t) { if (t != 0) { - device_printf(dev, + device_printf(ch->dev, "AHCI reset: device not ready after %dms " "(tfd = %08x)\n", MAX(t, 0) + t0, val); @@ -2666,7 +2197,7 @@ ahci_wait_ready(device_t dev, int t, int t0) timeout++; } if (bootverbose) - device_printf(dev, "AHCI reset: device ready after %dms\n", + device_printf(ch->dev, "AHCI reset: device ready after %dms\n", timeout + t0); return (0); } @@ -2674,22 +2205,21 @@ ahci_wait_ready(device_t dev, int t, int t0) static void ahci_reset_to(void *arg) { - device_t dev = arg; - struct ahci_channel *ch = device_get_softc(dev); + struct ahci_channel *ch = arg; if (ch->resetting == 0) return; ch->resetting--; - if (ahci_wait_ready(dev, ch->resetting == 0 ? -1 : 0, + if (ahci_wait_ready(ch, ch->resetting == 0 ? -1 : 0, (310 - ch->resetting) * 100) == 0) { ch->resetting = 0; - ahci_start(dev, 1); + ahci_start(ch, 1); xpt_release_simq(ch->sim, TRUE); return; } if (ch->resetting == 0) { - ahci_clo(dev); - ahci_start(dev, 1); + ahci_clo(ch); + ahci_start(ch, 1); xpt_release_simq(ch->sim, TRUE); return; } @@ -2697,15 +2227,14 @@ ahci_reset_to(void *arg) } static void -ahci_reset(device_t dev) +ahci_reset(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); - struct ahci_controller *ctlr = device_get_softc(device_get_parent(dev)); + struct ahci_controller *ctlr = device_get_softc(device_get_parent(ch->dev)); int i; xpt_freeze_simq(ch->sim, 1); if (bootverbose) - device_printf(dev, "AHCI reset...\n"); + device_printf(ch->dev, "AHCI reset...\n"); /* Forget about previous reset. */ if (ch->resetting) { ch->resetting = 0; @@ -2724,7 +2253,7 @@ ahci_reset(device_t dev) ahci_done(ch, fccb); } /* Kill the engine and requeue all running commands. */ - ahci_stop(dev); + ahci_stop(ch); for (i = 0; i < ch->numslots; i++) { /* Do we have a running request on slot? */ if (ch->slot[i].state < AHCI_SLOT_RUNNING) @@ -2750,9 +2279,9 @@ ahci_reset(device_t dev) /* Disable port interrupts */ ATA_OUTL(ch->r_mem, AHCI_P_IE, 0); /* Reset and reconnect PHY, */ - if (!ahci_sata_phy_reset(dev)) { + if (!ahci_sata_phy_reset(ch)) { if (bootverbose) - device_printf(dev, + device_printf(ch->dev, "AHCI reset: device not found\n"); ch->devices = 0; /* Enable wanted port interrupts */ @@ -2763,11 +2292,11 @@ ahci_reset(device_t dev) return; } if (bootverbose) - device_printf(dev, "AHCI reset: device found\n"); + device_printf(ch->dev, "AHCI reset: device found\n"); /* Wait for clearing busy status. */ - if (ahci_wait_ready(dev, dumping ? 31000 : 0, 0)) { + if (ahci_wait_ready(ch, dumping ? 31000 : 0, 0)) { if (dumping) - ahci_clo(dev); + ahci_clo(ch); else ch->resetting = 310; } @@ -2781,17 +2310,16 @@ ahci_reset(device_t dev) AHCI_P_IX_DP | AHCI_P_IX_UF | (ctlr->ccc ? 0 : AHCI_P_IX_SDB) | AHCI_P_IX_DS | AHCI_P_IX_PS | (ctlr->ccc ? 0 : AHCI_P_IX_DHR))); if (ch->resetting) - callout_reset(&ch->reset_timer, hz / 10, ahci_reset_to, dev); + callout_reset(&ch->reset_timer, hz / 10, ahci_reset_to, ch); else { - ahci_start(dev, 1); + ahci_start(ch, 1); xpt_release_simq(ch->sim, TRUE); } } static int -ahci_setup_fis(device_t dev, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag) +ahci_setup_fis(struct ahci_channel *ch, struct ahci_cmd_tab *ctp, union ccb *ccb, int tag) { - struct ahci_channel *ch = device_get_softc(dev); u_int8_t *fis = &ctp->cfis[0]; bzero(fis, 20); @@ -2883,9 +2411,8 @@ ahci_sata_connect(struct ahci_channel *ch) } static int -ahci_sata_phy_reset(device_t dev) +ahci_sata_phy_reset(struct ahci_channel *ch) { - struct ahci_channel *ch = device_get_softc(dev); int sata_rev; uint32_t val; @@ -2925,9 +2452,8 @@ ahci_sata_phy_reset(device_t dev) } static int -ahci_check_ids(device_t dev, union ccb *ccb) +ahci_check_ids(struct ahci_channel *ch, union ccb *ccb) { - struct ahci_channel *ch = device_get_softc(dev); if (ccb->ccb_h.target_id > ((ch->caps & AHCI_CAP_SPM) ? 15 : 0)) { ccb->ccb_h.status = CAM_TID_INVALID; @@ -2945,19 +2471,17 @@ ahci_check_ids(device_t dev, union ccb *ccb) static void ahciaction(struct cam_sim *sim, union ccb *ccb) { - device_t dev, parent; struct ahci_channel *ch; CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahciaction func_code=%x\n", ccb->ccb_h.func_code)); ch = (struct ahci_channel *)cam_sim_softc(sim); - dev = ch->dev; switch (ccb->ccb_h.func_code) { /* Common cases first */ case XPT_ATA_IO: /* Execute the requested I/O operation */ case XPT_SCSI_IO: - if (ahci_check_ids(dev, ccb)) + if (ahci_check_ids(ch, ccb)) return; if (ch->devices == 0 || (ch->pm_present == 0 && @@ -2967,14 +2491,14 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) } ccb->ccb_h.recovery_type = RECOVERY_NONE; /* Check for command collision. */ - if (ahci_check_collision(dev, ccb)) { + if (ahci_check_collision(ch, ccb)) { /* Freeze command. */ ch->frozen = ccb; /* We have only one frozen slot, so freeze simq also. */ xpt_freeze_simq(ch->sim, 1); return; } - ahci_begin_transaction(dev, ccb); + ahci_begin_transaction(ch, ccb); return; case XPT_EN_LUN: /* Enable LUN as a target */ case XPT_TARGET_IO: /* Execute target I/O request */ @@ -2989,7 +2513,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) struct ccb_trans_settings *cts = &ccb->cts; struct ahci_device *d; - if (ahci_check_ids(dev, ccb)) + if (ahci_check_ids(ch, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; @@ -3019,7 +2543,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) struct ahci_device *d; uint32_t status; - if (ahci_check_ids(dev, ccb)) + if (ahci_check_ids(ch, ccb)) return; if (cts->type == CTS_TYPE_CURRENT_SETTINGS) d = &ch->curr[ccb->ccb_h.target_id]; @@ -3076,7 +2600,7 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) } case XPT_RESET_BUS: /* Reset the specified SCSI bus */ case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */ - ahci_reset(dev); + ahci_reset(ch); ccb->ccb_h.status = CAM_REQ_CMP; break; case XPT_TERM_IO: /* Terminate the I/O process */ @@ -3087,7 +2611,6 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) { struct ccb_pathinq *cpi = &ccb->cpi; - parent = device_get_parent(dev); cpi->version_num = 1; /* XXX??? */ cpi->hba_inquiry = PI_SDTR_ABLE; if (ch->caps & AHCI_CAP_SNCQ) @@ -3115,12 +2638,12 @@ ahciaction(struct cam_sim *sim, union ccb *ccb) cpi->protocol_version = PROTO_VERSION_UNSPECIFIED; cpi->maxio = MAXPHYS; /* ATI SB600 can't handle 256 sectors with FPDMA (NCQ). */ - if (pci_get_devid(parent) == 0x43801002) + if (ch->quirks & AHCI_Q_MAXIO_64K) cpi->maxio = min(cpi->maxio, 128 * 512); - cpi->hba_vendor = pci_get_vendor(parent); - cpi->hba_device = pci_get_device(parent); - cpi->hba_subvendor = pci_get_subvendor(parent); - cpi->hba_subdevice = pci_get_subdevice(parent); + cpi->hba_vendor = ch->vendorid; + cpi->hba_device = ch->deviceid; + cpi->hba_subvendor = ch->subvendorid; + cpi->hba_subdevice = ch->subdeviceid; cpi->ccb_h.status = CAM_REQ_CMP; break; } @@ -3144,6 +2667,8 @@ ahcipoll(struct cam_sim *sim) if (ch->resetting != 0 && (--ch->resetpolldiv <= 0 || !callout_pending(&ch->reset_timer))) { ch->resetpolldiv = 1000; - ahci_reset_to(ch->dev); + ahci_reset_to(ch); } } +MODULE_VERSION(ahci, 1); +MODULE_DEPEND(ahci, cam, 1, 1, 1); diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index 9014fff..755fdc5 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -376,7 +376,7 @@ enum ahci_slot_states { }; struct ahci_slot { - device_t dev; /* Device handle */ + struct ahci_channel *ch; /* Channel */ u_int8_t slot; /* Number of this slot */ enum ahci_slot_states state; /* Slot state */ union ccb *ccb; /* CCB occupying slot */ @@ -416,23 +416,26 @@ struct ahci_channel { uint32_t caps2; /* Controller capabilities */ uint32_t chcaps; /* Channel capabilities */ uint32_t chscaps; /* Channel sleep capabilities */ + uint16_t vendorid; /* Vendor ID from the bus */ + uint16_t deviceid; /* Device ID from the bus */ + uint16_t subvendorid; /* Subvendor ID from the bus */ + uint16_t subdeviceid; /* Subdevice ID from the bus */ int quirks; int numslots; /* Number of present slots */ int pm_level; /* power management level */ - - struct ahci_slot slot[AHCI_MAX_SLOTS]; - union ccb *hold[AHCI_MAX_SLOTS]; - struct mtx mtx; /* state lock */ - STAILQ_HEAD(, ccb_hdr) doneq; /* queue of completed CCBs */ - int batch; /* doneq is in use */ int devices; /* What is present */ int pm_present; /* PM presence reported */ int fbs_enabled; /* FIS-based switching enabled */ + + union ccb *hold[AHCI_MAX_SLOTS]; + struct ahci_slot slot[AHCI_MAX_SLOTS]; uint32_t oslots; /* Occupied slots */ uint32_t rslots; /* Running slots */ uint32_t aslots; /* Slots with atomic commands */ uint32_t eslots; /* Slots in error */ uint32_t toslots; /* Slots in timeout */ + int lastslot; /* Last used slot */ + int taggedtarget; /* Last tagged target */ int numrslots; /* Number of running slots */ int numrslotspd[16];/* Number of running slots per dev */ int numtslots; /* Number of tagged slots */ @@ -440,8 +443,6 @@ struct ahci_channel { int numhslots; /* Number of held slots */ int recoverycmd; /* Our READ LOG active */ int fatalerr; /* Fatal error happend */ - int lastslot; /* Last used slot */ - int taggedtarget; /* Last tagged target */ int resetting; /* Hard-reset in progress. */ int resetpolldiv; /* Hard-reset poll divider. */ int listening; /* SUD bit is cleared. */ @@ -452,6 +453,10 @@ struct ahci_channel { struct ahci_device user[16]; /* User-specified settings */ struct ahci_device curr[16]; /* Current settings */ + + struct mtx_padalign mtx; /* state lock */ + STAILQ_HEAD(, ccb_hdr) doneq; /* queue of completed CCBs */ + int batch; /* doneq is in use */ }; struct ahci_enclosure { @@ -475,6 +480,10 @@ struct ahci_controller { device_t dev; bus_dma_tag_t dma_tag; int r_rid; + uint16_t vendorid; /* Vendor ID from the bus */ + uint16_t deviceid; /* Device ID from the bus */ + uint16_t subvendorid; /* Subvendor ID from the bus */ + uint16_t subdeviceid; /* Subdevice ID from the bus */ struct resource *r_mem; struct rman sc_iomem; struct ahci_controller_irq { @@ -545,3 +554,63 @@ enum ahci_err_type { bus_write_multi_4((res), (offset), (addr), (count)) #define ATA_OUTSL_STRM(res, offset, addr, count) \ bus_write_multi_stream_4((res), (offset), (addr), (count)) + + +#define AHCI_Q_NOFORCE 0x00000001 +#define AHCI_Q_NOPMP 0x00000002 +#define AHCI_Q_NONCQ 0x00000004 +#define AHCI_Q_1CH 0x00000008 +#define AHCI_Q_2CH 0x00000010 +#define AHCI_Q_4CH 0x00000020 +#define AHCI_Q_EDGEIS 0x00000040 +#define AHCI_Q_SATA2 0x00000080 +#define AHCI_Q_NOBSYRES 0x00000100 +#define AHCI_Q_NOAA 0x00000200 +#define AHCI_Q_NOCOUNT 0x00000400 +#define AHCI_Q_ALTSIG 0x00000800 +#define AHCI_Q_NOMSI 0x00001000 +#define AHCI_Q_ATI_PMP_BUG 0x00002000 +#define AHCI_Q_MAXIO_64K 0x00004000 +#define AHCI_Q_SATA1_UNIT0 0x00008000 /* need better method for this */ +#define AHCI_Q_ABAR0 0x00010000 +#define AHCI_Q_1MSI 0x00020000 + +#define AHCI_Q_BIT_STRING \ + "\021" \ + "\001NOFORCE" \ + "\002NOPMP" \ + "\003NONCQ" \ + "\0041CH" \ + "\0052CH" \ + "\0064CH" \ + "\007EDGEIS" \ + "\010SATA2" \ + "\011NOBSYRES" \ + "\012NOAA" \ + "\013NOCOUNT" \ + "\014ALTSIG" \ + "\015NOMSI" \ + "\016ATI_PMP_BUG" \ + "\017MAXIO_64K" \ + "\020SATA1_UNIT0" \ + "\021ABAR0" \ + "\0221MSI" + +int ahci_attach(device_t dev); +int ahci_detach(device_t dev); +int ahci_setup_interrupt(device_t dev); +int ahci_print_child(device_t dev, device_t child); +struct resource *ahci_alloc_resource(device_t dev, device_t child, int type, int *rid, + u_long start, u_long end, u_long count, u_int flags); +int ahci_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r); +int ahci_setup_intr(device_t dev, device_t child, struct resource *irq, + int flags, driver_filter_t *filter, driver_intr_t *function, + void *argument, void **cookiep); +int ahci_teardown_intr(device_t dev, device_t child, struct resource *irq, + void *cookie); +int ahci_child_location_str(device_t dev, device_t child, char *buf, + size_t buflen); +bus_dma_tag_t ahci_get_dma_tag(device_t dev, device_t child); +int ahci_ctlr_reset(device_t dev); +int ahci_ctlr_setup(device_t dev); diff --git a/sys/dev/ahci/ahci_pci.c b/sys/dev/ahci/ahci_pci.c new file mode 100644 index 0000000..fdca5cd --- /dev/null +++ b/sys/dev/ahci/ahci_pci.c @@ -0,0 +1,522 @@ +/*- + * Copyright (c) 2009-2012 Alexander Motin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahci.h" + +static int force_ahci = 1; +TUNABLE_INT("hw.ahci.force", &force_ahci); + +static const struct { + uint32_t id; + uint8_t rev; + const char *name; + int quirks; +} ahci_ids[] = { + {0x43801002, 0x00, "AMD SB600", + AHCI_Q_NOMSI | AHCI_Q_ATI_PMP_BUG | AHCI_Q_MAXIO_64K}, + {0x43901002, 0x00, "AMD SB7x0/SB8x0/SB9x0", + AHCI_Q_ATI_PMP_BUG | AHCI_Q_1MSI}, + {0x43911002, 0x00, "AMD SB7x0/SB8x0/SB9x0", + AHCI_Q_ATI_PMP_BUG | AHCI_Q_1MSI}, + {0x43921002, 0x00, "AMD SB7x0/SB8x0/SB9x0", + AHCI_Q_ATI_PMP_BUG | AHCI_Q_1MSI}, + {0x43931002, 0x00, "AMD SB7x0/SB8x0/SB9x0", + AHCI_Q_ATI_PMP_BUG | AHCI_Q_1MSI}, + {0x43941002, 0x00, "AMD SB7x0/SB8x0/SB9x0", + AHCI_Q_ATI_PMP_BUG | AHCI_Q_1MSI}, + /* Not sure SB8x0/SB9x0 needs this quirk. Be conservative though */ + {0x43951002, 0x00, "AMD SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG}, + {0x78001022, 0x00, "AMD Hudson-2", 0}, + {0x78011022, 0x00, "AMD Hudson-2", 0}, + {0x78021022, 0x00, "AMD Hudson-2", 0}, + {0x78031022, 0x00, "AMD Hudson-2", 0}, + {0x78041022, 0x00, "AMD Hudson-2", 0}, + {0x06111b21, 0x00, "ASMedia ASM2106", 0}, + {0x06121b21, 0x00, "ASMedia ASM1061", 0}, + {0x26528086, 0x00, "Intel ICH6", AHCI_Q_NOFORCE}, + {0x26538086, 0x00, "Intel ICH6M", AHCI_Q_NOFORCE}, + {0x26818086, 0x00, "Intel ESB2", 0}, + {0x26828086, 0x00, "Intel ESB2", 0}, + {0x26838086, 0x00, "Intel ESB2", 0}, + {0x27c18086, 0x00, "Intel ICH7", 0}, + {0x27c38086, 0x00, "Intel ICH7", 0}, + {0x27c58086, 0x00, "Intel ICH7M", 0}, + {0x27c68086, 0x00, "Intel ICH7M", 0}, + {0x28218086, 0x00, "Intel ICH8", 0}, + {0x28228086, 0x00, "Intel ICH8", 0}, + {0x28248086, 0x00, "Intel ICH8", 0}, + {0x28298086, 0x00, "Intel ICH8M", 0}, + {0x282a8086, 0x00, "Intel ICH8M", 0}, + {0x29228086, 0x00, "Intel ICH9", 0}, + {0x29238086, 0x00, "Intel ICH9", 0}, + {0x29248086, 0x00, "Intel ICH9", 0}, + {0x29258086, 0x00, "Intel ICH9", 0}, + {0x29278086, 0x00, "Intel ICH9", 0}, + {0x29298086, 0x00, "Intel ICH9M", 0}, + {0x292a8086, 0x00, "Intel ICH9M", 0}, + {0x292b8086, 0x00, "Intel ICH9M", 0}, + {0x292c8086, 0x00, "Intel ICH9M", 0}, + {0x292f8086, 0x00, "Intel ICH9M", 0}, + {0x294d8086, 0x00, "Intel ICH9", 0}, + {0x294e8086, 0x00, "Intel ICH9M", 0}, + {0x3a058086, 0x00, "Intel ICH10", 0}, + {0x3a228086, 0x00, "Intel ICH10", 0}, + {0x3a258086, 0x00, "Intel ICH10", 0}, + {0x3b228086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b238086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b258086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b298086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b2c8086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x3b2f8086, 0x00, "Intel 5 Series/3400 Series", 0}, + {0x1c028086, 0x00, "Intel Cougar Point", 0}, + {0x1c038086, 0x00, "Intel Cougar Point", 0}, + {0x1c048086, 0x00, "Intel Cougar Point", 0}, + {0x1c058086, 0x00, "Intel Cougar Point", 0}, + {0x1d028086, 0x00, "Intel Patsburg", 0}, + {0x1d048086, 0x00, "Intel Patsburg", 0}, + {0x1d068086, 0x00, "Intel Patsburg", 0}, + {0x28268086, 0x00, "Intel Patsburg (RAID)", 0}, + {0x1e028086, 0x00, "Intel Panther Point", 0}, + {0x1e038086, 0x00, "Intel Panther Point", 0}, + {0x1e048086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1e058086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1e068086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1e078086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1e0e8086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1e0f8086, 0x00, "Intel Panther Point (RAID)", 0}, + {0x1f228086, 0x00, "Intel Avoton", 0}, + {0x1f238086, 0x00, "Intel Avoton", 0}, + {0x1f248086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f258086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f268086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f278086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f2e8086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f2f8086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f328086, 0x00, "Intel Avoton", 0}, + {0x1f338086, 0x00, "Intel Avoton", 0}, + {0x1f348086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f358086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f368086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f378086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f3e8086, 0x00, "Intel Avoton (RAID)", 0}, + {0x1f3f8086, 0x00, "Intel Avoton (RAID)", 0}, + {0x23a38086, 0x00, "Intel Coleto Creek", 0}, + {0x28238086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x28278086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x8c028086, 0x00, "Intel Lynx Point", 0}, + {0x8c038086, 0x00, "Intel Lynx Point", 0}, + {0x8c048086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c058086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c068086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c078086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c0e8086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c0f8086, 0x00, "Intel Lynx Point (RAID)", 0}, + {0x8c828086, 0x00, "Intel Wildcat Point", 0}, + {0x8c838086, 0x00, "Intel Wildcat Point", 0}, + {0x8c848086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c858086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c868086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c878086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c8e8086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8c8f8086, 0x00, "Intel Wildcat Point (RAID)", 0}, + {0x8d028086, 0x00, "Intel Wellsburg", 0}, + {0x8d048086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x8d068086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x8d628086, 0x00, "Intel Wellsburg", 0}, + {0x8d648086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x8d668086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x8d6e8086, 0x00, "Intel Wellsburg (RAID)", 0}, + {0x9c028086, 0x00, "Intel Lynx Point-LP", 0}, + {0x9c038086, 0x00, "Intel Lynx Point-LP", 0}, + {0x9c048086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x9c058086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x9c068086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x9c078086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x9c0e8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x9c0f8086, 0x00, "Intel Lynx Point-LP (RAID)", 0}, + {0x23238086, 0x00, "Intel DH89xxCC", 0}, + {0x2360197b, 0x00, "JMicron JMB360", 0}, + {0x2361197b, 0x00, "JMicron JMB361", AHCI_Q_NOFORCE}, + {0x2362197b, 0x00, "JMicron JMB362", 0}, + {0x2363197b, 0x00, "JMicron JMB363", AHCI_Q_NOFORCE}, + {0x2365197b, 0x00, "JMicron JMB365", AHCI_Q_NOFORCE}, + {0x2366197b, 0x00, "JMicron JMB366", AHCI_Q_NOFORCE}, + {0x2368197b, 0x00, "JMicron JMB368", AHCI_Q_NOFORCE}, + {0x611111ab, 0x00, "Marvell 88SE6111", AHCI_Q_NOFORCE | AHCI_Q_1CH | + AHCI_Q_EDGEIS}, + {0x612111ab, 0x00, "Marvell 88SE6121", AHCI_Q_NOFORCE | AHCI_Q_2CH | + AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, + {0x614111ab, 0x00, "Marvell 88SE6141", AHCI_Q_NOFORCE | AHCI_Q_4CH | + AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, + {0x614511ab, 0x00, "Marvell 88SE6145", AHCI_Q_NOFORCE | AHCI_Q_4CH | + AHCI_Q_EDGEIS | AHCI_Q_NONCQ | AHCI_Q_NOCOUNT}, + {0x91201b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS}, + {0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_ALTSIG}, + {0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2}, + {0x91251b4b, 0x00, "Marvell 88SE9125", 0}, + {0x91281b4b, 0x00, "Marvell 88SE9128", AHCI_Q_ALTSIG}, + {0x91301b4b, 0x00, "Marvell 88SE9130", AHCI_Q_ALTSIG}, + {0x91721b4b, 0x00, "Marvell 88SE9172", 0}, + {0x91821b4b, 0x00, "Marvell 88SE9182", 0}, + {0x91831b4b, 0x00, "Marvell 88SS9183", 0}, + {0x91a01b4b, 0x00, "Marvell 88SE91Ax", 0}, + {0x92151b4b, 0x00, "Marvell 88SE9215", 0}, + {0x92201b4b, 0x00, "Marvell 88SE9220", AHCI_Q_ALTSIG}, + {0x92301b4b, 0x00, "Marvell 88SE9230", AHCI_Q_ALTSIG}, + {0x92351b4b, 0x00, "Marvell 88SE9235", 0}, + {0x06201103, 0x00, "HighPoint RocketRAID 620", 0}, + {0x06201b4b, 0x00, "HighPoint RocketRAID 620", 0}, + {0x06221103, 0x00, "HighPoint RocketRAID 622", 0}, + {0x06221b4b, 0x00, "HighPoint RocketRAID 622", 0}, + {0x06401103, 0x00, "HighPoint RocketRAID 640", 0}, + {0x06401b4b, 0x00, "HighPoint RocketRAID 640", 0}, + {0x06441103, 0x00, "HighPoint RocketRAID 644", 0}, + {0x06441b4b, 0x00, "HighPoint RocketRAID 644", 0}, + {0x06411103, 0x00, "HighPoint RocketRAID 640L", 0}, + {0x06421103, 0x00, "HighPoint RocketRAID 642L", 0}, + {0x06451103, 0x00, "HighPoint RocketRAID 644L", 0}, + {0x044c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x044d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x044e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x044f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x045c10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x045d10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x045e10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x045f10de, 0x00, "NVIDIA MCP65", AHCI_Q_NOAA}, + {0x055010de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055110de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055210de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055310de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055510de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055610de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055710de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055810de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055910de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055A10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x055B10de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x058410de, 0x00, "NVIDIA MCP67", AHCI_Q_NOAA}, + {0x07f010de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f110de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f210de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f310de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f410de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f510de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f610de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f710de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f810de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07f910de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07fa10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x07fb10de, 0x00, "NVIDIA MCP73", AHCI_Q_NOAA}, + {0x0ad010de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad110de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad210de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad310de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad410de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad510de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad610de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad710de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad810de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ad910de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ada10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0adb10de, 0x00, "NVIDIA MCP77", AHCI_Q_NOAA}, + {0x0ab410de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0ab510de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0ab610de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0ab710de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0ab810de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0ab910de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0aba10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0abb10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0abc10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0abd10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0abe10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0abf10de, 0x00, "NVIDIA MCP79", AHCI_Q_NOAA}, + {0x0d8410de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8510de, 0x00, "NVIDIA MCP89", AHCI_Q_NOFORCE|AHCI_Q_NOAA}, + {0x0d8610de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8710de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8810de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8910de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8a10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8b10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8c10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8d10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8e10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x0d8f10de, 0x00, "NVIDIA MCP89", AHCI_Q_NOAA}, + {0x3781105a, 0x00, "Promise TX8660", 0}, + {0x33491106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, + {0x62871106, 0x00, "VIA VT8251", AHCI_Q_NOPMP|AHCI_Q_NONCQ}, + {0x11841039, 0x00, "SiS 966", 0}, + {0x11851039, 0x00, "SiS 968", 0}, + {0x01861039, 0x00, "SiS 968", 0}, + {0xa01c177d, 0x00, "ThunderX", AHCI_Q_ABAR0|AHCI_Q_1MSI}, + {0x00000000, 0x00, NULL, 0} +}; + +static int +ahci_pci_ctlr_reset(device_t dev) +{ + + if (pci_read_config(dev, PCIR_DEVVENDOR, 4) == 0x28298086 && + (pci_read_config(dev, 0x92, 1) & 0xfe) == 0x04) + pci_write_config(dev, 0x92, 0x01, 1); + return ahci_ctlr_reset(dev); +} + +static int +ahci_probe(device_t dev) +{ + char buf[64]; + int i, valid = 0; + uint32_t devid = pci_get_devid(dev); + uint8_t revid = pci_get_revid(dev); + + /* + * Ensure it is not a PCI bridge (some vendors use + * the same PID and VID in PCI bridge and AHCI cards). + */ + if (pci_get_class(dev) == PCIC_BRIDGE) + return (ENXIO); + + /* Is this a possible AHCI candidate? */ + if (pci_get_class(dev) == PCIC_STORAGE && + pci_get_subclass(dev) == PCIS_STORAGE_SATA && + pci_get_progif(dev) == PCIP_STORAGE_SATA_AHCI_1_0) + valid = 1; + /* Is this a known AHCI chip? */ + for (i = 0; ahci_ids[i].id != 0; i++) { + if (ahci_ids[i].id == devid && + ahci_ids[i].rev <= revid && + (valid || (force_ahci == 1 && + !(ahci_ids[i].quirks & AHCI_Q_NOFORCE)))) { + /* Do not attach JMicrons with single PCI function. */ + if (pci_get_vendor(dev) == 0x197b && + (pci_read_config(dev, 0xdf, 1) & 0x40) == 0) + return (ENXIO); + snprintf(buf, sizeof(buf), "%s AHCI SATA controller", + ahci_ids[i].name); + device_set_desc_copy(dev, buf); + return (BUS_PROBE_VENDOR); + } + } + if (!valid) + return (ENXIO); + device_set_desc_copy(dev, "AHCI SATA controller"); + return (BUS_PROBE_VENDOR); +} + +static int +ahci_ata_probe(device_t dev) +{ + char buf[64]; + int i; + uint32_t devid = pci_get_devid(dev); + uint8_t revid = pci_get_revid(dev); + + if ((intptr_t)device_get_ivars(dev) >= 0) + return (ENXIO); + /* Is this a known AHCI chip? */ + for (i = 0; ahci_ids[i].id != 0; i++) { + if (ahci_ids[i].id == devid && + ahci_ids[i].rev <= revid) { + snprintf(buf, sizeof(buf), "%s AHCI SATA controller", + ahci_ids[i].name); + device_set_desc_copy(dev, buf); + return (BUS_PROBE_VENDOR); + } + } + device_set_desc_copy(dev, "AHCI SATA controller"); + return (BUS_PROBE_VENDOR); +} + +static int +ahci_pci_attach(device_t dev) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + int error, i; + uint32_t devid = pci_get_devid(dev); + uint8_t revid = pci_get_revid(dev); + + i = 0; + while (ahci_ids[i].id != 0 && + (ahci_ids[i].id != devid || + ahci_ids[i].rev > revid)) + i++; + ctlr->quirks = ahci_ids[i].quirks; + /* Limit speed for my onboard JMicron external port. + * It is not eSATA really, limit to SATA 1 */ + if (pci_get_devid(dev) == 0x2363197b && + pci_get_subvendor(dev) == 0x1043 && + pci_get_subdevice(dev) == 0x81e4) + ctlr->quirks |= AHCI_Q_SATA1_UNIT0; + ctlr->vendorid = pci_get_vendor(dev); + ctlr->deviceid = pci_get_device(dev); + ctlr->subvendorid = pci_get_subvendor(dev); + ctlr->subdeviceid = pci_get_subdevice(dev); + + /* Default AHCI Base Address is BAR(5), Cavium uses BAR(0) */ + if (ctlr->quirks & AHCI_Q_ABAR0) + ctlr->r_rid = PCIR_BAR(0); + else + ctlr->r_rid = PCIR_BAR(5); + if (!(ctlr->r_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &ctlr->r_rid, RF_ACTIVE))) + return ENXIO; + pci_enable_busmaster(dev); + /* Reset controller */ + if ((error = ahci_pci_ctlr_reset(dev)) != 0) { + bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); + return (error); + }; + + /* Setup interrupts. */ + + /* Setup MSI register parameters */ + /* Process hints. */ + if (ctlr->quirks & AHCI_Q_NOMSI) + ctlr->msi = 0; + else if (ctlr->quirks & AHCI_Q_1MSI) + ctlr->msi = 1; + else + ctlr->msi = 2; + resource_int_value(device_get_name(dev), + device_get_unit(dev), "msi", &ctlr->msi); + ctlr->numirqs = 1; + if (ctlr->msi < 0) + ctlr->msi = 0; + else if (ctlr->msi == 1) + ctlr->msi = min(1, pci_msi_count(dev)); + else if (ctlr->msi > 1) { + ctlr->msi = 2; + ctlr->numirqs = pci_msi_count(dev); + } + /* Allocate MSI if needed/present. */ + if (ctlr->msi && pci_alloc_msi(dev, &ctlr->numirqs) != 0) { + ctlr->msi = 0; + ctlr->numirqs = 1; + } + + error = ahci_attach(dev); + if (error != 0) + if (ctlr->msi) + pci_release_msi(dev); + return error; +} + +static int +ahci_pci_detach(device_t dev) +{ + + ahci_detach(dev); + pci_release_msi(dev); + return (0); +} + +static int +ahci_pci_suspend(device_t dev) +{ + struct ahci_controller *ctlr = device_get_softc(dev); + + bus_generic_suspend(dev); + /* Disable interupts, so the state change(s) doesn't trigger */ + ATA_OUTL(ctlr->r_mem, AHCI_GHC, + ATA_INL(ctlr->r_mem, AHCI_GHC) & (~AHCI_GHC_IE)); + return 0; +} + +static int +ahci_pci_resume(device_t dev) +{ + int res; + + if ((res = ahci_pci_ctlr_reset(dev)) != 0) + return (res); + ahci_ctlr_setup(dev); + return (bus_generic_resume(dev)); +} + +devclass_t ahci_devclass; +static device_method_t ahci_methods[] = { + DEVMETHOD(device_probe, ahci_probe), + DEVMETHOD(device_attach, ahci_pci_attach), + DEVMETHOD(device_detach, ahci_pci_detach), + DEVMETHOD(device_suspend, ahci_pci_suspend), + DEVMETHOD(device_resume, ahci_pci_resume), + DEVMETHOD(bus_print_child, ahci_print_child), + DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), + DEVMETHOD(bus_release_resource, ahci_release_resource), + DEVMETHOD(bus_setup_intr, ahci_setup_intr), + DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), + DEVMETHOD(bus_child_location_str, ahci_child_location_str), + DEVMETHOD(bus_get_dma_tag, ahci_get_dma_tag), + DEVMETHOD_END +}; +static driver_t ahci_driver = { + "ahci", + ahci_methods, + sizeof(struct ahci_controller) +}; +DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, NULL, NULL); +static device_method_t ahci_ata_methods[] = { + DEVMETHOD(device_probe, ahci_ata_probe), + DEVMETHOD(device_attach, ahci_pci_attach), + DEVMETHOD(device_detach, ahci_pci_detach), + DEVMETHOD(device_suspend, ahci_pci_suspend), + DEVMETHOD(device_resume, ahci_pci_resume), + DEVMETHOD(bus_print_child, ahci_print_child), + DEVMETHOD(bus_alloc_resource, ahci_alloc_resource), + DEVMETHOD(bus_release_resource, ahci_release_resource), + DEVMETHOD(bus_setup_intr, ahci_setup_intr), + DEVMETHOD(bus_teardown_intr,ahci_teardown_intr), + DEVMETHOD(bus_child_location_str, ahci_child_location_str), + DEVMETHOD_END +}; +static driver_t ahci_ata_driver = { + "ahci", + ahci_ata_methods, + sizeof(struct ahci_controller) +}; +DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, NULL, NULL); diff --git a/sys/dev/ahci/ahciem.c b/sys/dev/ahci/ahciem.c index 6871468..049b7c8 100644 --- a/sys/dev/ahci/ahciem.c +++ b/sys/dev/ahci/ahciem.c @@ -344,7 +344,7 @@ ahci_em_led(void *priv, int onoff) } static int -ahci_check_ids(device_t dev, union ccb *ccb) +ahci_check_ids(union ccb *ccb) { if (ccb->ccb_h.target_id != 0) { @@ -554,7 +554,7 @@ ahciemaction(struct cam_sim *sim, union ccb *ccb) dev = enc->dev; switch (ccb->ccb_h.func_code) { case XPT_ATA_IO: /* Execute the requested I/O operation */ - if (ahci_check_ids(dev, ccb)) + if (ahci_check_ids(ccb)) return; ahci_em_begin_transaction(dev, ccb); return; diff --git a/sys/modules/ahci/Makefile b/sys/modules/ahci/Makefile index ab2a0ed..86d12c8 100644 --- a/sys/modules/ahci/Makefile +++ b/sys/modules/ahci/Makefile @@ -3,6 +3,6 @@ .PATH: ${.CURDIR}/../../dev/ahci KMOD= ahci -SRCS= ahci.c ahciem.c ahci.h device_if.h bus_if.h pci_if.h opt_cam.h +SRCS= ahci.c ahci_pci.c ahciem.c ahci.h device_if.h bus_if.h pci_if.h opt_cam.h .include -- cgit v1.1