2fcbc377041d659446ded306a92901b4b0753b68yt * CDDL HEADER START
2fcbc377041d659446ded306a92901b4b0753b68yt * The contents of this file are subject to the terms of the
2fcbc377041d659446ded306a92901b4b0753b68yt * Common Development and Distribution License (the "License").
2fcbc377041d659446ded306a92901b4b0753b68yt * You may not use this file except in compliance with the License.
2fcbc377041d659446ded306a92901b4b0753b68yt * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2fcbc377041d659446ded306a92901b4b0753b68yt * See the License for the specific language governing permissions
2fcbc377041d659446ded306a92901b4b0753b68yt * and limitations under the License.
2fcbc377041d659446ded306a92901b4b0753b68yt * When distributing Covered Code, include this CDDL HEADER in each
2fcbc377041d659446ded306a92901b4b0753b68yt * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2fcbc377041d659446ded306a92901b4b0753b68yt * If applicable, add the following below this CDDL HEADER, with the
2fcbc377041d659446ded306a92901b4b0753b68yt * fields enclosed by brackets "[]" replaced with your own identifying
2fcbc377041d659446ded306a92901b4b0753b68yt * information: Portions Copyright [yyyy] [name of copyright owner]
2fcbc377041d659446ded306a92901b4b0753b68yt * CDDL HEADER END
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI (Advanced Host Controller Interface) SATA HBA Driver
13bcbb7a73761015c9ef46cac33040380196e57fyt * Power Management Support
13bcbb7a73761015c9ef46cac33040380196e57fyt * ------------------------
13bcbb7a73761015c9ef46cac33040380196e57fyt * At the moment, the ahci driver only implements suspend/resume to
13bcbb7a73761015c9ef46cac33040380196e57fyt * support Suspend to RAM on X86 feature. Device power management isn't
13bcbb7a73761015c9ef46cac33040380196e57fyt * implemented, link power management is disabled, and hot plug isn't
13bcbb7a73761015c9ef46cac33040380196e57fyt * allowed during the period from suspend to resume.
13bcbb7a73761015c9ef46cac33040380196e57fyt * For s/r support, the ahci driver only need to implement DDI_SUSPEND
13bcbb7a73761015c9ef46cac33040380196e57fyt * and DDI_RESUME entries, and don't need to take care of new requests
13bcbb7a73761015c9ef46cac33040380196e57fyt * sent down after suspend because the target driver (sd) has already
13bcbb7a73761015c9ef46cac33040380196e57fyt * handled these conditions, and blocked these requests. For the detailed
13bcbb7a73761015c9ef46cac33040380196e57fyt * information, please check with sdopen, sdclose and sdioctl routines.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * FMA header files
193974072f41a843678abf5f61979c748687e66bSherry Moore * This is the string displayed by modinfo, etc.
2fcbc377041d659446ded306a92901b4b0753b68yt * Function prototypes for driver entry points
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2fcbc377041d659446ded306a92901b4b0753b68yt * Function prototypes for SATA Framework interfaces
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_register_sata_hba_tran(ahci_ctl_t *, uint32_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_probe_port(dev_info_t *, sata_device_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_start(dev_info_t *, sata_pkt_t *spkt);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_abort(dev_info_t *, sata_pkt_t *, int);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_reset_dport(dev_info_t *, sata_device_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_hotplug_port_activate(dev_info_t *, sata_device_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_tran_hotplug_port_deactivate(dev_info_t *, sata_device_t *);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * FMA Prototypes
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void*);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_check_all_handle(ahci_ctl_t *);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_check_ctl_handle(ahci_ctl_t *);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_check_port_handle(ahci_ctl_t *, int);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_check_slot_handle(ahci_port_t *, int);
2fcbc377041d659446ded306a92901b4b0753b68yt * Local function prototypes
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic int ahci_setup_port_base_addresses(ahci_ctl_t *, ahci_port_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_dealloc_port_state(ahci_ctl_t *, uint8_t);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic int ahci_alloc_rcvd_fis(ahci_ctl_t *, ahci_port_t *);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic int ahci_alloc_cmd_list(ahci_ctl_t *, ahci_port_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_dealloc_cmd_list(ahci_ctl_t *, ahci_port_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_alloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_dealloc_cmd_tables(ahci_ctl_t *, ahci_port_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_alloc_pmult(ahci_ctl_t *, ahci_port_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_dealloc_pmult(ahci_ctl_t *, ahci_port_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_initialize_port(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic void ahci_staggered_spin_up(ahci_ctl_t *, uint8_t);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing Chinastatic void ahci_drain_ports_taskq(ahci_ctl_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_rdwr_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_read_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_write_pmult(ahci_ctl_t *, ahci_addr_t *, uint8_t, uint32_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_update_pmult_pscr(ahci_ctl_t *, ahci_addr_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_update_pmult_gscr(ahci_ctl_t *, ahci_addr_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_initialize_pmult(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_initialize_pmport(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_probe_pmult(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_probe_pmport(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *,
13bcbb7a73761015c9ef46cac33040380196e57fytstatic void ahci_disable_interface_pm(ahci_ctl_t *, uint8_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_start_port(ahci_ctl_t *, ahci_port_t *, uint8_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_find_dev_signature(ahci_ctl_t *, ahci_port_t *,
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_update_sata_registers(ahci_ctl_t *, uint8_t, sata_device_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_deliver_satapkt(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_do_sync_start(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_claim_free_slot(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_copy_err_cnxt(sata_cmd_t *, ahci_fis_d2h_register_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_copy_out_regs(sata_cmd_t *, ahci_fis_d2h_register_t *);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic void ahci_add_doneq(ahci_port_t *, sata_pkt_t *, int);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic void ahci_flush_doneq(ahci_port_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_software_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_port_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_pmport_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_reject_all_abort_pkts(ahci_ctl_t *, ahci_port_t *, uint8_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_reset_device_reject_pkts(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_reset_pmdevice_reject_pkts(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_reset_port_reject_pkts(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_put_port_into_notrunning_state(ahci_ctl_t *, ahci_port_t *,
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_restart_port_wait_till_ready(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t, int, int *);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_mop_commands(ahci_ctl_t *, ahci_port_t *, uint32_t,
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic uint32_t ahci_get_rdlogext_data(ahci_ctl_t *, ahci_port_t *, uint8_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_get_rqsense_data(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_fatal_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_pmult_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_timeout_pkts(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_events_handler(void *);
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic void ahci_port_intr(ahci_ctl_t *, ahci_port_t *, uint8_t);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing Chinastatic int ahci_add_intrs(ahci_ctl_t *, int);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_enable_port_intrs(ahci_ctl_t *, uint8_t);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_disable_port_intrs(ahci_ctl_t *, uint8_t);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic int ahci_intr_cmd_cmplt(ahci_ctl_t *, ahci_port_t *, uint8_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_intr_set_device_bits(ahci_ctl_t *, ahci_port_t *, uint8_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_intr_ncq_events(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_intr_pmult_sntf_events(ahci_ctl_t *, ahci_port_t *, uint8_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_intr_port_connect_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_intr_device_mechanical_presence_status(ahci_ctl_t *,
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_intr_phyrdy_change(ahci_ctl_t *, ahci_port_t *, uint8_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_intr_non_fatal_error(ahci_ctl_t *, ahci_port_t *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_intr_fatal_error(ahci_ctl_t *, ahci_port_t *,
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_intr_cold_port_detect(ahci_ctl_t *, ahci_port_t *, uint8_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_get_ahci_addr(ahci_ctl_t *, sata_device_t *, ahci_addr_t *);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing Chinastatic void ahci_log_fatal_error_message(ahci_ctl_t *, uint8_t, uint32_t);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing Chinastatic void ahci_dump_commands(ahci_ctl_t *, uint8_t, uint32_t);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eytstatic void ahci_log_serror_message(ahci_ctl_t *, uint8_t, uint32_t, int);
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the data buffer
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0x3fffffull, /* dma_attr_count_max i.e. for one cookie */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the rcvd FIS
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the command list
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for cmd tables
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt/* Device access attributes */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* refcnt */
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/* The following variables are watchdog handler related */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic clock_t ahci_watchdog_timeout = 5; /* 5 seconds */
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China * This static variable indicates the size of command table,
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China * and it's changeable with prdt number, which ahci_dma_prdt_number
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * The below global variables are tunable via /etc/system
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * ahci_dma_prdt_number
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * ahci_msi_enabled
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * ahci_buf_64bit_dma
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * ahci_commu_64bit_dma
2fcbc377041d659446ded306a92901b4b0753b68yt/* The number of Physical Region Descriptor Table(PRDT) in Command Table */
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/* AHCI MSI is tunable */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing Chinaboolean_t ahci_msi_enabled = B_TRUE;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * 64-bit dma addressing for data buffer is tunable
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * The variable controls only the below value:
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * DBAU (upper 32-bits physical address of data block)
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing Chinaboolean_t ahci_buf_64bit_dma = B_TRUE;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * 64-bit dma addressing for communication system descriptors is tunable
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * The variable controls the below three values:
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * PxCLBU (upper 32-bits for the command list base physical address)
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * PxFBU (upper 32-bits for the received FIS base physical address)
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * CTBAU (upper 32-bits of command table base)
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing Chinaboolean_t ahci_commu_64bit_dma = B_TRUE;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * By default, 64-bit dma for data buffer will be disabled for AMD/ATI SB600
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * chipset. If the users want to have a try with 64-bit dma, please change
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * the below variable value to enable it.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing Chinaboolean_t sb600_buf_64bit_dma_disable = B_TRUE;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * By default, 64-bit dma for command buffer will be disabled for AMD/ATI
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * SB600/700/710/750/800. If the users want to have a try with 64-bit dma,
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * please change the below value to enable it.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing Chinaboolean_t sbxxx_commu_64bit_dma_disable = B_TRUE;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * End of global tunable variable definition
f5f2d263454d943a366844932bdb677530ba733bFred Herarduint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT);
689d74b0a0dba643450e7fc74a03425c963657e7yt/* The following is needed for ahci_log() */
2fcbc377041d659446ded306a92901b4b0753b68yt/* Opaque state pointer initialized by ddi_soft_state_init() */
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci module initialization.
2fcbc377041d659446ded306a92901b4b0753b68yt ret = ddi_soft_state_init(&ahci_statep, sizeof (ahci_ctl_t), 0);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* watchdog tick */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci module uninitialize.
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Remove the resources allocated in _init(). */
2fcbc377041d659446ded306a92901b4b0753b68yt * _info entry point
2fcbc377041d659446ded306a92901b4b0753b68yt * The attach entry point for dev_ops.
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_attach enter",
2fcbc377041d659446ded306a92901b4b0753b68yt switch (cmd) {
13bcbb7a73761015c9ef46cac33040380196e57fyt * During DDI_RESUME, the hardware state of the device
13bcbb7a73761015c9ef46cac33040380196e57fyt * (power may have been removed from the device) must be
13bcbb7a73761015c9ef46cac33040380196e57fyt * restored, allow pending requests to continue, and
13bcbb7a73761015c9ef46cac33040380196e57fyt * service new requests.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * GHC.AE must be set to 1 before any other AHCI register
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * is accessed
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Restart watch thread */
13bcbb7a73761015c9ef46cac33040380196e57fyt (void (*)(void *))ahci_watchdog_handler,
13bcbb7a73761015c9ef46cac33040380196e57fyt * Re-initialize the controller and enable the interrupts and
13bcbb7a73761015c9ef46cac33040380196e57fyt * restart all the ports.
13bcbb7a73761015c9ef46cac33040380196e57fyt * Note that so far we don't support hot-plug during
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "Failed to initialize the controller "
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate soft state */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Initialize the cport/port mapping */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt for (i = 0; i < AHCI_MAX_PORTS; i++) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Initialize FMA properties */
2fcbc377041d659446ded306a92901b4b0753b68yt * Now map the AHCI base address; which includes global
2fcbc377041d659446ded306a92901b4b0753b68yt * registers and port control registers
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt * According to the spec, the AHCI Base Address is BAR5,
13bcbb7a73761015c9ef46cac33040380196e57fyt * but BAR0-BAR4 are optional, so we need to check which
13bcbb7a73761015c9ef46cac33040380196e57fyt * rnumber is used for BAR5.
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt * search through DDI "reg" property for the AHCI register set
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt /* AHCI Base Address is located at 0x24 offset */
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot find AHCI register set",
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * GHC.AE must be set to 1 before any other AHCI register
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * is accessed
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the AHCI version information */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_version = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: hba AHCI version = %x.%x", instance,
2fcbc377041d659446ded306a92901b4b0753b68yt /* We don't support controllers whose versions are lower than 1.0 */
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "ahci%d: Don't support AHCI HBA with lower "
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the HBA capabilities information */
2fcbc377041d659446ded306a92901b4b0753b68yt cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba capabilities = 0x%x",
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* CAP2 (HBA Capabilities Extended) is available since AHCI spec 1.2 */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Get the HBA capabilities extended information */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka cap2_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "hba capabilities extended = 0x%x", cap2_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Get the interface speed supported by the HBA */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 1 (1.5Gbps)", NULL);
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 2 (3 Gbps)", NULL);
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 3 (6 Gbps)", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the number of command slots supported by the HBA */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the bit map which indicates ports implemented by the HBA */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Max port number implemented */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the number of implemented ports by the HBA */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "hba number of implemented ports: %d",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt /* Check whether HBA supports 64bit DMA addressing */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba does not support 64-bit addressing", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for the support of Port Multiplier */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cap |= AHCI_CAP_PMULT_CBSS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support FIS-based switching ? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cap |= AHCI_CAP_PMULT_FBSS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hba supports FIS-based switching (FBSS)", NULL);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Checking for Support Command List Override */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for Asynchronous Notification */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hba supports asynchronous notification.", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle)
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot set up pci configure space",
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China * Check the pci configuration space, and set caps. We also
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China * handle the hardware defect in this function.
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * For example, force ATI SB600 to use 32-bit dma addressing
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * since it doesn't support 64-bit dma though its CAP register
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * declares it support.
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: ahci_config_space_init failed",
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable the whole controller interrupts before adding
2fcbc377041d659446ded306a92901b4b0753b68yt * interrupt handlers(s).
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get supported interrupt types */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_intr_get_supported_types(dip, &intr_types) != DDI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: ddi_intr_get_supported_types failed",
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_supported_types() returned: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_msi_enabled && (intr_types & DDI_INTR_TYPE_MSI)) {
2fcbc377041d659446ded306a92901b4b0753b68yt * Try MSI first, but fall back to FIXED if failed
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_MSI) ==
2fcbc377041d659446ded306a92901b4b0753b68yt "MSI registration failed, "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_FIXED) ==
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Interrupt registration failed", instance);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Initialize the controller mutex */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_init(&ahci_ctlp->ahcictl_mutex, NULL, MUTEX_DRIVER,
2fcbc377041d659446ded306a92901b4b0753b68yt } else if (ahci_dma_prdt_number > AHCI_MAX_PRDT_NUMBER) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_attach: ahci_dma_prdt_number set by user is 0x%x,"
2fcbc377041d659446ded306a92901b4b0753b68yt " ahci_cmd_table_size is 0x%x",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_rcvd_fis_dma_attr = rcvd_fis_dma_attr;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_cmd_list_dma_attr = cmd_list_dma_attr;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_cmd_table_dma_attr = cmd_table_dma_attr;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * enable 64bit dma for data buffer for SB600 if
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * sb600_buf_64bit_dma_disable is B_FALSE
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China if ((ahci_buf_64bit_dma == B_FALSE) ||
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ((ahci_ctlp->ahcictl_cap & AHCI_CAP_BUF_32BIT_DMA) &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China !(sb600_buf_64bit_dma_disable == B_FALSE &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_venid == 0x1002 &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_devid == 0x4380))) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * enable 64bit dma for command buffer for SB600/700/710/800
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * if sbxxx_commu_64bit_dma_disable is B_FALSE
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China if ((ahci_commu_64bit_dma == B_FALSE) ||
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ((ahci_ctlp->ahcictl_cap & AHCI_CAP_COMMU_32BIT_DMA) &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China !(sbxxx_commu_64bit_dma_disable == B_FALSE &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_venid == 0x1002 &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China (ahci_ctlp->ahcictl_devid == 0x4380 ||
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_devid == 0x4391)))) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Allocate the ports structure */
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot allocate ports structure",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Initialize the controller and ports.
2fcbc377041d659446ded306a92901b4b0753b68yt /* Start one thread to check packet timeouts */
2fcbc377041d659446ded306a92901b4b0753b68yt (void (*)(void *))ahci_watchdog_handler,
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_register_sata_hba_tran(ahci_ctlp, cap_status)) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: sata hba tran registration failed",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Check all handles at the end of the attach operation. */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_all_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmn_err(CE_WARN, "!ahci%d: invalid dma/acc handles",
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!", NULL);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* FMA message */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_fm_ereport(ahci_ctlp, DDI_FM_DEVICE_NO_RESPONSE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip, DDI_SERVICE_LOST);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt * The detach entry point for dev_ops.
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt switch (cmd) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* disable the interrupts for an uninterrupted detach */
2fcbc377041d659446ded306a92901b4b0753b68yt /* unregister from the sata framework. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* stop the watchdog handler */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* uninitialize the controller */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* remove the interrupts */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* deallocate the ports structures */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* destroy mutex */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* teardown the pci config */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt /* remove the reg maps. */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* release fma resource */
2fcbc377041d659446ded306a92901b4b0753b68yt /* free the soft state. */
13bcbb7a73761015c9ef46cac33040380196e57fyt * The steps associated with suspension must include putting
13bcbb7a73761015c9ef46cac33040380196e57fyt * the underlying device into a quiescent state so that it
13bcbb7a73761015c9ef46cac33040380196e57fyt * will not generate interrupts or modify or access memory.
13bcbb7a73761015c9ef46cac33040380196e57fyt /* stop the watchdog handler */
13bcbb7a73761015c9ef46cac33040380196e57fyt * drain the taskq
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_drain_ports_taskq(ahci_ctlp);
13bcbb7a73761015c9ef46cac33040380196e57fyt * Disable the interrupts and stop all the ports.
2fcbc377041d659446ded306a92901b4b0753b68yt * The info entry point for dev_ops.
2fcbc377041d659446ded306a92901b4b0753b68yt#endif /* __lock_lint */
2fcbc377041d659446ded306a92901b4b0753b68yt * Registers the ahci with sata framework.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_register_sata_hba_tran(ahci_ctl_t *ahci_ctlp, uint32_t cap_status)
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate memory for the sata_hba_tran */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran = kmem_zalloc(sizeof (sata_hba_tran_t), KM_SLEEP);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_hba_tran->sata_tran_hba_rev = SATA_TRAN_HBA_REV;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_hba_dip = ahci_ctlp->ahcictl_dip;
2fcbc377041d659446ded306a92901b4b0753b68yt /* Report the number of implemented ports */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Support ATAPI device */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_hba_tran->sata_tran_hba_features_support = SATA_CTLF_ATAPI;
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the data transfer capability for PIO command by the HBA */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "DRQ block data transfer for PIO command protocol", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt * According to the AHCI spec, the ATA/ATAPI-7 queued feature set
82263d52a84b4a969aa53f8ededddff841646ad9yt * is not supported by AHCI (including the READ QUEUED (EXT), WRITE
82263d52a84b4a969aa53f8ededddff841646ad9yt * QUEUED (EXT), and SERVICE commands). Queued operations are
82263d52a84b4a969aa53f8ededddff841646ad9yt * supported in AHCI using the READ FPDMA QUEUED and WRITE FPDMA
82263d52a84b4a969aa53f8ededddff841646ad9yt * QUEUED commands when the HBA and device support native command
82263d52a84b4a969aa53f8ededddff841646ad9yt * queuing(NCQ).
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATA_CTLF_NCQ will be set to sata_tran_hba_features_support if the
82263d52a84b4a969aa53f8ededddff841646ad9yt * CAP register of the HBA indicates NCQ is supported.
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATA_CTLF_NCQ cannot be set if AHCI_CAP_NO_MCMDLIST_NONQUEUE is
82263d52a84b4a969aa53f8ededddff841646ad9yt * set because the previous register content of PxCI can be re-written
82263d52a84b4a969aa53f8ededddff841646ad9yt * in the register write.
82263d52a84b4a969aa53f8ededddff841646ad9yt !(ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_hba_tran->sata_tran_hba_features_support |= SATA_CTLF_NCQ;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support port multiplier? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_tran->sata_tran_hba_features_support |=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support FIS-based switching for port multiplier? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_tran->sata_tran_hba_features_support |=
2fcbc377041d659446ded306a92901b4b0753b68yt /* Report the number of command slots */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_hba_qdepth = ahci_ctlp->ahcictl_num_cmd_slots;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_probe_port = ahci_tran_probe_port;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_reset_dport = ahci_tran_reset_dport;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_hotplug_ops = &ahci_tran_hotplug_ops;
2fcbc377041d659446ded306a92901b4b0753b68yt * When SATA framework adds support for pwrmgt the
2fcbc377041d659446ded306a92901b4b0753b68yt * pwrmgt_ops needs to be updated
2fcbc377041d659446ded306a92901b4b0753b68yt /* Attach it to SATA framework */
2fcbc377041d659446ded306a92901b4b0753b68yt if (sata_hba_attach(ahci_ctlp->ahcictl_dip, sata_hba_tran, DDI_ATTACH)
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free((void *)sata_hba_tran, sizeof (sata_hba_tran_t));
2fcbc377041d659446ded306a92901b4b0753b68yt * Unregisters the ahci with sata framework.
2fcbc377041d659446ded306a92901b4b0753b68yt /* Detach from the SATA framework. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (sata_hba_detach(ahci_ctlp->ahcictl_dip, DDI_DETACH) !=
2fcbc377041d659446ded306a92901b4b0753b68yt /* Deallocate sata_hba_tran. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d", (addrp)->aa_port); \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d (pmult)", (addrp)->aa_port); \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d:%d", (addrp)->aa_port, \
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_tran_probe_port is called by SATA framework. It returns port state,
2fcbc377041d659446ded306a92901b4b0753b68yt * port status registers and an attached device type via sata_device
2fcbc377041d659446ded306a92901b4b0753b68yt * structure.
2fcbc377041d659446ded306a92901b4b0753b68yt * We return the cached information from a previous hardware probe. The
2fcbc377041d659446ded306a92901b4b0753b68yt * actual hardware probing itself was done either from within
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_initialize_controller() during the driver attach or from a phy
2fcbc377041d659446ded306a92901b4b0753b68yt * ready change interrupt handler.
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port enter: port %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if ((AHCI_ADDR_IS_PMULT(&addr) || AHCI_ADDR_IS_PMPORT(&addr)) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* port mutliplier is removed. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The sata_device may refer to
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. A controller port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * A controller port should be ready here.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. A port multiplier.
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang * SATA_ADDR_PMULT_SPEC - if it is not initialized yet, initialize
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang * it and register the port multiplier to the framework.
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang * SATA_ADDR_PMULT - check the status of all its device ports.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 3. A port multiplier port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If it has not been initialized, initialized it.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * A port multiplier or a port multiplier port may require some
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * initialization because we cannot do these time-consuming jobs in an
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * interrupt context.
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (sd->satadev_addr.qual & SATA_ADDR_PMULT_SPEC) {
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang /* Initialize registers on a port multiplier */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang "ahci_tran_probe_port: "
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang } else if (sd->satadev_addr.qual & SATA_ADDR_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check pmports hotplug events */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_probe_pmult(ahci_ctlp, ahci_portp, &addr);
d1b621d50245b0085f783eded42445453fa2d670Xiao-Yu Zhang } else if (sd->satadev_addr.qual & (SATA_ADDR_PMPORT |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Update port state and device type */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT FAILED", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT SHUTDOWN", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT PWROFF", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT PWRON", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT NORMAL %x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang device_type = AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s DISK found", portstr);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * HBA driver only knows it's an ATAPI device, and don't know
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China * it's CD/DVD, tape or ATAPI disk because the ATAPI device
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China * type need to be determined by checking IDENTIFY PACKET
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China sd->satadev_type = SATA_DTYPE_ATAPI;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s ATAPI found", portstr);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(AHCI_ADDR_IS_PORT(&addr) || AHCI_ADDR_IS_PMULT(&addr));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Update the number of pmports. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s Port Multiplier found",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s Unknown device found",
2fcbc377041d659446ded306a92901b4b0753b68yt /* we don't support any other device types */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s No device found", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Register update only fails while probing a pmult/pmport */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(&addr) || AHCI_ADDR_IS_PMULT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_update_sata_registers(ahci_ctlp, port, sd);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Check handles for the sata registers access */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_port_handle(ahci_ctlp, port) != DDI_SUCCESS)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * There are four operation modes in sata framework:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_INTERRUPTS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_POLLING
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_ASYNCH
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Their combined meanings as following:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The command has to be completed before sata_tran_start functions returns.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Either interrupts or polling could be used - it's up to the driver.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Mode used currently for internal, sata-module initiated operations.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * It is the same as the one above.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH | SATA_OPMODE_POLLING
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The command has to be completed before sata_tran_start function returns.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * No interrupt used, polling only. This should be the mode used for scsi
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * packets with FLAG_NOINTR.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_ASYNCH | SATA_OPMODE_INTERRUPTS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The command may be queued (callback function specified). Interrupts could
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * be used. It's normal operation mode.
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to transport a sata packet down stream.
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start enter: cport %d satapkt 0x%p",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &spkt->satapkt_device, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Sanity check */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_device.satadev_type = SATA_DTYPE_NONE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_device.satadev_state = SATA_STATE_UNKNOWN;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning PORT_ERROR while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning PORT_ERROR "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "while sub-link is not initialized "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_STATE(ahci_portp, &addr) & SATA_PSTATE_FAILED ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_GET_STATE(ahci_portp, &addr) & SATA_PSTATE_SHUTDOWN||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_GET_STATE(ahci_portp, &addr) & SATA_PSTATE_PWROFF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * In case the target driver would send the packet before
2fcbc377041d659446ded306a92901b4b0753b68yt * sata framework can have the opportunity to process those
2fcbc377041d659446ded306a92901b4b0753b68yt * event reports.
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning PORT_ERROR while "
2fcbc377041d659446ded306a92901b4b0753b68yt "port in FAILED/SHUTDOWN/PWROFF state: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr) == SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * SATA_DTYPE_NONE.
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning PORT_ERROR while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* R/W PMULT command will occupy the whole HBA port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning BUSY while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "executing READ/WRITE PORT-MULT command: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning BUSY while "
2fcbc377041d659446ded306a92901b4b0753b68yt * SATA HBA driver should remember that a device was reset and it
2fcbc377041d659446ded306a92901b4b0753b68yt * is supposed to reject any packets which do not specify either
2fcbc377041d659446ded306a92901b4b0753b68yt * SATA_IGNORE_DEV_RESET_STATE or SATA_CLEAR_DEV_RESET_STATE.
2fcbc377041d659446ded306a92901b4b0753b68yt * This is to prevent a race condition when a device was arbitrarily
2fcbc377041d659446ded306a92901b4b0753b68yt * reset by the HBA driver (and lost it's setting) and a target
2fcbc377041d659446ded306a92901b4b0753b68yt * driver sending some commands to a device before the sata framework
2fcbc377041d659446ded306a92901b4b0753b68yt * has a chance to restore the device setting (such as cache enable/
2fcbc377041d659446ded306a92901b4b0753b68yt * disable or other resettable stuff).
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * It is unnecessary to use specific flags to indicate
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * reset_in_progress for a pmport. While mopping, all command will be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * mopped so that the entire HBA port is being dealt as a single
2fcbc377041d659446ded306a92901b4b0753b68yt if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start [CLEAR] the "
2fcbc377041d659446ded306a92901b4b0753b68yt ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset &&
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning BUSY while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start: packet 0x%p [PASSTHRU] at port %d",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning BUSY while "
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China * If a SYNC command to be executed in interrupt context,
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China * bounce it back to sata module.
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China if (!(spkt->satapkt_op_mode & SATA_OPMODE_POLLING) &&
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China spkt->satapkt_reason = SATA_PKT_BUSY;
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China "ahci_tran_start returning BUSY while "
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China "sending SYNC mode under interrupt context: "
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China mutex_exit(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* We need to do the sync start now */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Async start, using interrupt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_deliver_satapkt(ahci_ctlp, ahci_portp, &addr, spkt)
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start "
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Failed to deliver packet to the controller.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check if it's caused by invalid handles.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_check_port_handle(ahci_ctlp, port) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH flag is set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If SATA_OPMODE_POLLING flag is set, then we must poll the command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * without interrupt, otherwise we can still use the interrupt.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_do_sync_start(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_do_sync_start enter: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d spkt 0x%p", port, addrp->aa_pmport, spkt);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Simulate the interrupt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port %d satapkt 0x%p timed out\n",
82263d52a84b4a969aa53f8ededddff841646ad9yt * Note that the driver always uses the slot 0 to deliver
82263d52a84b4a969aa53f8ededddff841646ad9yt * REQUEST SENSE or READ LOG EXT command
82263d52a84b4a969aa53f8ededddff841646ad9yt * Searches for and claims a free command slot.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Returns value:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * AHCI_FAILURE returned only if
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. No empty slot left
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Non-queued command requested while queued command(s) is outstanding
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 3. Queued command requested while non-queued command(s) is outstanding
82263d52a84b4a969aa53f8ededddff841646ad9yt * 4. HBA doesn't support multiple-use of command list while already a
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * non-queued command is oustanding
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 5. Queued command requested while some queued command(s) has been
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * outstanding on a different port multiplier port. (AHCI spec 1.2,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * claimed slot number returned if succeeded
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: it will always return slot 0 for following commands to simplify the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. REQUEST SENSE or READ LOG EXT command during error recovery process
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. READ/WRITE PORTMULT command
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_claim_free_slot(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_claim_free_slot enter "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahciport_pending_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahciport_pending_ncq_tags = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt * According to the AHCI spec, system software is responsible to
82263d52a84b4a969aa53f8ededddff841646ad9yt * ensure that queued and non-queued commands are not mixed in
82263d52a84b4a969aa53f8ededddff841646ad9yt * the command list.
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Non-NCQ command request */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: there is still pending "
82263d52a84b4a969aa53f8ededddff841646ad9yt "queued command(s) in the command list, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "so no available slot for the non-queued "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_claim_free_slot: there is still pending "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "read/write port-mult command(s) in command list, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "so no available slot for the non-queued command",
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: HBA cannot support multiple-"
f5f2d263454d943a366844932bdb677530ba733bFred Herard "use of the command list for non-queued commands",
82263d52a84b4a969aa53f8ededddff841646ad9yt /* NCQ command request */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: there is still pending "
82263d52a84b4a969aa53f8ededddff841646ad9yt "non-queued command(s) in the command list, "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "so no available slot for the queued command",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NCQ commands cannot be sent to different port multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ports in Command-Based Switching mode
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: In Command-Based Switching mode, AHCI controller
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * usually reports a 'Handshake Error' when multiple NCQ
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * commands are outstanding simultaneously.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_DEV_TYPE(ahci_portp, addrp) == SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_PMULT_FBSS) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_claim_free_slot: there is still "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "pending queued command(s) in the "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "command list for another Port Multiplier "
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Error retrieval command request */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: slot 0 is allocated for REQUEST "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (command_type == AHCI_RDWR_PMULT_CMD) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * An extra check on PxCI. Sometimes PxCI bits may not be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * cleared during hot-plug or error recovery process.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, addrp->aa_port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_claim_free_slot: there is still pending "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "command(s) in command list (0x%x/0x%x, PxCI %x),"
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "so no available slot for R/W PMULT command.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_claim_free_slot: slot 0 is allocated for "
82263d52a84b4a969aa53f8ededddff841646ad9yt * According to the AHCI spec, to allow a simple mechanism for the
82263d52a84b4a969aa53f8ededddff841646ad9yt * HBA to map command list slots to queue entries, software must
82263d52a84b4a969aa53f8ededddff841646ad9yt * match the tag number it uses to the slot it is placing the command
82263d52a84b4a969aa53f8ededddff841646ad9yt * in. For example, if a queued command is placed in slot 5, the tag
82263d52a84b4a969aa53f8ededddff841646ad9yt * for that command must be 5.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_NCQ_PMPORT(ahci_portp) = addrp->aa_pmport;
2fcbc377041d659446ded306a92901b4b0753b68yt * Builds the Command Table for the sata packet and delivers it to controller.
2fcbc377041d659446ded306a92901b4b0753b68yt * Returns:
2fcbc377041d659446ded306a92901b4b0753b68yt * slot number if we can obtain a slot successfully
2fcbc377041d659446ded306a92901b4b0753b68yt * otherwise, return AHCI_FAILURE
2fcbc377041d659446ded306a92901b4b0753b68ytahci_deliver_satapkt(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if the command is a NCQ command */
82263d52a84b4a969aa53f8ededddff841646ad9yt * When NCQ is support, system software must determine the
82263d52a84b4a969aa53f8ededddff841646ad9yt * maximum tag allowed by the device and the HBA, and it
82263d52a84b4a969aa53f8ededddff841646ad9yt * must use a value not beyond of the lower bound of the two.
82263d52a84b4a969aa53f8ededddff841646ad9yt * Sata module is going to calculate the qdepth and send
82263d52a84b4a969aa53f8ededddff841646ad9yt * down to HBA driver via sata_cmd.
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_qdepth = scmd->satacmd_flags.sata_max_queue_depth + 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt * At the moment, the driver doesn't support the dynamic
82263d52a84b4a969aa53f8ededddff841646ad9yt * setting of the maximum ncq depth, and the value can be
82263d52a84b4a969aa53f8ededddff841646ad9yt * set either during the attach or after hot-plug insertion.
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_deliver_satapkt: port %d the max tags for "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt " port %d the max tag for NCQ command is "
82263d52a84b4a969aa53f8ededddff841646ad9yt "requested to change from %d to %d, at the"
82263d52a84b4a969aa53f8ededddff841646ad9yt " moment the driver doesn't support the "
82263d52a84b4a969aa53f8ededddff841646ad9yt "dynamic change so it's going to "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "still use the previous tag value",
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if the command is an error retrieval command */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check if the command is an read/write pmult command */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if there is an empty command slot */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmd_slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "no free command slot", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_deliver_satapkt enter: cmd_reg: 0x%x, cmd_slot: 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt /* For data transfer operations, it is the H2D Register FIS */
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PMP field only make sense when target is a port multiplier or a
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * device behind a port multiplier. Otherwise should set it to 0.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMULT(addrp) || AHCI_ADDR_IS_PMPORT(addrp))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_COMMAND(h2d_register_fisp, scmd->satacmd_cmd_reg);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_FEATURES(h2d_register_fisp, scmd->satacmd_features_reg);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_SECTOR_COUNT(h2d_register_fisp, scmd->satacmd_sec_count_lsb);
82263d52a84b4a969aa53f8ededddff841646ad9yt * satacmd_addr_type will be 0 for the commands below:
82263d52a84b4a969aa53f8ededddff841646ad9yt * ATAPI command
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_IDLE_IM
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_STANDBY_IM
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_DOWNLOAD_MICROCODE
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_FLUSH_CACHE
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_SET_FEATURES
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_SMART
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_ID_PACKET_DEVICE
82263d52a84b4a969aa53f8ededddff841646ad9yt * SATAC_ID_DEVICE
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * SATAC_READ_PORTMULT
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * SATAC_WRITE_PORTMULT
689d74b0a0dba643450e7fc74a03425c963657e7yt /* FALLTHRU */
689d74b0a0dba643450e7fc74a03425c963657e7yt /* FALLTHRU */
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[7:0] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[15:8] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[23:16] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [27:24] (also called dev_head) */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_DEV_HEAD(h2d_register_fisp, scmd->satacmd_device_reg);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[7:0] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[15:8] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[23:16] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [31:24] */
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [39:32] */
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [47:40] */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set dev_head */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set the extended sector count and features */
82263d52a84b4a969aa53f8ededddff841646ad9yt * For NCQ command (READ/WRITE FPDMA QUEUED), sector count 7:0 is
82263d52a84b4a969aa53f8ededddff841646ad9yt * filled into features field, and sector count 8:15 is filled into
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China * features (exp) field. The hba driver doesn't need to anything
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China * special with regard to this, since sata framework has already
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China * However the driver needs to make sure TAG is filled into sector
2fcbc377041d659446ded306a92901b4b0753b68yt "ncookies = 0x%x, ahci_dma_prdt_number = 0x%x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[cmd_slot] = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt /* *** now fill the scatter gather list ******* */
2fcbc377041d659446ded306a92901b4b0753b68yt for (i = 0; i < ncookies; i++) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[cmd_slot] +=
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China scmd->satacmd_dma_cookie_list[i].dmac_size;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahciport_prd_bytecounts 0x%x for cmd_slot 0x%x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[cmd_slot], cmd_slot);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* The ACMD field is filled in for ATAPI command */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set the number of entries in the PRD table */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set the length of the command in the CFIS area */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_FIS_LENGTH(cmd_header, AHCI_H2D_REGISTER_FIS_LENGTH);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PMP field only make sense when target is a port multiplier or a
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * device behind a port multiplier. Otherwise should set it to 0.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMULT(addrp) || AHCI_ADDR_IS_PMPORT(addrp))
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "command data direction is "
2fcbc377041d659446ded306a92901b4b0753b68yt "sata_data_direction = 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set A bit if it is an ATAPI command */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set W bit if data is going to the device */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (scmd->satacmd_flags.sata_data_direction == SATA_DIR_WRITE)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Set the prefetchable bit - this bit is only valid if the PRDTL
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * field is non-zero or the ATAPI 'A' bit is set in the command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * header. This bit cannot be set when using native command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * queuing commands or when using FIS-based switching with a Port
82263d52a84b4a969aa53f8ededddff841646ad9yt * multiplier.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Now remember the sata packet in ahciport_slot_pkts[].
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Error retrieval command and r/w port multiplier command will
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * be stored specifically for each port.
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * Keep the timeout value
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[cmd_slot] = spkt->satapkt_time;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * If the intial timout is less than 1 tick, then make it longer by
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * 1 tick to avoid immediate timeout
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (ahci_portp->ahciport_slot_timeout[cmd_slot] <=
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[cmd_slot] +=
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (ahci_debug_flags & AHCIDBG_ATACMD &&
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China scmd->satacmd_cmd_reg != SATAC_PACKET ||
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_debug_flags & AHCIDBG_ATAPICMD &&
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China scmd->satacmd_cmd_reg == SATAC_PACKET) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /* Dump the command header and table */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_log(ahci_ctlp, CE_WARN, "\n");
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_log(ahci_ctlp, CE_WARN, "Command header&table for spkt "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "0x%p cmd_reg 0x%x port %d", spkt,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Command Header:%8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /* Dump the H2D register FIS */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr = (uint32_t *)h2d_register_fisp;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Command FIS: %8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /* Dump the ACMD register FIS */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr2 = (uint8_t *)&(cmd_table->ahcict_atapi_cmd);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China for (i = 0; i < SATA_ATAPI_MAX_CDB_LEN/8; i++)
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (ahci_debug_flags & AHCIDBG_ATAPICMD)
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " ATAPI command: %2x %2x %2x %2x "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "%2x %2x %2x %2x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr2[8 * i + 6], ptr2[8 * i + 7]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /* Dump the PRDT */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China for (i = 0; i < ncookies; i++) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr = (uint32_t *)&(cmd_table->ahcict_prdt[i]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Cookie %d: %8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China i, ptr[0], ptr[1], ptr[2], ptr[3]);
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_dma_handle[cmd_slot]) != DDI_FM_OK) ||
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Set the corresponding bit in the PxSACT.DS for queued command */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt "
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Make sure the command is started by the PxSACT/PxCI */
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by the sata framework to abort the previously sent packet(s).
2fcbc377041d659446ded306a92901b4b0753b68yt * Reset device to abort commands.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_abort(dev_info_t *dip, sata_pkt_t *spkt, int flag)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * commands are being mopped, therefore there is nothing else to do
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort: port %d is in "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If AHCI_PORT_FLAG_RDWR_PMULT flag is set, it means a R/W PMULT
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * command is being executed so no other commands is outstanding,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * nothing to do.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_RDWR_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_abort: port %d is reading/writing "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port multiplier, so just return directly ", port);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
2fcbc377041d659446ded306a92901b4b0753b68yt * In case the targer driver would send the request before
2fcbc377041d659446ded306a92901b4b0753b68yt * sata framework can have the opportunity to process those
2fcbc377041d659446ded306a92901b4b0753b68yt * event reports.
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort returning SATA_FAILURE while "
2fcbc377041d659446ded306a92901b4b0753b68yt "port in FAILED/SHUTDOWN/PWROFF state: "
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI_PORT_TYPE_NODEV.
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort returning SATA_FAILURE while "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: ahci port %d abort all packets",
82263d52a84b4a969aa53f8ededddff841646ad9yt * Aborting one specific packet, first search the
2fcbc377041d659446ded306a92901b4b0753b68yt * ahciport_slot_pkts[] list for matching spkt.
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot < ahci_ctlp->ahcictl_num_cmd_slots; tmp_slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* request packet is not on the pending list */
2fcbc377041d659446ded306a92901b4b0753b68yt "Cannot find the aborting pkt 0x%p on the "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: ahci port %d abort satapkt 0x%p",
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt * To abort the packet(s), first we are trying to clear PxCMD.ST
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to stop the port, and if the port can be stopped
2fcbc377041d659446ded306a92901b4b0753b68yt * successfully with PxTFD.STS.BSY and PxTFD.STS.DRQ cleared to '0',
2fcbc377041d659446ded306a92901b4b0753b68yt * then we just send back the aborted packet(s) with ABORTED flag
2fcbc377041d659446ded306a92901b4b0753b68yt * and then restart the port by setting PxCMD.ST and PxCMD.FRE.
2fcbc377041d659446ded306a92901b4b0753b68yt * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then we
2fcbc377041d659446ded306a92901b4b0753b68yt * perform a COMRESET.
2fcbc377041d659446ded306a92901b4b0753b68yt * Compute which have finished and which need to be retried.
82263d52a84b4a969aa53f8ededddff841646ad9yt * The finished tags are ahciport_pending_tags/ahciport_pending_ncq_tags
82263d52a84b4a969aa53f8ededddff841646ad9yt * minus the slot_status. The aborted_tags has to be deducted by
82263d52a84b4a969aa53f8ededddff841646ad9yt * finished_tags since we can't possibly abort a tag which had finished
82263d52a84b4a969aa53f8ededddff841646ad9yt * already.
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0); /* reset tags */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device);
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do device reset and reject all the pending packets on a device
2fcbc377041d659446ded306a92901b4b0753b68yt * during the reset operation.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: ONLY called by ahci_tran_reset_dport
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * commands are being mopped, therefore there is nothing else to do
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_device_reject_pkts: port %d is in "
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp, addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt "Try to do a port reset after software "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_port_reset(ahci_ctlp, ahci_portp, addrp);
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_device_reject_pkts: port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set the reset in progress flag */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the framework that a reset has happened */
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Next try to mop the pending commands */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Used to do device reset and reject all the pending packets on a device
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * during the reset operation.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: ONLY called by ahci_tran_reset_dport
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_reset_pmdevice_reject_pkts(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t finished_tags = 0, reset_tags = 0, slot_status = 0;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reset_pmdevice_reject_pkts at port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reset_pmdevice_reject_pkts: port %d is in "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "mopping process, so return directly ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for outstanding commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Issue SOFTWARE reset command. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp, addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Try to do a port reset after software "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Set the reset in progress flag */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Indicate to the framework that a reset has happened */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_DPMPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d sending event up: SATA_EVNT_DEVICE_RESET",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Next try to mop the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_ncq_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "reset_tags = %x, finished_tags = %x, slot_status = %x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Because PxCI be only erased by unset PxCMD.ST bit, so even we
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * try to reset a single device behind a port multiplier will
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * terminate all the commands on that HBA port. We need mop these
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * commands as well.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* timeout tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do port reset and reject all the pending packets on a port during
2fcbc377041d659446ded306a92901b4b0753b68yt * the reset operation.
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reset_port_reject_pkts at port: %d", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If AHCI_PORT_FLAG_MOPPING flag is set, it means all the pending
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * commands are being mopped, therefore there is nothing else to do
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_port_reject_pkts: port %d is in "
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp, port, AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear mop flag */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_mop_in_progress == 0)
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do hba reset and reject all the pending packets on all ports
2fcbc377041d659446ded306a92901b4b0753b68yt * during the reset operation.
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: reset_tags = 0x%x pending_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: reset_tags = 0x%x pending_tags = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt * To prevent recursive enter to ahci_mop_commands, we need
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * check AHCI_PORT_FLAG_MOPPING flag.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_hba_reject_pkts: port %d is in "
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to reset a port(s) or device.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_reset_dport enter: cport %d", cport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If we want to issue a COMRESET on a pmport, we need to
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * reject the outstanding commands on that pmport. According
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * to AHCI spec, PxCI register could only be cleared by
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * clearing PxCMD.ST, which will halt the controller port - as
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * well as other pmports.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Therefore we directly reset the controller port for
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * simplicity. ahci_tran_probe_port() will handle reset stuff
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * like initializing the given pmport.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FALLTHRU */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Port reset */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_port_reject_pkts(ahci_ctlp, ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d reset device", instance, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FALLTHRU */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Device reset */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (sd->satadev_addr.qual == SATA_ADDR_DCPORT)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * software reset request must be sent to SATA_PMULT_HOSTPORT
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * if target is a port multiplier:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (sd->satadev_addr.qual == SATA_ADDR_DCPORT &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type == SATA_DTYPE_PMULT)
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
2fcbc377041d659446ded306a92901b4b0753b68yt * In case the targer driver would send the request
2fcbc377041d659446ded306a92901b4b0753b68yt * before sata framework can have the opportunity to
2fcbc377041d659446ded306a92901b4b0753b68yt * process those event reports.
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_reset_dport returning SATA_FAILURE "
2fcbc377041d659446ded306a92901b4b0753b68yt "while port in FAILED/SHUTDOWN/PWROFF state: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr) ==
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI_PORT_TYPE_NODEV.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sd->satadev_state = AHCIPORT_GET_STATE(ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_reset_dport returning SATA_FAILURE "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_device_reject_pkts(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_pmdevice_reject_pkts(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Reset the whole controller */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to activate a port as part of hotplug.
2fcbc377041d659446ded306a92901b4b0753b68yt * (cfgadm -c connect satax/y)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Support port multiplier.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_hotplug_port_activate(dev_info_t *dip, sata_device_t *satadev)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = satadev->satadev_addr.pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_hotplug_port_activate enter: cport %d", cport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, satadev, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PORT(&addr) || AHCI_ADDR_IS_PMPORT(&addr));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d is activated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Enable the interrupts on the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Reset the port so that the PHY communication would be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * re-established. But this reset is an internal operation
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * and the sata module doesn't need to know about it.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Moreover, the port with a device attached will be started
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_restart_port_wait_till_ready(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Need to check the link status and device status of the port
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * and consider raising power if the port was in D3 state
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state |= SATA_PSTATE_PWRON;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state &= ~SATA_PSTATE_PWROFF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state &= ~SATA_PSTATE_SHUTDOWN;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d:%d is activated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* AHCI_ADDR_PMPORT */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_PMSTATE(ahci_portp, &addr) |= SATA_PSTATE_PWRON;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt satadev->satadev_state = ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to deactivate a port as part of hotplug.
2fcbc377041d659446ded306a92901b4b0753b68yt * (cfgadm -c disconnect satax/y)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Support port multiplier.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_hotplug_port_deactivate(dev_info_t *dip, sata_device_t *satadev)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = satadev->satadev_addr.pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_hotplug_port_deactivate enter: cport %d", cport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, satadev, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PORT(&addr) || AHCI_ADDR_IS_PMPORT(&addr));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d is deactivated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Disable the interrupts on the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* First to abort all the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Then stop the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Next put the PHY offline */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_DISABLE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle, (uint32_t *)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_PORT_PxSCTL(ahci_ctlp, port), port_scontrol);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d:%d is deactivated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Re-enable the interrupts for the other pmports */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Update port state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, &addr, SATA_PSTATE_SHUTDOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satadev->satadev_state = SATA_PSTATE_SHUTDOWN;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * To be used to mark all the outstanding pkts with SATA_PKT_ABORTED
2fcbc377041d659446ded306a92901b4b0753b68yt * when a device is unplugged or a port is deactivated.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reject_all_abort_pkts at port: %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Read/write port multiplier command takes highest priority */
82263d52a84b4a969aa53f8ededddff841646ad9yt * When AHCI_PORT_FLAG_MOPPING is set, we need to check whether a
82263d52a84b4a969aa53f8ededddff841646ad9yt * REQUEST SENSE command or READ LOG EXT command is delivered to HBA
82263d52a84b4a969aa53f8ededddff841646ad9yt * to get the error data, if yes when the device is removed, the
82263d52a84b4a969aa53f8ededddff841646ad9yt * command needs to be aborted too.
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_reject_all_abort_pkts return directly "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port %d no needs to reject any outstanding "
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt abort_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* No need to do mop when there is no outstanding commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0, /* failed tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0, /* timeout tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0); /* reset tags */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Initialize fma capabilities and register with IO fault services.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Need to change iblock to priority for new MSI intr
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_ctlp->ahcictl_fm_cap = ddi_getprop(DDI_DEV_T_ANY,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Only register with IO Fault Services if we have some capability */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Adjust access and dma attributes for FMA */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang buffer_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang rcvd_fis_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmd_list_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmd_table_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Register capabilities with IO Fault Services.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * ahcictl_fm_cap will be updated to indicate
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * capabilities actually supported (not requested.)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_ctlp->ahcictl_fm_cap == DDI_FM_NOT_CAPABLE) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Initialize pci ereport capabilities if ereport
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * capable (should always be.)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (DDI_FM_EREPORT_CAP(ahci_ctlp->ahcictl_fm_cap) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FM_ERRCB_CAP(ahci_ctlp->ahcictl_fm_cap)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Register error callback if error callback capable.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (DDI_FM_ERRCB_CAP(ahci_ctlp->ahcictl_fm_cap)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_handler_register(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Releases fma capabilities and un-registers with IO fault services.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Only unregister FMA capabilities if registered */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Un-register error callback if error callback capable.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (DDI_FM_ERRCB_CAP(ahci_ctlp->ahcictl_fm_cap)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_handler_unregister(ahci_ctlp->ahcictl_dip);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Release any resources allocated by pci_ereport_setup()
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (DDI_FM_EREPORT_CAP(ahci_ctlp->ahcictl_fm_cap) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FM_ERRCB_CAP(ahci_ctlp->ahcictl_fm_cap)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Unregister from IO Fault Services */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Adjust access and dma attributes for FMA */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka buffer_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang rcvd_fis_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmd_list_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmd_table_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * as the driver can always deal with an error in any dma or
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * access handle, we can just return the fme_status value.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Generate an ereport
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_ereport(ahci_ctl_t *ahci_ctlp, char *detail)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (DDI_FM_EREPORT_CAP(ahci_ctlp->ahcictl_fm_cap)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_ereport_post(ahci_ctlp->ahcictl_dip, buf, ena,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * Check if all handles are correctly allocated.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_port_handle(ahci_ctlp, port) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the access handles for the controller. Note that
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * ahcictl_pci_conf_handle is only used in attach process.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the DMA handles and the access handles of a controller port.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_port_handle(ahci_ctl_t *ahci_ctlp, int port)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_port_t *ahci_portp = ahci_ctlp->ahcictl_ports[port];
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_rcvd_fis_dma_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_list_dma_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_rcvd_fis_acc_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_list_acc_handle) != DDI_FM_OK)) {
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the DMA handles and the access handles of a cmd table slot.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_slot_handle(ahci_port_t *ahci_portp, int slot)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_acc_handle[slot]) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_dma_handle[slot]) != DDI_FM_OK)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Allocate the ports structure, only called by ahci_attach
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Allocate structures only for the implemented ports */
f68cbde19e3ef99e6398b35f324dd995baa82758yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_alloc_port_state(ahci_ctlp, port) != AHCI_SUCCESS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Reverse of ahci_alloc_ports_state(), only called by ahci_detach
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* if this port is implemented by the HBA */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China * Drain the taskq.
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing Chinaahci_drain_ports_taskq(ahci_ctl_t *ahci_ctlp)
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_portp = ahci_ctlp->ahcictl_ports[port];
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China mutex_enter(&ahci_portp->ahciport_mutex);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ddi_taskq_wait(ahci_portp->ahciport_event_taskq);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China mutex_exit(&ahci_portp->ahciport_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt * Initialize the controller and all ports. And then try to start the ports
13bcbb7a73761015c9ef46cac33040380196e57fyt * if there are devices attached.
2fcbc377041d659446ded306a92901b4b0753b68yt * This routine can be called from three seperate cases: DDI_ATTACH,
2fcbc377041d659446ded306a92901b4b0753b68yt * PM_LEVEL_D0 and DDI_RESUME. The DDI_ATTACH case is different from
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * other two cases; device signature probing are attempted only during
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * DDI_ATTACH case.
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka /* Disable the whole controller interrupts */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Initialize the implemented ports and structures */
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt * Ensure that the controller is not in the running state
2fcbc377041d659446ded306a92901b4b0753b68yt * by checking every implemented port's PxCMD register
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_initialize_port(ahci_ctlp, ahci_portp, &addr)
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_initialize_controller: failed to "
2fcbc377041d659446ded306a92901b4b0753b68yt * Set the port state to SATA_PSTATE_FAILED if
2fcbc377041d659446ded306a92901b4b0753b68yt * failed to initialize it.
2fcbc377041d659446ded306a92901b4b0753b68yt /* Enable the whole controller interrupts */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Reverse of ahci_initialize_controller()
13bcbb7a73761015c9ef46cac33040380196e57fyt * We only need to stop the ports and disable the interrupt.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68yt /* disable all the interrupts. */
13bcbb7a73761015c9ef46cac33040380196e57fyt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Stop the port by clearing PxCMD.ST */
13bcbb7a73761015c9ef46cac33040380196e57fyt * Here we must disable the port interrupt because
13bcbb7a73761015c9ef46cac33040380196e57fyt * ahci_disable_all_intrs only clear GHC.IE, and IS
13bcbb7a73761015c9ef46cac33040380196e57fyt * register will be still set if PxIE is enabled.
13bcbb7a73761015c9ef46cac33040380196e57fyt * When ahci shares one IRQ with other drivers, the
13bcbb7a73761015c9ef46cac33040380196e57fyt * intr handler may claim the intr mistakenly.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_alloc_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. Setting HBA port registers which are necessary for a port multiplier.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * (Set PxCMD.PMA while PxCMD.ST is '0')
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Allocate ahci_pmult_info structure.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Must stop port before the function is called.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_alloc_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* The port must have been stopped before. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(!(port_cmd_status & AHCI_CMD_STATUS_ST));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_cmd_status & AHCI_CMD_STATUS_PMA)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* set PMA bit */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_alloc_pmult: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Allocate port multiplier information structure */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_pmult_info == NULL) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info = (ahci_pmult_info_t *)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang kmem_zalloc(sizeof (ahci_pmult_info_t), KM_SLEEP);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_dealloc_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. Clearing related registers when a port multiplier is detached.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * (Clear PxCMD.PMA while PxCMD.ST is '0')
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Deallocate ahci_pmult_info structure.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Must stop port before the function is called.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_dealloc_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear PMA bit */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_dealloc_pmult: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Release port multiplier information structure */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_pmult_info != NULL) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Staggered Spin-up.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_staggered_spin_up(ahci_ctl_t *ahci_ctlp, uint8_t port)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Check for staggered spin-up support */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* If PxCMD.SUD == 1, no staggered spin-up is needed */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "Spin-up at port %d", port);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Set PxCMD.SUD */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * The routine is to initialize a port. First put the port in NotRunning
2fcbc377041d659446ded306a92901b4b0753b68yt * state, then enable port interrupt and clear Serror register. And under
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI_ATTACH case, find device signature and then try to start the port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. ahci_initialize_controller
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. ahci_intr_phyrdy_change (hotplug)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang uint32_t port_sstatus, port_task_file, port_cmd_status;
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers boolean_t resuming = B_TRUE; /* processing DDI_RESUME */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* AHCI_ADDR_PORT: We've no idea of the attached device here. */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * At the time being, only probe ports/devices and get the types of
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * attached devices during DDI_ATTACH. In fact, the device can be
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * changed during power state changes, but at the time being, we
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * don't support the situation.
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /* check for DDI_RESUME case */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * During the resume, we need to set the PxCLB, PxCLBU, PxFB
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * and PxFBU registers in case these registers were cleared
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * during the suspend.
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers "ahci_initialize_port: port %d "
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers "set PxCLB, PxCLBU, PxFB and PxFBU "
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_setup_port_base_addresses(ahci_ctlp, ahci_portp) !=
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt * Check whether the port is in NotRunning state, if not,
2fcbc377041d659446ded306a92901b4b0753b68yt * put the port in NotRunning state
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Make sure the drive is spun-up */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Disable interrupt */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Device is unknown at first */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
e2d9bfa60df7cf2c53826b45daa99c8a7324780dying tian - Beijing China /* Disable the interface power management */
e2d9bfa60df7cf2c53826b45daa99c8a7324780dying tian - Beijing China ahci_disable_interface_pm(ahci_ctlp, port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Check physcial link status */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (SSTATUS_GET_IPM(port_sstatus) == SSTATUS_IPM_NODEV_NOPHYCOM ||
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_NOPHYCOM ||
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Check interface status */
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China port_task_file & AHCI_TFD_STS_DRQ ||
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China /* Check whether port reset must be executed */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers ahci_ctlp->ahcictl_cap & AHCI_CAP_INIT_PORT_RESET ||
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /* Always reset port on RESUME */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Something went wrong, we need do some reset things */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_port_reset(ahci_ctlp, ahci_portp, addrp);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Does port reset succeed on HBA port? */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_initialize_port:"
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Is port failed? */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_initialize_port: port %d state 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_STATE_READY);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "port %d is ready now.", port);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * Try to get the device signature if the port is not empty.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (!resuming && AHCIPORT_DEV_TYPE(ahci_portp, addrp) !=
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers ahci_find_dev_signature(ahci_ctlp, ahci_portp, addrp);
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Return directly if no device connected */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (AHCIPORT_DEV_TYPE(ahci_portp, addrp) == SATA_DTYPE_NONE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* If this is a port multiplier, we need do some initialization */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (AHCIPORT_DEV_TYPE(ahci_portp, addrp) == SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Try to start the port */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Enable port interrupts */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * Handle hardware defect, and check the capabilities. For example,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * power management capabilty and MSI capability.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt * Modify dma_attr_align of ahcictl_buffer_dma_attr. For VT8251, those
13bcbb7a73761015c9ef46cac33040380196e57fyt * controllers with 0x00 revision id work on 4-byte aligned buffer,
13bcbb7a73761015c9ef46cac33040380196e57fyt * which is a bug and was fixed after 0x00 revision id controllers.
13bcbb7a73761015c9ef46cac33040380196e57fyt * Moreover, VT8251 cannot use multiple command slots in the command
13bcbb7a73761015c9ef46cac33040380196e57fyt * list for non-queued commands because the previous register content
13bcbb7a73761015c9ef46cac33040380196e57fyt * of PxCI can be re-written in the register write, so a flag will be
13bcbb7a73761015c9ef46cac33040380196e57fyt * set to record this defect - AHCI_CAP_NO_MCMDLIST_NONQUEUE.
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China * For VT8251, software reset also has the same defect as the below
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China * AMD/ATI chipset. That is, software reset will get failed if 0xf
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China * is filled in pmport field. Therefore, another software reset need
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China * to be done with 0 filled in pmport field.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China if (ahci_ctlp->ahcictl_venid == VIA_VENID) {
13bcbb7a73761015c9ef46cac33040380196e57fyt revision = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_NO_MCMDLIST_NONQUEUE;
13bcbb7a73761015c9ef46cac33040380196e57fyt "VT8251 cannot use multiple command lists for "
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_SRST_NO_HOSTPORT;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * AMD/ATI SB600 (0x1002,0x4380) AHCI chipset doesn't support 64-bit
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * DMA addressing for communication memory descriptors though S64A bit
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * of CAP register declares it supports. Even though 64-bit DMA for
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * data buffer works on ASUS M2A-VM with newer BIOS, three other
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * motherboards are known not, so both AHCI_CAP_BUF_32BIT_DMA and
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China * AHCI_CAP_COMMU_32BIT_DMA are set for this controller.
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * Due to certain hardware issue, the chipset must do port reset during
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * initialization, otherwise, when retrieving device signature,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * software reset will get time out. So AHCI_CAP_INIT_PORT_RESET flag
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * For this chipset software reset will get failure if the pmport of
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * Register FIS was set with SATA_PMULT_HOSTPORT (0xf) and no port
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * multiplier is connected to the port. In order to fix the issue,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * AHCI_CAP_SRST_NO_HOSTPORT flag need to be set, and once software
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * reset got failure, the driver will try to do another software reset
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * with pmport 0.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China if (ahci_ctlp->ahcictl_venid == 0x1002 &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_devid == 0x4380) {
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_BUF_32BIT_DMA;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_INIT_PORT_RESET;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_SRST_NO_HOSTPORT;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China "ATI SB600 cannot do 64-bit DMA for both data buffer and "
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China "communication memory descriptors though CAP indicates "
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China "support, so force it to use 32-bit DMA", NULL);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB600 need to do a port reset during initialization",
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB600 will get software reset failure if pmport "
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "is set 0xf and no port multiplier is attached", NULL);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * AMD/ATI SB700/710/750/800 and SP5100 AHCI chipset share the same
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * vendor ID and device ID (0x1002,0x4391).
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * SB700/750 AHCI chipset on some boards doesn't support 64-bit
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * DMA addressing for communication memory descriptors though S64A bit
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * of CAP register declares the support. However, it does support
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * 64-bit DMA for data buffer. So only AHCI_CAP_COMMU_32BIT_DMA is
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * set for this controller.
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * SB710 has the same initialization issue as SB600, so it also need
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * a port reset. That is AHCI_CAP_INIT_PORT_RESET need to set for it.
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * SB700 also has the same issue about software reset, and thus
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * AHCI_CAP_SRST_NO_HOSTPORT flag also is needed.
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China if (ahci_ctlp->ahcictl_venid == 0x1002 &&
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_devid == 0x4391) {
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_COMMU_32BIT_DMA;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_INIT_PORT_RESET;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_SRST_NO_HOSTPORT;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "ATI SB700/750 cannot do 64-bit DMA for communication "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "memory descriptors though CAP indicates support, "
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB710 need to do a port reset during initialization",
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB700 will get software reset failure if pmport "
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "is set 0xf and no port multiplier is attached", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt * Check if capabilities list is supported and if so,
13bcbb7a73761015c9ef46cac33040380196e57fyt * get initial capabilities pointer and clear bits 0,1.
13bcbb7a73761015c9ef46cac33040380196e57fyt * Walk capabilities if supported.
13bcbb7a73761015c9ef46cac33040380196e57fyt for (cap_count = 0; caps_ptr != PCI_CAP_NEXT_PTR_NULL; ) {
13bcbb7a73761015c9ef46cac33040380196e57fyt * Check that we haven't exceeded the maximum number of
13bcbb7a73761015c9ef46cac33040380196e57fyt * capabilities and that the pointer is in a valid range.
13bcbb7a73761015c9ef46cac33040380196e57fyt "capabilities pointer 0x%x out of range",
13bcbb7a73761015c9ef46cac33040380196e57fyt * Get next capability and check that it is valid.
13bcbb7a73761015c9ef46cac33040380196e57fyt * For now, we only support power management.
13bcbb7a73761015c9ef46cac33040380196e57fyt cap = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt switch (cap) {
13bcbb7a73761015c9ef46cac33040380196e57fyt /* power management supported */
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Save PMCSR offset */
13bcbb7a73761015c9ef46cac33040380196e57fyt "Power Management capability found PCI_PMCAP "
13bcbb7a73761015c9ef46cac33040380196e57fyt "PCI Power Management Interface "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_pci_conf_handle,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "Message Signaled Interrupt capability found "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "MSICAP_MC.MMC = 0x%x", (msimc & 0xe) >> 1);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Get next capabilities pointer and clear bits 0,1.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Read/Write a register at port multiplier by SATA READ PORTMULT / SATA WRITE
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PORTMULT command. SYNC & POLLING mode is used.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_rdwr_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PMPORT(addrp) || AHCI_ADDR_IS_PMULT(addrp));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check the existence of the port multiplier */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Request a READ/WRITE PORTMULT sata packet. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device.satadev_addr.qual = SATA_ADDR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Make sure no command is outstanding here. All R/W PMULT requests
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. ahci_attach()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The port should be empty.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. ahci_tran_probe_port()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Any request from SATA framework (via ahci_tran_start) should be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * rejected if R/W PMULT command is outstanding.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If we are doing mopping, do not check those flags because no
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * command will be actually outstanding.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If the port has been occupied by any other commands, the probe
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * function will return a SATA_RETRY. SATA framework will retry
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "R/W PMULT failed: R/W PMULT in progress at port %d.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) && (
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "R/W PMULT failed: port %d is occupied (flags 0x%x).",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The port multiplier is gone. This may happen when
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. Cutting off the power of an enclosure. The device lose the power
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * before port multiplier.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Disconnecting the port multiplier during hot-plugging a sub-drive.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The issued command should be aborted and the following command
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * should not be continued.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_portp->ahciport_port_state & SATA_STATE_READY)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "READ/WRITE PMULT failed: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RDWR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt = sata_get_rdwr_pmult_pkt(ahci_ctlp->ahcictl_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * READ/WRITE PORTMULT command is intended to sent to the control port
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * of the port multiplier.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&pmult_addr, addrp->aa_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* No interrupt here. Store the interrupt enable mask. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang intr_mask = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), 0);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = ahci_do_sync_start(ahci_ctlp, ahci_portp, &pmult_addr, spkt);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Failed or not completed. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_rdwr_pmult: cannot [%s] %s[%d] at port %s",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang type == SATA_RDWR_PMULT_PKT_TYPE_READ?"Read":"Write",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_IS_PMULT(addrp)?"gscr":"pscr", regn, portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Restore the interrupt mask */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), intr_mask);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RDWR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_read_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return ahci_rdwr_pmult(ahci_ctlp, addrp, regn, pregv,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_write_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return ahci_rdwr_pmult(ahci_ctlp, addrp, regn, ®v,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_read_pmult(ahci_ctlp, addrp, r, pv) != AHCI_SUCCESS) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_write_pmult(ahci_ctlp, addrp, r, v) != AHCI_SUCCESS) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Update sata registers on port multiplier, including GSCR/PSCR registers.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_update_pmult_gscr()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_update_pmult_pscr()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_update_pmult_gscr(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka &ahci_ctlp->ahcictl_ports[addrp->aa_port]->ahciport_mutex));
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR0, &sg->gscr0, err);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR1, &sg->gscr1, err);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR2, &sg->gscr2, err);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR64, &sg->gscr64, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_update_pmult_pscr(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka &ahci_ctlp->ahcictl_ports[addrp->aa_port]->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SSTS, &sd->satadev_scr.sstatus, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SERR, &sd->satadev_scr.serror, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SCTL, &sd->satadev_scr.scontrol, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SACT, &sd->satadev_scr.sactive, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_initialize_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Initialize a port multiplier, including
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. Enable FEATURES register at port multiplier. (SATA Chp.16)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Redefine MASK register. (SATA Chap 16.?)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "[Initialize] Port-multiplier at port %d.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Enable features of port multiplier. Currently only
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Asynchronous Notification is enabled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check gscr64 for supported features. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR64, &gscr64, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: Port Multiplier supports "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Write to gscr96 to enabled features */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Now we need to update gscr33 register to enable hot-plug interrupt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * for sub devices behind port multiplier.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(addrp, SATA_PMULT_GSCR33, (0x1ffff), err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: gscr33 mask set to %x.", port, (0x1ffff));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Fetch the number of device ports of the port multiplier
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (ahci_update_pmult_gscr(ahci_ctlp, addrp, &sg) != AHCI_SUCCESS)
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang /* Register the port multiplier to SATA Framework. */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_register_pmult(ahci_ctlp->ahcictl_dip, sd, &sg);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info->ahcipmi_num_dev_ports =
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sd->satadev_add_info & SATA_PMULT_PORTNUM_MASK;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: pmult sub-port number updated to %x.", port,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info->ahcipmi_num_dev_ports);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Till now port-mult is successfully initialized */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state |= SATA_DSTATE_PMULT_INIT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Initialize a port multiplier port. According to spec, firstly we need
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * issue a COMRESET, then a software reset to get its signature.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: This function should only be called in ahci_probe_pmport()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_pmport(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t finished_tags = 0, reset_tags = 0, slot_status = 0;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check HBA port state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport:"
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d Port Multiplier is failed.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_HOTPLUG;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for outstanding commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear status */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_STATE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Firstly assume an unknown device */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* port reset is necessary for port multiplier port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_pmport_reset(ahci_ctlp, ahci_portp, addrp) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport:"
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port reset failed at port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is port failed? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: port %d:%d failed. "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is there any device attached? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Do not waste time on an empty port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: No device is found "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_STATE_READY);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Till now we can assure a device attached to that HBA port and work
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * correctly. Now try to get the device signature. This is an optional
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * step. If failed, unknown device is assumed, then SATA module will
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * continue to use IDENTIFY DEVICE to get the information of the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_find_dev_signature(ahci_ctlp, ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Next try to mop the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_ncq_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* timeout tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear PxSNTF register if supported. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_HOTPLUG;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_probe_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * This function will be called to probe a port multiplier, which will
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * handle hotplug events on port multiplier ports.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Only called from ahci_tran_probe_port()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_probe_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int dev_exists_now = 0, dev_existed_previously = 0;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* The bits in GSCR32 refers to the pmport that has a hot-plug event. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR32, &gscr32, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_hotplug_tags = gscr32 & AHCI_PMPORT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* no pending hot plug events. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hot-plug event at port %d:%d", port, npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMPORT(&pmport_addr, port, (uint8_t)npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check previous device at that port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &pmport_addr)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* PxSStatus tells the presence of device. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Clear PxSERR is critical. The transition from 0 to 1 will
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * emit a FIS which generates an asynchronous notification
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * event at controller. If we fail to clear the PxSERR, the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Async Notif events will no longer be activated on this
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(&pmport_addr, SATA_PMULT_REG_SERR,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = (uint8_t)npmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "[Existence] %d -> %d", dev_existed_previously,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Link (may) not change: Exist -> Exist * */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d:%d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "device link lost/established",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Link change: None -> Exist */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d:%d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear port state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else { /* No device exists now */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Link change: Exist -> None */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d:%d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* An existing device is lost. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, &pmport_addr,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Probe and initialize a port multiplier port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * A port multiplier port could only be initilaizer here.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_probe_pmport(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Check the parent - port multiplier first.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Parent port multiplier might have been removed. This event will be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ignored and failure.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "parent device removed, ignore event.", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* The port is ready? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_restart_port_wait_till_ready(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If port-mult is restarted due to some reason, we need
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * re-initialized the PMult.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize registers on a port multiplier */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&addr_pmult, addrp->aa_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_initialize_pmult(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Then we check the port-mult port
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is this pmport initialized? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* ahci_initialize_pmport() will set READY state */
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI device reset ...; a single device on one of the ports is reset,
2fcbc377041d659446ded306a92901b4b0753b68yt * but the HBA and physical communication remain intact. This is the
2fcbc377041d659446ded306a92901b4b0753b68yt * least intrusive.
2fcbc377041d659446ded306a92901b4b0753b68yt * When issuing a software reset sequence, there should not be other
2fcbc377041d659446ded306a92901b4b0753b68yt * commands in the command list, so we will first clear and then re-set
2fcbc377041d659446ded306a92901b4b0753b68yt * PxCMD.ST to clear PxCI. And before issuing the software reset,
2fcbc377041d659446ded306a92901b4b0753b68yt * the port must be idle and PxTFD.STS.BSY and PxTFD.STS.DRQ must be
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China * cleared unless command list override (PxCMD.CLO) is supported.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_status, port_cmd_issue, port_task_file;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d device software resetting (FIS)", port, pmport);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* First clear PxCMD.ST (AHCI v1.2 10.4.1) */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_software_reset: cannot stop HBA port %d.", port);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Check PxTFD.STS.BSY and PxTFD.STS.DRQ */
2fcbc377041d659446ded306a92901b4b0753b68yt port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_SCLO)) {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "PxTFD.STS.BSY/DRQ is set (PxTFD=0x%x), "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "cannot issue a software reset.", port_task_file);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * If HBA Support CLO, as Command List Override (CAP.SCLO is
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * set), PxCMD.CLO bit should be set before set PxCMD.ST, in
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * order to clear PxTFD.STS.BSY and PxTFD.STS.DRQ.
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Waiting till PxCMD.SCLO bit is cleared */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Wait for 10 millisec */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* We are effectively timing out after 1 sec. */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang } while (port_cmd_status & AHCI_CMD_STATUS_CLO);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Re-check */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "SCLO cannot clear PxTFD.STS.BSY/DRQ (PxTFD=0x%x)",
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Then start port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_start_port(ahci_ctlp, ahci_portp, port)
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_software_reset: cannot start AHCI port %d.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * When ahci_port.ahciport_mop_in_progress is set, A non-zero
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * ahci_port.ahciport_pending_ncq_tags may fail
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * ahci_claim_free_slot(). Actually according to spec, by clearing
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * PxCMD.ST there is no command outstanding while executing software
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * reseting. Hence we directly use slot 0 instead of
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * ahci_claim_free_slot().
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* Now send the first H2D Register FIS with SRST set to 1 */
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop till the first command is finished */
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* We are effectively timing out after 1 sec. */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "the first SRST FIS is timed out, "
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_software_reset: 1st loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_issue = 0x%x, slot = 0x%x",
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang /* According to ATA spec, we need wait at least 5 microsecs here. */
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* Now send the second H2D Register FIS with SRST cleard to zero */
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop till the second command is finished */
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* We are effectively timing out after 1 sec. */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "the second SRST FIS is timed out, "
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_software_reset: 2nd loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_issue = 0x%x, slot = 0x%x",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_port_handle(ahci_ctlp, port) != DDI_SUCCESS)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_software_reset: %s at port %d:%d",
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI port reset ...; the physical communication between the HBA and device
2fcbc377041d659446ded306a92901b4b0753b68yt * on a port are disabled. This is more intrusive.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When an HBA or port reset occurs, Phy communication is going to
2fcbc377041d659446ded306a92901b4b0753b68yt * be re-established with the device through a COMRESET followed by the
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * normal out-of-band communication sequence defined in Serial ATA. At
2fcbc377041d659446ded306a92901b4b0753b68yt * the end of reset, the device, if working properly, will send a D2H
2fcbc377041d659446ded306a92901b4b0753b68yt * Register FIS, which contains the device signature. When the HBA receives
2fcbc377041d659446ded306a92901b4b0753b68yt * this FIS, it updates PxTFD.STS and PxTFD.ERR register fields, and updates
2fcbc377041d659446ded306a92901b4b0753b68yt * the PxSIG register with the signature.
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * NOTE: It is expected both PxCMD.ST and PxCMD.CR are cleared before the
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * function is called. If not, it is assumed the interface is in hung
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * condition.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Target is a port multiplier port? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (ahci_pmport_reset(ahci_ctlp, ahci_portp, addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Otherwise it must be an HBA port. */
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * According to the spec, SUD bit should be set here,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * but JMicron JMB363 doesn't follow it, so print
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * a debug message.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "ahci_port_reset: port %d SUD bit not set", port);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_COMRESET);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Enable PxCMD.FRE to read device */
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka * The port enters P:StartComm state, and the HBA tells the link layer
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka * to start communication, which involves sending COMRESET to the
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka * device. And the HBA resets PxTFD.STS to 7Fh.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Give time for COMRESET to percolate, according to the AHCI
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * spec, software shall wait at least 1 millisecond before
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * clearing PxSCTL.DET
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Fetch the SCONTROL again and rewrite the DET part with 0 */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_NOACTION);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When a COMINIT is received from the device, then the port enters
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * P:ComInit state. And HBA sets PxTFD.STS to FFh or 80h. HBA sets
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxSSTS.DET to 1h to indicate a device is detected but communication
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * is not yet established. HBA sets PxSERR.DIAG.X to '1' to indicate
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a COMINIT has been received.
2fcbc377041d659446ded306a92901b4b0753b68yt * The DET field is valid only if IPM field indicates
2fcbc377041d659446ded306a92901b4b0753b68yt * that the interface is in active state.
2fcbc377041d659446ded306a92901b4b0753b68yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) {
2fcbc377041d659446ded306a92901b4b0753b68yt * If the interface is not active, the DET field
2fcbc377041d659446ded306a92901b4b0753b68yt * is considered not accurate. So we want to
2fcbc377041d659446ded306a92901b4b0753b68yt * continue looping.
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM)
2fcbc377041d659446ded306a92901b4b0753b68yt * We are effectively timing out after 0.1 sec.
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_port_reset: 1st loop count: %d, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port_sstatus = 0x%x port %d",
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM) {
2fcbc377041d659446ded306a92901b4b0753b68yt * Either the port is not active or there
2fcbc377041d659446ded306a92901b4b0753b68yt * is no device present.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_NONE);
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka /* Clear port serror register for the port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * Devices should return a FIS contains its signature to HBA after
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka * COMINIT signal. Check whether a D2H Register FIS is received by
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka * polling PxTFD.STS.
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if ((port_task_file & (AHCI_TFD_STS_BSY | AHCI_TFD_STS_DRQ |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * We are effectively timing out after 11 sec.
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang cmn_err(CE_WARN, "!ahci%d: ahci_port_reset port %d "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "the device hardware has been initialized and "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "the power-up diagnostics failed",
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_port_reset: "
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka "port %d: some or all of BSY, DRQ and ERR in "
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka "PxTFD.STS are not clear. We need another "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Clear port serror register for the port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Try another software reset. */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_port_reset: 2nd loop count: %d, "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "port_task_file = 0x%x port %d",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear port serror register for the port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Set port as ready */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, port_state|SATA_STATE_READY);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_port_reset: succeed at port %d.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * COMRESET on a port multiplier port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Only called in ahci_port_reset()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_pmport_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_scontrol, port_sstatus, port_serror;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d: pmport resetting", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize pmport state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SCTL, &port_scontrol, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_COMRESET);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(addrp, SATA_PMULT_REG_SCTL, port_scontrol, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* PxCMD.FRE should be set before. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(port_cmd_status & AHCI_CMD_STATUS_FRE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Give time for COMRESET to percolate, according to the AHCI
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * spec, software shall wait at least 1 millisecond before
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * clearing PxSCTL.DET
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Fetch the SCONTROL again and rewrite the DET part with 0
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * This will generate an Asychronous Notification events.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SCTL, &port_scontrol, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SCONTROL_SET_DET(port_scontrol, SCONTROL_DET_NOACTION);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(addrp, SATA_PMULT_REG_SCTL, port_scontrol, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The port enters P:StartComm state, and HBA tells link layer to
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * start communication, which involves sending COMRESET to device.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * And the HBA resets PxTFD.STS to 7Fh.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * When a COMINIT is received from the device, then the port enters
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * P:ComInit state. And HBA sets PxTFD.STS to FFh or 80h. HBA sets
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PxSSTS.DET to 1h to indicate a device is detected but communication
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * is not yet established. HBA sets PxSERR.DIAG.X to '1' to indicate
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * a COMINIT has been received.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The DET field is valid only if IPM field indicates
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * that the interface is in active state.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SSTS, &port_sstatus, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If the interface is not active, the DET field
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * is considered not accurate. So we want to
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * continue looping.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SSTATUS_SET_DET(port_sstatus, SSTATUS_DET_NODEV);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (loop_count++ > AHCI_POLLRATE_PORT_SSTATUS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * We are effectively timing out after 0.1 sec.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: 1st loop count: %d, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port_sstatus = 0x%x port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if ((SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Either the port is not active or there
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * is no device present.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "no device attached to port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_NONE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Now we can make sure there is a device connected to the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* COMINIT signal is supposed to be received (PxSERR.DIAG.X = '1') */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SERR, &port_serror, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_WARN, "!ahci%d: ahci_pmport_reset: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "COMINIT signal from the device not received port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_PSTATE_FAILED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * After clear PxSERR register, we will receive a D2H FIS.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Normally this FIS will cause a IPMS error according to AHCI spec
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * v1.2 because there is no command outstanding for it. So we need
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * to ignore this error.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_IGNORE_IPMS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(addrp, SATA_PMULT_REG_SERR, AHCI_SERROR_CLEAR_ALL, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Now we need to check the D2H FIS by checking IPMS error. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (loop_count++ > AHCI_POLLRATE_PORT_TFD_ERROR) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * No D2H FIS received. This is possible according
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * to SATA 2.6 spec.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_WARN, "ahci_port_reset: port %d:%d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "PxIS.IPMS is not set, we need another "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (!(port_intr_status & AHCI_INTR_STATUS_IPMS));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: 2st loop count: %d, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port_sstatus = 0x%x port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear IPMS */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_IGNORE_IPMS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* This pmport is now ready for ahci_tran_start() */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, port_state|SATA_STATE_READY);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: succeed at port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* IPMS flags might be set before. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_IGNORE_IPMS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: failed at port %d:%d", port, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI HBA reset ...; the entire HBA is reset, and all ports are disabled.
2fcbc377041d659446ded306a92901b4b0753b68yt * This is the most intrusive.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When an HBA reset occurs, Phy communication will be re-established with
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the device through a COMRESET followed by the normal out-of-band
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * communication sequence defined in Serial ATA. At the end of reset, the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * device, if working properly, will send a D2H Register FIS, which contains
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the device signature. When the HBA receives this FIS, it updates PxTFD.STS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * and PxTFD.ERR register fields, and updates the PxSIG register with the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * signature.
2fcbc377041d659446ded306a92901b4b0753b68yt * Remember to set GHC.AE to 1 before calling ahci_hba_reset.
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting",
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Setting GHC.HR to 1, remember GHC.AE is already set to 1 before */
2fcbc377041d659446ded306a92901b4b0753b68yt * Wait until HBA Reset complete or timeout
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci hba reset is timing out, "
2fcbc377041d659446ded306a92901b4b0753b68yt /* We are effectively timing out after 1 sec. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_hba_reset: 1st loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt /* The hba is not reset for some reasons */
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba reset failed: HBA in a hung or locked state", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * HBA reset will clear (AHCI Spec v1.2 10.4.3) GHC.IE / GHC.AE
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ghc_control |= (AHCI_HBA_GHC_AE | AHCI_HBA_GHC_IE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Only check implemented ports */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Make sure the drive is spun-up */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP, NULL) !=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Set the port state to SATA_PSTATE_FAILED if
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * failed to initialize it.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
2fcbc377041d659446ded306a92901b4b0753b68yt * This routine is only called from AHCI_ATTACH or phyrdy change
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * case. It first calls software reset, then stop the port and try to
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * read PxSIG register to find the type of device attached to the port.
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * The caller should make sure a valid device exists on specified port and
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * physical communication has been established so that the signature could
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * be retrieved by software reset.
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * NOTE: The port interrupts should be disabled before the function is called.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_find_dev_signature(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China ASSERT(AHCI_ADDR_IS_VALID(addrp));
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * If the HBA doesn't support port multiplier, then the driver
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * doesn't need to bother to check port multiplier device.
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * The second port of ICH7 on ASUS P5W DH deluxe motherboard is
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * connected to Silicon Image 4723, to which the two sata drives
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * attached can be set with RAID1, RAID0 or Spanning mode.
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * We found software reset will get failure if port multiplier address
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * 0xf is used by software reset, so just ignore the check since
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China * ICH7 doesn't support port multiplier device at all.
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China (ahci_ctlp->ahcictl_cap & AHCI_CAP_PMULT_CBSS)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature enter: port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: when the ahci address is a HBA port, we do not know
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * it is a device or a port multiplier that attached. we need
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * try a software reset at port multiplier address (0xf
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&dev_addr, addrp->aa_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature enter: port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Assume it is unknown. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Issue a software reset to get the signature */
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China rval = ahci_software_reset(ahci_ctlp, ahci_portp, &dev_addr);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * Try to do software reset again with pmport set with 0 if
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * the controller is set with AHCI_CAP_SRST_NO_HOSTPORT and
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China * the original pmport is set with SATA_PMULT_HOSTPORT (0xf)
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_SRST_NO_HOSTPORT) &&
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China (dev_addr.aa_pmport == SATA_PMULT_HOSTPORT)) {
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China rval = ahci_software_reset(ahci_ctlp, ahci_portp,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ahci_find_dev_signature: software reset failed "
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "at port %d:%d, cannot get signature.",
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIPORT_SET_STATE(ahci_portp, addrp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * ahci_software_reset has started the port, so we need manually stop
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * the port again.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_put_port_into_notrunning_state(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature: cannot stop port %d.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Now we can make sure that a valid signature is received. */
2fcbc377041d659446ded306a92901b4b0753b68yt signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature: signature = 0x%x at port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature: signature = 0x%x at port %d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* NOTE: Only support ATAPI device at controller port. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (signature == AHCI_SIGNATURE_ATAPI && !AHCI_ADDR_IS_PORT(addrp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_ATADISK);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_ATAPI);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Port Multiplier cannot recursively attached. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_PMULT);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
13bcbb7a73761015c9ef46cac33040380196e57fyt * According to the spec, to reliably detect hot plug removals, software
13bcbb7a73761015c9ef46cac33040380196e57fyt * must disable interface power management. Software should perform the
13bcbb7a73761015c9ef46cac33040380196e57fyt * following initialization on a port after a device is attached:
13bcbb7a73761015c9ef46cac33040380196e57fyt * Set PxSCTL.IPM to 3h to disable interface state transitions
13bcbb7a73761015c9ef46cac33040380196e57fyt * Set PxCMD.ALPE to '0' to disable aggressive power management
13bcbb7a73761015c9ef46cac33040380196e57fyt * Disable device initiated interface power management by SET FEATURE
13bcbb7a73761015c9ef46cac33040380196e57fyt * We can ignore the last item because by default the feature is disabled
13bcbb7a73761015c9ef46cac33040380196e57fytstatic void
13bcbb7a73761015c9ef46cac33040380196e57fytahci_disable_interface_pm(ahci_ctl_t *ahci_ctlp, uint8_t port)
13bcbb7a73761015c9ef46cac33040380196e57fyt port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt SCONTROL_SET_IPM(port_scontrol, SCONTROL_IPM_DISABLE_BOTH);
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port), port_scontrol);
13bcbb7a73761015c9ef46cac33040380196e57fyt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), port_cmd_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Start the port - set PxCMD.ST to 1, if PxCMD.FRE is not set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to 1, then set it firstly.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Each port contains two major DMA engines. One DMA engine walks through
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the command list, and is controlled by PxCMD.ST. The second DMA engine
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * copies received FISes into system memory, and is controlled by PxCMD.FRE.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Software shall not set PxCMD.ST to '1' until it verifies that PxCMD.CR
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * is '0' and has set PxCMD.FRE is '1'. And software shall not clear
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxCMD.FRE while PxCMD.ST or PxCMD.CR is set '1'.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Software shall not set PxCMD.ST to '1' unless a functional device is
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * present on the port(as determined by PxTFD.STS.BSY = '0',
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxTFD.STS.DRQ = '0', and PxSSTS.DET = 3h).
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_start_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "the state for port %d is 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* First to set PxCMD.FRE before setting PxCMD.ST. */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: "
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Setup PxCLB, PxCLBU, PxFB, and PxFBU for particular port. First, we need
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * to make sure PxCMD.ST, PxCMD.CR, PxCMD.FRE, and PxCMD.FR are all cleared.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Then set PxCLB, PxCLBU, PxFB, and PxFBU.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_setup_port_base_addresses(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 1: Make sure both PxCMD.ST and PxCMD.CR are cleared. */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (port_cmd_status & (AHCI_CMD_STATUS_ST | AHCI_CMD_STATUS_CR)) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 2: Make sure both PxCMD.FRE and PxCMD.FR are cleared. */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (port_cmd_status & (AHCI_CMD_STATUS_FRE | AHCI_CMD_STATUS_FR)) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Clear PxCMD.FRE */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Wait until PxCMD.FR is cleared */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (loop_count++ >= AHCI_POLLRATE_PORT_IDLE_FR) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCIDBG(AHCIDBG_INIT | AHCIDBG_ERRS, ahci_ctlp,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "ahci_setup_port_base_addresses: cannot "
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * We are effectively timing out after 0.5 sec.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * This value is specified in AHCI spec.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Wait for 1 millisec */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 3: Config Port Command List Base Address */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_cmd_list_dma_cookie.dmac_address);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_cmd_list_dma_cookie.dmac_notused);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 4: Config Port Received FIS Base Address */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_address);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_notused);
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocate the ahci_port_t including Received FIS and Command List.
2fcbc377041d659446ded306a92901b4b0753b68yt * The argument - port is the physical port number, and not logical
2fcbc377041d659446ded306a92901b4b0753b68yt * port number seen by the SATA framework.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_alloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China dev_info_t *dip = ahci_ctlp->ahcictl_dip;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China char taskq_name[64] = "event_handle_taskq";
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_port_t *)kmem_zalloc(sizeof (ahci_port_t), KM_SLEEP);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize the port condition variable */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cv_init(&ahci_portp->ahciport_cv, NULL, CV_DRIVER, NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Initialize the port mutex */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_init(&ahci_portp->ahciport_mutex, NULL, MUTEX_DRIVER,
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocate memory for received FIS structure and
2fcbc377041d659446ded306a92901b4b0753b68yt * command list for this port
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_alloc_rcvd_fis(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_alloc_cmd_list(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Setup PxCMD.CLB, PxCMD.CLBU, PxCMD.FB, and PxCMD.FBU */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_setup_port_base_addresses(ahci_ctlp, ahci_portp) !=
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China (void) snprintf(taskq_name + strlen(taskq_name),
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China sizeof (taskq_name) - strlen(taskq_name),
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China /* Create the taskq for the port */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China if ((ahci_portp->ahciport_event_taskq = ddi_taskq_create(dip,
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China taskq_name, 2, TASKQ_DEFAULTPRI, 0)) == NULL) {
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ddi_taskq_create failed for event "
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China "handle", ddi_get_instance(ahci_ctlp->ahcictl_dip));
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China /* Allocate the argument for the taskq */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_event_args->ahciea_addrp =
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /* Initialize the done queue */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneq = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneqtail = &ahci_portp->ahciport_doneq;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneq_len = 0;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ddi_taskq_destroy(ahci_portp->ahciport_event_taskq);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Reverse of ahci_alloc_port_state().
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp = ahci_ctlp->ahcictl_ports[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang kmem_free(ahci_portp->ahciport_event_args->ahciea_addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_event_args->ahciea_addrp = NULL;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt kmem_free(ahci_portp->ahciport_event_args, sizeof (ahci_event_arg_t));
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ddi_taskq_destroy(ahci_portp->ahciport_event_taskq);
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocates memory for the Received FIS Structure
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_alloc_rcvd_fis(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt /* allocate rcvd FIS dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_mem_alloc(ahci_portp->ahciport_rcvd_fis_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle & free the memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)ahci_portp->ahciport_rcvd_fis, rcvd_fis_size);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates the Received FIS Structure
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd list dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocates memory for the Command List, which contains up to 32 entries.
2fcbc377041d659446ded306a92901b4b0753b68yt * Each entry contains a command header, which is a 32-byte structure that
2fcbc377041d659446ded306a92901b4b0753b68yt * includes the pointer to the command table.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_alloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_cmd_slots * sizeof (ahci_cmd_header_t);
2fcbc377041d659446ded306a92901b4b0753b68yt /* allocate cmd list dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_list_dma_handle) != DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_mem_alloc(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_cmd_list_dma_handle,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle & free the memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)ahci_portp->ahciport_cmd_list, cmd_list_size);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_alloc_cmd_tables(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Unbind the cmd list dma handle first. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_cmd_list_dma_handle);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Then free the underlying memory. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Now free the handle itself. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates the Command List
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt /* First dealloc command table */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd list dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocates memory for all Command Tables, which contains Command FIS,
2fcbc377041d659446ded306a92901b4b0753b68yt * ATAPI Command and Physical Region Descriptor Table.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_alloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_alloc_cmd_tables: port %d enter",
2fcbc377041d659446ded306a92901b4b0753b68yt for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate cmd table dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle & free the memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Config Port Command Table Base Address */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd table dma handle first */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself */
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates memory for all Command Tables.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_dealloc_cmd_tables: %d enter",
2fcbc377041d659446ded306a92901b4b0753b68yt for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd table dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Update SATA registers at controller ports
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_update_sata_registers(ahci_ctl_t *ahci_ctlp, uint8_t port,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For poll mode, ahci_port_intr will be called to emulate the interrupt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_port_intr(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_POLLING) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* For SATA_OPMODE_POLLING commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * port_intr_enable indicates that the corresponding interrrupt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * reporting is enabled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_intr_enable = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* IPMS error in port reset should be ignored according AHCI spec. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_IGNORE_IPMS))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * port_intr_stats indicates that the corresponding interrupt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * condition is active.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_port_intr: port %d, port_intr_status = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_intr_enable = 0x%x",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Pending interrupt events are indicated by the PxIS register.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Make sure we don't miss any event.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* First clear the port interrupts status */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check the completed non-queued commands */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check the completed queued commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the port connect change status interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the device mechanical presence status interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the PhyRdy change status interrupt bit */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Check the non-fatal error interrupt bits, there are four
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * kinds of non-fatal errors at the time being:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.UFS - Unknown FIS Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.OFS - Overflow Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.INFS - Interface Non-Fatal Error
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PxIS.IPMS - Incorrect Port Multiplier Status Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For these non-fatal errors, the HBA can continue to operate,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * so the driver just log the error messages.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Check the fatal error interrupt bits, there are four kinds
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * of fatal errors for AHCI controllers:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.HBFS - Host Bus Fatal Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.HBDS - Host Bus Data Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.IFS - Interface Fatal Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.TFES - Task File Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The fatal error means the HBA can not recover from it by
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * itself, and it will try to abort the transfer, and the software
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * must intervene to restart the port.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the cold port detect interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_cold_port_detect(ahci_ctlp, ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Second clear the corresponding bit in IS.IPS */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Try to recover at the end of the interrupt handler. */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->ahcictl_ahci_acc_handle) !=
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt * Interrupt service handler
689d74b0a0dba643450e7fc74a03425c963657e7yt /* LINTED */
2fcbc377041d659446ded306a92901b4b0753b68yt * global_intr_status indicates that the corresponding port has
2fcbc377041d659446ded306a92901b4b0753b68yt * an interrupt pending.
2fcbc377041d659446ded306a92901b4b0753b68yt global_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(global_intr_status & ahci_ctlp->ahcictl_ports_implemented)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* The interrupt is not ours */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the handle after reading global_intr_status - we don't want
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * to miss any port with pending interrupts.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->ahcictl_ahci_acc_handle) !=
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop for all the ports */
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Call ahci_port_intr */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For non-queued commands, when the corresponding bit in the PxCI register
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * is cleared, it means the command is completed successfully. And according
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to the HBA state machine, there are three conditions which possibly will
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * try to clear the PxCI register bit.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1. Receive one D2H Register FIS which is with 'I' bit set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 2. Update PIO Setup FIS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 3. Transmit a command and receive R_OK if CTBA.C is set (software reset)
82263d52a84b4a969aa53f8ededddff841646ad9yt * Process completed non-queued commands when the interrupt status bit -
82263d52a84b4a969aa53f8ededddff841646ad9yt * AHCI_INTR_STATUS_DHRS or AHCI_INTR_STATUS_PSS is set.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * AHCI_INTR_STATUS_DHRS means a D2H Register FIS has been received
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * with the 'I' bit set. And the following commands will send thus
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * FIS with 'I' bit set upon the successful completion:
2fcbc377041d659446ded306a92901b4b0753b68yt * 1. Non-data commands
2fcbc377041d659446ded306a92901b4b0753b68yt * 2. DMA data-in command
2fcbc377041d659446ded306a92901b4b0753b68yt * 3. DMA data-out command
2fcbc377041d659446ded306a92901b4b0753b68yt * 4. PIO data-out command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 5. PACKET non-data commands
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 6. PACKET PIO data-in command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 7. PACKET PIO data-out command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 8. PACKET DMA data-in command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 9. PACKET DMA data-out command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * AHCI_INTR_STATUS_PSS means a PIO Setup FIS has been received
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * with the 'I' bit set. And the following commands will send this
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * FIS upon the successful completion:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1. PIO data-in command
2fcbc377041d659446ded306a92901b4b0753b68yt * Spurious interrupt. Nothing to be done.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* If the PxCI corrupts, don't complete the commmands. */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->ahcictl_ahci_acc_handle)
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Slot 0 is always used during error recovery */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: port %d the sata pkt for error "
82263d52a84b4a969aa53f8ededddff841646ad9yt "retrieval is finished, and finished_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_intr_cmd_cmplt: port %d the sata pkt for r/w "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port multiplier is finished, and finished_tags = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: pending_tags = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_cmd_issue = 0x%x finished_tags = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* READ PORTMULT need copy out FIS content. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * For non-native queued commands, the PRD byte count field
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * shall contain an accurate count of the number of bytes
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * transferred for the command before the PxCI bit is cleared
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * to '0' for the command.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * The purpose of this field is to let software know how many
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * bytes transferred for a given operation in order to
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * determine if underflow occurred. When issuing native command
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * queuing commands, this field should not be used and is not
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * required to be valid since in this case underflow is always
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * For data reads, the HBA will update its PRD byte count with
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * the total number of bytes received from the last FIS, and
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * may be able to continue normally. For data writes, the
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * device will detect an error, and HBA most likely will get
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * a fatal error.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * Therefore, here just put code to debug part. And please
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * refer to the comment above ahci_intr_fatal_error for the
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * definition of underflow error.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[finished_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China &ahci_portp->ahciport_cmd_list[finished_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_intr_cmd_cmplt: port %d, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "PRD Byte Count = 0x%x, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahciport_prd_bytecounts = 0x%x", port,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header->ahcich_prd_byte_count,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (cmd_header->ahcich_prd_byte_count != cmd_dmacount) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_intr_cmd_cmplt: port %d, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For SATAC_SMART command with SATA_SMART_RETURN_STATUS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * feature, sata_special_regs flag will be set, and the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * driver should copy the status and the other corresponding
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * register values in the D2H Register FIS received (It's
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * working on Non-data protocol) from the device back to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the sata_cmd.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For every AHCI port, there is only one Received FIS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * structure, which contains the FISes received from the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * device, So we're trying to copy the content of D2H
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Register FIS in the Received FIS structure back to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the sata_cmd.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, finished_slot);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_cmd_cmplt: pending_tags = 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * AHCI_INTR_STATUS_SDBS means a Set Device Bits FIS has been received
82263d52a84b4a969aa53f8ededddff841646ad9yt * with the 'I' bit set and has been copied into system memory. It will
82263d52a84b4a969aa53f8ededddff841646ad9yt * be sent under the following situations:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. NCQ command is completed
82263d52a84b4a969aa53f8ededddff841646ad9yt * The completion of NCQ commands (READ/WRITE FPDMA QUEUED) is performed
82263d52a84b4a969aa53f8ededddff841646ad9yt * via the Set Device Bits FIS. When such event is generated, the software
82263d52a84b4a969aa53f8ededddff841646ad9yt * needs to read PxSACT register and compares the current value to the
82263d52a84b4a969aa53f8ededddff841646ad9yt * list of commands previously issue by software. ahciport_pending_ncq_tags
82263d52a84b4a969aa53f8ededddff841646ad9yt * keeps the tags of previously issued commands.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Asynchronous Notification
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Asynchronous Notification is a feature in SATA spec 2.6.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1) ATAPI device will send a signal to the host when media is inserted or
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * removed and avoids polling the device for media changes. The signal
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * sent to the host is a Set Device Bits FIS with the 'I' and 'N' bits
82263d52a84b4a969aa53f8ededddff841646ad9yt * set to '1'. At the moment, it's not supported yet.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2) Port multiplier will send a signal to the host when a hot plug event
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * has occured on a port multiplier port. It is used when command based
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * switching is employed. This is handled by ahci_intr_pmult_sntf_events()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_intr_set_device_bits enter: port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize HBA port address */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* NCQ plug handler */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_intr_ncq_events(ahci_ctlp, ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check port multiplier's asynchronous notification events */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* ATAPI events is not supported yet */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NCQ interrupt handler. Called upon a NCQ command is completed.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Only be called from ahci_intr_set_device_bits().
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt * First the handler got which commands are finished by checking
82263d52a84b4a969aa53f8ededddff841646ad9yt * PxSACT register
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d pending_ncq_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: finished_tags = 0x%x", finished_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt * For NCQ commands, the software can determine which command has
82263d52a84b4a969aa53f8ededddff841646ad9yt * already been transmitted to the device by checking PxCI register.
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* If the PxSACT/PxCI corrupts, don't complete the NCQ commmands. */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->ahcictl_ahci_acc_handle)
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d pending_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: issued_tags = 0x%x", issued_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt * Clear ahciport_pending_tags bit when the corresponding command
82263d52a84b4a969aa53f8ededddff841646ad9yt * is already sent down to the device.
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, issued_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt /* The command is certainly transmitted to the device */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: sending up pkt 0x%p "
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags, finished_slot);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_ncq_tags = 0x%x pending_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Port multiplier asynchronous notification event handler. Called upon a
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * device is hot plugged/pulled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The async-notification event will only be recorded by ahcipmi_snotif_tags
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * here and will be handled by ahci_probe_pmult().
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: called only from ahci_port_intr().
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_intr_pmult_sntf_events(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_intr_pmult_sntf_events enter: port %d ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* no hot-plug while attaching process */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info->ahcipmi_snotif_tags =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_pmult_info->ahcipmi_snotif_tags == 0) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Port Multiplier sub-device hot-plug handler */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_PMULT_SNTF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Not allowed to re-enter. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_PMULT_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Even if Asynchronous Notification is supported (and enabled) by
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * both controller and the port multiplier, the content of PxSNTF
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * register is always set to 0x8000 by async notification event. We
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * need to check GSCR[32] on the port multiplier to find out the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * owner of this event.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * This is not accord with SATA spec 2.6 and needs further
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * clarification.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* hot-plug will not reported while reseting. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_reset_in_progress == 1) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_PMULT_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "PxSNTF is set to 0x%x by port multiplier",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info->ahcipmi_snotif_tags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Now we need do some necessary operation and inform SATA framework
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * that link/device events has happened.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = SATA_PMULT_HOSTPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Just reject packets, do not stop that port. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_PMULT_SNTF;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1=Change in Current Connect Status. 0=No change in Current Connect Status.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This bit reflects the state of PxSERR.DIAG.X. This bit is only cleared
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * when PxSERR.DIAG.X is cleared. When PxSERR.DIAG.X is set to one, it
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * indicates a COMINIT signal was received.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Hot plug insertion is detected by reception of a COMINIT signal from the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * device. On reception of unsolicited COMINIT, the HBA shall generate a
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * COMRESET. If the COMINIT is in responce to a COMRESET, then the HBA shall
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * begin the normal communication negotiation sequence as outlined in the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Serial ATA 1.0a specification. When a COMRESET is sent to the device the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxSSTS.DET field shall be cleared to 0h. When a COMINIT is received, the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxSSTS.DET field shall be set to 1h. When the communication negotiation
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * sequence is complete and PhyRdy is true the PxSSTS.DET field shall be set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to 3h. Therefore, at the moment the ahci driver is going to check PhyRdy
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to handle hot plug insertion. In this interrupt handler, just do nothing
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * but print some log message and clear the bit.
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_port_connect_change: port %d, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear PxSERR.DIAG.X to clear the interrupt bit */
2fcbc377041d659446ded306a92901b4b0753b68yt * Hot Plug Operation for platforms that support Mechanical Presence
2fcbc377041d659446ded306a92901b4b0753b68yt * Switches.
2fcbc377041d659446ded306a92901b4b0753b68yt * When set, it indicates that a mechanical presence switch attached to this
2fcbc377041d659446ded306a92901b4b0753b68yt * port has been opened or closed, which may lead to a change in the connection
2fcbc377041d659446ded306a92901b4b0753b68yt * state of the device. This bit is only valid if both CAP.SMPS and PxCMD.MPSP
2fcbc377041d659446ded306a92901b4b0753b68yt * are set to '1'.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * At the moment, this interrupt is not needed and disabled and we just log
2fcbc377041d659446ded306a92901b4b0753b68yt * the debug message.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_intr_device_mechanical_presence_status(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_intr_device_mechanical_presence_status enter, "
2fcbc377041d659446ded306a92901b4b0753b68yt cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt "CAP.SMPS or PxCMD.MPSP is not set, so just ignore "
2fcbc377041d659446ded306a92901b4b0753b68yt "the interrupt: cap_status = 0x%x, "
2fcbc377041d659446ded306a92901b4b0753b68yt "The mechanical presence switch is open: "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d, port_cmd_status = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt "The mechanical presence switch is close: "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d, port_cmd_status = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt * Native Hot Plug Support.
2fcbc377041d659446ded306a92901b4b0753b68yt * When set, it indicates that the internal PHYRDY signal changed state.
2fcbc377041d659446ded306a92901b4b0753b68yt * This bit reflects the state of PxSERR.DIAG.N.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * There are three kinds of conditions to generate this interrupt event:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1. a device is inserted
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 2. a device is disconnected
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 3. when the link enters/exits a Partial or Slumber interface power
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * management state
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If inteface power management is enabled for a port, the PxSERR.DIAG.N
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * bit may be set due to the link entering the Partial or Slumber power
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * management state, rather than due to a hot plug insertion or removal
13bcbb7a73761015c9ef46cac33040380196e57fyt * event. So far, the interface power management is disabled, so the
13bcbb7a73761015c9ef46cac33040380196e57fyt * driver can reliably get removal detection notification via the
13bcbb7a73761015c9ef46cac33040380196e57fyt * PxSERR.DIAG.N bit.
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_sstatus = 0; /* No dev present & PHY not established. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Clear PxSERR.DIAG.N to clear the interrupt bit */
2fcbc377041d659446ded306a92901b4b0753b68yt /* The whole controller setup is not yet done. */
2fcbc377041d659446ded306a92901b4b0753b68yt /* SStatus tells the presence of device. */
2fcbc377041d659446ded306a92901b4b0753b68yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) {
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_phyrdy_change: port %d "
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_HOTPLUG;
2fcbc377041d659446ded306a92901b4b0753b68yt /* Things are fine now. The loss was temporary. */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else { /* 0 -> 1 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * A new device has been detected. The new device
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * might be a port multiplier instead of a drive, so
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * we cannot update the signature directly.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Try to start the port */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d failed "
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Clear the max queue depth for inserted device */
2fcbc377041d659446ded306a92901b4b0753b68yt } else { /* No device exists now */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt /* An existing device is lost. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_STATE_UNKNOWN;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_HOTPLUG;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.UFS - Unknown FIS Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This interrupt event means an unknown FIS was received and has been
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * copied into system memory. An unknown FIS is not considered an illegal
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * FIS, unless the length received is more than 64 bytes. If an unknown
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * FIS arrives with length <= 64 bytes, it is posted and the HBA continues
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * normal operation. If the unknown FIS is more than 64 bytes, then it
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * won't be posted to memory and PxSERR.ERR.P will be set, which is then
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a fatal error.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PxIS.IPMS - Incorrect Port Multiplier Status
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * IPMS Indicates that the HBA received a FIS from a device that did not
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * have a command outstanding. The IPMS bit may be set during enumeration
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * of devices on a Port Multiplier due to the normal Port Multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * enumeration process. It is recommended that IPMS only be used after
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * enumeration is complete on the Port Multiplier (copied from spec).
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.OFS - Overflow Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Command list overflow is defined as software building a command table
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * that has fewer total bytes than the transaction given to the device.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * On device writes, the HBA will run out of data, and on reads, there
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * will be no room to put the data.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For an overflow on data read, either PIO or DMA, the HBA will set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.OFS, and the HBA will do a best effort to continue, and it's a
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * non-fatal error when the HBA can continues. Sometimes, it will cause
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a fatal error and need the software to do something.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For an overflow on data write, setting PxIS.OFS is optional for both
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * DMA and PIO, and it's a fatal error, and a COMRESET is required by
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * software to clean up from this serious error.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.INFS - Interface Non-Fatal Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This interrupt event indicates that the HBA encountered an error on
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the Serial ATA interface but was able to continue operation. The kind
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * of error usually occurred during a non-Data FIS, and under this condition
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the FIS will be re-transmitted by HBA automatically.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When the FMA is implemented, there should be a stat structure to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * record how many every kind of error happens.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_intr_non_fatal_error(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY|AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_non_fatal_error: port %d, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "PxSERR = 0x%x, PxIS = 0x%x ", port, port_serror, intr_status);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_log_serror_message(ahci_ctlp, port, port_serror, 1);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear the interrupt bit by clearing PxSERR.DIAG.F */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "has Incorrect Port Multiplier Status error", port);
2fcbc377041d659446ded306a92901b4b0753b68yt * Record the error occurred command's slot.
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt current_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_non_fatal_error: pending_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_non_fatal_error: port %d, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "satapkt 0x%p is being processed when error occurs",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * PRD Byte Count field of command header is not
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * required to reflect the total number of bytes
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * transferred when an overflow occurs, so here
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * just log the value.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[current_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_intr_non_fatal_error: port %d, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "PRD Byte Count = 0x%x, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahciport_prd_bytecounts = 0x%x", port,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header->ahcich_prd_byte_count,
82263d52a84b4a969aa53f8ededddff841646ad9yt * For queued command, list those command which have already
82263d52a84b4a969aa53f8ededddff841646ad9yt * been transmitted to the device and still not completed.
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_non_fatal_error: pending_ncq_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_sactive = 0x%x port_cmd_issue = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt "port %d, satapkt 0x%p is outstanding when "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * According to the AHCI spec, the error types include system memory
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * errors, interface errors, port multiplier errors, device errors,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * command list overflow, command list underflow, native command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * queuing tag errors and pio data transfer errors.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * System memory errors such as target abort, master abort, and parity
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * may cause the host to stop, and they are serious errors and needed
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to be recovered with software intervention. When system software
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * has given a pointer to the HBA that doesn't exist in physical memory,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a master/target abort error occurs, and PxIS.HBFS will be set. A
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * data error such as CRC or parity occurs, the HBA aborts the transfer
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * (if necessary) and PxIS.HBDS will be set.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Interface errors are errors that occur due to electrical issues on
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the interface, or protocol miscommunication between the device and
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * HBA, and the respective PxSERR register bit will be set. And PxIS.IFS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * (fatal) or PxIS.INFS (non-fatal) will be set. The conditions that
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * causes PxIS.IFS/PxIS.INFS to be set are
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1. in PxSERR.ERR, P bit is set to '1'
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 2. in PxSERR.DIAG, C or H bit is set to '1'
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 3. PhyRdy drop unexpectly, N bit is set to '1'
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If the error occurred during a non-data FIS, the FIS must be
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * retransmitted, and the error is non-fatal and PxIS.INFS is set. If
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the error occurred during a data FIS, the transfer will stop, so
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the error is fatal and PxIS.IFS is set.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When a FIS arrives that updates the taskfile, the HBA checks to see
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * if PxTFD.STS.ERR is set. If yes, PxIS.TFES will be set and the HBA
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * stops processing any more commands.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Command list overflow is defined as software building a command table
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * that has fewer total bytes than the transaction given to the device.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * On device writes, the HBA will run out of data, and on reads, there
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * will be no room to put the data. For an overflow on data read, either
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PIO or DMA, the HBA will set PxIS.OFS, and it's a non-fatal error.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For an overflow on data write, setting PxIS.OFS is optional for both
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * DMA and PIO, and a COMRESET is required by software to clean up from
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * this serious error.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Command list underflow is defined as software building a command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * table that has more total bytes than the transaction given to the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * device. For data writes, both PIO and DMA, the device will detect
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * an error and end the transfer. And these errors are most likely going
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to be fatal errors that will cause the port to be restarted. For
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * data reads, the HBA updates its PRD byte count, and may be
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * able to continue normally, but is not required to. And The HBA is
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * not required to detect underflow conditions for native command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * queuing command.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The HBA does not actively check incoming DMA Setup FISes to ensure
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * that the PxSACT register bit for that slot is set. Existing error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * mechanisms, such as host bus failure, or bad protocol, are used to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * recover from this case.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * In accordance with Serial ATA 1.0a, DATA FISes prior to the final
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * DATA FIS must be an integral number of Dwords. If the HBA receives
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a request which is not an integral number of Dwords, the HBA
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * set PxSERR.ERR.P to '1', set PxIS.IFS to '1' and stop running until
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * software restarts the port. And the HBA ensures that the size
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * of the DATA FIS received during a PIO command matches the size in
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the Transfer Cound field of the preceding PIO Setup FIS, if not, the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * HBA sets PxSERR.ERR.P to '1', set PxIS.IFS to '1', and then
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * stop running until software restarts the port.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the fatal errors include PxIS.IFS, PxIS.HBDS, PxIS.HBFS and PxIS.TFES.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.IFS indicates that the hba encountered an error on the serial ata
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * interface which caused the transfer to stop.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.HBDS indicates that the hba encountered a data error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * (uncorrectable ecc/parity) when reading from or writing to system memory.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.HBFS indicates that the hba encountered a host bus error that it
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * cannot recover from, such as a bad software pointer.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.TFES is set whenever the status register is updated by the device
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * and the error bit (bit 0) is set.
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int task_fail_flag = 0, task_abort_flag = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_intr_phyrdy_change() may have rendered it to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_DTYPE_NONE.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_fatal_error: port %d no device attached, "
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China if (intr_status & AHCI_INTR_STATUS_TFES) {
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China "ahci_intr_fatal_error: port %d "
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China "task_file_status = 0x%x", port, task_file_status);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China err_byte = (task_file_status & AHCI_TFD_ERR_MASK)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Here we just log the fatal error info in interrupt context.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Misc recovery processing will be handled in task queue.
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China * Read PxCMD.CCS to determine the slot that the HBA
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China * was processing when the error occurred.
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_ctlp->ahcictl_ahci_acc_handle,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China failed_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "ahci_intr_fatal_error: spkt 0x%p is being "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "processed when fatal error occurred for port %d",
82263d52a84b4a969aa53f8ededddff841646ad9yt * Won't emit the error message if it is an IDENTIFY
82263d52a84b4a969aa53f8ededddff841646ad9yt * DEVICE command sent to an ATAPI device.
82263d52a84b4a969aa53f8ededddff841646ad9yt * Won't emit the error message if it is an ATAPI PACKET
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_ctlp->ahcictl_ahci_acc_handle,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China /* print the fatal error type */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_log_fatal_error_message(ahci_ctlp, port, intr_status);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_ERRPRINT;
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China /* print PxSERR related error message */
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_log_serror_message(ahci_ctlp, port, port_serror, 0);
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China /* print task file register value */
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d task_file_status "
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China "= 0x%x", instance, port, task_file_status);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: the below command (s) on "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "port %d are aborted", instance, port);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_dump_commands(ahci_ctlp, port, failed_tags);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Prepare the argument for the taskq */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT((ahci_addr_t *)args->ahciea_addrp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Start the taskq to handle error recovery */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China if ((ddi_taskq_dispatch(ahci_portp->ahciport_event_taskq,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_ERRPRINT;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: start taskq for error recovery "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "port %d failed", instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt * Hot Plug Operation for platforms that support Cold Presence Detect.
2fcbc377041d659446ded306a92901b4b0753b68yt * When set, a device status has changed as detected by the cold presence
2fcbc377041d659446ded306a92901b4b0753b68yt * detect logic. This bit can either be set due to a non-connected port
2fcbc377041d659446ded306a92901b4b0753b68yt * receiving a device, or a connected port having its device removed.
2fcbc377041d659446ded306a92901b4b0753b68yt * This bit is only valid if the port supports cold presence detect as
2fcbc377041d659446ded306a92901b4b0753b68yt * indicated by PxCMD.CPD set to '1'.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * At the moment, this interrupt is not needed and disabled and we just
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * log the debug message.
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d does not support cold presence detect, so "
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
2fcbc377041d659446ded306a92901b4b0753b68yt * Enable the interrupts for a particular port.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
689d74b0a0dba643450e7fc74a03425c963657e7ytahci_enable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt * Clear port interrupt status before enabling interrupt
2fcbc377041d659446ded306a92901b4b0753b68yt * Clear the pending bit from IS.IPS
2fcbc377041d659446ded306a92901b4b0753b68yt * Enable the following interrupts:
2fcbc377041d659446ded306a92901b4b0753b68yt * Device to Host Register FIS Interrupt (DHRS)
2fcbc377041d659446ded306a92901b4b0753b68yt * PIO Setup FIS Interrupt (PSS)
82263d52a84b4a969aa53f8ededddff841646ad9yt * Set Device Bits Interrupt (SDBS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Unknown FIS Interrupt (UFS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Port Connect Change Status (PCS)
2fcbc377041d659446ded306a92901b4b0753b68yt * PhyRdy Change Status (PRCS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Overflow Status (OFS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Interface Non-fatal Error Status (INFS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Interface Fatal Error Status (IFS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Host Bus Data Error Status (HBDS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Host Bus Fatal Error Status (HBFS)
2fcbc377041d659446ded306a92901b4b0753b68yt * Task File Error Status (TFES)
2fcbc377041d659446ded306a92901b4b0753b68yt * Enable interrupts for all the ports.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable interrupts for a particular port.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
689d74b0a0dba643450e7fc74a03425c963657e7ytahci_disable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & AHCI_QUIESCE ||
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable interrupts for the whole HBA.
2fcbc377041d659446ded306a92901b4b0753b68yt * The global bit is cleared, then all interrupt sources from all
2fcbc377041d659446ded306a92901b4b0753b68yt * ports are disabled.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & (AHCI_ATTACH | AHCI_QUIESCE) ||
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter",
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Handle FIXED or MSI interrupts.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * According to AHCI spec, the HBA may support several interrupt modes:
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * * pin based interrupts (FIXED)
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * * single MSI message interrupts
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * * multiple MSI based message interrupts
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * For pin based interrupts, the software interrupt handler need to check IS
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * register to find out which port has pending interrupts. And then check
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * PxIS register to find out which interrupt events happened on that port.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * For single MSI message interrupts, MSICAP.MC.MSIE is set with '1', and
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * MSICAP.MC.MME is set with '0'. This mode is similar to pin based interrupts
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * in that software interrupt handler need to check IS register to determine
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * which port triggered the interrupts since it uses a single message for all
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * port interrupts.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * HBA may optionally support multiple MSI message for better performance. In
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * this mode, each port may have its own interrupt message, and thus generation
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * of interrupts is no longer controlled through the IS register. MSICAP.MC.MMC
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * represents a power-of-2 wrapper on the number of implemented ports, and
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * the mapping of ports to interrupts is done in a 1-1 relationship, up to the
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * maximum number of assigned interrupts. When the number of MSI messages
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * allocated is less than the number requested, then hardware may have two
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * implementation behaviors:
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * * assign each ports its own interrupt and then force all additional
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * ports to share the last interrupt message, and this condition is
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * indicated by clearing GHC.MRSM to '0'
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * * revert to single MSI mode, indicated by setting GHC.MRSM to '1'
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * When multiple-message MSI is enabled, hardware will still set IS register
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * as single message case. And this IS register may be used by software when
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * fewer than the requested number of messages is granted in order to determine
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * which port had the interrupt.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Note: The current ahci driver only supports the first two interrupt modes:
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * pin based interrupts and single MSI message interrupts, and the reason
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * is indicated in below code.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing Chinaahci_add_intrs(ahci_ctl_t *ahci_ctlp, int intr_type)
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "ahci_add_intrs enter interrupt type 0x%x", intr_type);
2fcbc377041d659446ded306a92901b4b0753b68yt /* get number of interrupts. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China rc = ddi_intr_get_nintrs(dip, intr_type, &count);
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_nintrs() failed, "
2fcbc377041d659446ded306a92901b4b0753b68yt /* get number of available interrupts. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China rc = ddi_intr_get_navail(dip, intr_type, &avail);
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_navail() failed, "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "ddi_intr_get_nintrs returned %d, navail() returned %d",
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Note: So far Solaris restricts the maximum number of messages for
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * x86 to 2, that is avail is 2, so here we set the count with 1 to
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * force the driver to use single MSI message interrupt. In future if
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Solaris remove the restriction, then we need to delete the below
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * code and try to use multiple interrupt routine to gain better
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "force to use one interrupt routine though the "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "HBA supports %d interrupt", count);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate an array of interrupt handles. */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_size = count * sizeof (ddi_intr_handle_t);
2fcbc377041d659446ded306a92901b4b0753b68yt /* call ddi_intr_alloc(). */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China intr_type, 0, count, &actual, DDI_INTR_ALLOC_NORMAL);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "ddi_intr_alloc() failed, rc %d count %d actual %d "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "avail %d\n", rc, count, actual, avail);
2fcbc377041d659446ded306a92901b4b0753b68yt /* use interrupt count returned */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Get priority for first, assume remaining are all the same.
2fcbc377041d659446ded306a92901b4b0753b68yt /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China (void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[i]);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Test for high level interrupt. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_add_intrs: Hi level intr not supported", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China (void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[i]);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_add_handler(). */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ddi_intr_add_handler(ahci_ctlp->ahcictl_intr_htable[i],
2fcbc377041d659446ded306a92901b4b0753b68yt /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ddi_intr_get_cap(ahci_ctlp->ahcictl_intr_htable[0],
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China &ahci_ctlp->ahcictl_intr_cap) != DDI_SUCCESS) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China kmem_free(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_block_enable() for MSI. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_block_enable(ahci_ctlp->ahcictl_intr_htable,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China /* Call ddi_intr_enable() for FIXED or MSI non block enable. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < ahci_ctlp->ahcictl_intr_cnt; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2fcbc377041d659446ded306a92901b4b0753b68yt * Removes the registered interrupts irrespective of whether they
2fcbc377041d659446ded306a92901b4b0753b68yt * were legacy or MSI.
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * NOTE: The controller interrupts must be disabled before calling
2fcbc377041d659446ded306a92901b4b0753b68yt * this routine.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Disable all interrupts. */
2fcbc377041d659446ded306a92901b4b0753b68yt if ((ahci_ctlp->ahcictl_intr_type == DDI_INTR_TYPE_MSI) &&
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_block_disable(). */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_block_disable(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_remove_handler(). */
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_ctlp->ahcictl_intr_htable, ahci_ctlp->ahcictl_intr_size);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This routine tries to put port into P:NotRunning state by clearing
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxCMD.ST. HBA will clear PxCI to 0h, PxSACT to 0h, PxCMD.CCS to 0h
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * and PxCMD.CR to '0'.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_put_port_into_notrunning_state(ahci_ctl_t *ahci_ctlp,
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & AHCI_QUIESCE ||
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_put_port_into_notrunning_state enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait until PxCMD.CR is cleared */
2fcbc377041d659446ded306a92901b4b0753b68yt "clearing port %d CMD.CR timeout, "
2fcbc377041d659446ded306a92901b4b0753b68yt * We are effectively timing out after 0.5 sec.
2fcbc377041d659446ded306a92901b4b0753b68yt * This value is specified in AHCI spec.
689d74b0a0dba643450e7fc74a03425c963657e7yt /* Wait for 10 millisec */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_put_port_into_notrunning_state: failed to clear "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "PxCMD.CR to '0' after loop count: %d, and "
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_POLL_LOOP, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_put_port_into_notrunning_state: succeeded to clear "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "PxCMD.CR to '0' after loop count: %d, and "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * First clear PxCMD.ST, and then check PxTFD. If both PxTFD.STS.BSY
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * and PxTFD.STS.DRQ cleared to '0', it means the device is in a
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * stable state, then set PxCMD.ST to '1' to start the port directly.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue a
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * COMRESET to the device to put it in an idle state.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The fifth argument returns whether the port reset is involved during
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the process.
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * The routine will be called under following scenarios:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * + To reset the HBA
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * + To abort the packet(s)
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * + To reset the port
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * + To activate the port
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * + Fatal error recovery
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * + To abort the timeout packet(s)
82263d52a84b4a969aa53f8ededddff841646ad9yt * NOTES!!! During this procedure, PxSERR register will be cleared, and
82263d52a84b4a969aa53f8ededddff841646ad9yt * according to the spec, the clearance of three bits will also clear
82263d52a84b4a969aa53f8ededddff841646ad9yt * three interrupt status bits.
82263d52a84b4a969aa53f8ededddff841646ad9yt * 1. PxSERR.DIAG.F will clear PxIS.UFS
82263d52a84b4a969aa53f8ededddff841646ad9yt * 2. PxSERR.DIAG.X will clear PxIS.PCS
82263d52a84b4a969aa53f8ededddff841646ad9yt * 3. PxSERR.DIAG.N will clear PxIS.PRCS
82263d52a84b4a969aa53f8ededddff841646ad9yt * Among these three interrupt events, the driver needs to take care of
82263d52a84b4a969aa53f8ededddff841646ad9yt * PxIS.PRCS, which is the hot plug event. When the driver found out
82263d52a84b4a969aa53f8ededddff841646ad9yt * a device was unplugged, it will call the interrupt handler.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_port_t *ahci_portp, uint8_t port, int flag, int *reset_flag)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t previous_dev_type = ahci_portp->ahciport_device_type;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t cport = ahci_ctlp->ahcictl_port_to_cport[port];
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_restart_port_wait_till_ready: port %d enter", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE)
82263d52a84b4a969aa53f8ededddff841646ad9yt /* First clear PxCMD.ST */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt rval = ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If PxCMD.CR does not clear within a reasonable time, it
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * may assume the interface is in a hung condition and may
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * continue with issuing the port reset.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Then clear PxSERR */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Then get PxTFD */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Check whether the device is in a stable status, if yes,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * then start the port directly. However for ahci_tran_reset_dport,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * we may have to perform a port reset.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (!(task_file_status & (AHCI_TFD_STS_BSY | AHCI_TFD_STS_DRQ)) &&
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a COMRESET to the device
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = ahci_port_reset(ahci_ctlp, ahci_portp, &addr_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_restart_port_wait_till_ready: port %d failed",
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the framework that a reset has happened. */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Set the reset in progress flag */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt /* SStatus tells the presence of device. */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_exists_begin == 0 && dev_exists_end == 0) /* 0 -> 0 */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check whether a hot plug event happened */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_exists_begin == 1 && dev_exists_end == 0) { /* 1 -> 0 */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_restart_port_wait_till_ready: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_restart_port_wait_till_ready: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt (void) ahci_intr_phyrdy_change(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* 0/1 -> 1 : device may change */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * May be called by ahci_fatal_error_recovery_handler, so
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * don't issue software if the previous device is ATAPI.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPI)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The COMRESET will make port multiplier enter legacy mode.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Issue a software reset to make it work again.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_find_dev_signature(ahci_ctlp, ahci_portp, &addr_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Following codes are specific for the port multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* in case previous_dev_type is corrupt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device change: PMult -> Non-PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * This might happen because
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. Software reset failed. Port multiplier is not correctly
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * enumerated.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Another non-port-multiplier device is attached. Perhaps
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * the port multiplier was replaced by another device by
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * whatever reason, but AHCI driver missed hot-plug event.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Now that the port has been initialized, we just need to
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * update the port structure according new device, then report
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * and wait SATA framework to probe new device.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Force to release pmult resource */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Port multiplier is [Gone] at port %d ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device change: Non-PMult -> PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* NOTE: The PxCMD.PMA may be cleared by HBA reset. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device (may) change: PMult -> PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * First initialize port multiplier. Set state to READY and wait for
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * probe entry point to initialize it
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_STATE_READY;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * It's a little complicated while target is a port multiplier. we
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * need to COMRESET all pmports behind that PMult otherwise those
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * sub-links between the PMult and the sub-devices will be in an
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * inactive state (indicated by PSCR0/PxSSTS) and the following access
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * to those sub-devices will be rejected by Link-Fatal-Error.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The PxSNTF will be set soon after the pmult is plugged. While the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * pmult itself is attaching, sata_hba_event_notfiy will fail. so we
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * simply mark every sub-port as 'unknown', then ahci_probe_pmport
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * will initialized it.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang for (npmport = 0; npmport < pminfo->ahcipmi_num_dev_ports; npmport++)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang pminfo->ahcipmi_port_state[npmport] = SATA_STATE_UNKNOWN;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Report reset event. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = SATA_PMULT_HOSTPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_state = SATA_DSTATE_RESET | SATA_DSTATE_PWR_ACTIVE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(ahci_ctlp->ahcictl_dip, &sdevice,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This routine may be called under four scenarios:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a) do the recovery from fatal error
2fcbc377041d659446ded306a92901b4b0753b68yt * b) or we need to timeout some commands
2fcbc377041d659446ded306a92901b4b0753b68yt * c) or we need to abort some commands
2fcbc377041d659446ded306a92901b4b0753b68yt * d) or we need reset device/port/controller
2fcbc377041d659446ded306a92901b4b0753b68yt * In all these scenarios, we need to send any pending unfinished
2fcbc377041d659446ded306a92901b4b0753b68yt * commands up to sata framework.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_mop_commands entered: port: %d slot_status: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_mop_commands: failed_tags: 0x%x, "
2fcbc377041d659446ded306a92901b4b0753b68yt "timeout_tags: 0x%x aborted_tags: 0x%x, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang for (i = 0x1f; i >= 0; i--) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_slot_pkts[i] != NULL)
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT is
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * set, it means REQUEST SENSE or READ LOG EXT command doesn't
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * complete successfully due to one of the following three
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * conditions:
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * 1. Fatal error - failed_tags includes its slot
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * 2. Timed out - timeout_tags includes its slot
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * 3. Aborted when hot unplug - aborted_tags includes its
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * Please note that the command is always sent down in Slot 0
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_mop_commands is called for port %d while "
82263d52a84b4a969aa53f8ededddff841646ad9yt "REQUEST SENSE or READ LOG EXT for error retrieval "
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China "is being executed slot_status = 0x%x",
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_portp->ahciport_port_num, slot_status);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands is called for port %d while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "READ/WRITE PORTMULT command is being executed",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: finished_tags: 0x%x, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "unfinished_tags 0x%x", finished_tags, unfinished_tags);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up finished packets with SATA_PKT_COMPLETED */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_COMPLETED",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Cannot fetch the return register content since the port
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * was restarted, so the corresponding tag will be set to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * aborted tags.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up failed packets with SATA_PKT_DEV_ERROR. */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_DEV_ERROR",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up timeout packets with SATA_PKT_TIMEOUT. */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_TIMEOUT",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up aborted packets with SATA_PKT_ABORTED */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_ABORTED",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_ABORTED",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_ABORTED",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up reset packets with SATA_PKT_RESET. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_RESET",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_RESET",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up unfinished packets with SATA_PKT_RESET */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "sending up pkt 0x%p with SATA_PKT_RESET",
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
82263d52a84b4a969aa53f8ededddff841646ad9yt * This routine is going to first request a READ LOG EXT sata pkt from sata
82263d52a84b4a969aa53f8ededddff841646ad9yt * module, and then deliver it to the HBA to get the ncq failure context.
82263d52a84b4a969aa53f8ededddff841646ad9yt * The return value is the exactly failed tags.
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_get_rdlogext_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Prepare the sdevice data */
82263d52a84b4a969aa53f8ededddff841646ad9yt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Translate sata_device.satadev_addr -> ahci_addr */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &sdevice, &addr);
82263d52a84b4a969aa53f8ededddff841646ad9yt * Call the sata hba interface to get a rdlog spkt
82263d52a84b4a969aa53f8ededddff841646ad9yt rdlog_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Sleep for a while */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Timed out after 1s */
82263d52a84b4a969aa53f8ededddff841646ad9yt * This flag is used to handle the specific error recovery when the
82263d52a84b4a969aa53f8ededddff841646ad9yt * READ LOG EXT command gets a failure (fatal error or time-out).
82263d52a84b4a969aa53f8ededddff841646ad9yt * This start is not supposed to fail because after port is restarted,
82263d52a84b4a969aa53f8ededddff841646ad9yt * the whole command list is empty.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr, rdlog_spkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Remove the flag after READ LOG EXT command is completed */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RDLOGEXT;
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Update the request log data */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Get the failed tag */
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_get_rdlogext_data: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_get_rdlogext_data: failed spkt 0x%p",
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Fill out the error context */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This routine is going to first request a REQUEST SENSE sata pkt from sata
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * module, and then deliver it to the HBA to get the sense data and copy
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the sense data back to the orignal failed sata pkt, and free the REQUEST
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SENSE sata pkt later.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_get_rqsense_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Prepare the sdevice data */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Translate sata_device.satadev_addr -> ahci_addr */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &sdevice, &addr);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Call the sata hba interface to get a rs spkt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt rs_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Sleep for a while */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Timed out after 1s */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This flag is used to handle the specific error recovery when the
82263d52a84b4a969aa53f8ededddff841646ad9yt * REQUEST SENSE command gets a faiure (fatal error or time-out).
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This start is not supposed to fail because after port is restarted,
82263d52a84b4a969aa53f8ededddff841646ad9yt * the whole command list is empty.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr, rs_spkt);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Remove the flag after REQUEST SENSE command is completed */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RQSENSE;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Update the request sense data */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Copy the request sense data */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Dump the sense data */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, "\n", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt "Sense data for satapkt %p ATAPI cmd 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt " es_code 0x%x es_class 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "es_key 0x%x es_add_code 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "es_qual_code 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt * Fatal errors will cause the HBA to enter the ERR: Fatal state. To recover,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the port must be restarted. When the HBA detects thus error, it may try
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to abort a transfer. And if the transfer was aborted, the device is
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * expected to send a D2H Register FIS with PxTFD.STS.ERR set to '1' and both
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxTFD.STS.BSY and PxTFD.STS.DRQ cleared to '0'. Then system software knows
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * that the device is in a stable status and transfers may be restarted without
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * issuing a COMRESET to the device. If PxTFD.STS.BSY or PxTFD.STS.DRQ is set,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * then the software will send the COMRESET to do the port reset.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Software should perform the appropriate error recovery actions based on
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * whether non-queued commands were being issued or natived command queuing
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * commands were being issued.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * And software will complete the command that had the error with error mark
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to higher level software.
2fcbc377041d659446ded306a92901b4b0753b68yt * Fatal errors include the following:
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * PxIS.IFS - Interface Fatal Error Status
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * PxIS.HBDS - Host Bus Data Error Status
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * PxIS.HBFS - Host Bus Fatal Error Status
2fcbc377041d659446ded306a92901b4b0753b68yt * PxIS.TFES - Task File Error Status
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp, uint32_t intr_status)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_fatal_error_recovery_handler enter: port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Port multiplier error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FBS code is neither completed nor tested. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_pmult_error_recovery_handler(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Force a port reset */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxCI to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt * Read PxCMD.CCS to determine the slot that the HBA
82263d52a84b4a969aa53f8ededddff841646ad9yt * was processing when the error occurred.
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt /* May happen when interface errors occur? */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * Debugging purpose...
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (ahci_portp->ahciport_prd_bytecounts[failed_slot]) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China &ahci_portp->ahciport_cmd_list[failed_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_fatal_error_recovery_handler: port %d, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "PRD Byte Count = 0x%x, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahciport_prd_bytecounts = 0x%x", port,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header->ahcich_prd_byte_count,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[failed_slot]);
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Fill out the status and error registers for PxIS.TFES */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Copy the error context back to the sata_cmd */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* The failed command must be one of the outstanding commands */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Update the sata registers, especially PxSERR register */
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxSACT to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT flag is
82263d52a84b4a969aa53f8ededddff841646ad9yt * set, it means a fatal error happened after REQUEST SENSE command
82263d52a84b4a969aa53f8ededddff841646ad9yt * or READ LOG EXT command is delivered to the HBA during the error
82263d52a84b4a969aa53f8ededddff841646ad9yt * recovery process. At this time, the only outstanding command is
82263d52a84b4a969aa53f8ededddff841646ad9yt * supposed to be REQUEST SENSE command or READ LOG EXT command.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_fatal_error_recovery_handler: port %d REQUEST SENSE "
82263d52a84b4a969aa53f8ededddff841646ad9yt "command or READ LOG EXT command for error data retrieval "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China rval = ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_ERRPRINT) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_ERRPRINT;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: error recovery for port %d "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: error recovery for port %d "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Won't retrieve error information:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 1. Port reset was involved to recover
82263d52a84b4a969aa53f8ededddff841646ad9yt * 2. Device is gone
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * 3. IDENTIFY DEVICE command sent to ATAPI device
82263d52a84b4a969aa53f8ededddff841646ad9yt * 4. REQUEST SENSE or READ LOG EXT command during error recovery
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt && spkt->satapkt_cmd.satacmd_cmd_reg == SATAC_ID_DEVICE ||
82263d52a84b4a969aa53f8ededddff841646ad9yt * Deliver READ LOG EXT to gather information about the error when
82263d52a84b4a969aa53f8ededddff841646ad9yt * a COMRESET has not been performed as part of the error recovery
82263d52a84b4a969aa53f8ededddff841646ad9yt * during NCQ command processing.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Deliver REQUEST SENSE for ATAPI command to gather information about
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the error when a COMRESET has not been performed as part of the
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * error recovery.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (spkt && ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPI)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_get_rqsense_data(ahci_ctlp, ahci_portp, port, spkt);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_fatal_error_recovery_handler: port %d fatal error "
82263d52a84b4a969aa53f8ededddff841646ad9yt "occurred slot_status = 0x%x, pending_tags = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_ncq_tags = 0x%x failed_tags = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0); /* reset tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Used to recovery a PMULT pmport fatal error under FIS-based switching.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. device specific.PxFBS.SDE=1
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Non-Deivce specific.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Nothing will be done when Command-based switching is employed.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Currently code is neither completed nor tested.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_pmult_error_recovery_handler(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Nothing will be done under Command-based switching. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_PMULT_FBSS))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_fbs_ctrl = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxFBS(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FBS is not enabled. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Problem's getting complicated now. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If FIS-based switching is used, we need to check
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * the PxFBS to see the error type.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_fbs_ctrl = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxFBS(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Refer to spec(v1.2) 9.3.6.1 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Controller has paused commands for all other
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * sub-devices until PxFBS.DEC is set.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Wait controller clear PxFBS.DEC,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * then we can continue.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Esclate the error. Follow
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * non-device specific error
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Issue a software reset to ensure drive is in
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * a known state.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Process Non-Device Specific Error. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* This will be handled later on. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!FBS is not supported now.");
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Handle events - fatal error recovery
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_events_handler enter: port %d intr_status = 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_intr_phyrdy_change() may have rendered it to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_DTYPE_NONE.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_events_handler: port %d no device attached, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "and just return without doing anything",
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_ERRPRINT) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_ERRPRINT;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: error recovery for port %d "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "succeed", instance, ahci_portp->ahciport_port_num);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_watchdog_handler() and ahci_do_sync_start will call us if they
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * detect there are some commands which are timed out.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_timeout_pkts(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxCI to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxSACT to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt * When AHCI_PORT_FLAG_RQSENSE or AHCI_PORT_FLAG_RDLOGEXT flag is
82263d52a84b4a969aa53f8ededddff841646ad9yt * set, it means a fatal error happened after REQUEST SENSE command
82263d52a84b4a969aa53f8ededddff841646ad9yt * or READ LOG EXT command is delivered to the HBA during the error
82263d52a84b4a969aa53f8ededddff841646ad9yt * recovery process. At this time, the only outstanding command is
82263d52a84b4a969aa53f8ededddff841646ad9yt * supposed to be REQUEST SENSE command or READ LOG EXT command.
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_timeout_pkts called while REQUEST SENSE "
82263d52a84b4a969aa53f8ededddff841646ad9yt "command or READ LOG EXT command for error recovery "
82263d52a84b4a969aa53f8ededddff841646ad9yt "timed out timeout_tags = 0x%x, slot_status = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_tags = 0x%x, pending_ncq_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_timeout_pkts called while executing R/W PMULT "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "command timeout_tags = 0x%x, slot_status = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt * Re-identify timeout tags because some previously checked commands
2fcbc377041d659446ded306a92901b4b0753b68yt * could already complete.
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "timeout_tags = 0x%x, port_cmd_issue = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_tags = 0x%x ",
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_timeout_pkts: port %d, finished_tags = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "timeout_tags = 0x%x, port_sactive = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_ncq_tags = 0x%x ",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0); /* reset tags */
2fcbc377041d659446ded306a92901b4b0753b68yt * Watchdog handler kicks in every 5 seconds to timeout any commands pending
2fcbc377041d659446ded306a92901b4b0753b68yt * for long time.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Skip the check for those ports in error recovery */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) &&
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp))
2fcbc377041d659446ded306a92901b4b0753b68yt * If a packet has survived for more than it's
2fcbc377041d659446ded306a92901b4b0753b68yt * max life cycles, it is a candidate for time
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[tmp_slot] -=
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (ahci_portp->ahciport_slot_timeout[tmp_slot]
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp, "watchdog: the current "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp, "watchdog: the current "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * We need to check whether the HBA has
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * begun to execute the command, if not,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * then re-set the timer of the command.
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout \
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d satapkt 0x%p timed out\n",
2fcbc377041d659446ded306a92901b4b0753b68yt /* Re-install the watchdog timeout handler */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Fill the error context into sata_cmd for non-queued command error.
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_copy_err_cnxt(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
82263d52a84b4a969aa53f8ededddff841646ad9yt * Fill the ncq error page into sata_cmd for queued command error.
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic void
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_sec_count_msb = ncq_err_page->ncq_sector_count_ext;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_sec_count_lsb = ncq_err_page->ncq_sector_count;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_low_msb = ncq_err_page->ncq_sector_number_ext;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_low_lsb = ncq_err_page->ncq_sector_number;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_mid_msb = ncq_err_page->ncq_cyl_low_ext;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_high_msb = ncq_err_page->ncq_cyl_high_ext;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Put the respective register value to sata_cmd_t for satacmd_flags.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_copy_out_regs(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_log_fatal_error_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has interface fatal "
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has bus data error",
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has bus fatal error",
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has task file error",
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d is trying to do error "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing Chinaahci_dump_commands(ahci_ctl_t *ahci_ctlp, uint8_t port,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp = ahci_ctlp->ahcictl_ports[port];
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China tmp_slot = ddi_ffs(slot_tags) - 1;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China spkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!satapkt 0x%p: cmd_reg = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "features_reg = 0x%x sec_count_msb = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "lba_low_msb = 0x%x lba_mid_msb = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "lba_high_msb = 0x%x sec_count_lsb = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "lba_low_lsb = 0x%x lba_mid_lsb = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "lba_high_lsb = 0x%x device_reg = 0x%x "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "addr_type = 0x%x cmd_flags = 0x%x", (void *)spkt,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_cmd_reg, cmd.satacmd_features_reg,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_sec_count_msb, cmd.satacmd_lba_low_msb,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_lba_mid_msb, cmd.satacmd_lba_high_msb,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_sec_count_lsb, cmd.satacmd_lba_low_lsb,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_lba_mid_lsb, cmd.satacmd_lba_high_lsb,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd.satacmd_device_reg, cmd.satacmd_addr_type,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China *((uint32_t *)&(cmd.satacmd_flags)));
2fcbc377041d659446ded306a92901b4b0753b68yt * Dump the serror message to the log.
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_log_serror_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tRecovered Data Integrity Error (I)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tRecovered Communication Error (M)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tTransient Data Integrity Error (T)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tPersistent Communication or Data Integrity Error (C)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\t10B to 8B Decode Error (B)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tLink Sequence Error (S)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tTransport state transition error (T)\n");
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg_header, NULL);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, err_msg, NULL);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (ahci_ctlp) {
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: %s %s",
f5f2d263454d943a366844932bdb677530ba733bFred Herard /* sata trace debug */
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci%d: %s %s", ddi_get_instance(ahci_ctlp->ahcictl_dip),
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci: %s %s", err_msg_header, err_msg);
f5f2d263454d943a366844932bdb677530ba733bFred Herard /* sata trace debug */
f5f2d263454d943a366844932bdb677530ba733bFred Herard sata_trace_debug(NULL, "ahci: %s %s", err_msg_header, err_msg);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Translate the sata_address_t type into the ahci_addr_t type.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * sata_device.satadev_addr structure is used as source.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_get_ahci_addr(ahci_ctl_t *ahci_ctlp, sata_device_t *sd,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_address_t *sata_addrp = &sd->satadev_addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cport_to_port[sata_addrp->cport];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* something went wrong */
2fcbc377041d659446ded306a92901b4b0753b68yt * This routine is to calculate the total number of ports implemented
2fcbc377041d659446ded306a92901b4b0753b68yt * by the HBA.
2fcbc377041d659446ded306a92901b4b0753b68ytahci_get_num_implemented_ports(uint32_t ports_implemented)
2fcbc377041d659446ded306a92901b4b0753b68yt for (i = 0; i < AHCI_MAX_PORTS; i++) {
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_log(ahci_ctl_t *ahci_ctlp, uint_t level, char *fmt, ...)
193974072f41a843678abf5f61979c748687e66bSherry Moore * quiesce(9E) entry point.
193974072f41a843678abf5f61979c748687e66bSherry Moore * This function is called when the system is single-threaded at high
193974072f41a843678abf5f61979c748687e66bSherry Moore * PIL with preemption disabled. Therefore, this function must not be
193974072f41a843678abf5f61979c748687e66bSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
193974072f41a843678abf5f61979c748687e66bSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen.
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
193974072f41a843678abf5f61979c748687e66bSherry Moore /* disable all the interrupts. */
193974072f41a843678abf5f61979c748687e66bSherry Moore for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
193974072f41a843678abf5f61979c748687e66bSherry Moore * Stop the port by clearing PxCMD.ST
193974072f41a843678abf5f61979c748687e66bSherry Moore * Here we must disable the port interrupt because
193974072f41a843678abf5f61979c748687e66bSherry Moore * ahci_disable_all_intrs only clear GHC.IE, and IS
193974072f41a843678abf5f61979c748687e66bSherry Moore * register will be still set if PxIE is enabled.
193974072f41a843678abf5f61979c748687e66bSherry Moore * When ahci shares one IRQ with other drivers, the
193974072f41a843678abf5f61979c748687e66bSherry Moore * intr handler may claim the intr mistakenly.
193974072f41a843678abf5f61979c748687e66bSherry Moore (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * The function will add a sata packet to the done queue.
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinaahci_add_doneq(ahci_port_t *ahci_portp, sata_pkt_t *satapkt, int reason)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /* set the reason for all packets */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_hba_driver_private = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (! (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * only add to queue when mode is not synch and there is
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * completion callback
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China *ahci_portp->ahciport_doneqtail = satapkt;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China (sata_pkt_t **)&(satapkt->satapkt_hba_driver_private);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China } else if ((satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ! (satapkt->satapkt_op_mode & SATA_OPMODE_POLLING))
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * for sync/non-poll mode, just call cv_broadcast
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China cv_broadcast(&ahci_portp->ahciport_cv);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * The function will call completion callback of sata packet on the
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * completed queue
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinaahci_flush_doneq(ahci_port_t *ahci_portp)
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt = ahci_portp->ahciport_doneq;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneq = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneqtail = &ahci_portp->ahciport_doneq;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneq_len = 0;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China mutex_exit(&ahci_portp->ahciport_mutex);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China next = satapkt->satapkt_hba_driver_private;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_hba_driver_private = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /* Call the callback */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China (*satapkt->satapkt_comp)(satapkt);