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 **)®s, 438*95c11c1fSyt (uint_t *)®s_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