Index: head/sys/dev/ata/ata-pci.h =================================================================== --- head/sys/dev/ata/ata-pci.h (revision 191567) +++ head/sys/dev/ata/ata-pci.h (revision 191568) @@ -1,498 +1,504 @@ /*- * Copyright (c) 2003 - 2008 Søren Schmidt * 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. * * $FreeBSD$ */ /* structure holding chipset config info */ struct ata_chip_id { u_int32_t chipid; u_int8_t chiprev; int cfg1; int cfg2; u_int8_t max_dma; char *text; }; /* structure describing a PCI ATA controller */ struct ata_pci_controller { device_t dev; int r_type1; int r_rid1; struct resource *r_res1; int r_type2; int r_rid2; struct resource *r_res2; int r_irq_rid; struct resource *r_irq; void *handle; struct ata_chip_id *chip; int legacy; int channels; int ichannels; int (*chipinit)(device_t); int (*suspend)(device_t); int (*resume)(device_t); int (*ch_attach)(device_t); int (*ch_detach)(device_t); int (*ch_suspend)(device_t); int (*ch_resume)(device_t); int (*locking)(device_t, int); void (*reset)(device_t); void (*setmode)(device_t, int); struct { void (*function)(void *); void *argument; } interrupt[8]; /* XXX SOS max ch# for now */ }; /* defines for known chipset PCI id's */ #define ATA_ACARD_ID 0x1191 #define ATA_ATP850 0x00021191 #define ATA_ATP850A 0x00041191 #define ATA_ATP850R 0x00051191 #define ATA_ATP860A 0x00061191 #define ATA_ATP860R 0x00071191 #define ATA_ATP865A 0x00081191 #define ATA_ATP865R 0x00091191 #define ATA_ACER_LABS_ID 0x10b9 #define ATA_ALI_1533 0x153310b9 #define ATA_ALI_5229 0x522910b9 #define ATA_ALI_5281 0x528110b9 #define ATA_ALI_5287 0x528710b9 #define ATA_ALI_5288 0x528810b9 #define ATA_ALI_5289 0x528910b9 #define ATA_AMD_ID 0x1022 #define ATA_AMD755 0x74011022 #define ATA_AMD756 0x74091022 #define ATA_AMD766 0x74111022 #define ATA_AMD768 0x74411022 #define ATA_AMD8111 0x74691022 #define ATA_AMD5536 0x209a1022 #define ATA_ADAPTEC_ID 0x9005 #define ATA_ADAPTEC_1420 0x02419005 #define ATA_ATI_ID 0x1002 #define ATA_ATI_IXP200 0x43491002 #define ATA_ATI_IXP300 0x43691002 #define ATA_ATI_IXP300_S1 0x436e1002 #define ATA_ATI_IXP400 0x43761002 #define ATA_ATI_IXP400_S1 0x43791002 #define ATA_ATI_IXP400_S2 0x437a1002 #define ATA_ATI_IXP600 0x438c1002 #define ATA_ATI_IXP600_S1 0x43801002 #define ATA_ATI_IXP700 0x439c1002 #define ATA_ATI_IXP700_S1 0x43901002 +#define ATA_ATI_IXP700_S2 0x43911002 +#define ATA_ATI_IXP700_S3 0x43921002 +#define ATA_ATI_IXP700_S4 0x43931002 +#define ATA_ATI_IXP800_S1 0x43941002 +#define ATA_ATI_IXP800_S2 0x43951002 #define ATA_CENATEK_ID 0x16ca #define ATA_CENATEK_ROCKET 0x000116ca #define ATA_CYRIX_ID 0x1078 #define ATA_CYRIX_5530 0x01021078 #define ATA_CYPRESS_ID 0x1080 #define ATA_CYPRESS_82C693 0xc6931080 #define ATA_DEC_21150 0x00221011 #define ATA_DEC_21150_1 0x00231011 #define ATA_HIGHPOINT_ID 0x1103 #define ATA_HPT366 0x00041103 #define ATA_HPT372 0x00051103 #define ATA_HPT302 0x00061103 #define ATA_HPT371 0x00071103 #define ATA_HPT374 0x00081103 #define ATA_INTEL_ID 0x8086 #define ATA_I960RM 0x09628086 #define ATA_I82371FB 0x12308086 #define ATA_I82371SB 0x70108086 #define ATA_I82371AB 0x71118086 #define ATA_I82443MX 0x71998086 #define ATA_I82451NX 0x84ca8086 #define ATA_I82372FB 0x76018086 #define ATA_I82801AB 0x24218086 #define ATA_I82801AA 0x24118086 #define ATA_I82801BA 0x244a8086 #define ATA_I82801BA_1 0x244b8086 #define ATA_I82801CA 0x248a8086 #define ATA_I82801CA_1 0x248b8086 #define ATA_I82801DB 0x24cb8086 #define ATA_I82801DB_1 0x24ca8086 #define ATA_I82801EB 0x24db8086 #define ATA_I82801EB_S1 0x24d18086 #define ATA_I82801EB_R1 0x24df8086 #define ATA_I6300ESB 0x25a28086 #define ATA_I6300ESB_S1 0x25a38086 #define ATA_I6300ESB_R1 0x25b08086 #define ATA_I63XXESB2 0x269e8086 #define ATA_I63XXESB2_S1 0x26808086 #define ATA_I63XXESB2_S2 0x26818086 #define ATA_I63XXESB2_R1 0x26828086 #define ATA_I63XXESB2_R2 0x26838086 #define ATA_I82801FB 0x266f8086 #define ATA_I82801FB_S1 0x26518086 #define ATA_I82801FB_R1 0x26528086 #define ATA_I82801FBM 0x26538086 #define ATA_I82801GB 0x27df8086 #define ATA_I82801GB_S1 0x27c08086 #define ATA_I82801GB_AH 0x27c18086 #define ATA_I82801GB_R1 0x27c38086 #define ATA_I82801GBM_S1 0x27c48086 #define ATA_I82801GBM_AH 0x27c58086 #define ATA_I82801GBM_R1 0x27c68086 #define ATA_I82801HB_S1 0x28208086 #define ATA_I82801HB_AH6 0x28218086 #define ATA_I82801HB_R1 0x28228086 #define ATA_I82801HB_AH4 0x28248086 #define ATA_I82801HB_S2 0x28258086 #define ATA_I82801HBM 0x28508086 #define ATA_I82801HBM_S1 0x28288086 #define ATA_I82801HBM_S2 0x28298086 #define ATA_I82801HBM_S3 0x282a8086 #define ATA_I82801IB_S1 0x29208086 #define ATA_I82801IB_AH2 0x29218086 #define ATA_I82801IB_AH6 0x29228086 #define ATA_I82801IB_AH4 0x29238086 #define ATA_I82801IB_R1 0x29258086 #define ATA_I82801IB_S2 0x29268086 #define ATA_I82801JIB_S1 0x3a208086 #define ATA_I82801JIB_AH 0x3a228086 #define ATA_I82801JIB_R1 0x3a258086 #define ATA_I82801JIB_S2 0x3a268086 #define ATA_I82801JD_S1 0x3a008086 #define ATA_I82801JD_AH 0x3a028086 #define ATA_I82801JD_R1 0x3a058086 #define ATA_I82801JD_S2 0x3a068086 #define ATA_I31244 0x32008086 #define ATA_ITE_ID 0x1283 #define ATA_IT8211F 0x82111283 #define ATA_IT8212F 0x82121283 #define ATA_IT8213F 0x82131283 #define ATA_JMICRON_ID 0x197b #define ATA_JMB360 0x2360197b #define ATA_JMB361 0x2361197b #define ATA_JMB363 0x2363197b #define ATA_JMB365 0x2365197b #define ATA_JMB366 0x2366197b #define ATA_JMB368 0x2368197b #define ATA_MARVELL_ID 0x11ab #define ATA_M88SX5040 0x504011ab #define ATA_M88SX5041 0x504111ab #define ATA_M88SX5080 0x508011ab #define ATA_M88SX5081 0x508111ab #define ATA_M88SX6041 0x604111ab #define ATA_M88SX6081 0x608111ab #define ATA_M88SX6101 0x610111ab #define ATA_M88SX6121 0x612111ab #define ATA_M88SX6145 0x614511ab #define ATA_MICRON_ID 0x1042 #define ATA_MICRON_RZ1000 0x10001042 #define ATA_MICRON_RZ1001 0x10011042 #define ATA_NATIONAL_ID 0x100b #define ATA_SC1100 0x0502100b #define ATA_NETCELL_ID 0x169c #define ATA_NETCELL_SR 0x0044169c #define ATA_NVIDIA_ID 0x10de #define ATA_NFORCE1 0x01bc10de #define ATA_NFORCE2 0x006510de #define ATA_NFORCE2_PRO 0x008510de #define ATA_NFORCE2_PRO_S1 0x008e10de #define ATA_NFORCE3 0x00d510de #define ATA_NFORCE3_PRO 0x00e510de #define ATA_NFORCE3_PRO_S1 0x00e310de #define ATA_NFORCE3_PRO_S2 0x00ee10de #define ATA_NFORCE_MCP04 0x003510de #define ATA_NFORCE_MCP04_S1 0x003610de #define ATA_NFORCE_MCP04_S2 0x003e10de #define ATA_NFORCE_CK804 0x005310de #define ATA_NFORCE_CK804_S1 0x005410de #define ATA_NFORCE_CK804_S2 0x005510de #define ATA_NFORCE_MCP51 0x026510de #define ATA_NFORCE_MCP51_S1 0x026610de #define ATA_NFORCE_MCP51_S2 0x026710de #define ATA_NFORCE_MCP55 0x036e10de #define ATA_NFORCE_MCP55_S1 0x037e10de #define ATA_NFORCE_MCP55_S2 0x037f10de #define ATA_NFORCE_MCP61 0x03ec10de #define ATA_NFORCE_MCP61_S1 0x03e710de #define ATA_NFORCE_MCP61_S2 0x03f610de #define ATA_NFORCE_MCP61_S3 0x03f710de #define ATA_NFORCE_MCP65 0x044810de #define ATA_NFORCE_MCP67_A0 0x055010de #define ATA_NFORCE_MCP67_A1 0x055110de #define ATA_NFORCE_MCP67_A2 0x055210de #define ATA_NFORCE_MCP67_A3 0x055310de #define ATA_NFORCE_MCP67_A4 0x055410de #define ATA_NFORCE_MCP67_A5 0x055510de #define ATA_NFORCE_MCP67_A6 0x055610de #define ATA_NFORCE_MCP67_A7 0x055710de #define ATA_NFORCE_MCP67_A8 0x055810de #define ATA_NFORCE_MCP67_A9 0x055910de #define ATA_NFORCE_MCP67_AA 0x055A10de #define ATA_NFORCE_MCP67_AB 0x055B10de #define ATA_NFORCE_MCP67 0x056010de #define ATA_NFORCE_MCP73 0x056c10de #define ATA_NFORCE_MCP73_A0 0x07f010de #define ATA_NFORCE_MCP73_A1 0x07f110de #define ATA_NFORCE_MCP73_A2 0x07f210de #define ATA_NFORCE_MCP73_A3 0x07f310de #define ATA_NFORCE_MCP73_A4 0x07f410de #define ATA_NFORCE_MCP73_A5 0x07f510de #define ATA_NFORCE_MCP73_A6 0x07f610de #define ATA_NFORCE_MCP73_A7 0x07f710de #define ATA_NFORCE_MCP73_A8 0x07f810de #define ATA_NFORCE_MCP73_A9 0x07f910de #define ATA_NFORCE_MCP73_AA 0x07fa10de #define ATA_NFORCE_MCP73_AB 0x07fb10de #define ATA_NFORCE_MCP77 0x075910de #define ATA_PROMISE_ID 0x105a #define ATA_PDC20246 0x4d33105a #define ATA_PDC20262 0x4d38105a #define ATA_PDC20263 0x0d38105a #define ATA_PDC20265 0x0d30105a #define ATA_PDC20267 0x4d30105a #define ATA_PDC20268 0x4d68105a #define ATA_PDC20269 0x4d69105a #define ATA_PDC20270 0x6268105a #define ATA_PDC20271 0x6269105a #define ATA_PDC20275 0x1275105a #define ATA_PDC20276 0x5275105a #define ATA_PDC20277 0x7275105a #define ATA_PDC20318 0x3318105a #define ATA_PDC20319 0x3319105a #define ATA_PDC20371 0x3371105a #define ATA_PDC20375 0x3375105a #define ATA_PDC20376 0x3376105a #define ATA_PDC20377 0x3377105a #define ATA_PDC20378 0x3373105a #define ATA_PDC20379 0x3372105a #define ATA_PDC20571 0x3571105a #define ATA_PDC20575 0x3d75105a #define ATA_PDC20579 0x3574105a #define ATA_PDC20771 0x3570105a #define ATA_PDC40518 0x3d18105a #define ATA_PDC40519 0x3519105a #define ATA_PDC40718 0x3d17105a #define ATA_PDC40719 0x3515105a #define ATA_PDC40775 0x3d73105a #define ATA_PDC40779 0x3577105a #define ATA_PDC20617 0x6617105a #define ATA_PDC20618 0x6626105a #define ATA_PDC20619 0x6629105a #define ATA_PDC20620 0x6620105a #define ATA_PDC20621 0x6621105a #define ATA_PDC20622 0x6622105a #define ATA_PDC20624 0x6624105a #define ATA_PDC81518 0x8002105a #define ATA_SERVERWORKS_ID 0x1166 #define ATA_ROSB4_ISA 0x02001166 #define ATA_ROSB4 0x02111166 #define ATA_CSB5 0x02121166 #define ATA_CSB6 0x02131166 #define ATA_CSB6_1 0x02171166 #define ATA_HT1000 0x02141166 #define ATA_HT1000_S1 0x024b1166 #define ATA_HT1000_S2 0x024a1166 #define ATA_K2 0x02401166 #define ATA_FRODO4 0x02411166 #define ATA_FRODO8 0x02421166 #define ATA_SILICON_IMAGE_ID 0x1095 #define ATA_SII3114 0x31141095 #define ATA_SII3512 0x35121095 #define ATA_SII3112 0x31121095 #define ATA_SII3112_1 0x02401095 #define ATA_SII3124 0x31241095 #define ATA_SII3132 0x31321095 #define ATA_SII3132_1 0x02421095 #define ATA_SII0680 0x06801095 #define ATA_CMD646 0x06461095 #define ATA_CMD648 0x06481095 #define ATA_CMD649 0x06491095 #define ATA_SIS_ID 0x1039 #define ATA_SISSOUTH 0x00081039 #define ATA_SIS5511 0x55111039 #define ATA_SIS5513 0x55131039 #define ATA_SIS5517 0x55171039 #define ATA_SIS5518 0x55181039 #define ATA_SIS5571 0x55711039 #define ATA_SIS5591 0x55911039 #define ATA_SIS5596 0x55961039 #define ATA_SIS5597 0x55971039 #define ATA_SIS5598 0x55981039 #define ATA_SIS5600 0x56001039 #define ATA_SIS530 0x05301039 #define ATA_SIS540 0x05401039 #define ATA_SIS550 0x05501039 #define ATA_SIS620 0x06201039 #define ATA_SIS630 0x06301039 #define ATA_SIS635 0x06351039 #define ATA_SIS633 0x06331039 #define ATA_SIS640 0x06401039 #define ATA_SIS645 0x06451039 #define ATA_SIS646 0x06461039 #define ATA_SIS648 0x06481039 #define ATA_SIS650 0x06501039 #define ATA_SIS651 0x06511039 #define ATA_SIS652 0x06521039 #define ATA_SIS655 0x06551039 #define ATA_SIS658 0x06581039 #define ATA_SIS661 0x06611039 #define ATA_SIS730 0x07301039 #define ATA_SIS733 0x07331039 #define ATA_SIS735 0x07351039 #define ATA_SIS740 0x07401039 #define ATA_SIS745 0x07451039 #define ATA_SIS746 0x07461039 #define ATA_SIS748 0x07481039 #define ATA_SIS750 0x07501039 #define ATA_SIS751 0x07511039 #define ATA_SIS752 0x07521039 #define ATA_SIS755 0x07551039 #define ATA_SIS961 0x09611039 #define ATA_SIS962 0x09621039 #define ATA_SIS963 0x09631039 #define ATA_SIS964 0x09641039 #define ATA_SIS965 0x09651039 #define ATA_SIS180 0x01801039 #define ATA_SIS181 0x01811039 #define ATA_SIS182 0x01821039 #define ATA_VIA_ID 0x1106 #define ATA_VIA82C571 0x05711106 #define ATA_VIA82C586 0x05861106 #define ATA_VIA82C596 0x05961106 #define ATA_VIA82C686 0x06861106 #define ATA_VIA8231 0x82311106 #define ATA_VIA8233 0x30741106 #define ATA_VIA8233A 0x31471106 #define ATA_VIA8233C 0x31091106 #define ATA_VIA8235 0x31771106 #define ATA_VIA8237 0x32271106 #define ATA_VIA8237A 0x05911106 #define ATA_VIA8237S 0x53371106 #define ATA_VIA8251 0x33491106 #define ATA_VIA8361 0x31121106 #define ATA_VIA8363 0x03051106 #define ATA_VIA8371 0x03911106 #define ATA_VIA8662 0x31021106 #define ATA_VIA6410 0x31641106 #define ATA_VIA6420 0x31491106 #define ATA_VIA6421 0x32491106 /* global prototypes ata-pci.c */ int ata_pci_probe(device_t dev); int ata_pci_attach(device_t dev); int ata_pci_detach(device_t dev); int ata_pci_suspend(device_t dev); int ata_pci_resume(device_t dev); struct resource * ata_pci_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 ata_pci_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r); int ata_pci_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 ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie); int ata_pci_ch_attach(device_t dev); int ata_pci_ch_detach(device_t dev); int ata_pci_status(device_t dev); void ata_pci_hw(device_t dev); void ata_pci_dmainit(device_t dev); void ata_pci_dmafini(device_t dev); char *ata_pcivendor2str(device_t dev); int ata_legacy(device_t); void ata_generic_intr(void *data); int ata_setup_interrupt(device_t dev, void *intr_func); void ata_set_desc(device_t dev); struct ata_chip_id *ata_match_chip(device_t dev, struct ata_chip_id *index); struct ata_chip_id *ata_find_chip(device_t dev, struct ata_chip_id *index, int slot); void ata_print_cable(device_t dev, u_int8_t *who); int ata_check_80pin(device_t dev, int mode); int ata_mode2idx(int mode); /* global prototypes ata-sata.c */ void ata_sata_phy_check_events(device_t dev); int ata_sata_scr_read(struct ata_channel *ch, int port, int reg, uint32_t *val); int ata_sata_scr_write(struct ata_channel *ch, int port, int reg, uint32_t val); int ata_sata_phy_reset(device_t dev, int port, int quick); void ata_sata_setmode(device_t dev, int mode); int ata_request2fis_h2d(struct ata_request *request, u_int8_t *fis); void ata_pm_identify(device_t dev); /* global prototypes from chipsets/ata-*.c */ int ata_ahci_chipinit(device_t); int ata_ahci_ch_attach(device_t dev); int ata_ahci_ch_detach(device_t dev); int ata_ahci_ch_suspend(device_t dev); int ata_ahci_ch_resume(device_t dev); +int ata_ahci_ctlr_reset(device_t dev); void ata_ahci_reset(device_t dev); int ata_marvell_edma_chipinit(device_t); int ata_sii_chipinit(device_t); /* global prototypes ata-dma.c */ void ata_dmainit(device_t); void ata_dmafini(device_t dev); /* externs */ extern devclass_t ata_pci_devclass; /* macro for easy definition of all driver module stuff */ #define ATA_DECLARE_DRIVER(dname) \ static device_method_t __CONCAT(dname,_methods)[] = { \ DEVMETHOD(device_probe, __CONCAT(dname,_probe)), \ DEVMETHOD(device_attach, ata_pci_attach), \ DEVMETHOD(device_detach, ata_pci_detach), \ DEVMETHOD(device_suspend, ata_pci_suspend), \ DEVMETHOD(device_resume, ata_pci_resume), \ DEVMETHOD(device_shutdown, bus_generic_shutdown), \ DEVMETHOD(bus_alloc_resource, ata_pci_alloc_resource), \ DEVMETHOD(bus_release_resource, ata_pci_release_resource), \ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), \ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), \ DEVMETHOD(bus_setup_intr, ata_pci_setup_intr), \ DEVMETHOD(bus_teardown_intr, ata_pci_teardown_intr), \ { 0, 0 } \ }; \ static driver_t __CONCAT(dname,_driver) = { \ "atapci", \ __CONCAT(dname,_methods), \ sizeof(struct ata_pci_controller) \ }; \ DRIVER_MODULE(dname, pci, __CONCAT(dname,_driver), ata_pci_devclass, 0, 0); \ MODULE_VERSION(dname, 1); \ MODULE_DEPEND(dname, ata, 1, 1, 1); \ MODULE_DEPEND(dname, atapci, 1, 1, 1); Index: head/sys/dev/ata/chipsets/ata-ahci.c =================================================================== --- head/sys/dev/ata/chipsets/ata-ahci.c (revision 191567) +++ head/sys/dev/ata/chipsets/ata-ahci.c (revision 191568) @@ -1,903 +1,902 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * 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 "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local prototypes */ -static int ata_ahci_ctlr_reset(device_t dev); static int ata_ahci_suspend(device_t dev); static int ata_ahci_status(device_t dev); static int ata_ahci_begin_transaction(struct ata_request *request); static int ata_ahci_end_transaction(struct ata_request *request); static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result); static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t result); static int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature); static u_int32_t ata_ahci_softreset(device_t dev, int port); static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error); static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *equest); static void ata_ahci_dmainit(device_t dev); static void ata_ahci_start(device_t dev); static void ata_ahci_stop(device_t dev); static void ata_ahci_clo(device_t dev); static void ata_ahci_start_fr(device_t dev); static void ata_ahci_stop_fr(device_t dev); /* * AHCI v1.x compliant SATA chipset support functions */ static int ata_ahci_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); char buffer[64]; /* is this a possible AHCI candidate ? */ if (pci_get_class(dev) != PCIC_STORAGE || pci_get_subclass(dev) != PCIS_STORAGE_SATA) return (ENXIO); /* is this PCI device flagged as an AHCI compliant chip ? */ if (pci_read_config(dev, PCIR_PROGIF, 1) != PCIP_STORAGE_SATA_AHCI_1_0) return ENXIO; if (bootverbose) sprintf(buffer, "%s (ID=%08x) AHCI controller", ata_pcivendor2str(dev), pci_get_devid(dev)); else sprintf(buffer, "%s AHCI controller", ata_pcivendor2str(dev)); device_set_desc_copy(dev, buffer); ctlr->chipinit = ata_ahci_chipinit; return 0; } int ata_ahci_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int error; u_int32_t version; /* if we have a memory BAR(5) we are likely on an AHCI part */ ctlr->r_type2 = SYS_RES_MEMORY; ctlr->r_rid2 = PCIR_BAR(5); if (!(ctlr->r_res2 = bus_alloc_resource_any(dev, ctlr->r_type2, &ctlr->r_rid2, RF_ACTIVE))) return ENXIO; /* setup interrupt delivery if not done allready by a vendor driver */ if (!ctlr->r_irq) { if (ata_setup_interrupt(dev, ata_generic_intr)) { bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); return ENXIO; } } else device_printf(dev, "AHCI called from vendor specific driver\n"); /* reset controller */ if ((error = ata_ahci_ctlr_reset(dev)) != 0) { bus_release_resource(dev, ctlr->r_type2, ctlr->r_rid2, ctlr->r_res2); return (error); }; /* get the number of HW channels */ ctlr->ichannels = ATA_INL(ctlr->r_res2, ATA_AHCI_PI); ctlr->channels = MAX(flsl(ctlr->ichannels), (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1); ctlr->reset = ata_ahci_reset; ctlr->ch_attach = ata_ahci_ch_attach; ctlr->ch_detach = ata_ahci_ch_detach; ctlr->ch_suspend = ata_ahci_ch_suspend; ctlr->ch_resume = ata_ahci_ch_resume; ctlr->setmode = ata_sata_setmode; ctlr->suspend = ata_ahci_suspend; ctlr->resume = ata_ahci_ctlr_reset; /* announce we support the HW */ version = ATA_INL(ctlr->r_res2, ATA_AHCI_VS); device_printf(dev, "AHCI Version %x%x.%x%x controller with %d ports PM %s\n", (version >> 24) & 0xff, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff, (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_NPMASK) + 1, (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) ? "supported" : "not supported"); return 0; } -static int +int ata_ahci_ctlr_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); int timeout; /* enable AHCI mode */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); /* reset AHCI controller */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE|ATA_AHCI_GHC_HR); for (timeout = 1000; timeout > 0; timeout--) { DELAY(1000); if ((ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & ATA_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_res2, ATA_AHCI_GHC, ATA_AHCI_GHC_AE); /* clear interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, ATA_INL(ctlr->r_res2, ATA_AHCI_IS)); /* enable AHCI interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) | ATA_AHCI_GHC_IE); return 0; } static int ata_ahci_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); /* disable interupts so the state change(s) doesn't trigger */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_GHC, ATA_INL(ctlr->r_res2, ATA_AHCI_GHC) & (~ATA_AHCI_GHC_IE)); return 0; } int ata_ahci_ch_attach(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; ata_ahci_dmainit(dev); /* set the SATA resources */ ch->r_io[ATA_SSTATUS].res = ctlr->r_res2; ch->r_io[ATA_SSTATUS].offset = ATA_AHCI_P_SSTS + offset; ch->r_io[ATA_SERROR].res = ctlr->r_res2; ch->r_io[ATA_SERROR].offset = ATA_AHCI_P_SERR + offset; ch->r_io[ATA_SCONTROL].res = ctlr->r_res2; ch->r_io[ATA_SCONTROL].offset = ATA_AHCI_P_SCTL + offset; ch->r_io[ATA_SACTIVE].res = ctlr->r_res2; ch->r_io[ATA_SACTIVE].offset = ATA_AHCI_P_SACT + offset; ch->hw.status = ata_ahci_status; ch->hw.begin_transaction = ata_ahci_begin_transaction; ch->hw.end_transaction = ata_ahci_end_transaction; ch->hw.command = NULL; /* not used here */ ch->hw.softreset = ata_ahci_softreset; ch->hw.pm_read = ata_ahci_pm_read; ch->hw.pm_write = ata_ahci_pm_write; ata_ahci_ch_resume(dev); return 0; } int ata_ahci_ch_detach(device_t dev) { ata_ahci_ch_suspend(dev); ata_dmafini(dev); return (0); } int ata_ahci_ch_suspend(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; /* Disable port interrupts. */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); /* Reset command register. */ ata_ahci_stop(dev); ata_ahci_stop_fr(dev); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, 0); /* Allow everything including partial and slumber modes. */ ATA_IDX_OUTL(ch, ATA_SCONTROL, 0); /* Request slumber mode transition and give some time to get there. */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_AHCI_P_CMD_SLUMBER); DELAY(100); /* Disable PHY. */ ATA_IDX_OUTL(ch, ATA_SCONTROL, ATA_SC_DET_DISABLE); return (0); } int ata_ahci_ch_resume(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); uint64_t work; int offset = ch->unit << 7; /* Disable port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); /* setup work areas */ work = ch->dma.work_bus + ATA_AHCI_CL_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CLBU + offset, work >> 32); work = ch->dma.work_bus + ATA_AHCI_FB_OFFSET; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FB + offset, work & 0xffffffff); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_FBU + offset, work >> 32); /* activate the channel and power/spin up device */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, (ATA_AHCI_P_CMD_ACTIVE | ATA_AHCI_P_CMD_POD | ATA_AHCI_P_CMD_SUD)); ata_ahci_start_fr(dev); ata_ahci_start(dev); return (0); } static int ata_ahci_status(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t action = ATA_INL(ctlr->r_res2, ATA_AHCI_IS); int offset = ch->unit << 7; #define ATA_AHCI_STATBITS \ (ATA_AHCI_P_IX_IF|ATA_AHCI_P_IX_HBD|ATA_AHCI_P_IX_HBF|ATA_AHCI_P_IX_TFE) if (action & (1 << ch->unit)) { u_int32_t istatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset); u_int32_t cstatus = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset); /* clear interrupt(s) */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, istatus); ATA_OUTL(ctlr->r_res2, ATA_AHCI_IS, 1 << ch->unit); /* do we have any PHY events ? */ if (istatus & (ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)) ata_sata_phy_check_events(dev); /* do we have a potentially hanging engine to take care of? */ /* XXX SOS what todo on NCQ */ if ((istatus & ATA_AHCI_STATBITS) && (cstatus & 1)) { u_int32_t cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); int timeout = 0; /* kill off all activity on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~(ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); /* XXX SOS this is not entirely wrong */ do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); /* start operations on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | (ATA_AHCI_P_CMD_FRE | ATA_AHCI_P_CMD_ST)); return 1; } else /* XXX SOS what todo on NCQ */ return (!(cstatus & 1)); } return 0; } /* must be called with ATA channel locked and state_mtx held */ static int ata_ahci_begin_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); struct ata_channel *ch = device_get_softc(request->parent); struct ata_device *atadev = device_get_softc(request->dev); struct ata_ahci_cmd_tab *ctp; struct ata_ahci_cmd_list *clp; int offset = ch->unit << 7; int port = atadev->unit & 0x0f; int entries = 0; int fis_size; /* get a piece of the workspace for this request */ ctp = (struct ata_ahci_cmd_tab *) (ch->dma.work + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE*request->tag)); /* setup the FIS for this request */ if (!(fis_size = ata_ahci_setup_fis(ctp, request))) { device_printf(request->dev, "setting up SATA FIS failed\n"); request->result = EIO; return ATA_OP_FINISHED; } /* if request moves data setup and load SG list */ if (request->flags & (ATA_R_READ | ATA_R_WRITE)) { if (ch->dma.load(request, ctp->prd_tab, &entries)) { device_printf(request->dev, "setting up DMA failed\n"); request->result = EIO; return ATA_OP_FINISHED; } } /* setup the command list entry */ clp = (struct ata_ahci_cmd_list *) (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); clp->prd_length = entries; clp->cmd_flags = (request->flags & ATA_R_WRITE ? ATA_AHCI_CMD_WRITE : 0) | (request->flags & ATA_R_ATAPI ? (ATA_AHCI_CMD_ATAPI | ATA_AHCI_CMD_PREFETCH) : 0) | (fis_size / sizeof(u_int32_t)) | (port << 12); clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET + (ATA_AHCI_CT_SIZE * request->tag)); /* clear eventual ACTIVE bit */ ATA_IDX_OUTL(ch, ATA_SACTIVE, ATA_IDX_INL(ch, ATA_SACTIVE) & (1 << request->tag)); /* set command type bit */ if (request->flags & ATA_R_ATAPI) ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) | ATA_AHCI_P_CMD_ATAPI); else ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ~ATA_AHCI_P_CMD_ATAPI); /* issue command to controller */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, (1 << request->tag)); if (!(request->flags & ATA_R_ATAPI)) { /* device reset doesn't interrupt */ if (request->u.ata.command == ATA_DEVICE_RESET) { u_int32_t tf_data; int timeout = 1000000; do { DELAY(10); tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + (ch->unit<<7)); } while ((tf_data & ATA_S_BUSY) && timeout--); if (bootverbose) device_printf(ch->dev, "device_reset timeout=%dus\n", (1000000-timeout)*10); request->status = tf_data; if (request->status & ATA_S_ERROR) request->error = tf_data >> 8; return ATA_OP_FINISHED; } } /* start the timeout */ callout_reset(&request->callout, request->timeout * hz, (timeout_t*)ata_timeout, request); return ATA_OP_CONTINUES; } /* must be called with ATA channel locked and state_mtx held */ static int ata_ahci_end_transaction(struct ata_request *request) { struct ata_pci_controller *ctlr=device_get_softc(GRANDPARENT(request->dev)); struct ata_channel *ch = device_get_softc(request->parent); struct ata_ahci_cmd_list *clp; u_int32_t tf_data; int offset = ch->unit << 7; /* kill the timeout */ callout_stop(&request->callout); /* get status */ tf_data = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset); request->status = tf_data; /* if error status get details */ if (request->status & ATA_S_ERROR) request->error = tf_data >> 8; /* on control commands read back registers to the request struct */ if (request->flags & ATA_R_CONTROL) { struct ata_device *atadev = device_get_softc(request->dev); u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; request->u.ata.count = fis[12] | ((u_int16_t)fis[13] << 8); request->u.ata.lba = fis[4] | ((u_int64_t)fis[5] << 8) | ((u_int64_t)fis[6] << 16); if (atadev->flags & ATA_D_48BIT_ACTIVE) request->u.ata.lba |= ((u_int64_t)fis[8] << 24) | ((u_int64_t)fis[9] << 32) | ((u_int64_t)fis[10] << 40); else request->u.ata.lba |= ((u_int64_t)(fis[7] & 0x0f) << 24); } /* record how much data we actually moved */ clp = (struct ata_ahci_cmd_list *) (ch->dma.work + ATA_AHCI_CL_OFFSET + (ATA_AHCI_CL_SIZE*request->tag)); request->donecount = clp->bytecount; /* release SG list etc */ ch->dma.unload(request); return ATA_OP_FINISHED; } static int ata_ahci_issue_cmd(device_t dev, u_int16_t flags, int timeout) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_list *clp = (struct ata_ahci_cmd_list *)(ch->dma.work + ATA_AHCI_CL_OFFSET); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); u_int32_t status = 0; int offset = ch->unit << 7; int port = (ctp->cfis[1] & 0x0f); int count; clp->prd_length = 0; clp->cmd_flags = (20 / sizeof(u_int32_t)) | flags | (port << 12); clp->bytecount = 0; clp->cmd_table_phys = htole64(ch->dma.work_bus + ATA_AHCI_CT_OFFSET); /* issue command to controller */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CI + offset, 1); /* poll for command finished */ for (count = 0; count < timeout; count++) { DELAY(1000); if (!((status = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CI + offset)) & 1)) break; } /* clear interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); if (timeout && (count >= timeout)) { if (bootverbose) { device_printf(dev, "ahci_issue_cmd timeout: %d of %dms, status=%08x\n", count, timeout, status); } return EIO; } return 0; } static int ata_ahci_pm_read(device_t dev, int port, int reg, u_int32_t *result) { struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); u_int8_t *fis = ch->dma.work + ATA_AHCI_FB_OFFSET + 0x40; bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ ctp->cfis[2] = ATA_READ_PM; ctp->cfis[3] = reg; ctp->cfis[7] = port | ATA_D_LBA; ctp->cfis[15] = ATA_A_4BIT; if (ata_ahci_issue_cmd(dev, 0, 10)) { device_printf(dev, "error reading PM port\n"); return EIO; } *result = fis[12] | (fis[4] << 8) | (fis[5] << 16) | (fis[6] << 24); return 0; } static int ata_ahci_pm_write(device_t dev, int port, int reg, u_int32_t value) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); int offset = ch->unit << 7; bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; /* host to device */ ctp->cfis[1] = 0x8f; /* command FIS to PM port */ ctp->cfis[2] = ATA_WRITE_PM; ctp->cfis[3] = reg; ctp->cfis[7] = port | ATA_D_LBA; ctp->cfis[12] = value & 0xff; ctp->cfis[4] = (value >> 8) & 0xff;; ctp->cfis[5] = (value >> 16) & 0xff;; ctp->cfis[6] = (value >> 24) & 0xff;; ctp->cfis[15] = ATA_A_4BIT; if (ata_ahci_issue_cmd(dev, 0, 100)) { device_printf(dev, "error writing PM port\n"); return ATA_E_ABORT; } return (ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset) >> 8) & 0xff; } static void ata_ahci_stop(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_ST); /* XXX SOS this is not entirely wrong */ timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_CR); } static void ata_ahci_clo(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* issue Command List Override if supported */ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_CLO) { cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); cmd |= ATA_AHCI_P_CMD_CLO; ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd); timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "executing CLO failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD+offset)&ATA_AHCI_P_CMD_CLO); } } static void ata_ahci_start(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; /* clear SATA error register */ ATA_IDX_OUTL(ch, ATA_SERROR, ATA_IDX_INL(ch, ATA_SERROR)); /* clear any interrupts pending on this channel */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IS + offset, ATA_INL(ctlr->r_res2, ATA_AHCI_P_IS + offset)); /* start operations on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_ST | (ch->devices & ATA_PORTMULTIPLIER ? ATA_AHCI_P_CMD_PMA : 0)); } static void ata_ahci_stop_fr(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; int timeout; /* kill off all activity on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd & ~ATA_AHCI_P_CMD_FRE); timeout = 0; do { DELAY(1000); if (timeout++ > 1000) { device_printf(dev, "stopping AHCI FR engine failed\n"); break; } } while (ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset) & ATA_AHCI_P_CMD_FR); } static void ata_ahci_start_fr(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t cmd; int offset = ch->unit << 7; /* start FIS reception on this channel */ cmd = ATA_INL(ctlr->r_res2, ATA_AHCI_P_CMD + offset); ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_CMD + offset, cmd | ATA_AHCI_P_CMD_FRE); } static int ata_ahci_wait_ready(device_t dev, int t) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; int timeout = 0; uint32_t val; while ((val = ATA_INL(ctlr->r_res2, ATA_AHCI_P_TFD + offset)) & (ATA_S_BUSY | ATA_S_DRQ)) { DELAY(1000); if (timeout++ > t) { device_printf(dev, "port is not ready (timeout %dms) tfd = %08x\n", t, val); return (EBUSY); } } if (bootverbose) device_printf(dev, "ready wait time=%dms\n", timeout); return (0); } static int ata_ahci_hardreset(device_t dev, int port, uint32_t *signature) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; *signature = 0xffffffff; ata_ahci_stop(dev); /* Reset port */ if (!ata_sata_phy_reset(dev, port, 0)) return (ENOENT); /* Wait for clearing busy status. */ if (ata_ahci_wait_ready(dev, 10000)) { device_printf(dev, "hardware reset timeout\n"); return (EBUSY); } *signature = ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); ata_ahci_start(dev); return (0); } static u_int32_t ata_ahci_softreset(device_t dev, int port) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); int offset = ch->unit << 7; struct ata_ahci_cmd_tab *ctp = (struct ata_ahci_cmd_tab *)(ch->dma.work + ATA_AHCI_CT_OFFSET); if (bootverbose) device_printf(dev, "software reset port %d...\n", port); /* kick controller into sane state */ ata_ahci_stop(dev); ata_ahci_clo(dev); ata_ahci_start(dev); /* pull reset active */ bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; ctp->cfis[1] = port & 0x0f; //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; ctp->cfis[15] = (ATA_A_4BIT | ATA_A_RESET); if (ata_ahci_issue_cmd(dev, ATA_AHCI_CMD_RESET | ATA_AHCI_CMD_CLR_BUSY,100)) { device_printf(dev, "software reset set timeout\n"); return (-1); } ata_udelay(50); /* pull reset inactive -> device softreset */ bzero(ctp->cfis, 64); ctp->cfis[0] = 0x27; ctp->cfis[1] = port & 0x0f; //ctp->cfis[7] = ATA_D_LBA | ATA_D_IBM; ctp->cfis[15] = ATA_A_4BIT; ata_ahci_issue_cmd(dev, 0, 3000); if (ata_ahci_wait_ready(dev, 0)) { device_printf(dev, "software reset clear timeout\n"); return (-1); } return ATA_INL(ctlr->r_res2, ATA_AHCI_P_SIG + offset); } void ata_ahci_reset(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); u_int32_t signature; int offset = ch->unit << 7; if (bootverbose) device_printf(dev, "AHCI reset...\n"); /* Disable port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, 0); if (ata_ahci_hardreset(dev, -1, &signature)) { if (bootverbose) device_printf(dev, "AHCI reset done: phy reset found no device\n"); ch->devices = 0; /* enable wanted port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC)); return; } /* enable wanted port interrupts */ ATA_OUTL(ctlr->r_res2, ATA_AHCI_P_IE + offset, (ATA_AHCI_P_IX_CPD | ATA_AHCI_P_IX_TFE | ATA_AHCI_P_IX_HBF | ATA_AHCI_P_IX_HBD | ATA_AHCI_P_IX_IF | ATA_AHCI_P_IX_OF | ATA_AHCI_P_IX_PRC | ATA_AHCI_P_IX_PC | ATA_AHCI_P_IX_DP | ATA_AHCI_P_IX_UF | ATA_AHCI_P_IX_SDB | ATA_AHCI_P_IX_DS | ATA_AHCI_P_IX_PS | ATA_AHCI_P_IX_DHR)); /* only probe for PortMultiplier if HW has support */ if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_SPM) { signature = ata_ahci_softreset(dev, ATA_PM); /* Workaround for some ATI chips, failing to soft-reset * when port multiplicator supported, but absent. * XXX: We can also check PxIS.IPMS==1 here to be sure. */ if (signature == 0xffffffff) signature = ata_ahci_softreset(dev, 0); } else { signature = ata_ahci_softreset(dev, 0); } if (bootverbose) device_printf(dev, "SIGNATURE: %08x\n", signature); switch (signature >> 16) { case 0x0000: ch->devices = ATA_ATA_MASTER; break; case 0x9669: ch->devices = ATA_PORTMULTIPLIER; ata_pm_identify(dev); break; case 0xeb14: ch->devices = ATA_ATAPI_MASTER; break; default: /* SOS XXX */ if (bootverbose) device_printf(dev, "Unknown signature, assuming disk device\n"); ch->devices = ATA_ATA_MASTER; } if (bootverbose) device_printf(dev, "AHCI reset done: devices=%08x\n", ch->devices); } static void ata_ahci_dmasetprd(void *xsc, bus_dma_segment_t *segs, int nsegs, int error) { struct ata_dmasetprd_args *args = xsc; struct ata_ahci_dma_prd *prd = args->dmatab; int i; if (!(args->error = error)) { for (i = 0; i < nsegs; i++) { prd[i].dba = htole64(segs[i].ds_addr); prd[i].dbc = htole32((segs[i].ds_len - 1) & ATA_AHCI_PRD_MASK); } } KASSERT(nsegs <= ATA_AHCI_DMA_ENTRIES, ("too many DMA segment entries\n")); args->nsegs = nsegs; } static void ata_ahci_dmainit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev)); struct ata_channel *ch = device_get_softc(dev); ata_dmainit(dev); /* note start and stop are not used here */ ch->dma.setprd = ata_ahci_dmasetprd; ch->dma.max_iosize = 8192 * DEV_BSIZE; if (ATA_INL(ctlr->r_res2, ATA_AHCI_CAP) & ATA_AHCI_CAP_64BIT) ch->dma.max_address = BUS_SPACE_MAXADDR; } static int ata_ahci_setup_fis(struct ata_ahci_cmd_tab *ctp, struct ata_request *request) { bzero(ctp->cfis, 64); if (request->flags & ATA_R_ATAPI) { bzero(ctp->acmd, 32); bcopy(request->u.atapi.ccb, ctp->acmd, 16); } return ata_request2fis_h2d(request, &ctp->cfis[0]); } ATA_DECLARE_DRIVER(ata_ahci); Index: head/sys/dev/ata/chipsets/ata-ati.c =================================================================== --- head/sys/dev/ata/chipsets/ata-ati.c (revision 191567) +++ head/sys/dev/ata/chipsets/ata-ati.c (revision 191568) @@ -1,197 +1,261 @@ /*- * Copyright (c) 1998 - 2008 Søren Schmidt * 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 "opt_ata.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include /* local prototypes */ static int ata_ati_chipinit(device_t dev); static void ata_ati_setmode(device_t dev, int mode); +static void ata_ati_ahci_enable(device_t dev); +static int ata_ati_ahci_chipinit(device_t dev); +static int ata_ati_ahci_resume(device_t dev); /* misc defines */ #define ATI_PATA 0x01 #define ATI_SATA 0x02 #define ATI_AHCI 0x04 #define SII_MEMIO 1 #define SII_BUG 0x04 +/* Misc Control Register */ +#define ATI_PCI_MISC_CTRL 0x40 +#define ATI_PCI_MISCCTRL_ENABLE_WR 0x00000001 +/* Watchdog Control/Status Register */ +#define ATI_PCI_WD_CTRL 0x44 +#define ATI_PCI_WDCTRL_ENABLE 0x0001 + /* * ATI chipset support functions */ static int ata_ati_probe(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); static struct ata_chip_id ids[] = {{ ATA_ATI_IXP200, 0x00, ATI_PATA, 0, ATA_UDMA5, "IXP200" }, { ATA_ATI_IXP300, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP300" }, { ATA_ATI_IXP300_S1, 0x00, ATI_SATA, 0, ATA_SA150, "IXP300" }, { ATA_ATI_IXP400, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP400" }, { ATA_ATI_IXP400_S1, 0x00, ATI_SATA, 0, ATA_SA150, "IXP400" }, { ATA_ATI_IXP400_S2, 0x00, ATI_SATA, 0, ATA_SA150, "IXP400" }, { ATA_ATI_IXP600, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP600" }, { ATA_ATI_IXP600_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP600" }, - { ATA_ATI_IXP700, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP700" }, - { ATA_ATI_IXP700_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700" }, + { ATA_ATI_IXP700, 0x00, ATI_PATA, 0, ATA_UDMA6, "IXP700/800" }, + { ATA_ATI_IXP700_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" }, + { ATA_ATI_IXP700_S2, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" }, + { ATA_ATI_IXP700_S3, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" }, + { ATA_ATI_IXP700_S4, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP700/800" }, + { ATA_ATI_IXP800_S1, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP800" }, + { ATA_ATI_IXP800_S2, 0x00, ATI_AHCI, 0, ATA_SA300, "IXP800" }, { 0, 0, 0, 0, 0, 0}}; if (pci_get_vendor(dev) != ATA_ATI_ID) return ENXIO; if (!(ctlr->chip = ata_match_chip(dev, ids))) return ENXIO; ata_set_desc(dev); switch (ctlr->chip->cfg1) { case ATI_PATA: ctlr->chipinit = ata_ati_chipinit; break; case ATI_SATA: /* * the ATI SATA controller is actually a SiI 3112 controller * cfg values below much match those in ata-siliconimage.c */ ctlr->chip->cfg1 = SII_MEMIO; ctlr->chip->cfg2 = SII_BUG; ctlr->chipinit = ata_sii_chipinit; break; case ATI_AHCI: - ctlr->chipinit = ata_ahci_chipinit; + /* + * Force AHCI mode if IDE mode is set from BIOS. + */ + if ((ctlr->chip->chipid == ATA_ATI_IXP600_S1 || + ctlr->chip->chipid == ATA_ATI_IXP700_S1) && + pci_get_subclass(dev) == PCIS_STORAGE_IDE) { + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + cfg->subclass = PCIS_STORAGE_SATA; + cfg->progif = PCIP_STORAGE_SATA_AHCI_1_0; + ata_ati_ahci_enable(dev); + } + ctlr->chipinit = ata_ati_ahci_chipinit; break; } return 0; } static int ata_ati_chipinit(device_t dev) { struct ata_pci_controller *ctlr = device_get_softc(dev); if (ata_setup_interrupt(dev, ata_generic_intr)) return ENXIO; - /* IXP600 & IXP700 only have 1 PATA channel */ - if ((ctlr->chip->chipid == ATA_ATI_IXP600) || - (ctlr->chip->chipid == ATA_ATI_IXP700)) + /* IXP600 only has 1 PATA channel */ + if (ctlr->chip->chipid == ATA_ATI_IXP600) ctlr->channels = 1; ctlr->setmode = ata_ati_setmode; return 0; } static void ata_ati_setmode(device_t dev, int mode) { device_t gparent = GRANDPARENT(dev); struct ata_pci_controller *ctlr = device_get_softc(gparent); struct ata_channel *ch = device_get_softc(device_get_parent(dev)); struct ata_device *atadev = device_get_softc(dev); int devno = (ch->unit << 1) + atadev->unit; int offset = (devno ^ 0x01) << 3; int error; u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 }; mode = ata_limit_mode(dev, mode, ctlr->chip->max_dma); mode = ata_check_80pin(dev, mode); error = ata_controlcmd(dev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode); if (bootverbose) device_printf(dev, "%ssetting %s on %s chip\n", (error) ? "FAILURE " : "", ata_mode2str(mode), ctlr->chip->text); if (!error) { if (mode >= ATA_UDMA0) { pci_write_config(gparent, 0x56, (pci_read_config(gparent, 0x56, 2) & ~(0xf << (devno << 2))) | ((mode & ATA_MODE_MASK) << (devno << 2)), 2); pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) | (0x01 << devno), 1); pci_write_config(gparent, 0x44, (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[2] << offset), 4); } else if (mode >= ATA_WDMA0) { pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); pci_write_config(gparent, 0x44, (pci_read_config(gparent, 0x44, 4) & ~(0xff << offset)) | (dmatimings[mode & ATA_MODE_MASK] << offset), 4); } else pci_write_config(gparent, 0x54, pci_read_config(gparent, 0x54, 1) & ~(0x01 << devno), 1); pci_write_config(gparent, 0x4a, (pci_read_config(gparent, 0x4a, 2) & ~(0xf << (devno << 2))) | (((mode - ATA_PIO0) & ATA_MODE_MASK) << (devno<<2)),2); pci_write_config(gparent, 0x40, (pci_read_config(gparent, 0x40, 4) & ~(0xff << offset)) | (piotimings[ata_mode2idx(mode)] << offset), 4); atadev->mode = mode; } +} + +static void +ata_ati_ahci_enable(device_t dev) +{ + struct pci_devinfo *dinfo = device_get_ivars(dev); + pcicfgregs *cfg = &dinfo->cfg; + uint32_t ctrl; + + ctrl = pci_read_config(dev, ATI_PCI_MISC_CTRL, 4); + pci_write_config(dev, ATI_PCI_MISC_CTRL, + ctrl | ATI_PCI_MISCCTRL_ENABLE_WR, 4); + pci_write_config(dev, PCIR_SUBCLASS, cfg->subclass, 1); + pci_write_config(dev, PCIR_PROGIF, cfg->progif, 1); + pci_write_config(dev, ATI_PCI_WD_CTRL, + pci_read_config(dev, ATI_PCI_WD_CTRL, 2) | ATI_PCI_WDCTRL_ENABLE, 2); + pci_write_config(dev, ATI_PCI_MISC_CTRL, + ctrl & ~ATI_PCI_MISCCTRL_ENABLE_WR, 4); +} + +static int +ata_ati_ahci_chipinit(device_t dev) +{ + struct ata_pci_controller *ctlr = device_get_softc(dev); + int error; + + error = ata_ahci_chipinit(dev); + ctlr->resume = ata_ati_ahci_resume; + return (error); +} + +static int +ata_ati_ahci_resume(device_t dev) +{ + + ata_ati_ahci_enable(dev); + return (ata_ahci_ctlr_reset(dev)); } ATA_DECLARE_DRIVER(ata_ati); MODULE_DEPEND(ata_ati, ata_ahci, 1, 1, 1); MODULE_DEPEND(ata_ati, ata_sii, 1, 1, 1);