Separate out PCI attachment from the main AHCI driver. Move checks of

PCI IDs into quirks, which mostly fit (though you'd get no argument
from me that AHCI_Q_SATA1_UNIT0 is oddly specific). Set these quirks
in the PCI attachment. Make some shared functions public so that PCI
and possibly other bus attachments can use them.

The split isn't perfect yet, but it is functional. The split will be
perfected as other bus attachments for AHCI are written.

Sponsored by: Netflix
Reviewed by: kan, mav
Differential Revision: https://reviews.freebsd.org/D699
This commit is contained in:
Warner Losh 2014-09-04 22:22:53 +00:00
parent fcb3a37075
commit 802df3ace6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=271146
5 changed files with 650 additions and 529 deletions

View File

@ -622,8 +622,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

View File

@ -41,8 +41,6 @@ __FBSDID("$FreeBSD$");
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include "ahci.h"
#include <cam/cam.h>
@ -52,12 +50,9 @@ __FBSDID("$FreeBSD$");
#include <cam/cam_debug.h>
/* 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,8 +61,6 @@ 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_dmasetprd(void *arg, bus_dma_segment_t *segs, int nsegs, int error);
static void ahci_execute_transaction(struct ahci_slot *slot);
@ -99,366 +92,76 @@ static void ahcipoll(struct cam_sim *sim);
static MALLOC_DEFINE(M_AHCI, "AHCI driver", "AHCI driver data buffers");
static 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},
{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|AHCI_Q_NOBSYRES},
{0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES},
{0x91251b4b, 0x00, "Marvell 88SE9125", AHCI_Q_NOBSYRES},
{0x91281b4b, 0x00, "Marvell 88SE9128", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91301b4b, 0x00, "Marvell 88SE9130", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91721b4b, 0x00, "Marvell 88SE9172", AHCI_Q_NOBSYRES},
{0x91821b4b, 0x00, "Marvell 88SE9182", AHCI_Q_NOBSYRES},
{0x91831b4b, 0x00, "Marvell 88SS9183", AHCI_Q_NOBSYRES},
{0x91a01b4b, 0x00, "Marvell 88SE91Ax", AHCI_Q_NOBSYRES},
{0x92151b4b, 0x00, "Marvell 88SE9215", AHCI_Q_NOBSYRES},
{0x92201b4b, 0x00, "Marvell 88SE9220", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x92301b4b, 0x00, "Marvell 88SE9230", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x92351b4b, 0x00, "Marvell 88SE9235", AHCI_Q_NOBSYRES},
{0x06201103, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06201b4b, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06221103, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
{0x06221b4b, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
{0x06401103, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
{0x06401b4b, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
{0x06441103, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
{0x06441b4b, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
{0x06411103, 0x00, "HighPoint RocketRAID 640L", AHCI_Q_NOBSYRES},
{0x06421103, 0x00, "HighPoint RocketRAID 642L", AHCI_Q_NOBSYRES},
{0x06451103, 0x00, "HighPoint RocketRAID 644L", AHCI_Q_NOBSYRES},
{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},
{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)
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);
}
/* 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;
}
device_set_desc_copy(dev, "AHCI SATA controller");
return (BUS_PROBE_VENDOR);
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
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;
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);
@ -474,13 +177,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);
@ -533,13 +229,7 @@ ahci_attach(device_t dev)
}
ahci_ctlr_setup(dev);
/* Setup interrupts. */
if (ahci_setup_interrupt(dev)) {
bus_dma_tag_destroy(ctlr->dma_tag);
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
rman_fini(&ctlr->sc_iomem);
return ENXIO;
}
i = 0;
for (u = ctlr->ichannels; u != 0; u >>= 1)
i += (u & 1);
@ -619,7 +309,7 @@ ahci_attach(device_t dev)
return 0;
}
static int
int
ahci_detach(device_t dev)
{
struct ahci_controller *ctlr = device_get_softc(dev);
@ -637,7 +327,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);
@ -646,109 +335,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) {
@ -864,9 +456,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;
@ -915,9 +507,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) {
@ -932,10 +524,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);
@ -949,9 +541,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);
@ -961,7 +553,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;
@ -974,7 +566,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)
{
@ -986,7 +578,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);
@ -994,51 +586,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),
{ 0, 0 }
};
static driver_t ahci_driver = {
"ahci",
ahci_methods,
sizeof(struct ahci_controller)
};
DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0);
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),
{ 0, 0 }
};
static driver_t ahci_ata_driver = {
"ahci",
ahci_ata_methods,
sizeof(struct ahci_controller)
};
DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, 0, 0);
MODULE_VERSION(ahci, 1);
MODULE_DEPEND(ahci, cam, 1, 1, 1);
static int
ahci_ch_probe(device_t dev)
{
@ -1061,6 +608,10 @@ 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);
resource_int_value(device_get_name(dev),
@ -1069,12 +620,8 @@ ahci_ch_attach(device_t dev)
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;
@ -1979,7 +1526,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;
@ -3085,12 +2632,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;
}
@ -3117,3 +2664,5 @@ ahcipoll(struct cam_sim *sim)
ahci_reset_to(ch->dev);
}
}
MODULE_VERSION(ahci, 1);
MODULE_DEPEND(ahci, cam, 1, 1, 1);

View File

@ -415,6 +415,10 @@ 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 */
@ -474,6 +478,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 {
@ -544,3 +552,59 @@ 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 1
#define AHCI_Q_NOPMP 2
#define AHCI_Q_NONCQ 4
#define AHCI_Q_1CH 8
#define AHCI_Q_2CH 0x10
#define AHCI_Q_4CH 0x20
#define AHCI_Q_EDGEIS 0x40
#define AHCI_Q_SATA2 0x80
#define AHCI_Q_NOBSYRES 0x100
#define AHCI_Q_NOAA 0x200
#define AHCI_Q_NOCOUNT 0x400
#define AHCI_Q_ALTSIG 0x800
#define AHCI_Q_NOMSI 0x1000
#define AHCI_Q_ATI_PMP_BUG 0x2000
#define AHCI_Q_MAXIO_64K 0x4000
#define AHCI_Q_SATA1_UNIT0 0x8000 /* need better method for this */
#define AHCI_Q_BIT_STRING \
"\020" \
"\001NOFORCE" \
"\002NOPMP" \
"\003NONCQ" \
"\0041CH" \
"\0052CH" \
"\0064CH" \
"\007EDGEIS" \
"\010SATA2" \
"\011NOBSYRES" \
"\012NOAA" \
"\013NOCOUNT" \
"\014ALTSIG" \
"\015NOMSI" \
"\016ATI_PMP_BUG" \
"\017MAXIO_64K" \
"\020SATA1_UNIT0"
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);

507
sys/dev/ahci/ahci_pci.c Normal file
View File

@ -0,0 +1,507 @@
/*-
* Copyright (c) 2009-2012 Alexander Motin <mav@FreeBSD.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include "ahci.h"
static int force_ahci = 1;
TUNABLE_INT("hw.ahci.force", &force_ahci);
static 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},
{0x43911002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG},
{0x43921002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG},
{0x43931002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG},
{0x43941002, 0x00, "AMD SB7x0/SB8x0/SB9x0", AHCI_Q_ATI_PMP_BUG},
/* 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},
{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|AHCI_Q_NOBSYRES},
{0x91231b4b, 0x11, "Marvell 88SE912x", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91231b4b, 0x00, "Marvell 88SE912x", AHCI_Q_EDGEIS|AHCI_Q_SATA2|AHCI_Q_NOBSYRES},
{0x91251b4b, 0x00, "Marvell 88SE9125", AHCI_Q_NOBSYRES},
{0x91281b4b, 0x00, "Marvell 88SE9128", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91301b4b, 0x00, "Marvell 88SE9130", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x91721b4b, 0x00, "Marvell 88SE9172", AHCI_Q_NOBSYRES},
{0x91821b4b, 0x00, "Marvell 88SE9182", AHCI_Q_NOBSYRES},
{0x91831b4b, 0x00, "Marvell 88SS9183", AHCI_Q_NOBSYRES},
{0x91a01b4b, 0x00, "Marvell 88SE91Ax", AHCI_Q_NOBSYRES},
{0x92151b4b, 0x00, "Marvell 88SE9215", AHCI_Q_NOBSYRES},
{0x92201b4b, 0x00, "Marvell 88SE9220", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x92301b4b, 0x00, "Marvell 88SE9230", AHCI_Q_NOBSYRES|AHCI_Q_ALTSIG},
{0x92351b4b, 0x00, "Marvell 88SE9235", AHCI_Q_NOBSYRES},
{0x06201103, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06201b4b, 0x00, "HighPoint RocketRAID 620", AHCI_Q_NOBSYRES},
{0x06221103, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
{0x06221b4b, 0x00, "HighPoint RocketRAID 622", AHCI_Q_NOBSYRES},
{0x06401103, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
{0x06401b4b, 0x00, "HighPoint RocketRAID 640", AHCI_Q_NOBSYRES},
{0x06441103, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
{0x06441b4b, 0x00, "HighPoint RocketRAID 644", AHCI_Q_NOBSYRES},
{0x06411103, 0x00, "HighPoint RocketRAID 640L", AHCI_Q_NOBSYRES},
{0x06421103, 0x00, "HighPoint RocketRAID 642L", AHCI_Q_NOBSYRES},
{0x06451103, 0x00, "HighPoint RocketRAID 644L", AHCI_Q_NOBSYRES},
{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},
{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}
};
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;
/* if we have a memory BAR(5) we are likely on an AHCI part */
ctlr->vendorid = pci_get_vendor(dev);
ctlr->deviceid = pci_get_device(dev);
ctlr->subvendorid = pci_get_subvendor(dev);
ctlr->subdeviceid = pci_get_subdevice(dev);
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 */
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;
}
if (ahci_setup_interrupt(dev)) {
if (ctlr->msi)
pci_release_msi(dev);
bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem);
return ENXIO;
}
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),
{ 0, 0 }
};
static driver_t ahci_driver = {
"ahci",
ahci_methods,
sizeof(struct ahci_controller)
};
DRIVER_MODULE(ahci, pci, ahci_driver, ahci_devclass, 0, 0);
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),
{ 0, 0 }
};
static driver_t ahci_ata_driver = {
"ahci",
ahci_ata_methods,
sizeof(struct ahci_controller)
};
DRIVER_MODULE(ahci, atapci, ahci_ata_driver, ahci_devclass, 0, 0);

View File

@ -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 <bsd.kmod.mk>