12fcbc377Syt /*
22fcbc377Syt  * CDDL HEADER START
32fcbc377Syt  *
42fcbc377Syt  * The contents of this file are subject to the terms of the
52fcbc377Syt  * Common Development and Distribution License (the "License").
62fcbc377Syt  * You may not use this file except in compliance with the License.
72fcbc377Syt  *
82fcbc377Syt  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92fcbc377Syt  * or http://www.opensolaris.org/os/licensing.
102fcbc377Syt  * See the License for the specific language governing permissions
112fcbc377Syt  * and limitations under the License.
122fcbc377Syt  *
132fcbc377Syt  * When distributing Covered Code, include this CDDL HEADER in each
142fcbc377Syt  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152fcbc377Syt  * If applicable, add the following below this CDDL HEADER, with the
162fcbc377Syt  * fields enclosed by brackets "[]" replaced with your own identifying
172fcbc377Syt  * information: Portions Copyright [yyyy] [name of copyright owner]
182fcbc377Syt  *
192fcbc377Syt  * CDDL HEADER END
202fcbc377Syt  */
212fcbc377Syt 
222fcbc377Syt /*
23b22851f1SXiao-Yu Zhang  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
24d8873b31SJoyce McIntosh  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
25fd6d41c5SRobert Mustacchi  * Copyright (c) 2018, Joyent, Inc.
2644a84c18SAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
272fcbc377Syt  */
282fcbc377Syt 
292fcbc377Syt /*
302fcbc377Syt  * AHCI (Advanced Host Controller Interface) SATA HBA Driver
3113bcbb7aSyt  *
3213bcbb7aSyt  * Power Management Support
3313bcbb7aSyt  * ------------------------
3413bcbb7aSyt  *
3513bcbb7aSyt  * At the moment, the ahci driver only implements suspend/resume to
3613bcbb7aSyt  * support Suspend to RAM on X86 feature. Device power management isn't
3713bcbb7aSyt  * implemented, link power management is disabled, and hot plug isn't
3813bcbb7aSyt  * allowed during the period from suspend to resume.
3913bcbb7aSyt  *
4013bcbb7aSyt  * For s/r support, the ahci driver only need to implement DDI_SUSPEND
4113bcbb7aSyt  * and DDI_RESUME entries, and don't need to take care of new requests
4213bcbb7aSyt  * sent down after suspend because the target driver (sd) has already
4313bcbb7aSyt  * handled these conditions, and blocked these requests. For the detailed
4413bcbb7aSyt  * information, please check with sdopen, sdclose and sdioctl routines.
4513bcbb7aSyt  *
46fd6d41c5SRobert Mustacchi  *
47fd6d41c5SRobert Mustacchi  * Enclosure Management Support
48fd6d41c5SRobert Mustacchi  * ----------------------------
49fd6d41c5SRobert Mustacchi  *
50fd6d41c5SRobert Mustacchi  * The ahci driver has basic support for AHCI Enclosure Management (EM)
51fd6d41c5SRobert Mustacchi  * services. The AHCI specification provides an area in the primary ahci BAR for
52fd6d41c5SRobert Mustacchi  * posting data to send out to the enclosure management and provides a register
53fd6d41c5SRobert Mustacchi  * that provides both information and control about this. While the
54fd6d41c5SRobert Mustacchi  * specification allows for multiple forms of enclosure management, the only
55fd6d41c5SRobert Mustacchi  * supported, and commonly found form, is the AHCI specified LED format. The LED
56fd6d41c5SRobert Mustacchi  * format is often implemented as a one-way communication mechanism. Software
57fd6d41c5SRobert Mustacchi  * can write out what it cares about into the aforementioned data buffer and
58fd6d41c5SRobert Mustacchi  * then we wait for the transmission to be sent.
59fd6d41c5SRobert Mustacchi  *
60fd6d41c5SRobert Mustacchi  * This has some drawbacks. It means that we cannot know whether or not it has
61fd6d41c5SRobert Mustacchi  * succeeded. This means we cannot ask hardware what it thinks the LEDs are
62fd6d41c5SRobert Mustacchi  * set to. There's also the added unfortunate reality that firmware on the
63fd6d41c5SRobert Mustacchi  * microcontroller driving this will often not show the LEDs if no drive is
64fd6d41c5SRobert Mustacchi  * present and that actions taken may potentially cause this to get out of sync
65fd6d41c5SRobert Mustacchi  * with what we expect it to be. For example, the specification does not
66fd6d41c5SRobert Mustacchi  * describe what should happen if a drive is removed from the enclosure while
67fd6d41c5SRobert Mustacchi  * this is set and what should happen when it returns. We can only infer that it
68fd6d41c5SRobert Mustacchi  * should be the same.
69fd6d41c5SRobert Mustacchi  *
70fd6d41c5SRobert Mustacchi  * Because only a single command can be sent at any time and we don't want to
71fd6d41c5SRobert Mustacchi  * interfere with controller I/O, we create a taskq dedicated to this that has a
72fd6d41c5SRobert Mustacchi  * single thread. Both resets (which occur on attach and resume) and normal
73fd6d41c5SRobert Mustacchi  * changes to the LED state will be driven through this taskq. Because the taskq
74fd6d41c5SRobert Mustacchi  * has a single thread, this guarantees serial processing.
75fd6d41c5SRobert Mustacchi  *
76fd6d41c5SRobert Mustacchi  * Each userland-submitted task (basically not resets) has a reference counted
77fd6d41c5SRobert Mustacchi  * task structure. This allows the thread that called it to be cancelled and
78fd6d41c5SRobert Mustacchi  * have the system clean itself up. The user thread in ioctl blocks on a CV that
79fd6d41c5SRobert Mustacchi  * can receive signals as it waits for completion.  Note, there is no guarantee
80fd6d41c5SRobert Mustacchi  * provided by the kernel that the first thread to enter the kernel will be the
81fd6d41c5SRobert Mustacchi  * first one to change state.
822fcbc377Syt  */
832fcbc377Syt 
84689d74b0Syt #include <sys/note.h>
852fcbc377Syt #include <sys/scsi/scsi.h>
862fcbc377Syt #include <sys/pci.h>
87b2e3645aSying tian - Beijing China #include <sys/disp.h>
882fcbc377Syt #include <sys/sata/sata_hba.h>
892fcbc377Syt #include <sys/sata/adapters/ahci/ahcireg.h>
902fcbc377Syt #include <sys/sata/adapters/ahci/ahcivar.h>
912fcbc377Syt 
92b22851f1SXiao-Yu Zhang /*
93b22851f1SXiao-Yu Zhang  * FMA header files
94b22851f1SXiao-Yu Zhang  */
95b22851f1SXiao-Yu Zhang #include <sys/ddifm.h>
96b22851f1SXiao-Yu Zhang #include <sys/fm/protocol.h>
97b22851f1SXiao-Yu Zhang #include <sys/fm/util.h>
98b22851f1SXiao-Yu Zhang #include <sys/fm/io/ddi.h>
99b22851f1SXiao-Yu Zhang 
100fd6d41c5SRobert Mustacchi /*
101fd6d41c5SRobert Mustacchi  * EM Control header files
102fd6d41c5SRobert Mustacchi  */
103fd6d41c5SRobert Mustacchi #include <sys/types.h>
104fd6d41c5SRobert Mustacchi #include <sys/file.h>
105fd6d41c5SRobert Mustacchi #include <sys/errno.h>
106fd6d41c5SRobert Mustacchi #include <sys/open.h>
107fd6d41c5SRobert Mustacchi #include <sys/cred.h>
108fd6d41c5SRobert Mustacchi #include <sys/ddi.h>
109fd6d41c5SRobert Mustacchi #include <sys/sunddi.h>
110fd6d41c5SRobert Mustacchi 
11119397407SSherry Moore /*
11219397407SSherry Moore  * This is the string displayed by modinfo, etc.
11319397407SSherry Moore  */
11419397407SSherry Moore static char ahci_ident[] = "ahci driver";
11519397407SSherry Moore 
1162fcbc377Syt /*
1172fcbc377Syt  * Function prototypes for driver entry points
1182fcbc377Syt  */
1192fcbc377Syt static	int ahci_attach(dev_info_t *, ddi_attach_cmd_t);
1202fcbc377Syt static	int ahci_detach(dev_info_t *, ddi_detach_cmd_t);
1212fcbc377Syt static	int ahci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
12219397407SSherry Moore static	int ahci_quiesce(dev_info_t *);
1232fcbc377Syt 
1242fcbc377Syt /*
1252fcbc377Syt  * Function prototypes for SATA Framework interfaces
1262fcbc377Syt  */
1272fcbc377Syt static	int ahci_register_sata_hba_tran(ahci_ctl_t *, uint32_t);
1282fcbc377Syt static	int ahci_unregister_sata_hba_tran(ahci_ctl_t *);
1292fcbc377Syt 
1302fcbc377Syt static	int ahci_tran_probe_port(dev_info_t *, sata_device_t *);
1312fcbc377Syt static	int ahci_tran_start(dev_info_t *, sata_pkt_t *spkt);
1322fcbc377Syt static	int ahci_tran_abort(dev_info_t *, sata_pkt_t *, int);
1332fcbc377Syt static	int ahci_tran_reset_dport(dev_info_t *, sata_device_t *);
1342fcbc377Syt static	int ahci_tran_hotplug_port_activate(dev_info_t *, sata_device_t *);
1352fcbc377Syt static	int ahci_tran_hotplug_port_deactivate(dev_info_t *, sata_device_t *);
1362fcbc377Syt #if defined(__lock_lint)
1372fcbc377Syt static	int ahci_selftest(dev_info_t *, sata_device_t *);
1382fcbc377Syt #endif
1392fcbc377Syt 
140b22851f1SXiao-Yu Zhang /*
141b22851f1SXiao-Yu Zhang  * FMA Prototypes
142b22851f1SXiao-Yu Zhang  */
143b22851f1SXiao-Yu Zhang static	void ahci_fm_init(ahci_ctl_t *);
144b22851f1SXiao-Yu Zhang static	void ahci_fm_fini(ahci_ctl_t *);
145b22851f1SXiao-Yu Zhang static	int ahci_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void*);
146b22851f1SXiao-Yu Zhang int	ahci_check_acc_handle(ddi_acc_handle_t);
147b22851f1SXiao-Yu Zhang int	ahci_check_dma_handle(ddi_dma_handle_t);
148b22851f1SXiao-Yu Zhang void	ahci_fm_ereport(ahci_ctl_t *, char *);
149b22851f1SXiao-Yu Zhang static	int ahci_check_all_handle(ahci_ctl_t *);
150b22851f1SXiao-Yu Zhang static	int ahci_check_ctl_handle(ahci_ctl_t *);
151b22851f1SXiao-Yu Zhang static	int ahci_check_port_handle(ahci_ctl_t *, int);
152b22851f1SXiao-Yu Zhang static	int ahci_check_slot_handle(ahci_port_t *, int);
153b22851f1SXiao-Yu Zhang 
1542fcbc377Syt /*
1552fcbc377Syt  * Local function prototypes
1562fcbc377Syt  */
1572ac30289SMarcel Telka static	int ahci_setup_port_base_addresses(ahci_ctl_t *, ahci_port_t *);
15868d33a25Syt static	int ahci_alloc_ports_state(ahci_ctl_t *);
15968d33a25Syt static	void ahci_dealloc_ports_state(ahci_ctl_t *);
1602fcbc377Syt static	int ahci_alloc_port_state(ahci_ctl_t *, uint8_t);
1612fcbc377Syt static	void ahci_dealloc_port_state(ahci_ctl_t *, uint8_t);
1622ac30289SMarcel Telka static	int ahci_alloc_rcvd_fis(ahci_ctl_t *, ahci_port_t *);
163689d74b0Syt static	void ahci_dealloc_rcvd_fis(ahci_port_t *);
1642ac30289SMarcel Telka static	int ahci_alloc_cmd_list(ahci_ctl_t *, ahci_port_t *);
1652fcbc377Syt static	void ahci_dealloc_cmd_list(ahci_ctl_t *, ahci_port_t *);
1662fcbc377Syt static  int ahci_alloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
1672fcbc377Syt static  void ahci_dealloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
1688aa6aadbSXiao-Yu Zhang static	void ahci_alloc_pmult(ahci_ctl_t *, ahci_port_t *);
1698aa6aadbSXiao-Yu Zhang static	void ahci_dealloc_pmult(ahci_ctl_t *, ahci_port_t *);
1702fcbc377Syt 
17168d33a25Syt static	int ahci_initialize_controller(ahci_ctl_t *);
17268d33a25Syt static	void ahci_uninitialize_controller(ahci_ctl_t *);
1738aa6aadbSXiao-Yu Zhang static	int ahci_initialize_port(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
17413bcbb7aSyt static	int ahci_config_space_init(ahci_ctl_t *);
1752ac30289SMarcel Telka static	void ahci_staggered_spin_up(ahci_ctl_t *, uint8_t);
17668d33a25Syt 
177f8a673adSying tian - Beijing China static	void ahci_drain_ports_taskq(ahci_ctl_t *);
1788aa6aadbSXiao-Yu Zhang static	int ahci_rdwr_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t *,
1798aa6aadbSXiao-Yu Zhang     uint8_t);
1808aa6aadbSXiao-Yu Zhang static	int ahci_read_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t *);
1818aa6aadbSXiao-Yu Zhang static	int ahci_write_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t);
1828aa6aadbSXiao-Yu Zhang static	int ahci_update_pmult_pscr(ahci_ctl_t *, ahci_addr_t *,
1838aa6aadbSXiao-Yu Zhang     sata_device_t *);
1848aa6aadbSXiao-Yu Zhang static	int ahci_update_pmult_gscr(ahci_ctl_t *, ahci_addr_t *,
185918304a3SXiao-Yu Zhang     sata_pmult_gscr_t *);
1868aa6aadbSXiao-Yu Zhang static	int ahci_initialize_pmult(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *,
1878aa6aadbSXiao-Yu Zhang     sata_device_t *);
1888aa6aadbSXiao-Yu Zhang static	int ahci_initialize_pmport(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
1898aa6aadbSXiao-Yu Zhang static	int ahci_probe_pmult(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
1908aa6aadbSXiao-Yu Zhang static	int ahci_probe_pmport(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *,
1918aa6aadbSXiao-Yu Zhang     sata_device_t *);
1928aa6aadbSXiao-Yu Zhang 
19313bcbb7aSyt static	void ahci_disable_interface_pm(ahci_ctl_t *, uint8_t);
19468d33a25Syt static	int ahci_start_port(ahci_ctl_t *, ahci_port_t *, uint8_t);
1958aa6aadbSXiao-Yu Zhang static	void ahci_find_dev_signature(ahci_ctl_t *, ahci_port_t *,
1968aa6aadbSXiao-Yu Zhang     ahci_addr_t *);
1972fcbc377Syt static	void ahci_update_sata_registers(ahci_ctl_t *, uint8_t, sata_device_t *);
1982fcbc377Syt static	int ahci_deliver_satapkt(ahci_ctl_t *, ahci_port_t *,
1998aa6aadbSXiao-Yu Zhang     ahci_addr_t *, sata_pkt_t *);
20068d33a25Syt static	int ahci_do_sync_start(ahci_ctl_t *, ahci_port_t *,
2018aa6aadbSXiao-Yu Zhang     ahci_addr_t *, sata_pkt_t *);
2028aa6aadbSXiao-Yu Zhang static	int ahci_claim_free_slot(ahci_ctl_t *, ahci_port_t *,
2038aa6aadbSXiao-Yu Zhang     ahci_addr_t *, int);
20468d33a25Syt static  void ahci_copy_err_cnxt(sata_cmd_t *, ahci_fis_d2h_register_t *);
20582263d52Syt static	void ahci_copy_ncq_err_page(sata_cmd_t *,
20682263d52Syt     struct sata_ncq_error_recovery_page *);
2072fcbc377Syt static	void ahci_copy_out_regs(sata_cmd_t *, ahci_fis_d2h_register_t *);
2086b62a236Sying tian - Beijing China static	void ahci_add_doneq(ahci_port_t *, sata_pkt_t *, int);
2096b62a236Sying tian - Beijing China static	void ahci_flush_doneq(ahci_port_t *);
2102fcbc377Syt 
2118aa6aadbSXiao-Yu Zhang static	int ahci_software_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2122fcbc377Syt static	int ahci_hba_reset(ahci_ctl_t *);
2138aa6aadbSXiao-Yu Zhang static	int ahci_port_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2148aa6aadbSXiao-Yu Zhang static	int ahci_pmport_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2152fcbc377Syt static	void ahci_reject_all_abort_pkts(ahci_ctl_t *, ahci_port_t *, uint8_t);
2168aa6aadbSXiao-Yu Zhang static	int ahci_reset_device_reject_pkts(ahci_ctl_t *, ahci_port_t *,
2178aa6aadbSXiao-Yu Zhang     ahci_addr_t *);
2188aa6aadbSXiao-Yu Zhang static	int ahci_reset_pmdevice_reject_pkts(ahci_ctl_t *, ahci_port_t *,
2198aa6aadbSXiao-Yu Zhang     ahci_addr_t *);
2208aa6aadbSXiao-Yu Zhang static	int ahci_reset_port_reject_pkts(ahci_ctl_t *, ahci_port_t *,
2218aa6aadbSXiao-Yu Zhang     ahci_addr_t *);
2222fcbc377Syt static	int ahci_reset_hba_reject_pkts(ahci_ctl_t *);
22368d33a25Syt static	int ahci_put_port_into_notrunning_state(ahci_ctl_t *, ahci_port_t *,
2242fcbc377Syt     uint8_t);
2252fcbc377Syt static	int ahci_restart_port_wait_till_ready(ahci_ctl_t *, ahci_port_t *,
22668d33a25Syt     uint8_t, int, int *);
227689d74b0Syt static	void ahci_mop_commands(ahci_ctl_t *, ahci_port_t *, uint32_t,
228689d74b0Syt     uint32_t, uint32_t, uint32_t, uint32_t);
22982263d52Syt static	uint32_t ahci_get_rdlogext_data(ahci_ctl_t *, ahci_port_t *, uint8_t);
23068d33a25Syt static void ahci_get_rqsense_data(ahci_ctl_t *, ahci_port_t *,
23168d33a25Syt     uint8_t, sata_pkt_t *);
23268d33a25Syt static	void ahci_fatal_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
2338aa6aadbSXiao-Yu Zhang     ahci_addr_t *, uint32_t);
2348aa6aadbSXiao-Yu Zhang static	void ahci_pmult_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
23582263d52Syt     uint8_t, uint32_t);
23668d33a25Syt static	void ahci_timeout_pkts(ahci_ctl_t *, ahci_port_t *,
23782263d52Syt     uint8_t, uint32_t);
23868d33a25Syt static	void ahci_events_handler(void *);
2392fcbc377Syt static	void ahci_watchdog_handler(ahci_ctl_t *);
2402fcbc377Syt 
2412fcbc377Syt static	uint_t ahci_intr(caddr_t, caddr_t);
24282263d52Syt static	void ahci_port_intr(ahci_ctl_t *, ahci_port_t *, uint8_t);
2432c742e1fSying tian - Beijing China static	int ahci_add_intrs(ahci_ctl_t *, int);
2442fcbc377Syt static	void ahci_rem_intrs(ahci_ctl_t *);
2452fcbc377Syt static	void ahci_enable_all_intrs(ahci_ctl_t *);
2462fcbc377Syt static	void ahci_disable_all_intrs(ahci_ctl_t *);
247689d74b0Syt static	void ahci_enable_port_intrs(ahci_ctl_t *, uint8_t);
248689d74b0Syt static	void ahci_disable_port_intrs(ahci_ctl_t *, uint8_t);
2492fcbc377Syt 
250689d74b0Syt static  int ahci_intr_cmd_cmplt(ahci_ctl_t *, ahci_port_t *, uint8_t);
25168d33a25Syt static	int ahci_intr_set_device_bits(ahci_ctl_t *, ahci_port_t *, uint8_t);
2528aa6aadbSXiao-Yu Zhang static	int ahci_intr_ncq_events(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2538aa6aadbSXiao-Yu Zhang static	int ahci_intr_pmult_sntf_events(ahci_ctl_t *, ahci_port_t *, uint8_t);
2542fcbc377Syt static	int ahci_intr_port_connect_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
2552fcbc377Syt static	int ahci_intr_device_mechanical_presence_status(ahci_ctl_t *,
2562fcbc377Syt     ahci_port_t *, uint8_t);
2572fcbc377Syt static	int ahci_intr_phyrdy_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
25868d33a25Syt static	int ahci_intr_non_fatal_error(ahci_ctl_t *, ahci_port_t *,
25968d33a25Syt     uint8_t, uint32_t);
26068d33a25Syt static  int ahci_intr_fatal_error(ahci_ctl_t *, ahci_port_t *,
26182263d52Syt     uint8_t, uint32_t);
2622fcbc377Syt static	int ahci_intr_cold_port_detect(ahci_ctl_t *, ahci_port_t *, uint8_t);
2632fcbc377Syt 
2648aa6aadbSXiao-Yu Zhang static	void ahci_get_ahci_addr(ahci_ctl_t *, sata_device_t *, ahci_addr_t *);
2652fcbc377Syt static	int ahci_get_num_implemented_ports(uint32_t);
2663f022900Sying tian - Beijing China static  void ahci_log_fatal_error_message(ahci_ctl_t *, uint8_t, uint32_t);
2673f022900Sying tian - Beijing China static	void ahci_dump_commands(ahci_ctl_t *, uint8_t, uint32_t);
268a9440e8dSyt static	void ahci_log_serror_message(ahci_ctl_t *, uint8_t, uint32_t, int);
269689d74b0Syt #if AHCI_DEBUG
2702fcbc377Syt static	void ahci_log(ahci_ctl_t *, uint_t, char *, ...);
271689d74b0Syt #endif
2722fcbc377Syt 
273fd6d41c5SRobert Mustacchi static	boolean_t ahci_em_init(ahci_ctl_t *);
274fd6d41c5SRobert Mustacchi static	void ahci_em_fini(ahci_ctl_t *);
275fd6d41c5SRobert Mustacchi static	void ahci_em_suspend(ahci_ctl_t *);
276fd6d41c5SRobert Mustacchi static	void ahci_em_resume(ahci_ctl_t *);
277fd6d41c5SRobert Mustacchi static	int ahci_em_ioctl(dev_info_t *, int, intptr_t);
278fd6d41c5SRobert Mustacchi 
2792fcbc377Syt 
2802fcbc377Syt /*
2812fcbc377Syt  * DMA attributes for the data buffer
2822fcbc377Syt  *
2832fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2842fcbc377Syt  * does not support 64-bit addressing
2852fcbc377Syt  */
2862fcbc377Syt static ddi_dma_attr_t buffer_dma_attr = {
2872fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
28868d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
2892fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
2902fcbc377Syt 	0x3fffffull,		/* dma_attr_count_max i.e. for one cookie */
29168d33a25Syt 	0x2ull,			/* dma_attr_align: word aligned */
2922fcbc377Syt 	1,			/* dma_attr_burstsizes */
2932fcbc377Syt 	1,			/* dma_attr_minxfer */
2942fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
2952fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
2962fcbc377Syt 	AHCI_PRDT_NUMBER,	/* dma_attr_sgllen */
2972fcbc377Syt 	512,			/* dma_attr_granular */
2982fcbc377Syt 	0,			/* dma_attr_flags */
2992fcbc377Syt };
3002fcbc377Syt 
3012fcbc377Syt /*
3022fcbc377Syt  * DMA attributes for the rcvd FIS
3032fcbc377Syt  *
3042fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
3052fcbc377Syt  * does not support 64-bit addressing
3062fcbc377Syt  */
3072fcbc377Syt static ddi_dma_attr_t rcvd_fis_dma_attr = {
3082fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
30968d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
3102fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
3112fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
31268d33a25Syt 	0x100ull,		/* dma_attr_align: 256-byte aligned */
3132fcbc377Syt 	1,			/* dma_attr_burstsizes */
3142fcbc377Syt 	1,			/* dma_attr_minxfer */
3152fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
3162fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
3172fcbc377Syt 	1,			/* dma_attr_sgllen */
3182fcbc377Syt 	1,			/* dma_attr_granular */
3192fcbc377Syt 	0,			/* dma_attr_flags */
3202fcbc377Syt };
3212fcbc377Syt 
3222fcbc377Syt /*
3232fcbc377Syt  * DMA attributes for the command list
3242fcbc377Syt  *
3252fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
3262fcbc377Syt  * does not support 64-bit addressing
3272fcbc377Syt  */
3282fcbc377Syt static ddi_dma_attr_t cmd_list_dma_attr = {
3292fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
33068d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
3312fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
3322fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
33368d33a25Syt 	0x400ull,		/* dma_attr_align: 1K-byte aligned */
3342fcbc377Syt 	1,			/* dma_attr_burstsizes */
3352fcbc377Syt 	1,			/* dma_attr_minxfer */
3362fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
3372fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
3382fcbc377Syt 	1,			/* dma_attr_sgllen */
3392fcbc377Syt 	1,			/* dma_attr_granular */
3402fcbc377Syt 	0,			/* dma_attr_flags */
3412fcbc377Syt };
3422fcbc377Syt 
3432fcbc377Syt /*
3442fcbc377Syt  * DMA attributes for cmd tables
3452fcbc377Syt  *
3462fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
3472fcbc377Syt  * does not support 64-bit addressing
3482fcbc377Syt  */
3492fcbc377Syt static ddi_dma_attr_t cmd_table_dma_attr = {
3502fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
35168d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
3522fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
3532fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
35468d33a25Syt 	0x80ull,		/* dma_attr_align: 128-byte aligned */
3552fcbc377Syt 	1,			/* dma_attr_burstsizes */
3562fcbc377Syt 	1,			/* dma_attr_minxfer */
3572fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
3582fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
3592fcbc377Syt 	1,			/* dma_attr_sgllen */
3602fcbc377Syt 	1,			/* dma_attr_granular */
3612fcbc377Syt 	0,			/* dma_attr_flags */
3622fcbc377Syt };
3632fcbc377Syt 
3642fcbc377Syt 
3652fcbc377Syt /* Device access attributes */
3662fcbc377Syt static ddi_device_acc_attr_t accattr = {
367b22851f1SXiao-Yu Zhang 	DDI_DEVICE_ATTR_V1,
3682fcbc377Syt 	DDI_STRUCTURE_LE_ACC,
369b22851f1SXiao-Yu Zhang 	DDI_STRICTORDER_ACC,
370b22851f1SXiao-Yu Zhang 	DDI_DEFAULT_ACC
3712fcbc377Syt };
3722fcbc377Syt 
3732fcbc377Syt static struct dev_ops ahcictl_dev_ops = {
3742fcbc377Syt 	DEVO_REV,		/* devo_rev */
3752fcbc377Syt 	0,			/* refcnt  */
3762fcbc377Syt 	ahci_getinfo,		/* info */
3772fcbc377Syt 	nulldev,		/* identify */
3782fcbc377Syt 	nulldev,		/* probe */
3792fcbc377Syt 	ahci_attach,		/* attach */
3802fcbc377Syt 	ahci_detach,		/* detach */
3812fcbc377Syt 	nodev,			/* no reset */
382fd6d41c5SRobert Mustacchi 	NULL,			/* driver operations */
3832fcbc377Syt 	NULL,			/* bus operations */
38419397407SSherry Moore 	NULL,			/* power */
38519397407SSherry Moore 	ahci_quiesce,		/* quiesce */
3862fcbc377Syt };
3872fcbc377Syt 
3882fcbc377Syt static sata_tran_hotplug_ops_t ahci_tran_hotplug_ops = {
3892fcbc377Syt 	SATA_TRAN_HOTPLUG_OPS_REV_1,
3902fcbc377Syt 	ahci_tran_hotplug_port_activate,
3912fcbc377Syt 	ahci_tran_hotplug_port_deactivate
3922fcbc377Syt };
3932fcbc377Syt 
3942fcbc377Syt extern struct mod_ops mod_driverops;
3952fcbc377Syt 
3962fcbc377Syt static  struct modldrv modldrv = {
3972fcbc377Syt 	&mod_driverops,		/* driverops */
39819397407SSherry Moore 	ahci_ident,		/* short description */
3992fcbc377Syt 	&ahcictl_dev_ops,	/* driver ops */
4002fcbc377Syt };
4012fcbc377Syt 
4022fcbc377Syt static  struct modlinkage modlinkage = {
4032fcbc377Syt 	MODREV_1,
4042fcbc377Syt 	&modldrv,
4052fcbc377Syt 	NULL
4062fcbc377Syt };
4072fcbc377Syt 
408db2cce03Sying tian - Beijing China /* The following variables are watchdog handler related */
4096b62a236Sying tian - Beijing China static clock_t ahci_watchdog_timeout = 5; /* 5 seconds */
4106b62a236Sying tian - Beijing China static clock_t ahci_watchdog_tick;
4112fcbc377Syt 
412db2cce03Sying tian - Beijing China /*
413db2cce03Sying tian - Beijing China  * This static variable indicates the size of command table,
414db2cce03Sying tian - Beijing China  * and it's changeable with prdt number, which ahci_dma_prdt_number
415db2cce03Sying tian - Beijing China  * indicates.
416db2cce03Sying tian - Beijing China  */
4172fcbc377Syt static size_t ahci_cmd_table_size;
4182fcbc377Syt 
419db2cce03Sying tian - Beijing China /*
420259105bcSying tian - Beijing China  * The below global variables are tunable via /etc/system
421259105bcSying tian - Beijing China  *
422259105bcSying tian - Beijing China  *	ahci_dma_prdt_number
423259105bcSying tian - Beijing China  *	ahci_msi_enabled
424259105bcSying tian - Beijing China  *	ahci_buf_64bit_dma
425259105bcSying tian - Beijing China  *	ahci_commu_64bit_dma
426db2cce03Sying tian - Beijing China  */
427db2cce03Sying tian - Beijing China 
4282fcbc377Syt /* The number of Physical Region Descriptor Table(PRDT) in Command Table */
4292fcbc377Syt int ahci_dma_prdt_number = AHCI_PRDT_NUMBER;
4302fcbc377Syt 
431db2cce03Sying tian - Beijing China /* AHCI MSI is tunable */
4322c742e1fSying tian - Beijing China boolean_t ahci_msi_enabled = B_TRUE;
4332fcbc377Syt 
434259105bcSying tian - Beijing China /*
435259105bcSying tian - Beijing China  * 64-bit dma addressing for data buffer is tunable
436259105bcSying tian - Beijing China  *
437259105bcSying tian - Beijing China  * The variable controls only the below value:
438259105bcSying tian - Beijing China  *	DBAU (upper 32-bits physical address of data block)
439259105bcSying tian - Beijing China  */
440259105bcSying tian - Beijing China boolean_t ahci_buf_64bit_dma = B_TRUE;
441259105bcSying tian - Beijing China 
442259105bcSying tian - Beijing China /*
443259105bcSying tian - Beijing China  * 64-bit dma addressing for communication system descriptors is tunable
444259105bcSying tian - Beijing China  *
445259105bcSying tian - Beijing China  * The variable controls the below three values:
446259105bcSying tian - Beijing China  *
447259105bcSying tian - Beijing China  *	PxCLBU (upper 32-bits for the command list base physical address)
448259105bcSying tian - Beijing China  *	PxFBU (upper 32-bits for the received FIS base physical address)
449259105bcSying tian - Beijing China  *	CTBAU (upper 32-bits of command table base)
450259105bcSying tian - Beijing China  */
451259105bcSying tian - Beijing China boolean_t ahci_commu_64bit_dma = B_TRUE;
452259105bcSying tian - Beijing China 
45317ac46baSying tian - Beijing China /*
45417ac46baSying tian - Beijing China  * By default, 64-bit dma for data buffer will be disabled for AMD/ATI SB600
45517ac46baSying tian - Beijing China  * chipset. If the users want to have a try with 64-bit dma, please change
45617ac46baSying tian - Beijing China  * the below variable value to enable it.
45717ac46baSying tian - Beijing China  */
45817ac46baSying tian - Beijing China boolean_t sb600_buf_64bit_dma_disable = B_TRUE;
45917ac46baSying tian - Beijing China 
46017ac46baSying tian - Beijing China /*
46117ac46baSying tian - Beijing China  * By default, 64-bit dma for command buffer will be disabled for AMD/ATI
46217ac46baSying tian - Beijing China  * SB600/700/710/750/800. If the users want to have a try with 64-bit dma,
46317ac46baSying tian - Beijing China  * please change the below value to enable it.
46417ac46baSying tian - Beijing China  */
46517ac46baSying tian - Beijing China boolean_t sbxxx_commu_64bit_dma_disable = B_TRUE;
46617ac46baSying tian - Beijing China 
467fd6d41c5SRobert Mustacchi /*
468fd6d41c5SRobert Mustacchi  * These values control the default delay and default number of times to wait
469fd6d41c5SRobert Mustacchi  * for an enclosure message to complete.
470fd6d41c5SRobert Mustacchi  */
471fd6d41c5SRobert Mustacchi uint_t	ahci_em_reset_delay_ms = 1;
472fd6d41c5SRobert Mustacchi uint_t	ahci_em_reset_delay_count = 1000;
473fd6d41c5SRobert Mustacchi uint_t	ahci_em_tx_delay_ms = 1;
474fd6d41c5SRobert Mustacchi uint_t	ahci_em_tx_delay_count = 1000;
475fd6d41c5SRobert Mustacchi 
47617ac46baSying tian - Beijing China 
477259105bcSying tian - Beijing China /*
478259105bcSying tian - Beijing China  * End of global tunable variable definition
479259105bcSying tian - Beijing China  */
480db2cce03Sying tian - Beijing China 
4811fdcc913SFred Herard #if AHCI_DEBUG
4821fdcc913SFred Herard uint32_t ahci_debug_flags = 0;
4831fdcc913SFred Herard #else
484f5f2d263SFred Herard uint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT);
4851fdcc913SFred Herard #endif
4861fdcc913SFred Herard 
487689d74b0Syt 
488f5f2d263SFred Herard #if AHCI_DEBUG
489689d74b0Syt /* The following is needed for ahci_log() */
490689d74b0Syt static kmutex_t ahci_log_mutex;
491689d74b0Syt static char ahci_log_buf[512];
4922fcbc377Syt #endif
4932fcbc377Syt 
4942fcbc377Syt /* Opaque state pointer initialized by ddi_soft_state_init() */
4952fcbc377Syt static void *ahci_statep = NULL;
4962fcbc377Syt 
4972fcbc377Syt /*
4982fcbc377Syt  *  ahci module initialization.
4992fcbc377Syt  */
5002fcbc377Syt int
_init(void)5012fcbc377Syt _init(void)
5022fcbc377Syt {
5032fcbc377Syt 	int	ret;
5042fcbc377Syt 
5052fcbc377Syt 	ret = ddi_soft_state_init(&ahci_statep, sizeof (ahci_ctl_t), 0);
5062fcbc377Syt 	if (ret != 0) {
5072fcbc377Syt 		goto err_out;
5082fcbc377Syt 	}
5092fcbc377Syt 
510689d74b0Syt #if AHCI_DEBUG
5112fcbc377Syt 	mutex_init(&ahci_log_mutex, NULL, MUTEX_DRIVER, NULL);
512689d74b0Syt #endif
5132fcbc377Syt 
5142fcbc377Syt 	if ((ret = sata_hba_init(&modlinkage)) != 0) {
515689d74b0Syt #if AHCI_DEBUG
5162fcbc377Syt 		mutex_destroy(&ahci_log_mutex);
517689d74b0Syt #endif
5182fcbc377Syt 		ddi_soft_state_fini(&ahci_statep);
5192fcbc377Syt 		goto err_out;
5202fcbc377Syt 	}
5212fcbc377Syt 
5222ac30289SMarcel Telka 	/* watchdog tick */
5232ac30289SMarcel Telka 	ahci_watchdog_tick = drv_usectohz(
5242ac30289SMarcel Telka 	    (clock_t)ahci_watchdog_timeout * 1000000);
5252ac30289SMarcel Telka 
5262fcbc377Syt 	ret = mod_install(&modlinkage);
5272fcbc377Syt 	if (ret != 0) {
5282fcbc377Syt 		sata_hba_fini(&modlinkage);
529689d74b0Syt #if AHCI_DEBUG
5302fcbc377Syt 		mutex_destroy(&ahci_log_mutex);
531689d74b0Syt #endif
5322fcbc377Syt 		ddi_soft_state_fini(&ahci_statep);
5332fcbc377Syt 		goto err_out;
5342fcbc377Syt 	}
5352fcbc377Syt 
5362fcbc377Syt 	return (ret);
5372fcbc377Syt 
5382fcbc377Syt err_out:
539a9440e8dSyt 	cmn_err(CE_WARN, "!ahci: Module init failed");
5402fcbc377Syt 	return (ret);
5412fcbc377Syt }
5422fcbc377Syt 
5432fcbc377Syt /*
5442fcbc377Syt  * ahci module uninitialize.
5452fcbc377Syt  */
5462fcbc377Syt int
_fini(void)5472fcbc377Syt _fini(void)
5482fcbc377Syt {
5492fcbc377Syt 	int	ret;
5502fcbc377Syt 
5512fcbc377Syt 	ret = mod_remove(&modlinkage);
5522fcbc377Syt 	if (ret != 0) {
5532fcbc377Syt 		return (ret);
5542fcbc377Syt 	}
5552fcbc377Syt 
5562fcbc377Syt 	/* Remove the resources allocated in _init(). */
5572fcbc377Syt 	sata_hba_fini(&modlinkage);
558689d74b0Syt #if AHCI_DEBUG
5592fcbc377Syt 	mutex_destroy(&ahci_log_mutex);
560689d74b0Syt #endif
5612fcbc377Syt 	ddi_soft_state_fini(&ahci_statep);
5622fcbc377Syt 
5632fcbc377Syt 	return (ret);
5642fcbc377Syt }
5652fcbc377Syt 
5662fcbc377Syt /*
5672fcbc377Syt  * _info entry point
5682fcbc377Syt  */
5692fcbc377Syt int
_info(struct modinfo * modinfop)5702fcbc377Syt _info(struct modinfo *modinfop)
5712fcbc377Syt {
5722fcbc377Syt 	return (mod_info(&modlinkage, modinfop));
5732fcbc377Syt }
5742fcbc377Syt 
5752fcbc377Syt /*
5762fcbc377Syt  * The attach entry point for dev_ops.
5772fcbc377Syt  */
5782fcbc377Syt static int
ahci_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)5792fcbc377Syt ahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5802fcbc377Syt {
581f5f2d263SFred Herard 	ahci_ctl_t *ahci_ctlp = NULL;
5822fcbc377Syt 	int instance = ddi_get_instance(dip);
5832fcbc377Syt 	int status;
5842fcbc377Syt 	int attach_state;
5852fcbc377Syt 	uint32_t cap_status, ahci_version;
5862ac30289SMarcel Telka 	uint32_t ghc_control;
5872fcbc377Syt 	int intr_types;
58868d33a25Syt 	int i;
58995c11c1fSyt 	pci_regspec_t *regs;
59095c11c1fSyt 	int regs_length;
59195c11c1fSyt 	int rnumber;
59268d33a25Syt #if AHCI_DEBUG
59368d33a25Syt 	int speed;
59468d33a25Syt #endif
5952fcbc377Syt 
596f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_attach enter",
597f5f2d263SFred Herard 	    NULL);
5982fcbc377Syt 
5992fcbc377Syt 	switch (cmd) {
6002fcbc377Syt 	case DDI_ATTACH:
6012fcbc377Syt 		break;
6022fcbc377Syt 
6032fcbc377Syt 	case DDI_RESUME:
60413bcbb7aSyt 
60513bcbb7aSyt 		/*
60613bcbb7aSyt 		 * During DDI_RESUME, the hardware state of the device
60713bcbb7aSyt 		 * (power may have been removed from the device) must be
60813bcbb7aSyt 		 * restored, allow pending requests to continue, and
60913bcbb7aSyt 		 * service new requests.
61013bcbb7aSyt 		 */
61113bcbb7aSyt 		ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
61213bcbb7aSyt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
61313bcbb7aSyt 
6142ac30289SMarcel Telka 		/*
6152ac30289SMarcel Telka 		 * GHC.AE must be set to 1 before any other AHCI register
6162ac30289SMarcel Telka 		 * is accessed
6172ac30289SMarcel Telka 		 */
6182ac30289SMarcel Telka 		ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
6192ac30289SMarcel Telka 		    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
6202ac30289SMarcel Telka 		ghc_control |= AHCI_HBA_GHC_AE;
6212ac30289SMarcel Telka 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
6222ac30289SMarcel Telka 		    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
6232ac30289SMarcel Telka 
62413bcbb7aSyt 		/* Restart watch thread */
62513bcbb7aSyt 		if (ahci_ctlp->ahcictl_timeout_id == 0)
62613bcbb7aSyt 			ahci_ctlp->ahcictl_timeout_id = timeout(
62713bcbb7aSyt 			    (void (*)(void *))ahci_watchdog_handler,
62813bcbb7aSyt 			    (caddr_t)ahci_ctlp, ahci_watchdog_tick);
62913bcbb7aSyt 
63013bcbb7aSyt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
63113bcbb7aSyt 
63213bcbb7aSyt 		/*
63313bcbb7aSyt 		 * Re-initialize the controller and enable the interrupts and
63413bcbb7aSyt 		 * restart all the ports.
63513bcbb7aSyt 		 *
63613bcbb7aSyt 		 * Note that so far we don't support hot-plug during
63713bcbb7aSyt 		 * suspend/resume.
63813bcbb7aSyt 		 */
63913bcbb7aSyt 		if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) {
640f5f2d263SFred Herard 			AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp,
641a9440e8dSyt 			    "Failed to initialize the controller "
642f5f2d263SFred Herard 			    "during DDI_RESUME", NULL);
64313bcbb7aSyt 			return (DDI_FAILURE);
64413bcbb7aSyt 		}
64513bcbb7aSyt 
646fd6d41c5SRobert Mustacchi 		/*
647fd6d41c5SRobert Mustacchi 		 * Reset the enclosure services.
648fd6d41c5SRobert Mustacchi 		 */
649fd6d41c5SRobert Mustacchi 		ahci_em_resume(ahci_ctlp);
650fd6d41c5SRobert Mustacchi 
65113bcbb7aSyt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
652265b5a40SMarcel Telka 		ahci_ctlp->ahcictl_flags &= ~AHCI_SUSPEND;
65313bcbb7aSyt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
65413bcbb7aSyt 
65513bcbb7aSyt 		return (DDI_SUCCESS);
6562fcbc377Syt 
6572fcbc377Syt 	default:
6582fcbc377Syt 		return (DDI_FAILURE);
6592fcbc377Syt 	}
6602fcbc377Syt 
6612fcbc377Syt 	attach_state = AHCI_ATTACH_STATE_NONE;
6622fcbc377Syt 
6632fcbc377Syt 	/* Allocate soft state */
6642fcbc377Syt 	status = ddi_soft_state_zalloc(ahci_statep, instance);
6652fcbc377Syt 	if (status != DDI_SUCCESS) {
666a9440e8dSyt 		cmn_err(CE_WARN, "!ahci%d: Cannot allocate soft state",
667a9440e8dSyt 		    instance);
6682fcbc377Syt 		goto err_out;
6692fcbc377Syt 	}
6702fcbc377Syt 
6712fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
67213bcbb7aSyt 	ahci_ctlp->ahcictl_flags |= AHCI_ATTACH;
6732fcbc377Syt 	ahci_ctlp->ahcictl_dip = dip;
6742fcbc377Syt 
67568d33a25Syt 	/* Initialize the cport/port mapping */
67668d33a25Syt 	for (i = 0; i < AHCI_MAX_PORTS; i++) {
67768d33a25Syt 		ahci_ctlp->ahcictl_port_to_cport[i] = 0xff;
67868d33a25Syt 		ahci_ctlp->ahcictl_cport_to_port[i] = 0xff;
67968d33a25Syt 	}
68068d33a25Syt 
6812fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_STATEP_ALLOC;
6822fcbc377Syt 
683b22851f1SXiao-Yu Zhang 	/* Initialize FMA properties */
684b22851f1SXiao-Yu Zhang 	ahci_fm_init(ahci_ctlp);
685b22851f1SXiao-Yu Zhang 
686b22851f1SXiao-Yu Zhang 	attach_state |= AHCI_ATTACH_STATE_FMA;
687b22851f1SXiao-Yu Zhang 
6882fcbc377Syt 	/*
6892fcbc377Syt 	 * Now map the AHCI base address; which includes global
6902fcbc377Syt 	 * registers and port control registers
69195c11c1fSyt 	 *
69295c11c1fSyt 	 * According to the spec, the AHCI Base Address is BAR5,
69313bcbb7aSyt 	 * but BAR0-BAR4 are optional, so we need to check which
69413bcbb7aSyt 	 * rnumber is used for BAR5.
69595c11c1fSyt 	 */
69695c11c1fSyt 
69795c11c1fSyt 	/*
69895c11c1fSyt 	 * search through DDI "reg" property for the AHCI register set
6992fcbc377Syt 	 */
70095c11c1fSyt 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
70195c11c1fSyt 	    DDI_PROP_DONTPASS, "reg", (int **)&regs,
70295c11c1fSyt 	    (uint_t *)&regs_length) != DDI_PROP_SUCCESS) {
703a9440e8dSyt 		cmn_err(CE_WARN, "!ahci%d: Cannot lookup reg property",
704a9440e8dSyt 		    instance);
70595c11c1fSyt 		goto err_out;
70695c11c1fSyt 	}
70795c11c1fSyt 
70895c11c1fSyt 	/* AHCI Base Address is located at 0x24 offset */
70995c11c1fSyt 	for (rnumber = 0; rnumber < regs_length; ++rnumber) {
71095c11c1fSyt 		if ((regs[rnumber].pci_phys_hi & PCI_REG_REG_M)
71195c11c1fSyt 		    == AHCI_PCI_RNUM)
71295c11c1fSyt 			break;
71395c11c1fSyt 	}
71495c11c1fSyt 
71595c11c1fSyt 	ddi_prop_free(regs);
71695c11c1fSyt 
71795c11c1fSyt 	if (rnumber == regs_length) {
718a9440e8dSyt 		cmn_err(CE_WARN, "!ahci%d: Cannot find AHCI register set",
719a9440e8dSyt 		    instance);
72095c11c1fSyt 		goto err_out;
72195c11c1fSyt 	}
72295c11c1fSyt 
723f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
72495c11c1fSyt 
7252fcbc377Syt 	status = ddi_regs_map_setup(dip,
72695c11c1fSyt 	    rnumber,
7272fcbc377Syt 	    (caddr_t *)&ahci_ctlp->ahcictl_ahci_addr,
7282fcbc377Syt 	    0,
7292fcbc377Syt 	    0,
7302fcbc377Syt 	    &accattr,
7312fcbc377Syt 	    &ahci_ctlp->ahcictl_ahci_acc_handle);
7322fcbc377Syt 	if (status != DDI_SUCCESS) {
733a9440e8dSyt 		cmn_err(CE_WARN, "!ahci%d: Cannot map register space",
734a9440e8dSyt 		    instance);
7352fcbc377Syt 		goto err_out;
7362fcbc377Syt 	}
7372fcbc377Syt 
7382fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_REG_MAP;
7392fcbc377Syt 
7402ac30289SMarcel Telka 	/*
7412ac30289SMarcel Telka 	 * GHC.AE must be set to 1 before any other AHCI register
7422ac30289SMarcel Telka 	 * is accessed
7432ac30289SMarcel Telka 	 */
7442ac30289SMarcel Telka 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
7452ac30289SMarcel Telka 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
7462ac30289SMarcel Telka 	ghc_control |= AHCI_HBA_GHC_AE;
7472ac30289SMarcel Telka 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
7482ac30289SMarcel Telka 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
7492ac30289SMarcel Telka 
7502fcbc377Syt 	/* Get the AHCI version information */
7512fcbc377Syt 	ahci_version = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
7522fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_VS(ahci_ctlp));
7532fcbc377Syt 
754a9440e8dSyt 	cmn_err(CE_NOTE, "!ahci%d: hba AHCI version = %x.%x", instance,
7552fcbc377Syt 	    (ahci_version & 0xffff0000) >> 16,
7562fcbc377Syt 	    ((ahci_version & 0x0000ff00) >> 4 |
7572fcbc377Syt 	    (ahci_version & 0x000000ff)));
7582fcbc377Syt 
7592fcbc377Syt 	/* We don't support controllers whose versions are lower than 1.0 */
7602fcbc377Syt 	if (!(ahci_version & 0xffff0000)) {
761a9440e8dSyt 		cmn_err(CE_WARN, "ahci%d: Don't support AHCI HBA with lower "
762a9440e8dSyt 		    "than version 1.0", instance);
7632fcbc377Syt 		goto err_out;
7642fcbc377Syt 	}
7652fcbc377Syt 
7662fcbc377Syt 	/* Get the HBA capabilities information */
7672fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
7682fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
7692fcbc377Syt 
770356f6268Sying tian - Beijing China 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba capabilities = 0x%x",
7712fcbc377Syt 	    cap_status);
7722fcbc377Syt 
7732ac30289SMarcel Telka 	/* CAP2 (HBA Capabilities Extended) is available since AHCI spec 1.2 */
7742ac30289SMarcel Telka 	if (ahci_version >= 0x00010200) {
7752ac30289SMarcel Telka 		uint32_t cap2_status;
7762ac30289SMarcel Telka 
7772ac30289SMarcel Telka 		/* Get the HBA capabilities extended information */
7782ac30289SMarcel Telka 		cap2_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
7792ac30289SMarcel Telka 		    (uint32_t *)AHCI_GLOBAL_CAP2(ahci_ctlp));
7802ac30289SMarcel Telka 
7812ac30289SMarcel Telka 		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
7822ac30289SMarcel Telka 		    "hba capabilities extended = 0x%x", cap2_status);
7832ac30289SMarcel Telka 	}
7842ac30289SMarcel Telka 
785fd6d41c5SRobert Mustacchi 	if (cap_status & AHCI_HBA_CAP_EMS) {
786fd6d41c5SRobert Mustacchi 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_EMS;
787fd6d41c5SRobert Mustacchi 		ahci_ctlp->ahcictl_em_loc =
788fd6d41c5SRobert Mustacchi 		    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
789fd6d41c5SRobert Mustacchi 		    (uint32_t *)AHCI_GLOBAL_EM_LOC(ahci_ctlp));
790fd6d41c5SRobert Mustacchi 		ahci_ctlp->ahcictl_em_ctl =
791fd6d41c5SRobert Mustacchi 		    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
792fd6d41c5SRobert Mustacchi 		    (uint32_t *)AHCI_GLOBAL_EM_CTL(ahci_ctlp));
793fd6d41c5SRobert Mustacchi 	}
794fd6d41c5SRobert Mustacchi 
79568d33a25Syt #if AHCI_DEBUG
79668d33a25Syt 	/* Get the interface speed supported by the HBA */
79768d33a25Syt 	speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
79868d33a25Syt 	if (speed == 0x01) {
799f5f2d263SFred Herard 		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
800f5f2d263SFred Herard 		    "hba interface speed support: Gen 1 (1.5Gbps)", NULL);
80168d33a25Syt 	} else if (speed == 0x10) {
802f5f2d263SFred Herard 		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
803f5f2d263SFred Herard 		    "hba interface speed support: Gen 2 (3 Gbps)", NULL);
80468d33a25Syt 	} else if (speed == 0x11) {
805f5f2d263SFred Herard 		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
806f5f2d263SFred Herard 		    "hba interface speed support: Gen 3 (6 Gbps)", NULL);
80768d33a25Syt 	}
80868d33a25Syt #endif
80968d33a25Syt 
8102fcbc377Syt 	/* Get the number of command slots supported by the HBA */
8112fcbc377Syt 	ahci_ctlp->ahcictl_num_cmd_slots =
8122fcbc377Syt 	    ((cap_status & AHCI_HBA_CAP_NCS) >>
8132fcbc377Syt 	    AHCI_HBA_CAP_NCS_SHIFT) + 1;
8142fcbc377Syt 
815f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
8162fcbc377Syt 	    ahci_ctlp->ahcictl_num_cmd_slots);
8172fcbc377Syt 
8182fcbc377Syt 	/* Get the bit map which indicates ports implemented by the HBA */
8192fcbc377Syt 	ahci_ctlp->ahcictl_ports_implemented =
8202fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8212fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_PI(ahci_ctlp));
8222fcbc377Syt 
823f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
8242fcbc377Syt 	    ahci_ctlp->ahcictl_ports_implemented);
8252fcbc377Syt 
8262ac30289SMarcel Telka 	/* Max port number implemented */
8272ac30289SMarcel Telka 	ahci_ctlp->ahcictl_num_ports =
8282ac30289SMarcel Telka 	    ddi_fls(ahci_ctlp->ahcictl_ports_implemented);
82909121340Syt 
830f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
8312ac30289SMarcel Telka 	    (cap_status & AHCI_HBA_CAP_NP) + 1);
83209121340Syt 
8332fcbc377Syt 	/* Get the number of implemented ports by the HBA */
8342fcbc377Syt 	ahci_ctlp->ahcictl_num_implemented_ports =
8352fcbc377Syt 	    ahci_get_num_implemented_ports(
8362fcbc377Syt 	    ahci_ctlp->ahcictl_ports_implemented);
8372fcbc377Syt 
838f5f2d263SFred Herard 	AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
83968d33a25Syt 	    "hba number of implemented ports: %d",
8402fcbc377Syt 	    ahci_ctlp->ahcictl_num_implemented_ports);
8412fcbc377Syt 
842a9440e8dSyt 	/* Check whether HBA supports 64bit DMA addressing */
8432fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
844259105bcSying tian - Beijing China 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA;
845259105bcSying tian - Beijing China 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
846f5f2d263SFred Herard 		AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
847f5f2d263SFred Herard 		    "hba does not support 64-bit addressing", NULL);
8482fcbc377Syt 	}
8492fcbc377Syt 
8508aa6aadbSXiao-Yu Zhang 	/* Checking for the support of Port Multiplier */
8518aa6aadbSXiao-Yu Zhang 	if (cap_status & AHCI_HBA_CAP_SPM) {
8528aa6aadbSXiao-Yu Zhang 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_PMULT_CBSS;
8538aa6aadbSXiao-Yu Zhang 		AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8548aa6aadbSXiao-Yu Zhang 		    "hba supports port multiplier (CBSS)", NULL);
8558aa6aadbSXiao-Yu Zhang 
8568aa6aadbSXiao-Yu Zhang 		/* Support FIS-based switching ? */
8578aa6aadbSXiao-Yu Zhang 		if (cap_status & AHCI_HBA_CAP_FBSS) {
8588aa6aadbSXiao-Yu Zhang 			ahci_ctlp->ahcictl_cap |= AHCI_CAP_PMULT_FBSS;
8598aa6aadbSXiao-Yu Zhang 			AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8608aa6aadbSXiao-Yu Zhang 			    "hba supports FIS-based switching (FBSS)", NULL);
8618aa6aadbSXiao-Yu Zhang 		}
8628aa6aadbSXiao-Yu Zhang 	}
8638aa6aadbSXiao-Yu Zhang 
8640a4c4cecSXiao-Yu Zhang 	/* Checking for Support Command List Override */
8650a4c4cecSXiao-Yu Zhang 	if (cap_status & AHCI_HBA_CAP_SCLO) {
8660a4c4cecSXiao-Yu Zhang 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_SCLO;
8678aa6aadbSXiao-Yu Zhang 		AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
868f5f2d263SFred Herard 		    "hba supports command list override.", NULL);
8690a4c4cecSXiao-Yu Zhang 	}
8700a4c4cecSXiao-Yu Zhang 
8718aa6aadbSXiao-Yu Zhang 	/* Checking for Asynchronous Notification */
8728aa6aadbSXiao-Yu Zhang 	if (cap_status & AHCI_HBA_CAP_SSNTF) {
8738aa6aadbSXiao-Yu Zhang 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_SNTF;
8748aa6aadbSXiao-Yu Zhang 		AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8758aa6aadbSXiao-Yu Zhang 		    "hba supports asynchronous notification.", NULL);
8768aa6aadbSXiao-Yu Zhang 	}
8778aa6aadbSXiao-Yu Zhang 
8782fcbc377Syt 	if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle)
8792fcbc377Syt 	    != DDI_SUCCESS) {
880a9440e8dSyt 		cmn_err(CE_WARN, "!ahci%d: Cannot set up pci configure space",
881a9440e8dSyt 		    instance);
8822fcbc377Syt 		goto err_out;
8832fcbc377Syt 	}
884