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 /*
23*95c11c1fSyt  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242fcbc377Syt  * Use is subject to license terms.
252fcbc377Syt  */
262fcbc377Syt 
272fcbc377Syt #pragma ident	"%Z%%M%	%I%	%E% SMI"
282fcbc377Syt 
292fcbc377Syt /*
302fcbc377Syt  * AHCI (Advanced Host Controller Interface) SATA HBA Driver
312fcbc377Syt  */
322fcbc377Syt 
332fcbc377Syt #include <sys/scsi/scsi.h>
342fcbc377Syt #include <sys/pci.h>
352fcbc377Syt #include <sys/sata/sata_hba.h>
362fcbc377Syt #include <sys/sata/adapters/ahci/ahcireg.h>
372fcbc377Syt #include <sys/sata/adapters/ahci/ahcivar.h>
382fcbc377Syt 
392fcbc377Syt /*
402fcbc377Syt  * Function prototypes for driver entry points
412fcbc377Syt  */
422fcbc377Syt static	int ahci_attach(dev_info_t *, ddi_attach_cmd_t);
432fcbc377Syt static	int ahci_detach(dev_info_t *, ddi_detach_cmd_t);
442fcbc377Syt static	int ahci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
452fcbc377Syt 
462fcbc377Syt /*
472fcbc377Syt  * Function prototypes for SATA Framework interfaces
482fcbc377Syt  */
492fcbc377Syt static	int ahci_register_sata_hba_tran(ahci_ctl_t *, uint32_t);
502fcbc377Syt static	int ahci_unregister_sata_hba_tran(ahci_ctl_t *);
512fcbc377Syt 
522fcbc377Syt static	int ahci_tran_probe_port(dev_info_t *, sata_device_t *);
532fcbc377Syt static	int ahci_tran_start(dev_info_t *, sata_pkt_t *spkt);
542fcbc377Syt static	int ahci_tran_abort(dev_info_t *, sata_pkt_t *, int);
552fcbc377Syt static	int ahci_tran_reset_dport(dev_info_t *, sata_device_t *);
562fcbc377Syt static	int ahci_tran_hotplug_port_activate(dev_info_t *, sata_device_t *);
572fcbc377Syt static	int ahci_tran_hotplug_port_deactivate(dev_info_t *, sata_device_t *);
582fcbc377Syt #if defined(__lock_lint)
592fcbc377Syt static	int ahci_selftest(dev_info_t *, sata_device_t *);
602fcbc377Syt #endif
612fcbc377Syt 
622fcbc377Syt /*
632fcbc377Syt  * Local function prototypes
642fcbc377Syt  */
6568d33a25Syt static	int ahci_alloc_ports_state(ahci_ctl_t *);
6668d33a25Syt static	void ahci_dealloc_ports_state(ahci_ctl_t *);
672fcbc377Syt static	int ahci_alloc_port_state(ahci_ctl_t *, uint8_t);
682fcbc377Syt static	void ahci_dealloc_port_state(ahci_ctl_t *, uint8_t);
692fcbc377Syt static	int ahci_alloc_rcvd_fis(ahci_ctl_t *, ahci_port_t *, uint8_t);
702fcbc377Syt static	void ahci_dealloc_rcvd_fis(ahci_ctl_t *, ahci_port_t *);
712fcbc377Syt static	int ahci_alloc_cmd_list(ahci_ctl_t *, ahci_port_t *, uint8_t);
722fcbc377Syt static	void ahci_dealloc_cmd_list(ahci_ctl_t *, ahci_port_t *);
732fcbc377Syt static  int ahci_alloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
742fcbc377Syt static  void ahci_dealloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
752fcbc377Syt 
7668d33a25Syt static	int ahci_initialize_controller(ahci_ctl_t *);
7768d33a25Syt static	void ahci_uninitialize_controller(ahci_ctl_t *);
782fcbc377Syt static	int ahci_initialize_port(ahci_ctl_t *, ahci_port_t *, uint8_t);
7968d33a25Syt 
8068d33a25Syt static	int ahci_start_port(ahci_ctl_t *, ahci_port_t *, uint8_t);
8168d33a25Syt static	void ahci_find_dev_signature(ahci_ctl_t *, ahci_port_t *, uint8_t);
822fcbc377Syt static	void ahci_update_sata_registers(ahci_ctl_t *, uint8_t, sata_device_t *);
832fcbc377Syt static	int ahci_deliver_satapkt(ahci_ctl_t *, ahci_port_t *,
842fcbc377Syt     uint8_t, sata_pkt_t *);
8568d33a25Syt static	int ahci_do_sync_start(ahci_ctl_t *, ahci_port_t *,
8668d33a25Syt     uint8_t, sata_pkt_t *);
8782263d52Syt static	int ahci_claim_free_slot(ahci_ctl_t *, ahci_port_t *, int);
8868d33a25Syt static  void ahci_copy_err_cnxt(sata_cmd_t *, ahci_fis_d2h_register_t *);
8982263d52Syt static	void ahci_copy_ncq_err_page(sata_cmd_t *,
9082263d52Syt     struct sata_ncq_error_recovery_page *);
912fcbc377Syt static	void ahci_copy_out_regs(sata_cmd_t *, ahci_fis_d2h_register_t *);
922fcbc377Syt 
932fcbc377Syt static	int ahci_software_reset(ahci_ctl_t *, ahci_port_t *, uint8_t);
942fcbc377Syt static	int ahci_hba_reset(ahci_ctl_t *);
952fcbc377Syt static	int ahci_port_reset(ahci_ctl_t *, ahci_port_t *, uint8_t);
962fcbc377Syt static	void ahci_reject_all_abort_pkts(ahci_ctl_t *, ahci_port_t *, uint8_t);
972fcbc377Syt static	int ahci_reset_device_reject_pkts(ahci_ctl_t *, ahci_port_t *, uint8_t);
982fcbc377Syt static	int ahci_reset_port_reject_pkts(ahci_ctl_t *, ahci_port_t *, uint8_t);
992fcbc377Syt static	int ahci_reset_hba_reject_pkts(ahci_ctl_t *);
10068d33a25Syt static	int ahci_put_port_into_notrunning_state(ahci_ctl_t *, ahci_port_t *,
1012fcbc377Syt     uint8_t);
1022fcbc377Syt static	int ahci_restart_port_wait_till_ready(ahci_ctl_t *, ahci_port_t *,
10368d33a25Syt     uint8_t, int, int *);
1042fcbc377Syt static	void ahci_mop_commands(ahci_ctl_t *, ahci_port_t *, uint8_t,
1052fcbc377Syt     uint32_t, uint32_t, uint32_t, uint32_t, uint32_t);
10682263d52Syt static	uint32_t ahci_get_rdlogext_data(ahci_ctl_t *, ahci_port_t *, uint8_t);
10768d33a25Syt static void ahci_get_rqsense_data(ahci_ctl_t *, ahci_port_t *,
10868d33a25Syt     uint8_t, sata_pkt_t *);
10968d33a25Syt static	void ahci_fatal_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
11082263d52Syt     uint8_t, uint32_t);
11168d33a25Syt static	void ahci_timeout_pkts(ahci_ctl_t *, ahci_port_t *,
11282263d52Syt     uint8_t, uint32_t);
11368d33a25Syt static	void ahci_events_handler(void *);
1142fcbc377Syt static	void ahci_watchdog_handler(ahci_ctl_t *);
1152fcbc377Syt 
1162fcbc377Syt static	uint_t ahci_intr(caddr_t, caddr_t);
11782263d52Syt static	void ahci_port_intr(ahci_ctl_t *, ahci_port_t *, uint8_t);
1182fcbc377Syt static	int ahci_add_legacy_intrs(ahci_ctl_t *);
1192fcbc377Syt static	int ahci_add_msi_intrs(ahci_ctl_t *);
1202fcbc377Syt static	void ahci_rem_intrs(ahci_ctl_t *);
1212fcbc377Syt static	void ahci_enable_all_intrs(ahci_ctl_t *);
1222fcbc377Syt static	void ahci_disable_all_intrs(ahci_ctl_t *);
1232fcbc377Syt static	void ahci_enable_port_intrs(ahci_ctl_t *, ahci_port_t *, uint8_t);
1242fcbc377Syt static	void ahci_disable_port_intrs(ahci_ctl_t *, ahci_port_t *, uint8_t);
1252fcbc377Syt 
12668d33a25Syt static  int ahci_intr_cmd_cmplt(ahci_ctl_t *, ahci_port_t *, uint8_t,
12782263d52Syt     uint32_t);
12868d33a25Syt static	int ahci_intr_set_device_bits(ahci_ctl_t *, ahci_port_t *, uint8_t);
1292fcbc377Syt static	int ahci_intr_port_connect_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
1302fcbc377Syt static	int ahci_intr_device_mechanical_presence_status(ahci_ctl_t *,
1312fcbc377Syt     ahci_port_t *, uint8_t);
1322fcbc377Syt static	int ahci_intr_phyrdy_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
13368d33a25Syt static	int ahci_intr_non_fatal_error(ahci_ctl_t *, ahci_port_t *,
13468d33a25Syt     uint8_t, uint32_t);
13568d33a25Syt static  int ahci_intr_fatal_error(ahci_ctl_t *, ahci_port_t *,
13682263d52Syt     uint8_t, uint32_t);
1372fcbc377Syt static	int ahci_intr_cold_port_detect(ahci_ctl_t *, ahci_port_t *, uint8_t);
1382fcbc377Syt 
1392fcbc377Syt static	int ahci_get_num_implemented_ports(uint32_t);
14068d33a25Syt static  void ahci_log_fatal_error_message(ahci_ctl_t *, uint8_t port,
14168d33a25Syt     uint32_t);
14268d33a25Syt static	void ahci_log_serror_message(ahci_ctl_t *, uint8_t, uint32_t);
1432fcbc377Syt static	void ahci_log(ahci_ctl_t *, uint_t, char *, ...);
1442fcbc377Syt 
1452fcbc377Syt 
1462fcbc377Syt /*
1472fcbc377Syt  * DMA attributes for the data buffer
1482fcbc377Syt  *
1492fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
1502fcbc377Syt  * does not support 64-bit addressing
1512fcbc377Syt  */
1522fcbc377Syt static ddi_dma_attr_t buffer_dma_attr = {
1532fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
15468d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
1552fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
1562fcbc377Syt 	0x3fffffull,		/* dma_attr_count_max i.e. for one cookie */
15768d33a25Syt 	0x2ull,			/* dma_attr_align: word aligned */
1582fcbc377Syt 	1,			/* dma_attr_burstsizes */
1592fcbc377Syt 	1,			/* dma_attr_minxfer */
1602fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
1612fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
1622fcbc377Syt 	AHCI_PRDT_NUMBER,	/* dma_attr_sgllen */
1632fcbc377Syt 	512,			/* dma_attr_granular */
1642fcbc377Syt 	0,			/* dma_attr_flags */
1652fcbc377Syt };
1662fcbc377Syt 
1672fcbc377Syt /*
1682fcbc377Syt  * DMA attributes for the rcvd FIS
1692fcbc377Syt  *
1702fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
1712fcbc377Syt  * does not support 64-bit addressing
1722fcbc377Syt  */
1732fcbc377Syt static ddi_dma_attr_t rcvd_fis_dma_attr = {
1742fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
17568d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
1762fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
1772fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
17868d33a25Syt 	0x100ull,		/* dma_attr_align: 256-byte aligned */
1792fcbc377Syt 	1,			/* dma_attr_burstsizes */
1802fcbc377Syt 	1,			/* dma_attr_minxfer */
1812fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
1822fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
1832fcbc377Syt 	1,			/* dma_attr_sgllen */
1842fcbc377Syt 	1,			/* dma_attr_granular */
1852fcbc377Syt 	0,			/* dma_attr_flags */
1862fcbc377Syt };
1872fcbc377Syt 
1882fcbc377Syt /*
1892fcbc377Syt  * DMA attributes for the command list
1902fcbc377Syt  *
1912fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
1922fcbc377Syt  * does not support 64-bit addressing
1932fcbc377Syt  */
1942fcbc377Syt static ddi_dma_attr_t cmd_list_dma_attr = {
1952fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
19668d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
1972fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
1982fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
19968d33a25Syt 	0x400ull,		/* dma_attr_align: 1K-byte aligned */
2002fcbc377Syt 	1,			/* dma_attr_burstsizes */
2012fcbc377Syt 	1,			/* dma_attr_minxfer */
2022fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
2032fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
2042fcbc377Syt 	1,			/* dma_attr_sgllen */
2052fcbc377Syt 	1,			/* dma_attr_granular */
2062fcbc377Syt 	0,			/* dma_attr_flags */
2072fcbc377Syt };
2082fcbc377Syt 
2092fcbc377Syt /*
2102fcbc377Syt  * DMA attributes for cmd tables
2112fcbc377Syt  *
2122fcbc377Syt  * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2132fcbc377Syt  * does not support 64-bit addressing
2142fcbc377Syt  */
2152fcbc377Syt static ddi_dma_attr_t cmd_table_dma_attr = {
2162fcbc377Syt 	DMA_ATTR_V0,		/* dma_attr_version */
21768d33a25Syt 	0x0ull,			/* dma_attr_addr_lo: lowest bus address */
2182fcbc377Syt 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
2192fcbc377Syt 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
22068d33a25Syt 	0x80ull,		/* dma_attr_align: 128-byte aligned */
2212fcbc377Syt 	1,			/* dma_attr_burstsizes */
2222fcbc377Syt 	1,			/* dma_attr_minxfer */
2232fcbc377Syt 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
2242fcbc377Syt 	0xffffffffull,		/* dma_attr_seg */
2252fcbc377Syt 	1,			/* dma_attr_sgllen */
2262fcbc377Syt 	1,			/* dma_attr_granular */
2272fcbc377Syt 	0,			/* dma_attr_flags */
2282fcbc377Syt };
2292fcbc377Syt 
2302fcbc377Syt 
2312fcbc377Syt /* Device access attributes */
2322fcbc377Syt static ddi_device_acc_attr_t accattr = {
2332fcbc377Syt 	DDI_DEVICE_ATTR_V0,
2342fcbc377Syt 	DDI_STRUCTURE_LE_ACC,
2352fcbc377Syt 	DDI_STRICTORDER_ACC
2362fcbc377Syt };
2372fcbc377Syt 
2382fcbc377Syt 
2392fcbc377Syt static struct dev_ops ahcictl_dev_ops = {
2402fcbc377Syt 	DEVO_REV,		/* devo_rev */
2412fcbc377Syt 	0,			/* refcnt  */
2422fcbc377Syt 	ahci_getinfo,		/* info */
2432fcbc377Syt 	nulldev,		/* identify */
2442fcbc377Syt 	nulldev,		/* probe */
2452fcbc377Syt 	ahci_attach,		/* attach */
2462fcbc377Syt 	ahci_detach,		/* detach */
2472fcbc377Syt 	nodev,			/* no reset */
2482fcbc377Syt 	(struct cb_ops *)0,	/* driver operations */
2492fcbc377Syt 	NULL,			/* bus operations */
2502fcbc377Syt 	NULL			/* power */
2512fcbc377Syt };
2522fcbc377Syt 
2532fcbc377Syt static sata_tran_hotplug_ops_t ahci_tran_hotplug_ops = {
2542fcbc377Syt 	SATA_TRAN_HOTPLUG_OPS_REV_1,
2552fcbc377Syt 	ahci_tran_hotplug_port_activate,
2562fcbc377Syt 	ahci_tran_hotplug_port_deactivate
2572fcbc377Syt };
2582fcbc377Syt 
2592fcbc377Syt extern struct mod_ops mod_driverops;
2602fcbc377Syt 
2612fcbc377Syt static  struct modldrv modldrv = {
2622fcbc377Syt 	&mod_driverops,		/* driverops */
2632fcbc377Syt 	"ahci driver %I%",
2642fcbc377Syt 	&ahcictl_dev_ops,	/* driver ops */
2652fcbc377Syt };
2662fcbc377Syt 
2672fcbc377Syt static  struct modlinkage modlinkage = {
2682fcbc377Syt 	MODREV_1,
2692fcbc377Syt 	&modldrv,
2702fcbc377Syt 	NULL
2712fcbc377Syt };
2722fcbc377Syt 
2732fcbc377Syt static int ahci_watchdog_timeout = 5; /* 5 seconds */
2742fcbc377Syt static int ahci_watchdog_tick;
2752fcbc377Syt 
2762fcbc377Syt /* The following is needed for ahci_log() */
2772fcbc377Syt static kmutex_t ahci_log_mutex;
2782fcbc377Syt static char ahci_log_buf[512];
2792fcbc377Syt 
2802fcbc377Syt static size_t ahci_cmd_table_size;
2812fcbc377Syt 
2822fcbc377Syt /* The number of Physical Region Descriptor Table(PRDT) in Command Table */
2832fcbc377Syt int ahci_dma_prdt_number = AHCI_PRDT_NUMBER;
2842fcbc377Syt 
2852fcbc377Syt /*
2862fcbc377Syt  * AHCI MSI tunable:
2872fcbc377Syt  *
2882fcbc377Syt  * MSI will be enabled in phase 2.
2892fcbc377Syt  */
2902fcbc377Syt boolean_t ahci_msi_enabled = B_FALSE;
2912fcbc377Syt 
2922fcbc377Syt #if AHCI_DEBUG
2932fcbc377Syt uint32_t ahci_debug_flags = 0;
2942fcbc377Syt #endif
2952fcbc377Syt 
2962fcbc377Syt /* Opaque state pointer initialized by ddi_soft_state_init() */
2972fcbc377Syt static void *ahci_statep = NULL;
2982fcbc377Syt 
2992fcbc377Syt /*
3002fcbc377Syt  *  ahci module initialization.
3012fcbc377Syt  */
3022fcbc377Syt int
3032fcbc377Syt _init(void)
3042fcbc377Syt {
3052fcbc377Syt 	int	ret;
3062fcbc377Syt 
3072fcbc377Syt 	ret = ddi_soft_state_init(&ahci_statep, sizeof (ahci_ctl_t), 0);
3082fcbc377Syt 	if (ret != 0) {
3092fcbc377Syt 		goto err_out;
3102fcbc377Syt 	}
3112fcbc377Syt 
3122fcbc377Syt 	mutex_init(&ahci_log_mutex, NULL, MUTEX_DRIVER, NULL);
3132fcbc377Syt 
3142fcbc377Syt 	if ((ret = sata_hba_init(&modlinkage)) != 0) {
3152fcbc377Syt 		mutex_destroy(&ahci_log_mutex);
3162fcbc377Syt 		ddi_soft_state_fini(&ahci_statep);
3172fcbc377Syt 		goto err_out;
3182fcbc377Syt 	}
3192fcbc377Syt 
3202fcbc377Syt 	ret = mod_install(&modlinkage);
3212fcbc377Syt 	if (ret != 0) {
3222fcbc377Syt 		sata_hba_fini(&modlinkage);
3232fcbc377Syt 		mutex_destroy(&ahci_log_mutex);
3242fcbc377Syt 		ddi_soft_state_fini(&ahci_statep);
3252fcbc377Syt 		goto err_out;
3262fcbc377Syt 	}
3272fcbc377Syt 
3282fcbc377Syt 	/* watchdog tick */
3292fcbc377Syt 	ahci_watchdog_tick = drv_usectohz(
3302fcbc377Syt 	    (clock_t)ahci_watchdog_timeout * 1000000);
3312fcbc377Syt 	return (ret);
3322fcbc377Syt 
3332fcbc377Syt err_out:
3342fcbc377Syt 	cmn_err(CE_WARN, "!Module init failed");
3352fcbc377Syt 	return (ret);
3362fcbc377Syt }
3372fcbc377Syt 
3382fcbc377Syt /*
3392fcbc377Syt  * ahci module uninitialize.
3402fcbc377Syt  */
3412fcbc377Syt int
3422fcbc377Syt _fini(void)
3432fcbc377Syt {
3442fcbc377Syt 	int	ret;
3452fcbc377Syt 
3462fcbc377Syt 	ret = mod_remove(&modlinkage);
3472fcbc377Syt 	if (ret != 0) {
3482fcbc377Syt 		return (ret);
3492fcbc377Syt 	}
3502fcbc377Syt 
3512fcbc377Syt 	/* Remove the resources allocated in _init(). */
3522fcbc377Syt 	sata_hba_fini(&modlinkage);
3532fcbc377Syt 	mutex_destroy(&ahci_log_mutex);
3542fcbc377Syt 	ddi_soft_state_fini(&ahci_statep);
3552fcbc377Syt 
3562fcbc377Syt 	return (ret);
3572fcbc377Syt }
3582fcbc377Syt 
3592fcbc377Syt /*
3602fcbc377Syt  * _info entry point
3612fcbc377Syt  */
3622fcbc377Syt int
3632fcbc377Syt _info(struct modinfo *modinfop)
3642fcbc377Syt {
3652fcbc377Syt 	return (mod_info(&modlinkage, modinfop));
3662fcbc377Syt }
3672fcbc377Syt 
3682fcbc377Syt /*
3692fcbc377Syt  * The attach entry point for dev_ops.
3702fcbc377Syt  */
3712fcbc377Syt static int
3722fcbc377Syt ahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3732fcbc377Syt {
3742fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
3752fcbc377Syt 	int instance = ddi_get_instance(dip);
3762fcbc377Syt 	int status;
3772fcbc377Syt 	int attach_state;
3782fcbc377Syt 	uint32_t cap_status, ahci_version;
3792fcbc377Syt 	int intr_types;
3802fcbc377Syt 	ushort_t venid;
3812fcbc377Syt 	uint8_t revision;
38268d33a25Syt 	int i;
383*95c11c1fSyt 	pci_regspec_t *regs;
384*95c11c1fSyt 	int regs_length;
385*95c11c1fSyt 	int rnumber;
38668d33a25Syt #if AHCI_DEBUG
38768d33a25Syt 	int speed;
38868d33a25Syt #endif
3892fcbc377Syt 
3902fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, NULL, "ahci_attach enter");
3912fcbc377Syt 
3922fcbc377Syt 	switch (cmd) {
3932fcbc377Syt 	case DDI_ATTACH:
3942fcbc377Syt 		break;
3952fcbc377Syt 
3962fcbc377Syt 	case DDI_RESUME:
3972fcbc377Syt 		/* It will be implemented in Phase 2 */
3982fcbc377Syt 		return (DDI_FAILURE);
3992fcbc377Syt 
4002fcbc377Syt 	default:
4012fcbc377Syt 		return (DDI_FAILURE);
4022fcbc377Syt 	}
4032fcbc377Syt 
4042fcbc377Syt 	attach_state = AHCI_ATTACH_STATE_NONE;
4052fcbc377Syt 
4062fcbc377Syt 	/* Allocate soft state */
4072fcbc377Syt 	status = ddi_soft_state_zalloc(ahci_statep, instance);
4082fcbc377Syt 	if (status != DDI_SUCCESS) {
40968d33a25Syt 		cmn_err(CE_WARN, "!Cannot allocate soft state");
4102fcbc377Syt 		goto err_out;
4112fcbc377Syt 	}
4122fcbc377Syt 
4132fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
4142fcbc377Syt 	ahci_ctlp->ahcictl_dip = dip;
4152fcbc377Syt 
41668d33a25Syt 	/* Initialize the cport/port mapping */
41768d33a25Syt 	for (i = 0; i < AHCI_MAX_PORTS; i++) {
41868d33a25Syt 		ahci_ctlp->ahcictl_port_to_cport[i] = 0xff;
41968d33a25Syt 		ahci_ctlp->ahcictl_cport_to_port[i] = 0xff;
42068d33a25Syt 	}
42168d33a25Syt 
4222fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_STATEP_ALLOC;
4232fcbc377Syt 
4242fcbc377Syt 	/*
4252fcbc377Syt 	 * Now map the AHCI base address; which includes global
4262fcbc377Syt 	 * registers and port control registers
427*95c11c1fSyt 	 *
428*95c11c1fSyt 	 * According to the spec, the AHCI Base Address is BAR5,
429*95c11c1fSyt 	 * but we found JMicron JMB363 PATA-SATA chipset doesn't
430*95c11c1fSyt 	 * follow this, so we need to check which rnumber is used
431*95c11c1fSyt 	 */
432*95c11c1fSyt 
433*95c11c1fSyt 	/*
434*95c11c1fSyt 	 * search through DDI "reg" property for the AHCI register set
4352fcbc377Syt 	 */
436*95c11c1fSyt 	if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
437*95c11c1fSyt 	    DDI_PROP_DONTPASS, "reg", (int **)&regs,
438*95c11c1fSyt 	    (uint_t *)&regs_length) != DDI_PROP_SUCCESS) {
439*95c11c1fSyt 		cmn_err(CE_WARN, "!Cannot lookup reg property");
440*95c11c1fSyt 		goto err_out;
441*95c11c1fSyt 	}
442*95c11c1fSyt 
443*95c11c1fSyt 	/* AHCI Base Address is located at 0x24 offset */
444*95c11c1fSyt 	for (rnumber = 0; rnumber < regs_length; ++rnumber) {
445*95c11c1fSyt 		if ((regs[rnumber].pci_phys_hi & PCI_REG_REG_M)
446*95c11c1fSyt 		    == AHCI_PCI_RNUM)
447*95c11c1fSyt 			break;
448*95c11c1fSyt 	}
449*95c11c1fSyt 
450*95c11c1fSyt 	ddi_prop_free(regs);
451*95c11c1fSyt 
452*95c11c1fSyt 	if (rnumber == regs_length) {
453*95c11c1fSyt 		cmn_err(CE_WARN, "!Cannot find AHCI register set");
454*95c11c1fSyt 		goto err_out;
455*95c11c1fSyt 	}
456*95c11c1fSyt 
457*95c11c1fSyt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
458*95c11c1fSyt 
4592fcbc377Syt 	status = ddi_regs_map_setup(dip,
460*95c11c1fSyt 	    rnumber,
4612fcbc377Syt 	    (caddr_t *)&ahci_ctlp->ahcictl_ahci_addr,
4622fcbc377Syt 	    0,
4632fcbc377Syt 	    0,
4642fcbc377Syt 	    &accattr,
4652fcbc377Syt 	    &ahci_ctlp->ahcictl_ahci_acc_handle);
4662fcbc377Syt 	if (status != DDI_SUCCESS) {
46768d33a25Syt 		cmn_err(CE_WARN, "!Cannot map register space");
4682fcbc377Syt 		goto err_out;
4692fcbc377Syt 	}
4702fcbc377Syt 
4712fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_REG_MAP;
4722fcbc377Syt 
4732fcbc377Syt 	/* Get the AHCI version information */
4742fcbc377Syt 	ahci_version = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
4752fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_VS(ahci_ctlp));
4762fcbc377Syt 
47768d33a25Syt 	cmn_err(CE_NOTE, "!hba AHCI version = %x.%x",
4782fcbc377Syt 	    (ahci_version & 0xffff0000) >> 16,
4792fcbc377Syt 	    ((ahci_version & 0x0000ff00) >> 4 |
4802fcbc377Syt 	    (ahci_version & 0x000000ff)));
4812fcbc377Syt 
4822fcbc377Syt 	/* We don't support controllers whose versions are lower than 1.0 */
4832fcbc377Syt 	if (!(ahci_version & 0xffff0000)) {
48468d33a25Syt 		cmn_err(CE_WARN, "Don't support AHCI HBA with lower than "
48568d33a25Syt 		    "version 1.0");
4862fcbc377Syt 		goto err_out;
4872fcbc377Syt 	}
4882fcbc377Syt 
4892fcbc377Syt 	/* Get the HBA capabilities information */
4902fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
4912fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
4922fcbc377Syt 
4932fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba capabilites = 0x%x",
4942fcbc377Syt 	    cap_status);
4952fcbc377Syt 
49668d33a25Syt #if AHCI_DEBUG
49768d33a25Syt 	/* Get the interface speed supported by the HBA */
49868d33a25Syt 	speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
49968d33a25Syt 	if (speed == 0x01) {
50068d33a25Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
50168d33a25Syt 		    "hba interface speed support: Gen 1 (1.5Gbps)");
50268d33a25Syt 	} else if (speed == 0x10) {
50368d33a25Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
50468d33a25Syt 		    "hba interface speed support: Gen 2 (3 Gbps)");
50568d33a25Syt 	} else if (speed == 0x11) {
50668d33a25Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
50768d33a25Syt 		    "hba interface speed support: Gen 3 (6 Gbps)");
50868d33a25Syt 	}
50968d33a25Syt #endif
51068d33a25Syt 
5112fcbc377Syt 	/* Get the number of command slots supported by the HBA */
5122fcbc377Syt 	ahci_ctlp->ahcictl_num_cmd_slots =
5132fcbc377Syt 	    ((cap_status & AHCI_HBA_CAP_NCS) >>
5142fcbc377Syt 	    AHCI_HBA_CAP_NCS_SHIFT) + 1;
5152fcbc377Syt 
51668d33a25Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
5172fcbc377Syt 	    ahci_ctlp->ahcictl_num_cmd_slots);
5182fcbc377Syt 
5192fcbc377Syt 	/* Get the bit map which indicates ports implemented by the HBA */
5202fcbc377Syt 	ahci_ctlp->ahcictl_ports_implemented =
5212fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
5222fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_PI(ahci_ctlp));
5232fcbc377Syt 
5242fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
5252fcbc377Syt 	    ahci_ctlp->ahcictl_ports_implemented);
5262fcbc377Syt 
52709121340Syt 	/*
52809121340Syt 	 * According to the AHCI spec, CAP.NP should indicate the maximum
52909121340Syt 	 * number of ports supported by the HBA silicon, but we found
53009121340Syt 	 * this value of ICH8 chipset only indicates the number of ports
53109121340Syt 	 * implemented (exposed) by it. Therefore, the driver should calculate
53209121340Syt 	 * the potential maximum value by checking PI register, and use
53309121340Syt 	 * the maximum of this value and CAP.NP.
53409121340Syt 	 */
53509121340Syt 	ahci_ctlp->ahcictl_num_ports = max(
53609121340Syt 	    (cap_status & AHCI_HBA_CAP_NP) + 1,
53709121340Syt 	    ddi_fls(ahci_ctlp->ahcictl_ports_implemented));
53809121340Syt 
53909121340Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
54009121340Syt 	    ahci_ctlp->ahcictl_num_ports);
54109121340Syt 
5422fcbc377Syt 	/* Get the number of implemented ports by the HBA */
5432fcbc377Syt 	ahci_ctlp->ahcictl_num_implemented_ports =
5442fcbc377Syt 	    ahci_get_num_implemented_ports(
5452fcbc377Syt 	    ahci_ctlp->ahcictl_ports_implemented);
5462fcbc377Syt 
5472fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
54868d33a25Syt 	    "hba number of implemented ports: %d",
5492fcbc377Syt 	    ahci_ctlp->ahcictl_num_implemented_ports);
5502fcbc377Syt 
5512fcbc377Syt 	ahci_ctlp->ahcictl_buffer_dma_attr = buffer_dma_attr;
5522fcbc377Syt 
5532fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
5542fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
5552fcbc377Syt 		    "hba does not support 64-bit addressing");
5562fcbc377Syt 		ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_addr_hi =
5572fcbc377Syt 		    0xffffffffull;
5582fcbc377Syt 	}
5592fcbc377Syt 
5602fcbc377Syt 	if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle)
5612fcbc377Syt 	    != DDI_SUCCESS) {
56268d33a25Syt 		cmn_err(CE_WARN, "!Cannot set up pci configure space");
5632fcbc377Syt 		goto err_out;
5642fcbc377Syt 	}
5652fcbc377Syt 
56668d33a25Syt 	attach_state |= AHCI_ATTACH_STATE_PCICFG_SETUP;
56768d33a25Syt 
56868d33a25Syt 	/*
56968d33a25Syt 	 * Modify dma_attr_align of ahcictl_buffer_dma_attr. For VT8251, those
57068d33a25Syt 	 * controllers with 0x00 revision id work on 4-byte aligned buffer,
57168d33a25Syt 	 * which is a bug and was fixed after 0x00 revision id controllers.
57268d33a25Syt 	 *
57382263d52Syt 	 * Moreover, VT8251 cannot use multiple command slots in the command
57482263d52Syt 	 * list for non-queued commands because the previous register content
57582263d52Syt 	 * of PxCI can be re-written in the register write, so a flag will be
57682263d52Syt 	 * set to record this defect - AHCI_CAP_NO_MCMDLIST_NONQUEUE.
57768d33a25Syt 	 */
5782fcbc377Syt 	venid = pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
5792fcbc377Syt 	    PCI_CONF_VENID);
5802fcbc377Syt 
5812fcbc377Syt 	if (venid == VIA_VENID) {
5822fcbc377Syt 		revision = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
5832fcbc377Syt 		    PCI_CONF_REVID);
5842fcbc377Syt 		AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
5852fcbc377Syt 		    "revision id = 0x%x", revision);
5862fcbc377Syt 		if (revision == 0x00) {
5872fcbc377Syt 			ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_align = 0x4;
5882fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
5892fcbc377Syt 			    "change ddi_attr_align to 0x4");
5902fcbc377Syt 		}
5912fcbc377Syt 
59268d33a25Syt 		ahci_ctlp->ahcictl_cap = AHCI_CAP_NO_MCMDLIST_NONQUEUE;
59368d33a25Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
59468d33a25Syt 		    "VT8251 cannot use multiple command lists for "
59568d33a25Syt 		    "non-queued commands");
59668d33a25Syt 	}
5972fcbc377Syt 
5982fcbc377Syt 	/*
5992fcbc377Syt 	 * Disable the whole controller interrupts before adding
6002fcbc377Syt 	 * interrupt handlers(s).
6012fcbc377Syt 	 */
6022fcbc377Syt 	ahci_disable_all_intrs(ahci_ctlp);
6032fcbc377Syt 
6042fcbc377Syt 	/* Get supported interrupt types */
6052fcbc377Syt 	if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
60668d33a25Syt 		cmn_err(CE_WARN, "!ddi_intr_get_supported_types failed");
6072fcbc377Syt 		goto err_out;
6082fcbc377Syt 	}
6092fcbc377Syt 
6102fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
6112fcbc377Syt 	    "ddi_intr_get_supported_types() returned: 0x%x",
6122fcbc377Syt 	    intr_types);
6132fcbc377Syt 
6142fcbc377Syt 	if (ahci_msi_enabled && (intr_types & DDI_INTR_TYPE_MSI)) {
6152fcbc377Syt 		/*
6162fcbc377Syt 		 * Try MSI first, but fall back to FIXED if failed
6172fcbc377Syt 		 */
6182fcbc377Syt 		if (ahci_add_msi_intrs(ahci_ctlp) == DDI_SUCCESS) {
6192fcbc377Syt 			ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_MSI;
6202fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
6212fcbc377Syt 			    "Using MSI interrupt type");
6222fcbc377Syt 			goto intr_done;
6232fcbc377Syt 		}
6242fcbc377Syt 
6252fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
6262fcbc377Syt 		    "MSI registration failed, "
6272fcbc377Syt 		    "trying FIXED interrupts");
6282fcbc377Syt 	}
6292fcbc377Syt 
6302fcbc377Syt 	if (intr_types & DDI_INTR_TYPE_FIXED) {
6312fcbc377Syt 		if (ahci_add_legacy_intrs(ahci_ctlp) == DDI_SUCCESS) {
6322fcbc377Syt 			ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_FIXED;
6332fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, NULL,
6342fcbc377Syt 			    "Using FIXED interrupt type");
6352fcbc377Syt 			goto intr_done;
6362fcbc377Syt 		}
6372fcbc377Syt 
6382fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
6392fcbc377Syt 		    "FIXED interrupt registration failed");
6402fcbc377Syt 	}
6412fcbc377Syt 
6422fcbc377Syt 	cmn_err(CE_WARN, "!Interrupt registration failed");
6432fcbc377Syt 
6442fcbc377Syt 	goto err_out;
6452fcbc377Syt 
6462fcbc377Syt intr_done:
6472fcbc377Syt 
6482fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_INTR_ADDED;
6492fcbc377Syt 
6502fcbc377Syt 	/* Initialize the controller mutex */
6512fcbc377Syt 	mutex_init(&ahci_ctlp->ahcictl_mutex, NULL, MUTEX_DRIVER,
6522fcbc377Syt 	    (void *)(uintptr_t)ahci_ctlp->ahcictl_intr_pri);
6532fcbc377Syt 
6542fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_MUTEX_INIT;
6552fcbc377Syt 
6562fcbc377Syt 	if (ahci_dma_prdt_number < AHCI_MIN_PRDT_NUMBER) {
6572fcbc377Syt 		ahci_dma_prdt_number = AHCI_MIN_PRDT_NUMBER;
6582fcbc377Syt 	} else if (ahci_dma_prdt_number > AHCI_MAX_PRDT_NUMBER) {
6592fcbc377Syt 		ahci_dma_prdt_number = AHCI_MAX_PRDT_NUMBER;
6602fcbc377Syt 	}
6612fcbc377Syt 
6622fcbc377Syt 	ahci_cmd_table_size = (sizeof (ahci_cmd_table_t) +
6632fcbc377Syt 	    (ahci_dma_prdt_number - AHCI_PRDT_NUMBER) *
6642fcbc377Syt 	    sizeof (ahci_prdt_item_t));
6652fcbc377Syt 
6662fcbc377Syt 	AHCIDBG2(AHCIDBG_INIT, ahci_ctlp,
6672fcbc377Syt 	    "ahci_attach: ahci_dma_prdt_number set by user is 0x%x,"
6682fcbc377Syt 	    " ahci_cmd_table_size is 0x%x",
6692fcbc377Syt 	    ahci_dma_prdt_number, ahci_cmd_table_size);
6702fcbc377Syt 
6712fcbc377Syt 	if (ahci_dma_prdt_number != AHCI_PRDT_NUMBER)
6722fcbc377Syt 		ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_sgllen =
6732fcbc377Syt 		    ahci_dma_prdt_number;
6742fcbc377Syt 
67568d33a25Syt 	/* Allocate the ports structure */
67668d33a25Syt 	status = ahci_alloc_ports_state(ahci_ctlp);
67768d33a25Syt 	if (status != AHCI_SUCCESS) {
67868d33a25Syt 		cmn_err(CE_WARN, "!Cannot allocate ports structure");
67968d33a25Syt 		goto err_out;
68068d33a25Syt 	}
68168d33a25Syt 
68268d33a25Syt 	attach_state |= AHCI_ATTACH_STATE_PORT_ALLOC;
68368d33a25Syt 
68468d33a25Syt 	/*
68568d33a25Syt 	 * A taskq is created for dealing with events
68668d33a25Syt 	 */
68768d33a25Syt 	if ((ahci_ctlp->ahcictl_event_taskq = ddi_taskq_create(dip,
68868d33a25Syt 	    "ahci_event_handle_taskq", 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
68968d33a25Syt 		cmn_err(CE_WARN, "!ddi_taskq_create failed for event handle");
69068d33a25Syt 		goto err_out;
69168d33a25Syt 	}
69268d33a25Syt 
69368d33a25Syt 	attach_state |= AHCI_ATTACH_STATE_ERR_RECV_TASKQ;
69468d33a25Syt 
6952fcbc377Syt 	/*
69668d33a25Syt 	 * Initialize the controller and ports.
6972fcbc377Syt 	 */
6982fcbc377Syt 	ahci_ctlp->ahcictl_flags |= AHCI_ATTACH;
6992fcbc377Syt 	status = ahci_initialize_controller(ahci_ctlp);
7002fcbc377Syt 	ahci_ctlp->ahcictl_flags &= ~AHCI_ATTACH;
7012fcbc377Syt 	if (status != AHCI_SUCCESS) {
70268d33a25Syt 		cmn_err(CE_WARN, "!HBA initialization failed");
7032fcbc377Syt 		goto err_out;
7042fcbc377Syt 	}
7052fcbc377Syt 
7062fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_HW_INIT;
7072fcbc377Syt 
7082fcbc377Syt 	/* Start one thread to check packet timeouts */
7092fcbc377Syt 	ahci_ctlp->ahcictl_timeout_id = timeout(
7102fcbc377Syt 	    (void (*)(void *))ahci_watchdog_handler,
7112fcbc377Syt 	    (caddr_t)ahci_ctlp, ahci_watchdog_tick);
7122fcbc377Syt 
7132fcbc377Syt 	attach_state |= AHCI_ATTACH_STATE_TIMEOUT_ENABLED;
7142fcbc377Syt 
7152fcbc377Syt 	if (ahci_register_sata_hba_tran(ahci_ctlp, cap_status)) {
71668d33a25Syt 		cmn_err(CE_WARN, "!sata hba tran registration failed");
7172fcbc377Syt 		goto err_out;
7182fcbc377Syt 	}
7192fcbc377Syt 
7202fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!");
7212fcbc377Syt 
7222fcbc377Syt 	return (DDI_SUCCESS);
7232fcbc377Syt 
7242fcbc377Syt err_out:
7252fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_TIMEOUT_ENABLED) {
7262fcbc377Syt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
7272fcbc377Syt 		(void) untimeout(ahci_ctlp->ahcictl_timeout_id);
7282fcbc377Syt 		ahci_ctlp->ahcictl_timeout_id = 0;
7292fcbc377Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
7302fcbc377Syt 	}
7312fcbc377Syt 
7322fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_HW_INIT) {
7332fcbc377Syt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
73468d33a25Syt 		ahci_uninitialize_controller(ahci_ctlp);
7352fcbc377Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
7362fcbc377Syt 	}
7372fcbc377Syt 
73868d33a25Syt 	if (attach_state & AHCI_ATTACH_STATE_ERR_RECV_TASKQ) {
73968d33a25Syt 		ddi_taskq_destroy(ahci_ctlp->ahcictl_event_taskq);
74068d33a25Syt 	}
74168d33a25Syt 
74268d33a25Syt 	if (attach_state & AHCI_ATTACH_STATE_PORT_ALLOC) {
74368d33a25Syt 		ahci_dealloc_ports_state(ahci_ctlp);
74468d33a25Syt 	}
74568d33a25Syt 
7462fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_MUTEX_INIT) {
7472fcbc377Syt 		mutex_destroy(&ahci_ctlp->ahcictl_mutex);
7482fcbc377Syt 	}
7492fcbc377Syt 
7502fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_INTR_ADDED) {
7512fcbc377Syt 		ahci_rem_intrs(ahci_ctlp);
7522fcbc377Syt 	}
7532fcbc377Syt 
75468d33a25Syt 	if (attach_state & AHCI_ATTACH_STATE_PCICFG_SETUP) {
75568d33a25Syt 		pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
75668d33a25Syt 	}
75768d33a25Syt 
7582fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_REG_MAP) {
7592fcbc377Syt 		ddi_regs_map_free(&ahci_ctlp->ahcictl_ahci_acc_handle);
7602fcbc377Syt 	}
7612fcbc377Syt 
7622fcbc377Syt 	if (attach_state & AHCI_ATTACH_STATE_STATEP_ALLOC) {
7632fcbc377Syt 		ddi_soft_state_free(ahci_statep, instance);
7642fcbc377Syt 	}
7652fcbc377Syt 
7662fcbc377Syt 	return (DDI_FAILURE);
7672fcbc377Syt }
7682fcbc377Syt 
7692fcbc377Syt /*
7702fcbc377Syt  * The detach entry point for dev_ops.
7712fcbc377Syt  */
7722fcbc377Syt static int
7732fcbc377Syt ahci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
7742fcbc377Syt {
7752fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
7762fcbc377Syt 	int instance;
7772fcbc377Syt 	int ret;
7782fcbc377Syt 
7792fcbc377Syt 	instance = ddi_get_instance(dip);
7802fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
7812fcbc377Syt 
7822fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter");
7832fcbc377Syt 
7842fcbc377Syt 	switch (cmd) {
7852fcbc377Syt 	case DDI_DETACH:
7862fcbc377Syt 		/* disable the interrupts for an uninterrupted detach */
7872fcbc377Syt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
7882fcbc377Syt 		ahci_disable_all_intrs(ahci_ctlp);
7892fcbc377Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
7902fcbc377Syt 
7912fcbc377Syt 		/* unregister from the sata framework. */
7922fcbc377Syt 		ret = ahci_unregister_sata_hba_tran(ahci_ctlp);
7932fcbc377Syt 		if (ret != AHCI_SUCCESS) {
7942fcbc377Syt 			mutex_enter(&ahci_ctlp->ahcictl_mutex);
7952fcbc377Syt 			ahci_enable_all_intrs(ahci_ctlp);
7962fcbc377Syt 			mutex_exit(&ahci_ctlp->ahcictl_mutex);
7972fcbc377Syt 			return (DDI_FAILURE);
7982fcbc377Syt 		}
7992fcbc377Syt 
8002fcbc377Syt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
8012fcbc377Syt 
8022fcbc377Syt 		/* stop the watchdog handler */
8032fcbc377Syt 		(void) untimeout(ahci_ctlp->ahcictl_timeout_id);
8042fcbc377Syt 		ahci_ctlp->ahcictl_timeout_id = 0;
8052fcbc377Syt 
80668d33a25Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
80768d33a25Syt 
80868d33a25Syt 		/* uninitialize the controller */
8092fcbc377Syt 		ahci_ctlp->ahcictl_flags |= AHCI_DETACH;
81068d33a25Syt 		ahci_uninitialize_controller(ahci_ctlp);
8112fcbc377Syt 		ahci_ctlp->ahcictl_flags &= ~AHCI_DETACH;
8122fcbc377Syt 
81368d33a25Syt 		/* remove the interrupts */
81468d33a25Syt 		ahci_rem_intrs(ahci_ctlp);
8152fcbc377Syt 
81668d33a25Syt 		/* destroy the taskq */
81768d33a25Syt 		ddi_taskq_destroy(ahci_ctlp->ahcictl_event_taskq);
8182fcbc377Syt 
81968d33a25Syt 		/* deallocate the ports structures */
82068d33a25Syt 		ahci_dealloc_ports_state(ahci_ctlp);
82168d33a25Syt 
82268d33a25Syt 		/* destroy mutex */
8232fcbc377Syt 		mutex_destroy(&ahci_ctlp->ahcictl_mutex);
8242fcbc377Syt 
82568d33a25Syt 		/* teardown the pci config */
82668d33a25Syt 		pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
8272fcbc377Syt 
8282fcbc377Syt 		/* remove the reg maps. */
8292fcbc377Syt 		ddi_regs_map_free(&ahci_ctlp->ahcictl_ahci_acc_handle);
8302fcbc377Syt 
8312fcbc377Syt 		/* free the soft state. */
8322fcbc377Syt 		ddi_soft_state_free(ahci_statep, instance);
8332fcbc377Syt 
8342fcbc377Syt 		return (DDI_SUCCESS);
8352fcbc377Syt 
8362fcbc377Syt 	case DDI_SUSPEND:
8372fcbc377Syt 		/* It will be implemented in Phase 2 */
8382fcbc377Syt 		return (DDI_FAILURE);
8392fcbc377Syt 
8402fcbc377Syt 	default:
8412fcbc377Syt 		return (DDI_FAILURE);
8422fcbc377Syt 	}
8432fcbc377Syt }
8442fcbc377Syt 
8452fcbc377Syt /*
8462fcbc377Syt  * The info entry point for dev_ops.
8472fcbc377Syt  *
8482fcbc377Syt  */
8492fcbc377Syt static int
8502fcbc377Syt ahci_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
8512fcbc377Syt 		    void *arg, void **result)
8522fcbc377Syt {
8532fcbc377Syt #ifndef __lock_lint
8542fcbc377Syt 	_NOTE(ARGUNUSED(dip))
8552fcbc377Syt #endif /* __lock_lint */
8562fcbc377Syt 
8572fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
8582fcbc377Syt 	int instance;
8592fcbc377Syt 	dev_t dev;
8602fcbc377Syt 
8612fcbc377Syt 	dev = (dev_t)arg;
8622fcbc377Syt 	instance = getminor(dev);
8632fcbc377Syt 
8642fcbc377Syt 	switch (infocmd) {
8652fcbc377Syt 		case DDI_INFO_DEVT2DEVINFO:
8662fcbc377Syt 			ahci_ctlp = ddi_get_soft_state(ahci_statep,  instance);
8672fcbc377Syt 			if (ahci_ctlp != NULL) {
8682fcbc377Syt 				*result = ahci_ctlp->ahcictl_dip;
8692fcbc377Syt 				return (DDI_SUCCESS);
8702fcbc377Syt 			} else {
8712fcbc377Syt 				*result = NULL;
8722fcbc377Syt 				return (DDI_FAILURE);
8732fcbc377Syt 			}
8742fcbc377Syt 		case DDI_INFO_DEVT2INSTANCE:
8752fcbc377Syt 			*(int *)result = instance;
8762fcbc377Syt 			break;
8772fcbc377Syt 		default:
8782fcbc377Syt 			break;
8792fcbc377Syt 	}
8802fcbc377Syt 
8812fcbc377Syt 	return (DDI_SUCCESS);
8822fcbc377Syt }
8832fcbc377Syt 
8842fcbc377Syt /*
8852fcbc377Syt  * Registers the ahci with sata framework.
8862fcbc377Syt  */
8872fcbc377Syt static int
8882fcbc377Syt ahci_register_sata_hba_tran(ahci_ctl_t *ahci_ctlp, uint32_t cap_status)
8892fcbc377Syt {
8902fcbc377Syt 	struct 	sata_hba_tran	*sata_hba_tran;
8912fcbc377Syt 
8922fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8932fcbc377Syt 	    "ahci_register_sata_hba_tran enter");
8942fcbc377Syt 
8952fcbc377Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
8962fcbc377Syt 
8972fcbc377Syt 	/* Allocate memory for the sata_hba_tran  */
8982fcbc377Syt 	sata_hba_tran = kmem_zalloc(sizeof (sata_hba_tran_t), KM_SLEEP);
8992fcbc377Syt 
90068d33a25Syt 	sata_hba_tran->sata_tran_hba_rev = SATA_TRAN_HBA_REV_2;
9012fcbc377Syt 	sata_hba_tran->sata_tran_hba_dip = ahci_ctlp->ahcictl_dip;
9022fcbc377Syt 	sata_hba_tran->sata_tran_hba_dma_attr =
9032fcbc377Syt 	    &ahci_ctlp->ahcictl_buffer_dma_attr;
9042fcbc377Syt 
9052fcbc377Syt 	/* Report the number of implemented ports */
9062fcbc377Syt 	sata_hba_tran->sata_tran_hba_num_cports =
9072fcbc377Syt 	    ahci_ctlp->ahcictl_num_implemented_ports;
9082fcbc377Syt 
90968d33a25Syt 	/* Support ATAPI device */
91068d33a25Syt 	sata_hba_tran->sata_tran_hba_features_support = SATA_CTLF_ATAPI;
9112fcbc377Syt 
9122fcbc377Syt 	/* Get the data transfer capability for PIO command by the HBA */
9132fcbc377Syt 	if (cap_status & AHCI_HBA_CAP_PMD) {
91482263d52Syt 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_PIO_MDRQ;
9152fcbc377Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple "
9162fcbc377Syt 		    "DRQ block data transfer for PIO command protocol");
9172fcbc377Syt 	} else {
9182fcbc377Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA only supports single "
9192fcbc377Syt 		    "DRQ block data transfer for PIO command protocol");
9202fcbc377Syt 	}
9212fcbc377Syt 
92282263d52Syt 	/*
92382263d52Syt 	 * According to the AHCI spec, the ATA/ATAPI-7 queued feature set
92482263d52Syt 	 * is not supported by AHCI (including the READ QUEUED (EXT), WRITE
92582263d52Syt 	 * QUEUED (EXT), and SERVICE commands). Queued operations are
92682263d52Syt 	 * supported in AHCI using the READ FPDMA QUEUED and WRITE FPDMA
92782263d52Syt 	 * QUEUED commands when the HBA and device support native command
92882263d52Syt 	 * queuing(NCQ).
92982263d52Syt 	 *
93082263d52Syt 	 * SATA_CTLF_NCQ will be set to sata_tran_hba_features_support if the
93182263d52Syt 	 * CAP register of the HBA indicates NCQ is supported.
93282263d52Syt 	 *
93382263d52Syt 	 * SATA_CTLF_NCQ cannot be set if AHCI_CAP_NO_MCMDLIST_NONQUEUE is
93482263d52Syt 	 * set because the previous register content of PxCI can be re-written
93582263d52Syt 	 * in the register write.
93682263d52Syt 	 */
93782263d52Syt 	if ((cap_status & AHCI_HBA_CAP_SNCQ) &&
93882263d52Syt 	    !(ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE)) {
93982263d52Syt 		sata_hba_tran->sata_tran_hba_features_support |= SATA_CTLF_NCQ;
94082263d52Syt 		ahci_ctlp->ahcictl_cap |= AHCI_CAP_NCQ;
94182263d52Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native "
94282263d52Syt 		    "Command Queuing");
94382263d52Syt 	}
94482263d52Syt 
9452fcbc377Syt 	/* Report the number of command slots */
9462fcbc377Syt 	sata_hba_tran->sata_tran_hba_qdepth = ahci_ctlp->ahcictl_num_cmd_slots;
9472fcbc377Syt 
9482fcbc377Syt 	sata_hba_tran->sata_tran_probe_port = ahci_tran_probe_port;
9492fcbc377Syt 	sata_hba_tran->sata_tran_start = ahci_tran_start;
9502fcbc377Syt 	sata_hba_tran->sata_tran_abort = ahci_tran_abort;
9512fcbc377Syt 	sata_hba_tran->sata_tran_reset_dport = ahci_tran_reset_dport;
9522fcbc377Syt 	sata_hba_tran->sata_tran_hotplug_ops = &ahci_tran_hotplug_ops;
9532fcbc377Syt #ifdef __lock_lint
9542fcbc377Syt 	sata_hba_tran->sata_tran_selftest = ahci_selftest;
9552fcbc377Syt #endif
9562fcbc377Syt 	/*
9572fcbc377Syt 	 * When SATA framework adds support for pwrmgt the
9582fcbc377Syt 	 * pwrmgt_ops needs to be updated
9592fcbc377Syt 	 */
9602fcbc377Syt 	sata_hba_tran->sata_tran_pwrmgt_ops = NULL;
9612fcbc377Syt 	sata_hba_tran->sata_tran_ioctl = NULL;
9622fcbc377Syt 
9632fcbc377Syt 	ahci_ctlp->ahcictl_sata_hba_tran = sata_hba_tran;
9642fcbc377Syt 
9652fcbc377Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
9662fcbc377Syt 
9672fcbc377Syt 	/* Attach it to SATA framework */
9682fcbc377Syt 	if (sata_hba_attach(ahci_ctlp->ahcictl_dip, sata_hba_tran, DDI_ATTACH)
9692fcbc377Syt 	    != DDI_SUCCESS) {
9702fcbc377Syt 		kmem_free((void *)sata_hba_tran, sizeof (sata_hba_tran_t));
9712fcbc377Syt 		mutex_enter(&ahci_ctlp->ahcictl_mutex);
9722fcbc377Syt 		ahci_ctlp->ahcictl_sata_hba_tran = NULL;
9732fcbc377Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
9742fcbc377Syt 		return (AHCI_FAILURE);
9752fcbc377Syt 	}
9762fcbc377Syt 
9772fcbc377Syt 	return (AHCI_SUCCESS);
9782fcbc377Syt }
9792fcbc377Syt 
9802fcbc377Syt /*
9812fcbc377Syt  * Unregisters the ahci with sata framework.
9822fcbc377Syt  */
9832fcbc377Syt static int
9842fcbc377Syt ahci_unregister_sata_hba_tran(ahci_ctl_t *ahci_ctlp)
9852fcbc377Syt {
9862fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp,
9872fcbc377Syt 	    "ahci_unregister_sata_hba_tran enter");
9882fcbc377Syt 
9892fcbc377Syt 	/* Detach from the SATA framework. */
9902fcbc377Syt 	if (sata_hba_detach(ahci_ctlp->ahcictl_dip, DDI_DETACH) !=
9912fcbc377Syt 	    DDI_SUCCESS) {
9922fcbc377Syt 		return (AHCI_FAILURE);
9932fcbc377Syt 	}
9942fcbc377Syt 
9952fcbc377Syt 	/* Deallocate sata_hba_tran. */
9962fcbc377Syt 	kmem_free((void *)ahci_ctlp->ahcictl_sata_hba_tran,
9972fcbc377Syt 	    sizeof (sata_hba_tran_t));
9982fcbc377Syt 
9992fcbc377Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
10002fcbc377Syt 	ahci_ctlp->ahcictl_sata_hba_tran = NULL;
10012fcbc377Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
10022fcbc377Syt 
10032fcbc377Syt 	return (AHCI_SUCCESS);
10042fcbc377Syt }
10052fcbc377Syt 
10062fcbc377Syt /*
10072fcbc377Syt  * ahci_tran_probe_port is called by SATA framework. It returns port state,
10082fcbc377Syt  * port status registers and an attached device type via sata_device
10092fcbc377Syt  * structure.
10102fcbc377Syt  *
10112fcbc377Syt  * We return the cached information from a previous hardware probe. The
10122fcbc377Syt  * actual hardware probing itself was done either from within
10132fcbc377Syt  * ahci_initialize_controller() during the driver attach or from a phy
10142fcbc377Syt  * ready change interrupt handler.
10152fcbc377Syt  */
10162fcbc377Syt static int
10172fcbc377Syt ahci_tran_probe_port(dev_info_t *dip, sata_device_t *sd)
10182fcbc377Syt {
10192fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
10202fcbc377Syt 	ahci_port_t *ahci_portp;
10212fcbc377Syt 	uint8_t	cport = sd->satadev_addr.cport;
10222fcbc377Syt 	uint8_t pmport = sd->satadev_addr.pmport;
10232fcbc377Syt 	uint8_t qual = sd->satadev_addr.qual;
10242fcbc377Syt 	uint8_t	device_type;
10252fcbc377Syt 	uint32_t port_state;
10262fcbc377Syt 	uint8_t port;
10272fcbc377Syt 
10282fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
10292fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
10302fcbc377Syt 
10312fcbc377Syt 	AHCIDBG3(AHCIDBG_ENTRY, ahci_ctlp,
103268d33a25Syt 	    "ahci_tran_probe_port enter: cport: %d, "
103368d33a25Syt 	    "pmport: %d, qual: %d", cport, pmport, qual);
10342fcbc377Syt 
10352fcbc377Syt 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
10362fcbc377Syt 
10372fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
10382fcbc377Syt 
10392fcbc377Syt 	port_state = ahci_portp->ahciport_port_state;
10402fcbc377Syt 	switch (port_state) {
10412fcbc377Syt 
10422fcbc377Syt 	case SATA_PSTATE_FAILED:
10432fcbc377Syt 		sd->satadev_state = SATA_PSTATE_FAILED;
10442fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
104568d33a25Syt 		    "ahci_tran_probe_port: port %d PORT FAILED", port);
10462fcbc377Syt 		goto out;
10472fcbc377Syt 
10482fcbc377Syt 	case SATA_PSTATE_SHUTDOWN:
10492fcbc377Syt 		sd->satadev_state = SATA_PSTATE_SHUTDOWN;
10502fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
105168d33a25Syt 		    "ahci_tran_probe_port: port %d PORT SHUTDOWN", port);
10522fcbc377Syt 		goto out;
10532fcbc377Syt 
10542fcbc377Syt 	case SATA_PSTATE_PWROFF:
10552fcbc377Syt 		sd->satadev_state = SATA_PSTATE_PWROFF;
10562fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
105768d33a25Syt 		    "ahci_tran_probe_port: port %d PORT PWROFF", port);
10582fcbc377Syt 		goto out;
10592fcbc377Syt 
10602fcbc377Syt 	case SATA_PSTATE_PWRON:
10612fcbc377Syt 		sd->satadev_state = SATA_PSTATE_PWRON;
10622fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
106368d33a25Syt 		    "ahci_tran_probe_port: port %d PORT PWRON", port);
10642fcbc377Syt 		break;
10652fcbc377Syt 
10662fcbc377Syt 	default:
10672fcbc377Syt 		sd->satadev_state = port_state;
10682fcbc377Syt 		AHCIDBG2(AHCIDBG_INFO, ahci_ctlp,
106968d33a25Syt 		    "ahci_tran_probe_port: port %d PORT NORMAL %x",
10702fcbc377Syt 		    port, port_state);
10712fcbc377Syt 		break;
10722fcbc377Syt 	}
10732fcbc377Syt 
10742fcbc377Syt 	device_type = ahci_portp->ahciport_device_type;
10752fcbc377Syt 
10762fcbc377Syt 	switch (device_type) {
10772fcbc377Syt 
10782fcbc377Syt 	case SATA_DTYPE_ATADISK:
10792fcbc377Syt 		sd->satadev_type = SATA_DTYPE_ATADISK;
10802fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
108168d33a25Syt 		    "ahci_tran_probe_port: port %d DISK found", port);
10822fcbc377Syt 		break;
10832fcbc377Syt 
10842fcbc377Syt 	case SATA_DTYPE_ATAPICD:
10852fcbc377Syt 		sd->satadev_type = SATA_DTYPE_ATAPICD;
10862fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
108768d33a25Syt 		    "ahci_tran_probe_port: port %d ATAPI found", port);
10882fcbc377Syt 		break;
10892fcbc377Syt 
10902fcbc377Syt 	case SATA_DTYPE_PMULT:
10912fcbc377Syt 		sd->satadev_type = SATA_DTYPE_PMULT;
10922fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
109368d33a25Syt 		    "ahci_tran_probe_port: port %d Port Multiplier found",
10942fcbc377Syt 		    port);
10952fcbc377Syt 		break;
10962fcbc377Syt 
10972fcbc377Syt 	case SATA_DTYPE_UNKNOWN:
10982fcbc377Syt 		sd->satadev_type = SATA_DTYPE_UNKNOWN;
10992fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
110068d33a25Syt 		    "ahci_tran_probe_port: port %d Unknown device found", port);
11012fcbc377Syt 		break;
11022fcbc377Syt 
11032fcbc377Syt 	default:
11042fcbc377Syt 		/* we don't support any other device types */
11052fcbc377Syt 		sd->satadev_type = SATA_DTYPE_NONE;
11062fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
110768d33a25Syt 		    "ahci_tran_probe_port: port %d No device found", port);
11082fcbc377Syt 		break;
11092fcbc377Syt 	}
11102fcbc377Syt 
11112fcbc377Syt out:
11122fcbc377Syt 	ahci_update_sata_registers(ahci_ctlp, port, sd);
11132fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
11142fcbc377Syt 
11152fcbc377Syt 	return (SATA_SUCCESS);
11162fcbc377Syt }
11172fcbc377Syt 
111868d33a25Syt /*
111968d33a25Syt  * There are four operation modes in sata framework:
112068d33a25Syt  * SATA_OPMODE_INTERRUPTS
112168d33a25Syt  * SATA_OPMODE_POLLING
112268d33a25Syt  * SATA_OPMODE_ASYNCH
112368d33a25Syt  * SATA_OPMODE_SYNCH
112468d33a25Syt  *
112568d33a25Syt  * Their combined meanings as following:
112668d33a25Syt  *
112768d33a25Syt  * SATA_OPMODE_SYNCH
112868d33a25Syt  * The command has to be completed before sata_tran_start functions returns.
112968d33a25Syt  * Either interrupts or polling could be used - it's up to the driver.
113068d33a25Syt  * Mode used currently for internal, sata-module initiated operations.
113168d33a25Syt  *
113268d33a25Syt  * SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS
113368d33a25Syt  * It is the same as the one above.
113468d33a25Syt  *
113568d33a25Syt  * SATA_OPMODE_SYNCH | SATA_OPMODE_POLLING
113668d33a25Syt  * The command has to be completed before sata_tran_start function returns.
113768d33a25Syt  * No interrupt used, polling only. This should be the mode used for scsi
113868d33a25Syt  * packets with FLAG_NOINTR.
113968d33a25Syt  *
114068d33a25Syt  * SATA_OPMODE_ASYNCH | SATA_OPMODE_INTERRUPTS
114168d33a25Syt  * The command may be queued (callback function specified). Interrupts could
114268d33a25Syt  * be used. It's normal operation mode.
114368d33a25Syt  */
11442fcbc377Syt /*
11452fcbc377Syt  * Called by sata framework to transport a sata packet down stream.
11462fcbc377Syt  */
11472fcbc377Syt static int
11482fcbc377Syt ahci_tran_start(dev_info_t *dip, sata_pkt_t *spkt)
11492fcbc377Syt {
11502fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
11512fcbc377Syt 	ahci_port_t *ahci_portp;
11522fcbc377Syt 	uint8_t	cport = spkt->satapkt_device.satadev_addr.cport;
11532fcbc377Syt 	uint8_t port;
11542fcbc377Syt 
11552fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
11562fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
11572fcbc377Syt 
11582fcbc377Syt 	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp,
11592fcbc377Syt 	    "ahci_tran_start enter: cport %d satapkt 0x%p",
11602fcbc377Syt 	    cport, (void *)spkt);
11612fcbc377Syt 
11622fcbc377Syt 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
11632fcbc377Syt 
11642fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
11652fcbc377Syt 
11662fcbc377Syt 	if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
11672fcbc377Syt 	    ahci_portp->ahciport_port_state & SATA_PSTATE_SHUTDOWN |
11682fcbc377Syt 	    ahci_portp->ahciport_port_state & SATA_PSTATE_PWROFF) {
11692fcbc377Syt 		/*
11702fcbc377Syt 		 * In case the targer driver would send the packet before
11712fcbc377Syt 		 * sata framework can have the opportunity to process those
11722fcbc377Syt 		 * event reports.
11732fcbc377Syt 		 */
11742fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
11752fcbc377Syt 		spkt->satapkt_device.satadev_state =
11762fcbc377Syt 		    ahci_portp->ahciport_port_state;
11772fcbc377Syt 		ahci_update_sata_registers(ahci_ctlp, port,
11782fcbc377Syt 		    &spkt->satapkt_device);
11792fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
11802fcbc377Syt 		    "ahci_tran_start returning PORT_ERROR while "
11812fcbc377Syt 		    "port in FAILED/SHUTDOWN/PWROFF state: "
118268d33a25Syt 		    "port: %d", port);
11832fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
11842fcbc377Syt 		return (SATA_TRAN_PORT_ERROR);
11852fcbc377Syt 	}
11862fcbc377Syt 
11872fcbc377Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
11882fcbc377Syt 		/*
11892fcbc377Syt 		 * ahci_intr_phyrdy_change() may have rendered it to
11902fcbc377Syt 		 * SATA_DTYPE_NONE.
11912fcbc377Syt 		 */
11922fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
11932fcbc377Syt 		spkt->satapkt_device.satadev_type = SATA_DTYPE_NONE;
11942fcbc377Syt 		spkt->satapkt_device.satadev_state =
11952fcbc377Syt 		    ahci_portp->ahciport_port_state;
11962fcbc377Syt 		ahci_update_sata_registers(ahci_ctlp, port,
11972fcbc377Syt 		    &spkt->satapkt_device);
11982fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
11992fcbc377Syt 		    "ahci_tran_start returning PORT_ERROR while "
120068d33a25Syt 		    "no device attached: port: %d", port);
12012fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
12022fcbc377Syt 		return (SATA_TRAN_PORT_ERROR);
12032fcbc377Syt 	}
12042fcbc377Syt 
12052fcbc377Syt 	/*
12062fcbc377Syt 	 * SATA HBA driver should remember that a device was reset and it
12072fcbc377Syt 	 * is supposed to reject any packets which do not specify either
12082fcbc377Syt 	 * SATA_IGNORE_DEV_RESET_STATE or SATA_CLEAR_DEV_RESET_STATE.
12092fcbc377Syt 	 *
12102fcbc377Syt 	 * This is to prevent a race condition when a device was arbitrarily
12112fcbc377Syt 	 * reset by the HBA driver (and lost it's setting) and a target
12122fcbc377Syt 	 * driver sending some commands to a device before the sata framework
12132fcbc377Syt 	 * has a chance to restore the device setting (such as cache enable/
12142fcbc377Syt 	 * disable or other resettable stuff).
12152fcbc377Syt 	 */
12162fcbc377Syt 	if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
12172fcbc377Syt 		ahci_portp->ahciport_reset_in_progress = 0;
12182fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
12192fcbc377Syt 		    "ahci_tran_start clearing the "
122068d33a25Syt 		    "reset_in_progress for port: %d", port);
12212fcbc377Syt 	}
12222fcbc377Syt 
12232fcbc377Syt 	if (ahci_portp->ahciport_reset_in_progress &&
12242fcbc377Syt 	    ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset &&
12252fcbc377Syt 	    ! ddi_in_panic()) {
12262fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_BUSY;
12272fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
12282fcbc377Syt 		    "ahci_tran_start returning BUSY while "
122968d33a25Syt 		    "reset in progress: port: %d", port);
12302fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
12312fcbc377Syt 		return (SATA_TRAN_BUSY);
12322fcbc377Syt 	}
12332fcbc377Syt 
123468d33a25Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
12352fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_BUSY;
12362fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
12372fcbc377Syt 		    "ahci_tran_start returning BUSY while "
123868d33a25Syt 		    "mopping in progress: port: %d", port);
12392fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
12402fcbc377Syt 		return (SATA_TRAN_BUSY);
12412fcbc377Syt 	}
12422fcbc377Syt 
12432fcbc377Syt 	if (spkt->satapkt_op_mode &
124468d33a25Syt 	    (SATA_OPMODE_SYNCH | SATA_OPMODE_POLLING)) {
124568d33a25Syt 		/* We need to do the sync start now */
124668d33a25Syt 		if (ahci_do_sync_start(ahci_ctlp, ahci_portp, port,
124768d33a25Syt 		    spkt) == AHCI_FAILURE) {
124868d33a25Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
124968d33a25Syt 			    "return QUEUE_FULL: port %d", port);
125068d33a25Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
125168d33a25Syt 			return (SATA_TRAN_QUEUE_FULL);
125268d33a25Syt 		}
125368d33a25Syt 	} else {
125468d33a25Syt 		/* Async start, using interrupt */
125568d33a25Syt 		if (ahci_deliver_satapkt(ahci_ctlp, ahci_portp, port, spkt)
125668d33a25Syt 		    == AHCI_FAILURE) {
125768d33a25Syt 			spkt->satapkt_reason = SATA_PKT_QUEUE_FULL;
125868d33a25Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
125968d33a25Syt 			    "returning QUEUE_FULL: port %d", port);
126068d33a25Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
126168d33a25Syt 			return (SATA_TRAN_QUEUE_FULL);
126268d33a25Syt 		}
12632fcbc377Syt 	}
12642fcbc377Syt 
12652fcbc377Syt 	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start "
12662fcbc377Syt 	    "sata tran accepted: port %d", port);
12672fcbc377Syt 
126868d33a25Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
12692fcbc377Syt 	return (SATA_TRAN_ACCEPTED);
12702fcbc377Syt }
12712fcbc377Syt 
127268d33a25Syt /*
127368d33a25Syt  * SATA_OPMODE_SYNCH flag is set
127468d33a25Syt  *
127568d33a25Syt  * If SATA_OPMODE_POLLING flag is set, then we must poll the command
127668d33a25Syt  * without interrupt, otherwise we can still use the interrupt.
127768d33a25Syt  *
127868d33a25Syt  * WARNING!!! ahciport_mutex should be acquired before the function
127968d33a25Syt  * is called.
128068d33a25Syt  */
128168d33a25Syt static int
128268d33a25Syt ahci_do_sync_start(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
128368d33a25Syt     uint8_t port, sata_pkt_t *spkt)
128468d33a25Syt {
128568d33a25Syt 	int pkt_timeout_ticks;
128668d33a25Syt 	uint32_t timeout_tags;
128768d33a25Syt 	int rval;
128868d33a25Syt 
128968d33a25Syt 	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: "
129068d33a25Syt 	    "port %d spkt 0x%p", port, spkt);
129168d33a25Syt 
129268d33a25Syt 	if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) {
129368d33a25Syt 		ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_POLLING;
129468d33a25Syt 		if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
129568d33a25Syt 		    port, spkt)) == AHCI_FAILURE) {
129668d33a25Syt 			ahci_portp->ahciport_flags &= ~ AHCI_PORT_FLAG_POLLING;
129768d33a25Syt 			return (rval);
129868d33a25Syt 		}
129968d33a25Syt 
130068d33a25Syt 		pkt_timeout_ticks =
130168d33a25Syt 		    drv_usectohz((clock_t)spkt->satapkt_time * 1000000);
130268d33a25Syt 
130368d33a25Syt 		while (spkt->satapkt_reason == SATA_PKT_BUSY) {
130468d33a25Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
130568d33a25Syt 
130668d33a25Syt 			/* Simulate the interrupt */
130782263d52Syt 			ahci_port_intr(ahci_ctlp, ahci_portp, port);
130868d33a25Syt 
130968d33a25Syt 			drv_usecwait(AHCI_1MS_USECS);
131068d33a25Syt 
131168d33a25Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
131268d33a25Syt 			pkt_timeout_ticks -= AHCI_1MS_TICKS;
131368d33a25Syt 			if (pkt_timeout_ticks < 0) {
131468d33a25Syt 				cmn_err(CE_NOTE, "!ahci_do_sync_start: "
131568d33a25Syt 				    "port %d satapkt 0x%p timed out\n",
131668d33a25Syt 				    port, (void *)spkt);
131768d33a25Syt 				timeout_tags = (0x1 << rval);
131868d33a25Syt 				mutex_exit(&ahci_portp->ahciport_mutex);
131968d33a25Syt 				ahci_timeout_pkts(ahci_ctlp, ahci_portp,
132082263d52Syt 				    port, timeout_tags);
132168d33a25Syt 				mutex_enter(&ahci_portp->ahciport_mutex);
132268d33a25Syt 			}
132368d33a25Syt 		}
132468d33a25Syt 		ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
132568d33a25Syt 		return (AHCI_SUCCESS);
132668d33a25Syt 
132768d33a25Syt 	} else {
132868d33a25Syt 		if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
132968d33a25Syt 		    port, spkt)) == AHCI_FAILURE)
133068d33a25Syt 			return (rval);
133168d33a25Syt 
133282263d52Syt #if AHCI_DEBUG
133382263d52Syt 		/*
133482263d52Syt 		 * Note that the driver always uses the slot 0 to deliver
133582263d52Syt 		 * REQUEST SENSE or READ LOG EXT command
133682263d52Syt 		 */
133782263d52Syt 		if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
133882263d52Syt 			ASSERT(rval == 0);
133982263d52Syt #endif
134082263d52Syt 
134168d33a25Syt 		while (spkt->satapkt_reason == SATA_PKT_BUSY)
134268d33a25Syt 			cv_wait(&ahci_portp->ahciport_cv,
134368d33a25Syt 			    &ahci_portp->ahciport_mutex);
134468d33a25Syt 
134568d33a25Syt 		return (AHCI_SUCCESS);
134668d33a25Syt 	}
134768d33a25Syt }
134868d33a25Syt 
13492fcbc377Syt #define	SENDUP_PACKET(ahci_portp, satapkt, reason)			\
13502fcbc377Syt 	if (satapkt) {							\
13512fcbc377Syt 		satapkt->satapkt_reason = reason;			\
13522fcbc377Syt 		/*							\
13532fcbc377Syt 		 * We set the satapkt_reason in both sync and		\
13542fcbc377Syt 		 * non-sync cases.					\
13552fcbc377Syt 		 */							\
13562fcbc377Syt 	}								\
13572fcbc377Syt 	if (satapkt &&							\
135868d33a25Syt 	    ! (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&		\
13592fcbc377Syt 	    satapkt->satapkt_comp) {					\
13602fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);		\
13612fcbc377Syt 		(*satapkt->satapkt_comp)(satapkt);			\
13622fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);		\
136368d33a25Syt 	} else {							\
136468d33a25Syt 		if (satapkt &&						\
136568d33a25Syt 		    (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&	\
136668d33a25Syt 		    ! (satapkt->satapkt_op_mode & SATA_OPMODE_POLLING))	\
136768d33a25Syt 			cv_signal(&ahci_portp->ahciport_cv);		\
13682fcbc377Syt 	}
13692fcbc377Syt 
13702fcbc377Syt /*
137182263d52Syt  * Searches for and claims a free command slot.
137282263d52Syt  *
137382263d52Syt  * Returns:
13742fcbc377Syt  *
137582263d52Syt  * AHCI_FAILURE if failed
137682263d52Syt  *	1. if no empty slot left
137782263d52Syt  *	2. non-queued command requested while queued command(s) is outstanding
137882263d52Syt  *	3. queued command requested whild non-queued command(s) is outstanding
137982263d52Syt  *	4. HBA doesn't support multiple-use of command list while already a
138082263d52Syt  *	non-queued command is oustanding
138182263d52Syt  *
138282263d52Syt  * claimed slot number if succeeded
138382263d52Syt  *
138482263d52Syt  * NOTE: it will always return slot 0 during error recovery process for
138582263d52Syt  * REQUEST SENSE or READ LOG EXT command to simplify the algorithm.
13862fcbc377Syt  *
13872fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
13882fcbc377Syt  * is called.
13892fcbc377Syt  */
13902fcbc377Syt /*ARGSUSED*/
13912fcbc377Syt static int
139282263d52Syt ahci_claim_free_slot(ahci_ctl_t *ahci_ctlp,
139382263d52Syt     ahci_port_t *ahci_portp, int command_type)
13942fcbc377Syt {
13952fcbc377Syt 	uint32_t free_slots;
13962fcbc377Syt 	int slot;
13972fcbc377Syt 
139882263d52Syt 	AHCIDBG2(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter "
139982263d52Syt 	    "ahciport_pending_tags = 0x%x "
140082263d52Syt 	    "ahciport_pending_ncq_tags = 0x%x",
140182263d52Syt 	    ahci_portp->ahciport_pending_tags,
140282263d52Syt 	    ahci_portp->ahciport_pending_ncq_tags);
14032fcbc377Syt 
140482263d52Syt 	/*
140582263d52Syt 	 * According to the AHCI spec, system software is responsible to
140682263d52Syt 	 * ensure that queued and non-queued commands are not mixed in
140782263d52Syt 	 * the command list.
140882263d52Syt 	 */
140982263d52Syt 	if (command_type == AHCI_NON_NCQ_CMD) {
141082263d52Syt 		/* Non-NCQ command request */
141182263d52Syt 		if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
141282263d52Syt 			AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
141382263d52Syt 			    "ahci_claim_free_slot: there is still pending "
141482263d52Syt 			    "queued command(s) in the command list, "
141582263d52Syt 			    "so no available slot for the non-queued "
141682263d52Syt 			    "command");
141782263d52Syt 			return (AHCI_FAILURE);
141882263d52Syt 		}
141982263d52Syt 		if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE) &&
142082263d52Syt 		    NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
142182263d52Syt 			AHCIDBG0(AHCIDBG_INFO, ahci_ctlp,
142282263d52Syt 			    "ahci_claim_free_slot: HBA cannot support multiple-"
142382263d52Syt 			    "use of the command list for non-queued commands");
142482263d52Syt 			return (AHCI_FAILURE);
142582263d52Syt 		}
142682263d52Syt 		free_slots = (~ahci_portp->ahciport_pending_tags) &
142782263d52Syt 		    AHCI_SLOT_MASK(ahci_ctlp);
142882263d52Syt 	} else if (command_type == AHCI_NCQ_CMD) {
142982263d52Syt 		/* NCQ command request */
143082263d52Syt 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
143182263d52Syt 			AHCIDBG0(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
143282263d52Syt 			    "ahci_claim_free_slot: there is still pending "
143382263d52Syt 			    "non-queued command(s) in the command list, "
143482263d52Syt 			    "so no available slot for the queued command");
143582263d52Syt 			return (AHCI_FAILURE);
143682263d52Syt 		}
143782263d52Syt 		free_slots = (~ahci_portp->ahciport_pending_ncq_tags) &
143882263d52Syt 		    AHCI_NCQ_SLOT_MASK(ahci_portp);
143982263d52Syt 	} else if (command_type == AHCI_ERR_RETRI_CMD) {
144082263d52Syt 		/* Error retrieval command request */
144182263d52Syt 		AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
144282263d52Syt 		    "ahci_claim_free_slot: slot 0 is allocated for REQUEST "
144382263d52Syt 		    "SENSE or READ LOG EXT command");
144482263d52Syt 		slot = 0;
144582263d52Syt 		goto out;
144682263d52Syt 	}
14472fcbc377Syt 
14482fcbc377Syt 	slot = ddi_ffs(free_slots) - 1;
14492fcbc377Syt 	if (slot == -1) {
14502fcbc377Syt 		AHCIDBG0(AHCIDBG_VERBOSE, ahci_ctlp,
14512fcbc377Syt 		    "ahci_claim_free_slot: no empty slots");
14522fcbc377Syt 		return (AHCI_FAILURE);
14532fcbc377Syt 	}
14542fcbc377Syt 
145582263d52Syt 	/*
145682263d52Syt 	 * According to the AHCI spec, to allow a simple mechanism for the
145782263d52Syt 	 * HBA to map command list slots to queue entries, software must
145882263d52Syt 	 * match the tag number it uses to the slot it is placing the command
145982263d52Syt 	 * in. For example, if a queued command is placed in slot 5, the tag
146082263d52Syt 	 * for that command must be 5.
146182263d52Syt 	 */
146282263d52Syt 	if (command_type == AHCI_NCQ_CMD) {
146382263d52Syt 		ahci_portp->ahciport_pending_ncq_tags |= (0x1 << slot);
146482263d52Syt 	}
146582263d52Syt 
14662fcbc377Syt 	ahci_portp->ahciport_pending_tags |= (0x1 << slot);
14672fcbc377Syt 
146882263d52Syt out:
14692fcbc377Syt 	AHCIDBG1(AHCIDBG_VERBOSE, ahci_ctlp,
14702fcbc377Syt 	    "ahci_claim_free_slot: found slot: 0x%x", slot);
14712fcbc377Syt 
14722fcbc377Syt 	return (slot);
14732fcbc377Syt }
14742fcbc377Syt 
14752fcbc377Syt /*
14762fcbc377Syt  * Builds the Command Table for the sata packet and delivers it to controller.
14772fcbc377Syt  *
14782fcbc377Syt  * Returns:
14792fcbc377Syt  * 	slot number if we can obtain a slot successfully
14802fcbc377Syt  *	otherwise, return AHCI_FAILURE
14812fcbc377Syt  *
14822fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
14832fcbc377Syt  */
14842fcbc377Syt static int
14852fcbc377Syt ahci_deliver_satapkt(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
14862fcbc377Syt     uint8_t port, sata_pkt_t *spkt)
14872fcbc377Syt {
148868d33a25Syt 	int cmd_slot;
148968d33a25Syt 	sata_cmd_t *scmd;
14902fcbc377Syt 	ahci_fis_h2d_register_t *h2d_register_fisp;
14912fcbc377Syt 	ahci_cmd_table_t *cmd_table;
14922fcbc377Syt 	ahci_cmd_header_t *cmd_header;
14932fcbc377Syt 	int ncookies;
14942fcbc377Syt 	int i;
149582263d52Syt 	int command_type = AHCI_NON_NCQ_CMD;
149682263d52Syt 	int ncq_qdepth;
149768d33a25Syt #if AHCI_DEBUG
149868d33a25Syt 	uint32_t *ptr;
149968d33a25Syt 	uint8_t *ptr2;
150068d33a25Syt #endif
15012fcbc377Syt 
15022fcbc377Syt 	spkt->satapkt_reason = SATA_PKT_BUSY;
15032fcbc377Syt 
150468d33a25Syt 	scmd = &spkt->satapkt_cmd;
15052fcbc377Syt 
150682263d52Syt 	/* Check if the command is a NCQ command */
150782263d52Syt 	if (scmd->satacmd_cmd_reg == SATAC_READ_FPDMA_QUEUED ||
150882263d52Syt 	    scmd->satacmd_cmd_reg == SATAC_WRITE_FPDMA_QUEUED) {
150982263d52Syt 		command_type = AHCI_NCQ_CMD;
151082263d52Syt 
151182263d52Syt 		/*
151282263d52Syt 		 * When NCQ is support, system software must determine the
151382263d52Syt 		 * maximum tag allowed by the device and the HBA, and it
151482263d52Syt 		 * must use a value not beyond of the lower bound of the two.
151582263d52Syt 		 *
151682263d52Syt 		 * Sata module is going to calculate the qdepth and send
151782263d52Syt 		 * down to HBA driver via sata_cmd.
151882263d52Syt 		 */
151982263d52Syt 		ncq_qdepth = scmd->satacmd_flags.sata_max_queue_depth + 1;
152082263d52Syt 
152182263d52Syt 		/*
152282263d52Syt 		 * At the moment, the driver doesn't support the dynamic
152382263d52Syt 		 * setting of the maximum ncq depth, and the value can be
152482263d52Syt 		 * set either during the attach or after hot-plug insertion.
152582263d52Syt 		 */
152682263d52Syt 		if (ahci_portp->ahciport_max_ncq_tags == 0) {
152782263d52Syt 			ahci_portp->ahciport_max_ncq_tags = ncq_qdepth;
152882263d52Syt 			AHCIDBG2(AHCIDBG_NCQ, ahci_ctlp,
152982263d52Syt 			    "ahci_deliver_satapkt: port %d the max tags for "
153082263d52Syt 			    "NCQ command is %d", port, ncq_qdepth);
153182263d52Syt 		} else {
153282263d52Syt 			if (ncq_qdepth != ahci_portp->ahciport_max_ncq_tags) {
153382263d52Syt 				cmn_err(CE_WARN, "ahci_deliver_satapkt: port "
153482263d52Syt 				    "%d the max tag for NCQ command is "
153582263d52Syt 				    "requested to change from %d to %d, at the"
153682263d52Syt 				    " moment the driver doesn't support the "
153782263d52Syt 				    "dynamic change so it's going to "
153882263d52Syt 				    "still use the previous tag value", port,
153982263d52Syt 				    ahci_portp->ahciport_max_ncq_tags,
154082263d52Syt 				    ncq_qdepth);
154182263d52Syt 			}
154282263d52Syt 		}
154382263d52Syt 	}
154482263d52Syt 
154582263d52Syt 	/* Check if the command is an error retrieval command */
154682263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
154782263d52Syt 		command_type = AHCI_ERR_RETRI_CMD;
154882263d52Syt 
154982263d52Syt 	/* Check if there is an empty command slot */
155082263d52Syt 	cmd_slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp, command_type);
155168d33a25Syt 	if (cmd_slot == AHCI_FAILURE) {
155282263d52Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp, "no free command slot");
15532fcbc377Syt 		return (AHCI_FAILURE);
15542fcbc377Syt 	}
15552fcbc377Syt 
15562fcbc377Syt 	AHCIDBG4(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp,
155768d33a25Syt 	    "ahci_deliver_satapkt enter: cmd_reg: 0x%x, cmd_slot: 0x%x, "
155868d33a25Syt 	    "port: %d, satapkt: 0x%p", scmd->satacmd_cmd_reg,
155968d33a25Syt 	    cmd_slot, port, (void *)spkt);
15602fcbc377Syt 
156168d33a25Syt 	cmd_table = ahci_portp->ahciport_cmd_tables[cmd_slot];
15622fcbc377Syt 	bzero((void *)cmd_table, ahci_cmd_table_size);
15632fcbc377Syt 
156482263d52Syt 	/* For data transfer operations, it is the H2D Register FIS */
15652fcbc377Syt 	h2d_register_fisp =
15662fcbc377Syt 	    &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
15672fcbc377Syt 
15682fcbc377Syt 	SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
15692fcbc377Syt 	if ((spkt->satapkt_device.satadev_addr.qual == SATA_ADDR_PMPORT) ||
15702fcbc377Syt 	    (spkt->satapkt_device.satadev_addr.qual == SATA_ADDR_DPMPORT)) {
15712fcbc377Syt 		SET_FIS_PMP(h2d_register_fisp,
15722fcbc377Syt 		    spkt->satapkt_device.satadev_addr.pmport);
15732fcbc377Syt 	}
15742fcbc377Syt 
15752fcbc377Syt 	SET_FIS_CDMDEVCTL(h2d_register_fisp, 1);
157668d33a25Syt 	SET_FIS_COMMAND(h2d_register_fisp, scmd->satacmd_cmd_reg);
157768d33a25Syt 	SET_FIS_FEATURES(h2d_register_fisp, scmd->satacmd_features_reg);
157868d33a25Syt 	SET_FIS_SECTOR_COUNT(h2d_register_fisp, scmd->satacmd_sec_count_lsb);
15792fcbc377Syt 
158068d33a25Syt 	switch (scmd->satacmd_addr_type) {
15812fcbc377Syt 
158282263d52Syt 	case 0:
158382263d52Syt 		/*
158482263d52Syt 		 * satacmd_addr_type will be 0 for the commands below:
158582263d52Syt 		 * 	ATAPI command
158682263d52Syt 		 * 	SATAC_IDLE_IM
158782263d52Syt 		 * 	SATAC_STANDBY_IM
158882263d52Syt 		 * 	SATAC_DOWNLOAD_MICROCODE
158982263d52Syt 		 * 	SATAC_FLUSH_CACHE
159082263d52Syt 		 * 	SATAC_SET_FEATURES
159182263d52Syt 		 * 	SATAC_SMART
159282263d52Syt 		 * 	SATAC_ID_PACKET_DEVICE
159382263d52Syt 		 * 	SATAC_ID_DEVICE
159482263d52Syt 		 */
159582263d52Syt 		/* fallthrough */
159682263d52Syt 
15972fcbc377Syt 	case ATA_ADDR_LBA:
15982fcbc377Syt 		/* fallthrough */
15992fcbc377Syt 
16002fcbc377Syt 	case ATA_ADDR_LBA28:
16012fcbc377Syt 		/* LBA[7:0] */
160268d33a25Syt 		SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
16032fcbc377Syt 
16042fcbc377Syt 		/* LBA[15:8] */
160568d33a25Syt 		SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
16062fcbc377Syt 
16072fcbc377Syt 		/* LBA[23:16] */
160868d33a25Syt 		SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
16092fcbc377Syt 
16102fcbc377Syt 		/* LBA [27:24] (also called dev_head) */
161168d33a25Syt 		SET_FIS_DEV_HEAD(h2d_register_fisp, scmd->satacmd_device_reg);
16122fcbc377Syt 
16132fcbc377Syt 		break;
16142fcbc377Syt 
16152fcbc377Syt 	case ATA_ADDR_LBA48:
16162fcbc377Syt 		/* LBA[7:0] */
161768d33a25Syt 		SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
16182fcbc377Syt 
16192fcbc377Syt 		/* LBA[15:8] */
162068d33a25Syt 		SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
16212fcbc377Syt 
16222fcbc377Syt 		/* LBA[23:16] */
162368d33a25Syt 		SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
16242fcbc377Syt 
16252fcbc377Syt 		/* LBA [31:24] */
16262fcbc377Syt 		SET_FIS_SECTOR_EXP(h2d_register_fisp,
162768d33a25Syt 		    scmd->satacmd_lba_low_msb);
16282fcbc377Syt 
16292fcbc377Syt 		/* LBA [39:32] */
16302fcbc377Syt 		SET_FIS_CYL_LOW_EXP(h2d_register_fisp,
163168d33a25Syt 		    scmd->satacmd_lba_mid_msb);
16322fcbc377Syt 
16332fcbc377Syt 		/* LBA [47:40] */
16342fcbc377Syt 		SET_FIS_CYL_HI_EXP(h2d_register_fisp,
163568d33a25Syt 		    scmd->satacmd_lba_high_msb);
16362fcbc377Syt 
16372fcbc377Syt 		/* Set dev_head */
16382fcbc377Syt 		SET_FIS_DEV_HEAD(h2d_register_fisp,
163968d33a25Syt 		    scmd->satacmd_device_reg);
16402fcbc377Syt 
16412fcbc377Syt 		/* Set the extended sector count and features */
16422fcbc377Syt 		SET_FIS_SECTOR_COUNT_EXP(h2d_register_fisp,
164368d33a25Syt 		    scmd->satacmd_sec_count_msb);
16442fcbc377Syt 		SET_FIS_FEATURES_EXP(h2d_register_fisp,
164568d33a25Syt 		    scmd->satacmd_features_reg_ext);
16462fcbc377Syt 		break;
16472fcbc377Syt 	}
16482fcbc377Syt 
164982263d52Syt 	/*
165082263d52Syt 	 * For NCQ command (READ/WRITE FPDMA QUEUED), sector count 7:0 is
165182263d52Syt 	 * filled into features field, and sector count 8:15 is filled into
165282263d52Syt 	 * features (exp) field. TAG is filled into sector field.
165382263d52Syt 	 */
165482263d52Syt 	if (command_type == AHCI_NCQ_CMD) {
165582263d52Syt 		SET_FIS_FEATURES(h2d_register_fisp,
165682263d52Syt 		    scmd->satacmd_sec_count_lsb);
165782263d52Syt 		SET_FIS_FEATURES_EXP(h2d_register_fisp,
165882263d52Syt 		    scmd->satacmd_sec_count_msb);
165982263d52Syt 
166082263d52Syt 		SET_FIS_SECTOR_COUNT(h2d_register_fisp,
166182263d52Syt 		    (cmd_slot << SATA_TAG_QUEUING_SHIFT));
166282263d52Syt 	}
166382263d52Syt 
166468d33a25Syt 	ncookies = scmd->satacmd_num_dma_cookies;
16652fcbc377Syt 	AHCIDBG2(AHCIDBG_INFO, ahci_ctlp,
16662fcbc377Syt 	    "ncookies = 0x%x, ahci_dma_prdt_number = 0x%x",
16672fcbc377Syt 	    ncookies, ahci_dma_prdt_number);
16682fcbc377Syt 
16692fcbc377Syt 	ASSERT(ncookies <= ahci_dma_prdt_number);
16702fcbc377Syt 
16712fcbc377Syt 	/* *** now fill the scatter gather list ******* */
16722fcbc377Syt 	for (i = 0; i < ncookies; i++) {
16732fcbc377Syt 		cmd_table->ahcict_prdt[i].ahcipi_data_base_addr =
167468d33a25Syt 		    scmd->satacmd_dma_cookie_list[i]._dmu._dmac_la[0];
16752fcbc377Syt 		cmd_table->ahcict_prdt[i].ahcipi_data_base_addr_upper =
167668d33a25Syt 		    scmd->satacmd_dma_cookie_list[i]._dmu._dmac_la[1];
16772fcbc377Syt 		cmd_table->ahcict_prdt[i].ahcipi_descr_info =
167868d33a25Syt 		    scmd->satacmd_dma_cookie_list[i].dmac_size - 1;
167968d33a25Syt 	}
168068d33a25Syt 
168168d33a25Syt 	/* The ACMD field is filled in for ATAPI command */
168268d33a25Syt 	if (scmd->satacmd_cmd_reg == SATAC_PACKET) {
168368d33a25Syt 		bcopy(scmd->satacmd_acdb, cmd_table->ahcict_atapi_cmd,
168468d33a25Syt 		    SATA_ATAPI_MAX_CDB_LEN);
16852fcbc377Syt 	}
16862fcbc377Syt 
16872fcbc377Syt 	/* Set Command Header in Command List */
168868d33a25Syt 	cmd_header = &ahci_portp->ahciport_cmd_list[cmd_slot];
16892fcbc377Syt 	BZERO_DESCR_INFO(cmd_header);
16902fcbc377Syt 	BZERO_PRD_BYTE_COUNT(cmd_header);
169168d33a25Syt 
169268d33a25Syt 	/* Set the number of entries in the PRD table */
16932fcbc377Syt 	SET_PRD_TABLE_LENGTH(cmd_header, ncookies);
169468d33a25Syt 
169568d33a25Syt 	/* Set the length of the command in the CFIS area */
16962fcbc377Syt 	SET_COMMAND_FIS_LENGTH(cmd_header, AHCI_H2D_REGISTER_FIS_LENGTH);
16972fcbc377Syt 
16982fcbc377Syt 	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "command data direction is "
16992fcbc377Syt 	    "sata_data_direction = 0x%x",
170068d33a25Syt 	    scmd->satacmd_flags.sata_data_direction);
170168d33a25Syt 
170268d33a25Syt 	/* Set A bit if it is an ATAPI command */
170368d33a25Syt 	if (scmd->satacmd_cmd_reg == SATAC_PACKET)
170468d33a25Syt 		SET_ATAPI(cmd_header, AHCI_CMDHEAD_ATAPI);
17052fcbc377Syt 
170668d33a25Syt 	/* Set W bit if data is going to the device */
170768d33a25Syt 	if (scmd->satacmd_flags.sata_data_direction == SATA_DIR_WRITE)
17082fcbc377Syt 		SET_WRITE(cmd_header, AHCI_CMDHEAD_DATA_WRITE);
17092fcbc377Syt 
171068d33a25Syt 	/*
171168d33a25Syt 	 * Set the prefetchable bit - this bit is only valid if the PRDTL
171268d33a25Syt 	 * field is non-zero or the ATAPI 'A' bit is set in the command
171368d33a25Syt 	 * header. This bit cannot be set when using native command
171468d33a25Syt 	 * queuing commands or when using FIS-based switching with a Port
171582263d52Syt 	 * multiplier.
171668d33a25Syt 	 */
171782263d52Syt 	if (command_type != AHCI_NCQ_CMD)
171882263d52Syt 		SET_PREFETCHABLE(cmd_header, AHCI_CMDHEAD_PREFETCHABLE);
17192fcbc377Syt 
17202fcbc377Syt 	/* Now remember the sata packet in ahciport_slot_pkts[]. */
172182263d52Syt 	if (!ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
172282263d52Syt 		ahci_portp->ahciport_slot_pkts[cmd_slot] = spkt;
17232fcbc377Syt 
17242fcbc377Syt 	/*
17252fcbc377Syt 	 * We are overloading satapkt_hba_driver_private with
17262fcbc377Syt 	 * watched_cycle count.
17272fcbc377Syt 	 */
17282fcbc377Syt 	spkt->satapkt_hba_driver_private = (void *)(intptr_t)0;
17292fcbc377Syt 
173068d33a25Syt #if AHCI_DEBUG
173168d33a25Syt 	/* Dump the command header and table */
173268d33a25Syt 	AHCIDBG0(AHCIDBG_COMMAND, ahci_ctlp, "\n");
173368d33a25Syt 	AHCIDBG3(AHCIDBG_COMMAND, ahci_ctlp,
173482263d52Syt 	    "Command header&table for spkt 0x%p cmd_reg 0x%x port %d",
173568d33a25Syt 	    spkt, scmd->satacmd_cmd_reg, port);
173668d33a25Syt 	ptr = (uint32_t *)cmd_header;
173768d33a25Syt 	AHCIDBG4(AHCIDBG_COMMAND, ahci_ctlp,
173868d33a25Syt 	    "  Command Header:%8x %8x %8x %8x",
173968d33a25Syt 	    ptr[0], ptr[1], ptr[2], ptr[3]);
174068d33a25Syt 
174168d33a25Syt 	/* Dump the H2D register FIS */
174268d33a25Syt 	ptr = (uint32_t *)h2d_register_fisp;
174368d33a25Syt 	AHCIDBG4(AHCIDBG_COMMAND, ahci_ctlp,
174468d33a25Syt 	    "  Command FIS:   %8x %8x %8x %8x",
174568d33a25Syt 	    ptr[0], ptr[1], ptr[2], ptr[3]);
174668d33a25Syt 
174768d33a25Syt 	/* Dump the ACMD register FIS */
174868d33a25Syt 	ptr2 = (uint8_t *)&(cmd_table->ahcict_atapi_cmd);
174968d33a25Syt 	for (i = 0; i < SATA_ATAPI_MAX_CDB_LEN/8; i++)
175068d33a25Syt 		if (ahci_debug_flags & AHCIDBG_COMMAND)
175168d33a25Syt 			ahci_log(ahci_ctlp, CE_WARN,
175268d33a25Syt 			    "  ATAPI command: %2x %2x %2x %2x "
175368d33a25Syt 			    "%2x %2x %2x %2x",
175468d33a25Syt 			    ptr2[8 * i], ptr2[8 * i + 1],
175568d33a25Syt 			    ptr2[8 * i + 2], ptr2[8 * i + 3],
175668d33a25Syt 			    ptr2[8 * i + 4], ptr2[8 * i + 5],
175768d33a25Syt 			    ptr2[8 * i + 6], ptr2[8 * i + 7]);
175868d33a25Syt 
175968d33a25Syt 	/* Dump the PRDT */
176068d33a25Syt 	for (i = 0; i < ncookies; i++) {
176168d33a25Syt 		ptr = (uint32_t *)&(cmd_table->ahcict_prdt[i]);
176268d33a25Syt 		AHCIDBG5(AHCIDBG_COMMAND, ahci_ctlp,
176368d33a25Syt 		    "  Cookie %d:      %8x %8x %8x %8x",
176468d33a25Syt 		    i, ptr[0], ptr[1], ptr[2], ptr[3]);
176568d33a25Syt 	}
176668d33a25Syt #endif
176768d33a25Syt 
176868d33a25Syt 	(void) ddi_dma_sync(
176968d33a25Syt 	    ahci_portp->ahciport_cmd_tables_dma_handle[cmd_slot],
17702fcbc377Syt 	    0,
17712fcbc377Syt 	    ahci_cmd_table_size,
17722fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
17732fcbc377Syt 
17742fcbc377Syt 	(void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
177568d33a25Syt 	    cmd_slot * sizeof (ahci_cmd_header_t),
17762fcbc377Syt 	    sizeof (ahci_cmd_header_t),
17772fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
17782fcbc377Syt 
177982263d52Syt 	/* Set the corresponding bit in the PxSACT.DS for queued command */
178082263d52Syt 	if (command_type == AHCI_NCQ_CMD) {
178182263d52Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
178282263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port),
178382263d52Syt 		    (0x1 << cmd_slot));
178482263d52Syt 	}
178582263d52Syt 
17862fcbc377Syt 	/* Indicate to the HBA that a command is active. */
17872fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
17882fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
178968d33a25Syt 	    (0x1 << cmd_slot));
17902fcbc377Syt 
17912fcbc377Syt 	AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt "
17922fcbc377Syt 	    "exit: port %d", port);
17932fcbc377Syt 
179468d33a25Syt 	return (cmd_slot);
17952fcbc377Syt }
17962fcbc377Syt 
17972fcbc377Syt /*
17982fcbc377Syt  * Called by the sata framework to abort the previously sent packet(s).
17992fcbc377Syt  *
18002fcbc377Syt  * Reset device to abort commands.
18012fcbc377Syt  */
18022fcbc377Syt static int
18032fcbc377Syt ahci_tran_abort(dev_info_t *dip, sata_pkt_t *spkt, int flag)
18042fcbc377Syt {
18052fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
18062fcbc377Syt 	ahci_port_t *ahci_portp;
180782263d52Syt 	uint32_t slot_status = 0;
180882263d52Syt 	uint32_t aborted_tags = 0;
180982263d52Syt 	uint32_t finished_tags = 0;
18102fcbc377Syt 	uint8_t cport = spkt->satapkt_device.satadev_addr.cport;
18112fcbc377Syt 	uint8_t port;
18122fcbc377Syt 	int tmp_slot;
18132fcbc377Syt 
18142fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
18152fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
18162fcbc377Syt 
18172fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
181868d33a25Syt 	    "ahci_tran_abort enter: port %d", port);
18192fcbc377Syt 
18202fcbc377Syt 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
18212fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
18222fcbc377Syt 
18232fcbc377Syt 	/*
182468d33a25Syt 	 * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
182568d33a25Syt 	 * commands are being mopped, therefore there is nothing else to do
18262fcbc377Syt 	 */
182768d33a25Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
18282fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
18292fcbc377Syt 		    "ahci_tran_abort: port %d is in "
18302fcbc377Syt 		    "mopping process, so just return directly ", port);
18312fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
18322fcbc377Syt 		return (SATA_SUCCESS);
18332fcbc377Syt 	}
18342fcbc377Syt 
18352fcbc377Syt 	if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
18362fcbc377Syt 	    ahci_portp->ahciport_port_state & SATA_PSTATE_SHUTDOWN |
18372fcbc377Syt 	    ahci_portp->ahciport_port_state & SATA_PSTATE_PWROFF) {
18382fcbc377Syt 		/*
18392fcbc377Syt 		 * In case the targer driver would send the request before
18402fcbc377Syt 		 * sata framework can have the opportunity to process those
18412fcbc377Syt 		 * event reports.
18422fcbc377Syt 		 */
18432fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
18442fcbc377Syt 		spkt->satapkt_device.satadev_state =
18452fcbc377Syt 		    ahci_portp->ahciport_port_state;
18462fcbc377Syt 		ahci_update_sata_registers(ahci_ctlp, port,
18472fcbc377Syt 		    &spkt->satapkt_device);
18482fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
18492fcbc377Syt 		    "ahci_tran_abort returning SATA_FAILURE while "
18502fcbc377Syt 		    "port in FAILED/SHUTDOWN/PWROFF state: "
185168d33a25Syt 		    "port: %d", port);
18522fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
18532fcbc377Syt 		return (SATA_FAILURE);
18542fcbc377Syt 	}
18552fcbc377Syt 
18562fcbc377Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
18572fcbc377Syt 		/*
18582fcbc377Syt 		 * ahci_intr_phyrdy_change() may have rendered it to
18592fcbc377Syt 		 * AHCI_PORT_TYPE_NODEV.
18602fcbc377Syt 		 */
18612fcbc377Syt 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
18622fcbc377Syt 		spkt->satapkt_device.satadev_type = SATA_DTYPE_NONE;
18632fcbc377Syt 		spkt->satapkt_device.satadev_state =
18642fcbc377Syt 		    ahci_portp->ahciport_port_state;
18652fcbc377Syt 		ahci_update_sata_registers(ahci_ctlp, port,
18662fcbc377Syt 		    &spkt->satapkt_device);
18672fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
18682fcbc377Syt 		    "ahci_tran_abort returning SATA_FAILURE while "
186968d33a25Syt 		    "no device attached: port: %d", port);
18702fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
18712fcbc377Syt 		return (SATA_FAILURE);
18722fcbc377Syt 	}
18732fcbc377Syt 
18742fcbc377Syt 	if (flag == SATA_ABORT_ALL_PACKETS) {
187582263d52Syt 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
187682263d52Syt 			aborted_tags = ahci_portp->ahciport_pending_tags;
187782263d52Syt 
187882263d52Syt 		if (NCQ_CMD_IN_PROGRESS(ahci_portp))
187982263d52Syt 			aborted_tags = ahci_portp->ahciport_pending_ncq_tags;
188082263d52Syt 
18812fcbc377Syt 		cmn_err(CE_NOTE, "!ahci port %d abort all packets", port);
18822fcbc377Syt 	} else {
18832fcbc377Syt 		aborted_tags = 0xffffffff;
18842fcbc377Syt 		/*
188582263d52Syt 		 * Aborting one specific packet, first search the
18862fcbc377Syt 		 * ahciport_slot_pkts[] list for matching spkt.
18872fcbc377Syt 		 */
18882fcbc377Syt 		for (tmp_slot = 0;
18892fcbc377Syt 		    tmp_slot < ahci_ctlp->ahcictl_num_cmd_slots; tmp_slot++) {
18902fcbc377Syt 			if (ahci_portp->ahciport_slot_pkts[tmp_slot] == spkt) {
18912fcbc377Syt 				aborted_tags = (0x1 << tmp_slot);
18922fcbc377Syt 				break;
18932fcbc377Syt 			}
18942fcbc377Syt 		}
18952fcbc377Syt 
18962fcbc377Syt 		if (aborted_tags == 0xffffffff) {
18972fcbc377Syt 			/* request packet is not on the pending list */
18982fcbc377Syt 			AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
18992fcbc377Syt 			    "Cannot find the aborting pkt 0x%p on the "
19002fcbc377Syt 			    "pending list", (void *)spkt);
19012fcbc377Syt 			ahci_update_sata_registers(ahci_ctlp, port,
19022fcbc377Syt 			    &spkt->satapkt_device);
19032fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
19042fcbc377Syt 			return (SATA_FAILURE);
19052fcbc377Syt 		}
19062fcbc377Syt 		cmn_err(CE_NOTE, "!ahci port %d abort satapkt 0x%p",
19072fcbc377Syt 		    port, (void *)spkt);
19082fcbc377Syt 	}
19092fcbc377Syt 
191082263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
191182263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
191282263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
191382263d52Syt 
191482263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp))
191582263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
191682263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
19172fcbc377Syt 
191868d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
191968d33a25Syt 	ahci_portp->ahciport_mop_in_progress++;
19202fcbc377Syt 
19212fcbc377Syt 	/*
19222fcbc377Syt 	 * To abort the packet(s), first we are trying to clear PxCMD.ST
192368d33a25Syt 	 * to stop the port, and if the port can be stopped
19242fcbc377Syt 	 * successfully with PxTFD.STS.BSY and PxTFD.STS.DRQ cleared to '0',
19252fcbc377Syt 	 * then we just send back the aborted packet(s) with ABORTED flag
19262fcbc377Syt 	 * and then restart the port by setting PxCMD.ST and PxCMD.FRE.
19272fcbc377Syt 	 * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then we
19282fcbc377Syt 	 * perform a COMRESET.
19292fcbc377Syt 	 */
19302fcbc377Syt 	(void) ahci_restart_port_wait_till_ready(ahci_ctlp,
193168d33a25Syt 	    ahci_portp, port, NULL, NULL);
19322fcbc377Syt 
19332fcbc377Syt 	/*
19342fcbc377Syt 	 * Compute which have finished and which need to be retried.
19352fcbc377Syt 	 *
193682263d52Syt 	 * The finished tags are ahciport_pending_tags/ahciport_pending_ncq_tags
193782263d52Syt 	 * minus the slot_status. The aborted_tags has to be deducted by
193882263d52Syt 	 * finished_tags since we can't possibly abort a tag which had finished
193982263d52Syt 	 * already.
19402fcbc377Syt 	 */
194182263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
194282263d52Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
194382263d52Syt 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
194482263d52Syt 
194582263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp))
194682263d52Syt 		finished_tags = ahci_portp->ahciport_pending_ncq_tags &
194782263d52Syt 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
19482fcbc377Syt 
19492fcbc377Syt 	aborted_tags &= ~finished_tags;
19502fcbc377Syt 
19512fcbc377Syt 	ahci_mop_commands(ahci_ctlp,
19522fcbc377Syt 	    ahci_portp,
19532fcbc377Syt 	    port,
19542fcbc377Syt 	    slot_status,
19552fcbc377Syt 	    0, /* failed tags */
19562fcbc377Syt 	    0, /* timeout tags */
19572fcbc377Syt 	    aborted_tags,
19582fcbc377Syt 	    0); /* reset tags */
19592fcbc377Syt 
19602fcbc377Syt 	ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device);
19612fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
19622fcbc377Syt 
19632fcbc377Syt 	return (SATA_SUCCESS);
19642fcbc377Syt }
19652fcbc377Syt 
19662fcbc377Syt /*
19672fcbc377Syt  * Used to do device reset and reject all the pending packets on a device
19682fcbc377Syt  * during the reset operation.
19692fcbc377Syt  *
19702fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
19712fcbc377Syt  */
19722fcbc377Syt static int
19732fcbc377Syt ahci_reset_device_reject_pkts(ahci_ctl_t *ahci_ctlp,
19742fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
19752fcbc377Syt {
197682263d52Syt 	uint32_t slot_status = 0;
197782263d52Syt 	uint32_t reset_tags = 0;
197882263d52Syt 	uint32_t finished_tags = 0;
19792fcbc377Syt 	sata_device_t sdevice;
19802fcbc377Syt 	int ret;
19812fcbc377Syt 
19822fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
19832fcbc377Syt 	    "ahci_reset_device_reject_pkts on port: %d", port);
19842fcbc377Syt 
19852fcbc377Syt 	/*
198668d33a25Syt 	 * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
198768d33a25Syt 	 * commands are being mopped, therefore there is nothing else to do
19882fcbc377Syt 	 */
198968d33a25Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
19902fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
19912fcbc377Syt 		    "ahci_reset_device_reject_pkts: port %d is in "
19922fcbc377Syt 		    "mopping process, so return directly ", port);
19932fcbc377Syt 		return (SATA_SUCCESS);
19942fcbc377Syt 	}
19952fcbc377Syt 
199682263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
199782263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
199882263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
199982263d52Syt 		reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
200082263d52Syt 	}
20012fcbc377Syt 
200282263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
200382263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
200482263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
200582263d52Syt 		reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
200682263d52Syt 	}
20072fcbc377Syt 
20082fcbc377Syt 	if (ahci_software_reset(ahci_ctlp, ahci_portp, port)
20092fcbc377Syt 	    != AHCI_SUCCESS) {
20102fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
20112fcbc377Syt 		    "Try to do a port reset after software "
20122fcbc377Syt 		    "reset failed", port);
20132fcbc377Syt 		ret = ahci_port_reset(ahci_ctlp, ahci_portp, port);
20142fcbc377Syt 		if (ret != AHCI_SUCCESS) {
20152fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
20162fcbc377Syt 			    "ahci_reset_device_reject_pkts: port %d "
20172fcbc377Syt 			    "failed", port);
20182fcbc377Syt 			return (SATA_FAILURE);
20192fcbc377Syt 		}
20202fcbc377Syt 	}
20212fcbc377Syt 	/* Set the reset in progress flag */
20222fcbc377Syt 	ahci_portp->ahciport_reset_in_progress = 1;
20232fcbc377Syt 
202468d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
202568d33a25Syt 	ahci_portp->ahciport_mop_in_progress++;
20262fcbc377Syt 
20272fcbc377Syt 	/* Indicate to the framework that a reset has happened */
20282fcbc377Syt 	bzero((void *)&sdevice, sizeof (sata_device_t));
202909121340Syt 	sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
203068d33a25Syt 	sdevice.satadev_addr.pmport = 0;
203168d33a25Syt 	sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
20322fcbc377Syt 
20332fcbc377Syt 	sdevice.satadev_state = SATA_DSTATE_RESET |
20342fcbc377Syt 	    SATA_DSTATE_PWR_ACTIVE;
20352fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
20362fcbc377Syt 	sata_hba_event_notify(
20372fcbc377Syt 	    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
20382fcbc377Syt 	    &sdevice,
20392fcbc377Syt 	    SATA_EVNT_DEVICE_RESET);
20402fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
20412fcbc377Syt 
20422fcbc377Syt 	AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
20432fcbc377Syt 	    "port %d sending event up: SATA_EVNT_RESET", port);
20442fcbc377Syt 
20452fcbc377Syt 	/* Next try to mop the pending commands */
204682263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
204782263d52Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
204882263d52Syt 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
204982263d52Syt 
205082263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp))
205182263d52Syt 		finished_tags = ahci_portp->ahciport_pending_ncq_tags &
205282263d52Syt 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
20532fcbc377Syt 
20542fcbc377Syt 	reset_tags &= ~finished_tags;
20552fcbc377Syt 
20562fcbc377Syt 	ahci_mop_commands(ahci_ctlp,
20572fcbc377Syt 	    ahci_portp,
20582fcbc377Syt 	    port,
20592fcbc377Syt 	    slot_status,
20602fcbc377Syt 	    0, /* failed tags */
20612fcbc377Syt 	    0, /* timeout tags */
20622fcbc377Syt 	    0, /* aborted tags */
20632fcbc377Syt 	    reset_tags); /* reset tags */
20642fcbc377Syt 
20652fcbc377Syt 	return (SATA_SUCCESS);
20662fcbc377Syt }
20672fcbc377Syt 
20682fcbc377Syt /*
20692fcbc377Syt  * Used to do port reset and reject all the pending packets on a port during
20702fcbc377Syt  * the reset operation.
20712fcbc377Syt  *
20722fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
20732fcbc377Syt  */
20742fcbc377Syt static int
20752fcbc377Syt ahci_reset_port_reject_pkts(ahci_ctl_t *ahci_ctlp,
20762fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
20772fcbc377Syt {
207882263d52Syt 	uint32_t slot_status = 0;
207982263d52Syt 	uint32_t reset_tags = 0;
208082263d52Syt 	uint32_t finished_tags = 0;
20812fcbc377Syt 
20822fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
20832fcbc377Syt 	    "ahci_reset_port_reject_pkts on port: %d", port);
20842fcbc377Syt 
20852fcbc377Syt 	/*
208668d33a25Syt 	 * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
208768d33a25Syt 	 * commands are being mopped, therefore there is nothing else to do
20882fcbc377Syt 	 */
208968d33a25Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
20902fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
20912fcbc377Syt 		    "ahci_reset_port_reject_pkts: port %d is in "
20922fcbc377Syt 		    "mopping process, so return directly ", port);
20932fcbc377Syt 		return (SATA_SUCCESS);
20942fcbc377Syt 	}
20952fcbc377Syt 
209668d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
209768d33a25Syt 	ahci_portp->ahciport_mop_in_progress++;
20982fcbc377Syt 
209982263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
210082263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
210182263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
210282263d52Syt 		reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
210382263d52Syt 	}
21042fcbc377Syt 
210582263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
210682263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
210782263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
210882263d52Syt 		reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
210982263d52Syt 	}
21102fcbc377Syt 
21112fcbc377Syt 	if (ahci_restart_port_wait_till_ready(ahci_ctlp,
211282263d52Syt 	    ahci_portp, port, AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP,
211382263d52Syt 	    NULL) != AHCI_SUCCESS)
21142fcbc377Syt 		return (SATA_FAILURE);
21152fcbc377Syt 
211682263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
211782263d52Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
211882263d52Syt 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
211982263d52Syt 
212082263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp))
212182263d52Syt 		finished_tags = ahci_portp->ahciport_pending_ncq_tags &
212282263d52Syt 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
21232fcbc377Syt 
21242fcbc377Syt 	reset_tags &= ~finished_tags;
21252fcbc377Syt 
21262fcbc377Syt 	ahci_mop_commands(ahci_ctlp,
21272fcbc377Syt 	    ahci_portp,
21282fcbc377Syt 	    port,
21292fcbc377Syt 	    slot_status,
21302fcbc377Syt 	    0, /* failed tags */
21312fcbc377Syt 	    0, /* timeout tags */
21322fcbc377Syt 	    0, /* aborted tags */
21332fcbc377Syt 	    reset_tags); /* reset tags */
21342fcbc377Syt 
21352fcbc377Syt 	return (SATA_SUCCESS);
21362fcbc377Syt }
21372fcbc377Syt 
21382fcbc377Syt /*
21392fcbc377Syt  * Used to do hba reset and reject all the pending packets on all ports
21402fcbc377Syt  * during the reset operation.
21412fcbc377Syt  */
21422fcbc377Syt static int
21432fcbc377Syt ahci_reset_hba_reject_pkts(ahci_ctl_t *ahci_ctlp)
21442fcbc377Syt {
21452fcbc377Syt 	ahci_port_t *ahci_portp;
21462fcbc377Syt 	uint32_t slot_status[AHCI_MAX_PORTS];
21472fcbc377Syt 	uint32_t reset_tags[AHCI_MAX_PORTS];
21482fcbc377Syt 	uint32_t finished_tags[AHCI_MAX_PORTS];
21492fcbc377Syt 	uint8_t port;
21502fcbc377Syt 	int ret = SATA_SUCCESS;
21512fcbc377Syt 
21522fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp,
21532fcbc377Syt 	    "ahci_reset_hba_reject_pkts enter");
21542fcbc377Syt 
21552fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
21562fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
21572fcbc377Syt 			continue;
21582fcbc377Syt 		}
21592fcbc377Syt 
21602fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
21612fcbc377Syt 
21622fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
216382263d52Syt 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
216482263d52Syt 			slot_status[port] = ddi_get32(
216582263d52Syt 			    ahci_ctlp->ahcictl_ahci_acc_handle,
216682263d52Syt 			    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
216782263d52Syt 			reset_tags[port] = slot_status[port] &
216882263d52Syt 			    AHCI_SLOT_MASK(ahci_ctlp);
216982263d52Syt 		}
217082263d52Syt 
217182263d52Syt 		if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
217282263d52Syt 			slot_status[port] = ddi_get32(
217382263d52Syt 			    ahci_ctlp->ahcictl_ahci_acc_handle,
217482263d52Syt 			    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
217582263d52Syt 			reset_tags[port] = slot_status[port] &
217682263d52Syt 			    AHCI_NCQ_SLOT_MASK(ahci_portp);
217782263d52Syt 		}
21782fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
21792fcbc377Syt 	}
21802fcbc377Syt 
21812fcbc377Syt 	if (ahci_hba_reset(ahci_ctlp) != AHCI_SUCCESS) {
21822fcbc377Syt 		ret = SATA_FAILURE;
21832fcbc377Syt 		goto out;
21842fcbc377Syt 	}
21852fcbc377Syt 
21862fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
21872fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
21882fcbc377Syt 			continue;
21892fcbc377Syt 		}
21902fcbc377Syt 
21912fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
21922fcbc377Syt 
21932fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
21942fcbc377Syt 		/*
21952fcbc377Syt 		 * To prevent recursive enter to ahci_mop_commands, we need
219668d33a25Syt 		 * check AHCI_PORT_FLAG_MOPPING flag.
21972fcbc377Syt 		 */
219868d33a25Syt 		if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
21992fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
22002fcbc377Syt 			    "ahci_reset_hba_reject_pkts: port %d is in "
22012fcbc377Syt 			    "mopping process, so return directly ", port);
22022fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
22032fcbc377Syt 			continue;
22042fcbc377Syt 		}
22052fcbc377Syt 
220668d33a25Syt 		ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
220768d33a25Syt 		ahci_portp->ahciport_mop_in_progress++;
22082fcbc377Syt 
220982263d52Syt 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
221082263d52Syt 			finished_tags[port]  =
221182263d52Syt 			    ahci_portp->ahciport_pending_tags &
221282263d52Syt 			    ~slot_status[port] & AHCI_SLOT_MASK(ahci_ctlp);
22132fcbc377Syt 
221482263d52Syt 		if (NCQ_CMD_IN_PROGRESS(ahci_portp))
221582263d52Syt 			finished_tags[port] =
221682263d52Syt 			    ahci_portp->ahciport_pending_ncq_tags &
221782263d52Syt 			    ~slot_status[port] & AHCI_NCQ_SLOT_MASK(ahci_portp);
22182fcbc377Syt 
22192fcbc377Syt 		reset_tags[port] &= ~finished_tags[port];
22202fcbc377Syt 
22212fcbc377Syt 		ahci_mop_commands(ahci_ctlp,
22222fcbc377Syt 		    ahci_portp,
22232fcbc377Syt 		    port,
22242fcbc377Syt 		    slot_status[port],
22252fcbc377Syt 		    0, /* failed tags */
22262fcbc377Syt 		    0, /* timeout tags */
22272fcbc377Syt 		    0, /* aborted tags */
22282fcbc377Syt 		    reset_tags[port]); /* reset tags */
222968d33a25Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
22302fcbc377Syt 	}
22312fcbc377Syt out:
22322fcbc377Syt 	return (ret);
22332fcbc377Syt }
22342fcbc377Syt 
22352fcbc377Syt /*
22362fcbc377Syt  * Called by sata framework to reset a port(s) or device.
22372fcbc377Syt  */
22382fcbc377Syt static int
22392fcbc377Syt ahci_tran_reset_dport(dev_info_t *dip, sata_device_t *sd)
22402fcbc377Syt {
22412fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
22422fcbc377Syt 	ahci_port_t *ahci_portp;
22432fcbc377Syt 	uint8_t cport = sd->satadev_addr.cport;
22442fcbc377Syt 	uint8_t port;
22452fcbc377Syt 	int ret = SATA_SUCCESS;
22462fcbc377Syt 
22472fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
22482fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
22492fcbc377Syt 
22502fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
225168d33a25Syt 	    "ahci_tran_reset_port enter: cport: %d", cport);
22522fcbc377Syt 
22532fcbc377Syt 	switch (sd->satadev_addr.qual) {
22542fcbc377Syt 	case SATA_ADDR_CPORT:
22552fcbc377Syt 		/* Port reset */
22562fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
225768d33a25Syt 		cmn_err(CE_NOTE, "!ahci_tran_reset_dport: port %d "
225868d33a25Syt 		    "reset port", port);
22592fcbc377Syt 
22602fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
22612fcbc377Syt 		ret = ahci_reset_port_reject_pkts(ahci_ctlp, ahci_portp, port);
22622fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
22632fcbc377Syt 
22642fcbc377Syt 		break;
22652fcbc377Syt 
22662fcbc377Syt 	case SATA_ADDR_DCPORT:
22672fcbc377Syt 		/* Device reset */
22682fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
226968d33a25Syt 		cmn_err(CE_NOTE, "!ahci_tran_reset_dport: port %d "
227068d33a25Syt 		    "reset device", port);
22712fcbc377Syt 
22722fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
22732fcbc377Syt 		if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
22742fcbc377Syt 		    ahci_portp->ahciport_port_state & SATA_PSTATE_SHUTDOWN |
22752fcbc377Syt 		    ahci_portp->ahciport_port_state & SATA_PSTATE_PWROFF) {
22762fcbc377Syt 			/*
22772fcbc377Syt 			 * In case the targer driver would send the request
22782fcbc377Syt 			 * before sata framework can have the opportunity to
22792fcbc377Syt 			 * process those event reports.
22802fcbc377Syt 			 */
22812fcbc377Syt 			sd->satadev_state = ahci_portp->ahciport_port_state;
22822fcbc377Syt 			ahci_update_sata_registers(ahci_ctlp, port, sd);
22832fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
22842fcbc377Syt 			    "ahci_tran_reset_dport returning SATA_FAILURE "
22852fcbc377Syt 			    "while port in FAILED/SHUTDOWN/PWROFF state: "
228668d33a25Syt 			    "port: %d", port);
22872fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
22882fcbc377Syt 			ret = SATA_FAILURE;
22892fcbc377Syt 			break;
22902fcbc377Syt 		}
22912fcbc377Syt 
22922fcbc377Syt 		if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
22932fcbc377Syt 			/*
22942fcbc377Syt 			 * ahci_intr_phyrdy_change() may have rendered it to
22952fcbc377Syt 			 * AHCI_PORT_TYPE_NODEV.
22962fcbc377Syt 			 */
22972fcbc377Syt 			sd->satadev_type = SATA_DTYPE_NONE;
22982fcbc377Syt 			sd->satadev_state = ahci_portp->ahciport_port_state;
22992fcbc377Syt 			ahci_update_sata_registers(ahci_ctlp, port, sd);
23002fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
23012fcbc377Syt 			    "ahci_tran_reset_dport returning SATA_FAILURE "
230268d33a25Syt 			    "while no device attached: port: %d", port);
23032fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
23042fcbc377Syt 			ret = SATA_FAILURE;
23052fcbc377Syt 			break;
23062fcbc377Syt 		}
23072fcbc377Syt 
23082fcbc377Syt 		ret = ahci_reset_device_reject_pkts(ahci_ctlp,
23092fcbc377Syt 		    ahci_portp, port);
23102fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
23112fcbc377Syt 		break;
23122fcbc377Syt 
23132fcbc377Syt 	case SATA_ADDR_CNTRL:
23142fcbc377Syt 		/* Reset the whole controller */
231568d33a25Syt 		cmn_err(CE_NOTE, "!ahci_tran_reset_dport: port %d "
231668d33a25Syt 		    "reset the whole hba", port);
23172fcbc377Syt 		ret = ahci_reset_hba_reject_pkts(ahci_ctlp);
23182fcbc377Syt 		break;
23192fcbc377Syt 
23202fcbc377Syt 	case SATA_ADDR_PMPORT:
23212fcbc377Syt 	case SATA_ADDR_DPMPORT:
23222fcbc377Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp,
232368d33a25Syt 		    "ahci_tran_reset_dport: port multiplier will be "
232468d33a25Syt 		    "supported later");
23252fcbc377Syt 		/* FALLSTHROUGH */
23262fcbc377Syt 	default:
23272fcbc377Syt 		ret = SATA_FAILURE;
23282fcbc377Syt 	}
23292fcbc377Syt 
23302fcbc377Syt 	return (ret);
23312fcbc377Syt }
23322fcbc377Syt 
23332fcbc377Syt /*
23342fcbc377Syt  * Called by sata framework to activate a port as part of hotplug.
23352fcbc377Syt  * (cfgadm -c connect satax/y)
23362fcbc377Syt  * Note: Not port-mult aware.
23372fcbc377Syt  */
23382fcbc377Syt static int
23392fcbc377Syt ahci_tran_hotplug_port_activate(dev_info_t *dip, sata_device_t *satadev)
23402fcbc377Syt {
23412fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
23422fcbc377Syt 	ahci_port_t *ahci_portp;
23432fcbc377Syt 	uint8_t	cport = satadev->satadev_addr.cport;
23442fcbc377Syt 	uint8_t port;
23452fcbc377Syt 
23462fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
23472fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
23482fcbc377Syt 
23492fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
23502fcbc377Syt 	    "ahci_tran_hotplug_port_activate cport %d enter", cport);
23512fcbc377Syt 
23522fcbc377Syt 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
23532fcbc377Syt 
23542fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
235582263d52Syt 	ahci_enable_port_intrs(ahci_ctlp, ahci_portp, port);
235668d33a25Syt 	cmn_err(CE_NOTE, "!ahci port %d is activated", port);
23572fcbc377Syt 
23582fcbc377Syt 	/*
23592fcbc377Syt 	 * Reset the port so that the PHY communication would be re-established.
236068d33a25Syt 	 * But this reset is an internal operation and the sata module doesn't
236168d33a25Syt 	 * need to know about it. Moreover, the port with a device attached will
236268d33a25Syt 	 * be started too.
23632fcbc377Syt 	 */
23642fcbc377Syt 	(void) ahci_restart_port_wait_till_ready(ahci_ctlp,
236568d33a25Syt 	    ahci_portp, port,
236668d33a25Syt 	    AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP,
236768d33a25Syt 	    NULL);
23682fcbc377Syt 
23692fcbc377Syt 	/*
23702fcbc377Syt 	 * Need to check the link status and device status of the port
23712fcbc377Syt 	 * and consider raising power if the port was in D3 state
23722fcbc377Syt 	 */
237368d33a25Syt 	ahci_portp->ahciport_port_state |= SATA_PSTATE_PWRON;
237468d33a25Syt 	ahci_portp->ahciport_port_state &= ~SATA_PSTATE_PWROFF;
237568d33a25Syt 	ahci_portp->ahciport_port_state &= ~SATA_PSTATE_SHUTDOWN;
237668d33a25Syt 
237768d33a25Syt 	satadev->satadev_state = ahci_portp->ahciport_port_state;
23782fcbc377Syt 
23792fcbc377Syt 	ahci_update_sata_registers(ahci_ctlp, port, satadev);
23802fcbc377Syt 
23812fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
23822fcbc377Syt 	return (SATA_SUCCESS);
23832fcbc377Syt }
23842fcbc377Syt 
23852fcbc377Syt /*
23862fcbc377Syt  * Called by sata framework to deactivate a port as part of hotplug.
23872fcbc377Syt  * (cfgadm -c disconnect satax/y)
23882fcbc377Syt  * Note: Not port-mult aware.
23892fcbc377Syt  */
23902fcbc377Syt static int
23912fcbc377Syt ahci_tran_hotplug_port_deactivate(dev_info_t *dip, sata_device_t *satadev)
23922fcbc377Syt {
23932fcbc377Syt 	ahci_ctl_t *ahci_ctlp;
23942fcbc377Syt 	ahci_port_t *ahci_portp;
23952fcbc377Syt 	uint8_t cport = satadev->satadev_addr.cport;
23962fcbc377Syt 	uint8_t port;
239768d33a25Syt 	uint32_t port_scontrol;
23982fcbc377Syt 
23992fcbc377Syt 	ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
24002fcbc377Syt 	port = ahci_ctlp->ahcictl_cport_to_port[cport];
24012fcbc377Syt 
24022fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
24032fcbc377Syt 	    "ahci_tran_hotplug_port_deactivate cport %d enter", cport);
24042fcbc377Syt 
24052fcbc377Syt 	ahci_portp = ahci_ctlp->ahcictl_ports[port];
24062fcbc377Syt 
24072fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
240868d33a25Syt 	cmn_err(CE_NOTE, "!ahci port %d is deactivated", port);
24092fcbc377Syt 
241068d33a25Syt 	/* Disable the interrupts on the port */
24112fcbc377Syt 	ahci_disable_port_intrs(ahci_ctlp, ahci_portp, port);
24122fcbc377Syt 
241368d33a25Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
241468d33a25Syt 		goto phy_offline;
241568d33a25Syt 	}
241668d33a25Syt 
24172fcbc377Syt 	/* First to abort all the pending commands */
24182fcbc377Syt 	ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
24192fcbc377Syt 
242068d33a25Syt 	/* Then stop the port */
242168d33a25Syt 	(void) ahci_put_port_into_notrunning_state(ahci_ctlp,
24222fcbc377Syt 	    ahci_portp, port);
24232fcbc377Syt 
242468d33a25Syt 	/* Next put the PHY offline */
242568d33a25Syt 
242668d33a25Syt phy_offline:
242768d33a25Syt 	port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
242868d33a25Syt 	    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
242982263d52Syt 	SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_DISABLE);
243068d33a25Syt 
24312fcbc377Syt 	/* Update ahciport_port_state */
24322fcbc377Syt 	ahci_portp->ahciport_port_state = SATA_PSTATE_SHUTDOWN;
243368d33a25Syt 	satadev->satadev_state = ahci_portp->ahciport_port_state;
24342fcbc377Syt 
24352fcbc377Syt 	ahci_update_sata_registers(ahci_ctlp, port, satadev);
24362fcbc377Syt 
24372fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
24382fcbc377Syt 	return (SATA_SUCCESS);
24392fcbc377Syt }
24402fcbc377Syt 
24412fcbc377Syt /*
244268d33a25Syt  * To be used to mark all the outstanding pkts with SATA_PKT_ABORTED
24432fcbc377Syt  * when a device is unplugged or a port is deactivated.
24442fcbc377Syt  *
24452fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
24462fcbc377Syt  */
24472fcbc377Syt static void
24482fcbc377Syt ahci_reject_all_abort_pkts(ahci_ctl_t *ahci_ctlp,
24492fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
24502fcbc377Syt {
245182263d52Syt 	uint32_t slot_status = 0;
245282263d52Syt 	uint32_t abort_tags = 0;
24532fcbc377Syt 
245468d33a25Syt 	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
24552fcbc377Syt 	    "ahci_reject_all_abort_pkts on port: %d", port);
24562fcbc377Syt 
245782263d52Syt 	/*
245882263d52Syt 	 * When AHCI_PORT_FLAG_MOPPING is set, we need to check whether a
245982263d52Syt 	 * REQUEST SENSE command or READ LOG EXT command is delivered to HBA
246082263d52Syt 	 * to get the error data, if yes when the device is removed, the
246182263d52Syt 	 * command needs to be aborted too.
246282263d52Syt 	 */
246382263d52Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
246482263d52Syt 		if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
246582263d52Syt 			slot_status = 0x1;
246682263d52Syt 			abort_tags = 0x1;
246782263d52Syt 			goto out;
246882263d52Syt 		} else {
246982263d52Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
247082263d52Syt 			    "ahci_reject_all_abort_pkts return directly "
247182263d52Syt 			    "port %d no needs to reject any outstanding "
247282263d52Syt 			    "commands", port);
247382263d52Syt 			return;
247482263d52Syt 		}
247582263d52Syt 	}
24762fcbc377Syt 
247782263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
247882263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
247982263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
248082263d52Syt 		abort_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
248182263d52Syt 	}
248282263d52Syt 
248382263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
248482263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
248582263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
248682263d52Syt 		abort_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
248782263d52Syt 	}
248882263d52Syt 
248982263d52Syt out:
249068d33a25Syt 	/* No need to do mop when there is no outstanding commands */
249168d33a25Syt 	if (slot_status != 0) {
249268d33a25Syt 		ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
249368d33a25Syt 		ahci_portp->ahciport_mop_in_progress++;
24942fcbc377Syt 
249568d33a25Syt 		ahci_mop_commands(ahci_ctlp,
249668d33a25Syt 		    ahci_portp,
249768d33a25Syt 		    port,
249868d33a25Syt 		    slot_status,
249968d33a25Syt 		    0, /* failed tags */
250068d33a25Syt 		    0, /* timeout tags */
250168d33a25Syt 		    abort_tags, /* aborting tags */
250268d33a25Syt 		    0); /* reset tags */
250368d33a25Syt 	}
250468d33a25Syt }
250568d33a25Syt 
250668d33a25Syt #if defined(__lock_lint)
250768d33a25Syt static int
250868d33a25Syt ahci_selftest(dev_info_t *dip, sata_device_t *device)
250968d33a25Syt {
25102fcbc377Syt 	return (SATA_SUCCESS);
25112fcbc377Syt }
25122fcbc377Syt #endif
25132fcbc377Syt 
25142fcbc377Syt /*
251568d33a25Syt  * Allocate the ports structure, only called by ahci_attach
251668d33a25Syt  */
251768d33a25Syt static int
251868d33a25Syt ahci_alloc_ports_state(ahci_ctl_t *ahci_ctlp)
251968d33a25Syt {
252068d33a25Syt 	int port, cport = 0;
252168d33a25Syt 
252268d33a25Syt 	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
252368d33a25Syt 	    "ahci_alloc_ports_state enter");
252468d33a25Syt 
252568d33a25Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
252668d33a25Syt 
252768d33a25Syt 	/* Allocate structures only for the implemented ports */
252868d33a25Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
252968d33a25Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
253068d33a25Syt 			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
253168d33a25Syt 			    "hba port %d not implemented", port);
253268d33a25Syt 			continue;
253368d33a25Syt 		}
253468d33a25Syt 
253568d33a25Syt #ifndef __lock_lint
253668d33a25Syt 		ahci_ctlp->ahcictl_cport_to_port[cport] = (uint8_t)port;
253768d33a25Syt 		ahci_ctlp->ahcictl_port_to_cport[port] =
253868d33a25Syt 		    (uint8_t)cport++;
253968d33a25Syt #endif /* __lock_lint */
254068d33a25Syt 
254168d33a25Syt 		if (ahci_alloc_port_state(ahci_ctlp, port) != AHCI_SUCCESS) {
254268d33a25Syt 			goto err_out;
254368d33a25Syt 		}
254468d33a25Syt 	}
254568d33a25Syt 
254668d33a25Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
254768d33a25Syt 	return (AHCI_SUCCESS);
254868d33a25Syt 
254968d33a25Syt err_out:
255068d33a25Syt 	for (port--; port >= 0; port--) {
255168d33a25Syt 		if (AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
255268d33a25Syt 			ahci_dealloc_port_state(ahci_ctlp, port);
255368d33a25Syt 		}
255468d33a25Syt 	}
255568d33a25Syt 
255668d33a25Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
255768d33a25Syt 	return (AHCI_FAILURE);
255868d33a25Syt }
255968d33a25Syt 
256068d33a25Syt /*
256168d33a25Syt  * Reverse of ahci_alloc_ports_state(), only called by ahci_detach
256268d33a25Syt  */
256368d33a25Syt static void
256468d33a25Syt ahci_dealloc_ports_state(ahci_ctl_t *ahci_ctlp)
256568d33a25Syt {
256668d33a25Syt 	int port;
256768d33a25Syt 
256868d33a25Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
256968d33a25Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
257068d33a25Syt 		/* if this port is implemented by the HBA */
257168d33a25Syt 		if (AHCI_PORT_IMPLEMENTED(ahci_ctlp, port))
257268d33a25Syt 			ahci_dealloc_port_state(ahci_ctlp, port);
257368d33a25Syt 	}
257468d33a25Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
257568d33a25Syt }
257668d33a25Syt 
257768d33a25Syt /*
257868d33a25Syt  * Initialize the controller.
25792fcbc377Syt  *
25802fcbc377Syt  * This routine can be called from three seperate cases: DDI_ATTACH,
25812fcbc377Syt  * PM_LEVEL_D0 and DDI_RESUME. The DDI_ATTACH case is different from
258268d33a25Syt  * other two cases; device signature probing are attempted only during
258368d33a25Syt  * DDI_ATTACH case.
25842fcbc377Syt  *
25852fcbc377Syt  * WARNING!!! Disable the whole controller's interrupts before calling and
25862fcbc377Syt  * the interrupts will be enabled upon successfully return.
25872fcbc377Syt  */
25882fcbc377Syt static int
25892fcbc377Syt ahci_initialize_controller(ahci_ctl_t *ahci_ctlp)
25902fcbc377Syt {
25912fcbc377Syt 	ahci_port_t *ahci_portp;
25922fcbc377Syt 	uint32_t ghc_control;
259368d33a25Syt 	int port;
25942fcbc377Syt 
25952fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
25962fcbc377Syt 	    "ahci_initialize_controller enter");
25972fcbc377Syt 
25982fcbc377Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
25992fcbc377Syt 
26002fcbc377Syt 	/*
26012fcbc377Syt 	 * Indicate that system software is AHCI aware by setting
26022fcbc377Syt 	 * GHC.AE to 1
26032fcbc377Syt 	 */
26042fcbc377Syt 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
26052fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
26062fcbc377Syt 
26072fcbc377Syt 	ghc_control |= AHCI_HBA_GHC_AE;
26082fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
26092fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp),
26102fcbc377Syt 	    ghc_control);
26112fcbc377Syt 
261282263d52Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
261382263d52Syt 
26142fcbc377Syt 	/* Initialize the implemented ports and structures */
26152fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
26162fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
26172fcbc377Syt 			continue;
26182fcbc377Syt 		}
26192fcbc377Syt 
26202fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
26212fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
26222fcbc377Syt 
26232fcbc377Syt 		/*
26242fcbc377Syt 		 * Ensure that the controller is not in the running state
26252fcbc377Syt 		 * by checking every implemented port's PxCMD register
26262fcbc377Syt 		 */
26272fcbc377Syt 		if (ahci_initialize_port(ahci_ctlp, ahci_portp, port)
26282fcbc377Syt 		    != AHCI_SUCCESS) {
26292fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
26302fcbc377Syt 			    "ahci_initialize_controller: failed to "
26312fcbc377Syt 			    "initialize port %d", port);
26322fcbc377Syt 			/*
26332fcbc377Syt 			 * Set the port state to SATA_PSTATE_FAILED if
26342fcbc377Syt 			 * failed to initialize it.
26352fcbc377Syt 			 */
263668d33a25Syt 			ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
26372fcbc377Syt 		}
26382fcbc377Syt 
26392fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
26402fcbc377Syt 	}
26412fcbc377Syt 
26422fcbc377Syt 	/* Enable the whole controller interrupts */
264382263d52Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
26442fcbc377Syt 	ahci_enable_all_intrs(ahci_ctlp);
26452fcbc377Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
26462fcbc377Syt 
26472fcbc377Syt 	return (AHCI_SUCCESS);
26482fcbc377Syt }
26492fcbc377Syt 
26502fcbc377Syt /*
265168d33a25Syt  * Reverse of ahci_initialize_controller()
26522fcbc377Syt  *
26532fcbc377Syt  * WARNING!!! ahcictl_mutex should be acquired before the function is called.
26542fcbc377Syt  */
26552fcbc377Syt static void
265668d33a25Syt ahci_uninitialize_controller(ahci_ctl_t *ahci_ctlp)
26572fcbc377Syt {
26582fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
265968d33a25Syt 	    "ahci_uninitialize_controller enter");
26602fcbc377Syt 
26612fcbc377Syt 	/* disable all the interrupts. */
26622fcbc377Syt 	ahci_disable_all_intrs(ahci_ctlp);
26632fcbc377Syt }
26642fcbc377Syt 
26652fcbc377Syt /*
26662fcbc377Syt  * The routine is to initialize the port. First put the port in NOTRunning
26672fcbc377Syt  * state, then enable port interrupt and clear Serror register. And under
26682fcbc377Syt  * AHCI_ATTACH case, find device signature and then try to start the port.
26692fcbc377Syt  *
267082263d52Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
26712fcbc377Syt  */
26722fcbc377Syt static int
26732fcbc377Syt ahci_initialize_port(ahci_ctl_t *ahci_ctlp,
26742fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
26752fcbc377Syt {
26762fcbc377Syt 	uint32_t port_cmd_status;
26772fcbc377Syt 
26782fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
26792fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
26802fcbc377Syt 
26812fcbc377Syt 	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
26822fcbc377Syt 	    "ahci_initialize_port: port %d "
26832fcbc377Syt 	    "port_cmd_status = 0x%x", port, port_cmd_status);
26842fcbc377Syt 	/*
26852fcbc377Syt 	 * Check whether the port is in NotRunning state, if not,
26862fcbc377Syt 	 * put the port in NotRunning state
26872fcbc377Syt 	 */
26882fcbc377Syt 	if (!(port_cmd_status &
26892fcbc377Syt 	    (AHCI_CMD_STATUS_ST |
26902fcbc377Syt 	    AHCI_CMD_STATUS_CR |
26912fcbc377Syt 	    AHCI_CMD_STATUS_FRE |
26922fcbc377Syt 	    AHCI_CMD_STATUS_FR))) {
26932fcbc377Syt 
269468d33a25Syt 		goto next;
26952fcbc377Syt 	}
26962fcbc377Syt 
26972fcbc377Syt 	if (ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
269868d33a25Syt 	    port, AHCI_RESET_NO_EVENTS_UP|AHCI_PORT_INIT, NULL) != AHCI_SUCCESS)
26992fcbc377Syt 		return (AHCI_FAILURE);
27002fcbc377Syt 
270168d33a25Syt next:
27022fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
270368d33a25Syt 	    "port %d is in NotRunning state now", port);
27042fcbc377Syt 
27052fcbc377Syt 	/*
270668d33a25Syt 	 * At the time being, only probe ports/devices and get the types of
270768d33a25Syt 	 * attached devices during attach. In fact, the device can be changed
270868d33a25Syt 	 * during power state changes, but I would like to postpone this part
270968d33a25Syt 	 * when the power management is supported.
27102fcbc377Syt 	 */
27112fcbc377Syt 	if (ahci_ctlp->ahcictl_flags & AHCI_ATTACH) {
271268d33a25Syt 		/* Try to get the device signature */
271368d33a25Syt 		ahci_find_dev_signature(ahci_ctlp, ahci_portp, port);
27142fcbc377Syt 
271568d33a25Syt 		/* Return directly if no device connected */
271668d33a25Syt 		if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
271768d33a25Syt 			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
271868d33a25Syt 			    "No device connected to port %d", port);
271968d33a25Syt 			goto out;
27202fcbc377Syt 		}
27212fcbc377Syt 
27222fcbc377Syt 		/* Try to start the port */
272368d33a25Syt 		if (ahci_start_port(ahci_ctlp, ahci_portp, port)
272468d33a25Syt 		    != AHCI_SUCCESS) {
272568d33a25Syt 			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
272668d33a25Syt 			    "failed to start port %d", port);
27272fcbc377Syt 			return (AHCI_FAILURE);
27282fcbc377Syt 		}
27292fcbc377Syt 	}
273068d33a25Syt out:
273168d33a25Syt 	/* Enable port interrupts */
273268d33a25Syt 	ahci_enable_port_intrs(ahci_ctlp, ahci_portp, port);
27332fcbc377Syt 
27342fcbc377Syt 	return (AHCI_SUCCESS);
27352fcbc377Syt }
27362fcbc377Syt 
27372fcbc377Syt /*
27382fcbc377Syt  * AHCI device reset ...; a single device on one of the ports is reset,
27392fcbc377Syt  * but the HBA and physical communication remain intact. This is the
27402fcbc377Syt  * least intrusive.
27412fcbc377Syt  *
27422fcbc377Syt  * When issuing a software reset sequence, there should not be other
27432fcbc377Syt  * commands in the command list, so we will first clear and then re-set
27442fcbc377Syt  * PxCMD.ST to clear PxCI. And before issuing the software reset,
27452fcbc377Syt  * the port must be idle and PxTFD.STS.BSY and PxTFD.STS.DRQ must be
27462fcbc377Syt  * cleared.
27472fcbc377Syt  *
27482fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired and PxCMD.FRE should be
27492fcbc377Syt  * set before the function is called.
27502fcbc377Syt  */
27512fcbc377Syt static int
27522fcbc377Syt ahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
27532fcbc377Syt     uint8_t port)
27542fcbc377Syt {
27552fcbc377Syt 	ahci_fis_h2d_register_t *h2d_register_fisp;
27562fcbc377Syt 	ahci_cmd_table_t *cmd_table;
27572fcbc377Syt 	ahci_cmd_header_t *cmd_header;
275868d33a25Syt 	uint32_t port_cmd_status, port_cmd_issue, port_task_file;
27592fcbc377Syt 	int slot, loop_count;
27602fcbc377Syt 
27612fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
27622fcbc377Syt 	    "Port %d device resetting", port);
27632fcbc377Syt 
27642fcbc377Syt 	/* First to clear PxCMD.ST */
27652fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
27662fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
27672fcbc377Syt 
27682fcbc377Syt 	port_cmd_status &= ~AHCI_CMD_STATUS_ST;
27692fcbc377Syt 
27702fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
27712fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
27722fcbc377Syt 	    port_cmd_status|AHCI_CMD_STATUS_ST);
27732fcbc377Syt 
27742fcbc377Syt 	/* And then to re-set PxCMD.ST */
27752fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
27762fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
27772fcbc377Syt 
27782fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
27792fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
27802fcbc377Syt 	    port_cmd_status|AHCI_CMD_STATUS_ST);
27812fcbc377Syt 
27822fcbc377Syt 	/* Check PxTFD.STS.BSY and PxTFD.STS.DRQ */
27832fcbc377Syt 	port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
27842fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
27852fcbc377Syt 
27862fcbc377Syt 	if (port_task_file & AHCI_TFD_STS_BSY ||
27872fcbc377Syt 	    port_task_file & AHCI_TFD_STS_DRQ) {
27882fcbc377Syt 		if (!(port_cmd_status & AHCI_CMD_STATUS_CLO)) {
27892fcbc377Syt 			AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
27902fcbc377Syt 			    "PxTFD.STS.BSY or PxTFD.STS.DRQ is still set, "
27912fcbc377Syt 			    "but PxCMD.CLO isn't supported, so a port "
27922fcbc377Syt 			    "reset is needed.");
27932fcbc377Syt 			return (AHCI_FAILURE);
27942fcbc377Syt 		}
27952fcbc377Syt 	}
27962fcbc377Syt 
279782263d52Syt 	slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp, AHCI_NON_NCQ_CMD);
27982fcbc377Syt 	if (slot == AHCI_FAILURE) {
27992fcbc377Syt 		AHCIDBG0(AHCIDBG_INFO, ahci_ctlp,
28002fcbc377Syt 		    "ahci_software_reset: no free slot");
28012fcbc377Syt 		return (AHCI_FAILURE);
28022fcbc377Syt 	}
28032fcbc377Syt 
28042fcbc377Syt 	/* Now send the first R2H FIS with SRST set to 1 */
28052fcbc377Syt 	cmd_table = ahci_portp->ahciport_cmd_tables[slot];
28062fcbc377Syt 	bzero((void *)cmd_table, ahci_cmd_table_size);
28072fcbc377Syt 
28082fcbc377Syt 	h2d_register_fisp =
28092fcbc377Syt 	    &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
28102fcbc377Syt 
28112fcbc377Syt 	SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
28122fcbc377Syt 	SET_FIS_PMP(h2d_register_fisp, AHCI_PORTMULT_CONTROL_PORT);
28132fcbc377Syt 	SET_FIS_DEVCTL(h2d_register_fisp, SATA_DEVCTL_SRST);
28142fcbc377Syt 
28152fcbc377Syt 	/* Set Command Header in Command List */
28162fcbc377Syt 	cmd_header = &ahci_portp->ahciport_cmd_list[slot];
28172fcbc377Syt 	BZERO_DESCR_INFO(cmd_header);
28182fcbc377Syt 	BZERO_PRD_BYTE_COUNT(cmd_header);
28192fcbc377Syt 	SET_COMMAND_FIS_LENGTH(cmd_header, 5);
28202fcbc377Syt 
28212fcbc377Syt 	SET_CLEAR_BUSY_UPON_R_OK(cmd_header, 1);
28222fcbc377Syt 	SET_RESET(cmd_header, 1);
28232fcbc377Syt 	SET_WRITE(cmd_header, 1);
28242fcbc377Syt 
28252fcbc377Syt 	(void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
28262fcbc377Syt 	    0,
28272fcbc377Syt 	    ahci_cmd_table_size,
28282fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
28292fcbc377Syt 
28302fcbc377Syt 	(void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
28312fcbc377Syt 	    slot * sizeof (ahci_cmd_header_t),
28322fcbc377Syt 	    sizeof (ahci_cmd_header_t),
28332fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
28342fcbc377Syt 
28352fcbc377Syt 	/* Indicate to the HBA that a command is active. */
28362fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
28372fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
28382fcbc377Syt 	    (0x1 << slot));
28392fcbc377Syt 
28402fcbc377Syt 	loop_count = 0;
28412fcbc377Syt 
28422fcbc377Syt 	/* Loop till the first command is finished */
28432fcbc377Syt 	do {
28442fcbc377Syt 		port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
28452fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
28462fcbc377Syt 
28472fcbc377Syt 		if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
28482fcbc377Syt 			/* We are effectively timing out after 0.1 sec. */
28492fcbc377Syt 			break;
28502fcbc377Syt 		}
28512fcbc377Syt 		/* Wait for 10 millisec */
28522fcbc377Syt #ifndef __lock_lint
28532fcbc377Syt 		delay(AHCI_10MS_TICKS);
28542fcbc377Syt #endif /* __lock_lint */
28552fcbc377Syt 	} while (port_cmd_issue	& AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
28562fcbc377Syt 
28572fcbc377Syt 	AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp,
28582fcbc377Syt 	    "ahci_software_reset: 1st loop count: %d, "
28592fcbc377Syt 	    "port_cmd_issue = 0x%x, slot = 0x%x",
28602fcbc377Syt 	    loop_count, port_cmd_issue, slot);
28612fcbc377Syt 
28622fcbc377Syt 	CLEAR_BIT(ahci_portp->ahciport_pending_tags, slot);
28632fcbc377Syt 	ahci_portp->ahciport_slot_pkts[slot] = NULL;
28642fcbc377Syt 
28652fcbc377Syt 	/* Now send the second R2H FIS with SRST cleard to zero */
28662fcbc377Syt 	cmd_table = ahci_portp->ahciport_cmd_tables[slot];
28672fcbc377Syt 	bzero((void *)cmd_table, ahci_cmd_table_size);
28682fcbc377Syt 
28692fcbc377Syt 	h2d_register_fisp =
28702fcbc377Syt 	    &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
28712fcbc377Syt 
28722fcbc377Syt 	SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
28732fcbc377Syt 	SET_FIS_PMP(h2d_register_fisp, AHCI_PORTMULT_CONTROL_PORT);
28742fcbc377Syt 
28752fcbc377Syt 	/* Set Command Header in Command List */
28762fcbc377Syt 	cmd_header = &ahci_portp->ahciport_cmd_list[slot];
28772fcbc377Syt 	BZERO_DESCR_INFO(cmd_header);
28782fcbc377Syt 	BZERO_PRD_BYTE_COUNT(cmd_header);
28792fcbc377Syt 	SET_COMMAND_FIS_LENGTH(cmd_header, 5);
28802fcbc377Syt 
28812fcbc377Syt 	SET_WRITE(cmd_header, 1);
28822fcbc377Syt 
28832fcbc377Syt 	(void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
28842fcbc377Syt 	    0,
28852fcbc377Syt 	    ahci_cmd_table_size,
28862fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
28872fcbc377Syt 
28882fcbc377Syt 	(void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
28892fcbc377Syt 	    slot * sizeof (ahci_cmd_header_t),
28902fcbc377Syt 	    sizeof (ahci_cmd_header_t),
28912fcbc377Syt 	    DDI_DMA_SYNC_FORDEV);
28922fcbc377Syt 
28932fcbc377Syt 	/* Indicate to the HBA that a command is active. */
28942fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
28952fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
28962fcbc377Syt 	    (0x1 << slot));
28972fcbc377Syt 
28982fcbc377Syt 	loop_count = 0;
28992fcbc377Syt 
29002fcbc377Syt 	/* Loop till the second command is finished */
29012fcbc377Syt 	do {
29022fcbc377Syt 		port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
29032fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
29042fcbc377Syt 
29052fcbc377Syt 		if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
29062fcbc377Syt 			/* We are effectively timing out after 0.1 sec. */
29072fcbc377Syt 			break;
29082fcbc377Syt 		}
29092fcbc377Syt 		/* Wait for 10 millisec */
29102fcbc377Syt #ifndef __lock_lint
29112fcbc377Syt 		delay(AHCI_10MS_TICKS);
29122fcbc377Syt #endif /* __lock_lint */
29132fcbc377Syt 	} while (port_cmd_issue	& AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
29142fcbc377Syt 
29152fcbc377Syt 	AHCIDBG3(AHCIDBG_POLL_LOOP, ahci_ctlp,
29162fcbc377Syt 	    "ahci_software_reset: 2nd loop count: %d, "
29172fcbc377Syt 	    "port_cmd_issue = 0x%x, slot = 0x%x",
29182fcbc377Syt 	    loop_count, port_cmd_issue, slot);
29192fcbc377Syt 
29202fcbc377Syt 	CLEAR_BIT(ahci_portp->ahciport_pending_tags, slot);
29212fcbc377Syt 	ahci_portp->ahciport_slot_pkts[slot] = NULL;
29222fcbc377Syt 
29232fcbc377Syt 	return (AHCI_SUCCESS);
29242fcbc377Syt }
29252fcbc377Syt 
29262fcbc377Syt /*
29272fcbc377Syt  * AHCI port reset ...; the physical communication between the HBA and device
29282fcbc377Syt  * on a port are disabled. This is more intrusive.
29292fcbc377Syt  *
293068d33a25Syt  * When an HBA or port reset occurs, Phy communication is going to
29312fcbc377Syt  * be re-established with the device through a COMRESET followed by the
29322fcbc377Syt  * normal out-of-band communication sequence defined in Serial ATA. AT
29332fcbc377Syt  * the end of reset, the device, if working properly, will send a D2H
29342fcbc377Syt  * Register FIS, which contains the device signature. When the HBA receives
29352fcbc377Syt  * this FIS, it updates PxTFD.STS and PxTFD.ERR register fields, and updates
29362fcbc377Syt  * the PxSIG register with the signature.
29372fcbc377Syt  *
29382fcbc377Syt  * Staggered spin-up is an optional feature in SATA II, and it enables an HBA
29392fcbc377Syt  * to individually spin-up attached devices. Please refer to chapter 10.9 of
294068d33a25Syt  * AHCI 1.0 spec.
29412fcbc377Syt  */
29422fcbc377Syt /*
294382263d52Syt  * WARNING!!! ahciport_mutex should be acquired, and PxCMD.ST should be also
294482263d52Syt  * cleared before the function is called.
29452fcbc377Syt  */
29462fcbc377Syt static int
29472fcbc377Syt ahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
29482fcbc377Syt {
29492fcbc377Syt 	uint32_t cap_status, port_cmd_status;
29502fcbc377Syt 	uint32_t port_scontrol, port_sstatus;
29512fcbc377Syt 	uint32_t port_signature, port_intr_status, port_task_file;
29522fcbc377Syt 	int loop_count;
295368d33a25Syt 	int rval = AHCI_SUCCESS;
29542fcbc377Syt 
29552fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
29562fcbc377Syt 	    "Port %d port resetting...", port);
295768d33a25Syt 	ahci_portp->ahciport_port_state = 0;
29582fcbc377Syt 
29592fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
29602fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
29612fcbc377Syt 
29622fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
29632fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
29642fcbc377Syt 
29652fcbc377Syt 	if (cap_status & AHCI_HBA_CAP_SSS) {
29662fcbc377Syt 		/*
29672fcbc377Syt 		 * HBA support staggered spin-up, if the port has
29682fcbc377Syt 		 * not spin up yet, then force it to do spin-up
29692fcbc377Syt 		 */
29702fcbc377Syt 		if (!(port_cmd_status & AHCI_CMD_STATUS_SUD)) {
29712fcbc377Syt 			if (!(ahci_portp->ahciport_flags
297268d33a25Syt 			    & AHCI_PORT_FLAG_SPINUP)) {
29732fcbc377Syt 				AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
29742fcbc377Syt 				    "Port %d PxCMD.SUD is zero, force "
29752fcbc377Syt 				    "it to do spin-up", port);
29762fcbc377Syt 				ahci_portp->ahciport_flags |=
297768d33a25Syt 				    AHCI_PORT_FLAG_SPINUP;
29782fcbc377Syt 			}
29792fcbc377Syt 		}
29802fcbc377Syt 	} else {
29812fcbc377Syt 		/*
29822fcbc377Syt 		 * HBA doesn't support stagger spin-up, force it
29832fcbc377Syt 		 * to do normal COMRESET
29842fcbc377Syt 		 */
29852fcbc377Syt 		if (ahci_portp->ahciport_flags &
298668d33a25Syt 		    AHCI_PORT_FLAG_SPINUP) {
29872fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
29882fcbc377Syt 			    "HBA does not support staggered spin-up "
29892fcbc377Syt 			    "force it to do normal COMRESET");
29902fcbc377Syt 			ahci_portp->ahciport_flags &=
299168d33a25Syt 			    ~AHCI_PORT_FLAG_SPINUP;
29922fcbc377Syt 		}
29932fcbc377Syt 	}
29942fcbc377Syt 
299568d33a25Syt 	if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_SPINUP)) {
29962fcbc377Syt 		/* Do normal COMRESET */
29972fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
29982fcbc377Syt 		    "ahci_port_reset: do normal COMRESET", port);
29992fcbc377Syt 
3000*95c11c1fSyt 		/*
3001*95c11c1fSyt 		 * According to the spec, SUD bit should be set here,
3002*95c11c1fSyt 		 * but JMicron JMB363 doesn't follow it, so remove
3003*95c11c1fSyt 		 * the assertion, and just print a debug message.
3004*95c11c1fSyt 		 */
3005*95c11c1fSyt #if AHCI_DEBUG
3006*95c11c1fSyt 		if (!(port_cmd_status & AHCI_CMD_STATUS_SUD))
3007*95c11c1fSyt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
3008*95c11c1fSyt 			    "port %d SUD bit not set", port)
3009*95c11c1fSyt #endif
30102fcbc377Syt 
30112fcbc377Syt 		port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
30122fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
301382263d52Syt 		SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_COMRESET);
30142fcbc377Syt 
30152fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30162fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port),
30172fcbc377Syt 		    port_scontrol);
30182fcbc377Syt 
30192fcbc377Syt 		/* Enable PxCMD.FRE to read device */
30202fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30212fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
30222fcbc377Syt 		    port_cmd_status|AHCI_CMD_STATUS_FRE);
30232fcbc377Syt 
302468d33a25Syt 		/*
302568d33a25Syt 		 * Give time for COMRESET to percolate, according to the AHCI
302668d33a25Syt 		 * spec, software shall wait at least 1 millisecond before
302768d33a25Syt 		 * clearing PxSCTL.DET
302868d33a25Syt 		 */
30292fcbc377Syt #ifndef __lock_lint
30302fcbc377Syt 		delay(AHCI_1MS_TICKS*2);
30312fcbc377Syt #endif /* __lock_lint */
30322fcbc377Syt 
30332fcbc377Syt 		/* Fetch the SCONTROL again and rewrite the DET part with 0 */
30342fcbc377Syt 		port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
30352fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
303682263d52Syt 		SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_NOACTION);
30372fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30382fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port),
30392fcbc377Syt 		    port_scontrol);
30402fcbc377Syt 	} else {
30412fcbc377Syt 		/* Do staggered spin-up */
30422fcbc377Syt 		port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
30432fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
304482263d52Syt 		SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_NOACTION);
30452fcbc377Syt 
30462fcbc377Syt 		/* PxSCTL.DET must be 0 */
30472fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30482fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port),
30492fcbc377Syt 		    port_scontrol);
30502fcbc377Syt 
30512fcbc377Syt 		port_cmd_status &= ~AHCI_CMD_STATUS_SUD;
30522fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30532fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
30542fcbc377Syt 		    port_cmd_status);
30552fcbc377Syt 
30562fcbc377Syt 		/* 0 -> 1 edge */
30572fcbc377Syt #ifndef __lock_lint
30582fcbc377Syt 		delay(AHCI_1MS_TICKS*2);
30592fcbc377Syt #endif /* __lock_lint */
30602fcbc377Syt 
30612fcbc377Syt 		/* Set PxCMD.SUD to 1 */
30622fcbc377Syt 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
30632fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
30642fcbc377Syt 		port_cmd_status |= AHCI_CMD_STATUS_SUD;
30652fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30662fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
30672fcbc377Syt 		    port_cmd_status);
30682fcbc377Syt 
30692fcbc377Syt 		/* Enable PxCMD.FRE to read device */
30702fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
30712fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
30722fcbc377Syt 		    port_cmd_status|AHCI_CMD_STATUS_FRE);
30732fcbc377Syt 	}
30742fcbc377Syt 
30752fcbc377Syt 	/*
307668d33a25Syt 	 * The port enters P:StartComm state, and HBA tells link layer to
307768d33a25Syt 	 * start communication, which involves sending COMRESET to device.
307868d33a25Syt 	 * And the HBA resets PxTFD.STS to 7Fh.
307968d33a25Syt 	 *
308068d33a25Syt 	 * When a COMINIT is received from the device, then the port enters
308168d33a25Syt 	 * P:ComInit state. And HBA sets PxTFD.STS to FFh or 80h. HBA sets
308268d33a25Syt 	 * PxSSTS.DET to 1h to indicate a device is detected but communication
308368d33a25Syt 	 * is not yet established. HBA sets PxSERR.DIAG.X to '1' to indicate
308468d33a25Syt 	 * a COMINIT has been received.
30852fcbc377Syt 	 */
30862fcbc377Syt 	/*
30872fcbc377Syt 	 * The DET field is valid only if IPM field indicates
30882fcbc377Syt 	 * that the interface is in active state.
30892fcbc377Syt 	 */
30902fcbc377Syt 	loop_count = 0;
30912fcbc377Syt 	do {
30922fcbc377Syt 		port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
30932fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
30942fcbc377Syt 
309582263d52Syt 		if (SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) {
30962fcbc377Syt 			/*
30972fcbc377Syt 			 * If the interface is not active, the DET field
30982fcbc377Syt 			 * is considered not accurate. So we want to
30992fcbc377Syt 			 * continue looping.
31002fcbc377Syt 			 */
310182263d52Syt 			SSTATUS_SET_DET(port_sstatus, SSTATUS_DET_NODEV);
31022fcbc377Syt 		}
31032fcbc377Syt 
31042fcbc377Syt 		if (loop_count++ > AHCI_POLLRATE_PORT_SSTATUS) {
31052fcbc377Syt 			/*
31062fcbc377Syt 			 * We are effectively timing out after 0.1 sec.
31072fcbc377Syt 			 */
31082fcbc377Syt 			break;
31092fcbc377Syt 		}
31102fcbc377Syt 
31112fcbc377Syt 		/* Wait for 10 millisec */
31122fcbc377Syt #ifndef __lock_lint
31132fcbc377Syt 		delay(AHCI_10MS_TICKS);
31142fcbc377Syt #endif /* __lock_lint */
31152fcbc377Syt 
311682263d52Syt 	} while (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM);
31172fcbc377Syt 
311868d33a25Syt 	AHCIDBG3(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
311968d33a25Syt 	    "ahci_port_reset: 1st loop count: %d, "
312068d33a25Syt 	    "port_sstatus = 0x%x port %d",
312168d33a25Syt 	    loop_count, port_sstatus, port);
31222fcbc377Syt 
312382263d52Syt 	if ((SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) ||
312482263d52Syt 	    (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM)) {
31252fcbc377Syt 		/*
31262fcbc377Syt 		 * Either the port is not active or there
31272fcbc377Syt 		 * is no device present.
31282fcbc377Syt 		 */
31292fcbc377Syt 		ahci_portp->ahciport_device_type = SATA_DTYPE_NONE;
313068d33a25Syt 		goto out;
31312fcbc377Syt 	}
31322fcbc377Syt 
313368d33a25Syt 	/* Now we can make sure there is a device connected to the port */
313468d33a25Syt 	port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
313568d33a25Syt 	    (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port));
31362fcbc377Syt 
313768d33a25Syt 	/* a COMINIT signal is supposed to be received */
313868d33a25Syt 	if (!(port_intr_status & AHCI_INTR_STATUS_PCS)) {
313968d33a25Syt 		cmn_err(CE_WARN, "ahci_port_reset: port %d COMINIT signal "
314068d33a25Syt 		    "from the device not received", port);
314168d33a25Syt 		ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED;
314268d33a25Syt 		rval = AHCI_FAILURE;
314368d33a25Syt 		goto out;
314468d33a25Syt 	}
31452fcbc377Syt 
3146*95c11c1fSyt 	/*
3147*95c11c1fSyt 	 * According to the spec, when PxSCTL.DET is set to 0h, upon
3148*95c11c1fSyt 	 * receiving a COMINIT from the attached device, PxTFD.STS.BSY
3149*95c11c1fSyt 	 * shall be set to '1' by the HBA.
3150*95c11c1fSyt 	 *
3151*95c11c1fSyt 	 * However, we found JMicron JMB363 doesn't follow this, so
3152*95c11c1fSyt 	 * remove this check, and just print a debug message.
3153*95c11c1fSyt 	 */
3154*95c11c1fSyt #if AHCI_DEBUG
315568d33a25Syt 	port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
315668d33a25Syt 	    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
315768d33a25Syt 	if (!(port_task_file & AHCI_TFD_STS_BSY)) {
3158*95c11c1fSyt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
3159*95c11c1fSyt 		    "port %d BSY bit is not set after COMINIT signal "
3160*95c11c1fSyt 		    "is received", port);
316168d33a25Syt 	}
3162*95c11c1fSyt #endif
31632fcbc377Syt 
316468d33a25Syt 	/*
316568d33a25Syt 	 * PxSERR.DIAG.X has to be cleared in order to update PxTFD with
316668d33a25Syt 	 * the D2H FIS received by HBA.
316768d33a25Syt 	 */
316868d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
316968d33a25Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
317082263d52Syt 	    SERROR_EXCHANGED_ERR);
31712fcbc377Syt 
317268d33a25Syt 	/*
317368d33a25Syt 	 * Next check whether COMRESET is completed successfully
317468d33a25Syt 	 */
317568d33a25Syt 	loop_count = 0;
317668d33a25Syt 	do {
317768d33a25Syt 		port_task_file =
317868d33a25Syt 		    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
317968d33a25Syt 		    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
31802fcbc377Syt 
31812fcbc377Syt 		/*
318268d33a25Syt 		 * The Error bit '1' means COMRESET is finished successfully
318368d33a25Syt 		 * The device hardware has been initialized and the power-up
318468d33a25Syt 		 * diagnostics successfully completed.
31852fcbc377Syt 		 */
318668d33a25Syt 		if (((port_task_file & AHCI_TFD_ERR_MASK)
318768d33a25Syt 		    >> AHCI_TFD_ERR_SHIFT) == 0x1) {
318868d33a25Syt 
318968d33a25Syt 			port_signature = ddi_get32(
319068d33a25Syt 			    ahci_ctlp->ahcictl_ahci_acc_handle,
319168d33a25Syt 			    (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port));
319268d33a25Syt 			AHCIDBG2(AHCIDBG_INFO, ahci_ctlp,
319368d33a25Syt 			    "COMRESET success, D2H register FIS "
319468d33a25Syt 			    "post to received FIS structure "
319568d33a25Syt 			    "port %d signature = 0x%x",
319668d33a25Syt 			    port, port_signature);
319768d33a25Syt 			goto out_check;
319868d33a25Syt 		}
31992fcbc377Syt 
320068d33a25Syt 		if (loop_count++ > AHCI_POLLRATE_PORT_TFD_ERROR) {
320168d33a25Syt 			/*
320268d33a25Syt 			 * We are effectively timing out after 11 sec.
320368d33a25Syt 			 */
320468d33a25Syt 			break;
320568d33a25Syt 		}
32062fcbc377Syt 
320768d33a25Syt 		/* Wait for 10 millisec */
32082fcbc377Syt #ifndef __lock_lint
320968d33a25Syt 		delay(AHCI_10MS_TICKS);
32102fcbc377Syt #endif /* __lock_lint */
32112fcbc377Syt 
321268d33a25Syt 	} while (((port_task_file & AHCI_TFD_ERR_MASK)
321368d33a25Syt 	    >> AHCI_TFD_ERR_SHIFT) != 0x1);
32142fcbc377Syt 
321568d33a25Syt 	AHCIDBG3(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: 2nd loop "
321668d33a25Syt 	    "count: %d, port_task_file = 0x%x port %d",
321768d33a25Syt 	    loop_count, port_task_file, port);
32182fcbc377Syt 
321968d33a25Syt 	cmn_err(CE_WARN, "ahci_port_reset: port %d the device hardware "
322068d33a25Syt 	    "has been initialized and the power-up diagnostics failed",
322168d33a25Syt 	    port);
32222fcbc377Syt 
322368d33a25Syt 	ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED;
322468d33a25Syt 	rval = AHCI_FAILURE;
32252fcbc377Syt 
322668d33a25Syt out:
322768d33a25Syt 	/* Clear port serror register for the port */
322868d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
322968d33a25Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
323068d33a25Syt 	    AHCI_SERROR_CLEAR_ALL);
323168d33a25Syt 
323268d33a25Syt 	return (rval);
323368d33a25Syt 
323468d33a25Syt out_check:
323568d33a25Syt 	/*
323668d33a25Syt 	 * Check device status, if keep busy or COMRESET error
323768d33a25Syt 	 * do device reset to patch some SATA disks' issue
323868d33a25Syt 	 *
323968d33a25Syt 	 * For VT8251, sometimes need to do the device reset
324068d33a25Syt 	 */
324168d33a25Syt 	if ((port_task_file & AHCI_TFD_STS_BSY) ||
324268d33a25Syt 	    (port_task_file & AHCI_TFD_STS_DRQ)) {
324368d33a25Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "port %d keep BSY/DRQ set "
324468d33a25Syt 		    "need to do device reset", port);
32452fcbc377Syt 
324668d33a25Syt 		(void) ahci_software_reset(ahci_ctlp, ahci_portp, port);
32472fcbc377Syt 
324868d33a25Syt 		port_task_file =
324968d33a25Syt 		    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
325068d33a25Syt 		    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
325168d33a25Syt 
325268d33a25Syt 		if (port_task_file & AHCI_TFD_STS_BSY ||
325368d33a25Syt 		    port_task_file & AHCI_TFD_STS_DRQ) {
325468d33a25Syt 			cmn_err(CE_WARN, "ahci_port_reset: port %d "
325568d33a25Syt 			    "BSY/DRQ still set after device reset "
325668d33a25Syt 			    "port_task_file = 0x%x",
325768d33a25Syt 			    port, port_task_file);
325868d33a25Syt 			ahci_portp->ahciport_port_state |= SATA_PSTATE_FAILED;
325968d33a25Syt 			rval = AHCI_FAILURE;
32602fcbc377Syt 		}
32612fcbc377Syt 	}
32622fcbc377Syt 
326368d33a25Syt 	goto out;
32642fcbc377Syt }
32652fcbc377Syt 
32662fcbc377Syt /*
32672fcbc377Syt  * AHCI HBA reset ...; the entire HBA is reset, and all ports are disabled.
32682fcbc377Syt  * This is the most intrusive.
32692fcbc377Syt  *
327068d33a25Syt  * When an HBA reset occurs, Phy communication will be re-established with
327168d33a25Syt  * the device through a COMRESET followed by the normal out-of-band
327268d33a25Syt  * communication sequence defined in Serial ATA. AT the end of reset, the
327368d33a25Syt  * device, if working properly, will send a D2H Register FIS, which contains
327468d33a25Syt  * the device signature. When the HBA receives this FIS, it updates PxTFD.STS
327568d33a25Syt  * and PxTFD.ERR register fields, and updates the PxSIG register with the
327668d33a25Syt  * signature.
32772fcbc377Syt  *
32782fcbc377Syt  * Remember to set GHC.AE to 1 before calling ahci_hba_reset.
32792fcbc377Syt  */
32802fcbc377Syt static int
32812fcbc377Syt ahci_hba_reset(ahci_ctl_t *ahci_ctlp)
32822fcbc377Syt {
32832fcbc377Syt 	ahci_port_t *ahci_portp;
32842fcbc377Syt 	uint32_t ghc_control;
32852fcbc377Syt 	uint8_t port;
32862fcbc377Syt 	int loop_count;
32872fcbc377Syt 	int rval = AHCI_SUCCESS;
32882fcbc377Syt 
32892fcbc377Syt 	AHCIDBG0(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting");
32902fcbc377Syt 
329168d33a25Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
329268d33a25Syt 
32932fcbc377Syt 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
32942fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
32952fcbc377Syt 
32962fcbc377Syt 	/* Setting GHC.HR to 1, remember GHC.AE is already set to 1 before */
32972fcbc377Syt 	ghc_control |= AHCI_HBA_GHC_HR;
32982fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
32992fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
33002fcbc377Syt 
33012fcbc377Syt 	/*
33022fcbc377Syt 	 * Wait until HBA Reset complete or timeout
33032fcbc377Syt 	 */
33042fcbc377Syt 	loop_count = 0;
33052fcbc377Syt 	do {
33062fcbc377Syt 		ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
33072fcbc377Syt 		    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
33082fcbc377Syt 
33092fcbc377Syt 		if (loop_count++ > AHCI_POLLRATE_HBA_RESET) {
33102fcbc377Syt 			AHCIDBG1(AHCIDBG_INIT, ahci_ctlp,
33112fcbc377Syt 			    "ahci hba reset is timing out, "
33122fcbc377Syt 			    "ghc_control = 0x%x", ghc_control);
33132fcbc377Syt 			/* We are effectively timing out after 1 sec. */
33142fcbc377Syt 			break;
33152fcbc377Syt 		}
33162fcbc377Syt 
33172fcbc377Syt 		/* Wait for 10 millisec */
33182fcbc377Syt #ifndef __lock_lint
33192fcbc377Syt 		delay(AHCI_10MS_TICKS);
33202fcbc377Syt #endif /* __lock_lint */
33212fcbc377Syt 
33222fcbc377Syt 	} while (ghc_control & AHCI_HBA_GHC_HR);
33232fcbc377Syt 
33242fcbc377Syt 	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
33252fcbc377Syt 	    "ahci_hba_reset: 1st loop count: %d, "
33262fcbc377Syt 	    "ghc_control = 0x%x", loop_count, ghc_control);
33272fcbc377Syt 
33282fcbc377Syt 	if (ghc_control & AHCI_HBA_GHC_HR) {
33292fcbc377Syt 		/* The hba is not reset for some reasons */
33302fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
33312fcbc377Syt 		    "hba reset failed: HBA in a hung or locked state");
333268d33a25Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
33332fcbc377Syt 		return (AHCI_FAILURE);
33342fcbc377Syt 	}
33352fcbc377Syt 
33362fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
33372fcbc377Syt 		/* Only check implemented ports */
33382fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
33392fcbc377Syt 			continue;
33402fcbc377Syt 		}
33412fcbc377Syt 
33422fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
33432fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
33442fcbc377Syt 
33452fcbc377Syt 		if (ahci_port_reset(ahci_ctlp, ahci_portp, port)
33462fcbc377Syt 		    != AHCI_SUCCESS) {
33472fcbc377Syt 			rval = AHCI_FAILURE;
33482fcbc377Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
33492fcbc377Syt 			    "ahci_hba_reset: port %d failed", port);
33502fcbc377Syt 		}
33512fcbc377Syt 
33522fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
33532fcbc377Syt 	}
33542fcbc377Syt 
33552fcbc377Syt 	/*
33562fcbc377Syt 	 * Indicate that system software is AHCI aware by setting
33572fcbc377Syt 	 * GHC.AE to 1
33582fcbc377Syt 	 */
33592fcbc377Syt 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
33602fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
33612fcbc377Syt 
33622fcbc377Syt 	ghc_control |= AHCI_HBA_GHC_AE;
33632fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
33642fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
33652fcbc377Syt 
336668d33a25Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
336768d33a25Syt 
33682fcbc377Syt 	return (rval);
33692fcbc377Syt }
33702fcbc377Syt 
33712fcbc377Syt /*
33722fcbc377Syt  * This routine is only called from AHCI_ATTACH or phyrdy change
33732fcbc377Syt  * case. It first calls port reset to initialize port, probe port and probe
337468d33a25Syt  * device, then try to read PxSIG register to find the type of device
337568d33a25Syt  * attached to the port.
33762fcbc377Syt  *
33772fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
337868d33a25Syt  * is called. And the port interrupt is disabled.
33792fcbc377Syt  */
338068d33a25Syt static void
33812fcbc377Syt ahci_find_dev_signature(ahci_ctl_t *ahci_ctlp,
33822fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
33832fcbc377Syt {
33842fcbc377Syt 	uint32_t signature;
33852fcbc377Syt 
33862fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
338768d33a25Syt 	    "ahci_find_dev_signature enter: port %d", port);
33882fcbc377Syt 
338968d33a25Syt 	ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN;
33902fcbc377Syt 
33912fcbc377Syt 	/* Call port reset to check link status and get device signature */
339268d33a25Syt 	(void) ahci_port_reset(ahci_ctlp, ahci_portp, port);
339368d33a25Syt 
339468d33a25Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
339568d33a25Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
339668d33a25Syt 		    "ahci_find_dev_signature: No device is found "
339768d33a25Syt 		    "at port %d", port);
339868d33a25Syt 		return;
33992fcbc377Syt 	}
34002fcbc377Syt 
340168d33a25Syt 	/* Check the port state */
340268d33a25Syt 	if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
340368d33a25Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
340468d33a25Syt 		    "ahci_find_dev_signature: port %d state 0x%x",
340568d33a25Syt 		    port, ahci_portp->ahciport_port_state);
340668d33a25Syt 		return;
340768d33a25Syt 	}
34082fcbc377Syt 
34092fcbc377Syt 	signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
34102fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port));
34112fcbc377Syt 
34122fcbc377Syt 	AHCIDBG2(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp,
341368d33a25Syt 	    "ahci_find_dev_signature: port %d signature = 0x%x",
341468d33a25Syt 	    port, signature);
34152fcbc377Syt 
34162fcbc377Syt 	switch (signature) {
34172fcbc377Syt 
34182fcbc377Syt 	case AHCI_SIGNATURE_DISK:
34192fcbc377Syt 		ahci_portp->ahciport_device_type = SATA_DTYPE_ATADISK;
34202fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
34212fcbc377Syt 		    "Disk is found at port: %d", port);
34222fcbc377Syt 		break;
34232fcbc377Syt 
34242fcbc377Syt 	case AHCI_SIGNATURE_ATAPI:
34252fcbc377Syt 		ahci_portp->ahciport_device_type = SATA_DTYPE_ATAPICD;
34262fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
34272fcbc377Syt 		    "ATAPI device is found at port: %d", port);
34282fcbc377Syt 		break;
34292fcbc377Syt 
34302fcbc377Syt 	case AHCI_SIGNATURE_PORT_MULTIPLIER:
34312fcbc377Syt 		ahci_portp->ahciport_device_type = SATA_DTYPE_PMULT;
34322fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
34332fcbc377Syt 		    "Port Multiplier is found at port: %d", port);
34342fcbc377Syt 		break;
34352fcbc377Syt 
34362fcbc377Syt 	default:
34372fcbc377Syt 		ahci_portp->ahciport_device_type = SATA_DTYPE_UNKNOWN;
34382fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp,
34392fcbc377Syt 		    "Unknown device is found at port: %d", port);
34402fcbc377Syt 	}
34412fcbc377Syt }
34422fcbc377Syt 
34432fcbc377Syt /*
344468d33a25Syt  * Start the port - set PxCMD.ST to 1, if PxCMD.FRE is not set
344568d33a25Syt  * to 1, then set it firstly.
344668d33a25Syt  *
344768d33a25Syt  * Each port contains two major DMA engines. One DMA engine walks through
344868d33a25Syt  * the command list, and is controlled by PxCMD.ST. The second DMA engine
344968d33a25Syt  * copies received FISes into system memory, and is controlled by PxCMD.FRE.
345068d33a25Syt  *
345168d33a25Syt  * Software shall not set PxCMD.ST to '1' until it verifies that PxCMD.CR
345268d33a25Syt  * is '0' and has set PxCMD.FRE is '1'. And software shall not clear
345368d33a25Syt  * PxCMD.FRE while PxCMD.ST or PxCMD.CR is set '1'.
345468d33a25Syt  *
345568d33a25Syt  * Software shall not set PxCMD.ST to '1' unless a functional device is
345668d33a25Syt  * present on the port(as determined by PxTFD.STS.BSY = '0',
345768d33a25Syt  * PxTFD.STS.DRQ = '0', and PxSSTS.DET = 3h).
34582fcbc377Syt  *
34592fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
34602fcbc377Syt  * is called.
34612fcbc377Syt  */
34622fcbc377Syt static int
346368d33a25Syt ahci_start_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
34642fcbc377Syt {
346568d33a25Syt 	uint32_t port_cmd_status;
34662fcbc377Syt 
346768d33a25Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port);
34682fcbc377Syt 
346968d33a25Syt 	if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
347068d33a25Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
347168d33a25Syt 		    "the state for port %d is 0x%x",
347268d33a25Syt 		    port, ahci_portp->ahciport_port_state);
34732fcbc377Syt 		return (AHCI_FAILURE);
347468d33a25Syt 	}
34752fcbc377Syt 
347668d33a25Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
347768d33a25Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
347868d33a25Syt 		    "no device is attached at port %d", port);
347968d33a25Syt 		return (AHCI_FAILURE);
348068d33a25Syt 	}
34812fcbc377Syt 
348268d33a25Syt 	/* First to set PxCMD.FRE before setting PxCMD.ST. */
348368d33a25Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
348468d33a25Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
34852fcbc377Syt 
348668d33a25Syt 	if (!(port_cmd_status & AHCI_CMD_STATUS_FRE)) {
348768d33a25Syt 		port_cmd_status |= AHCI_CMD_STATUS_FRE;
34882fcbc377Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
34892fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
34902fcbc377Syt 		    port_cmd_status);
34912fcbc377Syt 	}
349268d33a25Syt 
349368d33a25Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
349468d33a25Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
349568d33a25Syt 
349668d33a25Syt 	port_cmd_status |= AHCI_CMD_STATUS_ST;
349768d33a25Syt 
349868d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
349968d33a25Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
350068d33a25Syt 	    port_cmd_status);
350168d33a25Syt 
350268d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_STARTED;
350368d33a25Syt 
350468d33a25Syt 	return (AHCI_SUCCESS);
35052fcbc377Syt }
35062fcbc377Syt 
35072fcbc377Syt /*
35082fcbc377Syt  * Allocate the ahci_port_t including Received FIS and Command List.
35092fcbc377Syt  * The argument - port is the physical port number, and not logical
35102fcbc377Syt  * port number seen by the SATA framework.
35112fcbc377Syt  *
35122fcbc377Syt  * WARNING!!! ahcictl_mutex should be acquired before the function
35132fcbc377Syt  * is called.
35142fcbc377Syt  */
35152fcbc377Syt static int
35162fcbc377Syt ahci_alloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
35172fcbc377Syt {
35182fcbc377Syt 	ahci_port_t *ahci_portp;
35192fcbc377Syt 
35202fcbc377Syt 	ahci_portp =
35212fcbc377Syt 	    (ahci_port_t *)kmem_zalloc(sizeof (ahci_port_t), KM_SLEEP);
35222fcbc377Syt 
35232fcbc377Syt #ifndef __lock_lint
35242fcbc377Syt 	ahci_ctlp->ahcictl_ports[port] = ahci_portp;
35252fcbc377Syt #endif /* __lock_lint */
35262fcbc377Syt 
35272fcbc377Syt 	ahci_portp->ahciport_port_num = port;
35282fcbc377Syt 
352968d33a25Syt 	/* Intialize the port condition variable */
353068d33a25Syt 	cv_init(&ahci_portp->ahciport_cv, NULL, CV_DRIVER, NULL);
353168d33a25Syt 
353268d33a25Syt 	/* Initialize the port mutex */
35332fcbc377Syt 	mutex_init(&ahci_portp->ahciport_mutex, NULL, MUTEX_DRIVER,
35342fcbc377Syt 	    (void *)(uintptr_t)ahci_ctlp->ahcictl_intr_pri);
353568d33a25Syt 
35362fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
35372fcbc377Syt 
35382fcbc377Syt 	/*
35392fcbc377Syt 	 * Allocate memory for received FIS structure and
35402fcbc377Syt 	 * command list for this port
35412fcbc377Syt 	 */
35422fcbc377Syt 	if (ahci_alloc_rcvd_fis(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) {
35432fcbc377Syt 		goto err_case1;
35442fcbc377Syt 	}
35452fcbc377Syt 
35462fcbc377Syt 	if (ahci_alloc_cmd_list(ahci_ctlp, ahci_portp, port) != AHCI_SUCCESS) {
35472fcbc377Syt 		goto err_case2;
35482fcbc377Syt 	}
35492fcbc377Syt 
355068d33a25Syt 	ahci_portp->ahciport_event_args =
355168d33a25Syt 	    kmem_zalloc(sizeof (ahci_event_arg_t), KM_SLEEP);
355268d33a25Syt 
355368d33a25Syt 	if (ahci_portp->ahciport_event_args == NULL)
355468d33a25Syt 		goto err_case3;
355568d33a25Syt 
35562fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
35572fcbc377Syt 
35582fcbc377Syt 	return (AHCI_SUCCESS);
35592fcbc377Syt 
356068d33a25Syt err_case3:
356168d33a25Syt 	ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
356268d33a25Syt 
35632fcbc377Syt err_case2:
35642fcbc377Syt 	ahci_dealloc_rcvd_fis(ahci_ctlp, ahci_portp);
35652fcbc377Syt 
35662fcbc377Syt err_case1:
35672fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
35682fcbc377Syt 	mutex_destroy(&ahci_portp->ahciport_mutex);
356968d33a25Syt 	cv_destroy(&ahci_portp->ahciport_cv);
35702fcbc377Syt 
35712fcbc377Syt 	kmem_free(ahci_portp, sizeof (ahci_port_t));
35722fcbc377Syt 
35732fcbc377Syt 	return (AHCI_FAILURE);
35742fcbc377Syt }
35752fcbc377Syt 
35762fcbc377Syt /*
35772fcbc377Syt  * Reverse of ahci_dealloc_port_state().
35782fcbc377Syt  *
35792fcbc377Syt  * WARNING!!! ahcictl_mutex should be acquired before the function
35802fcbc377Syt  * is called.
35812fcbc377Syt  */
35822fcbc377Syt static void
35832fcbc377Syt ahci_dealloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
35842fcbc377Syt {
35852fcbc377Syt 	ahci_port_t *ahci_portp = ahci_ctlp->ahcictl_ports[port];
35862fcbc377Syt 
35872fcbc377Syt 	ASSERT(ahci_portp != NULL);
35882fcbc377Syt 
35892fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
359068d33a25Syt 	kmem_free(ahci_portp->ahciport_event_args, sizeof (ahci_event_arg_t));
359168d33a25Syt 	ahci_portp->ahciport_event_args = NULL;
35922fcbc377Syt 	ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
35932fcbc377Syt 	ahci_dealloc_rcvd_fis(ahci_ctlp, ahci_portp);
35942fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
35952fcbc377Syt 
35962fcbc377Syt 	mutex_destroy(&ahci_portp->ahciport_mutex);
359768d33a25Syt 	cv_destroy(&ahci_portp->ahciport_cv);
35982fcbc377Syt 
35992fcbc377Syt 	kmem_free(ahci_portp, sizeof (ahci_port_t));
36002fcbc377Syt 
36012fcbc377Syt #ifndef __lock_lint
36022fcbc377Syt 	ahci_ctlp->ahcictl_ports[port] = NULL;
36032fcbc377Syt #endif /* __lock_lint */
36042fcbc377Syt }
36052fcbc377Syt 
36062fcbc377Syt /*
36072fcbc377Syt  * Allocates memory for the Received FIS Structure
36082fcbc377Syt  *
36092fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
36102fcbc377Syt  * is called.
36112fcbc377Syt  */
36122fcbc377Syt static int
36132fcbc377Syt ahci_alloc_rcvd_fis(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
36142fcbc377Syt     uint8_t port)
36152fcbc377Syt {
36162fcbc377Syt 	size_t rcvd_fis_size;
36172fcbc377Syt 	size_t ret_len;
36182fcbc377Syt 	ddi_dma_cookie_t rcvd_fis_dma_cookie;
36192fcbc377Syt 	uint_t cookie_count;
36202fcbc377Syt 	uint32_t cap_status;
36212fcbc377Syt 
36222fcbc377Syt 	rcvd_fis_size = sizeof (ahci_rcvd_fis_t);
36232fcbc377Syt 
36242fcbc377Syt 	/* Check whether the HBA can access 64-bit data structures */
36252fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
36262fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
36272fcbc377Syt 
36282fcbc377Syt 	ahci_ctlp->ahcictl_rcvd_fis_dma_attr = rcvd_fis_dma_attr;
36292fcbc377Syt 
36302fcbc377Syt 	/*
36312fcbc377Syt 	 * If 64-bit addressing is not supported,
36322fcbc377Syt 	 * change dma_attr_addr_hi of ahcictl_rcvd_fis_dma_attr
36332fcbc377Syt 	 */
36342fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
36352fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
36362fcbc377Syt 		    "hba does not support 64-bit addressing");
36372fcbc377Syt 		ahci_ctlp->ahcictl_rcvd_fis_dma_attr.dma_attr_addr_hi =
36382fcbc377Syt 		    0xffffffffull;
36392fcbc377Syt 	}
36402fcbc377Syt 
36412fcbc377Syt 	/* allocate rcvd FIS dma handle. */
36422fcbc377Syt 	if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
36432fcbc377Syt 	    &ahci_ctlp->ahcictl_rcvd_fis_dma_attr,
36442fcbc377Syt 	    DDI_DMA_SLEEP,
36452fcbc377Syt 	    NULL,
36462fcbc377Syt 	    &ahci_portp->ahciport_rcvd_fis_dma_handle) !=
36472fcbc377Syt 	    DDI_SUCCESS) {
36482fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
36492fcbc377Syt 		    "rcvd FIS dma handle alloc failed");
36502fcbc377Syt 
36512fcbc377Syt 		return (AHCI_FAILURE);
36522fcbc377Syt 	}
36532fcbc377Syt 
36542fcbc377Syt 	if (ddi_dma_mem_alloc(ahci_portp->ahciport_rcvd_fis_dma_handle,
36552fcbc377Syt 	    rcvd_fis_size,
36562fcbc377Syt 	    &accattr,
36572fcbc377Syt 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
36582fcbc377Syt 	    DDI_DMA_SLEEP,
36592fcbc377Syt 	    NULL,
36602fcbc377Syt 	    (caddr_t *)&ahci_portp->ahciport_rcvd_fis,
36612fcbc377Syt 	    &ret_len,
36622fcbc377Syt 	    &ahci_portp->ahciport_rcvd_fis_acc_handle) != NULL) {
36632fcbc377Syt 
36642fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
36652fcbc377Syt 		    "rcvd FIS dma mem alloc fail");
36662fcbc377Syt 		/* error.. free the dma handle. */
36672fcbc377Syt 		ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
36682fcbc377Syt 		return (AHCI_FAILURE);
36692fcbc377Syt 	}
36702fcbc377Syt 
36712fcbc377Syt 	if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle,
36722fcbc377Syt 	    NULL,
36732fcbc377Syt 	    (caddr_t)ahci_portp->ahciport_rcvd_fis,
36742fcbc377Syt 	    rcvd_fis_size,
36752fcbc377Syt 	    DDI_DMA_CONSISTENT,
36762fcbc377Syt 	    DDI_DMA_SLEEP,
36772fcbc377Syt 	    NULL,
36782fcbc377Syt 	    &rcvd_fis_dma_cookie,
36792fcbc377Syt 	    &cookie_count) !=  DDI_DMA_MAPPED) {
36802fcbc377Syt 
36812fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
36822fcbc377Syt 		    "rcvd FIS dma handle bind fail");
36832fcbc377Syt 		/*  error.. free the dma handle & free the memory. */
36842fcbc377Syt 		ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
36852fcbc377Syt 		ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
36862fcbc377Syt 		return (AHCI_FAILURE);
36872fcbc377Syt 	}
36882fcbc377Syt 
36892fcbc377Syt 	bzero((void *)ahci_portp->ahciport_rcvd_fis, rcvd_fis_size);
36902fcbc377Syt 
36912fcbc377Syt 	/* Config Port Received FIS Base Address */
36922fcbc377Syt 	ddi_put64(ahci_ctlp->ahcictl_ahci_acc_handle,
36932fcbc377Syt 	    (uint64_t *)AHCI_PORT_PxFB(ahci_ctlp, port),
36942fcbc377Syt 	    rcvd_fis_dma_cookie.dmac_laddress);
36952fcbc377Syt 
36962fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
36972fcbc377Syt 	    rcvd_fis_dma_cookie.dmac_laddress);
36982fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
36992fcbc377Syt 	    rcvd_fis_dma_cookie.dmac_address);
37002fcbc377Syt 
37012fcbc377Syt 	return (AHCI_SUCCESS);
37022fcbc377Syt }
37032fcbc377Syt 
37042fcbc377Syt /*
37052fcbc377Syt  * Deallocates the Received FIS Structure
37062fcbc377Syt  *
37072fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
37082fcbc377Syt  * is called.
37092fcbc377Syt  */
37102fcbc377Syt static void
37112fcbc377Syt ahci_dealloc_rcvd_fis(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
37122fcbc377Syt {
37132fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
37142fcbc377Syt 	    "ahci_dealloc_rcvd_fis: port %d enter",
37152fcbc377Syt 	    ahci_portp->ahciport_port_num);
37162fcbc377Syt 
37172fcbc377Syt 	/* Unbind the cmd list dma handle first. */
37182fcbc377Syt 	(void) ddi_dma_unbind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle);
37192fcbc377Syt 
37202fcbc377Syt 	/* Then free the underlying memory. */
37212fcbc377Syt 	ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
37222fcbc377Syt 
37232fcbc377Syt 	/* Now free the handle itself. */
37242fcbc377Syt 	ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
37252fcbc377Syt }
37262fcbc377Syt 
37272fcbc377Syt /*
37282fcbc377Syt  * Allocates memory for the Command List, which contains up to 32 entries.
37292fcbc377Syt  * Each entry contains a command header, which is a 32-byte structure that
37302fcbc377Syt  * includes the pointer to the command table.
37312fcbc377Syt  *
37322fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
37332fcbc377Syt  * is called.
37342fcbc377Syt  */
37352fcbc377Syt static int
37362fcbc377Syt ahci_alloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
37372fcbc377Syt     uint8_t port)
37382fcbc377Syt {
37392fcbc377Syt 	size_t cmd_list_size;
37402fcbc377Syt 	size_t ret_len;
37412fcbc377Syt 	ddi_dma_cookie_t cmd_list_dma_cookie;
37422fcbc377Syt 	uint_t cookie_count;
37432fcbc377Syt 	uint32_t cap_status;
37442fcbc377Syt 
37452fcbc377Syt 	cmd_list_size =
37462fcbc377Syt 	    ahci_ctlp->ahcictl_num_cmd_slots * sizeof (ahci_cmd_header_t);
37472fcbc377Syt 
37482fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
37492fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
37502fcbc377Syt 
37512fcbc377Syt 	ahci_ctlp->ahcictl_cmd_list_dma_attr = cmd_list_dma_attr;
37522fcbc377Syt 
37532fcbc377Syt 	/*
37542fcbc377Syt 	 * If 64-bit addressing is not supported,
37552fcbc377Syt 	 * change dma_attr_addr_hi of ahcictl_cmd_list_dma_attr
37562fcbc377Syt 	 */
37572fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
37582fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
37592fcbc377Syt 		    "hba does not support 64-bit addressing");
37602fcbc377Syt 		ahci_ctlp->ahcictl_cmd_list_dma_attr.dma_attr_addr_hi =
37612fcbc377Syt 		    0xffffffffull;
37622fcbc377Syt 	}
37632fcbc377Syt 
37642fcbc377Syt 	/* allocate cmd list dma handle. */
37652fcbc377Syt 	if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
37662fcbc377Syt 	    &ahci_ctlp->ahcictl_cmd_list_dma_attr,
37672fcbc377Syt 	    DDI_DMA_SLEEP,
37682fcbc377Syt 	    NULL,
37692fcbc377Syt 	    &ahci_portp->ahciport_cmd_list_dma_handle) != DDI_SUCCESS) {
37702fcbc377Syt 
37712fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
37722fcbc377Syt 		    "cmd list dma handle alloc failed");
37732fcbc377Syt 		return (AHCI_FAILURE);
37742fcbc377Syt 	}
37752fcbc377Syt 
37762fcbc377Syt 	if (ddi_dma_mem_alloc(ahci_portp->ahciport_cmd_list_dma_handle,
37772fcbc377Syt 	    cmd_list_size,
37782fcbc377Syt 	    &accattr,
37792fcbc377Syt 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
37802fcbc377Syt 	    DDI_DMA_SLEEP,
37812fcbc377Syt 	    NULL,
37822fcbc377Syt 	    (caddr_t *)&ahci_portp->ahciport_cmd_list,
37832fcbc377Syt 	    &ret_len,
37842fcbc377Syt 	    &ahci_portp->ahciport_cmd_list_acc_handle) != NULL) {
37852fcbc377Syt 
37862fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
37872fcbc377Syt 		    "cmd list dma mem alloc fail");
37882fcbc377Syt 		/* error.. free the dma handle. */
37892fcbc377Syt 		ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
37902fcbc377Syt 		return (AHCI_FAILURE);
37912fcbc377Syt 	}
37922fcbc377Syt 
37932fcbc377Syt 	if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_cmd_list_dma_handle,
37942fcbc377Syt 	    NULL,
37952fcbc377Syt 	    (caddr_t)ahci_portp->ahciport_cmd_list,
37962fcbc377Syt 	    cmd_list_size,
37972fcbc377Syt 	    DDI_DMA_CONSISTENT,
37982fcbc377Syt 	    DDI_DMA_SLEEP,
37992fcbc377Syt 	    NULL,
38002fcbc377Syt 	    &cmd_list_dma_cookie,
38012fcbc377Syt 	    &cookie_count) !=  DDI_DMA_MAPPED) {
38022fcbc377Syt 
38032fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
38042fcbc377Syt 		    "cmd list dma handle bind fail");
38052fcbc377Syt 		/*  error.. free the dma handle & free the memory. */
38062fcbc377Syt 		ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
38072fcbc377Syt 		ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
38082fcbc377Syt 		return (AHCI_FAILURE);
38092fcbc377Syt 	}
38102fcbc377Syt 
38112fcbc377Syt 	bzero((void *)ahci_portp->ahciport_cmd_list, cmd_list_size);
38122fcbc377Syt 
38132fcbc377Syt 	/* Config Port Command List Base Address */
38142fcbc377Syt 	ddi_put64(ahci_ctlp->ahcictl_ahci_acc_handle,
38152fcbc377Syt 	    (uint64_t *)AHCI_PORT_PxCLB(ahci_ctlp, port),
38162fcbc377Syt 	    cmd_list_dma_cookie.dmac_laddress);
38172fcbc377Syt 
38182fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
38192fcbc377Syt 	    cmd_list_dma_cookie.dmac_laddress);
38202fcbc377Syt 
38212fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
38222fcbc377Syt 	    cmd_list_dma_cookie.dmac_address);
38232fcbc377Syt 
38242fcbc377Syt 	if (ahci_alloc_cmd_tables(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
38252fcbc377Syt 		ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
38262fcbc377Syt 		return (AHCI_FAILURE);
38272fcbc377Syt 	}
38282fcbc377Syt 
38292fcbc377Syt 	return (AHCI_SUCCESS);
38302fcbc377Syt }
38312fcbc377Syt 
38322fcbc377Syt /*
38332fcbc377Syt  * Deallocates the Command List
38342fcbc377Syt  *
38352fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
38362fcbc377Syt  * is called.
38372fcbc377Syt  */
38382fcbc377Syt static void
38392fcbc377Syt ahci_dealloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
38402fcbc377Syt {
38412fcbc377Syt 	/* First dealloc command table */
38422fcbc377Syt 	ahci_dealloc_cmd_tables(ahci_ctlp, ahci_portp);
38432fcbc377Syt 
38442fcbc377Syt 	/* Unbind the cmd list dma handle first. */
38452fcbc377Syt 	(void) ddi_dma_unbind_handle(ahci_portp->ahciport_cmd_list_dma_handle);
38462fcbc377Syt 
38472fcbc377Syt 	/* Then free the underlying memory. */
38482fcbc377Syt 	ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
38492fcbc377Syt 
38502fcbc377Syt 	/* Now free the handle itself. */
38512fcbc377Syt 	ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
38522fcbc377Syt }
38532fcbc377Syt 
38542fcbc377Syt /*
38552fcbc377Syt  * Allocates memory for all Command Tables, which contains Command FIS,
38562fcbc377Syt  * ATAPI Command and Physical Region Descriptor Table.
38572fcbc377Syt  *
38582fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
38592fcbc377Syt  * is called.
38602fcbc377Syt  */
38612fcbc377Syt static int
38622fcbc377Syt ahci_alloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
38632fcbc377Syt {
38642fcbc377Syt 	size_t ret_len;
38652fcbc377Syt 	ddi_dma_cookie_t cmd_table_dma_cookie;
38662fcbc377Syt 	uint_t cookie_count;
38672fcbc377Syt 	uint32_t cap_status;
38682fcbc377Syt 	int slot;
38692fcbc377Syt 
38702fcbc377Syt 	AHCIDBG1(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
38712fcbc377Syt 	    "ahci_alloc_cmd_tables: port %d enter",
38722fcbc377Syt 	    ahci_portp->ahciport_port_num);
38732fcbc377Syt 
38742fcbc377Syt 	/* Check whether the HBA can access 64-bit data structures */
38752fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
38762fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
38772fcbc377Syt 
38782fcbc377Syt 	ahci_ctlp->ahcictl_cmd_table_dma_attr = cmd_table_dma_attr;
38792fcbc377Syt 
38802fcbc377Syt 	/*
38812fcbc377Syt 	 * If 64-bit addressing is not supported,
38822fcbc377Syt 	 * change dma_attr_addr_hi of ahcictl_cmd_table_dma_attr
38832fcbc377Syt 	 */
38842fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_S64A)) {
38852fcbc377Syt 		AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
38862fcbc377Syt 		    "hba does not support 64-bit addressing");
38872fcbc377Syt 		ahci_ctlp->ahcictl_cmd_table_dma_attr.dma_attr_addr_hi =
38882fcbc377Syt 		    0xffffffffull;
38892fcbc377Syt 	}
38902fcbc377Syt 
38912fcbc377Syt 	for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
38922fcbc377Syt 		/* Allocate cmd table dma handle. */
38932fcbc377Syt 		if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
38942fcbc377Syt 		    &ahci_ctlp->ahcictl_cmd_table_dma_attr,
38952fcbc377Syt 		    DDI_DMA_SLEEP,
38962fcbc377Syt 		    NULL,
38972fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]) !=
38982fcbc377Syt 		    DDI_SUCCESS) {
38992fcbc377Syt 
39002fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
39012fcbc377Syt 			    "cmd table dma handle alloc failed");
39022fcbc377Syt 
39032fcbc377Syt 			goto err_out;
39042fcbc377Syt 		}
39052fcbc377Syt 
39062fcbc377Syt 		if (ddi_dma_mem_alloc(
39072fcbc377Syt 		    ahci_portp->ahciport_cmd_tables_dma_handle[slot],
39082fcbc377Syt 		    ahci_cmd_table_size,
39092fcbc377Syt 		    &accattr,
39102fcbc377Syt 		    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
39112fcbc377Syt 		    DDI_DMA_SLEEP,
39122fcbc377Syt 		    NULL,
39132fcbc377Syt 		    (caddr_t *)&ahci_portp->ahciport_cmd_tables[slot],
39142fcbc377Syt 		    &ret_len,
39152fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]) !=
39162fcbc377Syt 		    NULL) {
39172fcbc377Syt 
39182fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
39192fcbc377Syt 			    "cmd table dma mem alloc fail");
39202fcbc377Syt 
39212fcbc377Syt 			/* error.. free the dma handle. */
39222fcbc377Syt 			ddi_dma_free_handle(
39232fcbc377Syt 			    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
39242fcbc377Syt 			goto err_out;
39252fcbc377Syt 		}
39262fcbc377Syt 
39272fcbc377Syt 		if (ddi_dma_addr_bind_handle(
39282fcbc377Syt 		    ahci_portp->ahciport_cmd_tables_dma_handle[slot],
39292fcbc377Syt 		    NULL,
39302fcbc377Syt 		    (caddr_t)ahci_portp->ahciport_cmd_tables[slot],
39312fcbc377Syt 		    ahci_cmd_table_size,
39322fcbc377Syt 		    DDI_DMA_CONSISTENT,
39332fcbc377Syt 		    DDI_DMA_SLEEP,
39342fcbc377Syt 		    NULL,
39352fcbc377Syt 		    &cmd_table_dma_cookie,
39362fcbc377Syt 		    &cookie_count) !=  DDI_DMA_MAPPED) {
39372fcbc377Syt 
39382fcbc377Syt 			AHCIDBG0(AHCIDBG_INIT, ahci_ctlp,
39392fcbc377Syt 			    "cmd table dma handle bind fail");
39402fcbc377Syt 			/*  error.. free the dma handle & free the memory. */
39412fcbc377Syt 			ddi_dma_mem_free(
39422fcbc377Syt 			    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
39432fcbc377Syt 			ddi_dma_free_handle(
39442fcbc377Syt 			    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
39452fcbc377Syt 			goto err_out;
39462fcbc377Syt 		}
39472fcbc377Syt 
39482fcbc377Syt 		bzero((void *)ahci_portp->ahciport_cmd_tables[slot],
39492fcbc377Syt 		    ahci_cmd_table_size);
39502fcbc377Syt 
39512fcbc377Syt 		/* Config Port Command Table Base Address */
39522fcbc377Syt 		SET_COMMAND_TABLE_BASE_ADDR(
39532fcbc377Syt 		    (&ahci_portp->ahciport_cmd_list[slot]),
39542fcbc377Syt 		    cmd_table_dma_cookie.dmac_laddress & 0xffffffffull);
39552fcbc377Syt 
39562fcbc377Syt #ifndef __lock_lint
39572fcbc377Syt 		SET_COMMAND_TABLE_BASE_ADDR_UPPER(
39582fcbc377Syt 		    (&ahci_portp->ahciport_cmd_list[slot]),
39592fcbc377Syt 		    cmd_table_dma_cookie.dmac_laddress >> 32);
39602fcbc377Syt #endif /* __lock_lint */
39612fcbc377Syt 	}
39622fcbc377Syt 
39632fcbc377Syt 	return (AHCI_SUCCESS);
39642fcbc377Syt err_out:
39652fcbc377Syt 
39662fcbc377Syt 	for (slot--; slot >= 0; slot--) {
39672fcbc377Syt 		/* Unbind the cmd table dma handle first */
39682fcbc377Syt 		(void) ddi_dma_unbind_handle(
39692fcbc377Syt 		    ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
39702fcbc377Syt 
39712fcbc377Syt 		/* Then free the underlying memory */
39722fcbc377Syt 		ddi_dma_mem_free(
39732fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
39742fcbc377Syt 
39752fcbc377Syt 		/* Now free the handle itself */
39762fcbc377Syt 		ddi_dma_free_handle(
39772fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
39782fcbc377Syt 	}
39792fcbc377Syt 
39802fcbc377Syt 	return (AHCI_FAILURE);
39812fcbc377Syt }
39822fcbc377Syt 
39832fcbc377Syt /*
39842fcbc377Syt  * Deallocates memory for all Command Tables.
39852fcbc377Syt  *
39862fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
39872fcbc377Syt  * is called.
39882fcbc377Syt  */
39892fcbc377Syt static void
39902fcbc377Syt ahci_dealloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
39912fcbc377Syt {
39922fcbc377Syt 	int slot;
39932fcbc377Syt 
39942fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
39952fcbc377Syt 	    "ahci_dealloc_cmd_tables: %d enter",
39962fcbc377Syt 	    ahci_portp->ahciport_port_num);
39972fcbc377Syt 
39982fcbc377Syt 	for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
39992fcbc377Syt 		/* Unbind the cmd table dma handle first. */
40002fcbc377Syt 		(void) ddi_dma_unbind_handle(
40012fcbc377Syt 		    ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
40022fcbc377Syt 
40032fcbc377Syt 		/* Then free the underlying memory. */
40042fcbc377Syt 		ddi_dma_mem_free(
40052fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
40062fcbc377Syt 
40072fcbc377Syt 		/* Now free the handle itself. */
40082fcbc377Syt 		ddi_dma_free_handle(
40092fcbc377Syt 		    &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
40102fcbc377Syt 	}
40112fcbc377Syt }
40122fcbc377Syt 
40132fcbc377Syt /*
40142fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
40152fcbc377Syt  * is called.
40162fcbc377Syt  */
40172fcbc377Syt static void
40182fcbc377Syt ahci_update_sata_registers(ahci_ctl_t *ahci_ctlp, uint8_t port,
40192fcbc377Syt     sata_device_t *sd)
40202fcbc377Syt {
40212fcbc377Syt 	sd->satadev_scr.sstatus =
40222fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
40232fcbc377Syt 	    (uint32_t *)(AHCI_PORT_PxSSTS(ahci_ctlp, port)));
40242fcbc377Syt 	sd->satadev_scr.serror =
40252fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
40262fcbc377Syt 	    (uint32_t *)(AHCI_PORT_PxSERR(ahci_ctlp, port)));
40272fcbc377Syt 	sd->satadev_scr.scontrol =
40282fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
40292fcbc377Syt 	    (uint32_t *)(AHCI_PORT_PxSCTL(ahci_ctlp, port)));
40302fcbc377Syt 	sd->satadev_scr.sactive =
40312fcbc377Syt 	    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
40322fcbc377Syt 	    (uint32_t *)(AHCI_PORT_PxSACT(ahci_ctlp, port)));
40332fcbc377Syt }
40342fcbc377Syt 
40352fcbc377Syt /*
403668d33a25Syt  * For poll mode, ahci_port_intr will be called to emulate the interrupt
40372fcbc377Syt  */
40382fcbc377Syt static void
403982263d52Syt ahci_port_intr(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
40402fcbc377Syt {
404168d33a25Syt 	uint32_t port_intr_status;
404268d33a25Syt 	uint32_t port_intr_enable;
404368d33a25Syt 
404468d33a25Syt 	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
404568d33a25Syt 	    "ahci_port_intr enter: port %d", port);
404668d33a25Syt 
404768d33a25Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
404868d33a25Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_POLLING) {
404968d33a25Syt 		/* For SATA_OPMODE_POLLING commands */
405068d33a25Syt 		port_intr_enable =
405168d33a25Syt 		    (AHCI_INTR_STATUS_DHRS |
405268d33a25Syt 		    AHCI_INTR_STATUS_PSS |
405368d33a25Syt 		    AHCI_INTR_STATUS_SDBS |
405468d33a25Syt 		    AHCI_INTR_STATUS_UFS |
405568d33a25Syt 		    AHCI_INTR_STATUS_PCS |
405668d33a25Syt 		    AHCI_INTR_STATUS_PRCS |
405768d33a25Syt 		    AHCI_INTR_STATUS_OFS |
405868d33a25Syt 		    AHCI_INTR_STATUS_INFS |
405968d33a25Syt 		    AHCI_INTR_STATUS_IFS |
406068d33a25Syt 		    AHCI_INTR_STATUS_HBDS |
406168d33a25Syt 		    AHCI_INTR_STATUS_HBFS |
406268d33a25Syt 		    AHCI_INTR_STATUS_TFES);
406368d33a25Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
406468d33a25Syt 		goto next;
406568d33a25Syt 	}
406668d33a25Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
406768d33a25Syt 
406868d33a25Syt 	/*
406968d33a25Syt 	 * port_intr_enable indicates that the corresponding interrrupt
407068d33a25Syt 	 * reporting is enabled.
407168d33a25Syt 	 */
407268d33a25Syt 	port_intr_enable = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
407368d33a25Syt 	    (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port));
407468d33a25Syt next:
407568d33a25Syt 	/*
407668d33a25Syt 	 * port_intr_stats indicates that the corresponding interrupt
407768d33a25Syt 	 * condition is active.
407868d33a25Syt 	 */
407968d33a25Syt 	port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
408068d33a25Syt 	    (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port));
408168d33a25Syt 
408282263d52Syt 	AHCIDBG3(AHCIDBG_INTR, ahci_ctlp,
408368d33a25Syt 	    "ahci_port_intr: port %d, port_intr_status = 0x%x, "
408482263d52Syt 	    "port_intr_enable = 0x%x",
408582263d52Syt 	    port, port_intr_status, port_intr_enable);
408668d33a25Syt 
408768d33a25Syt 	port_intr_status &= port_intr_enable;
408868d33a25Syt 
408968d33a25Syt 	/* First clear the port interrupts status */
409068d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
409168d33a25Syt 	    (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port),
409268d33a25Syt 	    port_intr_status);
409368d33a25Syt 
409482263d52Syt 	/* Check the completed non-queued commands */
409568d33a25Syt 	if (port_intr_status & (AHCI_INTR_STATUS_DHRS |
409668d33a25Syt 	    AHCI_INTR_STATUS_PSS)) {
409768d33a25Syt 		(void) ahci_intr_cmd_cmplt(ahci_ctlp,
409882263d52Syt 		    ahci_portp, port, port_intr_status);
409968d33a25Syt 	}
410068d33a25Syt 
410182263d52Syt 	/* Check the completed queued commands */
410268d33a25Syt 	if (port_intr_status & AHCI_INTR_STATUS_SDBS) {
410368d33a25Syt 		(void) ahci_intr_set_device_bits(ahci_ctlp,
410468d33a25Syt 		    ahci_portp, port);
410568d33a25Syt 	}
410668d33a25Syt 
410768d33a25Syt 	/* Check the port connect change status interrupt bit */
410868d33a25Syt 	if (port_intr_status & AHCI_INTR_STATUS_PCS) {
410968d33a25Syt 		(void) ahci_intr_port_connect_change(ahci_ctlp,
411068d33a25Syt 		    ahci_portp, port);
411168d33a25Syt 	}
411268d33a25Syt 
411368d33a25Syt 	/* Check the device mechanical presence status interrupt bit */
411468d33a25Syt 	if (port_intr_status & AHCI_INTR_STATUS_DMPS) {
411568d33a25Syt 		(void) ahci_intr_device_mechanical_presence_status(
411668d33a25Syt 		    ahci_ctlp, ahci_portp, port);
411768d33a25Syt 	}
411868d33a25Syt 
411968d33a25Syt 	/* Check the PhyRdy change status interrupt bit */
412068d33a25Syt 	if (port_intr_status & AHCI_INTR_STATUS_PRCS) {
412168d33a25Syt 		(void) ahci_intr_phyrdy_change(ahci_ctlp, ahci_portp,
412268d33a25Syt 		    port);
41232fcbc377Syt 	}
412468d33a25Syt 
412568d33a25Syt 	/*
412668d33a25Syt 	 * Check the non-fatal error interrupt bits, there are three
412768d33a25Syt 	 * kinds of non-fatal errors at the time being:
412868d33a25Syt 	 *
412968d33a25Syt 	 *    PxIS.UFS - Unknown FIS Error
413068d33a25Syt 	 *    PxIS.OFS - Overflow Error
413168d33a25Syt 	 *    PxIS.INFS - Interface Non-Fatal Error
413268d33a25Syt 	 *
413368d33a25Syt 	 * For these non-fatal errors, the HBA can continue to operate,
413468d33a25Syt 	 * so the driver just log the error messages.
413568d33a25Syt 	 */
413668d33a25Syt 	if (port_intr_status & (AHCI_INTR_STATUS_UFS |
413768d33a25Syt 	    AHCI_INTR_STATUS_OFS |
413868d33a25Syt 	    AHCI_INTR_STATUS_INFS)) {
413968d33a25Syt 		(void) ahci_intr_non_fatal_error(ahci_ctlp, ahci_portp,
414068d33a25Syt 		    port, port_intr_status);
414168d33a25Syt 	}
414268d33a25Syt 
414368d33a25Syt 	/*
414468d33a25Syt 	 * Check the fatal error interrupt bits, there are four kinds
414568d33a25Syt 	 * of fatal errors for AHCI controllers:
414668d33a25Syt 	 *
414768d33a25Syt 	 *    PxIS.HBFS - Host Bus Fatal Error
414868d33a25Syt 	 *    PxIS.HBDS - Host Bus Data Error
414968d33a25Syt 	 *    PxIS.IFS - Interface Fatal Error
415068d33a25Syt 	 *    PxIS.TFES - Task File Error
415168d33a25Syt 	 *
415268d33a25Syt 	 * The fatal error means the HBA can not recover from it by
415368d33a25Syt 	 * itself, and it will try to abort the transfer, and the software
415468d33a25Syt 	 * must intervene to restart the port.
415568d33a25Syt 	 */
415668d33a25Syt 	if (port_intr_status & (AHCI_INTR_STATUS_IFS |
415768d33a25Syt 	    AHCI_INTR_STATUS_HBDS |
415868d33a25Syt 	    AHCI_INTR_STATUS_HBFS |
415968d33a25Syt 	    AHCI_INTR_STATUS_TFES))
416068d33a25Syt 		(void) ahci_intr_fatal_error(ahci_ctlp, ahci_portp,
416182263d52Syt 		    port, port_intr_status);
416268d33a25Syt 
416368d33a25Syt 	/* Check the cold port detect interrupt bit */
416468d33a25Syt 	if (port_intr_status & AHCI_INTR_STATUS_CPDS) {
416568d33a25Syt 		(void) ahci_intr_cold_port_detect(ahci_ctlp, ahci_portp, port);
416668d33a25Syt 	}
416768d33a25Syt 
416868d33a25Syt 	/* Second clear the corresponding bit in IS.IPS */
416968d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
417068d33a25Syt 	    (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp), (0x1 << port));
41712fcbc377Syt }
41722fcbc377Syt 
41732fcbc377Syt /*
41742fcbc377Syt  * Interrupt service handler
41752fcbc377Syt  */
41762fcbc377Syt /* ARGSUSED1 */
41772fcbc377Syt static uint_t
41782fcbc377Syt ahci_intr(caddr_t arg1, caddr_t arg2)
41792fcbc377Syt {
41802fcbc377Syt 	ahci_ctl_t *ahci_ctlp = (ahci_ctl_t *)arg1;
41812fcbc377Syt 	ahci_port_t *ahci_portp;
418268d33a25Syt 	int32_t global_intr_status;
41832fcbc377Syt 	uint8_t port;
41842fcbc377Syt 
41852fcbc377Syt 	/*
41862fcbc377Syt 	 * global_intr_status indicates that the corresponding port has
41872fcbc377Syt 	 * an interrupt pending.
41882fcbc377Syt 	 */
41892fcbc377Syt 	global_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
41902fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp));
41912fcbc377Syt 
41922fcbc377Syt 	if (!(global_intr_status & ahci_ctlp->ahcictl_ports_implemented)) {
41932fcbc377Syt 		/* The interrupt is not ours */
41942fcbc377Syt 		return (DDI_INTR_UNCLAIMED);
41952fcbc377Syt 	}
41962fcbc377Syt 
41972fcbc377Syt 	/* Loop for all the ports */
41982fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
41992fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
42002fcbc377Syt 			continue;
42012fcbc377Syt 		}
42022fcbc377Syt 		if (!((0x1 << port) & global_intr_status)) {
42032fcbc377Syt 			continue;
42042fcbc377Syt 		}
42052fcbc377Syt 
42062fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
42072fcbc377Syt 
420868d33a25Syt 		/* Call ahci_port_intr */
420982263d52Syt 		ahci_port_intr(ahci_ctlp, ahci_portp, port);
42102fcbc377Syt 	}
42112fcbc377Syt 
42122fcbc377Syt 	return (DDI_INTR_CLAIMED);
42132fcbc377Syt }
42142fcbc377Syt 
42152fcbc377Syt /*
421668d33a25Syt  * For non-queued commands, when the corresponding bit in the PxCI register
421768d33a25Syt  * is cleared, it means the command is completed successfully. And according
421868d33a25Syt  * to the HBA state machine, there are three conditions which possibly will
421968d33a25Syt  * try to clear the PxCI register bit.
422068d33a25Syt  *	1. Receive one D2H Register FIS which is with 'I' bit set
422168d33a25Syt  *	2. Update PIO Setup FIS
422268d33a25Syt  *	3. Transmit a command and receive R_OK if CTBA.C is set (software reset)
422368d33a25Syt  *
422482263d52Syt  * Process completed non-queued commands when the interrupt status bit -
422582263d52Syt  * AHCI_INTR_STATUS_DHRS or AHCI_INTR_STATUS_PSS is set.
42262fcbc377Syt  *
422768d33a25Syt  * AHCI_INTR_STATUS_DHRS means a D2H Register FIS has been received
422868d33a25Syt  * with the 'I' bit set. And the following commands will send thus
422968d33a25Syt  * FIS with 'I' bit set upon the successful completion:
42302fcbc377Syt  * 	1. Non-data commands
42312fcbc377Syt  * 	2. DMA data-in command
42322fcbc377Syt  * 	3. DMA data-out command
42332fcbc377Syt  * 	4. PIO data-out command
423468d33a25Syt  *	5. PACKET non-data commands
423568d33a25Syt  *	6. PACKET PIO data-in command
423668d33a25Syt  *	7. PACKET PIO data-out command
423768d33a25Syt  *	8. PACKET DMA data-in command
423868d33a25Syt  *	9. PACKET DMA data-out command
423968d33a25Syt  *
424068d33a25Syt  * AHCI_INTR_STATUS_PSS means a PIO Setup FIS has been received
424168d33a25Syt  * with the 'I' bit set. And the following commands will send this
424268d33a25Syt  * FIS upon the successful completion:
424368d33a25Syt  * 	1. PIO data-in command
42442fcbc377Syt  */
42452fcbc377Syt static int
424682263d52Syt ahci_intr_cmd_cmplt(ahci_ctl_t *ahci_ctlp,
424782263d52Syt     ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
42482fcbc377Syt {
424968d33a25Syt 	uint32_t port_cmd_issue = 0;
42502fcbc377Syt 	uint32_t finished_tags;
425168d33a25Syt 	int finished_slot;
42522fcbc377Syt 	sata_pkt_t *satapkt;
42532fcbc377Syt 	ahci_fis_d2h_register_t *rcvd_fisp;
42542fcbc377Syt 
425568d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_DHRS)
425668d33a25Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
425768d33a25Syt 		    "ahci_intr_cmd_cmplt enter: port %d "
425868d33a25Syt 		    "a d2h register fis is received", port);
42592fcbc377Syt 
426068d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_PSS)
426168d33a25Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
426268d33a25Syt 		    "ahci_intr_cmd_cmplt enter: port %d "
426368d33a25Syt 		    "a pio setup fis is received", port);
42642fcbc377Syt 
426568d33a25Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
426682263d52Syt 
426782263d52Syt 	if (!ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) &&
426882263d52Syt 	    !NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
42692fcbc377Syt 		/*
42702fcbc377Syt 		 * Spurious interrupt. Nothing to be done.
42712fcbc377Syt 		 */
42722fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
42732fcbc377Syt 		return (AHCI_SUCCESS);
42742fcbc377Syt 	}
42752fcbc377Syt 
427668d33a25Syt 	port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
427768d33a25Syt 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
42782fcbc377Syt 
427982263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
428082263d52Syt 		/* Slot 0 is always used during error recovery */
428182263d52Syt 		finished_tags = 0x1 & ~port_cmd_issue;
428282263d52Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
428382263d52Syt 		    "ahci_intr_cmd_cmplt: port %d the sata pkt for error "
428482263d52Syt 		    "retrieval is finished, and finished_tags = 0x%x",
428582263d52Syt 		    port, finished_tags);
428668d33a25Syt 	} else {
428768d33a25Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
428868d33a25Syt 		    ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
42892fcbc377Syt 	}
42902fcbc377Syt 
429168d33a25Syt 	AHCIDBG3(AHCIDBG_INTR, ahci_ctlp,
429282263d52Syt 	    "ahci_intr_cmd_cmplt: pending_tags = 0x%x, "
429382263d52Syt 	    "port_cmd_issue = 0x%x finished_tags = 0x%x",
429468d33a25Syt 	    ahci_portp->ahciport_pending_tags, port_cmd_issue,
429582263d52Syt 	    finished_tags);
42962fcbc377Syt 
429782263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) &&
429882263d52Syt 	    (finished_tags == 0x1)) {
429982263d52Syt 		satapkt = ahci_portp->ahciport_err_retri_pkt;
430082263d52Syt 		ASSERT(satapkt != NULL);
430182263d52Syt 
430282263d52Syt 		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
430382263d52Syt 		    "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
430482263d52Syt 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
430582263d52Syt 
430682263d52Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
430782263d52Syt 		goto out;
430882263d52Syt 	}
43092fcbc377Syt 
431068d33a25Syt 	while (finished_tags) {
431168d33a25Syt 		finished_slot = ddi_ffs(finished_tags) - 1;
431268d33a25Syt 		if (finished_slot == -1) {
431368d33a25Syt 			goto out;
431468d33a25Syt 		}
43152fcbc377Syt 
431668d33a25Syt 		satapkt = ahci_portp->ahciport_slot_pkts[finished_slot];
431768d33a25Syt 		ASSERT(satapkt != NULL);
43182fcbc377Syt 
43192fcbc377Syt 		/*
432068d33a25Syt 		 * For SATAC_SMART command with SATA_SMART_RETURN_STATUS
432168d33a25Syt 		 * feature, sata_special_regs flag will be set, and the
432268d33a25Syt 		 * driver should copy the status and the other corresponding
432368d33a25Syt 		 * register values in the D2H Register FIS received (It's
432468d33a25Syt 		 * working on Non-data protocol) from the device back to
432568d33a25Syt 		 * the sata_cmd.
432668d33a25Syt 		 *
432768d33a25Syt 		 * For every AHCI port, there is only one Received FIS
432868d33a25Syt 		 * structure, which contains the FISes received from the
432968d33a25Syt 		 * device, So we're trying to copy the content of D2H
433068d33a25Syt 		 * Register FIS in the Received FIS structure back to
433168d33a25Syt 		 * the sata_cmd.
43322fcbc377Syt 		 */
433368d33a25Syt 		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
433468d33a25Syt 			rcvd_fisp = &(ahci_portp->ahciport_rcvd_fis->
433568d33a25Syt 			    ahcirf_d2h_register_fis);
433668d33a25Syt 			satapkt->satapkt_cmd.satacmd_status_reg =
433768d33a25Syt 			    GET_RFIS_STATUS(rcvd_fisp);
433868d33a25Syt 			ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp);
433968d33a25Syt 		}
43402fcbc377Syt 
434168d33a25Syt 		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
434268d33a25Syt 		    "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
434368d33a25Syt 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
43442fcbc377Syt 
434568d33a25Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, finished_slot);
434668d33a25Syt 		CLEAR_BIT(finished_tags, finished_slot);
434768d33a25Syt 		ahci_portp->ahciport_slot_pkts[finished_slot] = NULL;
43482fcbc377Syt 
434968d33a25Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
43502fcbc377Syt 	}
43512fcbc377Syt out:
43522fcbc377Syt 	AHCIDBG1(AHCIDBG_PKTCOMP, ahci_ctlp,
435368d33a25Syt 	    "ahci_intr_cmd_cmplt: pending_tags = 0x%x",
43542fcbc377Syt 	    ahci_portp->ahciport_pending_tags);
43552fcbc377Syt 
43562fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
43572fcbc377Syt 
43582fcbc377Syt 	return (AHCI_SUCCESS);
43592fcbc377Syt }
43602fcbc377Syt 
43612fcbc377Syt /*
436268d33a25Syt  * AHCI_INTR_STATUS_SDBS means a Set Device Bits FIS has been received
436382263d52Syt  * with the 'I' bit set and has been copied into system memory. It will
436482263d52Syt  * be sent under the following situations:
436582263d52Syt  *
436682263d52Syt  * 	1. NCQ command is completed
436782263d52Syt  * 	2. Asynchronous notification
436882263d52Syt  *
436982263d52Syt  * The completion of NCQ commands (READ/WRITE FPDMA QUEUED) is performed
437082263d52Syt  * via the Set Device Bits FIS. When such event is generated, the software
437182263d52Syt  * needs to read PxSACT register and compares the current value to the
437282263d52Syt  * list of commands previously issue by software. ahciport_pending_ncq_tags
437382263d52Syt  * keeps the tags of previously issued commands.
43742fcbc377Syt  *
437568d33a25Syt  * Asynchronous Notification is a feature in SATA II, which allows an
437668d33a25Syt  * ATAPI device to send a signal to the host when media is inserted or
437768d33a25Syt  * removed and avoids polling the device for media changes. The signal
437868d33a25Syt  * sent to the host is a Set Device Bits FIS with the 'I' and 'N' bits
437982263d52Syt  * set to '1'. At the moment, it's not supported yet.
43802fcbc377Syt  */
43812fcbc377Syt static int
438268d33a25Syt ahci_intr_set_device_bits(ahci_ctl_t *ahci_ctlp,
43832fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
43842fcbc377Syt {
438582263d52Syt 	uint32_t port_sactive;
438682263d52Syt 	uint32_t port_cmd_issue;
438782263d52Syt 	uint32_t issued_tags;
438882263d52Syt 	int issued_slot;
438982263d52Syt 	uint32_t finished_tags;
439082263d52Syt 	int finished_slot;
439182263d52Syt 	sata_pkt_t *satapkt;
43922fcbc377Syt 
439382263d52Syt 	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
439468d33a25Syt 	    "ahci_intr_set_device_bits enter: port %d", port);
43952fcbc377Syt 
439682263d52Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
439782263d52Syt 	if (!NCQ_CMD_IN_PROGRESS(ahci_portp)) {
439882263d52Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
439982263d52Syt 		return (AHCI_SUCCESS);
440082263d52Syt 	}
440182263d52Syt 
440282263d52Syt 	/*
440382263d52Syt 	 * First the handler got which commands are finished by checking
440482263d52Syt 	 * PxSACT register
440582263d52Syt 	 */
440682263d52Syt 	port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
440782263d52Syt 	    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
440868d33a25Syt 
440982263d52Syt 	finished_tags = ahci_portp->ahciport_pending_ncq_tags &
441082263d52Syt 	    ~port_sactive & AHCI_NCQ_SLOT_MASK(ahci_portp);
441182263d52Syt 
441282263d52Syt 	AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
441382263d52Syt 	    "ahci_intr_set_device_bits: port %d pending_ncq_tags = 0x%x "
441482263d52Syt 	    "port_sactive = 0x%x", port,
441582263d52Syt 	    ahci_portp->ahciport_pending_ncq_tags, port_sactive);
441682263d52Syt 
441782263d52Syt 	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
441882263d52Syt 	    "ahci_intr_set_device_bits: finished_tags = 0x%x", finished_tags);
441982263d52Syt 
442082263d52Syt 	/*
442182263d52Syt 	 * For NCQ commands, the software can determine which command has
442282263d52Syt 	 * already been transmitted to the device by checking PxCI register.
442382263d52Syt 	 */
442482263d52Syt 	port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
442582263d52Syt 	    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
442682263d52Syt 
442782263d52Syt 	issued_tags = ahci_portp->ahciport_pending_tags &
442882263d52Syt 	    ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
442982263d52Syt 
443082263d52Syt 	AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
443182263d52Syt 	    "ahci_intr_set_device_bits: port %d pending_tags = 0x%x "
443282263d52Syt 	    "port_cmd_issue = 0x%x", port,
443382263d52Syt 	    ahci_portp->ahciport_pending_tags, port_cmd_issue);
443482263d52Syt 
443582263d52Syt 	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
443682263d52Syt 	    "ahci_intr_set_device_bits: issued_tags = 0x%x", issued_tags);
443782263d52Syt 
443882263d52Syt 	/*
443982263d52Syt 	 * Clear ahciport_pending_tags bit when the corresponding command
444082263d52Syt 	 * is already sent down to the device.
444182263d52Syt 	 */
444282263d52Syt 	while (issued_tags) {
444382263d52Syt 		issued_slot = ddi_ffs(issued_tags) - 1;
444482263d52Syt 		if (issued_slot == -1) {
444582263d52Syt 			goto next;
444682263d52Syt 		}
444782263d52Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, issued_slot);
444882263d52Syt 		CLEAR_BIT(issued_tags, issued_slot);
444982263d52Syt 	}
445082263d52Syt 
445182263d52Syt next:
445282263d52Syt 	while (finished_tags) {
445382263d52Syt 		finished_slot = ddi_ffs(finished_tags) - 1;
445482263d52Syt 		if (finished_slot == -1) {
445582263d52Syt 			goto out;
445682263d52Syt 		}
445782263d52Syt 
445882263d52Syt 		/* The command is certainly transmitted to the device */
445982263d52Syt 		ASSERT(!(ahci_portp->ahciport_pending_tags &
446082263d52Syt 		    (0x1 << finished_slot)));
446182263d52Syt 
446282263d52Syt 		satapkt = ahci_portp->ahciport_slot_pkts[finished_slot];
446382263d52Syt 		ASSERT(satapkt != NULL);
446482263d52Syt 
446582263d52Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
446682263d52Syt 		    "ahci_intr_set_device_bits: sending up pkt 0x%p "
446782263d52Syt 		    "with SATA_PKT_COMPLETED", (void *)satapkt);
446882263d52Syt 
446982263d52Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags, finished_slot);
447082263d52Syt 		CLEAR_BIT(finished_tags, finished_slot);
447182263d52Syt 		ahci_portp->ahciport_slot_pkts[finished_slot] = NULL;
447282263d52Syt 
447382263d52Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
447468d33a25Syt 	}
447582263d52Syt out:
447682263d52Syt 	AHCIDBG3(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp,
447782263d52Syt 	    "ahci_intr_set_device_bits: port %d "
447882263d52Syt 	    "pending_ncq_tags = 0x%x pending_tags = 0x%x",
447982263d52Syt 	    port, ahci_portp->ahciport_pending_ncq_tags,
448082263d52Syt 	    ahci_portp->ahciport_pending_tags);
448182263d52Syt 
448282263d52Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
44832fcbc377Syt 
44842fcbc377Syt 	return (AHCI_SUCCESS);
44852fcbc377Syt }
44862fcbc377Syt 
44872fcbc377Syt /*
448868d33a25Syt  * 1=Change in Current Connect Status. 0=No change in Current Connect Status.
448968d33a25Syt  * This bit reflects the state of PxSERR.DIAG.X. This bit is only cleared
449068d33a25Syt  * when PxSERR.DIAG.X is cleared. When PxSERR.DIAG.X is set to one, it
449168d33a25Syt  * indicates a COMINIT signal was received.
44922fcbc377Syt  *
449368d33a25Syt  * Hot plug insertion is detected by reception of a COMINIT signal from the
449468d33a25Syt  * device. On reception of unsolicited COMINIT, the HBA shall generate a
449568d33a25Syt  * COMRESET. If the COMINIT is in responce to a COMRESET, then the HBA shall
449668d33a25Syt  * begin the normal communication negotiation sequence as outlined in the
449768d33a25Syt  * Serial ATA 1.0a specification. When a COMRESET is sent to the device the
449868d33a25Syt  * PxSSTS.DET field shall be cleared to 0h. When a COMINIT is received, the
449968d33a25Syt  * PxSSTS.DET field shall be set to 1h. When the communication negotiation
450068d33a25Syt  * sequence is complete and PhyRdy is true the PxSSTS.DET field	shall be set
450168d33a25Syt  * to 3h. Therefore, at the moment the ahci driver is going to check PhyRdy
450268d33a25Syt  * to handle hot plug insertion. In this interrupt handler, just do nothing
450368d33a25Syt  * but print some log message and clear the bit.
45042fcbc377Syt  */
45052fcbc377Syt static int
450668d33a25Syt ahci_intr_port_connect_change(ahci_ctl_t *ahci_ctlp,
45072fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
45082fcbc377Syt {
45092fcbc377Syt 	uint32_t port_serror;
45102fcbc377Syt 
45112fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
45122fcbc377Syt 
45132fcbc377Syt 	port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
45142fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
45152fcbc377Syt 
45162fcbc377Syt 	AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
451768d33a25Syt 	    "ahci_intr_port_connect_change: port %d, "
451868d33a25Syt 	    "port_serror = 0x%x", port, port_serror);
45192fcbc377Syt 
452068d33a25Syt 	/* Clear PxSERR.DIAG.X to clear the interrupt bit */
45212fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
45222fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
452382263d52Syt 	    SERROR_EXCHANGED_ERR);
45242fcbc377Syt 
45252fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
45262fcbc377Syt 
45272fcbc377Syt 	return (AHCI_SUCCESS);
45282fcbc377Syt }
45292fcbc377Syt 
45302fcbc377Syt /*
45312fcbc377Syt  * Hot Plug Operation for platforms that support Mechanical Presence
45322fcbc377Syt  * Switches.
45332fcbc377Syt  *
45342fcbc377Syt  * When set, it indicates that a mechanical presence switch attached to this
45352fcbc377Syt  * port has been opened or closed, which may lead to a change in the connection
45362fcbc377Syt  * state of the device. This bit is only valid if both CAP.SMPS and PxCMD.MPSP
45372fcbc377Syt  * are set to '1'.
45382fcbc377Syt  *
453968d33a25Syt  * At the moment, this interrupt is not needed and disabled and we just log
45402fcbc377Syt  * the debug message.
45412fcbc377Syt  */
45422fcbc377Syt /* ARGSUSED */
45432fcbc377Syt static int
45442fcbc377Syt ahci_intr_device_mechanical_presence_status(ahci_ctl_t *ahci_ctlp,
45452fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
45462fcbc377Syt {
45472fcbc377Syt 	uint32_t cap_status, port_cmd_status;
45482fcbc377Syt 
45492fcbc377Syt 	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
45502fcbc377Syt 	    "ahci_intr_device_mechanical_presence_status enter, "
45512fcbc377Syt 	    "port %d", port);
45522fcbc377Syt 
45532fcbc377Syt 	cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
45542fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
45552fcbc377Syt 
45562fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
45572fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
45582fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
45592fcbc377Syt 
45602fcbc377Syt 	if (!(cap_status & AHCI_HBA_CAP_SMPS) ||
45612fcbc377Syt 	    !(port_cmd_status & AHCI_CMD_STATUS_MPSP)) {
45622fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
45632fcbc377Syt 		    "CAP.SMPS or PxCMD.MPSP is not set, so just ignore "
45642fcbc377Syt 		    "the interrupt: cap_status = 0x%x, "
45652fcbc377Syt 		    "port_cmd_status = 0x%x", cap_status, port_cmd_status);
45662fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
45672fcbc377Syt 
45682fcbc377Syt 		return (AHCI_SUCCESS);
45692fcbc377Syt 	}
45702fcbc377Syt 
45712fcbc377Syt 	if (port_cmd_status & AHCI_CMD_STATUS_MPSS) {
45722fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
45732fcbc377Syt 		    "The mechanical presence switch is open: "
45742fcbc377Syt 		    "port %d, port_cmd_status = 0x%x",
45752fcbc377Syt 		    port, port_cmd_status);
45762fcbc377Syt 	} else {
45772fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR, ahci_ctlp,
45782fcbc377Syt 		    "The mechanical presence switch is close: "
45792fcbc377Syt 		    "port %d, port_cmd_status = 0x%x",
45802fcbc377Syt 		    port, port_cmd_status);
45812fcbc377Syt 	}
45822fcbc377Syt 
45832fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
45842fcbc377Syt 
45852fcbc377Syt 	return (AHCI_SUCCESS);
45862fcbc377Syt }
45872fcbc377Syt 
45882fcbc377Syt /*
45892fcbc377Syt  * Native Hot Plug Support.
45902fcbc377Syt  *
45912fcbc377Syt  * When set, it indicates that the internal PHYRDY signal changed state.
45922fcbc377Syt  * This bit reflects the state of PxSERR.DIAG.N.
459368d33a25Syt  *
459468d33a25Syt  * There are three kinds of conditions to generate this interrupt event:
459568d33a25Syt  * 1. a device is inserted
459668d33a25Syt  * 2. a device is disconnected
459768d33a25Syt  * 3. when the link enters/exits a Partial or Slumber interface power
459868d33a25Syt  *    management state
459968d33a25Syt  *
460068d33a25Syt  * If inteface power management is enabled for a port, the PxSERR.DIAG.N
460168d33a25Syt  * bit may be set due to the link entering the Partial or Slumber power
460268d33a25Syt  * management state, rather than due to a hot plug insertion or removal
460368d33a25Syt  * event. So far, the power management is disabled, so the driver can
460468d33a25Syt  * reliably get removal detection notification via the PxSERR.DIAG.N bit.
46052fcbc377Syt  */
46062fcbc377Syt static int
46072fcbc377Syt ahci_intr_phyrdy_change(ahci_ctl_t *ahci_ctlp,
46082fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
46092fcbc377Syt {
46102fcbc377Syt 	uint32_t port_sstatus = 0; /* No dev present & PHY not established. */
46112fcbc377Syt 	sata_device_t sdevice;
46122fcbc377Syt 	int dev_exists_now = 0;
46132fcbc377Syt 	int dev_existed_previously = 0;
46142fcbc377Syt 
46152fcbc377Syt 	AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
46162fcbc377Syt 	    "ahci_intr_phyrdy_change enter, port %d", port);
46172fcbc377Syt 
46182fcbc377Syt 	/* Clear PxSERR.DIAG.N to clear the interrupt bit */
46192fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
46202fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
46212fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
462282263d52Syt 	    SERROR_PHY_RDY_CHG);
46232fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
46242fcbc377Syt 
46252fcbc377Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
46262fcbc377Syt 	if ((ahci_ctlp->ahcictl_sata_hba_tran == NULL) ||
46272fcbc377Syt 	    (ahci_portp == NULL)) {
46282fcbc377Syt 		/* The whole controller setup is not yet done. */
46292fcbc377Syt 		mutex_exit(&ahci_ctlp->ahcictl_mutex);
46302fcbc377Syt 		return (AHCI_SUCCESS);
46312fcbc377Syt 	}
46322fcbc377Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
46332fcbc377Syt 
46342fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
46352fcbc377Syt 
46362fcbc377Syt 	/* SStatus tells the presence of device. */
46372fcbc377Syt 	port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
46382fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
46392fcbc377Syt 
464082263d52Syt 	if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
464168d33a25Syt 		dev_exists_now = 1;
464268d33a25Syt 	}
46432fcbc377Syt 
46442fcbc377Syt 	if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) {
46452fcbc377Syt 		dev_existed_previously = 1;
46462fcbc377Syt 	}
46472fcbc377Syt 
464882263d52Syt 	if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_NODEV) {
464982263d52Syt 		ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_NODEV;
465082263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
465182263d52Syt 		    "ahci_intr_phyrdy_change: port %d "
465282263d52Syt 		    "AHCI_PORT_FLAG_NODEV is cleared", port);
465382263d52Syt 		if (dev_exists_now == 0)
465482263d52Syt 			dev_existed_previously = 1;
465582263d52Syt 	}
465682263d52Syt 
46572fcbc377Syt 	bzero((void *)&sdevice, sizeof (sata_device_t));
465809121340Syt 	sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
46592fcbc377Syt 	sdevice.satadev_addr.qual = SATA_ADDR_CPORT;
46602fcbc377Syt 	sdevice.satadev_addr.pmport = 0;
46612fcbc377Syt 	sdevice.satadev_state = SATA_PSTATE_PWRON;
46622fcbc377Syt 	ahci_portp->ahciport_port_state = SATA_PSTATE_PWRON;
46632fcbc377Syt 
46642fcbc377Syt 	if (dev_exists_now) {
46652fcbc377Syt 		if (dev_existed_previously) {
46662fcbc377Syt 			/* Things are fine now. The loss was temporary. */
466768d33a25Syt 			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
466868d33a25Syt 			    "ahci_intr_phyrdy_change  port %d "
46692fcbc377Syt 			    "device link lost/established", port);
46702fcbc377Syt 
46712fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
46722fcbc377Syt 			sata_hba_event_notify(
46732fcbc377Syt 			    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
46742fcbc377Syt 			    &sdevice,
46752fcbc377Syt 			    SATA_EVNT_LINK_LOST|SATA_EVNT_LINK_ESTABLISHED);
46762fcbc377Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
46772fcbc377Syt 
46782fcbc377Syt 		} else {
467968d33a25Syt 			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
468068d33a25Syt 			    "ahci_intr_phyrdy_change: port %d "
46812fcbc377Syt 			    "device link established", port);
46822fcbc377Syt 
46832fcbc377Syt 			/* A new device has been detected. */
468468d33a25Syt 			ahci_find_dev_signature(ahci_ctlp, ahci_portp, port);
46852fcbc377Syt 
468668d33a25Syt 			/* Try to start the port */
468768d33a25Syt 			if (ahci_start_port(ahci_ctlp, ahci_portp, port)
468868d33a25Syt 			    != AHCI_SUCCESS) {
468968d33a25Syt 				sdevice.satadev_state |= SATA_PSTATE_FAILED;
46902fcbc377Syt 				AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
469168d33a25Syt 				    "ahci_intr_phyrdy_change: port %d failed "
46922fcbc377Syt 				    "at start port", port);
46932fcbc377Syt 			}
46942fcbc377Syt 
469582263d52Syt 			/* Clear the max queue depth for inserted device */
469682263d52Syt 			ahci_portp->ahciport_max_ncq_tags = 0;
469782263d52Syt 
46982fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
46992fcbc377Syt 			sata_hba_event_notify(
47002fcbc377Syt 			    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
47012fcbc377Syt 			    &sdevice,
47022fcbc377Syt 			    SATA_EVNT_LINK_ESTABLISHED);
47032fcbc377Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
47042fcbc377Syt 
47052fcbc377Syt 		}
47062fcbc377Syt 	} else { /* No device exists now */
47072fcbc377Syt 
47082fcbc377Syt 		if (dev_existed_previously) {
470968d33a25Syt 			AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
471068d33a25Syt 			    "ahci_intr_phyrdy_change: port %d "
47112fcbc377Syt 			    "device link lost", port);
47122fcbc377Syt 
47132fcbc377Syt 			ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
471468d33a25Syt 			(void) ahci_put_port_into_notrunning_state(ahci_ctlp,
47152fcbc377Syt 			    ahci_portp, port);
47162fcbc377Syt 
47172fcbc377Syt 			/* An existing device is lost. */
47182fcbc377Syt 			ahci_portp->ahciport_device_type = SATA_DTYPE_NONE;
47192fcbc377Syt 
47202fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
47212fcbc377Syt 			sata_hba_event_notify(
47222fcbc377Syt 			    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
47232fcbc377Syt 			    &sdevice,
47242fcbc377Syt 			    SATA_EVNT_LINK_LOST);
47252fcbc377Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
47262fcbc377Syt 
47272fcbc377Syt 		} else {
47282fcbc377Syt 
47292fcbc377Syt 			/* Spurious interrupt */
47302fcbc377Syt 			AHCIDBG0(AHCIDBG_INTR, ahci_ctlp,
473168d33a25Syt 			    "ahci_intr_phyrdy_change: "
47322fcbc377Syt 			    "spurious phy ready interrupt");
47332fcbc377Syt 		}
47342fcbc377Syt 	}
47352fcbc377Syt 
47362fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
47372fcbc377Syt 
47382fcbc377Syt 	return (AHCI_SUCCESS);
47392fcbc377Syt }
47402fcbc377Syt 
47412fcbc377Syt /*
474268d33a25Syt  * PxIS.UFS - Unknown FIS Error
47432fcbc377Syt  *
474468d33a25Syt  * This interrupt event means an unknown FIS was received and has been
474568d33a25Syt  * copied into system memory. An unknown FIS is not considered an illegal
474668d33a25Syt  * FIS, unless the length received is more than 64 bytes. If an unknown
474768d33a25Syt  * FIS arrives with length <= 64 bytes, it is posted and the HBA continues
474868d33a25Syt  * normal operation. If the unknown FIS is more than 64 bytes, then it
474968d33a25Syt  * won't be posted to memory and PxSERR.ERR.P will be set, which is then
475068d33a25Syt  * a fatal error.
47512fcbc377Syt  *
475268d33a25Syt  * PxIS.OFS - Overflow Error
47532fcbc377Syt  *
475468d33a25Syt  * Command list overflow is defined as software building a command table
475568d33a25Syt  * that has fewer total bytes than the transaction given to the device.
475668d33a25Syt  * On device writes, the HBA will run out of data, and on reads, there
475768d33a25Syt  * will be no room to put the data.
47582fcbc377Syt  *
475968d33a25Syt  * For an overflow on data read, either PIO or DMA, the HBA will set
476068d33a25Syt  * PxIS.OFS, and the HBA will do a best effort to continue, and it's a
476168d33a25Syt  * non-fatal error when the HBA can continues. Sometimes, it will cause
476268d33a25Syt  * a fatal error and need the software to do something.
47632fcbc377Syt  *
476468d33a25Syt  * For an overflow on data write, setting PxIS.OFS is optional for both
476568d33a25Syt  * DMA and PIO, and it's a fatal error, and a COMRESET is required by
476668d33a25Syt  * software to clean up from this serious error.
47672fcbc377Syt  *
476868d33a25Syt  * PxIS.INFS - Interface Non-Fatal Error
476968d33a25Syt  *
477068d33a25Syt  * This interrupt event indicates that the HBA encountered an error on
477168d33a25Syt  * the Serial ATA interface but was able to continue operation. The kind
477268d33a25Syt  * of error usually occurred during a non-Data FIS, and under this condition
477368d33a25Syt  * the FIS will be re-transmitted by HBA automatically.
47742fcbc377Syt  *
477568d33a25Syt  * When the FMA is implemented, there should be a stat structure to
477668d33a25Syt  * record how many every kind of error happens.
47772fcbc377Syt  */
47782fcbc377Syt static int
477968d33a25Syt ahci_intr_non_fatal_error(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
478068d33a25Syt     uint8_t port, uint32_t intr_status)
47812fcbc377Syt {
47822fcbc377Syt 	uint32_t port_serror;
478368d33a25Syt #if AHCI_DEBUG
47842fcbc377Syt 	uint32_t port_cmd_status;
478582263d52Syt 	uint32_t port_cmd_issue;
478682263d52Syt 	uint32_t port_sactive;
47872fcbc377Syt 	int current_slot;
478882263d52Syt 	uint32_t current_tags;
478968d33a25Syt 	sata_pkt_t *satapkt;
479068d33a25Syt #endif
47912fcbc377Syt 
47922fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
47932fcbc377Syt 
47942fcbc377Syt 	port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
47952fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
47962fcbc377Syt 
479768d33a25Syt 	AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp,
479868d33a25Syt 	    "ahci_intr_non_fatal_error: port %d, "
47992fcbc377Syt 	    "port_serror = 0x%x", port, port_serror);
48002fcbc377Syt 
480168d33a25Syt 	ahci_log_serror_message(ahci_ctlp, port, port_serror);
480268d33a25Syt 
480368d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_UFS) {
480468d33a25Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
480568d33a25Syt 		    "ahci port %d has unknown FIS error", port);
48062fcbc377Syt 
480768d33a25Syt 		/* Clear the interrupt bit by clearing PxSERR.DIAG.F */
480868d33a25Syt 		ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
480968d33a25Syt 		    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
481082263d52Syt 		    SERROR_FIS_TYPE);
481168d33a25Syt 	}
481268d33a25Syt 
481368d33a25Syt #if AHCI_DEBUG
481468d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_OFS) {
481568d33a25Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
481668d33a25Syt 		    "ahci port %d has overflow error", port);
481768d33a25Syt 	}
481868d33a25Syt 
481968d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_INFS) {
482068d33a25Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
482168d33a25Syt 		    "ahci port %d has interface non fatal error", port);
482268d33a25Syt 	}
48232fcbc377Syt 
48242fcbc377Syt 	/*
48252fcbc377Syt 	 * Record the error occurred command's slot.
48262fcbc377Syt 	 */
482782263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
482882263d52Syt 	    ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
482982263d52Syt 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
483082263d52Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
483182263d52Syt 
483282263d52Syt 		current_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
483382263d52Syt 		    AHCI_CMD_STATUS_CCS_SHIFT;
48342fcbc377Syt 
483582263d52Syt 		if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
483682263d52Syt 			satapkt = ahci_portp->ahciport_err_retri_pkt;
483782263d52Syt 			ASSERT(satapkt != NULL);
483882263d52Syt 			ASSERT(current_slot == 0);
483982263d52Syt 		} else {
484082263d52Syt 			satapkt = ahci_portp->ahciport_slot_pkts[current_slot];
484182263d52Syt 		}
48422fcbc377Syt 
484382263d52Syt 		if (satapkt != NULL) {
484482263d52Syt 			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
484582263d52Syt 			    "ahci_intr_non_fatal_error: pending_tags = 0x%x "
484682263d52Syt 			    "cmd 0x%x", ahci_portp->ahciport_pending_tags,
484782263d52Syt 			    satapkt->satapkt_cmd.satacmd_cmd_reg);
48482fcbc377Syt 
484982263d52Syt 			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
485082263d52Syt 			    "ahci_intr_non_fatal_error: port %d, "
485182263d52Syt 			    "satapkt 0x%p is being processed when error occurs",
485282263d52Syt 			    port, (void *)satapkt);
485382263d52Syt 		}
485482263d52Syt 	}
485582263d52Syt 
485682263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
485782263d52Syt 		/*
485882263d52Syt 		 * For queued command, list those command which have already
485982263d52Syt 		 * been transmitted to the device and still not completed.
486082263d52Syt 		 */
486182263d52Syt 		port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
486282263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
486382263d52Syt 
486482263d52Syt 		port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
486582263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
486682263d52Syt 
486782263d52Syt 		AHCIDBG3(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp,
486882263d52Syt 		    "ahci_intr_non_fatal_error: pending_ncq_tags = 0x%x "
486982263d52Syt 		    "port_sactive = 0x%x port_cmd_issue = 0x%x",
487082263d52Syt 		    ahci_portp->ahciport_pending_ncq_tags,
487182263d52Syt 		    port_sactive, port_cmd_issue);
487282263d52Syt 
487382263d52Syt 		current_tags = ahci_portp->ahciport_pending_ncq_tags &
487482263d52Syt 		    port_sactive & ~port_cmd_issue &
487582263d52Syt 		    AHCI_NCQ_SLOT_MASK(ahci_portp);
487682263d52Syt 
487782263d52Syt 		while (current_tags) {
487882263d52Syt 			current_slot = ddi_ffs(current_tags) - 1;
487982263d52Syt 			if (current_slot == -1) {
488082263d52Syt 				goto out;
488182263d52Syt 			}
488282263d52Syt 
488382263d52Syt 			satapkt = ahci_portp->ahciport_slot_pkts[current_slot];
488482263d52Syt 			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS,
488582263d52Syt 			    ahci_ctlp, "ahci_intr_non_fatal_error: "
488682263d52Syt 			    "port %d, satapkt 0x%p is outstanding when "
488782263d52Syt 			    "error occurs", port, (void *)satapkt);
488882263d52Syt 		}
48892fcbc377Syt 	}
489082263d52Syt out:
48912fcbc377Syt #endif
48922fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
48932fcbc377Syt 
48942fcbc377Syt 	return (AHCI_SUCCESS);
48952fcbc377Syt }
48962fcbc377Syt 
48972fcbc377Syt /*
489868d33a25Syt  * According to the AHCI spec, the error types include system memory
489968d33a25Syt  * errors, interface errors, port multiplier errors, device errors,
490068d33a25Syt  * command list overflow, command list underflow, native command
490168d33a25Syt  * queuing tag errors and pio data transfer errors.
490268d33a25Syt  *
490368d33a25Syt  * System memory errors such as target abort, master abort, and parity
490468d33a25Syt  * may cause the host to stop, and they are serious errors and needed
490568d33a25Syt  * to be recovered with software intervention. When system software
490668d33a25Syt  * has given a pointer to the HBA that doesn't exist in physical memory,
490768d33a25Syt  * a master/target abort error occurs, and PxIS.HBFS will be set. A
490868d33a25Syt  * data error such as CRC or parity occurs, the HBA aborts the transfer
490968d33a25Syt  * (if necessary) and PxIS.HBDS will be set.
491068d33a25Syt  *
491168d33a25Syt  * Interface errors are errors that occur due to electrical issues on
491268d33a25Syt  * the interface, or protocol miscommunication between the device and
491368d33a25Syt  * HBA, and the respective PxSERR register bit will be set. And PxIS.IFS
491468d33a25Syt  * (fatal) or PxIS.INFS (non-fatal) will be set. The conditions that
491568d33a25Syt  * causes PxIS.IFS/PxIS.INFS to be set are
491668d33a25Syt  * 	1. in PxSERR.ERR, P bit is set to '1'
491768d33a25Syt  *	2. in PxSERR.DIAG, C or H bit is set to '1'
491868d33a25Syt  *	3. PhyRdy drop unexpectly, N bit is set to '1'
491968d33a25Syt  * If the error occurred during a non-data FIS, the FIS must be
492068d33a25Syt  * retransmitted, and the error is non-fatal and PxIS.INFS is set. If
492168d33a25Syt  * the error occurred during a data FIS, the transfer will stop, so
492268d33a25Syt  * the error is fatal and PxIS.IFS is set.
492368d33a25Syt  *
492468d33a25Syt  * When a FIS arrives that updates the taskfile, the HBA checks to see
492568d33a25Syt  * if PxTFD.STS.ERR is set. If yes, PxIS.TFES will be set and the HBA
492668d33a25Syt  * stops processing any more commands.
49272fcbc377Syt  *
492868d33a25Syt  * Command list overflow is defined as software building a command table
492968d33a25Syt  * that has fewer total bytes than the transaction given to the device.
493068d33a25Syt  * On device writes, the HBA will run out of data, and on reads, there
493168d33a25Syt  * will be no room to put the data. For an overflow on data read, either
493268d33a25Syt  * PIO or DMA, the HBA will set PxIS.OFS, and it's a non-fatal error.
493368d33a25Syt  * For an overflow on data write, setting PxIS.OFS is optional for both
493468d33a25Syt  * DMA and PIO, and a COMRESET is required by software to clean up from
493568d33a25Syt  * this serious error.
49362fcbc377Syt  *
493768d33a25Syt  * Command list underflow is defined as software building a command
493868d33a25Syt  * table that has more total bytes than the transaction given to the
493968d33a25Syt  * device. For data writes, both PIO and DMA, the device will detect
494068d33a25Syt  * an error and end the transfer. And these errors are most likely going
494168d33a25Syt  * to be fatal errors that will cause the port to be restarted. For
494268d33a25Syt  * data reads, the HBA updates its PRD byte count, and may be
494368d33a25Syt  * able to continue normally, but is not required to. And The HBA is
494468d33a25Syt  * not required to detect underflow conditions for native command
494568d33a25Syt  * queuing command.
494668d33a25Syt  *
494768d33a25Syt  * The HBA does not actively check incoming DMA Setup FISes to ensure
494868d33a25Syt  * that the PxSACT register bit for that slot is set. Existing error
494968d33a25Syt  * mechanisms, such as host bus failure, or bad protocol, are used to
495068d33a25Syt  * recover from this case.
495168d33a25Syt  *
495268d33a25Syt  * In accordance with Serial ATA 1.0a, DATA FISes prior to the final
495368d33a25Syt  * DATA FIS must be an integral number of Dwords. If the HBA receives
495468d33a25Syt  * a request which is not an integral number of Dwords, the HBA
495568d33a25Syt  * set PxSERR.ERR.P to '1', set PxIS.IFS to '1' and stop running until
495668d33a25Syt  * software restarts the port. And the HBA ensures that the size
495768d33a25Syt  * of the DATA FIS received during a PIO command matches the size in
495868d33a25Syt  * the Transfer Cound field of the preceding PIO Setup FIS, if not, the
495968d33a25Syt  * HBA sets PxSERR.ERR.P to '1', set PxIS.IFS to '1', and then
496068d33a25Syt  * stop running until software restarts the port.
49612fcbc377Syt  */
49622fcbc377Syt /*
496368d33a25Syt  * the fatal errors include PxIS.IFS, PxIS.HBDS, PxIS.HBFS and PxIS.TFES.
496468d33a25Syt  *
496568d33a25Syt  * PxIS.IFS indicates that the hba encountered an error on the serial ata
496668d33a25Syt  * interface which caused the transfer to stop.
49672fcbc377Syt  *
496868d33a25Syt  * PxIS.HBDS indicates that the hba encountered a data error
496968d33a25Syt  * (uncorrectable ecc/parity) when reading from or writing to system memory.
497068d33a25Syt  *
497168d33a25Syt  * PxIS.HBFS indicates that the hba encountered a host bus error that it
497268d33a25Syt  * cannot recover from, such as a bad software pointer.
497368d33a25Syt  *
497468d33a25Syt  * PxIS.TFES is set whenever the status register is updated by the device
497568d33a25Syt  * and the error bit (bit 0) is set.
49762fcbc377Syt  */
49772fcbc377Syt static int
497882263d52Syt ahci_intr_fatal_error(ahci_ctl_t *ahci_ctlp,
497982263d52Syt     ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
49802fcbc377Syt {
498168d33a25Syt 	uint32_t port_cmd_status;
49822fcbc377Syt 	uint32_t port_serror;
498368d33a25Syt 	uint32_t task_file_status;
498468d33a25Syt 	int failed_slot;
498582263d52Syt 	sata_pkt_t *spkt = NULL;
498668d33a25Syt 	uint8_t err_byte;
498768d33a25Syt 	ahci_event_arg_t *args;
49882fcbc377Syt 
49892fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
49902fcbc377Syt 
499168d33a25Syt 	/*
499268d33a25Syt 	 * ahci_intr_phyrdy_change() may have rendered it to
499368d33a25Syt 	 * SATA_DTYPE_NONE.
499468d33a25Syt 	 */
499568d33a25Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
499668d33a25Syt 		AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
499768d33a25Syt 		    "ahci_intr_fatal_error: port %d no device attached, "
499868d33a25Syt 		    "and just return without doing anything", port);
499968d33a25Syt 		goto out0;
500068d33a25Syt 	}
50012fcbc377Syt 
500282263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
500382263d52Syt 		/*
500482263d52Syt 		 * Read PxCMD.CCS to determine the slot that the HBA
500582263d52Syt 		 * was processing when the error occurred.
500682263d52Syt 		 */
500782263d52Syt 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
500882263d52Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
500982263d52Syt 		failed_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
501082263d52Syt 		    AHCI_CMD_STATUS_CCS_SHIFT;
50112fcbc377Syt 
501282263d52Syt 		spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
501368d33a25Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
501482263d52Syt 		    "ahci_intr_fatal_error: spkt 0x%p is being processed when "
501582263d52Syt 		    "fatal error occurred for port %d", spkt, port);
50162fcbc377Syt 
501782263d52Syt 		if (intr_status & AHCI_INTR_STATUS_TFES) {
501882263d52Syt 			task_file_status = ddi_get32(
501982263d52Syt 			    ahci_ctlp->ahcictl_ahci_acc_handle,
502082263d52Syt 			    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
502182263d52Syt 			AHCIDBG2(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
502282263d52Syt 			    "ahci_intr_fatal_error: port %d "
502382263d52Syt 			    "task_file_status = 0x%x", port, task_file_status);
50242fcbc377Syt 
502582263d52Syt 			err_byte = (task_file_status & AHCI_TFD_ERR_MASK)
502682263d52Syt 			    >> AHCI_TFD_ERR_SHIFT;
50272fcbc377Syt 
502882263d52Syt 			/*
502982263d52Syt 			 * Won't emit the error message if it is an IDENTIFY
503082263d52Syt 			 * DEVICE command sent to an ATAPI device.
503182263d52Syt 			 */
503282263d52Syt 			if ((spkt != NULL) &&
503382263d52Syt 			    (spkt->satapkt_cmd.satacmd_cmd_reg ==
503482263d52Syt 			    SATAC_ID_DEVICE) &&
503582263d52Syt 			    (err_byte == SATA_ERROR_ABORT))
503682263d52Syt 				goto out1;
503782263d52Syt 
503882263d52Syt 			/*
503982263d52Syt 			 * Won't emit the error message if it is an ATAPI PACKET
504082263d52Syt 			 * command
504182263d52Syt 			 */
504282263d52Syt 			if ((spkt != NULL) &&
504382263d52Syt 			    (spkt->satapkt_cmd.satacmd_cmd_reg == SATAC_PACKET))
504482263d52Syt 				goto out1;
504582263d52Syt 		}
504668d33a25Syt 	}
50472fcbc377Syt 
504868d33a25Syt 	ahci_log_fatal_error_message(ahci_ctlp, port, intr_status);
50492fcbc377Syt 
505068d33a25Syt out1:
50512fcbc377Syt 	port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
50522fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
505368d33a25Syt 	ahci_log_serror_message(ahci_ctlp, port, port_serror);
505468d33a25Syt 
505568d33a25Syt 	/* Prepare the argument for the taskq */
505668d33a25Syt 	args = ahci_portp->ahciport_event_args;
505768d33a25Syt 	args->ahciea_ctlp = (void *)ahci_ctlp;
505868d33a25Syt 	args->ahciea_portp = (void *)ahci_portp;
505968d33a25Syt 	args->ahciea_event = intr_status;
506068d33a25Syt 
506168d33a25Syt 	/* Start the taskq to handle error recovery */
506268d33a25Syt 	if ((ddi_taskq_dispatch(ahci_ctlp->ahcictl_event_taskq,
506368d33a25Syt 	    ahci_events_handler,
506468d33a25Syt 	    (void *)args, DDI_NOSLEEP)) != DDI_SUCCESS) {
506568d33a25Syt 		cmn_err(CE_WARN, "ahci start taskq for event handler failed");
506668d33a25Syt 	}
506768d33a25Syt out0:
50682fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
50692fcbc377Syt 
50702fcbc377Syt 	return (AHCI_SUCCESS);
50712fcbc377Syt }
50722fcbc377Syt 
50732fcbc377Syt /*
50742fcbc377Syt  * Hot Plug Operation for platforms that support Cold Presence Detect.
50752fcbc377Syt  *
50762fcbc377Syt  * When set, a device status has changed as detected by the cold presence
50772fcbc377Syt  * detect logic. This bit can either be set due to a non-connected port
50782fcbc377Syt  * receiving a device, or a connected port having its device removed.
50792fcbc377Syt  * This bit is only valid if the port supports cold presence detect as
50802fcbc377Syt  * indicated by PxCMD.CPD set to '1'.
50812fcbc377Syt  *
508268d33a25Syt  * At the moment, this interrupt is not needed and disabled and we just
508368d33a25Syt  * log the debug message.
50842fcbc377Syt  */
50852fcbc377Syt /* ARGSUSED */
50862fcbc377Syt static int
50872fcbc377Syt ahci_intr_cold_port_detect(ahci_ctl_t *ahci_ctlp,
50882fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
50892fcbc377Syt {
50902fcbc377Syt 	uint32_t port_cmd_status;
50912fcbc377Syt 	sata_device_t sdevice;
50922fcbc377Syt 
50932fcbc377Syt 	AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
50942fcbc377Syt 	    "ahci_intr_cold_port_detect enter, port %d", port);
50952fcbc377Syt 
50962fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
50972fcbc377Syt 
50982fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
50992fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
51002fcbc377Syt 	if (!(port_cmd_status & AHCI_CMD_STATUS_CPD)) {
51012fcbc377Syt 		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
51022fcbc377Syt 		    "port %d does not support cold presence detect, so "
51032fcbc377Syt 		    "we just ignore this interrupt", port);
51042fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
51052fcbc377Syt 		return (AHCI_SUCCESS);
51062fcbc377Syt 	}
51072fcbc377Syt 
51082fcbc377Syt 	AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
51092fcbc377Syt 	    "port %d device status has changed", port);
51102fcbc377Syt 
51112fcbc377Syt 	bzero((void *)&sdevice, sizeof (sata_device_t));
511209121340Syt 	sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
51132fcbc377Syt 	sdevice.satadev_addr.qual = SATA_ADDR_CPORT;
51142fcbc377Syt 	sdevice.satadev_addr.pmport = 0;
51152fcbc377Syt 	sdevice.satadev_state = SATA_PSTATE_PWRON;
51162fcbc377Syt 
51172fcbc377Syt 	if (port_cmd_status & AHCI_CMD_STATUS_CPS) {
51182fcbc377Syt 		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
51192fcbc377Syt 		    "port %d: a device is hot plugged", port);
51202fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
51212fcbc377Syt 		sata_hba_event_notify(
51222fcbc377Syt 		    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
51232fcbc377Syt 		    &sdevice,
51242fcbc377Syt 		    SATA_EVNT_DEVICE_ATTACHED);
51252fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
51262fcbc377Syt 
51272fcbc377Syt 	} else {
51282fcbc377Syt 		AHCIDBG1(AHCIDBG_INTR, ahci_ctlp,
51292fcbc377Syt 		    "port %d: a device is hot unplugged", port);
51302fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
51312fcbc377Syt 		sata_hba_event_notify(
51322fcbc377Syt 		    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
51332fcbc377Syt 		    &sdevice,
51342fcbc377Syt 		    SATA_EVNT_DEVICE_DETACHED);
51352fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
51362fcbc377Syt 	}
51372fcbc377Syt 
51382fcbc377Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
51392fcbc377Syt 
51402fcbc377Syt 	return (AHCI_SUCCESS);
51412fcbc377Syt }
51422fcbc377Syt 
51432fcbc377Syt /*
51442fcbc377Syt  * Enable the interrupts for a particular port.
51452fcbc377Syt  *
51462fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
51472fcbc377Syt  * is called.
51482fcbc377Syt  */
51492fcbc377Syt /* ARGSUSED */
51502fcbc377Syt static void
51512fcbc377Syt ahci_enable_port_intrs(ahci_ctl_t *ahci_ctlp,
51522fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
51532fcbc377Syt {
51542fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
51552fcbc377Syt 	    "ahci_enable_port_intrs enter, port %d", port);
51562fcbc377Syt 
51572fcbc377Syt 	/*
51582fcbc377Syt 	 * Clear port interrupt status before enabling interrupt
51592fcbc377Syt 	 */
51602fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
51612fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port),
51622fcbc377Syt 	    AHCI_PORT_INTR_MASK);
51632fcbc377Syt 
51642fcbc377Syt 	/*
51652fcbc377Syt 	 * Clear the pending bit from IS.IPS
51662fcbc377Syt 	 */
51672fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
51682fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp), (1 << port));
51692fcbc377Syt 
51702fcbc377Syt 	/*
51712fcbc377Syt 	 * Enable the following interrupts:
51722fcbc377Syt 	 *	Device to Host Register FIS Interrupt (DHRS)
51732fcbc377Syt 	 *	PIO Setup FIS Interrupt (PSS)
517482263d52Syt 	 *	Set Device Bits Interrupt (SDBS)
51752fcbc377Syt 	 *	Unknown FIS Interrupt (UFS)
51762fcbc377Syt 	 *	Port Connect Change Status (PCS)
51772fcbc377Syt 	 *	PhyRdy Change Status (PRCS)
51782fcbc377Syt 	 *	Overflow Status (OFS)
51792fcbc377Syt 	 *	Interface Non-fatal Error Status (INFS)
51802fcbc377Syt 	 *	Interface Fatal Error Status (IFS)
51812fcbc377Syt 	 *	Host Bus Data Error Status (HBDS)
51822fcbc377Syt 	 *	Host Bus Fatal Error Status (HBFS)
51832fcbc377Syt 	 *	Task File Error Status (TFES)
51842fcbc377Syt 	 */
51852fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
51862fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port),
51872fcbc377Syt 	    (AHCI_INTR_STATUS_DHRS |
51882fcbc377Syt 	    AHCI_INTR_STATUS_PSS |
518982263d52Syt 	    AHCI_INTR_STATUS_SDBS |
51902fcbc377Syt 	    AHCI_INTR_STATUS_UFS |
519168d33a25Syt 	    AHCI_INTR_STATUS_DPS |
51922fcbc377Syt 	    AHCI_INTR_STATUS_PCS |
51932fcbc377Syt 	    AHCI_INTR_STATUS_PRCS |
51942fcbc377Syt 	    AHCI_INTR_STATUS_OFS |
51952fcbc377Syt 	    AHCI_INTR_STATUS_INFS |
51962fcbc377Syt 	    AHCI_INTR_STATUS_IFS |
51972fcbc377Syt 	    AHCI_INTR_STATUS_HBDS |
51982fcbc377Syt 	    AHCI_INTR_STATUS_HBFS |
51992fcbc377Syt 	    AHCI_INTR_STATUS_TFES));
52002fcbc377Syt }
52012fcbc377Syt 
52022fcbc377Syt /*
52032fcbc377Syt  * Enable interrupts for all the ports.
52042fcbc377Syt  *
52052fcbc377Syt  * WARNING!!! ahcictl_mutex should be acquired before the function
52062fcbc377Syt  * is called.
52072fcbc377Syt  */
52082fcbc377Syt static void
52092fcbc377Syt ahci_enable_all_intrs(ahci_ctl_t *ahci_ctlp)
52102fcbc377Syt {
52112fcbc377Syt 	uint32_t ghc_control;
52122fcbc377Syt 
52132fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter");
52142fcbc377Syt 
52152fcbc377Syt 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
52162fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
52172fcbc377Syt 
52182fcbc377Syt 	ghc_control |= AHCI_HBA_GHC_IE;
52192fcbc377Syt 
52202fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
52212fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
52222fcbc377Syt }
52232fcbc377Syt 
52242fcbc377Syt /*
52252fcbc377Syt  * Disable interrupts for a particular port.
52262fcbc377Syt  *
52272fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
52282fcbc377Syt  * is called.
52292fcbc377Syt  */
52302fcbc377Syt /* ARGSUSED */
52312fcbc377Syt static void
52322fcbc377Syt ahci_disable_port_intrs(ahci_ctl_t *ahci_ctlp,
52332fcbc377Syt     ahci_port_t *ahci_portp, uint8_t port)
52342fcbc377Syt {
52352fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
52362fcbc377Syt 	    "ahci_disable_port_intrs enter, port %d", port);
52372fcbc377Syt 
52382fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
52392fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), 0);
52402fcbc377Syt }
52412fcbc377Syt 
52422fcbc377Syt /*
52432fcbc377Syt  * Disable interrupts for the whole HBA.
52442fcbc377Syt  *
52452fcbc377Syt  * The global bit is cleared, then all interrupt sources from all
52462fcbc377Syt  * ports are disabled.
52472fcbc377Syt  *
52482fcbc377Syt  * WARNING!!! ahcictl_mutex should be acquired before the function
52492fcbc377Syt  * is called.
52502fcbc377Syt  */
52512fcbc377Syt static void
52522fcbc377Syt ahci_disable_all_intrs(ahci_ctl_t *ahci_ctlp)
52532fcbc377Syt {
52542fcbc377Syt 	uint32_t ghc_control;
52552fcbc377Syt 
52562fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter");
52572fcbc377Syt 
52582fcbc377Syt 	ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
52592fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
52602fcbc377Syt 
52612fcbc377Syt 	ghc_control &= ~ AHCI_HBA_GHC_IE;
52622fcbc377Syt 
52632fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
52642fcbc377Syt 	    (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
52652fcbc377Syt }
52662fcbc377Syt 
52672fcbc377Syt /*
52682fcbc377Syt  * Handle INTx and legacy interrupts.
52692fcbc377Syt  */
52702fcbc377Syt static int
52712fcbc377Syt ahci_add_legacy_intrs(ahci_ctl_t *ahci_ctlp)
52722fcbc377Syt {
52732fcbc377Syt 	dev_info_t	*dip = ahci_ctlp->ahcictl_dip;
52742fcbc377Syt 	int		actual, count = 0;
52752fcbc377Syt 	int		x, y, rc, inum = 0;
52762fcbc377Syt 
52772fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY|AHCIDBG_INIT, ahci_ctlp,
52782fcbc377Syt 	    "ahci_add_legacy_intrs enter");
52792fcbc377Syt 
52802fcbc377Syt 	/* get number of interrupts. */
52812fcbc377Syt 	rc = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count);
52822fcbc377Syt 	if ((rc != DDI_SUCCESS) || (count == 0)) {
52832fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
52842fcbc377Syt 		    "ddi_intr_get_nintrs() failed, "
52852fcbc377Syt 		    "rc %d count %d\n", rc, count);
52862fcbc377Syt 		return (DDI_FAILURE);
52872fcbc377Syt 	}
52882fcbc377Syt 
52892fcbc377Syt 	/* Allocate an array of interrupt handles. */
52902fcbc377Syt 	ahci_ctlp->ahcictl_intr_size = count * sizeof (ddi_intr_handle_t);
52912fcbc377Syt 	ahci_ctlp->ahcictl_intr_htable =
52922fcbc377Syt 	    kmem_zalloc(ahci_ctlp->ahcictl_intr_size, KM_SLEEP);
52932fcbc377Syt 
52942fcbc377Syt 	/* call ddi_intr_alloc(). */
52952fcbc377Syt 	rc = ddi_intr_alloc(dip, ahci_ctlp->ahcictl_intr_htable,
52962fcbc377Syt 	    DDI_INTR_TYPE_FIXED,
52972fcbc377Syt 	    inum, count, &actual, DDI_INTR_ALLOC_STRICT);
52982fcbc377Syt 
52992fcbc377Syt 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
53002fcbc377Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53012fcbc377Syt 		    "ddi_intr_alloc() failed, rc %d\n", rc);
53022fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
53032fcbc377Syt 		    ahci_ctlp->ahcictl_intr_size);
53042fcbc377Syt 		return (DDI_FAILURE);
53052fcbc377Syt 	}
53062fcbc377Syt 
53072fcbc377Syt 	if (actual < count) {
53082fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53092fcbc377Syt 		    "Requested: %d, Received: %d", count, actual);
53102fcbc377Syt 
53112fcbc377Syt 		for (x = 0; x < actual; x++) {
53122fcbc377Syt 			(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[x]);
53132fcbc377Syt 		}
53142fcbc377Syt 
53152fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
53162fcbc377Syt 		    ahci_ctlp->ahcictl_intr_size);
53172fcbc377Syt 		return (DDI_FAILURE);
53182fcbc377Syt 	}
53192fcbc377Syt 
53202fcbc377Syt 	ahci_ctlp->ahcictl_intr_cnt = actual;
53212fcbc377Syt 
53222fcbc377Syt 	/* Get intr priority. */
53232fcbc377Syt 	if (ddi_intr_get_pri(ahci_ctlp->ahcictl_intr_htable[0],
53242fcbc377Syt 	    &ahci_ctlp->ahcictl_intr_pri) != DDI_SUCCESS) {
53252fcbc377Syt 		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53262fcbc377Syt 		    "ddi_intr_get_pri() failed");
53272fcbc377Syt 
53282fcbc377Syt 		for (x = 0; x < actual; x++) {
53292fcbc377Syt 			(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[x]);
53302fcbc377Syt 		}
53312fcbc377Syt 
53322fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
53332fcbc377Syt 		    ahci_ctlp->ahcictl_intr_size);
53342fcbc377Syt 		return (DDI_FAILURE);
53352fcbc377Syt 	}
53362fcbc377Syt 
53372fcbc377Syt 	/* Test for high level interrupt. */
53382fcbc377Syt 	if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
53392fcbc377Syt 		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53402fcbc377Syt 		    "ahci_add_legacy_intrs: Hi level intr not supported");
53412fcbc377Syt 
53422fcbc377Syt 		for (x = 0; x < actual; x++) {
53432fcbc377Syt 			(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[x]);
53442fcbc377Syt 		}
53452fcbc377Syt 
53462fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
53472fcbc377Syt 		    sizeof (ddi_intr_handle_t));
53482fcbc377Syt 
53492fcbc377Syt 		return (DDI_FAILURE);
53502fcbc377Syt 	}
53512fcbc377Syt 
53522fcbc377Syt 	/* Call ddi_intr_add_handler(). */
53532fcbc377Syt 	for (x = 0; x < actual; x++) {
53542fcbc377Syt 		if (ddi_intr_add_handler(ahci_ctlp->ahcictl_intr_htable[x],
53552fcbc377Syt 		    ahci_intr, (caddr_t)ahci_ctlp, NULL) != DDI_SUCCESS) {
53562fcbc377Syt 			AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53572fcbc377Syt 			    "ddi_intr_add_handler() failed");
53582fcbc377Syt 
53592fcbc377Syt 			for (y = 0; y < actual; y++) {
53602fcbc377Syt 				(void) ddi_intr_free(
53612fcbc377Syt 				    ahci_ctlp->ahcictl_intr_htable[y]);
53622fcbc377Syt 			}
53632fcbc377Syt 
53642fcbc377Syt 			kmem_free(ahci_ctlp->ahcictl_intr_htable,
53652fcbc377Syt 			    ahci_ctlp->ahcictl_intr_size);
53662fcbc377Syt 			return (DDI_FAILURE);
53672fcbc377Syt 		}
53682fcbc377Syt 	}
53692fcbc377Syt 
53702fcbc377Syt 	/* Call ddi_intr_enable() for legacy interrupts. */
53712fcbc377Syt 	for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
53722fcbc377Syt 		(void) ddi_intr_enable(ahci_ctlp->ahcictl_intr_htable[x]);
53732fcbc377Syt 	}
53742fcbc377Syt 
53752fcbc377Syt 	return (DDI_SUCCESS);
53762fcbc377Syt }
53772fcbc377Syt 
53782fcbc377Syt /*
53792fcbc377Syt  * Handle MSI interrupts.
53802fcbc377Syt  */
53812fcbc377Syt static int
53822fcbc377Syt ahci_add_msi_intrs(ahci_ctl_t *ahci_ctlp)
53832fcbc377Syt {
53842fcbc377Syt 	dev_info_t *dip = ahci_ctlp->ahcictl_dip;
53852fcbc377Syt 	int		count, avail, actual;
53862fcbc377Syt 	int		x, y, rc, inum = 0;
53872fcbc377Syt 
53882fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY|AHCIDBG_INIT, ahci_ctlp,
53892fcbc377Syt 	    "ahci_add_msi_intrs enter");
53902fcbc377Syt 
53912fcbc377Syt 	/* get number of interrupts. */
53922fcbc377Syt 	rc = ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_MSI, &count);
53932fcbc377Syt 	if ((rc != DDI_SUCCESS) || (count == 0)) {
53942fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
53952fcbc377Syt 		    "ddi_intr_get_nintrs() failed, "
53962fcbc377Syt 		    "rc %d count %d\n", rc, count);
53972fcbc377Syt 		return (DDI_FAILURE);
53982fcbc377Syt 	}
53992fcbc377Syt 
54002fcbc377Syt 	/* get number of available interrupts. */
54012fcbc377Syt 	rc = ddi_intr_get_navail(dip, DDI_INTR_TYPE_MSI, &avail);
54022fcbc377Syt 	if ((rc != DDI_SUCCESS) || (avail == 0)) {
54032fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54042fcbc377Syt 		    "ddi_intr_get_navail() failed, "
54052fcbc377Syt 		    "rc %d avail %d\n", rc, avail);
54062fcbc377Syt 		return (DDI_FAILURE);
54072fcbc377Syt 	}
54082fcbc377Syt 
54092fcbc377Syt 	if (avail < count) {
54102fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54112fcbc377Syt 		    "ddi_intr_get_nvail returned %d, navail() returned %d",
54122fcbc377Syt 		    count, avail);
54132fcbc377Syt 	}
54142fcbc377Syt 
54152fcbc377Syt 	/* Allocate an array of interrupt handles. */
54162fcbc377Syt 	ahci_ctlp->ahcictl_intr_size = count * sizeof (ddi_intr_handle_t);
54172fcbc377Syt 	ahci_ctlp->ahcictl_intr_htable =
54182fcbc377Syt 	    kmem_alloc(ahci_ctlp->ahcictl_intr_size, KM_SLEEP);
54192fcbc377Syt 
54202fcbc377Syt 	/* call ddi_intr_alloc(). */
54212fcbc377Syt 	rc = ddi_intr_alloc(dip, ahci_ctlp->ahcictl_intr_htable,
54222fcbc377Syt 	    DDI_INTR_TYPE_MSI, inum, count, &actual, DDI_INTR_ALLOC_NORMAL);
54232fcbc377Syt 
54242fcbc377Syt 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
54252fcbc377Syt 		AHCIDBG1(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54262fcbc377Syt 		    "ddi_intr_alloc() failed, rc %d\n", rc);
54272fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
54282fcbc377Syt 		    ahci_ctlp->ahcictl_intr_size);
54292fcbc377Syt 		return (DDI_FAILURE);
54302fcbc377Syt 	}
54312fcbc377Syt 
54322fcbc377Syt 	/* use interrupt count returned */
54332fcbc377Syt 	if (actual < count) {
54342fcbc377Syt 		AHCIDBG2(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54352fcbc377Syt 		    "Requested: %d, Received: %d", count, actual);
54362fcbc377Syt 	}
54372fcbc377Syt 
54382fcbc377Syt 	ahci_ctlp->ahcictl_intr_cnt = actual;
54392fcbc377Syt 
54402fcbc377Syt 	/*
54412fcbc377Syt 	 * Get priority for first msi, assume remaining are all the same.
54422fcbc377Syt 	 */
54432fcbc377Syt 	if (ddi_intr_get_pri(ahci_ctlp->ahcictl_intr_htable[0],
54442fcbc377Syt 	    &ahci_ctlp->ahcictl_intr_pri) != DDI_SUCCESS) {
54452fcbc377Syt 		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54462fcbc377Syt 		    "ddi_intr_get_pri() failed");
54472fcbc377Syt 
54482fcbc377Syt 		/* Free already allocated intr. */
54492fcbc377Syt 		for (y = 0; y < actual; y++) {
54502fcbc377Syt 			(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[y]);
54512fcbc377Syt 		}
54522fcbc377Syt 
54532fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
54542fcbc377Syt 		    ahci_ctlp->ahcictl_intr_size);
54552fcbc377Syt 		return (DDI_FAILURE);
54562fcbc377Syt 	}
54572fcbc377Syt 
54582fcbc377Syt 	/* Test for high level interrupt. */
54592fcbc377Syt 	if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
54602fcbc377Syt 		AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54612fcbc377Syt 		    "ahci_add_msi_intrs: Hi level intr not supported");
54622fcbc377Syt 
54632fcbc377Syt 		/* Free already allocated intr. */
54642fcbc377Syt 		for (y = 0; y < actual; y++) {
54652fcbc377Syt 			(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[y]);
54662fcbc377Syt 		}
54672fcbc377Syt 
54682fcbc377Syt 		kmem_free(ahci_ctlp->ahcictl_intr_htable,
54692fcbc377Syt 		    sizeof (ddi_intr_handle_t));
54702fcbc377Syt 
54712fcbc377Syt 		return (DDI_FAILURE);
54722fcbc377Syt 	}
54732fcbc377Syt 
54742fcbc377Syt 	/* Call ddi_intr_add_handler(). */
54752fcbc377Syt 	for (x = 0; x < actual; x++) {
54762fcbc377Syt 		if (ddi_intr_add_handler(ahci_ctlp->ahcictl_intr_htable[x],
54772fcbc377Syt 		    ahci_intr, (caddr_t)ahci_ctlp, NULL) != DDI_SUCCESS) {
54782fcbc377Syt 			AHCIDBG0(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
54792fcbc377Syt 			    "ddi_intr_add_handler() failed");
54802fcbc377Syt 
54812fcbc377Syt 			/* Free already allocated intr. */
54822fcbc377Syt 			for (y = 0; y < actual; y++) {
54832fcbc377Syt 				(void) ddi_intr_free(
54842fcbc377Syt 				    ahci_ctlp->ahcictl_intr_htable[y]);
54852fcbc377Syt 			}
54862fcbc377Syt 
54872fcbc377Syt 			kmem_free(ahci_ctlp->ahcictl_intr_htable,
54882fcbc377Syt 			    ahci_ctlp->ahcictl_intr_size);
54892fcbc377Syt 			return (DDI_FAILURE);
54902fcbc377Syt 		}
54912fcbc377Syt 	}
54922fcbc377Syt 
54932fcbc377Syt 
54942fcbc377Syt 	(void) ddi_intr_get_cap(ahci_ctlp->ahcictl_intr_htable[0],
54952fcbc377Syt 	    &ahci_ctlp->ahcictl_intr_cap);
54962fcbc377Syt 
54972fcbc377Syt 	if (ahci_ctlp->ahcictl_intr_cap & DDI_INTR_FLAG_BLOCK) {
54982fcbc377Syt 		/* Call ddi_intr_block_enable() for MSI. */
54992fcbc377Syt 		(void) ddi_intr_block_enable(ahci_ctlp->ahcictl_intr_htable,
55002fcbc377Syt 		    ahci_ctlp->ahcictl_intr_cnt);
55012fcbc377Syt 	} else {
55022fcbc377Syt 		/* Call ddi_intr_enable() for MSI non block enable. */
55032fcbc377Syt 		for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
55042fcbc377Syt 			(void) ddi_intr_enable(
55052fcbc377Syt 			    ahci_ctlp->ahcictl_intr_htable[x]);
55062fcbc377Syt 		}
55072fcbc377Syt 	}
55082fcbc377Syt 
55092fcbc377Syt 	return (DDI_SUCCESS);
55102fcbc377Syt }
55112fcbc377Syt 
55122fcbc377Syt /*
55132fcbc377Syt  * Removes the registered interrupts irrespective of whether they
55142fcbc377Syt  * were legacy or MSI.
55152fcbc377Syt  *
55162fcbc377Syt  * WARNING!!! The controller interrupts must be disabled before calling
55172fcbc377Syt  * this routine.
55182fcbc377Syt  */
55192fcbc377Syt static void
55202fcbc377Syt ahci_rem_intrs(ahci_ctl_t *ahci_ctlp)
55212fcbc377Syt {
55222fcbc377Syt 	int x;
55232fcbc377Syt 
55242fcbc377Syt 	AHCIDBG0(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered");
55252fcbc377Syt 
55262fcbc377Syt 	/* Disable all interrupts. */
55272fcbc377Syt 	if ((ahci_ctlp->ahcictl_intr_type == DDI_INTR_TYPE_MSI) &&
55282fcbc377Syt 	    (ahci_ctlp->ahcictl_intr_cap & DDI_INTR_FLAG_BLOCK)) {
55292fcbc377Syt 		/* Call ddi_intr_block_disable(). */
55302fcbc377Syt 		(void) ddi_intr_block_disable(ahci_ctlp->ahcictl_intr_htable,
55312fcbc377Syt 		    ahci_ctlp->ahcictl_intr_cnt);
55322fcbc377Syt 	} else {
55332fcbc377Syt 		for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
55342fcbc377Syt 			(void) ddi_intr_disable(
55352fcbc377Syt 			    ahci_ctlp->ahcictl_intr_htable[x]);
55362fcbc377Syt 		}
55372fcbc377Syt 	}
55382fcbc377Syt 
55392fcbc377Syt 	/* Call ddi_intr_remove_handler(). */
55402fcbc377Syt 	for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
55412fcbc377Syt 		(void) ddi_intr_remove_handler(
55422fcbc377Syt 		    ahci_ctlp->ahcictl_intr_htable[x]);
55432fcbc377Syt 		(void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[x]);
55442fcbc377Syt 	}
55452fcbc377Syt 
55462fcbc377Syt 	kmem_free(ahci_ctlp->ahcictl_intr_htable, ahci_ctlp->ahcictl_intr_size);
55472fcbc377Syt }
55482fcbc377Syt 
55492fcbc377Syt /*
555068d33a25Syt  * This routine tries to put port into P:NotRunning state by clearing
555168d33a25Syt  * PxCMD.ST. HBA will clear PxCI to 0h, PxSACT to 0h, PxCMD.CCS to 0h
555268d33a25Syt  * and PxCMD.CR to '0'.
55532fcbc377Syt  *
55542fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
55552fcbc377Syt  * is called.
55562fcbc377Syt  */
55572fcbc377Syt /* ARGSUSED */
55582fcbc377Syt static int
555968d33a25Syt ahci_put_port_into_notrunning_state(ahci_ctl_t *ahci_ctlp,
556068d33a25Syt     ahci_port_t *ahci_portp, uint8_t port)
55612fcbc377Syt {
55622fcbc377Syt 	uint32_t port_cmd_status;
55632fcbc377Syt 	int loop_count;
55642fcbc377Syt 
55652fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
556668d33a25Syt 	    "ahci_put_port_into_notrunning_state enter: port %d", port);
55672fcbc377Syt 
55682fcbc377Syt 	port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
55692fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
55702fcbc377Syt 
55712fcbc377Syt 	port_cmd_status &= ~AHCI_CMD_STATUS_ST;
55722fcbc377Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
55732fcbc377Syt 	    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), port_cmd_status);
55742fcbc377Syt 
55752fcbc377Syt 	/* Wait until PxCMD.CR is cleared */
55762fcbc377Syt 	loop_count = 0;
55772fcbc377Syt 	do {
55782fcbc377Syt 		port_cmd_status =
55792fcbc377Syt 		    ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
55802fcbc377Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
55812fcbc377Syt 
55822fcbc377Syt 		if (loop_count++ > AHCI_POLLRATE_PORT_IDLE) {
55832fcbc377Syt 			AHCIDBG2(AHCIDBG_INIT, ahci_ctlp,
55842fcbc377Syt 			    "clearing port %d CMD.CR timeout, "
55852fcbc377Syt 			    "port_cmd_status = 0x%x", port,
55862fcbc377Syt 			    port_cmd_status);
55872fcbc377Syt 			/*
55882fcbc377Syt 			 * We are effectively timing out after 0.5 sec.
55892fcbc377Syt 			 * This value is specified in AHCI spec.
55902fcbc377Syt 			 */
55912fcbc377Syt 			break;
55922fcbc377Syt 		}
55932fcbc377Syt 
55942fcbc377Syt 	/* Wait for 10 millisec */
55952fcbc377Syt #ifndef __lock_lint
55962fcbc377Syt 		delay(AHCI_10MS_TICKS);
55972fcbc377Syt #endif /* __lock_lint */
55982fcbc377Syt 
55992fcbc377Syt 	} while (port_cmd_status & AHCI_CMD_STATUS_CR);
56002fcbc377Syt 
560168d33a25Syt 	ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_STARTED;
56022fcbc377Syt 
560368d33a25Syt 	if (port_cmd_status & AHCI_CMD_STATUS_CR) {
56042fcbc377Syt 		AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
560568d33a25Syt 		    "ahci_put_port_into_notrunning_state: failed to clear "
560668d33a25Syt 		    "PxCMD.CR to '0' after loop count: %d, and "
560768d33a25Syt 		    "port_cmd_status = 0x%x", loop_count, port_cmd_status);
56082fcbc377Syt 		return (AHCI_FAILURE);
56092fcbc377Syt 	} else {
561068d33a25Syt 		AHCIDBG2(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
561168d33a25Syt 		    "ahci_put_port_into_notrunning_state: succeeded to clear "
561268d33a25Syt 		    "PxCMD.CR to '0' after loop count: %d, and "
561368d33a25Syt 		    "port_cmd_status = 0x%x", loop_count, port_cmd_status);
56142fcbc377Syt 		return (AHCI_SUCCESS);
56152fcbc377Syt 	}
56162fcbc377Syt }
56172fcbc377Syt 
56182fcbc377Syt /*
561968d33a25Syt  * First clear PxCMD.ST, and then check PxTFD. If both PxTFD.STS.BSY
562068d33a25Syt  * and PxTFD.STS.DRQ cleared to '0', it means the device is in a
562168d33a25Syt  * stable state, then set PxCMD.ST to '1' to start the port directly.
562268d33a25Syt  * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue a
562368d33a25Syt  * COMRESET to the device to put it in an idle state.
562468d33a25Syt  *
562568d33a25Syt  * The fifth argument returns whether the port reset is involved during
562668d33a25Syt  * the process.
562768d33a25Syt  *
562868d33a25Syt  * The routine will be called under six scenarios:
56292fcbc377Syt  *	1. Initialize the port
56302fcbc377Syt  *	2. To abort the packet(s)
56312fcbc377Syt  *	3. To reset the port
563268d33a25Syt  *	4. To activate the port
563368d33a25Syt  *	5. Fatal error recovery
563468d33a25Syt  *	6. To abort the timeout packet(s)
56352fcbc377Syt  *
56362fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function
563768d33a25Syt  * is called. And ahciport_mutex will be released before the reset
563868d33a25Syt  * event is reported to sata module by calling sata_hba_event_notify,
563968d33a25Syt  * and then be acquired again later.
564082263d52Syt  *
564182263d52Syt  * NOTES!!! During this procedure, PxSERR register will be cleared, and
564282263d52Syt  * according to the spec, the clearance of three bits will also clear
564382263d52Syt  * three interrupt status bits.
564482263d52Syt  *	1. PxSERR.DIAG.F will clear PxIS.UFS
564582263d52Syt  *	2. PxSERR.DIAG.X will clear PxIS.PCS
564682263d52Syt  *	3. PxSERR.DIAG.N will clear PxIS.PRCS
564782263d52Syt  *
564882263d52Syt  * Among these three interrupt events, the driver needs to take care of
564982263d52Syt  * PxIS.PRCS, which is the hot plug event. When the driver found out
565082263d52Syt  * a device was unplugged, it will call the interrupt handler.
56512fcbc377Syt  */
56522fcbc377Syt static int
56532fcbc377Syt ahci_restart_port_wait_till_ready(ahci_ctl_t *ahci_ctlp,
565468d33a25Syt     ahci_port_t *ahci_portp, uint8_t port, int flag, int *reset_flag)
56552fcbc377Syt {
565682263d52Syt 	uint32_t port_sstatus;
56572fcbc377Syt 	uint32_t task_file_status;
56582fcbc377Syt 	sata_device_t sdevice;
56592fcbc377Syt 	int rval;
566082263d52Syt 	int dev_exists_begin = 0;
566182263d52Syt 	int dev_exists_end = 0;
56622fcbc377Syt 
56632fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
56642fcbc377Syt 	    "ahci_restart_port_wait_till_ready: port %d enter", port);
56652fcbc377Syt 
566682263d52Syt 	if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE)
566782263d52Syt 		dev_exists_begin = 1;
56682fcbc377Syt 
566982263d52Syt 	/* First clear PxCMD.ST */
567068d33a25Syt 	rval = ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
567168d33a25Syt 	    port);
567268d33a25Syt 	if (rval != AHCI_SUCCESS)
567368d33a25Syt 		/*
567468d33a25Syt 		 * If PxCMD.CR does not clear within a reasonable time, it
567568d33a25Syt 		 * may assume the interface is in a hung condition and may
567668d33a25Syt 		 * continue with issuing the port reset.
567768d33a25Syt 		 */
567868d33a25Syt 		goto reset;
56792fcbc377Syt 
568068d33a25Syt 	/* Then clear PxSERR */
568168d33a25Syt 	ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
568268d33a25Syt 	    (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
568368d33a25Syt 	    AHCI_SERROR_CLEAR_ALL);
56842fcbc377Syt 
568582263d52Syt 	/* Then get PxTFD */
568668d33a25Syt 	task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
568768d33a25Syt 	    (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
56882fcbc377Syt 
568968d33a25Syt 	/*
569068d33a25Syt 	 * Check whether the device is in a stable status, if yes,
569168d33a25Syt 	 * then start the port directly. However for ahci_tran_dport_reset,
569268d33a25Syt 	 * we may have to perform a port reset.
569368d33a25Syt 	 */
569468d33a25Syt 	if (!(task_file_status & (AHCI_TFD_STS_BSY | AHCI_TFD_STS_DRQ)) &&
569568d33a25Syt 	    !(flag & AHCI_PORT_RESET))
56962fcbc377Syt 		goto out;
56972fcbc377Syt 
569868d33a25Syt reset:
569968d33a25Syt 	/*
570068d33a25Syt 	 * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue
570168d33a25Syt 	 * a COMRESET to the device
570268d33a25Syt 	 */
57032fcbc377Syt 	rval = ahci_port_reset(ahci_ctlp, ahci_portp, port);
570468d33a25Syt 	if (rval != AHCI_SUCCESS)
57052fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
57062fcbc377Syt 		    "ahci_restart_port_wait_till_ready: port %d failed",
57072fcbc377Syt 		    port);
570868d33a25Syt 
570968d33a25Syt 	if (reset_flag != NULL)
571068d33a25Syt 		*reset_flag = 1;
57112fcbc377Syt 
57122fcbc377Syt 	/* Indicate to the framework that a reset has happened. */
571382263d52Syt 	if ((ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) &&
571482263d52Syt 	    !(flag & AHCI_RESET_NO_EVENTS_UP)) {
571582263d52Syt 		/* Set the reset in progress flag */
571682263d52Syt 		ahci_portp->ahciport_reset_in_progress = 1;
57172fcbc377Syt 
57182fcbc377Syt 		bzero((void *)&sdevice, sizeof (sata_device_t));
571909121340Syt 		sdevice.satadev_addr.cport =
572009121340Syt 		    ahci_ctlp->ahcictl_port_to_cport[port];
572168d33a25Syt 		sdevice.satadev_addr.pmport = 0;
572268d33a25Syt 		sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
57232fcbc377Syt 
57242fcbc377Syt 		sdevice.satadev_state = SATA_DSTATE_RESET |
57252fcbc377Syt 		    SATA_DSTATE_PWR_ACTIVE;
57262fcbc377Syt 		if (ahci_ctlp->ahcictl_sata_hba_tran) {
57272fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
57282fcbc377Syt 			sata_hba_event_notify(
57292fcbc377Syt 			    ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
57302fcbc377Syt 			    &sdevice,
57312fcbc377Syt 			    SATA_EVNT_DEVICE_RESET);
57322fcbc377Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
57332fcbc377Syt 		}
57342fcbc377Syt 
573568d33a25Syt 		AHCIDBG1(AHCIDBG_EVENT, ahci_ctlp,
573668d33a25Syt 		    "port %d sending event up: SATA_EVNT_RESET", port);
573782263d52Syt 	} else {
573882263d52Syt 		ahci_portp->ahciport_reset_in_progress = 0;
57392fcbc377Syt 	}
574082263d52Syt 
57412fcbc377Syt out:
574268d33a25Syt 	/* Start the port */
57432fcbc377Syt 	if (!(flag & AHCI_PORT_INIT)) {
574468d33a25Syt 		(void) ahci_start_port(ahci_ctlp, ahci_portp, port);
574582263d52Syt 	}
574682263d52Syt 
574782263d52Syt 	/* SStatus tells the presence of device. */
574882263d52Syt 	port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
574982263d52Syt 	    (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
575082263d52Syt 
575182263d52Syt 	if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
575282263d52Syt 		dev_exists_end = 1;
575382263d52Syt 		ASSERT(ahci_portp->ahciport_device_type != SATA_DTYPE_NONE);
575482263d52Syt 	}
575582263d52Syt 
575682263d52Syt 	/* Check whether a hot plug event happened */
575782263d52Syt 	if (dev_exists_begin == 1 && dev_exists_end == 0) {
575882263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
575982263d52Syt 		    "ahci_restart_port_wait_till_ready: port %d "
576082263d52Syt 		    "device is removed", port);
576182263d52Syt 		ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_NODEV;
576282263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
576382263d52Syt 		    "ahci_restart_port_wait_till_ready: port %d "
576482263d52Syt 		    "AHCI_PORT_FLAG_NODEV flag is set", port);
576582263d52Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
576682263d52Syt 		(void) ahci_intr_phyrdy_change(ahci_ctlp, ahci_portp, port);
576782263d52Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
57682fcbc377Syt 	}
57692fcbc377Syt 
57702fcbc377Syt 	return (rval);
57712fcbc377Syt }
57722fcbc377Syt 
57732fcbc377Syt /*
577468d33a25Syt  * This routine may be called under four scenarios:
577568d33a25Syt  *	a) do the recovery from fatal error
57762fcbc377Syt  *	b) or we need to timeout some commands
57772fcbc377Syt  *	c) or we need to abort some commands
57782fcbc377Syt  *	d) or we need reset device/port/controller
57792fcbc377Syt  *
57802fcbc377Syt  * In all these scenarios, we need to send any pending unfinished
57812fcbc377Syt  * commands up to sata framework.
57822fcbc377Syt  *
578368d33a25Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
57842fcbc377Syt  */
57852fcbc377Syt static void
57862fcbc377Syt ahci_mop_commands(ahci_ctl_t *ahci_ctlp,
57872fcbc377Syt     ahci_port_t *ahci_portp,
57882fcbc377Syt     uint8_t port,
57892fcbc377Syt     uint32_t slot_status,
57902fcbc377Syt     uint32_t failed_tags,
57912fcbc377Syt     uint32_t timeout_tags,
57922fcbc377Syt     uint32_t aborted_tags,
57932fcbc377Syt     uint32_t reset_tags)
57942fcbc377Syt {
579582263d52Syt 	uint32_t finished_tags = 0;
579682263d52Syt 	uint32_t unfinished_tags = 0;
57972fcbc377Syt 	int tmp_slot;
57982fcbc377Syt 	sata_pkt_t *satapkt;
579982263d52Syt 	int ncq_cmd_in_progress = 0;
580082263d52Syt 	int err_retri_cmd_in_progress = 0;
58012fcbc377Syt 
58022fcbc377Syt 	AHCIDBG2(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
58032fcbc377Syt 	    "ahci_mop_commands entered: port: %d slot_status: 0x%x",
58042fcbc377Syt 	    port, slot_status);
58052fcbc377Syt 
58062fcbc377Syt 	AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
58072fcbc377Syt 	    "ahci_mop_commands: failed_tags: 0x%x, "
58082fcbc377Syt 	    "timeout_tags: 0x%x aborted_tags: 0x%x, "
58092fcbc377Syt 	    "reset_tags: 0x%x", failed_tags,
58102fcbc377Syt 	    timeout_tags, aborted_tags, reset_tags);
58112fcbc377Syt 
581282263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
581382263d52Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
581482263d52Syt 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
58152fcbc377Syt 
581682263d52Syt 		unfinished_tags = slot_status &
581782263d52Syt 		    AHCI_SLOT_MASK(ahci_ctlp) &
581882263d52Syt 		    ~failed_tags &
581982263d52Syt 		    ~aborted_tags &
582082263d52Syt 		    ~reset_tags &
582182263d52Syt 		    ~timeout_tags;
582282263d52Syt 	}
582382263d52Syt 
582482263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
582582263d52Syt 		ncq_cmd_in_progress = 1;
582682263d52Syt 		finished_tags = ahci_portp->ahciport_pending_ncq_tags &
582782263d52Syt 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
582882263d52Syt 
582982263d52Syt 		unfinished_tags = slot_status &
583082263d52Syt 		    AHCI_NCQ_SLOT_MASK(ahci_portp) &
583182263d52Syt 		    ~failed_tags &
583282263d52Syt 		    ~aborted_tags &
583382263d52Syt 		    ~reset_tags &
583482263d52Syt 		    ~timeout_tags;
583582263d52Syt 	}
58362fcbc377Syt 
58372fcbc377Syt 	/*
583882263d52Syt 	 * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT is set,
583982263d52Syt 	 * it means REQUEST SENSE or READ LOG EXT command doesn't complete
584082263d52Syt 	 * successfully due to one of the following three conditions:
584168d33a25Syt 	 *
584268d33a25Syt 	 *	1. Fatal error - failed_tags includes its slot
584368d33a25Syt 	 *	2. Timed out - timeout_tags includes its slot
584468d33a25Syt 	 *	3. Aborted when hot unplug - aborted_tags includes its slot
584582263d52Syt 	 *
584682263d52Syt 	 * Please note that the command is always sent down in Slot 0
58472fcbc377Syt 	 */
584882263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
584982263d52Syt 		err_retri_cmd_in_progress = 1;
585082263d52Syt 		AHCIDBG1(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp,
585182263d52Syt 		    "ahci_mop_commands is called for port %d while "
585282263d52Syt 		    "REQUEST SENSE or READ LOG EXT for error retrieval "
585382263d52Syt 		    "is being executed", port);
585468d33a25Syt 		ASSERT(ahci_portp->ahciport_mop_in_progress > 1);
585582263d52Syt 		ASSERT(slot_status == 0x1);
58562fcbc377Syt 	}
58572fcbc377Syt 
585868d33a25Syt 	/* Send up finished packets with SATA_PKT_COMPLETED */
58592fcbc377Syt 	while (finished_tags) {
58602fcbc377Syt 		tmp_slot = ddi_ffs(finished_tags) - 1;
58612fcbc377Syt 		if (tmp_slot == -1) {
58622fcbc377Syt 			break;
58632fcbc377Syt 		}
58642fcbc377Syt 
58652fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
58662fcbc377Syt 		ASSERT(satapkt != NULL);
58672fcbc377Syt 
58682fcbc377Syt 		AHCIDBG1(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: "
58692fcbc377Syt 		    "sending up pkt 0x%p with SATA_PKT_COMPLETED",
58702fcbc377Syt 		    (void *)satapkt);
58712fcbc377Syt 
587268d33a25Syt 		/*
587368d33a25Syt 		 * Cannot fetch the return register content since the port
587468d33a25Syt 		 * was restarted, so the corresponding tag will be set to
587568d33a25Syt 		 * aborted tags.
587668d33a25Syt 		 */
587768d33a25Syt 		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
587868d33a25Syt 			CLEAR_BIT(finished_tags, tmp_slot);
587968d33a25Syt 			aborted_tags |= tmp_slot;
588068d33a25Syt 			continue;
588168d33a25Syt 		}
588268d33a25Syt 
588382263d52Syt 		if (ncq_cmd_in_progress)
588482263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
588582263d52Syt 			    tmp_slot);
58862fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
58872fcbc377Syt 		CLEAR_BIT(finished_tags, tmp_slot);
58882fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
58892fcbc377Syt 
58902fcbc377Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_COMPLETED);
58912fcbc377Syt 	}
58922fcbc377Syt 
589368d33a25Syt 	/* Send up failed packets with SATA_PKT_DEV_ERROR. */
58942fcbc377Syt 	while (failed_tags) {
589582263d52Syt 		if (err_retri_cmd_in_progress) {
589682263d52Syt 			satapkt = ahci_portp->ahciport_err_retri_pkt;
589782263d52Syt 			ASSERT(satapkt != NULL);
589882263d52Syt 			ASSERT(failed_tags == 0x1);
589982263d52Syt 
590082263d52Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
590182263d52Syt 			    "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
590282263d52Syt 			    (void *)satapkt);
590382263d52Syt 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
590482263d52Syt 			break;
590582263d52Syt 		}
590682263d52Syt 
59072fcbc377Syt 		tmp_slot = ddi_ffs(failed_tags) - 1;
59082fcbc377Syt 		if (tmp_slot == -1) {
59092fcbc377Syt 			break;
59102fcbc377Syt 		}
59112fcbc377Syt 
59122fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
59132fcbc377Syt 		ASSERT(satapkt != NULL);
59142fcbc377Syt 
59152fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
59162fcbc377Syt 		    "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
59172fcbc377Syt 		    (void *)satapkt);
59182fcbc377Syt 
591982263d52Syt 		if (ncq_cmd_in_progress)
592082263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
592182263d52Syt 			    tmp_slot);
59222fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
59232fcbc377Syt 		CLEAR_BIT(failed_tags, tmp_slot);
59242fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
59252fcbc377Syt 
59262fcbc377Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
59272fcbc377Syt 	}
59282fcbc377Syt 
592968d33a25Syt 	/* Send up timeout packets with SATA_PKT_TIMEOUT. */
59302fcbc377Syt 	while (timeout_tags) {
593182263d52Syt 		if (err_retri_cmd_in_progress) {
593282263d52Syt 			satapkt = ahci_portp->ahciport_err_retri_pkt;
593382263d52Syt 			ASSERT(satapkt != NULL);
593482263d52Syt 			ASSERT(timeout_tags == 0x1);
593582263d52Syt 
593682263d52Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
593782263d52Syt 			    "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
593882263d52Syt 			    (void *)satapkt);
593982263d52Syt 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
594082263d52Syt 			break;
594182263d52Syt 		}
594282263d52Syt 
59432fcbc377Syt 		tmp_slot = ddi_ffs(timeout_tags) - 1;
59442fcbc377Syt 		if (tmp_slot == -1) {
59452fcbc377Syt 			break;
59462fcbc377Syt 		}
59472fcbc377Syt 
59482fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
59492fcbc377Syt 		ASSERT(satapkt != NULL);
59502fcbc377Syt 
59512fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
59522fcbc377Syt 		    "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
59532fcbc377Syt 		    (void *)satapkt);
59542fcbc377Syt 
595582263d52Syt 		if (ncq_cmd_in_progress)
595682263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
595782263d52Syt 			    tmp_slot);
59582fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
59592fcbc377Syt 		CLEAR_BIT(timeout_tags, tmp_slot);
59602fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
59612fcbc377Syt 
59622fcbc377Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
59632fcbc377Syt 	}
59642fcbc377Syt 
596568d33a25Syt 	/* Send up aborted packets with SATA_PKT_ABORTED */
59662fcbc377Syt 	while (aborted_tags) {
596782263d52Syt 		if (err_retri_cmd_in_progress) {
596882263d52Syt 			satapkt = ahci_portp->ahciport_err_retri_pkt;
596982263d52Syt 			ASSERT(satapkt != NULL);
597082263d52Syt 			ASSERT(aborted_tags == 0x1);
597182263d52Syt 
597282263d52Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
597382263d52Syt 			    "sending up pkt 0x%p with SATA_PKT_ABORTED",
597482263d52Syt 			    (void *)satapkt);
597582263d52Syt 			SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED);
597682263d52Syt 			break;
597782263d52Syt 		}
597882263d52Syt 
59792fcbc377Syt 		tmp_slot = ddi_ffs(aborted_tags) - 1;
59802fcbc377Syt 		if (tmp_slot == -1) {
59812fcbc377Syt 			break;
59822fcbc377Syt 		}
59832fcbc377Syt 
59842fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
59852fcbc377Syt 		ASSERT(satapkt != NULL);
59862fcbc377Syt 
59872fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
59882fcbc377Syt 		    "sending up pkt 0x%p with SATA_PKT_ABORTED",
59892fcbc377Syt 		    (void *)satapkt);
59902fcbc377Syt 
599182263d52Syt 		if (ncq_cmd_in_progress)
599282263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
599382263d52Syt 			    tmp_slot);
59942fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
59952fcbc377Syt 		CLEAR_BIT(aborted_tags, tmp_slot);
59962fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
59972fcbc377Syt 
59982fcbc377Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_ABORTED);
59992fcbc377Syt 	}
60002fcbc377Syt 
600168d33a25Syt 	/* Send up reset packets with SATA_PKT_RESET. */
60022fcbc377Syt 	while (reset_tags) {
60032fcbc377Syt 		tmp_slot = ddi_ffs(reset_tags) - 1;
60042fcbc377Syt 		if (tmp_slot == -1) {
60052fcbc377Syt 			break;
60062fcbc377Syt 		}
60072fcbc377Syt 
60082fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
60092fcbc377Syt 		ASSERT(satapkt != NULL);
60102fcbc377Syt 
60112fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
60122fcbc377Syt 		    "sending up pkt 0x%p with SATA_PKT_RESET",
60132fcbc377Syt 		    (void *)satapkt);
60142fcbc377Syt 
601582263d52Syt 		if (ncq_cmd_in_progress)
601682263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
601782263d52Syt 			    tmp_slot);
60182fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
60192fcbc377Syt 		CLEAR_BIT(reset_tags, tmp_slot);
60202fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
60212fcbc377Syt 
60222fcbc377Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_RESET);
60232fcbc377Syt 	}
60242fcbc377Syt 
602568d33a25Syt 	/* Send up unfinished packets with SATA_PKT_RESET */
60262fcbc377Syt 	while (unfinished_tags) {
60272fcbc377Syt 		tmp_slot = ddi_ffs(unfinished_tags) - 1;
60282fcbc377Syt 		if (tmp_slot == -1) {
60292fcbc377Syt 			break;
60302fcbc377Syt 		}
60312fcbc377Syt 
60322fcbc377Syt 		satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
60332fcbc377Syt 		ASSERT(satapkt != NULL);
60342fcbc377Syt 
60352fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
603668d33a25Syt 		    "sending up pkt 0x%p with SATA_PKT_RESET",
60372fcbc377Syt 		    (void *)satapkt);
60382fcbc377Syt 
603982263d52Syt 		if (ncq_cmd_in_progress)
604082263d52Syt 			CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
604182263d52Syt 			    tmp_slot);
60422fcbc377Syt 		CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
60432fcbc377Syt 		CLEAR_BIT(unfinished_tags, tmp_slot);
60442fcbc377Syt 		ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
60452fcbc377Syt 
604668d33a25Syt 		SENDUP_PACKET(ahci_portp, satapkt, SATA_PKT_RESET);
60472fcbc377Syt 	}
60482fcbc377Syt 
604968d33a25Syt 	ahci_portp->ahciport_mop_in_progress--;
605068d33a25Syt 	ASSERT(ahci_portp->ahciport_mop_in_progress >= 0);
60512fcbc377Syt 
605268d33a25Syt 	if (ahci_portp->ahciport_mop_in_progress == 0)
605368d33a25Syt 		ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_MOPPING;
605468d33a25Syt }
60552fcbc377Syt 
605682263d52Syt /*
605782263d52Syt  * This routine is going to first request a READ LOG EXT sata pkt from sata
605882263d52Syt  * module, and then deliver it to the HBA to get the ncq failure context.
605982263d52Syt  * The return value is the exactly failed tags.
606082263d52Syt  */
606182263d52Syt static uint32_t
606282263d52Syt ahci_get_rdlogext_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
606382263d52Syt     uint8_t port)
606482263d52Syt {
606582263d52Syt 	sata_device_t	sdevice;
606682263d52Syt 	sata_pkt_t	*rdlog_spkt, *spkt;
606782263d52Syt 	ddi_dma_handle_t buf_dma_handle;
606882263d52Syt 	int		loop_count;
606982263d52Syt 	int		rval;
607082263d52Syt 	int		failed_slot;
607182263d52Syt 	uint32_t	failed_tags = 0;
607282263d52Syt 	struct sata_ncq_error_recovery_page *ncq_err_page;
607382263d52Syt 
607482263d52Syt 	AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp,
607582263d52Syt 	    "ahci_get_rdlogext_data enter: port %d", port);
607682263d52Syt 
607782263d52Syt 	/* Prepare the sdevice data */
607882263d52Syt 	bzero((void *)&sdevice, sizeof (sata_device_t));
607982263d52Syt 	sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
608082263d52Syt 
608182263d52Syt 	sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
608282263d52Syt 	sdevice.satadev_addr.pmport = 0;
608382263d52Syt 
608482263d52Syt 	/*
608582263d52Syt 	 * Call the sata hba interface to get a rdlog spkt
608682263d52Syt 	 */
608782263d52Syt 	loop_count = 0;
608882263d52Syt loop:
608982263d52Syt 	rdlog_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
609082263d52Syt 	    &sdevice, SATA_ERR_RETR_PKT_TYPE_NCQ);
609182263d52Syt 	if (rdlog_spkt == NULL) {
609282263d52Syt 		if (loop_count++ < AHCI_POLLRATE_GET_SPKT) {
609382263d52Syt 			/* Sleep for a while */
609482263d52Syt 			delay(AHCI_10MS_TICKS);
609582263d52Syt 			goto loop;
609682263d52Syt 		}
609782263d52Syt 		/* Timed out after 1s */
609882263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
609982263d52Syt 		    "failed to get rdlog spkt for port %d", port);
610082263d52Syt 		return (failed_tags);
610182263d52Syt 	}
610282263d52Syt 
610382263d52Syt 	ASSERT(rdlog_spkt->satapkt_op_mode & SATA_OPMODE_SYNCH);
610482263d52Syt 
610582263d52Syt 	/*
610682263d52Syt 	 * This flag is used to handle the specific error recovery when the
610782263d52Syt 	 * READ LOG EXT command gets a failure (fatal error or time-out).
610882263d52Syt 	 */
610982263d52Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RDLOGEXT;
611082263d52Syt 
611182263d52Syt 	/*
611282263d52Syt 	 * This start is not supposed to fail because after port is restarted,
611382263d52Syt 	 * the whole command list is empty.
611482263d52Syt 	 */
611582263d52Syt 	ahci_portp->ahciport_err_retri_pkt = rdlog_spkt;
611682263d52Syt 	(void) ahci_do_sync_start(ahci_ctlp, ahci_portp, port, rdlog_spkt);
611782263d52Syt 	ahci_portp->ahciport_err_retri_pkt = NULL;
611882263d52Syt 
611982263d52Syt 	/* Remove the flag after READ LOG EXT command is completed */
612082263d52Syt 	ahci_portp->ahciport_flags &= ~ AHCI_PORT_FLAG_RDLOGEXT;
612182263d52Syt 
612282263d52Syt 	if (rdlog_spkt->satapkt_reason == SATA_PKT_COMPLETED) {
612382263d52Syt 		/* Update the request log data */
612482263d52Syt 		buf_dma_handle = *(ddi_dma_handle_t *)
612582263d52Syt 		    (rdlog_spkt->satapkt_cmd.satacmd_err_ret_buf_handle);
612682263d52Syt 		rval = ddi_dma_sync(buf_dma_handle, 0, 0,
612782263d52Syt 		    DDI_DMA_SYNC_FORKERNEL);
612882263d52Syt 		if (rval == DDI_SUCCESS) {
612982263d52Syt 			ncq_err_page =
613082263d52Syt 			    (struct sata_ncq_error_recovery_page *)rdlog_spkt->
613182263d52Syt 			    satapkt_cmd.satacmd_bp->b_un.b_addr;
613282263d52Syt 
613382263d52Syt 			/* Get the failed tag */
613482263d52Syt 			failed_slot = ncq_err_page->ncq_tag;
613582263d52Syt 			AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
613682263d52Syt 			    "ahci_get_rdlogext_data: port %d "
613782263d52Syt 			    "failed slot %d", port, failed_slot);
613882263d52Syt 			if (failed_slot & NQ) {
613982263d52Syt 				AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
614082263d52Syt 				    "the failed slot is not a valid tag");
614182263d52Syt 				goto out;
614282263d52Syt 			}
614382263d52Syt 
614482263d52Syt 			failed_slot &= NCQ_TAG_MASK;
614582263d52Syt 			spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
614682263d52Syt 			AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
614782263d52Syt 			    "ahci_get_rdlogext_data: failed spkt 0x%p",
614882263d52Syt 			    (void *)spkt);
614982263d52Syt 			if (spkt == NULL) {
615082263d52Syt 				AHCIDBG0(AHCIDBG_ERRS, ahci_ctlp,
615182263d52Syt 				    "the failed slot spkt is NULL")
615282263d52Syt 				goto out;
615382263d52Syt 			}
615482263d52Syt 
615582263d52Syt 			failed_tags = 0x1 << failed_slot;
615682263d52Syt 
615782263d52Syt 			/* Fill out the error context */
615882263d52Syt 			ahci_copy_ncq_err_page(&spkt->satapkt_cmd,
615982263d52Syt 			    ncq_err_page);
616082263d52Syt 			ahci_update_sata_registers(ahci_ctlp, port,
616182263d52Syt 			    &spkt->satapkt_device);
616282263d52Syt 		}
616382263d52Syt 	} else {
616482263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
616582263d52Syt 		    "ahci_get_rdlogext_data: port %d READ LOG EXT command "
616682263d52Syt 		    "did not successfully complete", port);
616782263d52Syt 	}
616882263d52Syt out:
616982263d52Syt 	sata_free_error_retrieval_pkt(rdlog_spkt);
617082263d52Syt 
617182263d52Syt 	return (failed_tags);
617282263d52Syt }
617382263d52Syt 
617468d33a25Syt /*
617568d33a25Syt  * This routine is going to first request a REQUEST SENSE sata pkt from sata
617668d33a25Syt  * module, and then deliver it to the HBA to get the sense data and copy
617768d33a25Syt  * the sense data back to the orignal failed sata pkt, and free the REQUEST
617868d33a25Syt  * SENSE sata pkt later.
617968d33a25Syt  */
618068d33a25Syt static void
618168d33a25Syt ahci_get_rqsense_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
618268d33a25Syt     uint8_t port, sata_pkt_t *spkt)
618368d33a25Syt {
618468d33a25Syt 	sata_device_t	sdevice;
618568d33a25Syt 	sata_pkt_t	*rs_spkt;
618668d33a25Syt 	sata_cmd_t	*sata_cmd;
618768d33a25Syt 	ddi_dma_handle_t buf_dma_handle;
618868d33a25Syt 	int		loop_count;
618968d33a25Syt #if AHCI_DEBUG
619068d33a25Syt 	struct scsi_extended_sense *rqsense;
619168d33a25Syt #endif
619268d33a25Syt 
619368d33a25Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
619468d33a25Syt 	    "ahci_get_rqsense_data enter: port %d", port);
619568d33a25Syt 
619668d33a25Syt 	/* Prepare the sdevice data */
619768d33a25Syt 	bzero((void *)&sdevice, sizeof (sata_device_t));
619868d33a25Syt 	sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
619968d33a25Syt 
620068d33a25Syt 	sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
620168d33a25Syt 	sdevice.satadev_addr.pmport = 0;
620268d33a25Syt 
620368d33a25Syt 	sata_cmd = &spkt->satapkt_cmd;
620468d33a25Syt 
620568d33a25Syt 	/*
620668d33a25Syt 	 * Call the sata hba interface to get a rs spkt
620768d33a25Syt 	 */
620868d33a25Syt 	loop_count = 0;
620968d33a25Syt loop:
621068d33a25Syt 	rs_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
621168d33a25Syt 	    &sdevice, SATA_ERR_RETR_PKT_TYPE_ATAPI);
621268d33a25Syt 	if (rs_spkt == NULL) {
621368d33a25Syt 		if (loop_count++ < AHCI_POLLRATE_GET_SPKT) {
621468d33a25Syt 			/* Sleep for a while */
621568d33a25Syt 			delay(AHCI_10MS_TICKS);
621668d33a25Syt 			goto loop;
621768d33a25Syt 
621868d33a25Syt 		}
621968d33a25Syt 		/* Timed out after 1s */
622082263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
622168d33a25Syt 		    "failed to get rs spkt for port %d", port);
622268d33a25Syt 		return;
622368d33a25Syt 	}
622468d33a25Syt 
622568d33a25Syt 	ASSERT(rs_spkt->satapkt_op_mode & SATA_OPMODE_SYNCH);
622668d33a25Syt 
622768d33a25Syt 	/*
622868d33a25Syt 	 * This flag is used to handle the specific error recovery when the
622982263d52Syt 	 * REQUEST SENSE command gets a faiure (fatal error or time-out).
623068d33a25Syt 	 */
623168d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RQSENSE;
623268d33a25Syt 
623368d33a25Syt 	/*
623468d33a25Syt 	 * This start is not supposed to fail because after port is restarted,
623582263d52Syt 	 * the whole command list is empty.
623668d33a25Syt 	 */
623782263d52Syt 	ahci_portp->ahciport_err_retri_pkt = rs_spkt;
623882263d52Syt 	(void) ahci_do_sync_start(ahci_ctlp, ahci_portp, port, rs_spkt);
623982263d52Syt 	ahci_portp->ahciport_err_retri_pkt = NULL;
624068d33a25Syt 
624168d33a25Syt 	/* Remove the flag after REQUEST SENSE command is completed */
624268d33a25Syt 	ahci_portp->ahciport_flags &= ~ AHCI_PORT_FLAG_RQSENSE;
624368d33a25Syt 
624468d33a25Syt 	if (rs_spkt->satapkt_reason == SATA_PKT_COMPLETED) {
624568d33a25Syt 		/* Update the request sense data */
624668d33a25Syt 		buf_dma_handle = *(ddi_dma_handle_t *)
624768d33a25Syt 		    (rs_spkt->satapkt_cmd.satacmd_err_ret_buf_handle);
624882263d52Syt 		(void) ddi_dma_sync(buf_dma_handle, 0, 0,
624968d33a25Syt 		    DDI_DMA_SYNC_FORKERNEL);
625082263d52Syt 		/* Copy the request sense data */
625182263d52Syt 		bcopy(rs_spkt->
625282263d52Syt 		    satapkt_cmd.satacmd_bp->b_un.b_addr,
625382263d52Syt 		    &sata_cmd->satacmd_rqsense,
625482263d52Syt 		    SATA_ATAPI_MIN_RQSENSE_LEN);
625568d33a25Syt #if AHCI_DEBUG
625682263d52Syt 		rqsense = (struct scsi_extended_sense *)
625782263d52Syt 		    sata_cmd->satacmd_rqsense;
625882263d52Syt 
625982263d52Syt 		/* Dump the sense data */
626082263d52Syt 		AHCIDBG0(AHCIDBG_SENSEDATA, ahci_ctlp, "\n");
626182263d52Syt 		AHCIDBG2(AHCIDBG_SENSEDATA, ahci_ctlp,
626282263d52Syt 		    "Sense data for satapkt %p ATAPI cmd 0x%x",
626382263d52Syt 		    spkt, sata_cmd->satacmd_acdb[0]);
626482263d52Syt 		AHCIDBG5(AHCIDBG_SENSEDATA, ahci_ctlp,
626582263d52Syt 		    "  es_code 0x%x es_class 0x%x "
626682263d52Syt 		    "es_key 0x%x es_add_code 0x%x "
626782263d52Syt 		    "es_qual_code 0x%x",
626882263d52Syt 		    rqsense->es_code, rqsense->es_class,
626982263d52Syt 		    rqsense->es_key, rqsense->es_add_code,
627082263d52Syt 		    rqsense->es_qual_code);
627168d33a25Syt #endif
627282263d52Syt 	} else {
627382263d52Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
627482263d52Syt 		    "ahci_get_rqsense_data: port %d REQUEST SENSE command "
627582263d52Syt 		    "did not successfully complete", port);
627668d33a25Syt 	}
627768d33a25Syt 
627868d33a25Syt 	sata_free_error_retrieval_pkt(rs_spkt);
62792fcbc377Syt }
62802fcbc377Syt 
62812fcbc377Syt /*
62822fcbc377Syt  * Fatal errors will cause the HBA to enter the ERR: Fatal state. To recover,
628368d33a25Syt  * the port must be restarted. When the HBA detects thus error, it may try
628468d33a25Syt  * to abort a transfer. And if the transfer was aborted, the device is
628568d33a25Syt  * expected to send a D2H Register FIS with PxTFD.STS.ERR set to '1' and both
628668d33a25Syt  * PxTFD.STS.BSY and PxTFD.STS.DRQ cleared to '0'. Then system software knows
628768d33a25Syt  * that the device is in a stable status and transfers may be restarted without
628868d33a25Syt  * issuing a COMRESET to the device. If PxTFD.STS.BSY or PxTFD.STS.DRQ is set,
628968d33a25Syt  * then the software will send the COMRESET to do the port reset.
629068d33a25Syt  *
629168d33a25Syt  * Software should perform the appropriate error recovery actions based on
629268d33a25Syt  * whether non-queued commands were being issued or natived command queuing
629368d33a25Syt  * commands were being issued.
629468d33a25Syt  *
629568d33a25Syt  * And software will complete the command that had the error with error mark
629668d33a25Syt  * to higher level software.
62972fcbc377Syt  *
62982fcbc377Syt  * Fatal errors include the following:
62992fcbc377Syt  * 	PxIS.IFS - Interface Fatal Error Status
63002fcbc377Syt  * 	PxIS.HBDS - Host Bus Data Error Status
63012fcbc377Syt  * 	PxIS.HBFS - Host Bus Fatal Error Status
63022fcbc377Syt  *	PxIS.TFES - Task File Error Status
63032fcbc377Syt  *
63042fcbc377Syt  * WARNING!!! ahciport_mutex should be acquired before the function is called.
63052fcbc377Syt  */
630668d33a25Syt static void
630768d33a25Syt ahci_fatal_error_recovery_handler(ahci_ctl_t *ahci_ctlp,
630882263d52Syt     ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
63092fcbc377Syt {
631082263d52Syt 	uint32_t	port_cmd_status;
631182263d52Syt 	uint32_t	slot_status = 0;
631268d33a25Syt 	uint32_t	failed_tags = 0;
631368d33a25Syt 	int		failed_slot;
631468d33a25Syt 	int		reset_flag = 0;
631568d33a25Syt 	ahci_fis_d2h_register_t	*ahci_rcvd_fisp;
631682263d52Syt 	sata_cmd_t	*sata_cmd = NULL;
631782263d52Syt 	sata_pkt_t	*spkt = NULL;
63182fcbc377Syt 
63192fcbc377Syt 	AHCIDBG1(AHCIDBG_ENTRY, ahci_ctlp,
632068d33a25Syt 	    "ahci_fatal_error_recovery_handler enter: port %d", port);
63212fcbc377Syt 
632282263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
632382263d52Syt 	    ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
63242fcbc377Syt 
632582263d52Syt 		/* Read PxCI to see which commands are still outstanding */
632682263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
632782263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
63282fcbc377Syt 
632982263d52Syt 		/*
633082263d52Syt 		 * Read PxCMD.CCS to determine the slot that the HBA
633182263d52Syt 		 * was processing when the error occurred.
633282263d52Syt 		 */
633382263d52Syt 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
633482263d52Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
633582263d52Syt 		failed_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
633682263d52Syt 		    AHCI_CMD_STATUS_CCS_SHIFT;
63372fcbc377Syt 
633882263d52Syt 		if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
633982263d52Syt 			spkt = ahci_portp->ahciport_err_retri_pkt;
634082263d52Syt 			ASSERT(spkt != NULL);
634182263d52Syt 		} else {
634282263d52Syt 			spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
634382263d52Syt 			if (spkt == NULL) {
634482263d52Syt 				/* May happen when interface errors occur? */
634582263d52Syt 				goto next;
634682263d52Syt 			}
634782263d52Syt 		}
63482fcbc377Syt 
634982263d52Syt 		sata_cmd = &spkt->satapkt_cmd;
63502fcbc377Syt 
635182263d52Syt 		/* Fill out the status and error registers for PxIS.TFES */
635282263d52Syt 		if (intr_status & AHCI_INTR_STATUS_TFES) {
635382263d52Syt 			ahci_rcvd_fisp = &(ahci_portp->ahciport_rcvd_fis->
635482263d52Syt 			    ahcirf_d2h_register_fis);
635582263d52Syt 
635682263d52Syt 			/* Copy the error context back to the sata_cmd */
635782263d52Syt 			ahci_copy_err_cnxt(sata_cmd, ahci_rcvd_fisp);
635882263d52Syt 		}
63592fcbc377Syt 
636082263d52Syt 		/* The failed command must be one of the outstanding commands */
636182263d52Syt 		failed_tags = 0x1 << failed_slot;
636282263d52Syt 		ASSERT(failed_tags & slot_status);
636382263d52Syt 
636482263d52Syt 		/* Update the sata registers, especially PxSERR register */
636582263d52Syt 		ahci_update_sata_registers(ahci_ctlp, port,
636682263d52Syt 		    &spkt->satapkt_device);
63672fcbc377Syt 
636868d33a25Syt 	}
63692fcbc377Syt 
637082263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
637182263d52Syt 		/* Read PxSACT to see which commands are still outstanding */
637282263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
637382263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
637482263d52Syt 	}
637568d33a25Syt next:
63762fcbc377Syt 
637768d33a25Syt #if AHCI_DEBUG
637868d33a25Syt 	/*
637982263d52Syt 	 * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT flag is
638082263d52Syt 	 * set, it means a fatal error happened after REQUEST SENSE command
638182263d52Syt 	 * or READ LOG EXT command is delivered to the HBA during the error
638282263d52Syt 	 * recovery process. At this time, the only outstanding command is
638382263d52Syt 	 * supposed to be REQUEST SENSE command or READ LOG EXT command.
638468d33a25Syt 	 */
638582263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
63862fcbc377Syt 		AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
638768d33a25Syt 		    "ahci_fatal_error_recovery_handler: port %d REQUEST SENSE "
638882263d52Syt 		    "command or READ LOG EXT command for error data retrieval "
638982263d52Syt 		    "failed", port);
639082263d52Syt 		ASSERT(slot_status == 0x1);
639182263d52Syt 		ASSERT(failed_slot == 0x1);
639282263d52Syt 		ASSERT(spkt->satapkt_cmd.satacmd_acdb[0] ==
639382263d52Syt 		    SCMD_REQUEST_SENSE ||
639482263d52Syt 		    spkt->satapkt_cmd.satacmd_cmd_reg ==
639582263d52Syt 		    SATAC_READ_LOG_EXT);
63962fcbc377Syt 	}
639768d33a25Syt #endif
63982fcbc377Syt 
639968d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
640068d33a25Syt 	ahci_portp->ahciport_mop_in_progress++;
64012fcbc377Syt 
640268d33a25Syt 	(void) ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
640368d33a25Syt 	    port, NULL, &reset_flag);
64042fcbc377Syt 
640568d33a25Syt 	/*
640668d33a25Syt 	 * Won't retrieve error information:
640768d33a25Syt 	 * 1. Port reset was involved to recover
640882263d52Syt 	 * 2. Device is gone
640968d33a25Syt 	 * 3. IDENTIFY DEVICE command sent to ATAPI device
641082263d52Syt 	 * 4. REQUEST SENSE or READ LOG EXT command during error recovery
641168d33a25Syt 	 */
641282263d52Syt 	if (reset_flag ||
641382263d52Syt 	    ahci_portp->ahciport_device_type == SATA_DTYPE_NONE ||
641482263d52Syt 	    spkt && spkt->satapkt_cmd.satacmd_cmd_reg == SATAC_ID_DEVICE ||
641582263d52Syt 	    ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
641668d33a25Syt 		goto out;
64172fcbc377Syt 
641882263d52Syt 	/*
641982263d52Syt 	 * Deliver READ LOG EXT to gather information about the error when
642082263d52Syt 	 * a COMRESET has not been performed as part of the error recovery
642182263d52Syt 	 * during NCQ command processing.
642282263d52Syt 	 */
642382263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
642482263d52Syt 		failed_tags = ahci_get_rdlogext_data(ahci_ctlp,
642582263d52Syt 		    ahci_portp, port);
642682263d52Syt 		goto out;
642782263d52Syt 	}
642882263d52Syt 
642968d33a25Syt 	/*
643068d33a25Syt 	 * Deliver REQUEST SENSE for ATAPI command to gather information about
643168d33a25Syt 	 * the error when a COMRESET has not been performed as part of the
643268d33a25Syt 	 * error recovery.
643368d33a25Syt 	 */
643482263d52Syt 	if (spkt && ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPICD)
643568d33a25Syt 		ahci_get_rqsense_data(ahci_ctlp, ahci_portp, port, spkt);
643668d33a25Syt out:
643782263d52Syt 	AHCIDBG5(AHCIDBG_ERRS, ahci_ctlp,
643882263d52Syt 	    "ahci_fatal_error_recovery_handler: port %d interface error "
643982263d52Syt 	    "occurred slot_status = 0x%x, pending_tags = 0x%x, "
644082263d52Syt 	    "pending_ncq_tags = 0x%x failed_tags = 0x%x",
644182263d52Syt 	    port, slot_status, ahci_portp->ahciport_pending_tags,
644282263d52Syt 	    ahci_portp->ahciport_pending_ncq_tags, failed_tags);
644382263d52Syt 
64442fcbc377Syt 	ahci_mop_commands(ahci_ctlp,
64452fcbc377Syt 	    ahci_portp,
64462fcbc377Syt 	    port,
644782263d52Syt 	    slot_status,
64482fcbc377Syt 	    failed_tags, /* failed tags */
64492fcbc377Syt 	    0, /* timeout tags */
64502fcbc377Syt 	    0, /* aborted tags */
64512fcbc377Syt 	    0); /* reset tags */
645268d33a25Syt }
645368d33a25Syt 
645468d33a25Syt /*
645568d33a25Syt  * Handle events - fatal error recovery
645668d33a25Syt  */
645768d33a25Syt static void
645868d33a25Syt ahci_events_handler(void *args)
645968d33a25Syt {
646068d33a25Syt 	ahci_event_arg_t *ahci_event_arg;
646168d33a25Syt 	ahci_ctl_t *ahci_ctlp;
646268d33a25Syt 	ahci_port_t *ahci_portp;
646368d33a25Syt 	uint32_t event;
646468d33a25Syt 	uint8_t port;
646568d33a25Syt 
646668d33a25Syt 	ahci_event_arg = (ahci_event_arg_t *)args;
646782263d52Syt 
646868d33a25Syt 	ahci_ctlp = ahci_event_arg->ahciea_ctlp;
646968d33a25Syt 	ahci_portp = ahci_event_arg->ahciea_portp;
647068d33a25Syt 	event = ahci_event_arg->ahciea_event;
647168d33a25Syt 	port = ahci_portp->ahciport_port_num;
647268d33a25Syt 
647382263d52Syt 	AHCIDBG2(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
647482263d52Syt 	    "ahci_events_handler enter: port %d intr_status = 0x%x",
647582263d52Syt 	    port, event);
647668d33a25Syt 
64772fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
64782fcbc377Syt 
647968d33a25Syt 	/*
648068d33a25Syt 	 * ahci_intr_phyrdy_change() may have rendered it to
648168d33a25Syt 	 * SATA_DTYPE_NONE.
648268d33a25Syt 	 */
648368d33a25Syt 	if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
648468d33a25Syt 		AHCIDBG1(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
648568d33a25Syt 		    "ahci_events_handler: port %d no device attached, "
648668d33a25Syt 		    "and just return without doing anything", port);
648768d33a25Syt 		goto out;
648868d33a25Syt 	}
648968d33a25Syt 
649068d33a25Syt 	if (event & (AHCI_INTR_STATUS_IFS |
649168d33a25Syt 	    AHCI_INTR_STATUS_HBDS |
649268d33a25Syt 	    AHCI_INTR_STATUS_HBFS |
649368d33a25Syt 	    AHCI_INTR_STATUS_TFES))
649468d33a25Syt 		ahci_fatal_error_recovery_handler(ahci_ctlp, ahci_portp,
649582263d52Syt 		    port, event);
649668d33a25Syt 
649768d33a25Syt out:
649868d33a25Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
64992fcbc377Syt }
65002fcbc377Syt 
65012fcbc377Syt /*
650268d33a25Syt  * ahci_watchdog_handler() and ahci_do_sync_start will call us if they
650368d33a25Syt  * detect there are some commands which are timed out.
65042fcbc377Syt  */
65052fcbc377Syt static void
65062fcbc377Syt ahci_timeout_pkts(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
650782263d52Syt     uint8_t port, uint32_t tmp_timeout_tags)
65082fcbc377Syt {
650982263d52Syt 	uint32_t slot_status = 0;
651082263d52Syt 	uint32_t finished_tags = 0;
651182263d52Syt 	uint32_t timeout_tags = 0;
65122fcbc377Syt 
651368d33a25Syt 	AHCIDBG1(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
651468d33a25Syt 	    "ahci_timeout_pkts enter: port %d", port);
65152fcbc377Syt 
65162fcbc377Syt 	mutex_enter(&ahci_portp->ahciport_mutex);
65172fcbc377Syt 
651882263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
651982263d52Syt 	    ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
652082263d52Syt 		/* Read PxCI to see which commands are still outstanding */
652182263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
652282263d52Syt 		    (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
652382263d52Syt 	}
652482263d52Syt 
652582263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
652682263d52Syt 		/* Read PxSACT to see which commands are still outstanding */
652782263d52Syt 		slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
652882263d52Syt 		    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
652982263d52Syt 	}
653068d33a25Syt 
653168d33a25Syt #if AHCI_DEBUG
65322fcbc377Syt 	/*
653382263d52Syt 	 * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT flag is
653482263d52Syt 	 * set, it means a fatal error happened after REQUEST SENSE command
653582263d52Syt 	 * or READ LOG EXT command is delivered to the HBA during the error
653682263d52Syt 	 * recovery process. At this time, the only outstanding command is
653782263d52Syt 	 * supposed to be REQUEST SENSE command or READ LOG EXT command.
65382fcbc377Syt 	 */
653982263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
654082263d52Syt 		AHCIDBG4(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp,
654168d33a25Syt 		    "ahci_timeout_pkts called while REQUEST SENSE "
654282263d52Syt 		    "command or READ LOG EXT command for error recovery "
654382263d52Syt 		    "timed out timeout_tags = 0x%x, slot_status = 0x%x, "
654482263d52Syt 		    "pending_tags = 0x%x, pending_ncq_tags = 0x%x",
654582263d52Syt 		    tmp_timeout_tags, slot_status,
654682263d52Syt 		    ahci_portp->ahciport_pending_tags,
654782263d52Syt 		    ahci_portp->ahciport_pending_ncq_tags);
654882263d52Syt 		ASSERT(slot_status == 0x1);
65492fcbc377Syt 	}
655068d33a25Syt #endif
65512fcbc377Syt 
655268d33a25Syt 	ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
655368d33a25Syt 	ahci_portp->ahciport_mop_in_progress++;
65542fcbc377Syt 
65552fcbc377Syt 	(void) ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
655668d33a25Syt 	    port, NULL, NULL);
655768d33a25Syt 
65582fcbc377Syt 	/*
65592fcbc377Syt 	 * Re-identify timeout tags because some previously checked commands
65602fcbc377Syt 	 * could already complete.
65612fcbc377Syt 	 */
656282263d52Syt 	if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
656382263d52Syt 		finished_tags = ahci_portp->ahciport_pending_tags &
656482263d52Syt 		    ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
656582263d52Syt 		timeout_tags = tmp_timeout_tags & ~finished_tags;
656682263d52Syt 
656782263d52Syt 		AHCIDBG5(AHCIDBG_TIMEOUT, ahci_ctlp,
656882263d52Syt 		    "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
656982263d52Syt 		    "timeout_tags = 0x%x, port_cmd_issue = 0x%x, "
657082263d52Syt 		    "pending_tags = 0x%x ",
657182263d52Syt 		    port, finished_tags, timeout_tags,
657282263d52Syt 		    slot_status, ahci_portp->ahciport_pending_tags);
657382263d52Syt 	}
657482263d52Syt 
657582263d52Syt 	if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
657682263d52Syt 		finished_tags = ahci_portp->ahciport_pending_ncq_tags &
657782263d52Syt 		    ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
657882263d52Syt 		timeout_tags = tmp_timeout_tags & ~finished_tags;
657982263d52Syt 
658082263d52Syt 		AHCIDBG5(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp,
658182263d52Syt 		    "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
658282263d52Syt 		    "timeout_tags = 0x%x, port_sactive = 0x%x, "
658382263d52Syt 		    "pending_ncq_tags = 0x%x ",
658482263d52Syt 		    port, finished_tags, timeout_tags,
658582263d52Syt 		    slot_status, ahci_portp->ahciport_pending_ncq_tags);
658682263d52Syt 	}
65872fcbc377Syt 
658882263d52Syt 	if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
658982263d52Syt 		timeout_tags = tmp_timeout_tags;
659082263d52Syt 	}
65912fcbc377Syt 
65922fcbc377Syt 	ahci_mop_commands(ahci_ctlp,
65932fcbc377Syt 	    ahci_portp,
65942fcbc377Syt 	    port,
659582263d52Syt 	    slot_status,
65962fcbc377Syt 	    0, /* failed tags */
65972fcbc377Syt 	    timeout_tags, /* timeout tags */
65982fcbc377Syt 	    0, /* aborted tags */
65992fcbc377Syt 	    0); /* reset tags */
660068d33a25Syt 
660168d33a25Syt 	mutex_exit(&ahci_portp->ahciport_mutex);
66022fcbc377Syt }
66032fcbc377Syt 
66042fcbc377Syt /*
66052fcbc377Syt  * Watchdog handler kicks in every 5 seconds to timeout any commands pending
66062fcbc377Syt  * for long time.
66072fcbc377Syt  */
66082fcbc377Syt static void
66092fcbc377Syt ahci_watchdog_handler(ahci_ctl_t *ahci_ctlp)
66102fcbc377Syt {
66112fcbc377Syt 	ahci_port_t *ahci_portp;
661268d33a25Syt 	sata_pkt_t *spkt;
661382263d52Syt 	uint32_t pending_tags;
661482263d52Syt 	uint32_t timeout_tags;
661568d33a25Syt 	uint32_t port_cmd_status;
661682263d52Syt 	uint32_t port_sactive;
66172fcbc377Syt 	uint8_t port;
66182fcbc377Syt 	int tmp_slot;
661968d33a25Syt 	int current_slot;
662082263d52Syt 	uint32_t current_tags;
66212fcbc377Syt 	/* max number of cycles this packet should survive */
66222fcbc377Syt 	int max_life_cycles;
66232fcbc377Syt 
66242fcbc377Syt 	/* how many cycles this packet survived so far */
66252fcbc377Syt 	int watched_cycles;
66262fcbc377Syt 
66272fcbc377Syt 	mutex_enter(&ahci_ctlp->ahcictl_mutex);
66282fcbc377Syt 
66292fcbc377Syt 	AHCIDBG0(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
66302fcbc377Syt 	    "ahci_watchdog_handler entered");
66312fcbc377Syt 
66322fcbc377Syt 	for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
66332fcbc377Syt 		if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
66342fcbc377Syt 			continue;
66352fcbc377Syt 		}
66362fcbc377Syt 
66372fcbc377Syt 		ahci_portp = ahci_ctlp->ahcictl_ports[port];
66382fcbc377Syt 
66392fcbc377Syt 		mutex_enter(&ahci_portp->ahciport_mutex);
66402fcbc377Syt 		if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
66412fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
66422fcbc377Syt 			continue;
66432fcbc377Syt 		}
66442fcbc377Syt 
664568d33a25Syt 		/* Skip the check for those ports in error recovery */
664682263d52Syt 		if ((ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) &&
664782263d52Syt 		    !(ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))) {
664868d33a25Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
664968d33a25Syt 			continue;
665068d33a25Syt 		}
665168d33a25Syt 
665282263d52Syt 		pending_tags = 0;
665368d33a25Syt 		port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
665468d33a25Syt 		    (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
665568d33a25Syt 
665682263d52Syt 		if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
665782263d52Syt 			current_slot = 0;
665882263d52Syt 			pending_tags = 0x1;
665982263d52Syt 		}
666082263d52Syt 
666182263d52Syt 		if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
666282263d52Syt 			current_slot =
666382263d52Syt 			    (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
666482263d52Syt 			    AHCI_CMD_STATUS_CCS_SHIFT;
666582263d52Syt 			pending_tags = ahci_portp->ahciport_pending_tags;
666682263d52Syt 		}
666782263d52Syt 
666882263d52Syt 		if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
666982263d52Syt 			port_sactive = ddi_get32(
667082263d52Syt 			    ahci_ctlp->ahcictl_ahci_acc_handle,
667182263d52Syt 			    (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
667282263d52Syt 			current_tags = port_sactive &
667382263d52Syt 			    ~port_cmd_status &
667482263d52Syt 			    AHCI_NCQ_SLOT_MASK(ahci_portp);
667582263d52Syt 			pending_tags = ahci_portp->ahciport_pending_ncq_tags;
667682263d52Syt 		}
667782263d52Syt 
66782fcbc377Syt 		timeout_tags = 0;
66792fcbc377Syt 		while (pending_tags) {
66802fcbc377Syt 			tmp_slot = ddi_ffs(pending_tags) - 1;
66812fcbc377Syt 			if (tmp_slot == -1) {
66822fcbc377Syt 				break;
66832fcbc377Syt 			}
66842fcbc377Syt 
668582263d52Syt 			if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
668682263d52Syt 				spkt = ahci_portp->ahciport_err_retri_pkt;
668782263d52Syt 			else
668882263d52Syt 				spkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
668982263d52Syt 
669068d33a25Syt 			if ((spkt != NULL) && spkt->satapkt_time &&
669168d33a25Syt 			    !(spkt->satapkt_op_mode & SATA_OPMODE_POLLING)) {
66922fcbc377Syt 				/*
66932fcbc377Syt 				 * We are overloading satapkt_hba_driver_private
66942fcbc377Syt 				 * with watched_cycle count.
66952fcbc377Syt 				 *
66962fcbc377Syt 				 * If a packet has survived for more than it's
66972fcbc377Syt 				 * max life cycles, it is a candidate for time
66982fcbc377Syt 				 * out.
66992fcbc377Syt 				 */
67002fcbc377Syt 				watched_cycles = (int)(intptr_t)
670168d33a25Syt 				    spkt->satapkt_hba_driver_private;
67022fcbc377Syt 				watched_cycles++;
670368d33a25Syt 				max_life_cycles = (spkt->satapkt_time +
67042fcbc377Syt 				    ahci_watchdog_timeout - 1) /
67052fcbc377Syt 				    ahci_watchdog_timeout;
670668d33a25Syt 
670768d33a25Syt 				spkt->satapkt_hba_driver_private =
670868d33a25Syt 				    (void *)(intptr_t)watched_cycles;
670968d33a25Syt 
671068d33a25Syt 				if (watched_cycles <= max_life_cycles)
671168d33a25Syt 					goto next;
671268d33a25Syt 
671368d33a25Syt 				AHCIDBG1(AHCIDBG_ERRS, ahci_ctlp,
671468d33a25Syt 				    "the current slot is %d", current_slot);
671568d33a25Syt 				/*
671668d33a25Syt 				 * We need to check whether the HBA has
671768d33a25Syt 				 * begun to execute the command, if not,
671868d33a25Syt 				 * then re-set the timer of the command.
671968d33a25Syt 				 */
672082263d52Syt 				if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) &&
672182263d52Syt 				    (tmp_slot != current_slot) ||
672282263d52Syt 				    NCQ_CMD_IN_PROGRESS(ahci_portp) &&
672382263d52Syt 				    ((0x1 << tmp_slot) & current_tags)) {
672468d33a25Syt 					spkt->satapkt_hba_driver_private =
672568d33a25Syt 					    (void *)(intptr_t)0;
672668d33a25Syt 				} else {
67272fcbc377Syt 					timeout_tags |= (0x1 << tmp_slot);
67282fcbc377Syt 					cmn_err(CE_NOTE, "!ahci watchdog: "
67292fcbc377Syt 					    "port %d satapkt 0x%p timed out\n",
673068d33a25Syt 					    port, (void *)spkt);
67312fcbc377Syt 				}
67322fcbc377Syt 			}
673368d33a25Syt next:
67342fcbc377Syt 			CLEAR_BIT(pending_tags, tmp_slot);
67352fcbc377Syt 		}
67362fcbc377Syt 
67372fcbc377Syt 		if (timeout_tags) {
67382fcbc377Syt 			mutex_exit(&ahci_portp->ahciport_mutex);
67392fcbc377Syt 			mutex_exit(&ahci_ctlp->ahcictl_mutex);
67402fcbc377Syt 			ahci_timeout_pkts(ahci_ctlp, ahci_portp,
674182263d52Syt 			    port, timeout_tags);
67422fcbc377Syt 			mutex_enter(&ahci_ctlp->ahcictl_mutex);
67432fcbc377Syt 			mutex_enter(&ahci_portp->ahciport_mutex);
67442fcbc377Syt 		}
67452fcbc377Syt 
67462fcbc377Syt 		mutex_exit(&ahci_portp->ahciport_mutex);
67472fcbc377Syt 	}
67482fcbc377Syt 
67492fcbc377Syt 	/* Re-install the watchdog timeout handler */
67502fcbc377Syt 	if (ahci_ctlp->ahcictl_timeout_id != 0) {
67512fcbc377Syt 		ahci_ctlp->ahcictl_timeout_id =
67522fcbc377Syt 		    timeout((void (*)(void *))ahci_watchdog_handler,
67532fcbc377Syt 		    (caddr_t)ahci_ctlp, ahci_watchdog_tick);
67542fcbc377Syt 	}
67552fcbc377Syt 
67562fcbc377Syt 	mutex_exit(&ahci_ctlp->ahcictl_mutex);
67572fcbc377Syt }
67582fcbc377Syt 
67592fcbc377Syt /*
676068d33a25Syt  * Fill the error context into sata_cmd for non-queued command error.
676168d33a25Syt  */
676268d33a25Syt static void
676368d33a25Syt ahci_copy_err_cnxt(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
676468d33a25Syt {
676568d33a25Syt 	scmd->satacmd_status_reg = GET_RFIS_STATUS(rfisp);
676668d33a25Syt 	scmd->satacmd_error_reg = GET_RFIS_ERROR(rfisp);
676768d33a25Syt 	scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
676868d33a25Syt 	scmd->satacmd_lba_low_lsb = GET_RFIS_CYL_LOW(rfisp);
676968d33a25Syt 	scmd->satacmd_lba_mid_lsb = GET_RFIS_CYL_MID(rfisp);
677068d33a25Syt 	scmd->satacmd_lba_high_lsb = GET_RFIS_CYL_HI(rfisp);
677168d33a25Syt 	scmd->satacmd_device_reg = GET_RFIS_DEV_HEAD(rfisp);
677268d33a25Syt 
677368d33a25Syt 	if (scmd->satacmd_addr_type == ATA_ADDR_LBA48) {
677468d33a25Syt 		scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
677568d33a25Syt 		scmd->satacmd_lba_low_msb = GET_RFIS_CYL_LOW_EXP(rfisp);
677668d33a25Syt 		scmd->satacmd_lba_mid_msb = GET_RFIS_CYL_MID_EXP(rfisp);
677768d33a25Syt 		scmd->satacmd_lba_high_msb = GET_RFIS_CYL_HI_EXP(rfisp);
677868d33a25Syt 	}
677968d33a25Syt }
678068d33a25Syt 
678182263d52Syt /*
678282263d52Syt  * Fill the ncq error page into sata_cmd for queued command error.
678382263d52Syt  */
678482263d52Syt static void
678582263d52Syt ahci_copy_ncq_err_page(sata_cmd_t *scmd,
678682263d52Syt     struct sata_ncq_error_recovery_page *ncq_err_page)
678782263d52Syt {
678882263d52Syt 	scmd->satacmd_sec_count_msb = ncq_err_page->ncq_sector_count_ext;
678982263d52Syt 	scmd->satacmd_sec_count_lsb = ncq_err_page->ncq_sector_count;
679082263d52Syt 	scmd->satacmd_lba_low_msb = ncq_err_page->ncq_sector_number_ext;
679182263d52Syt 	scmd->satacmd_lba_low_lsb = ncq_err_page->ncq_sector_number;
679282263d52Syt 	scmd->satacmd_lba_mid_msb = ncq_err_page->ncq_cyl_low_ext;
679382263d52Syt 	scmd->satacmd_lba_mid_lsb = ncq_err_page->ncq_cyl_low;
679482263d52Syt 	scmd->satacmd_lba_high_msb = ncq_err_page->ncq_cyl_high_ext;
679582263d52Syt 	scmd->satacmd_lba_high_lsb = ncq_err_page->ncq_cyl_high;
679682263d52Syt 	scmd->satacmd_device_reg = ncq_err_page->ncq_dev_head;
679782263d52Syt 	scmd->satacmd_status_reg = ncq_err_page->ncq_status;
679882263d52Syt 	scmd->satacmd_error_reg = ncq_err_page->ncq_error;
679982263d52Syt }
680082263d52Syt 
680168d33a25Syt /*
680268d33a25Syt  * Put the respective register value to sata_cmd_t for satacmd_flags.
68032fcbc377Syt  */
68042fcbc377Syt static void
68052fcbc377Syt ahci_copy_out_regs(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
68062fcbc377Syt {
68072fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_sec_count_msb)
68082fcbc377Syt 		scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
68092fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_low_msb)
68102fcbc377Syt 		scmd->satacmd_lba_low_msb = GET_RFIS_CYL_LOW_EXP(rfisp);
68112fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb)
68122fcbc377Syt 		scmd->satacmd_lba_mid_msb = GET_RFIS_CYL_MID_EXP(rfisp);
68132fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_high_msb)
68142fcbc377Syt 		scmd->satacmd_lba_high_msb = GET_RFIS_CYL_HI_EXP(rfisp);
68152fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb)
68162fcbc377Syt 		scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
68172fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb)
68182fcbc377Syt 		scmd->satacmd_lba_low_lsb = GET_RFIS_CYL_LOW(rfisp);
68192fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb)
68202fcbc377Syt 		scmd->satacmd_lba_mid_lsb = GET_RFIS_CYL_MID(rfisp);
68212fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb)
68222fcbc377Syt 		scmd->satacmd_lba_high_lsb = GET_RFIS_CYL_HI(rfisp);
68232fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_device_reg)
68242fcbc377Syt 		scmd->satacmd_device_reg = GET_RFIS_DEV_HEAD(rfisp);
68252fcbc377Syt 	if (scmd->satacmd_flags.sata_copy_out_error_reg)
68262fcbc377Syt 		scmd->satacmd_error_reg = GET_RFIS_ERROR(rfisp);
68272fcbc377Syt }
68282fcbc377Syt 
682968d33a25Syt static void
683068d33a25Syt ahci_log_fatal_error_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
683168d33a25Syt     uint32_t intr_status)
683268d33a25Syt {
683368d33a25Syt #ifndef __lock_lint
683468d33a25Syt 	_NOTE(ARGUNUSED(ahci_ctlp))
683568d33a25Syt #endif
683668d33a25Syt 
683768d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_IFS)
683868d33a25Syt 		cmn_err(CE_NOTE, "!ahci port %d has interface fatal "
683968d33a25Syt 		    "error", port);
684068d33a25Syt 
684168d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_HBDS)
684268d33a25Syt 		cmn_err(CE_NOTE, "!ahci port %d has bus data error", port);
684368d33a25Syt 
684468d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_HBFS)
684568d33a25Syt 		cmn_err(CE_NOTE, "!ahci port %d has bus fatal error", port);
684668d33a25Syt 
684768d33a25Syt 	if (intr_status & AHCI_INTR_STATUS_TFES)
684868d33a25Syt 		cmn_err(CE_NOTE, "!ahci port %d has task file error", port);
684968d33a25Syt 
685068d33a25Syt 	cmn_err(CE_NOTE, "!ahci port %d is trying to do error "
685168d33a25Syt 	    "recovery", port);
685268d33a25Syt }
685368d33a25Syt 
68542fcbc377Syt /*
68552fcbc377Syt  * Dump the serror message to the log.
68562fcbc377Syt  */
68572fcbc377Syt static void
685868d33a25Syt ahci_log_serror_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
68592fcbc377Syt     uint32_t port_serror)
68602fcbc377Syt {
686168d33a25Syt #ifndef __lock_lint
686268d33a25Syt 	_NOTE(ARGUNUSED(ahci_ctlp))
686368d33a25Syt #endif
68642fcbc377Syt 	char *err_str;
68652fcbc377Syt 
686682263d52Syt 	if (port_serror & SERROR_DATA_ERR_FIXED) {
68672fcbc377Syt 		err_str = "Recovered Data Integrity Error (I)";
68682fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
68692fcbc377Syt 		    "command error: port: %d, error: %s",
68702fcbc377Syt 		    port, err_str);
68712fcbc377Syt 	}
68722fcbc377Syt 
687382263d52Syt 	if (port_serror & SERROR_COMM_ERR_FIXED) {
68742fcbc377Syt 		err_str = "Recovered Communication Error (M)";
68752fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
68762fcbc377Syt 		    "command error: port: %d, error: %s",
68772fcbc377Syt 		    port, err_str);
68782fcbc377Syt 	}
68792fcbc377Syt 
688082263d52Syt 	if (port_serror & SERROR_DATA_ERR) {
68812fcbc377Syt 		err_str = "Transient Data Integrity Error (T)";
68822fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
68832fcbc377Syt 		    "command error: port: %d, error: %s",
68842fcbc377Syt 		    port, err_str);
68852fcbc377Syt 	}
68862fcbc377Syt 
688782263d52Syt 	if (port_serror & SERROR_PERSISTENT_ERR) {
68882fcbc377Syt 		err_str =
68892fcbc377Syt 		    "Persistent Communication or Data Integrity Error (C)";
68902fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
68912fcbc377Syt 		    "command error: port: %d, error: %s",
68922fcbc377Syt 		    port, err_str);
68932fcbc377Syt 	}
68942fcbc377Syt 
689582263d52Syt 	if (port_serror & SERROR_PROTOCOL_ERR) {
68962fcbc377Syt 		err_str = "Protocol Error (P)";
68972fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
68982fcbc377Syt 		    "command error: port: %d, error: %s",
68992fcbc377Syt 		    port, err_str);
69002fcbc377Syt 	}
69012fcbc377Syt 
690282263d52Syt 	if (port_serror & SERROR_INT_ERR) {
69032fcbc377Syt 		err_str = "Internal Error (E)";
69042fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69052fcbc377Syt 		    "command error: port: %d, error: %s",
69062fcbc377Syt 		    port, err_str);
69072fcbc377Syt 	}
69082fcbc377Syt 
690982263d52Syt 	if (port_serror & SERROR_PHY_RDY_CHG) {
69102fcbc377Syt 		err_str = "PhyRdy Change (N)";
69112fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69122fcbc377Syt 		    "command error: port: %d, error: %s",
69132fcbc377Syt 		    port, err_str);
69142fcbc377Syt 	}
69152fcbc377Syt 
691682263d52Syt 	if (port_serror & SERROR_PHY_INT_ERR) {
69172fcbc377Syt 		err_str = "Phy Internal Error (I)";
69182fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69192fcbc377Syt 		    "command error: port: %d, error: %s",
69202fcbc377Syt 		    port, err_str);
69212fcbc377Syt 	}
69222fcbc377Syt 
692382263d52Syt 	if (port_serror & SERROR_COMM_WAKE) {
69242fcbc377Syt 		err_str = "Comm Wake (W)";
69252fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69262fcbc377Syt 		    "command error: port: %d, error: %s",
69272fcbc377Syt 		    port, err_str);
69282fcbc377Syt 	}
69292fcbc377Syt 
693082263d52Syt 	if (port_serror & SERROR_10B_TO_8B_ERR) {
69312fcbc377Syt 		err_str = "10B to 8B Decode Error (B)";
69322fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69332fcbc377Syt 		    "command error: port: %d, error: %s",
69342fcbc377Syt 		    port, err_str);
69352fcbc377Syt 	}
69362fcbc377Syt 
693782263d52Syt 	if (port_serror & SERROR_DISPARITY_ERR) {
69382fcbc377Syt 		err_str = "Disparity Error (D)";
69392fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69402fcbc377Syt 		    "command error: port: %d, error: %s",
69412fcbc377Syt 		    port, err_str);
69422fcbc377Syt 	}
69432fcbc377Syt 
694482263d52Syt 	if (port_serror & SERROR_CRC_ERR) {
69452fcbc377Syt 		err_str = "CRC Error (C)";
69462fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69472fcbc377Syt 		    "command error: port: %d, error: %s",
69482fcbc377Syt 		    port, err_str);
69492fcbc377Syt 	}
69502fcbc377Syt 
695182263d52Syt 	if (port_serror & SERROR_HANDSHAKE_ERR) {
69522fcbc377Syt 		err_str = "Handshake Error (H)";
69532fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69542fcbc377Syt 		    "command error: port: %d, error: %s",
69552fcbc377Syt 		    port, err_str);
69562fcbc377Syt 	}
69572fcbc377Syt 
695882263d52Syt 	if (port_serror & SERROR_LINK_SEQ_ERR) {
69592fcbc377Syt 		err_str = "Link Sequence Error (S)";
69602fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69612fcbc377Syt 		    "command error: port: %d, error: %s",
69622fcbc377Syt 		    port, err_str);
69632fcbc377Syt 	}
69642fcbc377Syt 
696582263d52Syt 	if (port_serror & SERROR_TRANS_ERR) {
69662fcbc377Syt 		err_str = "Transport state transition error (T)";
69672fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69682fcbc377Syt 		    "command error: port: %d, error: %s",
69692fcbc377Syt 		    port, err_str);
69702fcbc377Syt 	}
69712fcbc377Syt 
697282263d52Syt 	if (port_serror & SERROR_FIS_TYPE) {
69732fcbc377Syt 		err_str = "Unknown FIS Type (F)";
69742fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69752fcbc377Syt 		    "command error: port: %d, error: %s",
69762fcbc377Syt 		    port, err_str);
69772fcbc377Syt 	}
69782fcbc377Syt 
697982263d52Syt 	if (port_serror & SERROR_EXCHANGED_ERR) {
69802fcbc377Syt 		err_str = "Exchanged (X)";
69812fcbc377Syt 		AHCIDBG2(AHCIDBG_ERRS, ahci_ctlp,
69822fcbc377Syt 		    "command error: port: %d, error: %s",
69832fcbc377Syt 		    port, err_str);
69842fcbc377Syt 	}
69852fcbc377Syt }
69862fcbc377Syt 
69872fcbc377Syt /*
69882fcbc377Syt  * This routine is to calculate the total number of ports implemented
69892fcbc377Syt  * by the HBA.
69902fcbc377Syt  */
69912fcbc377Syt static int
69922fcbc377Syt ahci_get_num_implemented_ports(uint32_t ports_implemented)
69932fcbc377Syt {
69942fcbc377Syt 	uint8_t i;
69952fcbc377Syt 	int num = 0;
69962fcbc377Syt 
69972fcbc377Syt 	for (i = 0; i < AHCI_MAX_PORTS; i++) {
69982fcbc377Syt 		if (((uint32_t)0x1 << i) & ports_implemented)
69992fcbc377Syt 			num++;
70002fcbc377Syt 	}
70012fcbc377Syt 
70022fcbc377Syt 	return (num);
70032fcbc377Syt }
70042fcbc377Syt 
70052fcbc377Syt static void
70062fcbc377Syt ahci_log(ahci_ctl_t *ahci_ctlp, uint_t level, char *fmt, ...)
70072fcbc377Syt {
70082fcbc377Syt 	va_list ap;
70092fcbc377Syt 
70102fcbc377Syt 	mutex_enter(&ahci_log_mutex);
70112fcbc377Syt 
70122fcbc377Syt 	va_start(ap, fmt);
70132fcbc377Syt 	if (ahci_ctlp) {
70142fcbc377Syt 		(void) sprintf(ahci_log_buf, "%s-[%d]:",
70152fcbc377Syt 		    ddi_get_name(ahci_ctlp->ahcictl_dip),
70162fcbc377Syt 		    ddi_get_instance(ahci_ctlp->ahcictl_dip));
70172fcbc377Syt 	} else {
70182fcbc377Syt 		(void) sprintf(ahci_log_buf, "ahci:");
70192fcbc377Syt 	}
70202fcbc377Syt 
70212fcbc377Syt 	(void) vsprintf(ahci_log_buf, fmt, ap);
70222fcbc377Syt 	va_end(ap);
70232fcbc377Syt 
70242fcbc377Syt 	cmn_err(level, "%s", ahci_log_buf);
70252fcbc377Syt 
70262fcbc377Syt 	mutex_exit(&ahci_log_mutex);
70272fcbc377Syt }
7028