2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * CDDL HEADER START
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
2fcbc377041d659446ded306a92901b4b0753b68yt * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2fcbc377041d659446ded306a92901b4b0753b68yt * or http://www.opensolaris.org/os/licensing.
2fcbc377041d659446ded306a92901b4b0753b68yt * See the License for the specific language governing permissions
2fcbc377041d659446ded306a92901b4b0753b68yt * and limitations under the License.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
2fcbc377041d659446ded306a92901b4b0753b68yt * CDDL HEADER END
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI (Advanced Host Controller Interface) SATA HBA Driver
13bcbb7a73761015c9ef46cac33040380196e57fyt *
13bcbb7a73761015c9ef46cac33040380196e57fyt * Power Management Support
13bcbb7a73761015c9ef46cac33040380196e57fyt * ------------------------
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 *
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.
13bcbb7a73761015c9ef46cac33040380196e57fyt *
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#include <sys/note.h>
2fcbc377041d659446ded306a92901b4b0753b68yt#include <sys/scsi/scsi.h>
2fcbc377041d659446ded306a92901b4b0753b68yt#include <sys/pci.h>
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China#include <sys/disp.h>
2fcbc377041d659446ded306a92901b4b0753b68yt#include <sys/sata/sata_hba.h>
2fcbc377041d659446ded306a92901b4b0753b68yt#include <sys/sata/adapters/ahci/ahcireg.h>
2fcbc377041d659446ded306a92901b4b0753b68yt#include <sys/sata/adapters/ahci/ahcivar.h>
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * FMA header files
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang#include <sys/ddifm.h>
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang#include <sys/fm/protocol.h>
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang#include <sys/fm/util.h>
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang#include <sys/fm/io/ddi.h>
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
193974072f41a843678abf5f61979c748687e66bSherry Moore/*
193974072f41a843678abf5f61979c748687e66bSherry Moore * This is the string displayed by modinfo, etc.
193974072f41a843678abf5f61979c748687e66bSherry Moore */
193974072f41a843678abf5f61979c748687e66bSherry Moorestatic char ahci_ident[] = "ahci driver";
193974072f41a843678abf5f61979c748687e66bSherry Moore
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Function prototypes for driver entry points
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_attach(dev_info_t *, ddi_attach_cmd_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_detach(dev_info_t *, ddi_detach_cmd_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
193974072f41a843678abf5f61979c748687e66bSherry Moorestatic int ahci_quiesce(dev_info_t *);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Function prototypes for SATA Framework interfaces
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_register_sata_hba_tran(ahci_ctl_t *, uint32_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_unregister_sata_hba_tran(ahci_ctl_t *);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 *);
2fcbc377041d659446ded306a92901b4b0753b68yt#if defined(__lock_lint)
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_selftest(dev_info_t *, sata_device_t *);
2fcbc377041d659446ded306a92901b4b0753b68yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * FMA Prototypes
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic void ahci_fm_init(ahci_ctl_t *);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic void ahci_fm_fini(ahci_ctl_t *);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int ahci_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void*);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangint ahci_check_acc_handle(ddi_acc_handle_t);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangint ahci_check_dma_handle(ddi_dma_handle_t);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangvoid ahci_fm_ereport(ahci_ctl_t *, char *);
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);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Local function prototypes
2fcbc377041d659446ded306a92901b4b0753b68yt */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic int ahci_setup_port_base_addresses(ahci_ctl_t *, ahci_port_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_alloc_ports_state(ahci_ctl_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_dealloc_ports_state(ahci_ctl_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_alloc_port_state(ahci_ctl_t *, uint8_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 *);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_dealloc_rcvd_fis(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 *);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_initialize_controller(ahci_ctl_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_uninitialize_controller(ahci_ctl_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_initialize_port(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
13bcbb7a73761015c9ef46cac33040380196e57fytstatic int ahci_config_space_init(ahci_ctl_t *);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic void ahci_staggered_spin_up(ahci_ctl_t *, uint8_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
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 Zhang uint8_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 Zhang sata_device_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_update_pmult_gscr(ahci_ctl_t *, ahci_addr_t *,
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_pmult_gscr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_initialize_pmult(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_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 *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_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 *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *, sata_pkt_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_do_sync_start(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *, sata_pkt_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_claim_free_slot(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *, int);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_copy_err_cnxt(sata_cmd_t *, ahci_fis_d2h_register_t *);
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic void ahci_copy_ncq_err_page(sata_cmd_t *,
82263d52a84b4a969aa53f8ededddff841646ad9yt struct sata_ncq_error_recovery_page *);
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 *);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_software_reset(ahci_ctl_t *, ahci_port_t *, ahci_addr_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_hba_reset(ahci_ctl_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 Zhang ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_reset_pmdevice_reject_pkts(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int ahci_reset_port_reject_pkts(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_reset_hba_reject_pkts(ahci_ctl_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_put_port_into_notrunning_state(ahci_ctl_t *, ahci_port_t *,
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_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,
689d74b0a0dba643450e7fc74a03425c963657e7yt uint32_t, uint32_t, uint32_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 *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t, sata_pkt_t *);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_fatal_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *, uint32_t);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_pmult_error_recovery_handler(ahci_ctl_t *, ahci_port_t *,
82263d52a84b4a969aa53f8ededddff841646ad9yt uint8_t, uint32_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_timeout_pkts(ahci_ctl_t *, ahci_port_t *,
82263d52a84b4a969aa53f8ededddff841646ad9yt uint8_t, uint32_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void ahci_events_handler(void *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_watchdog_handler(ahci_ctl_t *);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic uint_t ahci_intr(caddr_t, caddr_t);
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);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_rem_intrs(ahci_ctl_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_enable_all_intrs(ahci_ctl_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_disable_all_intrs(ahci_ctl_t *);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_enable_port_intrs(ahci_ctl_t *, uint8_t);
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic void ahci_disable_port_intrs(ahci_ctl_t *, uint8_t);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 *,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *, uint8_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 *,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t, uint32_t);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int ahci_intr_fatal_error(ahci_ctl_t *, ahci_port_t *,
82263d52a84b4a969aa53f8ededddff841646ad9yt uint8_t, uint32_t);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_intr_cold_port_detect(ahci_ctl_t *, ahci_port_t *, uint8_t);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void ahci_get_ahci_addr(ahci_ctl_t *, sata_device_t *, ahci_addr_t *);
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int ahci_get_num_implemented_ports(uint32_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);
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void ahci_log(ahci_ctl_t *, uint_t, char *, ...);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the data buffer
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic ddi_dma_attr_t buffer_dma_attr = {
2fcbc377041d659446ded306a92901b4b0753b68yt DMA_ATTR_V0, /* dma_attr_version */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x0ull, /* dma_attr_addr_lo: lowest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0x3fffffull, /* dma_attr_count_max i.e. for one cookie */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x2ull, /* dma_attr_align: word aligned */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_burstsizes */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_minxfer */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_seg */
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_PRDT_NUMBER, /* dma_attr_sgllen */
2fcbc377041d659446ded306a92901b4b0753b68yt 512, /* dma_attr_granular */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the rcvd FIS
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic ddi_dma_attr_t rcvd_fis_dma_attr = {
2fcbc377041d659446ded306a92901b4b0753b68yt DMA_ATTR_V0, /* dma_attr_version */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x0ull, /* dma_attr_addr_lo: lowest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x100ull, /* dma_attr_align: 256-byte aligned */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_burstsizes */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_minxfer */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_seg */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_sgllen */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_granular */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for the command list
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic ddi_dma_attr_t cmd_list_dma_attr = {
2fcbc377041d659446ded306a92901b4b0753b68yt DMA_ATTR_V0, /* dma_attr_version */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x0ull, /* dma_attr_addr_lo: lowest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x400ull, /* dma_attr_align: 1K-byte aligned */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_burstsizes */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_minxfer */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_seg */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_sgllen */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_granular */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * DMA attributes for cmd tables
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * dma_attr_addr_hi will be changed to 0xffffffffull if the HBA
2fcbc377041d659446ded306a92901b4b0753b68yt * does not support 64-bit addressing
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic ddi_dma_attr_t cmd_table_dma_attr = {
2fcbc377041d659446ded306a92901b4b0753b68yt DMA_ATTR_V0, /* dma_attr_version */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x0ull, /* dma_attr_addr_lo: lowest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffffffffffull, /* dma_attr_addr_hi: highest bus address */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_count_max i.e. for one cookie */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0x80ull, /* dma_attr_align: 128-byte aligned */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_burstsizes */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_minxfer */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_maxxfer i.e. includes all cookies */
2fcbc377041d659446ded306a92901b4b0753b68yt 0xffffffffull, /* dma_attr_seg */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_sgllen */
2fcbc377041d659446ded306a92901b4b0753b68yt 1, /* dma_attr_granular */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* dma_attr_flags */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/* Device access attributes */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic ddi_device_acc_attr_t accattr = {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_DEVICE_ATTR_V1,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_STRUCTURE_LE_ACC,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_STRICTORDER_ACC,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_DEFAULT_ACC
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic struct dev_ops ahcictl_dev_ops = {
2fcbc377041d659446ded306a92901b4b0753b68yt DEVO_REV, /* devo_rev */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* refcnt */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_getinfo, /* info */
2fcbc377041d659446ded306a92901b4b0753b68yt nulldev, /* identify */
2fcbc377041d659446ded306a92901b4b0753b68yt nulldev, /* probe */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_attach, /* attach */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_detach, /* detach */
2fcbc377041d659446ded306a92901b4b0753b68yt nodev, /* no reset */
2fcbc377041d659446ded306a92901b4b0753b68yt (struct cb_ops *)0, /* driver operations */
2fcbc377041d659446ded306a92901b4b0753b68yt NULL, /* bus operations */
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL, /* power */
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_quiesce, /* quiesce */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic sata_tran_hotplug_ops_t ahci_tran_hotplug_ops = {
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_TRAN_HOTPLUG_OPS_REV_1,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_tran_hotplug_port_activate,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_tran_hotplug_port_deactivate
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytextern struct mod_ops mod_driverops;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic struct modldrv modldrv = {
2fcbc377041d659446ded306a92901b4b0753b68yt &mod_driverops, /* driverops */
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_ident, /* short description */
2fcbc377041d659446ded306a92901b4b0753b68yt &ahcictl_dev_ops, /* driver ops */
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytstatic struct modlinkage modlinkage = {
2fcbc377041d659446ded306a92901b4b0753b68yt MODREV_1,
2fcbc377041d659446ded306a92901b4b0753b68yt &modldrv,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL
2fcbc377041d659446ded306a92901b4b0753b68yt};
2fcbc377041d659446ded306a92901b4b0753b68yt
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/* The following variables are watchdog handler related */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic clock_t ahci_watchdog_timeout = 5; /* 5 seconds */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic clock_t ahci_watchdog_tick;
2fcbc377041d659446ded306a92901b4b0753b68yt
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/*
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
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China * indicates.
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic size_t ahci_cmd_table_size;
2fcbc377041d659446ded306a92901b4b0753b68yt
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/*
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * The below global variables are tunable via /etc/system
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China *
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
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China */
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt/* The number of Physical Region Descriptor Table(PRDT) in Command Table */
2fcbc377041d659446ded306a92901b4b0753b68ytint ahci_dma_prdt_number = AHCI_PRDT_NUMBER;
2fcbc377041d659446ded306a92901b4b0753b68yt
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China/* AHCI MSI is tunable */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing Chinaboolean_t ahci_msi_enabled = B_TRUE;
2fcbc377041d659446ded306a92901b4b0753b68yt
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China/*
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * 64-bit dma addressing for data buffer is tunable
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China *
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 China */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing Chinaboolean_t ahci_buf_64bit_dma = B_TRUE;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China/*
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * 64-bit dma addressing for communication system descriptors is tunable
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China *
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * The variable controls the below three values:
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China *
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 China */
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing Chinaboolean_t ahci_commu_64bit_dma = B_TRUE;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China/*
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 China */
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing Chinaboolean_t sb600_buf_64bit_dma_disable = B_TRUE;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China/*
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 China */
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing Chinaboolean_t sbxxx_commu_64bit_dma_disable = B_TRUE;
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China/*
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * End of global tunable variable definition
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China */
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China
1fdcc9139935dd14beb1d9e08de4a26c202d41f2Fred Herard#if AHCI_DEBUG
1fdcc9139935dd14beb1d9e08de4a26c202d41f2Fred Herarduint32_t ahci_debug_flags = 0;
1fdcc9139935dd14beb1d9e08de4a26c202d41f2Fred Herard#else
f5f2d263454d943a366844932bdb677530ba733bFred Herarduint32_t ahci_debug_flags = (AHCIDBG_ERRS|AHCIDBG_TIMEOUT);
1fdcc9139935dd14beb1d9e08de4a26c202d41f2Fred Herard#endif
1fdcc9139935dd14beb1d9e08de4a26c202d41f2Fred Herard
689d74b0a0dba643450e7fc74a03425c963657e7yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard#if AHCI_DEBUG
689d74b0a0dba643450e7fc74a03425c963657e7yt/* The following is needed for ahci_log() */
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic kmutex_t ahci_log_mutex;
689d74b0a0dba643450e7fc74a03425c963657e7ytstatic char ahci_log_buf[512];
2fcbc377041d659446ded306a92901b4b0753b68yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/* Opaque state pointer initialized by ddi_soft_state_init() */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void *ahci_statep = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci module initialization.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytint
2fcbc377041d659446ded306a92901b4b0753b68yt_init(void)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt int ret;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ret = ddi_soft_state_init(&ahci_statep, sizeof (ahci_ctl_t), 0);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_init(&ahci_log_mutex, NULL, MUTEX_DRIVER, NULL);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if ((ret = sata_hba_init(&modlinkage)) != 0) {
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_log_mutex);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_soft_state_fini(&ahci_statep);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* watchdog tick */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_watchdog_tick = drv_usectohz(
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (clock_t)ahci_watchdog_timeout * 1000000);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt ret = mod_install(&modlinkage);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_fini(&modlinkage);
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_log_mutex);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_soft_state_fini(&ahci_statep);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yterr_out:
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci: Module init failed");
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci module uninitialize.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytint
2fcbc377041d659446ded306a92901b4b0753b68yt_fini(void)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt int ret;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ret = mod_remove(&modlinkage);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Remove the resources allocated in _init(). */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_fini(&modlinkage);
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_log_mutex);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_soft_state_fini(&ahci_statep);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * _info entry point
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytint
2fcbc377041d659446ded306a92901b4b0753b68yt_info(struct modinfo *modinfop)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt return (mod_info(&modlinkage, modinfop));
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * The attach entry point for dev_ops.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2fcbc377041d659446ded306a92901b4b0753b68yt{
f5f2d263454d943a366844932bdb677530ba733bFred Herard ahci_ctl_t *ahci_ctlp = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt int instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt int status;
2fcbc377041d659446ded306a92901b4b0753b68yt int attach_state;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t cap_status, ahci_version;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t ghc_control;
2fcbc377041d659446ded306a92901b4b0753b68yt int intr_types;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int i;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt pci_regspec_t *regs;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt int regs_length;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt int rnumber;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int speed;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "ahci_attach enter",
f5f2d263454d943a366844932bdb677530ba733bFred Herard NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (cmd) {
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_ATTACH:
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_RESUME:
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
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.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_enter(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /*
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * GHC.AE must be set to 1 before any other AHCI register
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * is accessed
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control |= AHCI_HBA_GHC_AE;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Restart watch thread */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_ctlp->ahcictl_timeout_id == 0)
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_timeout_id = timeout(
13bcbb7a73761015c9ef46cac33040380196e57fyt (void (*)(void *))ahci_watchdog_handler,
13bcbb7a73761015c9ef46cac33040380196e57fyt (caddr_t)ahci_ctlp, ahci_watchdog_tick);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Re-initialize the controller and enable the interrupts and
13bcbb7a73761015c9ef46cac33040380196e57fyt * restart all the ports.
13bcbb7a73761015c9ef46cac33040380196e57fyt *
13bcbb7a73761015c9ef46cac33040380196e57fyt * Note that so far we don't support hot-plug during
13bcbb7a73761015c9ef46cac33040380196e57fyt * suspend/resume.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_initialize_controller(ahci_ctlp) != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PM, ahci_ctlp,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "Failed to initialize the controller "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "during DDI_RESUME", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt return (DDI_FAILURE);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_enter(&ahci_ctlp->ahcictl_mutex);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_ctlp->ahcictl_flags &= ~AHCI_SUSPEND;
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state = AHCI_ATTACH_STATE_NONE;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate soft state */
2fcbc377041d659446ded306a92901b4b0753b68yt status = ddi_soft_state_zalloc(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt if (status != DDI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot allocate soft state",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_flags |= AHCI_ATTACH;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_dip = dip;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Initialize the cport/port mapping */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt for (i = 0; i < AHCI_MAX_PORTS; i++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctlp->ahcictl_port_to_cport[i] = 0xff;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctlp->ahcictl_cport_to_port[i] = 0xff;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_STATEP_ALLOC;
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Initialize FMA properties */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_fm_init(ahci_ctlp);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang attach_state |= AHCI_ATTACH_STATE_FMA;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Now map the AHCI base address; which includes global
2fcbc377041d659446ded306a92901b4b0753b68yt * registers and port control registers
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt *
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 */
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt /*
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt * search through DDI "reg" property for the AHCI register set
2fcbc377041d659446ded306a92901b4b0753b68yt */
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt DDI_PROP_DONTPASS, "reg", (int **)&regs,
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt (uint_t *)&regs_length) != DDI_PROP_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot lookup reg property",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt goto err_out;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt }
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt /* AHCI Base Address is located at 0x24 offset */
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt for (rnumber = 0; rnumber < regs_length; ++rnumber) {
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt if ((regs[rnumber].pci_phys_hi & PCI_REG_REG_M)
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt == AHCI_PCI_RNUM)
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt break;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt }
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt ddi_prop_free(regs);
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt if (rnumber == regs_length) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot find AHCI register set",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt goto err_out;
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt }
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "rnumber = %d", rnumber);
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt
2fcbc377041d659446ded306a92901b4b0753b68yt status = ddi_regs_map_setup(dip,
95c11c1f0a327937bf49e1fc3b7529ca70ffb34dyt rnumber,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t *)&ahci_ctlp->ahcictl_ahci_addr,
2fcbc377041d659446ded306a92901b4b0753b68yt 0,
2fcbc377041d659446ded306a92901b4b0753b68yt 0,
2fcbc377041d659446ded306a92901b4b0753b68yt &accattr,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_ahci_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt if (status != DDI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot map register space",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_REG_MAP;
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /*
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * GHC.AE must be set to 1 before any other AHCI register
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * is accessed
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ghc_control |= AHCI_HBA_GHC_AE;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the AHCI version information */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_version = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_VS(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: hba AHCI version = %x.%x", instance,
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_version & 0xffff0000) >> 16,
2fcbc377041d659446ded306a92901b4b0753b68yt ((ahci_version & 0x0000ff00) >> 4 |
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_version & 0x000000ff)));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* We don't support controllers whose versions are lower than 1.0 */
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(ahci_version & 0xffff0000)) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "ahci%d: Don't support AHCI HBA with lower "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "than version 1.0", instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the HBA capabilities information */
2fcbc377041d659446ded306a92901b4b0753b68yt cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba capabilities = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt cap_status);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* CAP2 (HBA Capabilities Extended) is available since AHCI spec 1.2 */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_version >= 0x00010200) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t cap2_status;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Get the HBA capabilities extended information */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka cap2_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_CAP2(ahci_ctlp));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "hba capabilities extended = 0x%x", cap2_status);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Get the interface speed supported by the HBA */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt speed = (cap_status & AHCI_HBA_CAP_ISS) >> AHCI_HBA_CAP_ISS_SHIFT;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (speed == 0x01) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 1 (1.5Gbps)", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else if (speed == 0x10) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 2 (3 Gbps)", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else if (speed == 0x11) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba interface speed support: Gen 3 (6 Gbps)", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the number of command slots supported by the HBA */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_cmd_slots =
2fcbc377041d659446ded306a92901b4b0753b68yt ((cap_status & AHCI_HBA_CAP_NCS) >>
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_HBA_CAP_NCS_SHIFT) + 1;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of cmd slots: %d",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_cmd_slots);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the bit map which indicates ports implemented by the HBA */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_ports_implemented =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_PI(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba implementation of ports: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_ports_implemented);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Max port number implemented */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_ctlp->ahcictl_num_ports =
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_fls(ahci_ctlp->ahcictl_ports_implemented);
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "hba number of ports: %d",
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (cap_status & AHCI_HBA_CAP_NP) + 1);
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the number of implemented ports by the HBA */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_implemented_ports =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_get_num_implemented_ports(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_ports_implemented);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "hba number of implemented ports: %d",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_implemented_ports);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt /* Check whether HBA supports 64bit DMA addressing */
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(cap_status & AHCI_HBA_CAP_S64A)) {
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 AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba does not support 64-bit addressing", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for the support of Port Multiplier */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_SPM) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cap |= AHCI_CAP_PMULT_CBSS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hba supports port multiplier (CBSS)", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support FIS-based switching ? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_FBSS) {
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);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Checking for Support Command List Override */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_SCLO) {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang ahci_ctlp->ahcictl_cap |= AHCI_CAP_SCLO;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba supports command list override.", NULL);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for Asynchronous Notification */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_SSNTF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cap |= AHCI_CAP_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hba supports asynchronous notification.", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (pci_config_setup(dip, &ahci_ctlp->ahcictl_pci_conf_handle)
2fcbc377041d659446ded306a92901b4b0753b68yt != DDI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot set up pci configure space",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt attach_state |= AHCI_ATTACH_STATE_PCICFG_SETUP;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China /*
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.
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China *
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.
db2cce03c1de6d34b1b74513379b81575f7d7e87ying tian - Beijing China */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_config_space_init(ahci_ctlp) == AHCI_FAILURE) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: ahci_config_space_init failed",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
13bcbb7a73761015c9ef46cac33040380196e57fyt goto err_out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable the whole controller interrupts before adding
2fcbc377041d659446ded306a92901b4b0753b68yt * interrupt handlers(s).
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_disable_all_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt
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",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_supported_types() returned: 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt intr_types);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_msi_enabled && (intr_types & DDI_INTR_TYPE_MSI)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Try MSI first, but fall back to FIXED if failed
2fcbc377041d659446ded306a92901b4b0753b68yt */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_MSI) ==
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_MSI;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "Using MSI interrupt type", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt goto intr_done;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "MSI registration failed, "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "trying FIXED interrupts", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (intr_types & DDI_INTR_TYPE_FIXED) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if (ahci_add_intrs(ahci_ctlp, DDI_INTR_TYPE_FIXED) ==
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_type = DDI_INTR_TYPE_FIXED;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "Using FIXED interrupt type", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt goto intr_done;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_INTR, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "FIXED interrupt registration failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Interrupt registration failed", instance);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytintr_done:
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_INTR_ADDED;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Initialize the controller mutex */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_init(&ahci_ctlp->ahcictl_mutex, NULL, MUTEX_DRIVER,
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)(uintptr_t)ahci_ctlp->ahcictl_intr_pri);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_MUTEX_INIT;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_dma_prdt_number < AHCI_MIN_PRDT_NUMBER) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dma_prdt_number = AHCI_MIN_PRDT_NUMBER;
2fcbc377041d659446ded306a92901b4b0753b68yt } else if (ahci_dma_prdt_number > AHCI_MAX_PRDT_NUMBER) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dma_prdt_number = AHCI_MAX_PRDT_NUMBER;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size = (sizeof (ahci_cmd_table_t) +
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_dma_prdt_number - AHCI_PRDT_NUMBER) *
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (ahci_prdt_item_t));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_attach: ahci_dma_prdt_number set by user is 0x%x,"
2fcbc377041d659446ded306a92901b4b0753b68yt " ahci_cmd_table_size is 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dma_prdt_number, ahci_cmd_table_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_dma_prdt_number != AHCI_PRDT_NUMBER)
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_sgllen =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dma_prdt_number;
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_buffer_dma_attr = buffer_dma_attr;
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;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China /*
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
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China */
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 ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_addr_hi =
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China }
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China /*
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
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China */
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 ahci_ctlp->ahcictl_rcvd_fis_dma_attr.dma_attr_addr_hi =
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_cmd_list_dma_attr.dma_attr_addr_hi =
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp->ahcictl_cmd_table_dma_attr.dma_attr_addr_hi =
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt 0xffffffffull;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt }
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Allocate the ports structure */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt status = ahci_alloc_ports_state(ahci_ctlp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (status != AHCI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: Cannot allocate ports structure",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto err_out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt attach_state |= AHCI_ATTACH_STATE_PORT_ALLOC;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Initialize the controller and ports.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt status = ahci_initialize_controller(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (status != AHCI_SUCCESS) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: HBA initialization failed",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_HW_INIT;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Start one thread to check packet timeouts */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_timeout_id = timeout(
2fcbc377041d659446ded306a92901b4b0753b68yt (void (*)(void *))ahci_watchdog_handler,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t)ahci_ctlp, ahci_watchdog_tick);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt attach_state |= AHCI_ATTACH_STATE_TIMEOUT_ENABLED;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_register_sata_hba_tran(ahci_ctlp, cap_status)) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: sata hba tran registration failed",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
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",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang instance);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang goto err_out;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_flags &= ~AHCI_ATTACH;
13bcbb7a73761015c9ef46cac33040380196e57fyt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "ahci_attach success!", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yterr_out:
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);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_TIMEOUT_ENABLED) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_timeout_id = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_HW_INIT) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_uninitialize_controller(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (attach_state & AHCI_ATTACH_STATE_PORT_ALLOC) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_dealloc_ports_state(ahci_ctlp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_MUTEX_INIT) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_INTR_ADDED) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_rem_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (attach_state & AHCI_ATTACH_STATE_PCICFG_SETUP) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_REG_MAP) {
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_regs_map_free(&ahci_ctlp->ahcictl_ahci_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (attach_state & AHCI_ATTACH_STATE_FMA) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_fm_fini(ahci_ctlp);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (attach_state & AHCI_ATTACH_STATE_STATEP_ALLOC) {
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_soft_state_free(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * The detach entry point for dev_ops.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt int instance;
2fcbc377041d659446ded306a92901b4b0753b68yt int ret;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_detach enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (cmd) {
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_DETACH:
13bcbb7a73761015c9ef46cac33040380196e57fyt
2fcbc377041d659446ded306a92901b4b0753b68yt /* disable the interrupts for an uninterrupted detach */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_disable_all_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* unregister from the sata framework. */
2fcbc377041d659446ded306a92901b4b0753b68yt ret = ahci_unregister_sata_hba_tran(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != AHCI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_enable_all_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* stop the watchdog handler */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_timeout_id = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* uninitialize the controller */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_uninitialize_controller(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* remove the interrupts */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_rem_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* deallocate the ports structures */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_dealloc_ports_state(ahci_ctlp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* destroy mutex */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* teardown the pci config */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt pci_config_teardown(&ahci_ctlp->ahcictl_pci_conf_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* remove the reg maps. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_regs_map_free(&ahci_ctlp->ahcictl_ahci_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* release fma resource */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_fm_fini(ahci_ctlp);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /* free the soft state. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_soft_state_free(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_SUSPEND:
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
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 */
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_enter(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_ctlp->ahcictl_flags & AHCI_SUSPEND) {
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt return (DDI_SUCCESS);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_flags |= AHCI_SUSPEND;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /* stop the watchdog handler */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_ctlp->ahcictl_timeout_id) {
13bcbb7a73761015c9ef46cac33040380196e57fyt (void) untimeout(ahci_ctlp->ahcictl_timeout_id);
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_timeout_id = 0;
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * drain the taskq
13bcbb7a73761015c9ef46cac33040380196e57fyt */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_drain_ports_taskq(ahci_ctlp);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Disable the interrupts and stop all the ports.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_uninitialize_controller(ahci_ctlp);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * The info entry point for dev_ops.
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
2fcbc377041d659446ded306a92901b4b0753b68yt void *arg, void **result)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt#ifndef __lock_lint
2fcbc377041d659446ded306a92901b4b0753b68yt _NOTE(ARGUNUSED(dip))
2fcbc377041d659446ded306a92901b4b0753b68yt#endif /* __lock_lint */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt int instance;
2fcbc377041d659446ded306a92901b4b0753b68yt dev_t dev;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt dev = (dev_t)arg;
2fcbc377041d659446ded306a92901b4b0753b68yt instance = getminor(dev);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (infocmd) {
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_INFO_DEVT2DEVINFO:
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp != NULL) {
2fcbc377041d659446ded306a92901b4b0753b68yt *result = ahci_ctlp->ahcictl_dip;
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
2fcbc377041d659446ded306a92901b4b0753b68yt *result = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt case DDI_INFO_DEVT2INSTANCE:
2fcbc377041d659446ded306a92901b4b0753b68yt *(int *)result = instance;
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Registers the ahci with sata framework.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_register_sata_hba_tran(ahci_ctl_t *ahci_ctlp, uint32_t cap_status)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt struct sata_hba_tran *sata_hba_tran;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_register_sata_hba_tran enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate memory for the sata_hba_tran */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran = kmem_zalloc(sizeof (sata_hba_tran_t), KM_SLEEP);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 sata_hba_tran->sata_tran_hba_dma_attr =
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_buffer_dma_attr;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Report the number of implemented ports */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_hba_num_cports =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_implemented_ports;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Support ATAPI device */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_hba_tran->sata_tran_hba_features_support = SATA_CTLF_ATAPI;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Get the data transfer capability for PIO command by the HBA */
2fcbc377041d659446ded306a92901b4b0753b68yt if (cap_status & AHCI_HBA_CAP_PMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp->ahcictl_cap |= AHCI_CAP_PIO_MDRQ;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports multiple "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "DRQ block data transfer for PIO command protocol", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 *
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 *
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((cap_status & AHCI_HBA_CAP_SNCQ) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt !(ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_hba_tran->sata_tran_hba_features_support |= SATA_CTLF_NCQ;
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp->ahcictl_cap |= AHCI_CAP_NCQ;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "HBA supports Native "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "Command Queuing", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support port multiplier? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_SPM) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_tran->sata_tran_hba_features_support |=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_CTLF_PORT_MULTIPLIER;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Support FIS-based switching for port multiplier? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (cap_status & AHCI_HBA_CAP_FBSS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_tran->sata_tran_hba_features_support |=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_CTLF_PMULT_FBS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /* Report the number of command slots */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_hba_qdepth = ahci_ctlp->ahcictl_num_cmd_slots;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_probe_port = ahci_tran_probe_port;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_start = ahci_tran_start;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_abort = ahci_tran_abort;
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#ifdef __lock_lint
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_selftest = ahci_selftest;
2fcbc377041d659446ded306a92901b4b0753b68yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * When SATA framework adds support for pwrmgt the
2fcbc377041d659446ded306a92901b4b0753b68yt * pwrmgt_ops needs to be updated
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_pwrmgt_ops = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_tran->sata_tran_ioctl = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran = sata_hba_tran;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Attach it to SATA framework */
2fcbc377041d659446ded306a92901b4b0753b68yt if (sata_hba_attach(ahci_ctlp->ahcictl_dip, sata_hba_tran, DDI_ATTACH)
2fcbc377041d659446ded306a92901b4b0753b68yt != DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free((void *)sata_hba_tran, sizeof (sata_hba_tran_t));
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Unregisters the ahci with sata framework.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_unregister_sata_hba_tran(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_unregister_sata_hba_tran enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Detach from the SATA framework. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (sata_hba_detach(ahci_ctlp->ahcictl_dip, DDI_DETACH) !=
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Deallocate sata_hba_tran. */
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free((void *)ahci_ctlp->ahcictl_sata_hba_tran,
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (sata_hba_tran_t));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#define SET_PORTSTR(str, addrp) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(addrp)) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d", (addrp)->aa_port); \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else if (AHCI_ADDR_IS_PMULT(addrp)) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d (pmult)", (addrp)->aa_port); \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) sprintf((str), "%d:%d", (addrp)->aa_port, \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (addrp)->aa_pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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 */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_probe_port(dev_info_t *dip, sata_device_t *sd)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr, pmult_addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t cport = sd->satadev_addr.cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang char portstr[10];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t device_type;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int rval = SATA_SUCCESS, rval_init;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, sd, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_VALID(&addr));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORTSTR(portstr, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port enter: port %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 ahci_portp->ahciport_pmult_info == NULL)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* port mutliplier is removed. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang "pmult is removed from port %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 *
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.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (sd->satadev_addr.qual & SATA_ADDR_PMULT_SPEC) {
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&pmult_addr, port);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang /* Initialize registers on a port multiplier */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang rval_init = ahci_initialize_pmult(ahci_ctlp,
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang ahci_portp, &pmult_addr, sd);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (rval_init != AHCI_SUCCESS) {
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang AHCIDBG(AHCIDBG_PMULT, ahci_ctlp,
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang "ahci_tran_probe_port: "
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang "pmult initialization failed.", NULL);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang return (SATA_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
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 |
d1b621d50245b0085f783eded42445453fa2d670Xiao-Yu Zhang SATA_ADDR_DPMPORT)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_probe_pmport(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &addr, sd) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = SATA_FAILURE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Update port state and device type */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt switch (port_state) {
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_PSTATE_FAILED:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = SATA_PSTATE_FAILED;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT FAILED", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_PSTATE_SHUTDOWN:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = SATA_PSTATE_SHUTDOWN;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT SHUTDOWN", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_PSTATE_PWROFF:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = SATA_PSTATE_PWROFF;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT PWROFF", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_PSTATE_PWRON:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = SATA_PSTATE_PWRON;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT PWRON", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = port_state;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s PORT NORMAL %x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang portstr, port_state);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang device_type = AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (device_type) {
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_DTYPE_ATADISK:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_type = SATA_DTYPE_ATADISK;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s DISK found", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China case SATA_DTYPE_ATAPI:
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /*
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
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China * DEVICE data
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China sd->satadev_type = SATA_DTYPE_ATAPI;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s ATAPI found", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_DTYPE_PMULT:
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(AHCI_ADDR_IS_PORT(&addr) || AHCI_ADDR_IS_PMULT(&addr));
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_type = SATA_DTYPE_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Update the number of pmports. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sd->satadev_add_info = ahci_portp->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahciport_pmult_info->ahcipmi_num_dev_ports;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s Port Multiplier found",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_DTYPE_UNKNOWN:
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_type = SATA_DTYPE_UNKNOWN;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s Unknown device found",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt /* we don't support any other device types */
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_type = SATA_DTYPE_NONE;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: port %s No device found", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68ytout:
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);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (AHCI_ADDR_IS_PMPORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (port_state & SATA_STATE_READY)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_update_pmult_pscr(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &addr, sd) != AHCI_SUCCESS)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = SATA_FAILURE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
2fcbc377041d659446ded306a92901b4b0753b68yt
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)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang rval = SATA_FAILURE;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Their combined meanings as following:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH | SATA_OPMODE_INTERRUPTS
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * It is the same as the one above.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to transport a sata packet down stream.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_start(dev_info_t *dip, sata_pkt_t *spkt)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang ahci_addr_t addr;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t cport = spkt->satapkt_device.satadev_addr.cport;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang char portstr[10];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp = ddi_get_soft_state(ahci_statep, ddi_get_instance(dip));
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start enter: cport %d satapkt 0x%p",
2fcbc377041d659446ded306a92901b4b0753b68yt cport, (void *)spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &spkt->satapkt_device, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORTSTR(portstr, &addr);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Sanity check */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMPORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info == NULL) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
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_update_sata_registers(ahci_ctlp, port,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &spkt->satapkt_device);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning PORT_ERROR while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "pmult removed: port: %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_TRAN_PORT_ERROR);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(AHCIPORT_GET_STATE(ahci_portp, &addr) &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_STATE_READY)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!ddi_in_panic() ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_initialize_pmport(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, &addr) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_device.satadev_type =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_device.satadev_state =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_GET_STATE(ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_update_sata_registers(ahci_ctlp, port,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &spkt->satapkt_device);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning PORT_ERROR "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "while sub-link is not initialized "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "at port: %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_TRAN_PORT_ERROR);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_state =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port,
2fcbc377041d659446ded306a92901b4b0753b68yt &spkt->satapkt_device);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning PORT_ERROR while "
2fcbc377041d659446ded306a92901b4b0753b68yt "port in FAILED/SHUTDOWN/PWROFF state: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port: %s", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_TRAN_PORT_ERROR);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr) == SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * SATA_DTYPE_NONE.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_type = SATA_DTYPE_NONE;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_state =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port,
2fcbc377041d659446ded306a92901b4b0753b68yt &spkt->satapkt_device);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning PORT_ERROR while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "no device attached: port: %s", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_TRAN_PORT_ERROR);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* R/W PMULT command will occupy the whole HBA port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning BUSY while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "executing READ/WRITE PORT-MULT command: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port: %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_reason = SATA_PKT_BUSY;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_TRAN_BUSY);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start returning BUSY while "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "hot-plug in progress: port: %s", portstr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_reason = SATA_PKT_BUSY;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_TRAN_BUSY);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 *
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).
2fcbc377041d659446ded306a92901b4b0753b68yt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * object.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
2fcbc377041d659446ded306a92901b4b0753b68yt if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_reset_in_progress = 0;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start [CLEAR] the "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "reset_in_progress for port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_reset_in_progress &&
2fcbc377041d659446ded306a92901b4b0753b68yt ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset &&
2fcbc377041d659446ded306a92901b4b0753b68yt ! ddi_in_panic()) {
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_BUSY;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning BUSY while "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "reset in progress: port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_TRAN_BUSY);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#ifdef AHCI_DEBUG
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_start: packet 0x%p [PASSTHRU] at port %d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#endif
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_BUSY;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_start returning BUSY while "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "mopping in progress: port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_TRAN_BUSY);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (SATA_TRAN_BUSY);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (spkt->satapkt_op_mode &
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (SATA_OPMODE_SYNCH | SATA_OPMODE_POLLING)) {
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /*
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 */
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China if (!(spkt->satapkt_op_mode & SATA_OPMODE_POLLING) &&
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China servicing_interrupt()) {
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China spkt->satapkt_reason = SATA_PKT_BUSY;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China "ahci_tran_start returning BUSY while "
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China "sending SYNC mode under interrupt context: "
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China "port : %d", port);
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China mutex_exit(&ahci_portp->ahciport_mutex);
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China return (SATA_TRAN_BUSY);
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China }
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* We need to do the sync start now */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt spkt) == AHCI_FAILURE) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang goto fail_out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Async start, using interrupt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_deliver_satapkt(ahci_ctlp, ahci_portp, &addr, spkt)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt == AHCI_FAILURE) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt spkt->satapkt_reason = SATA_PKT_QUEUE_FULL;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang goto fail_out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_tran_start "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "sata tran accepted: port %s", portstr);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_TRAN_ACCEPTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangfail_out:
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Failed to deliver packet to the controller.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check if it's caused by invalid handles.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
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 spkt->satapkt_device.satadev_type =
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang spkt->satapkt_device.satadev_state =
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIPORT_GET_STATE(ahci_portp, &addr);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang spkt->satapkt_reason = SATA_PKT_DEV_ERROR;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (SATA_TRAN_PORT_ERROR);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_tran_start "
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang "return QUEUE_FULL: port %d", port);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (SATA_TRAN_QUEUE_FULL);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_OPMODE_SYNCH flag is set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If SATA_OPMODE_POLLING flag is set, then we must poll the command
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * without interrupt, otherwise we can still use the interrupt.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_do_sync_start(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp, sata_pkt_t *spkt)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int pkt_timeout_ticks;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t timeout_tags;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int rval;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (spkt->satapkt_op_mode & SATA_OPMODE_POLLING) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_POLLING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp, spkt)) == AHCI_FAILURE) {
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (rval);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt pkt_timeout_ticks =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt drv_usectohz((clock_t)spkt->satapkt_time * 1000000);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt while (spkt->satapkt_reason == SATA_PKT_BUSY) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Simulate the interrupt */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_port_intr(ahci_ctlp, ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang pkt_timeout_ticks -= AHCI_10MS_TICKS;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (pkt_timeout_ticks < 0) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: ahci_do_sync_start "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port %d satapkt 0x%p timed out\n",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port, (void *)spkt);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt timeout_tags = (0x1 << rval);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_timeout_pkts(ahci_ctlp, ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt port, timeout_tags);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_POLLING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_SUCCESS);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if ((rval = ahci_deliver_satapkt(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp, spkt)) == AHCI_FAILURE)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (rval);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt#if AHCI_DEBUG
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Note that the driver always uses the slot 0 to deliver
82263d52a84b4a969aa53f8ededddff841646ad9yt * REQUEST SENSE or READ LOG EXT command
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(rval == 0);
82263d52a84b4a969aa53f8ededddff841646ad9yt#endif
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt while (spkt->satapkt_reason == SATA_PKT_BUSY)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cv_wait(&ahci_portp->ahciport_cv,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt &ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_SUCCESS);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Searches for and claims a free command slot.
82263d52a84b4a969aa53f8ededddff841646ad9yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Returns value:
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 * 9.1.2)
82263d52a84b4a969aa53f8ededddff841646ad9yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * claimed slot number returned if succeeded
82263d52a84b4a969aa53f8ededddff841646ad9yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: it will always return slot 0 for following commands to simplify the
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * algorithm.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. REQUEST SENSE or READ LOG EXT command during error recovery process
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. READ/WRITE PORTMULT command
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_claim_free_slot(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp, int command_type)
2fcbc377041d659446ded306a92901b4b0753b68yt{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_cmd_issue;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t free_slots;
2fcbc377041d659446ded306a92901b4b0753b68yt int slot;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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 ahci_portp->ahciport_pending_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (command_type == AHCI_NON_NCQ_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Non-NCQ command request */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
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 "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "command", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt return (AHCI_FAILURE);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
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",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((ahci_ctlp->ahcictl_cap & AHCI_CAP_NO_MCMDLIST_NONQUEUE) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: HBA cannot support multiple-"
f5f2d263454d943a366844932bdb677530ba733bFred Herard "use of the command list for non-queued commands",
f5f2d263454d943a366844932bdb677530ba733bFred Herard NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt return (AHCI_FAILURE);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt free_slots = (~ahci_portp->ahciport_pending_tags) &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_SLOT_MASK(ahci_ctlp);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else if (command_type == AHCI_NCQ_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* NCQ command request */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO|AHCIDBG_NCQ, ahci_ctlp,
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",
f5f2d263454d943a366844932bdb677530ba733bFred Herard NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt return (AHCI_FAILURE);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NCQ commands cannot be sent to different port multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ports in Command-Based Switching mode
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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 NCQ_CMD_IN_PROGRESS(ahci_portp) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_NCQ_PMPORT(ahci_portp) !=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp->aa_pmport) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
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 "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port, so no available slot.", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt free_slots = (~ahci_portp->ahciport_pending_ncq_tags) &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else if (command_type == AHCI_ERR_RETRI_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Error retrieval command request */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_claim_free_slot: slot 0 is allocated for REQUEST "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "SENSE or READ LOG EXT command", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt slot = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (command_type == AHCI_RDWR_PMULT_CMD) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (port_cmd_issue != 0) {
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 NON_NCQ_CMD_IN_PROGRESS(ahci_portp),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NCQ_CMD_IN_PROGRESS(ahci_portp),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_issue);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_claim_free_slot: slot 0 is allocated for "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "READ/WRITE PORTMULT command", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt slot = ddi_ffs(free_slots) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (slot == -1) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_claim_free_slot: no empty slots", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (command_type == AHCI_NCQ_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags |= (0x1 << slot);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMPORT(addrp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_NCQ_PMPORT(ahci_portp) = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_pending_tags |= (0x1 << slot);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9ytout:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_VERBOSE, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_claim_free_slot: found slot: 0x%x", slot);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (slot);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Builds the Command Table for the sata packet and delivers it to controller.
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * Returns:
2fcbc377041d659446ded306a92901b4b0753b68yt * slot number if we can obtain a slot successfully
2fcbc377041d659446ded306a92901b4b0753b68yt * otherwise, return AHCI_FAILURE
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_deliver_satapkt(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp, sata_pkt_t *spkt)
2fcbc377041d659446ded306a92901b4b0753b68yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int cmd_slot;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_cmd_t *scmd;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_fis_h2d_register_t *h2d_register_fisp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_t *cmd_table;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_header_t *cmd_header;
2fcbc377041d659446ded306a92901b4b0753b68yt int ncookies;
2fcbc377041d659446ded306a92901b4b0753b68yt int i;
82263d52a84b4a969aa53f8ededddff841646ad9yt int command_type = AHCI_NON_NCQ_CMD;
82263d52a84b4a969aa53f8ededddff841646ad9yt int ncq_qdepth;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port, pmport;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t *ptr;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t *ptr2;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang pmport = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_BUSY;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd = &spkt->satapkt_cmd;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if the command is a NCQ command */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (scmd->satacmd_cmd_reg == SATAC_READ_FPDMA_QUEUED ||
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_cmd_reg == SATAC_WRITE_FPDMA_QUEUED) {
82263d52a84b4a969aa53f8ededddff841646ad9yt command_type = AHCI_NCQ_CMD;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 *
82263d52a84b4a969aa53f8ededddff841646ad9yt * Sata module is going to calculate the qdepth and send
82263d52a84b4a969aa53f8ededddff841646ad9yt * down to HBA driver via sata_cmd.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_qdepth = scmd->satacmd_flags.sata_max_queue_depth + 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ahci_portp->ahciport_max_ncq_tags == 0) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_max_ncq_tags = ncq_qdepth;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_deliver_satapkt: port %d the max tags for "
82263d52a84b4a969aa53f8ededddff841646ad9yt "NCQ command is %d", port, ncq_qdepth);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_qdepth != ahci_portp->ahciport_max_ncq_tags) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: ahci_deliver_satapkt"
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",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_max_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_qdepth);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if the command is an error retrieval command */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt command_type = AHCI_ERR_RETRI_CMD;
82263d52a84b4a969aa53f8ededddff841646ad9yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check if the command is an read/write pmult command */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang command_type = AHCI_RDWR_PMULT_CMD;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check if there is an empty command slot */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmd_slot = ahci_claim_free_slot(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp, command_type);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (cmd_slot == AHCI_FAILURE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "no free command slot", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INFO, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_deliver_satapkt enter: cmd_reg: 0x%x, cmd_slot: 0x%x, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port: %d, satapkt: 0x%p", scmd->satacmd_cmd_reg,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cmd_slot, port, (void *)spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cmd_table = ahci_portp->ahciport_cmd_tables[cmd_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)cmd_table, ahci_cmd_table_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* For data transfer operations, it is the H2D Register FIS */
2fcbc377041d659446ded306a92901b4b0753b68yt h2d_register_fisp =
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMULT(addrp) || AHCI_ADDR_IS_PMPORT(addrp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_FIS_PMP(h2d_register_fisp, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_CDMDEVCTL(h2d_register_fisp, 1);
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);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt switch (scmd->satacmd_addr_type) {
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt case 0:
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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
82263d52a84b4a969aa53f8ededddff841646ad9yt */
689d74b0a0dba643450e7fc74a03425c963657e7yt /* FALLTHRU */
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt case ATA_ADDR_LBA:
689d74b0a0dba643450e7fc74a03425c963657e7yt /* FALLTHRU */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case ATA_ADDR_LBA28:
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[7:0] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[15:8] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[23:16] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [27:24] (also called dev_head) */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_DEV_HEAD(h2d_register_fisp, scmd->satacmd_device_reg);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case ATA_ADDR_LBA48:
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[7:0] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_SECTOR(h2d_register_fisp, scmd->satacmd_lba_low_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[15:8] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_LOW(h2d_register_fisp, scmd->satacmd_lba_mid_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA[23:16] */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_FIS_CYL_HI(h2d_register_fisp, scmd->satacmd_lba_high_lsb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [31:24] */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_SECTOR_EXP(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_low_msb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [39:32] */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_CYL_LOW_EXP(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_mid_msb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* LBA [47:40] */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_CYL_HI_EXP(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_high_msb);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set dev_head */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_DEV_HEAD(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_device_reg);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set the extended sector count and features */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_SECTOR_COUNT_EXP(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_sec_count_msb);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_FEATURES_EXP(h2d_register_fisp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_features_reg_ext);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 * done so.
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China *
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China * However the driver needs to make sure TAG is filled into sector
754bb1a01e5c207dcdde918d31a30d971f690f1bying tian - Beijing China * field.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (command_type == AHCI_NCQ_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt SET_FIS_SECTOR_COUNT(h2d_register_fisp,
82263d52a84b4a969aa53f8ededddff841646ad9yt (cmd_slot << SATA_TAG_QUEUING_SHIFT));
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ncookies = scmd->satacmd_num_dma_cookies;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PRDT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ncookies = 0x%x, ahci_dma_prdt_number = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt ncookies, ahci_dma_prdt_number);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(ncookies <= ahci_dma_prdt_number);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[cmd_slot] = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* *** now fill the scatter gather list ******* */
2fcbc377041d659446ded306a92901b4b0753b68yt for (i = 0; i < ncookies; i++) {
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table->ahcict_prdt[i].ahcipi_data_base_addr =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_dma_cookie_list[i]._dmu._dmac_la[0];
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table->ahcict_prdt[i].ahcipi_data_base_addr_upper =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_dma_cookie_list[i]._dmu._dmac_la[1];
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table->ahcict_prdt[i].ahcipi_descr_info =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_dma_cookie_list[i].dmac_size - 1;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[cmd_slot] +=
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China scmd->satacmd_dma_cookie_list[i].dmac_size;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PRDT, ahci_ctlp,
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);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* The ACMD field is filled in for ATAPI command */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (scmd->satacmd_cmd_reg == SATAC_PACKET) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt bcopy(scmd->satacmd_acdb, cmd_table->ahcict_atapi_cmd,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SATA_ATAPI_MAX_CDB_LEN);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cmd_header = &ahci_portp->ahciport_cmd_list[cmd_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_DESCR_INFO(cmd_header);
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_PRD_BYTE_COUNT(cmd_header);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set the number of entries in the PRD table */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_PRD_TABLE_LENGTH(cmd_header, ncookies);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set the length of the command in the CFIS area */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_FIS_LENGTH(cmd_header, AHCI_H2D_REGISTER_FIS_LENGTH);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMULT(addrp) || AHCI_ADDR_IS_PMPORT(addrp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORT_MULTI_PORT(cmd_header, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "command data direction is "
2fcbc377041d659446ded306a92901b4b0753b68yt "sata_data_direction = 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_flags.sata_data_direction);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set A bit if it is an ATAPI command */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (scmd->satacmd_cmd_reg == SATAC_PACKET)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt SET_ATAPI(cmd_header, AHCI_CMDHEAD_ATAPI);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Set W bit if data is going to the device */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (scmd->satacmd_flags.sata_data_direction == SATA_DIR_WRITE)
2fcbc377041d659446ded306a92901b4b0753b68yt SET_WRITE(cmd_header, AHCI_CMDHEAD_DATA_WRITE);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (command_type != AHCI_NCQ_CMD)
82263d52a84b4a969aa53f8ededddff841646ad9yt SET_PREFETCHABLE(cmd_header, AHCI_CMDHEAD_PREFETCHABLE);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang !RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_slot_pkts[cmd_slot] = spkt;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * Keep the timeout value
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[cmd_slot] = spkt->satapkt_time;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /*
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
2fcbc377041d659446ded306a92901b4b0753b68yt */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (ahci_portp->ahciport_slot_timeout[cmd_slot] <=
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_watchdog_timeout)
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[cmd_slot] +=
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_watchdog_timeout;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
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
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 scmd->satacmd_cmd_reg, port);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr = (uint32_t *)cmd_header;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_log(ahci_ctlp, CE_WARN,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Command Header:%8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr[0], ptr[1], ptr[2], ptr[3]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /* Dump the H2D register FIS */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr = (uint32_t *)h2d_register_fisp;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_log(ahci_ctlp, CE_WARN,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Command FIS: %8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr[0], ptr[1], ptr[2], ptr[3]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
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 ahci_log(ahci_ctlp, CE_WARN,
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], ptr2[8 * i + 1],
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr2[8 * i + 2], ptr2[8 * i + 3],
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr2[8 * i + 4], ptr2[8 * i + 5],
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ptr2[8 * i + 6], ptr2[8 * i + 7]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
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]);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_log(ahci_ctlp, CE_WARN,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China " Cookie %d: %8x %8x %8x %8x",
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China i, ptr[0], ptr[1], ptr[2], ptr[3]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ddi_dma_sync(
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_cmd_tables_dma_handle[cmd_slot],
2fcbc377041d659446ded306a92901b4b0753b68yt 0,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cmd_slot * sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_dma_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_dma_handle[cmd_slot]) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_check_dma_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_list_dma_handle) != DDI_FM_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (AHCI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Set the corresponding bit in the PxSACT.DS for queued command */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (command_type == AHCI_NCQ_CMD) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port),
82263d52a84b4a969aa53f8ededddff841646ad9yt (0x1 << cmd_slot));
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (0x1 << cmd_slot));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_deliver_satapkt "
2fcbc377041d659446ded306a92901b4b0753b68yt "exit: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Make sure the command is started by the PxSACT/PxCI */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahcictl_ahci_acc_handle) != DDI_FM_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (AHCI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (cmd_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by the sata framework to abort the previously sent packet(s).
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * Reset device to abort commands.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_abort(dev_info_t *dip, sata_pkt_t *spkt, int flag)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t aborted_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t cport = spkt->satapkt_device.satadev_addr.cport;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
2fcbc377041d659446ded306a92901b4b0753b68yt int tmp_slot;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_tran_abort enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort: port %d is in "
2fcbc377041d659446ded306a92901b4b0753b68yt "mopping process, so just return directly ", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_RDWR_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_abort: port %d is reading/writing "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port multiplier, so just return directly ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state & SATA_PSTATE_SHUTDOWN |
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state & SATA_PSTATE_PWROFF) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_state =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port,
2fcbc377041d659446ded306a92901b4b0753b68yt &spkt->satapkt_device);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort returning SATA_FAILURE while "
2fcbc377041d659446ded306a92901b4b0753b68yt "port in FAILED/SHUTDOWN/PWROFF state: "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI_PORT_TYPE_NODEV.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_type = SATA_DTYPE_NONE;
2fcbc377041d659446ded306a92901b4b0753b68yt spkt->satapkt_device.satadev_state =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port,
2fcbc377041d659446ded306a92901b4b0753b68yt &spkt->satapkt_device);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_abort returning SATA_FAILURE while "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "no device attached: port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (flag == SATA_ABORT_ALL_PACKETS) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt aborted_tags = ahci_portp->ahciport_pending_tags;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt aborted_tags = ahci_portp->ahciport_pending_ncq_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: ahci port %d abort all packets",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
2fcbc377041d659446ded306a92901b4b0753b68yt aborted_tags = 0xffffffff;
2fcbc377041d659446ded306a92901b4b0753b68yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Aborting one specific packet, first search the
2fcbc377041d659446ded306a92901b4b0753b68yt * ahciport_slot_pkts[] list for matching spkt.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt for (tmp_slot = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot < ahci_ctlp->ahcictl_num_cmd_slots; tmp_slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_slot_pkts[tmp_slot] == spkt) {
2fcbc377041d659446ded306a92901b4b0753b68yt aborted_tags = (0x1 << tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (aborted_tags == 0xffffffff) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* request packet is not on the pending list */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Cannot find the aborting pkt 0x%p on the "
2fcbc377041d659446ded306a92901b4b0753b68yt "pending list", (void *)spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port,
2fcbc377041d659446ded306a92901b4b0753b68yt &spkt->satapkt_device);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_NOTE, "!ahci%d: ahci port %d abort satapkt 0x%p",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port, (void *)spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ahci_restart_port_wait_till_ready(ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp, port, NULL, NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Compute which have finished and which need to be retried.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt aborted_tags &= ~finished_tags;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt slot_status,
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt aborted_tags,
2fcbc377041d659446ded306a92901b4b0753b68yt 0); /* reset tags */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, &spkt->satapkt_device);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do device reset and reject all the pending packets on a device
2fcbc377041d659446ded306a92901b4b0753b68yt * during the reset operation.
2fcbc377041d659446ded306a92901b4b0753b68yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: ONLY called by ahci_tran_reset_dport
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_reset_device_reject_pkts(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t reset_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_device_t sdevice;
2fcbc377041d659446ded306a92901b4b0753b68yt int ret;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_device_reject_pkts on port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_device_reject_pkts: port %d is in "
2fcbc377041d659446ded306a92901b4b0753b68yt "mopping process, so return directly ", port);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp, addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Try to do a port reset after software "
2fcbc377041d659446ded306a92901b4b0753b68yt "reset failed", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_port_reset(ahci_ctlp, ahci_portp, addrp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ret != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_device_reject_pkts: port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt "failed", port);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set the reset in progress flag */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_reset_in_progress = 1;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the framework that a reset has happened */
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)&sdevice, sizeof (sata_device_t));
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.pmport = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_state = SATA_DSTATE_RESET |
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_DSTATE_PWR_ACTIVE;
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_DEVICE_RESET);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Next try to mop the pending commands */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags &= ~finished_tags;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt slot_status,
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags); /* reset tags */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: ONLY called by ahci_tran_reset_dport
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_reset_pmdevice_reject_pkts(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t finished_tags = 0, reset_tags = 0, slot_status = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t sdevice;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reset_pmdevice_reject_pkts: port %d is in "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "mopping process, so return directly ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for outstanding commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
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 }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Issue SOFTWARE reset command. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp, addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Try to do a port reset after software "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "reset failed", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Set the reset in progress flag */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_reset_in_progress = 1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_mop_in_progress++;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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.pmport = pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMULT(addrp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_DPMPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_state = SATA_DSTATE_RESET |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_DSTATE_PWR_ACTIVE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_DEVICE_RESET);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d sending event up: SATA_EVNT_DEVICE_RESET",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Next try to mop the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
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 reset_tags &= ~finished_tags;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 reset_tags, finished_tags, slot_status);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_mop_commands(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* timeout tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags); /* reset tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (SATA_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do port reset and reject all the pending packets on a port during
2fcbc377041d659446ded306a92901b4b0753b68yt * the reset operation.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_reset_port_reject_pkts(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t reset_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reset_port_reject_pkts at port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_port_reject_pkts: port %d is in "
2fcbc377041d659446ded306a92901b4b0753b68yt "mopping process, so return directly ", port);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_restart_port_wait_till_ready(ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp, port, AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NULL) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear mop flag */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_mop_in_progress--;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_mop_in_progress == 0)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~AHCI_PORT_FLAG_MOPPING;
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags &= ~finished_tags;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt slot_status,
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags); /* reset tags */
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Used to do hba reset and reject all the pending packets on all ports
2fcbc377041d659446ded306a92901b4b0753b68yt * during the reset operation.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_reset_hba_reject_pkts(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t slot_status[AHCI_MAX_PORTS];
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t reset_tags[AHCI_MAX_PORTS];
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t finished_tags[AHCI_MAX_PORTS];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int port;
2fcbc377041d659446ded306a92901b4b0753b68yt int ret = SATA_SUCCESS;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_reset_hba_reject_pkts enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero(slot_status, sizeof (slot_status));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero(reset_tags, sizeof (reset_tags));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero(finished_tags, sizeof (finished_tags));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_reset_in_progress = 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status[port] = ddi_get32(
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags[port] = slot_status[port] &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: reset_tags = 0x%x pending_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, reset_tags[port],
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pending_tags);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status[port] = ddi_get32(
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt reset_tags[port] = slot_status[port] &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_NCQ_SLOT_MASK(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: reset_tags = 0x%x pending_tags = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, reset_tags[port],
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pending_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_hba_reset(ahci_ctlp) != AHCI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt ret = SATA_FAILURE;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * To prevent recursive enter to ahci_mop_commands, we need
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * check AHCI_PORT_FLAG_MOPPING flag.
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_reset_hba_reject_pkts: port %d is in "
2fcbc377041d659446ded306a92901b4b0753b68yt "mopping process, so return directly ", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags[port] =
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status[port] & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags[port] =
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status[port] & AHCI_NCQ_SLOT_MASK(ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags[port] &= ~finished_tags[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt slot_status[port],
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt reset_tags[port]); /* reset tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68ytout:
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Called by sata framework to reset a port(s) or device.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_reset_dport(dev_info_t *dip, sata_device_t *sd)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t cport = sd->satadev_addr.cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = sd->satadev_addr.pmport;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
2fcbc377041d659446ded306a92901b4b0753b68yt int ret = SATA_SUCCESS;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp = ahci_ctlp->ahcictl_ports[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, sd, &addr);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_reset_dport enter: cport %d", cport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (sd->satadev_addr.qual) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_PMPORT:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 *
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FALLTHRU */
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_ADDR_CPORT:
2fcbc377041d659446ded306a92901b4b0753b68yt /* Port reset */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d reset port", instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_port_reject_pkts(ahci_ctlp, ahci_portp, &addr);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_DPMPORT:
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 case SATA_ADDR_DCPORT:
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 "port %d reset device", instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (sd->satadev_addr.qual == SATA_ADDR_DCPORT &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type == SATA_DTYPE_PMULT)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&addr, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED |
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state & SATA_PSTATE_SHUTDOWN |
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state & SATA_PSTATE_PWROFF) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_state = ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, sd);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_reset_dport returning SATA_FAILURE "
2fcbc377041d659446ded306a92901b4b0753b68yt "while port in FAILED/SHUTDOWN/PWROFF state: "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ret = SATA_FAILURE;
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr) ==
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * ahci_intr_phyrdy_change() may have rendered it to
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI_PORT_TYPE_NODEV.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_type = SATA_DTYPE_NONE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sd->satadev_state = AHCIPORT_GET_STATE(ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &addr);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, sd);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_tran_reset_dport returning SATA_FAILURE "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "while no device attached: port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ret = SATA_FAILURE;
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_device_reject_pkts(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = ahci_reset_pmdevice_reject_pkts(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case SATA_ADDR_CNTRL:
2fcbc377041d659446ded306a92901b4b0753b68yt /* Reset the whole controller */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci_tran_reset_dport "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "reset the whole hba", instance);
2fcbc377041d659446ded306a92901b4b0753b68yt ret = ahci_reset_hba_reject_pkts(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
2fcbc377041d659446ded306a92901b4b0753b68yt ret = SATA_FAILURE;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (ret);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_hotplug_port_activate(dev_info_t *dip, sata_device_t *satadev)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t cport = satadev->satadev_addr.cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = satadev->satadev_addr.pmport;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_hotplug_port_activate enter: cport %d", cport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
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));
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d is activated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Enable the interrupts on the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_enable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 * too.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_restart_port_wait_till_ready(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, port,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_PORT_RESET|AHCI_RESET_NO_EVENTS_UP,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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 } else if (AHCI_ADDR_IS_PMPORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d:%d is activated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang instance, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* AHCI_ADDR_PMPORT */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_PMSTATE(ahci_portp, &addr) |= SATA_PSTATE_PWRON;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_PMSTATE(ahci_portp, &addr) &=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~(SATA_PSTATE_PWROFF|SATA_PSTATE_SHUTDOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt satadev->satadev_state = ahci_portp->ahciport_port_state;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, satadev);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_tran_hotplug_port_deactivate(dev_info_t *dip, sata_device_t *satadev)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t cport = satadev->satadev_addr.cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = satadev->satadev_addr.pmport;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_scontrol;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
2fcbc377041d659446ded306a92901b4b0753b68yt port = ahci_ctlp->ahcictl_cport_to_port[cport];
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_hotplug_port_deactivate enter: cport %d", cport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
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));
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d is deactivated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang instance, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Disable the interrupts on the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_disable_port_intrs(ahci_ctlp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* First to abort all the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Then stop the port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
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 } else if (AHCI_ADDR_IS_PMPORT(&addr)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "!ahci%d: ahci port %d:%d is deactivated",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang instance, port, pmport);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_disable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &addr)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang != SATA_DTYPE_NONE)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Re-enable the interrupts for the other pmports */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_enable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_update_sata_registers(ahci_ctlp, port, satadev);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_reject_all_abort_pkts(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t abort_tags = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_reject_all_abort_pkts at port: %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Read/write port multiplier command takes highest priority */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = 0x1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang abort_tags = 0x1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = 0x1;
82263d52a84b4a969aa53f8ededddff841646ad9yt abort_tags = 0x1;
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt } else {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_reject_all_abort_pkts return directly "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port %d no needs to reject any outstanding "
82263d52a84b4a969aa53f8ededddff841646ad9yt "commands", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt return;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt abort_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt abort_tags = slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9ytout:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* No need to do mop when there is no outstanding commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (slot_status != 0) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_mop_commands(ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt slot_status,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0, /* failed tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0, /* timeout tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt abort_tags, /* aborting tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt 0); /* reset tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if defined(__lock_lint)
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_selftest(dev_info_t *dip, sata_device_t *device)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
2fcbc377041d659446ded306a92901b4b0753b68yt return (SATA_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Initialize fma capabilities and register with IO fault services.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic void
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_init(ahci_ctl_t *ahci_ctlp)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Need to change iblock to priority for new MSI intr
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_iblock_cookie_t fm_ibc;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_ctlp->ahcictl_fm_cap = ddi_getprop(DDI_DEV_T_ANY,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_ctlp->ahcictl_dip,
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
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Only register with IO Fault Services if we have some capability */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_ctlp->ahcictl_fm_cap) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Adjust access and dma attributes for FMA */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang accattr.devacc_attr_access = DDI_FLAGERR_ACC;
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
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
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 */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_init(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang &ahci_ctlp->ahcictl_fm_cap, &fm_ibc);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_ctlp->ahcictl_fm_cap == DDI_FM_NOT_CAPABLE) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang cmn_err(CE_WARN, "!ahci%d: fma init failed.",
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_get_instance(ahci_ctlp->ahcictl_dip));
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Initialize pci ereport capabilities if ereport
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * capable (should always be.)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
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 pci_ereport_setup(ahci_ctlp->ahcictl_dip);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Register error callback if error callback capable.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
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 ahci_fm_error_cb, (void *) ahci_ctlp);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang "ahci_fm_fini: fma enabled.", NULL);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Releases fma capabilities and un-registers with IO fault services.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic void
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_fini(ahci_ctl_t *ahci_ctlp)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Only unregister FMA capabilities if registered */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_ctlp->ahcictl_fm_cap) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Un-register error callback if error callback capable.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
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 }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Release any resources allocated by pci_ereport_setup()
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
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 pci_ereport_teardown(ahci_ctlp->ahcictl_dip);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Unregister from IO Fault Services */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_fini(ahci_ctlp->ahcictl_dip);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /* Adjust access and dma attributes for FMA */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang accattr.devacc_attr_access = DDI_DEFAULT_ACC;
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 Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang "ahci_fm_fini: fma disabled.", NULL);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*ARGSUSED*/
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
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 */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang pci_ereport_post(dip, err, NULL);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (err->fme_status);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangint
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_acc_handle(ddi_acc_handle_t handle)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_error_t de;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (de.fme_status);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangint
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_dma_handle(ddi_dma_handle_t handle)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_error_t de;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (de.fme_status);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Generate an ereport
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangvoid
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_fm_ereport(ahci_ctl_t *ahci_ctlp, char *detail)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang uint64_t ena;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang char buf[FM_MAX_CLASS];
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ena = fm_ena_generate(0, FM_ENA_FMT1);
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,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang FM_EREPORT_VERSION, NULL);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * Check if all handles are correctly allocated.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_all_handle(ahci_ctl_t *ahci_ctlp)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang int port;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_port_t *ahci_portp;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port))
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang continue;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp = ahci_ctlp->ahcictl_ports[port];
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka mutex_enter(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_port_handle(ahci_ctlp, port) != DDI_SUCCESS) {
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_SUCCESS);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
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 */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_ctl_handle(ahci_ctl_t *ahci_ctlp)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_acc_handle(ahci_ctlp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahcictl_pci_conf_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_acc_handle(ahci_ctlp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahcictl_ahci_acc_handle) != DDI_FM_OK)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_SUCCESS);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the DMA handles and the access handles of a controller port.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_port_handle(ahci_ctl_t *ahci_ctlp, int port)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahci_port_t *ahci_portp = ahci_ctlp->ahcictl_ports[port];
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang int slot;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_dma_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_rcvd_fis_dma_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_dma_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_list_dma_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_acc_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_rcvd_fis_acc_handle) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_acc_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_list_acc_handle) != DDI_FM_OK)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_slot_handle(ahci_portp, slot)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_SUCCESS);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang/*
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang * Check the DMA handles and the access handles of a cmd table slot.
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangstatic int
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhangahci_check_slot_handle(ahci_port_t *ahci_portp, int slot)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if ((ahci_check_acc_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_acc_handle[slot]) != DDI_FM_OK) ||
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang (ahci_check_dma_handle(ahci_portp->
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ahciport_cmd_tables_dma_handle[slot]) != DDI_FM_OK)) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_SUCCESS);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang}
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Allocate the ports structure, only called by ahci_attach
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_alloc_ports_state(ahci_ctl_t *ahci_ctlp)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
f68cbde19e3ef99e6398b35f324dd995baa82758yt int port, cport = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_alloc_ports_state enter", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Allocate structures only for the implemented ports */
f68cbde19e3ef99e6398b35f324dd995baa82758yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "hba port %d not implemented", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt continue;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctlp->ahcictl_cport_to_port[cport] = (uint8_t)port;
f68cbde19e3ef99e6398b35f324dd995baa82758yt ahci_ctlp->ahcictl_port_to_cport[port] =
f68cbde19e3ef99e6398b35f324dd995baa82758yt (uint8_t)cport++;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_alloc_port_state(ahci_ctlp, port) != AHCI_SUCCESS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto err_out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_SUCCESS);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yterr_out:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt for (port--; port >= 0; port--) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_dealloc_port_state(ahci_ctlp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_FAILURE);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Reverse of ahci_alloc_ports_state(), only called by ahci_detach
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_dealloc_ports_state(ahci_ctl_t *ahci_ctlp)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int port;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* if this port is implemented by the HBA */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (AHCI_PORT_IMPLEMENTED(ahci_ctlp, port))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_dealloc_port_state(ahci_ctlp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China/*
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China * Drain the taskq.
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing Chinastatic void
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing Chinaahci_drain_ports_taskq(ahci_ctl_t *ahci_ctlp)
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China{
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_port_t *ahci_portp;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China int port;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
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 continue;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China }
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ahci_portp = ahci_ctlp->ahcictl_ports[port];
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
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);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China }
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China}
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Initialize the controller and all ports. And then try to start the ports
13bcbb7a73761015c9ef46cac33040380196e57fyt * if there are devices attached.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_initialize_controller(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int port;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_initialize_controller enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka /* Disable the whole controller interrupts */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka mutex_enter(&ahci_ctlp->ahcictl_mutex);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_disable_all_intrs(ahci_ctlp);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka mutex_exit(&ahci_ctlp->ahcictl_mutex);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt /* Initialize the implemented ports and structures */
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Ensure that the controller is not in the running state
2fcbc377041d659446ded306a92901b4b0753b68yt * by checking every implemented port's PxCMD register
2fcbc377041d659446ded306a92901b4b0753b68yt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT(&addr, (uint8_t)port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_initialize_port(ahci_ctlp, ahci_portp, &addr)
2fcbc377041d659446ded306a92901b4b0753b68yt != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_initialize_controller: failed to "
2fcbc377041d659446ded306a92901b4b0753b68yt "initialize port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Set the port state to SATA_PSTATE_FAILED if
2fcbc377041d659446ded306a92901b4b0753b68yt * failed to initialize it.
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Enable the whole controller interrupts */
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_enable_all_intrs(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Reverse of ahci_initialize_controller()
2fcbc377041d659446ded306a92901b4b0753b68yt *
13bcbb7a73761015c9ef46cac33040380196e57fyt * We only need to stop the ports and disable the interrupt.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_uninitialize_controller(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_port_t *ahci_portp;
13bcbb7a73761015c9ef46cac33040380196e57fyt int port;
13bcbb7a73761015c9ef46cac33040380196e57fyt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_uninitialize_controller enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* disable all the interrupts. */
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_disable_all_intrs(ahci_ctlp);
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_ctlp->ahcictl_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
13bcbb7a73761015c9ef46cac33040380196e57fyt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
13bcbb7a73761015c9ef46cac33040380196e57fyt continue;
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp = ahci_ctlp->ahcictl_ports[port];
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Stop the port by clearing PxCMD.ST */
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_enter(&ahci_portp->ahciport_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
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.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_disable_port_intrs(ahci_ctlp, port);
13bcbb7a73761015c9ef46cac33040380196e57fyt (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp, port);
13bcbb7a73761015c9ef46cac33040380196e57fyt mutex_exit(&ahci_portp->ahciport_mutex);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Must stop port before the function is called.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_alloc_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_cmd_status;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = ahci_portp->ahciport_port_num;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* The port must have been stopped before. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(!(port_cmd_status & AHCI_CMD_STATUS_ST));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_cmd_status & AHCI_CMD_STATUS_PMA)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* set PMA bit */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_cmd_status|AHCI_CMD_STATUS_PMA);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_alloc_pmult: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "PxCMD.PMA bit set at port %d.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Must stop port before the function is called.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_dealloc_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_cmd_status;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = ahci_portp->ahciport_port_num;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (port_cmd_status & AHCI_CMD_STATUS_PMA) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear PMA bit */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (port_cmd_status & (~AHCI_CMD_STATUS_PMA)));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_dealloc_pmult: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "PxCMD.PMA bit cleared at port %d.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Release port multiplier information structure */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_pmult_info != NULL) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang kmem_free(ahci_portp->ahciport_pmult_info,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sizeof (ahci_pmult_info_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info = NULL;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka/*
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Staggered Spin-up.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic void
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_staggered_spin_up(ahci_ctl_t *ahci_ctlp, uint8_t port)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka{
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t cap_status;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t port_cmd_status;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Check for staggered spin-up support */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (!(cap_status & AHCI_HBA_CAP_SSS))
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* If PxCMD.SUD == 1, no staggered spin-up is needed */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (port_cmd_status & AHCI_CMD_STATUS_SUD)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "Spin-up at port %d", port);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Set PxCMD.SUD */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status |= AHCI_CMD_STATUS_SUD;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka}
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Called by
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. ahci_initialize_controller
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. ahci_intr_phyrdy_change (hotplug)
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang uint32_t port_sstatus, port_task_file, port_cmd_status;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers boolean_t resuming = B_TRUE; /* processing DDI_RESUME */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang int ret;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* AHCI_ADDR_PORT: We've no idea of the attached device here. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PORT(addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /*
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 */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers resuming = B_FALSE;
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers } else {
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /* check for DDI_RESUME case */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers mutex_exit(&ahci_portp->ahciport_mutex);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers mutex_enter(&ahci_ctlp->ahcictl_mutex);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers if (ahci_ctlp->ahcictl_flags & AHCI_ATTACH)
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers resuming = B_FALSE;
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers mutex_exit(&ahci_ctlp->ahcictl_mutex);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers mutex_enter(&ahci_portp->ahciport_mutex);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers }
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers if (resuming) {
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /*
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 */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers AHCIDBG(AHCIDBG_PM, ahci_ctlp,
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers "ahci_initialize_port: port %d "
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers "set PxCLB, PxCLBU, PxFB and PxFBU "
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers "during resume", port);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_setup_port_base_addresses(ahci_ctlp, ahci_portp) !=
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCI_SUCCESS)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return (AHCI_FAILURE);
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers }
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_port: port %d ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Check whether the port is in NotRunning state, if not,
2fcbc377041d659446ded306a92901b4b0753b68yt * put the port in NotRunning state
2fcbc377041d659446ded306a92901b4b0753b68yt */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (port_cmd_status &
2fcbc377041d659446ded306a92901b4b0753b68yt (AHCI_CMD_STATUS_ST |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_CMD_STATUS_CR |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_CMD_STATUS_FRE |
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang AHCI_CMD_STATUS_FR)) {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang ahci_portp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Make sure the drive is spun-up */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_staggered_spin_up(ahci_ctlp, port);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Disable interrupt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_disable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Device is unknown at first */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
2fcbc377041d659446ded306a92901b4b0753b68yt
e2d9bfa60df7cf2c53826b45daa99c8a7324780dying tian - Beijing China /* Disable the interface power management */
e2d9bfa60df7cf2c53826b45daa99c8a7324780dying tian - Beijing China ahci_disable_interface_pm(ahci_ctlp, port);
e2d9bfa60df7cf2c53826b45daa99c8a7324780dying tian - Beijing China
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
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
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Check interface status */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_task_file & AHCI_TFD_STS_BSY ||
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China port_task_file & AHCI_TFD_STS_DRQ ||
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China /* Check whether port reset must be executed */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers ahci_ctlp->ahcictl_cap & AHCI_CAP_INIT_PORT_RESET ||
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers /* Always reset port on RESUME */
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers resuming != B_FALSE) {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
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
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Does port reset succeed on HBA port? */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ret != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_initialize_port:"
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "port reset failed at port %d", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (AHCI_FAILURE);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Is port failed? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_STATE(ahci_portp, addrp) &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_PSTATE_FAILED) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_initialize_port: port %d state 0x%x",
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port, ahci_portp->ahciport_port_state);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (AHCI_FAILURE);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
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);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers * Try to get the device signature if the port is not empty.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (!resuming && AHCIPORT_DEV_TYPE(ahci_portp, addrp) !=
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka SATA_DTYPE_NONE)
8f4d31eaa428c695c80cba9eebfa5b63bffb1078Dana Myers ahci_find_dev_signature(ahci_ctlp, ahci_portp, addrp);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Return directly if no device connected */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (AHCIPORT_DEV_TYPE(ahci_portp, addrp) == SATA_DTYPE_NONE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "No device connected to port %d", port);
13bcbb7a73761015c9ef46cac33040380196e57fyt goto out;
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
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,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Port multiplier found at port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_alloc_pmult(ahci_ctlp, ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Try to start the port */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (ahci_start_port(ahci_ctlp, ahci_portp, port)
13bcbb7a73761015c9ef46cac33040380196e57fyt != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "failed to start port %d", port);
13bcbb7a73761015c9ef46cac33040380196e57fyt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytout:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Enable port interrupts */
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_enable_port_intrs(ahci_ctlp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
13bcbb7a73761015c9ef46cac33040380196e57fyt/*
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * Handle hardware defect, and check the capabilities. For example,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China * power management capabilty and MSI capability.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fytstatic int
13bcbb7a73761015c9ef46cac33040380196e57fytahci_config_space_init(ahci_ctl_t *ahci_ctlp)
13bcbb7a73761015c9ef46cac33040380196e57fyt{
689d74b0a0dba643450e7fc74a03425c963657e7yt ushort_t caps_ptr, cap_count, cap;
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
689d74b0a0dba643450e7fc74a03425c963657e7yt ushort_t pmcap, pmcsr;
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ushort_t msimc;
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
13bcbb7a73761015c9ef46cac33040380196e57fyt uint8_t revision;
13bcbb7a73761015c9ef46cac33040380196e57fyt
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_venid =
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt PCI_CONF_VENID);
13bcbb7a73761015c9ef46cac33040380196e57fyt
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China ahci_ctlp->ahcictl_devid =
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt PCI_CONF_DEVID);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
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 *
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 *
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.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
17ac46ba2202ffe2a65f9d29f49c544fd3f7d31dying tian - Beijing China if (ahci_ctlp->ahcictl_venid == VIA_VENID) {
13bcbb7a73761015c9ef46cac33040380196e57fyt revision = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt PCI_CONF_REVID);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "revision id = 0x%x", revision);
13bcbb7a73761015c9ef46cac33040380196e57fyt if (revision == 0x00) {
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_buffer_dma_attr.dma_attr_align = 0x4;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "change ddi_attr_align to 0x4", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_NO_MCMDLIST_NONQUEUE;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "VT8251 cannot use multiple command lists for "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "non-queued commands", NULL);
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China
e0ab0eca1a1f461b67482b50176e92440d1a08b4ying tian - Beijing China ahci_ctlp->ahcictl_cap |= AHCI_CAP_SRST_NO_HOSTPORT;
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt /*
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 *
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 * need to set.
7fb8b96e0c933d6bb796be011b28ac70a8c4dac2ying tian - Beijing China *
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.
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China */
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;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
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 AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB600 need to do a port reset during initialization",
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China NULL);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
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);
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China }
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China /*
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 *
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 *
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 *
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.
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt */
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;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "ATI SB700/750 cannot do 64-bit DMA for communication "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "memory descriptors though CAP indicates support, "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "so force it to use 32-bit DMA", NULL);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China "ATI SB710 need to do a port reset during initialization",
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China NULL);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
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);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt }
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Check if capabilities list is supported and if so,
13bcbb7a73761015c9ef46cac33040380196e57fyt * get initial capabilities pointer and clear bits 0,1.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (pci_config_get16(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt PCI_CONF_STAT) & PCI_STAT_CAP) {
13bcbb7a73761015c9ef46cac33040380196e57fyt caps_ptr = P2ALIGN(pci_config_get8(
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt PCI_CONF_CAP_PTR), 4);
13bcbb7a73761015c9ef46cac33040380196e57fyt } else {
13bcbb7a73761015c9ef46cac33040380196e57fyt caps_ptr = PCI_CAP_NEXT_PTR_NULL;
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Walk capabilities if supported.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt for (cap_count = 0; caps_ptr != PCI_CAP_NEXT_PTR_NULL; ) {
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Check that we haven't exceeded the maximum number of
13bcbb7a73761015c9ef46cac33040380196e57fyt * capabilities and that the pointer is in a valid range.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt if (++cap_count > PCI_CAP_MAX_PTR) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "too many device capabilities", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt return (AHCI_FAILURE);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt if (caps_ptr < PCI_CAP_PTR_OFF) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "capabilities pointer 0x%x out of range",
13bcbb7a73761015c9ef46cac33040380196e57fyt caps_ptr);
13bcbb7a73761015c9ef46cac33040380196e57fyt return (AHCI_FAILURE);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /*
13bcbb7a73761015c9ef46cac33040380196e57fyt * Get next capability and check that it is valid.
13bcbb7a73761015c9ef46cac33040380196e57fyt * For now, we only support power management.
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fyt cap = pci_config_get8(ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt caps_ptr);
13bcbb7a73761015c9ef46cac33040380196e57fyt switch (cap) {
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_PM:
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /* power management supported */
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_cap |= AHCI_CAP_PM;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt /* Save PMCSR offset */
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_pmcsr_offset = caps_ptr + PCI_PMCSR;
13bcbb7a73761015c9ef46cac33040380196e57fyt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
13bcbb7a73761015c9ef46cac33040380196e57fyt pmcap = pci_config_get16(
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt caps_ptr + PCI_PMCAP);
13bcbb7a73761015c9ef46cac33040380196e57fyt pmcsr = pci_config_get16(
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_pci_conf_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_ctlp->ahcictl_pmcsr_offset);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "Power Management capability found PCI_PMCAP "
13bcbb7a73761015c9ef46cac33040380196e57fyt "= 0x%x PCI_PMCSR = 0x%x", pmcap, pmcsr);
13bcbb7a73761015c9ef46cac33040380196e57fyt if ((pmcap & 0x3) == 0x3)
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
13bcbb7a73761015c9ef46cac33040380196e57fyt "PCI Power Management Interface "
f5f2d263454d943a366844932bdb677530ba733bFred Herard "spec 1.2 compliant", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt#endif
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_MSI:
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China#if AHCI_DEBUG
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China msimc = pci_config_get16(
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_pci_conf_handle,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China caps_ptr + PCI_MSI_CTRL);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_MSI, ahci_ctlp,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "Message Signaled Interrupt capability found "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "MSICAP_MC.MMC = 0x%x", (msimc & 0xe) >> 1);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China#endif
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_MSI, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "MSI capability found", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_PCIX:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "PCI-X capability found", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_PCI_E:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "PCI Express capability found", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_MSI_X:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "MSI-X capability found", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt case PCI_CAP_ID_SATA:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "SATA capability found", NULL);
13bcbb7a73761015c9ef46cac33040380196e57fyt break;
13bcbb7a73761015c9ef46cac33040380196e57fyt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt case PCI_CAP_ID_VS:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PM, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "Vendor Specific capability found", NULL);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt break;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang default:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_PM, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "unrecognized capability 0x%x", cap);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Get next capabilities pointer and clear bits 0,1.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang caps_ptr = P2ALIGN(pci_config_get8(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_pci_conf_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (caps_ptr + PCI_CAP_NEXT_PTR)), 4);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_rdwr_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t regn, uint32_t *pregv, uint8_t type)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t pmult_addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_pkt_t *spkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_cmd_t *scmd;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t sata_device;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t intr_mask;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int rval;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang char portstr[10];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORTSTR(portstr, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cport = ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp = ahci_ctlp->ahcictl_ports[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
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 return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Request a READ/WRITE PORTMULT sata packet. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero(&sata_device, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device.satadev_addr.cport = cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device.satadev_addr.pmport = pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device.satadev_addr.qual = SATA_ADDR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device.satadev_rev = SATA_DEVICE_REV;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Make sure no command is outstanding here. All R/W PMULT requests
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * come from
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. ahci_attach()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The port should be empty.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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 *
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 *
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 * later.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
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 port, ahci_portp->ahciport_flags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) && (
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NCQ_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang NON_NCQ_CMD_IN_PROGRESS(ahci_portp))) {
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 port, ahci_portp->ahciport_flags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * The issued command should be aborted and the following command
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * should not be continued.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
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 "port-mult is removed from port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RDWR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt = sata_get_rdwr_pmult_pkt(ahci_ctlp->ahcictl_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sata_device, regn, *pregv, type);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&pmult_addr, addrp->aa_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_rdwr_pmult_pkt = spkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), 0);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = ahci_do_sync_start(ahci_ctlp, ahci_portp, &pmult_addr, spkt);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rval == AHCI_SUCCESS &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt->satapkt_reason == SATA_PKT_COMPLETED) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (type == SATA_RDWR_PMULT_PKT_TYPE_READ) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang scmd = &spkt->satapkt_cmd;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *pregv = scmd->satacmd_lba_high_lsb << 24 |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang scmd->satacmd_lba_mid_lsb << 16 |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang scmd->satacmd_lba_low_lsb << 8 |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang scmd->satacmd_sec_count_lsb;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
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 rval = AHCI_FAILURE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangout:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Restore the interrupt mask */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), intr_mask);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RDWR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_rdwr_pmult_pkt = NULL;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_free_rdwr_pmult_pkt(spkt);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_read_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t regn, uint32_t *pregv)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return ahci_rdwr_pmult(ahci_ctlp, addrp, regn, pregv,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_RDWR_PMULT_PKT_TYPE_READ);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_write_pmult(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t regn, uint32_t regv)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return ahci_rdwr_pmult(ahci_ctlp, addrp, regn, &regv,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_RDWR_PMULT_PKT_TYPE_WRITE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#define READ_PMULT(addrp, r, pv, out) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_read_pmult(ahci_ctlp, addrp, r, pv) != AHCI_SUCCESS) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#define WRITE_PMULT(addrp, r, v, out) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_write_pmult(ahci_ctlp, addrp, r, v) != AHCI_SUCCESS) \
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_update_pmult_gscr(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_pmult_gscr_t *sg)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka &ahci_ctlp->ahcictl_ports[addrp->aa_port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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 Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangerr: /* R/W PMULT error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_update_pmult_pscr(ahci_ctl_t *ahci_ctlp, ahci_addr_t *addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t *sd)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PMPORT(addrp));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka &ahci_ctlp->ahcictl_ports[addrp->aa_port]->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangerr: /* R/W PMULT error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_initialize_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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 Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp, sata_device_t *sd)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_pmult_gscr_t sg;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t gscr64;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "[Initialize] Port-multiplier at port %d.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Enable features of port multiplier. Currently only
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Asynchronous Notification is enabled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check gscr64 for supported features. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_GSCR64, &gscr64, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (gscr64 & SATA_PMULT_CAP_SNOTIF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: Port Multiplier supports "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Asynchronous Notification.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Write to gscr96 to enabled features */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(addrp, SATA_PMULT_GSCR96,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_PMULT_CAP_SNOTIF, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_SNOTIF_CLEAR_ALL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d: PMult PxSNTF cleared.", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Fetch the number of device ports of the port multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang if (ahci_update_pmult_gscr(ahci_ctlp, addrp, &sg) != AHCI_SUCCESS)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang /* Register the port multiplier to SATA Framework. */
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang sata_register_pmult(ahci_ctlp->ahcictl_dip, sd, &sg);
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
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
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 return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangerr: /* R/W PMULT error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: This function should only be called in ahci_probe_pmport()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_initialize_pmport(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t finished_tags = 0, reset_tags = 0, slot_status = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int ret = AHCI_FAILURE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PMPORT(addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check HBA port state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_port_state & SATA_PSTATE_FAILED) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport:"
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d Port Multiplier is failed.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_HOTPLUG) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_HOTPLUG;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Checking for outstanding commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags = slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
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 }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_mop_in_progress++;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear status */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_STATE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Firstly assume an unknown device */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_disable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 AHCIDBG(AHCIDBG_INIT|AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport:"
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port reset failed at port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is port failed? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_STATE(ahci_portp, addrp) &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_PSTATE_FAILED) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: port %d:%d failed. "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "state = 0x%x", port, pmport,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is there any device attached? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang == SATA_DTYPE_NONE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Do not waste time on an empty port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_initialize_pmport: No device is found "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "at port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = AHCI_SUCCESS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_STATE_READY);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d is ready now.", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 * device.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_find_dev_signature(ahci_ctlp, ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ret = AHCI_SUCCESS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangout:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Next try to mop the pending commands */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = ahci_portp->ahciport_pending_tags &
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else if (NCQ_CMD_IN_PROGRESS(ahci_portp))
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 reset_tags &= ~finished_tags;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_mop_commands(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang slot_status,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* timeout tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang reset_tags); /* reset tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear PxSNTF register if supported. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_ctlp->ahcictl_cap & AHCI_CAP_SNTF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_SNOTIF_CLEAR_ALL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_HOTPLUG;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_enable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (ret);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ahci_probe_pmult()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Only called from ahci_tran_probe_port()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_probe_pmult(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t sdevice;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t pmport_addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t gscr32, port_hotplug_tags;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t pmport_sstatus;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int dev_exists_now = 0, dev_existed_previously = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int npmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang do {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang npmport = ddi_ffs(port_hotplug_tags) - 1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (npmport == -1)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* no pending hot plug events. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMPORT(&pmport_addr, port, (uint8_t)npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check previous device at that port */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCIPORT_GET_DEV_TYPE(ahci_portp, &pmport_addr)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang != SATA_DTYPE_NONE)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang dev_existed_previously = 1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* PxSStatus tells the presence of device. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(&pmport_addr, SATA_PMULT_REG_SSTS,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &pmport_sstatus, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (SSTATUS_GET_DET(pmport_sstatus) ==
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SSTATUS_DET_DEVPRE_PHYCOM)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang dev_exists_now = 1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 * pmport.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang WRITE_PMULT(&pmport_addr, SATA_PMULT_REG_SERR,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_SERROR_CLEAR_ALL, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.cport = ahci_ctlp->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_PMPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = (uint8_t)npmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_state = SATA_PSTATE_PWRON;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "[Existence] %d -> %d", dev_existed_previously,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang dev_exists_now);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_exists_now) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_existed_previously) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Link (may) not change: Exist -> Exist * */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d:%d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "device link lost/established",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_LINK_LOST|
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_LINK_ESTABLISHED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
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 "device link established", port, npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear port state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, &pmport_addr,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_STATE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_probe_pmult: port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahciport_port_state [Cleared].", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_LINK_ESTABLISHED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else { /* No device exists now */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_existed_previously) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 "device link lost", port, npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* An existing device is lost. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, &pmport_addr,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_STATE_UNKNOWN);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, &pmport_addr,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_DTYPE_NONE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_LINK_LOST);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang CLEAR_BIT(port_hotplug_tags, npmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (port_hotplug_tags != 0);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangerr: /* R/W PMULT error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Probe and initialize a port multiplier port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * A port multiplier port could only be initilaizer here.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_probe_pmport(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp, sata_device_t *sd)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_state;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr_pmult;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Check the parent - port multiplier first.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Parent port multiplier might have been removed. This event will be
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * ignored and failure.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* The port is ready? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = ahci_portp->ahciport_port_state;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_state & SATA_STATE_READY)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "parent port-mult is NOT ready.", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_restart_port_wait_till_ready(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, port, AHCI_PORT_RESET, NULL) !=
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS|AHCIDBG_PMULT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_tran_probe_port: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "restart port-mult failed.", NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
13bcbb7a73761015c9ef46cac33040380196e57fyt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * If port-mult is restarted due to some reason, we need
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * re-initialized the PMult.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_state & SATA_DSTATE_PMULT_INIT)) {
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 &addr_pmult, sd) != AHCI_SUCCESS)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Then we check the port-mult port
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Is this pmport initialized? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_state = AHCIPORT_GET_STATE(ahci_portp, addrp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_state & SATA_STATE_READY)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* ahci_initialize_pmport() will set READY state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_initialize_pmport(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, addrp) != AHCI_SUCCESS)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
13bcbb7a73761015c9ef46cac33040380196e57fyt }
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt return (AHCI_SUCCESS);
13bcbb7a73761015c9ef46cac33040380196e57fyt}
13bcbb7a73761015c9ef46cac33040380196e57fyt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_software_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_fis_h2d_register_t *h2d_register_fisp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_t *cmd_table;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_header_t *cmd_header;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_status, port_cmd_issue, port_task_file;
2fcbc377041d659446ded306a92901b4b0753b68yt int slot, loop_count;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang int rval = AHCI_FAILURE;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d device software resetting (FIS)", port, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 port) != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_software_reset: cannot stop HBA port %d.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Check PxTFD.STS.BSY and PxTFD.STS.DRQ */
2fcbc377041d659446ded306a92901b4b0753b68yt port_task_file = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (port_task_file & AHCI_TFD_STS_BSY ||
2fcbc377041d659446ded306a92901b4b0753b68yt port_task_file & AHCI_TFD_STS_DRQ) {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (!(ahci_ctlp->ahcictl_cap & AHCI_CAP_SCLO)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
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 goto out;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /*
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.
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "PxTFD.STS.BSY/DRQ is set, try SCLO.", NULL)
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
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 ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_cmd_status|AHCI_CMD_STATUS_CLO);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Waiting till PxCMD.SCLO bit is cleared */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang loop_count = 0;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang do {
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Wait for 10 millisec */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* We are effectively timing out after 1 sec. */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (loop_count++ > 100) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "SCLO time out. port %d is busy.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_cmd_status =
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
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
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 if (port_task_file & AHCI_TFD_STS_BSY ||
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_task_file & AHCI_TFD_STS_DRQ) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "SCLO cannot clear PxTFD.STS.BSY/DRQ (PxTFD=0x%x)",
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang port_task_file);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Then start port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_start_port(ahci_ctlp, ahci_portp, port)
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang != AHCI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_software_reset: cannot start AHCI port %d.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /*
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().
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang slot = 0;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* Now send the first H2D Register FIS with SRST set to 1 */
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table = ahci_portp->ahciport_cmd_tables[slot];
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)cmd_table, ahci_cmd_table_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt h2d_register_fisp =
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_FIS_PMP(h2d_register_fisp, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_DEVCTL(h2d_register_fisp, SATA_DEVCTL_SRST);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_header = &ahci_portp->ahciport_cmd_list[slot];
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_DESCR_INFO(cmd_header);
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_PRD_BYTE_COUNT(cmd_header);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_FIS_LENGTH(cmd_header, 5);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORT_MULTI_PORT(cmd_header, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_CLEAR_BUSY_UPON_R_OK(cmd_header, 1);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_RESET(cmd_header, 1);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_WRITE(cmd_header, 1);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt 0,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt slot * sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
2fcbc377041d659446ded306a92901b4b0753b68yt (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop till the first command is finished */
2fcbc377041d659446ded306a92901b4b0753b68yt do {
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* We are effectively timing out after 1 sec. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "the first SRST FIS is timed out, "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "loop_count = %d", loop_count);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_software_reset: 1st loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_issue = 0x%x, slot = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count, port_cmd_issue, slot);
2fcbc377041d659446ded306a92901b4b0753b68yt
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang /* According to ATA spec, we need wait at least 5 microsecs here. */
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang drv_usecwait(AHCI_1MS_USECS);
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* Now send the second H2D Register FIS with SRST cleard to zero */
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table = ahci_portp->ahciport_cmd_tables[slot];
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)cmd_table, ahci_cmd_table_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt h2d_register_fisp =
2fcbc377041d659446ded306a92901b4b0753b68yt &(cmd_table->ahcict_command_fis.ahcifc_fis.ahcifc_h2d_register);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_FIS_TYPE(h2d_register_fisp, AHCI_H2D_REGISTER_FIS_TYPE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_FIS_PMP(h2d_register_fisp, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Set Command Header in Command List */
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_header = &ahci_portp->ahciport_cmd_list[slot];
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_DESCR_INFO(cmd_header);
2fcbc377041d659446ded306a92901b4b0753b68yt BZERO_PRD_BYTE_COUNT(cmd_header);
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_FIS_LENGTH(cmd_header, 5);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SET_PORT_MULTI_PORT(cmd_header, pmport);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt SET_WRITE(cmd_header, 1);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt 0,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_sync(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt slot * sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (ahci_cmd_header_t),
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SYNC_FORDEV);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Indicate to the HBA that a command is active. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port),
2fcbc377041d659446ded306a92901b4b0753b68yt (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop till the second command is finished */
2fcbc377041d659446ded306a92901b4b0753b68yt do {
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
b2e3645a19d26829ca421c8959ecfb419a0ef972ying tian - Beijing China /* We are effectively timing out after 1 sec. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (loop_count++ > AHCI_POLLRATE_PORT_SOFTRESET) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "the second SRST FIS is timed out, "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "loop_count = %d", loop_count);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China } while (port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp) & (0x1 << slot));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_software_reset: 2nd loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_issue = 0x%x, slot = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count, port_cmd_issue, slot);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang goto out;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang rval = AHCI_SUCCESS;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhangout:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_software_reset: %s at port %d:%d",
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang rval == AHCI_SUCCESS ? "succeed" : "failed",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (rval);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI port reset ...; the physical communication between the HBA and device
2fcbc377041d659446ded306a92901b4b0753b68yt * on a port are disabled. This is more intrusive.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_port_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t pmult_addr;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t port_cmd_status;
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka uint32_t port_scontrol, port_sstatus;
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka uint32_t port_task_file;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_state;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt int loop_count;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Target is a port multiplier port? */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMPORT(addrp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (ahci_pmport_reset(ahci_ctlp, ahci_portp, addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Otherwise it must be an HBA port. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PORT(addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Port %d port resetting...", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_port_state = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /*
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 */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (!(port_cmd_status & AHCI_CMD_STATUS_SUD))
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka "ahci_port_reset: port %d SUD bit not set", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
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);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_scontrol);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Enable PxCMD.FRE to read device */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status|AHCI_CMD_STATUS_FRE);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /*
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.
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka *
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 */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka drv_usecwait(AHCI_1MS_USECS * 2);
2fcbc377041d659446ded306a92901b4b0753b68yt
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);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_scontrol);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * The DET field is valid only if IPM field indicates
2fcbc377041d659446ded306a92901b4b0753b68yt * that the interface is in active state.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count = 0;
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka for (;;) {
2fcbc377041d659446ded306a92901b4b0753b68yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * If the interface is not active, the DET field
2fcbc377041d659446ded306a92901b4b0753b68yt * is considered not accurate. So we want to
2fcbc377041d659446ded306a92901b4b0753b68yt * continue looping.
2fcbc377041d659446ded306a92901b4b0753b68yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt SSTATUS_SET_DET(port_sstatus, SSTATUS_DET_NODEV);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM)
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka break;
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt if (loop_count++ > AHCI_POLLRATE_PORT_SSTATUS) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * We are effectively timing out after 0.1 sec.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka }
2fcbc377041d659446ded306a92901b4b0753b68yt
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",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt loop_count, port_sstatus, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Either the port is not active or there
2fcbc377041d659446ded306a92901b4b0753b68yt * is no device present.
2fcbc377041d659446ded306a92901b4b0753b68yt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_NONE);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka /* Clear port serror register for the port */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka AHCI_SERROR_CLEAR_ALL);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt loop_count = 0;
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka for (;;) {
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka port_task_file =
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka if ((port_task_file & (AHCI_TFD_STS_BSY | AHCI_TFD_STS_DRQ |
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka AHCI_TFD_STS_ERR)) == 0)
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka break;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (loop_count++ > AHCI_POLLRATE_PORT_TFD_ERROR) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * We are effectively timing out after 11 sec.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
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",
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang instance, port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
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 "software reset.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Clear port serror register for the port */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang AHCI_SERROR_CLEAR_ALL);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&pmult_addr, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Try another software reset. */
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_software_reset(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &pmult_addr) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_PSTATE_FAILED);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (AHCI_FAILURE);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt break;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
257c04ecb24858f6d68020a41589306f554ea434Marcel Telka }
2fcbc377041d659446ded306a92901b4b0753b68yt
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 loop_count, port_task_file, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear port serror register for the port */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_SERROR_CLEAR_ALL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
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);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp,
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "ahci_port_reset: succeed at port %d.", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * COMRESET on a port multiplier port.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: Only called in ahci_port_reset()
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_pmport_reset(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_scontrol, port_sstatus, port_serror;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_cmd_status, port_intr_status;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_state;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int loop_count;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d:%d: pmport resetting", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize pmport state */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, 0);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
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 if (!(port_cmd_status & AHCI_CMD_STATUS_FRE))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_1MS_USECS*2);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 *
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang loop_count = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang do {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang READ_PMULT(addrp, SATA_PMULT_REG_SSTS, &port_sstatus, err);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (SSTATUS_GET_IPM(port_sstatus) != SSTATUS_IPM_ACTIVE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SSTATUS_SET_DET(port_sstatus, SSTATUS_DET_NODEV);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (loop_count++ > AHCI_POLLRATE_PORT_SSTATUS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * We are effectively timing out after 0.1 sec.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (SSTATUS_GET_DET(port_sstatus) != SSTATUS_DET_DEVPRE_PHYCOM);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: 1st loop count: %d, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port_sstatus = 0x%x port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang loop_count, port_sstatus, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Either the port is not active or there
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * is no device present.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "no device attached to port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_NONE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_serror & (1 << 26))) {
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 instance, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_STATE(ahci_portp, addrp, SATA_PSTATE_FAILED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Now we need to check the D2H FIS by checking IPMS error. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang loop_count = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang do {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (loop_count++ > AHCI_POLLRATE_PORT_TFD_ERROR) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * No D2H FIS received. This is possible according
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * to SATA 2.6 spec.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
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 "software reset.", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang delay(AHCI_10MS_TICKS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (!(port_intr_status & AHCI_INTR_STATUS_IPMS));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: 2st loop count: %d, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port_sstatus = 0x%x port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang loop_count, port_sstatus, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Clear IPMS */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_INTR_STATUS_IPMS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_IGNORE_IPMS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: succeed at port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangerr: /* R/W PMULT error */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* IPMS flags might be set before. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_IGNORE_IPMS;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO|AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_pmport_reset: failed at port %d:%d", port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_FAILURE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * AHCI HBA reset ...; the entire HBA is reset, and all ports are disabled.
2fcbc377041d659446ded306a92901b4b0753b68yt * This is the most intrusive.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
2fcbc377041d659446ded306a92901b4b0753b68yt * Remember to set GHC.AE to 1 before calling ahci_hba_reset.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_hba_reset(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t ghc_control;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
2fcbc377041d659446ded306a92901b4b0753b68yt int loop_count;
2fcbc377041d659446ded306a92901b4b0753b68yt int rval = AHCI_SUCCESS;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp, "HBA resetting",
f5f2d263454d943a366844932bdb677530ba733bFred Herard NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Setting GHC.HR to 1, remember GHC.AE is already set to 1 before */
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control |= AHCI_HBA_GHC_HR;
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Wait until HBA Reset complete or timeout
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt do {
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (loop_count++ > AHCI_POLLRATE_HBA_RESET) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci hba reset is timing out, "
2fcbc377041d659446ded306a92901b4b0753b68yt "ghc_control = 0x%x", ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt /* We are effectively timing out after 1 sec. */
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
2fcbc377041d659446ded306a92901b4b0753b68yt } while (ghc_control & AHCI_HBA_GHC_HR);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_POLL_LOOP, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_hba_reset: 1st loop count: %d, "
2fcbc377041d659446ded306a92901b4b0753b68yt "ghc_control = 0x%x", loop_count, ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ghc_control & AHCI_HBA_GHC_HR) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* The hba is not reset for some reasons */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "hba reset failed: HBA in a hung or locked state", NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * HBA reset will clear (AHCI Spec v1.2 10.4.3) GHC.IE / GHC.AE
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ghc_control |= (AHCI_HBA_GHC_AE | AHCI_HBA_GHC_IE);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_ctlp->ahcictl_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Only check implemented ports */
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Make sure the drive is spun-up */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_staggered_spin_up(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 AHCI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt rval = AHCI_FAILURE;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_hba_reset: port %d failed", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Set the port state to SATA_PSTATE_FAILED if
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * failed to initialize it.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (rval);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * NOTE: The port interrupts should be disabled before the function is called.
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_find_dev_signature(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t dev_addr;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t signature;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t pmport = addrp->aa_pmport;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China int rval;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China ASSERT(AHCI_ADDR_IS_VALID(addrp));
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China /*
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 *
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 *
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 */
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China if (AHCI_ADDR_IS_PORT(addrp) &&
356f626884baacdca93fa012ac65e47c4d59606aying tian - Beijing China (ahci_ctlp->ahcictl_cap & AHCI_CAP_PMULT_CBSS)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 * pmport)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PMULT(&dev_addr, addrp->aa_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature enter: port %d:%d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang dev_addr = *addrp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Assume it is unknown. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 if (rval != AHCI_SUCCESS) {
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China /*
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 */
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 dev_addr.aa_pmport = 0;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China rval = ahci_software_reset(ahci_ctlp, ahci_portp,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China &dev_addr);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China }
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China if (rval != AHCI_SUCCESS) {
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
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 port, pmport);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China AHCIPORT_SET_STATE(ahci_portp, addrp,
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China SATA_PSTATE_FAILED);
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China return;
5ce0c8ceebeb61b99b7c69aaa673f96df29434d3ying tian - Beijing China }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /*
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * ahci_software_reset has started the port, so we need manually stop
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang * the port again.
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PORT(addrp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_put_port_into_notrunning_state(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, port) != AHCI_SUCCESS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature: cannot stop port %d.",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_PSTATE_FAILED;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang /* Now we can make sure that a valid signature is received. */
2fcbc377041d659446ded306a92901b4b0753b68yt signature = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSIG(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (AHCI_ADDR_IS_PMPORT(addrp)) {
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 signature, port, pmport);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INIT|AHCIDBG_INFO, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_find_dev_signature: signature = 0x%x at port %d",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang signature, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 signature = SATA_DTYPE_UNKNOWN;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt switch (signature) {
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case AHCI_SIGNATURE_DISK:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_ATADISK);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Disk is found at port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case AHCI_SIGNATURE_ATAPI:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_ATAPI);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ATAPI device is found at port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt case AHCI_SIGNATURE_PORT_MULTIPLIER:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Port Multiplier cannot recursively attached. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(AHCI_ADDR_IS_PORT(addrp));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_PMULT);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Port Multiplier is found at port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt default:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIPORT_SET_DEV_TYPE(ahci_portp, addrp, SATA_DTYPE_UNKNOWN);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Unknown device is found at port: %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
13bcbb7a73761015c9ef46cac33040380196e57fyt/*
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 *
13bcbb7a73761015c9ef46cac33040380196e57fyt * We can ignore the last item because by default the feature is disabled
13bcbb7a73761015c9ef46cac33040380196e57fyt */
13bcbb7a73761015c9ef46cac33040380196e57fytstatic void
13bcbb7a73761015c9ef46cac33040380196e57fytahci_disable_interface_pm(ahci_ctl_t *ahci_ctlp, uint8_t port)
13bcbb7a73761015c9ef46cac33040380196e57fyt{
13bcbb7a73761015c9ef46cac33040380196e57fyt uint32_t port_scontrol, port_cmd_status;
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt port_scontrol = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port));
13bcbb7a73761015c9ef46cac33040380196e57fyt SCONTROL_SET_IPM(port_scontrol, SCONTROL_IPM_DISABLE_BOTH);
13bcbb7a73761015c9ef46cac33040380196e57fyt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxSCTL(ahci_ctlp, port), port_scontrol);
13bcbb7a73761015c9ef46cac33040380196e57fyt
13bcbb7a73761015c9ef46cac33040380196e57fyt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
13bcbb7a73761015c9ef46cac33040380196e57fyt port_cmd_status &= ~AHCI_CMD_STATUS_ALPE;
13bcbb7a73761015c9ef46cac33040380196e57fyt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
13bcbb7a73761015c9ef46cac33040380196e57fyt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), port_cmd_status);
13bcbb7a73761015c9ef46cac33040380196e57fyt}
13bcbb7a73761015c9ef46cac33040380196e57fyt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Start the port - set PxCMD.ST to 1, if PxCMD.FRE is not set
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to 1, then set it firstly.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
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 *
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).
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_start_port(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_status;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_start_port: %d enter", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 port, ahci_portp->ahciport_port_state);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port failed "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "no device is attached at port %d", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_FAILURE);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* First to set PxCMD.FRE before setting PxCMD.ST. */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (!(port_cmd_status & AHCI_CMD_STATUS_FRE)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status |= AHCI_CMD_STATUS_FRE;
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status |= AHCI_CMD_STATUS_ST;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_STARTED;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_start_port: "
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang "PxCMD.ST set to '1' at port %d", port);
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka/*
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 Telka */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkastatic int
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_setup_port_base_addresses(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka{
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint8_t port = ahci_portp->ahciport_port_num;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka uint32_t port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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) != AHCI_SUCCESS)
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return (AHCI_FAILURE);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
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 int loop_count = 0;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Clear PxCMD.FRE */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status &= ~AHCI_CMD_STATUS_FRE;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Wait until PxCMD.FR is cleared */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka for (;;) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka port_cmd_status =
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (!(port_cmd_status & AHCI_CMD_STATUS_FR))
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka break;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
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 "clear PxCMD.FR for port %d.", port);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /*
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * We are effectively timing out after 0.5 sec.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * This value is specified in AHCI spec.
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return (AHCI_FAILURE);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Wait for 1 millisec */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka drv_usecwait(AHCI_1MS_USECS);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 3: Config Port Command List Base Address */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCLB(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_cmd_list_dma_cookie.dmac_address);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxCLBU(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_cmd_list_dma_cookie.dmac_notused);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Step 4: Config Port Received FIS Base Address */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxFB(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_address);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka (uint32_t *)AHCI_PORT_PxFBU(ahci_ctlp, port),
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_notused);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka return (AHCI_SUCCESS);
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka}
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_alloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China dev_info_t *dip = ahci_ctlp->ahcictl_dip;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China char taskq_name[64] = "event_handle_taskq";
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp =
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_port_t *)kmem_zalloc(sizeof (ahci_port_t), KM_SLEEP);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_ports[port] = ahci_portp;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_num = port;
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize the port condition variable */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cv_init(&ahci_portp->ahciport_cv, NULL, CV_DRIVER, NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Initialize the port mutex */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_init(&ahci_portp->ahciport_mutex, NULL, MUTEX_DRIVER,
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)(uintptr_t)ahci_ctlp->ahcictl_intr_pri);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocate memory for received FIS structure and
2fcbc377041d659446ded306a92901b4b0753b68yt * command list for this port
2fcbc377041d659446ded306a92901b4b0753b68yt */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_alloc_rcvd_fis(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_case1;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_alloc_cmd_list(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_case2;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka /* Setup PxCMD.CLB, PxCMD.CLBU, PxCMD.FB, and PxCMD.FBU */
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka if (ahci_setup_port_base_addresses(ahci_ctlp, ahci_portp) !=
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka AHCI_SUCCESS) {
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka goto err_case3;
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka }
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka
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 "_port%d", port);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
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 goto err_case3;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China }
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China /* Allocate the argument for the taskq */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_event_args =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt kmem_zalloc(sizeof (ahci_event_arg_t), KM_SLEEP);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_event_args->ahciea_addrp =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang kmem_zalloc(sizeof (ahci_addr_t), KM_SLEEP);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_event_args == NULL)
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China goto err_case4;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
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;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing Chinaerr_case4:
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ddi_taskq_destroy(ahci_portp->ahciport_event_taskq);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yterr_case3:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yterr_case2:
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_dealloc_rcvd_fis(ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yterr_case1:
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cv_destroy(&ahci_portp->ahciport_cv);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_portp, sizeof (ahci_port_t));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telka * Reverse of ahci_alloc_port_state().
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_port_state(ahci_ctl_t *ahci_ctlp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_mutex));
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(ahci_portp != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang kmem_free(ahci_portp->ahciport_event_args->ahciea_addrp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sizeof (ahci_addr_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_event_args->ahciea_addrp = NULL;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt kmem_free(ahci_portp->ahciport_event_args, sizeof (ahci_event_arg_t));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_event_args = NULL;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ddi_taskq_destroy(ahci_portp->ahciport_event_taskq);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dealloc_cmd_list(ahci_ctlp, ahci_portp);
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_dealloc_rcvd_fis(ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_dealloc_pmult(ahci_ctlp, ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_destroy(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt cv_destroy(&ahci_portp->ahciport_cv);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_portp, sizeof (ahci_port_t));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_ports[port] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocates memory for the Received FIS Structure
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_alloc_rcvd_fis(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt size_t rcvd_fis_size;
2fcbc377041d659446ded306a92901b4b0753b68yt size_t ret_len;
2fcbc377041d659446ded306a92901b4b0753b68yt uint_t cookie_count;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt rcvd_fis_size = sizeof (ahci_rcvd_fis_t);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* allocate rcvd FIS dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_rcvd_fis_dma_attr,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_rcvd_fis_dma_handle) !=
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "rcvd FIS dma handle alloc failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_mem_alloc(ahci_portp->ahciport_rcvd_fis_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt rcvd_fis_size,
2fcbc377041d659446ded306a92901b4b0753b68yt &accattr,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t *)&ahci_portp->ahciport_rcvd_fis,
2fcbc377041d659446ded306a92901b4b0753b68yt &ret_len,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_rcvd_fis_acc_handle) != NULL) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "rcvd FIS dma mem alloc fail", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t)ahci_portp->ahciport_rcvd_fis,
2fcbc377041d659446ded306a92901b4b0753b68yt rcvd_fis_size,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
13bcbb7a73761015c9ef46cac33040380196e57fyt &ahci_portp->ahciport_rcvd_fis_dma_cookie,
2fcbc377041d659446ded306a92901b4b0753b68yt &cookie_count) != DDI_DMA_MAPPED) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "rcvd FIS dma handle bind fail", NULL);
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 return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)ahci_portp->ahciport_rcvd_fis, rcvd_fis_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_laddress);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp->ahciport_rcvd_fis_dma_cookie.dmac_address);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates the Received FIS Structure
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
689d74b0a0dba643450e7fc74a03425c963657e7ytahci_dealloc_rcvd_fis(ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd list dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_rcvd_fis_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_rcvd_fis_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2ac302890e472bf0c11db192dd18f12ded6043f6Marcel Telkaahci_alloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt size_t cmd_list_size;
2fcbc377041d659446ded306a92901b4b0753b68yt size_t ret_len;
2fcbc377041d659446ded306a92901b4b0753b68yt uint_t cookie_count;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_list_size =
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_num_cmd_slots * sizeof (ahci_cmd_header_t);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* allocate cmd list dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_cmd_list_dma_attr,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_list_dma_handle) != DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd list dma handle alloc failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_mem_alloc(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_list_size,
2fcbc377041d659446ded306a92901b4b0753b68yt &accattr,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t *)&ahci_portp->ahciport_cmd_list,
2fcbc377041d659446ded306a92901b4b0753b68yt &ret_len,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_list_acc_handle) != NULL) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd list dma mem alloc fail", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_addr_bind_handle(ahci_portp->ahciport_cmd_list_dma_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t)ahci_portp->ahciport_cmd_list,
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_list_size,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
13bcbb7a73761015c9ef46cac33040380196e57fyt &ahci_portp->ahciport_cmd_list_dma_cookie,
2fcbc377041d659446ded306a92901b4b0753b68yt &cookie_count) != DDI_DMA_MAPPED) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd list dma handle bind fail", NULL);
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 return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)ahci_portp->ahciport_cmd_list, cmd_list_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "64-bit, dma address: 0x%llx",
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp->ahciport_cmd_list_dma_cookie.dmac_laddress);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp, "32-bit, dma address: 0x%x",
13bcbb7a73761015c9ef46cac33040380196e57fyt ahci_portp->ahciport_cmd_list_dma_cookie.dmac_address);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_alloc_cmd_tables(ahci_ctlp, ahci_portp) != AHCI_SUCCESS) {
e2decd04da4059e1b20578edbd72fb1acb9b2317yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt
e2decd04da4059e1b20578edbd72fb1acb9b2317yterr_out:
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Unbind the cmd list dma handle first. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_cmd_list_dma_handle);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Then free the underlying memory. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt
e2decd04da4059e1b20578edbd72fb1acb9b2317yt /* Now free the handle itself. */
e2decd04da4059e1b20578edbd72fb1acb9b2317yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
e2decd04da4059e1b20578edbd72fb1acb9b2317yt
e2decd04da4059e1b20578edbd72fb1acb9b2317yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates the Command List
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_cmd_list(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt /* First dealloc command table */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_dealloc_cmd_tables(ahci_ctlp, ahci_portp);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd list dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(&ahci_portp->ahciport_cmd_list_acc_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(&ahci_portp->ahciport_cmd_list_dma_handle);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Allocates memory for all Command Tables, which contains Command FIS,
2fcbc377041d659446ded306a92901b4b0753b68yt * ATAPI Command and Physical Region Descriptor Table.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_alloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt size_t ret_len;
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_cookie_t cmd_table_dma_cookie;
2fcbc377041d659446ded306a92901b4b0753b68yt uint_t cookie_count;
2fcbc377041d659446ded306a92901b4b0753b68yt int slot;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_alloc_cmd_tables: port %d enter",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_num);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate cmd table dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_alloc_handle(ahci_ctlp->ahcictl_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_cmd_table_dma_attr,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_dma_handle[slot]) !=
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_SUCCESS) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd table dma handle alloc failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_mem_alloc(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size,
2fcbc377041d659446ded306a92901b4b0753b68yt &accattr,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t *)&ahci_portp->ahciport_cmd_tables[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt &ret_len,
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_acc_handle[slot]) !=
2fcbc377041d659446ded306a92901b4b0753b68yt NULL) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd table dma mem alloc fail", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_dma_addr_bind_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_cmd_tables_dma_handle[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t)ahci_portp->ahciport_cmd_tables[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size,
2ab9355fd0b7eee900436bbe1ec5758ffc59d52bying tian - Beijing China DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2fcbc377041d659446ded306a92901b4b0753b68yt DDI_DMA_SLEEP,
2fcbc377041d659446ded306a92901b4b0753b68yt NULL,
2fcbc377041d659446ded306a92901b4b0753b68yt &cmd_table_dma_cookie,
2fcbc377041d659446ded306a92901b4b0753b68yt &cookie_count) != DDI_DMA_MAPPED) {
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "cmd table dma handle bind fail", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt /* error.. free the dma handle & free the memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt goto err_out;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)ahci_portp->ahciport_cmd_tables[slot],
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_cmd_table_size);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Config Port Command Table Base Address */
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_TABLE_BASE_ADDR(
2fcbc377041d659446ded306a92901b4b0753b68yt (&ahci_portp->ahciport_cmd_list[slot]),
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table_dma_cookie.dmac_laddress & 0xffffffffull);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt#ifndef __lock_lint
2fcbc377041d659446ded306a92901b4b0753b68yt SET_COMMAND_TABLE_BASE_ADDR_UPPER(
2fcbc377041d659446ded306a92901b4b0753b68yt (&ahci_portp->ahciport_cmd_list[slot]),
2fcbc377041d659446ded306a92901b4b0753b68yt cmd_table_dma_cookie.dmac_laddress >> 32);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yterr_out:
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (slot--; slot >= 0; slot--) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd table dma handle first */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Deallocates memory for all Command Tables.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_dealloc_cmd_tables(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt int slot;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_dealloc_cmd_tables: %d enter",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_num);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (slot = 0; slot < ahci_ctlp->ahcictl_num_cmd_slots; slot++) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Unbind the cmd table dma handle first. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_dma_unbind_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Then free the underlying memory. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_mem_free(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_acc_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Now free the handle itself. */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_dma_free_handle(
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_portp->ahciport_cmd_tables_dma_handle[slot]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Update SATA registers at controller ports
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_update_sata_registers(ahci_ctl_t *ahci_ctlp, uint8_t port,
2fcbc377041d659446ded306a92901b4b0753b68yt sata_device_t *sd)
2fcbc377041d659446ded306a92901b4b0753b68yt{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_scr.sstatus =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)(AHCI_PORT_PxSSTS(ahci_ctlp, port)));
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_scr.serror =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)(AHCI_PORT_PxSERR(ahci_ctlp, port)));
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_scr.scontrol =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)(AHCI_PORT_PxSCTL(ahci_ctlp, port)));
2fcbc377041d659446ded306a92901b4b0753b68yt sd->satadev_scr.sactive =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)(AHCI_PORT_PxSACT(ahci_ctlp, port)));
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For poll mode, ahci_port_intr will be called to emulate the interrupt
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_port_intr(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_intr_status;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_intr_enable;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_port_intr enter: port %d", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_POLLING) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* For SATA_OPMODE_POLLING commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_intr_enable =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (AHCI_INTR_STATUS_DHRS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_PSS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_SDBS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_UFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_PCS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_PRCS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_OFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_INFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_IFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBDS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_TFES);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * port_intr_enable indicates that the corresponding interrrupt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * reporting is enabled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_intr_enable = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_intr_enable |= AHCI_INTR_STATUS_IPMS;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * port_intr_stats indicates that the corresponding interrupt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * condition is active.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_port_intr: port %d, port_intr_status = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_intr_enable = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, port_intr_status, port_intr_enable);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_intr_status &= port_intr_enable;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
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 */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_ctl_handle(ahci_ctlp) != DDI_SUCCESS) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return;
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* First clear the port interrupts status */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port),
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_intr_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check the completed non-queued commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & (AHCI_INTR_STATUS_DHRS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_PSS)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_cmd_cmplt(ahci_ctlp,
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check the completed queued commands */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & AHCI_INTR_STATUS_SDBS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_set_device_bits(ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the port connect change status interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & AHCI_INTR_STATUS_PCS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_port_connect_change(ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the device mechanical presence status interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & AHCI_INTR_STATUS_DMPS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_device_mechanical_presence_status(
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctlp, ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the PhyRdy change status interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & AHCI_INTR_STATUS_PRCS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_phyrdy_change(ahci_ctlp, ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Check the non-fatal error interrupt bits, there are four
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * kinds of non-fatal errors at the time being:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * For these non-fatal errors, the HBA can continue to operate,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * so the driver just log the error messages.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & (AHCI_INTR_STATUS_UFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_OFS |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_INTR_STATUS_IPMS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_INFS)) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_non_fatal_error(ahci_ctlp, ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port, port_intr_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Check the fatal error interrupt bits, there are four kinds
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * of fatal errors for AHCI controllers:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
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 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & (AHCI_INTR_STATUS_IFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBDS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_TFES))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_fatal_error(ahci_ctlp, ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt port, port_intr_status);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Check the cold port detect interrupt bit */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_intr_status & AHCI_INTR_STATUS_CPDS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_intr_cold_port_detect(ahci_ctlp, ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Second clear the corresponding bit in IS.IPS */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp), (0x1 << port));
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
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_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Interrupt service handler
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic uint_t
2fcbc377041d659446ded306a92901b4b0753b68ytahci_intr(caddr_t arg1, caddr_t arg2)
2fcbc377041d659446ded306a92901b4b0753b68yt{
689d74b0a0dba643450e7fc74a03425c963657e7yt#ifndef __lock_lint
689d74b0a0dba643450e7fc74a03425c963657e7yt _NOTE(ARGUNUSED(arg2))
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
689d74b0a0dba643450e7fc74a03425c963657e7yt /* LINTED */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctl_t *ahci_ctlp = (ahci_ctl_t *)arg1;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int32_t global_intr_status;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * global_intr_status indicates that the corresponding port has
2fcbc377041d659446ded306a92901b4b0753b68yt * an interrupt pending.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt global_intr_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(global_intr_status & ahci_ctlp->ahcictl_ports_implemented)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* The interrupt is not ours */
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_INTR_UNCLAIMED);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang /*
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 */
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang if (ahci_check_acc_handle(ahci_ctlp->ahcictl_ahci_acc_handle) !=
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FM_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_service_impact(ahci_ctlp->ahcictl_dip,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_SERVICE_UNAFFECTED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang ddi_fm_acc_err_clear(ahci_ctlp->ahcictl_ahci_acc_handle,
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang DDI_FME_VERSION);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (DDI_INTR_UNCLAIMED);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /* Loop for all the ports */
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt if (!((0x1 << port) & global_intr_status)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Call ahci_port_intr */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_port_intr(ahci_ctlp, ahci_portp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_INTR_CLAIMED);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
82263d52a84b4a969aa53f8ededddff841646ad9yt * Process completed non-queued commands when the interrupt status bit -
82263d52a84b4a969aa53f8ededddff841646ad9yt * AHCI_INTR_STATUS_DHRS or AHCI_INTR_STATUS_PSS is set.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
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 */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_intr_cmd_cmplt(ahci_ctl_t *ahci_ctlp,
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_issue = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t finished_tags;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int finished_slot;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_pkt_t *satapkt;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_fis_d2h_register_t *rcvd_fisp;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#if AHCI_DEBUG
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_cmd_header_t *cmd_header;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China uint32_t cmd_dmacount;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_enter(&ahci_portp->ahciport_mutex);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (!ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang !RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt !NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Spurious interrupt. Nothing to be done.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
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)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang != DDI_FM_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (AHCI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Slot 0 is always used during error recovery */
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = 0x1 & ~port_cmd_issue;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: port %d the sata pkt for error "
82263d52a84b4a969aa53f8ededddff841646ad9yt "retrieval is finished, and finished_tags = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, finished_tags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang finished_tags = 0x1 & ~port_cmd_issue;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INFO, ahci_ctlp,
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",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, finished_tags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt finished_tags = ahci_portp->ahciport_pending_tags &
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: pending_tags = 0x%x, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_cmd_issue = 0x%x finished_tags = 0x%x",
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_pending_tags, port_cmd_issue,
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt (finished_tags == 0x1)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
82263d52a84b4a969aa53f8ededddff841646ad9yt "with SATA_PKT_COMPLETED", (void *)satapkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp) &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (finished_tags == 0x1)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(satapkt != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "with SATA_PKT_COMPLETED", (void *)satapkt);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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 rcvd_fisp = &(ahci_portp->ahciport_rcvd_fis->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahcirf_d2h_register_fis);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt->satapkt_cmd.satacmd_status_reg =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang GET_RFIS_STATUS(rcvd_fisp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang goto out;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt while (finished_tags) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt finished_slot = ddi_ffs(finished_tags) - 1;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (finished_slot == -1) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt satapkt = ahci_portp->ahciport_slot_pkts[finished_slot];
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ASSERT(satapkt != NULL);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#if AHCI_DEBUG
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /*
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 *
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 * illegal.
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China *
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 *
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 */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_dmacount =
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[finished_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (cmd_dmacount) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header =
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China &ahci_portp->ahciport_cmd_list[finished_slot];
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_PRDT, ahci_ctlp,
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 cmd_dmacount);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (cmd_header->ahcich_prd_byte_count != cmd_dmacount) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_UNDERFLOW, ahci_ctlp,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "ahci_intr_cmd_cmplt: port %d, "
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China "an underflow occurred", port);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China }
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China }
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt rcvd_fisp = &(ahci_portp->ahciport_rcvd_fis->
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahcirf_d2h_register_fis);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt satapkt->satapkt_cmd.satacmd_status_reg =
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt GET_RFIS_STATUS(rcvd_fisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_copy_out_regs(&satapkt->satapkt_cmd, rcvd_fisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_cmd_cmplt: sending up pkt 0x%p "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "with SATA_PKT_COMPLETED", (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, finished_slot);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt CLEAR_BIT(finished_tags, finished_slot);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_slot_pkts[finished_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68ytout:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PKTCOMP, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_cmd_cmplt: pending_tags = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_pending_tags);
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_flush_doneq(ahci_portp);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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:
82263d52a84b4a969aa53f8ededddff841646ad9yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 1. NCQ command is completed
82263d52a84b4a969aa53f8ededddff841646ad9yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * 2. Asynchronous Notification
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Asynchronous Notification is a feature in SATA spec 2.6.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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 *
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()
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_intr_set_device_bits(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Initialize HBA port address */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT(&addr, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* NCQ plug handler */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_intr_ncq_events(ahci_ctlp, ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Check port multiplier's asynchronous notification events */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_ctlp->ahcictl_cap & AHCI_CAP_SNTF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_intr_pmult_sntf_events(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* ATAPI events is not supported yet */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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().
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_intr_ncq_events(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_sactive;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_cmd_issue;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t issued_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt int issued_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt int finished_slot;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port = addrp->aa_port;
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_pkt_t *satapkt;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_set_device_bits enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_enter(&ahci_portp->ahciport_mutex);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (!NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_exit(&ahci_portp->ahciport_mutex);
82263d52a84b4a969aa53f8ededddff841646ad9yt return (AHCI_SUCCESS);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * First the handler got which commands are finished by checking
82263d52a84b4a969aa53f8ededddff841646ad9yt * PxSACT register
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~port_sactive & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d pending_ncq_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_sactive = 0x%x", port,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags, port_sactive);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: finished_tags = 0x%x", finished_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * For NCQ commands, the software can determine which command has
82263d52a84b4a969aa53f8ededddff841646ad9yt * already been transmitted to the device by checking PxCI register.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt issued_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~port_cmd_issue & AHCI_SLOT_MASK(ahci_ctlp);
82263d52a84b4a969aa53f8ededddff841646ad9yt
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)
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang != DDI_FM_OK) {
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang return (AHCI_FAILURE);
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang }
b22851f1a70ff0ed1ec71258e1089d2f795b2344Xiao-Yu Zhang
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d pending_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port_cmd_issue = 0x%x", port,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_tags, port_cmd_issue);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: issued_tags = 0x%x", issued_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Clear ahciport_pending_tags bit when the corresponding command
82263d52a84b4a969aa53f8ededddff841646ad9yt * is already sent down to the device.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt while (issued_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt issued_slot = ddi_ffs(issued_tags) - 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt if (issued_slot == -1) {
82263d52a84b4a969aa53f8ededddff841646ad9yt goto next;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, issued_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(issued_tags, issued_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9ytnext:
82263d52a84b4a969aa53f8ededddff841646ad9yt while (finished_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_slot = ddi_ffs(finished_tags) - 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt if (finished_slot == -1) {
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* The command is certainly transmitted to the device */
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(!(ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt (0x1 << finished_slot)));
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_slot_pkts[finished_slot];
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: sending up pkt 0x%p "
82263d52a84b4a969aa53f8ededddff841646ad9yt "with SATA_PKT_COMPLETED", (void *)satapkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags, finished_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(finished_tags, finished_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_slot_pkts[finished_slot] = NULL;
82263d52a84b4a969aa53f8ededddff841646ad9yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
82263d52a84b4a969aa53f8ededddff841646ad9ytout:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_PKTCOMP|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_set_device_bits: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "pending_ncq_tags = 0x%x pending_tags = 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_flush_doneq(ahci_portp);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Port multiplier asynchronous notification event handler. Called upon a
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * device is hot plugged/pulled.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE: called only from ahci_port_intr().
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic int
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_intr_pmult_sntf_events(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t port)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_device_t sdevice;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* no hot-plug while attaching process */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_ctlp->ahcictl_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_ctlp->ahcictl_flags & AHCI_ATTACH) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_ctlp->ahcictl_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_ctlp->ahcictl_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(ahci_portp->ahciport_pmult_info != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_pmult_info->ahcipmi_snotif_tags =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxSNTF(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_SNOTIF_CLEAR_ALL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_pmult_info->ahcipmi_snotif_tags == 0) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Port Multiplier sub-device hot-plug handler */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_PMULT_SNTF) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Not allowed to re-enter. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_PMULT_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * NOTE:
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 */
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 "port %d snotif event ignored", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_PMULT_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.cport = ahci_ctlp->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = SATA_PMULT_HOSTPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_state = SATA_PSTATE_PWRON;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_PMULT_LINK_CHANGED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_PMULT_SNTF;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_intr_port_connect_change(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_serror;
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_port_connect_change: port %d, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port_serror = 0x%x", port, port_serror);
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear PxSERR.DIAG.X to clear the interrupt bit */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
82263d52a84b4a969aa53f8ededddff841646ad9yt SERROR_EXCHANGED_ERR);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Hot Plug Operation for platforms that support Mechanical Presence
2fcbc377041d659446ded306a92901b4b0753b68yt * Switches.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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'.
2fcbc377041d659446ded306a92901b4b0753b68yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * At the moment, this interrupt is not needed and disabled and we just log
2fcbc377041d659446ded306a92901b4b0753b68yt * the debug message.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_intr_device_mechanical_presence_status(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t cap_status, port_cmd_status;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_intr_device_mechanical_presence_status enter, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt cap_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_CAP(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(cap_status & AHCI_HBA_CAP_SMPS) ||
2fcbc377041d659446ded306a92901b4b0753b68yt !(port_cmd_status & AHCI_CMD_STATUS_MPSP)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "CAP.SMPS or PxCMD.MPSP is not set, so just ignore "
2fcbc377041d659446ded306a92901b4b0753b68yt "the interrupt: cap_status = 0x%x, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_status = 0x%x", cap_status, port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt if (port_cmd_status & AHCI_CMD_STATUS_MPSS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "The mechanical presence switch is open: "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d, port_cmd_status = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt port, port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "The mechanical presence switch is close: "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d, port_cmd_status = 0x%x",
2fcbc377041d659446ded306a92901b4b0753b68yt port, port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt }
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Native Hot Plug Support.
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * When set, it indicates that the internal PHYRDY signal changed state.
2fcbc377041d659446ded306a92901b4b0753b68yt * This bit reflects the state of PxSERR.DIAG.N.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
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 */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_intr_phyrdy_change(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_sstatus = 0; /* No dev present & PHY not established. */
2fcbc377041d659446ded306a92901b4b0753b68yt sata_device_t sdevice;
2fcbc377041d659446ded306a92901b4b0753b68yt int dev_exists_now = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt int dev_existed_previously = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t port_addr;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_intr_phyrdy_change enter, port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Clear PxSERR.DIAG.N to clear the interrupt bit */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
82263d52a84b4a969aa53f8ededddff841646ad9yt SERROR_PHY_RDY_CHG);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt if ((ahci_ctlp->ahcictl_sata_hba_tran == NULL) ||
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_portp == NULL)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* The whole controller setup is not yet done. */
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* SStatus tells the presence of device. */
2fcbc377041d659446ded306a92901b4b0753b68yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt dev_exists_now = 1;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt dev_existed_previously = 1;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ahci_portp->ahciport_flags & AHCI_PORT_FLAG_NODEV) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_NODEV;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_phyrdy_change: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "AHCI_PORT_FLAG_NODEV is cleared", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (dev_exists_now == 0)
82263d52a84b4a969aa53f8ededddff841646ad9yt dev_existed_previously = 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)&sdevice, sizeof (sata_device_t));
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_addr.qual = SATA_ADDR_CPORT;
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_addr.pmport = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_state = SATA_PSTATE_PWRON;
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_port_state = SATA_PSTATE_PWRON;
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT(&port_addr, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_HOTPLUG;
2fcbc377041d659446ded306a92901b4b0753b68yt if (dev_exists_now) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_existed_previously) { /* 1 -> 1 */
2fcbc377041d659446ded306a92901b4b0753b68yt /* Things are fine now. The loss was temporary. */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt "device link lost/established", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_LINK_LOST|SATA_EVNT_LINK_ESTABLISHED);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else { /* 0 -> 1 */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt "device link established", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_initialize_port(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, &port_addr);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Try to start the port */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_start_port(ahci_ctlp, ahci_portp, port)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt != AHCI_SUCCESS) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_state |= SATA_PSTATE_FAILED;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d failed "
2fcbc377041d659446ded306a92901b4b0753b68yt "at start port", port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Clear the max queue depth for inserted device */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_max_ncq_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_LINK_ESTABLISHED);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt } else { /* No device exists now */
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_existed_previously) { /* 1 -> 0 */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_phyrdy_change: port %d "
2fcbc377041d659446ded306a92901b4b0753b68yt "device link lost", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_reject_all_abort_pkts(ahci_ctlp, ahci_portp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type ==
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_dealloc_pmult(ahci_ctlp, ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt /* An existing device is lost. */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_device_type = SATA_DTYPE_NONE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_STATE_UNKNOWN;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_LINK_LOST);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_HOTPLUG;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.UFS - Unknown FIS Error
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * PxIS.IPMS - Incorrect Port Multiplier Status
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
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).
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.OFS - Overflow Error
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.INFS - Interface Non-Fatal Error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * When the FMA is implemented, there should be a stat structure to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * record how many every kind of error happens.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_intr_non_fatal_error(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t port, uint32_t intr_status)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_serror;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_cmd_status;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_cmd_issue;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_sactive;
2fcbc377041d659446ded306a92901b4b0753b68yt int current_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t current_tags;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_pkt_t *satapkt;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_cmd_header_t *cmd_header;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China uint32_t cmd_dmacount;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
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);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_log_serror_message(ahci_ctlp, port, port_serror, 1);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_UFS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci port %d has unknown FIS error", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Clear the interrupt bit by clearing PxSERR.DIAG.F */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
82263d52a84b4a969aa53f8ededddff841646ad9yt SERROR_FIS_TYPE);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (intr_status & AHCI_INTR_STATUS_IPMS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci port %d "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "has Incorrect Port Multiplier Status error", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_OFS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci port %d has overflow error", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_INFS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci port %d has interface non fatal error", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Record the error occurred command's slot.
2fcbc377041d659446ded306a92901b4b0753b68yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
82263d52a84b4a969aa53f8ededddff841646ad9yt ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt current_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_CMD_STATUS_CCS_SHIFT;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(current_slot == 0);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_slot_pkts[current_slot];
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (satapkt != NULL) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_non_fatal_error: pending_tags = 0x%x "
82263d52a84b4a969aa53f8ededddff841646ad9yt "cmd 0x%x", ahci_portp->ahciport_pending_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt->satapkt_cmd.satacmd_cmd_reg);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_intr_non_fatal_error: port %d, "
82263d52a84b4a969aa53f8ededddff841646ad9yt "satapkt 0x%p is being processed when error occurs",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, (void *)satapkt);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /*
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 */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_dmacount =
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_portp->ahciport_prd_bytecounts[current_slot];
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (cmd_dmacount) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header = &ahci_portp->
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahciport_cmd_list[current_slot];
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
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,
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_dmacount);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * For queued command, list those command which have already
82263d52a84b4a969aa53f8ededddff841646ad9yt * been transmitted to the device and still not completed.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_issue = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt
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 ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive, port_cmd_issue);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt current_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive & ~port_cmd_issue &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt while (current_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt current_slot = ddi_ffs(current_tags) - 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt if (current_slot == -1) {
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_slot_pkts[current_slot];
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_NCQ|AHCIDBG_ERRS,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp, "ahci_intr_non_fatal_error: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "port %d, satapkt 0x%p is outstanding when "
82263d52a84b4a969aa53f8ededddff841646ad9yt "error occurs", port, (void *)satapkt);
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang
a419422e719e968918316ef55a9fe46ad3ad7b00Xiao-Yu Zhang CLEAR_BIT(current_tags, current_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
82263d52a84b4a969aa53f8ededddff841646ad9ytout:
2fcbc377041d659446ded306a92901b4b0753b68yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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 *
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the fatal errors include PxIS.IFS, PxIS.HBDS, PxIS.HBFS and PxIS.TFES.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.IFS indicates that the hba encountered an error on the serial ata
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * interface which caused the transfer to stop.
2fcbc377041d659446ded306a92901b4b0753b68yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.HBDS indicates that the hba encountered a data error
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * (uncorrectable ecc/parity) when reading from or writing to system memory.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * PxIS.TFES is set whenever the status register is updated by the device
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * and the error bit (bit 0) is set.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_intr_fatal_error(ahci_ctl_t *ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_port_t *ahci_portp, uint8_t port, uint32_t intr_status)
2fcbc377041d659446ded306a92901b4b0753b68yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_status;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_serror;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t task_file_status;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int failed_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_pkt_t *spkt = NULL;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t err_byte;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_event_arg_t *args;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China uint32_t failed_tags = 0;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int task_fail_flag = 0, task_abort_flag = 0;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China uint32_t slot_status;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_intr_phyrdy_change() may have rendered it to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_DTYPE_NONE.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_intr_fatal_error: port %d no device attached, "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "and just return without doing anything", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto out0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
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));
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
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 task_fail_flag = 1;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China err_byte = (task_file_status & AHCI_TFD_ERR_MASK)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China >> AHCI_TFD_ERR_SHIFT;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (err_byte == SATA_ERROR_ABORT)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China task_abort_flag = 1;
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China }
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (task_fail_flag == 1) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China /*
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 */
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China port_cmd_status = ddi_get32(
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 AHCI_CMD_STATUS_CCS_SHIFT;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China failed_tags = 0x1 << failed_slot;
2fcbc377041d659446ded306a92901b4b0753b68yt
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",
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China spkt, port);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Won't emit the error message if it is an IDENTIFY
82263d52a84b4a969aa53f8ededddff841646ad9yt * DEVICE command sent to an ATAPI device.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((spkt != NULL) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt (spkt->satapkt_cmd.satacmd_cmd_reg ==
82263d52a84b4a969aa53f8ededddff841646ad9yt SATAC_ID_DEVICE) &&
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China (task_abort_flag == 1))
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China goto out1;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Won't emit the error message if it is an ATAPI PACKET
82263d52a84b4a969aa53f8ededddff841646ad9yt * command
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((spkt != NULL) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt (spkt->satapkt_cmd.satacmd_cmd_reg == SATAC_PACKET))
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out1;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China slot_status = ddi_get32(
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_ctlp->ahcictl_ahci_acc_handle,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China failed_tags = slot_status &
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
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;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt port_serror = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port));
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China /* print PxSERR related error message */
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ahci_log_serror_message(ahci_ctlp, port, port_serror, 0);
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China /* print task file register value */
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (task_fail_flag == 1) {
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 if (task_abort_flag == 1) {
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);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China }
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China }
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China
a9440e8dda4d8a2be7e0201ca261df3118c86b5eytout1:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Prepare the argument for the taskq */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt args = ahci_portp->ahciport_event_args;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt args->ahciea_ctlp = (void *)ahci_ctlp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt args->ahciea_portp = (void *)ahci_portp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt args->ahciea_event = intr_status;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT((ahci_addr_t *)args->ahciea_addrp, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Start the taskq to handle error recovery */
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China if ((ddi_taskq_dispatch(ahci_portp->ahciport_event_taskq,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_events_handler,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (void *)args, DDI_NOSLEEP)) != DDI_SUCCESS) {
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);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytout0:
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Hot Plug Operation for platforms that support Cold Presence Detect.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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'.
2fcbc377041d659446ded306a92901b4b0753b68yt *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * At the moment, this interrupt is not needed and disabled and we just
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * log the debug message.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_intr_cold_port_detect(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_cmd_status;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_device_t sdevice;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_intr_cold_port_detect enter, port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt if (!(port_cmd_status & AHCI_CMD_STATUS_CPD)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d does not support cold presence detect, so "
2fcbc377041d659446ded306a92901b4b0753b68yt "we just ignore this interrupt", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d device status has changed", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)&sdevice, sizeof (sata_device_t));
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_addr.qual = SATA_ADDR_CPORT;
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_addr.pmport = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_state = SATA_PSTATE_PWRON;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (port_cmd_status & AHCI_CMD_STATUS_CPS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d: a device is hot plugged", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_DEVICE_ATTACHED);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d: a device is hot unplugged", port);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_DEVICE_DETACHED);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Enable the interrupts for a particular port.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
689d74b0a0dba643450e7fc74a03425c963657e7ytahci_enable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_enable_port_intrs enter, port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Clear port interrupt status before enabling interrupt
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxIS(ahci_ctlp, port),
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_PORT_INTR_MASK);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Clear the pending bit from IS.IPS
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_IS(ahci_ctlp), (1 << port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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 */
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port),
2fcbc377041d659446ded306a92901b4b0753b68yt (AHCI_INTR_STATUS_DHRS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_PSS |
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_INTR_STATUS_SDBS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_UFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_DPS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_PCS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_PRCS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_OFS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_INFS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_IFS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_HBDS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_HBFS |
2fcbc377041d659446ded306a92901b4b0753b68yt AHCI_INTR_STATUS_TFES));
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Enable interrupts for all the ports.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_enable_all_intrs(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t ghc_control;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_ctlp->ahcictl_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_enable_all_intrs enter", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control |= AHCI_HBA_GHC_IE;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable interrupts for a particular port.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
689d74b0a0dba643450e7fc74a03425c963657e7ytahci_disable_port_intrs(ahci_ctl_t *ahci_ctlp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & AHCI_QUIESCE ||
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_disable_port_intrs enter, port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxIE(ahci_ctlp, port), 0);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Disable interrupts for the whole HBA.
2fcbc377041d659446ded306a92901b4b0753b68yt *
2fcbc377041d659446ded306a92901b4b0753b68yt * The global bit is cleared, then all interrupt sources from all
2fcbc377041d659446ded306a92901b4b0753b68yt * ports are disabled.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_disable_all_intrs(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t ghc_control;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & (AHCI_ATTACH | AHCI_QUIESCE) ||
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka MUTEX_HELD(&ahci_ctlp->ahcictl_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_disable_all_intrs enter",
f5f2d263454d943a366844932bdb677530ba733bFred Herard NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ghc_control = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp));
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ghc_control &= ~AHCI_HBA_GHC_IE;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_GLOBAL_GHC(ahci_ctlp), ghc_control);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Handle FIXED or MSI interrupts.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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 *
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 *
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing Chinaahci_add_intrs(ahci_ctl_t *ahci_ctlp, int intr_type)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt dev_info_t *dip = ahci_ctlp->ahcictl_dip;
2fcbc377041d659446ded306a92901b4b0753b68yt int count, avail, actual;
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China int i, rc;
2fcbc377041d659446ded306a92901b4b0753b68yt
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
2fcbc377041d659446ded306a92901b4b0753b68yt /* get number of interrupts. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China rc = ddi_intr_get_nintrs(dip, intr_type, &count);
2fcbc377041d659446ded306a92901b4b0753b68yt if ((rc != DDI_SUCCESS) || (count == 0)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_nintrs() failed, "
2fcbc377041d659446ded306a92901b4b0753b68yt "rc %d count %d\n", rc, count);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* get number of available interrupts. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China rc = ddi_intr_get_navail(dip, intr_type, &avail);
2fcbc377041d659446ded306a92901b4b0753b68yt if ((rc != DDI_SUCCESS) || (avail == 0)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ddi_intr_get_navail() failed, "
2fcbc377041d659446ded306a92901b4b0753b68yt "rc %d avail %d\n", rc, avail);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt if (avail < count) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "ddi_intr_get_nintrs returned %d, navail() returned %d",
2fcbc377041d659446ded306a92901b4b0753b68yt count, avail);
2fcbc377041d659446ded306a92901b4b0753b68yt }
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China /*
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 * performance.
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China if ((intr_type == DDI_INTR_TYPE_MSI) && (count > 1)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR, ahci_ctlp,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "force to use one interrupt routine though the "
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China "HBA supports %d interrupt", count);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China count = 1;
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China }
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt /* Allocate an array of interrupt handles. */
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_size = count * sizeof (ddi_intr_handle_t);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_htable =
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_alloc(ahci_ctlp->ahcictl_intr_size, KM_SLEEP);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* call ddi_intr_alloc(). */
2fcbc377041d659446ded306a92901b4b0753b68yt rc = ddi_intr_alloc(dip, ahci_ctlp->ahcictl_intr_htable,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China intr_type, 0, count, &actual, DDI_INTR_ALLOC_NORMAL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if ((rc != DDI_SUCCESS) || (actual == 0)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
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 kmem_free(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_size);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* use interrupt count returned */
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt if (actual < count) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "Requested: %d, Received: %d", count, actual);
2fcbc377041d659446ded306a92901b4b0753b68yt }
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_cnt = actual;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China * Get priority for first, assume remaining are all the same.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ddi_intr_get_pri(ahci_ctlp->ahcictl_intr_htable[0],
2fcbc377041d659446ded306a92901b4b0753b68yt &ahci_ctlp->ahcictl_intr_pri) != DDI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ddi_intr_get_pri() failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_size);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Test for high level interrupt. */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp->ahcictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_add_intrs: Hi level intr not supported", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt sizeof (ddi_intr_handle_t));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
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 ahci_intr, (caddr_t)ahci_ctlp, NULL) != DDI_SUCCESS) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ddi_intr_add_handler() failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_free(
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_size);
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
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) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_INIT, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ddi_intr_get_cap() failed", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China /* Free already allocated intr. */
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China for (i = 0; i < actual; i++) {
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China (void) ddi_intr_free(
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China }
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China kmem_free(ahci_ctlp->ahcictl_intr_htable,
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_size);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China return (DDI_FAILURE);
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp->ahcictl_intr_cap & DDI_INTR_FLAG_BLOCK) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_block_enable() for MSI. */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_block_enable(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_cnt);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
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++) {
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_enable(
2c742e1fc31a2d9ed20c81c69ba6d34ff94272d3ying tian - Beijing China ahci_ctlp->ahcictl_intr_htable[i]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (DDI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Removes the registered interrupts irrespective of whether they
2fcbc377041d659446ded306a92901b4b0753b68yt * were legacy or MSI.
2fcbc377041d659446ded306a92901b4b0753b68yt *
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka * NOTE: The controller interrupts must be disabled before calling
2fcbc377041d659446ded306a92901b4b0753b68yt * this routine.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_rem_intrs(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt int x;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp, "ahci_rem_intrs entered", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Disable all interrupts. */
2fcbc377041d659446ded306a92901b4b0753b68yt if ((ahci_ctlp->ahcictl_intr_type == DDI_INTR_TYPE_MSI) &&
2fcbc377041d659446ded306a92901b4b0753b68yt (ahci_ctlp->ahcictl_intr_cap & DDI_INTR_FLAG_BLOCK)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_block_disable(). */
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_block_disable(ahci_ctlp->ahcictl_intr_htable,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_cnt);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
2fcbc377041d659446ded306a92901b4b0753b68yt for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_disable(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_htable[x]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Call ddi_intr_remove_handler(). */
2fcbc377041d659446ded306a92901b4b0753b68yt for (x = 0; x < ahci_ctlp->ahcictl_intr_cnt; x++) {
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_remove_handler(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_intr_htable[x]);
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ddi_intr_free(ahci_ctlp->ahcictl_intr_htable[x]);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt kmem_free(ahci_ctlp->ahcictl_intr_htable, ahci_ctlp->ahcictl_intr_size);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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'.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_put_port_into_notrunning_state(ahci_ctl_t *ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_port_t *ahci_portp, uint8_t port)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t port_cmd_status;
2fcbc377041d659446ded306a92901b4b0753b68yt int loop_count;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(ahci_ctlp->ahcictl_flags & AHCI_QUIESCE ||
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka MUTEX_HELD(&ahci_ctlp->ahcictl_ports[port]->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_put_port_into_notrunning_state enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status &= ~AHCI_CMD_STATUS_ST;
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port), port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Wait until PxCMD.CR is cleared */
2fcbc377041d659446ded306a92901b4b0753b68yt loop_count = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt do {
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status =
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
2fcbc377041d659446ded306a92901b4b0753b68yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (loop_count++ > AHCI_POLLRATE_PORT_IDLE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INIT, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "clearing port %d CMD.CR timeout, "
2fcbc377041d659446ded306a92901b4b0753b68yt "port_cmd_status = 0x%x", port,
2fcbc377041d659446ded306a92901b4b0753b68yt port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * We are effectively timing out after 0.5 sec.
2fcbc377041d659446ded306a92901b4b0753b68yt * This value is specified in AHCI spec.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt /* Wait for 10 millisec */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
2fcbc377041d659446ded306a92901b4b0753b68yt } while (port_cmd_status & AHCI_CMD_STATUS_CR);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_STARTED;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (port_cmd_status & AHCI_CMD_STATUS_CR) {
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 "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "port_cmd_status = 0x%x", loop_count, port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_FAILURE);
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
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 "port_cmd_status = 0x%x", loop_count, port_cmd_status);
2fcbc377041d659446ded306a92901b4b0753b68yt return (AHCI_SUCCESS);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * The fifth argument returns whether the port reset is involved during
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * the process.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *
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)
2fcbc377041d659446ded306a92901b4b0753b68yt *
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 *
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_restart_port_wait_till_ready(ahci_ctl_t *ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_port_t *ahci_portp, uint8_t port, int flag, int *reset_flag)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_sstatus;
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t task_file_status;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_device_t sdevice;
2fcbc377041d659446ded306a92901b4b0753b68yt int rval;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr_port;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_pmult_info_t *pminfo = NULL;
82263d52a84b4a969aa53f8ededddff841646ad9yt int dev_exists_begin = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt int dev_exists_end = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t previous_dev_type = ahci_portp->ahciport_device_type;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int npmport = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint8_t cport = ahci_ctlp->ahcictl_port_to_cport[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_restart_port_wait_till_ready: port %d enter", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_ADDR_SET_PORT(&addr_port, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
0a4c4cec315123d3aa1d87ee8ea976c5501de577Xiao-Yu Zhang if (ahci_portp->ahciport_device_type != SATA_DTYPE_NONE)
82263d52a84b4a969aa53f8ededddff841646ad9yt dev_exists_begin = 1;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* First clear PxCMD.ST */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt rval = ahci_put_port_into_notrunning_state(ahci_ctlp, ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (rval != AHCI_SUCCESS)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto reset;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Then clear PxSERR */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxSERR(ahci_ctlp, port),
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_SERROR_CLEAR_ALL);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Then get PxTFD */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt task_file_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxTFD(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (!(task_file_status & (AHCI_TFD_STS_BSY | AHCI_TFD_STS_DRQ)) &&
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt !(flag & AHCI_PORT_RESET))
2fcbc377041d659446ded306a92901b4b0753b68yt goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytreset:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * If PxTFD.STS.BSY or PxTFD.STS.DRQ is set to '1', then issue
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * a COMRESET to the device
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_disable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rval = ahci_port_reset(ahci_ctlp, ahci_portp, &addr_port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_enable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#ifdef AHCI_DEBUG
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rval != AHCI_SUCCESS)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_restart_port_wait_till_ready: port %d failed",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#endif
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (reset_flag != NULL)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt *reset_flag = 1;
2fcbc377041d659446ded306a92901b4b0753b68yt
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 !(flag & AHCI_RESET_NO_EVENTS_UP)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Set the reset in progress flag */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_reset_in_progress = 1;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt bzero((void *)&sdevice, sizeof (sata_device_t));
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt sdevice.satadev_addr.cport =
09121340f9903b3bd50e1b0efd2087ebccc5d98fyt ahci_ctlp->ahcictl_port_to_cport[port];
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.pmport = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt sdevice.satadev_state = SATA_DSTATE_RESET |
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_DSTATE_PWR_ACTIVE;
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp->ahcictl_sata_hba_tran) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt sata_hba_event_notify(
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_sata_hba_tran->sata_tran_hba_dip,
2fcbc377041d659446ded306a92901b4b0753b68yt &sdevice,
2fcbc377041d659446ded306a92901b4b0753b68yt SATA_EVNT_DEVICE_RESET);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_reset_in_progress = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68ytout:
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* SStatus tells the presence of device. */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sstatus = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSSTS(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (SSTATUS_GET_DET(port_sstatus) == SSTATUS_DET_DEVPRE_PHYCOM) {
82263d52a84b4a969aa53f8ededddff841646ad9yt dev_exists_end = 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_exists_begin == 0 && dev_exists_end == 0) /* 0 -> 0 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Check whether a hot plug event happened */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (dev_exists_begin == 1 && dev_exists_end == 0) { /* 1 -> 0 */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_restart_port_wait_till_ready: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "device is removed", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_NODEV;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_restart_port_wait_till_ready: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "AHCI_PORT_FLAG_NODEV flag is set", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_exit(&ahci_portp->ahciport_mutex);
82263d52a84b4a969aa53f8ededddff841646ad9yt (void) ahci_intr_phyrdy_change(ahci_ctlp, ahci_portp, port);
82263d52a84b4a969aa53f8ededddff841646ad9yt mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* 0/1 -> 1 : device may change */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_ATAPI)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_disable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_find_dev_signature(ahci_ctlp, ahci_portp, &addr_port);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_enable_port_intrs(ahci_ctlp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Following codes are specific for the port multiplier
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (previous_dev_type != SATA_DTYPE_PMULT &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* in case previous_dev_type is corrupt */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_dealloc_pmult(ahci_ctlp, ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (rval);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device change: PMult -> Non-PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (previous_dev_type == SATA_DTYPE_PMULT &&
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_device_type != SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 *
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Force to release pmult resource */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_dealloc_pmult(ahci_ctlp, ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.cport =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_port_to_cport[port];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_state = SATA_DSTATE_RESET |
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_DSTATE_PWR_ACTIVE;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_exit(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_hba_event_notify(
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_dip,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang &sdevice,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_DEVICE_RESET);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang mutex_enter(&ahci_portp->ahciport_mutex);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "Port multiplier is [Gone] at port %d ", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_EVENT, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "port %d sending event up: SATA_EVNT_DEVICE_RESET", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return (AHCI_SUCCESS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device change: Non-PMult -> PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_device_type == SATA_DTYPE_PMULT) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* NOTE: The PxCMD.PMA may be cleared by HBA reset. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_alloc_pmult(ahci_ctlp, ahci_portp);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_start_port(ahci_ctlp, ahci_portp, port);
2fcbc377041d659446ded306a92901b4b0753b68yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang pminfo = ahci_portp->ahciport_pmult_info;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(pminfo != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Device (may) change: PMult -> PMult */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_state = SATA_STATE_READY;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Report reset event. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_reset_in_progress = 1;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang bzero((void *)&sdevice, sizeof (sata_device_t));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.cport = cport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.pmport = SATA_PMULT_HOSTPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sdevice.satadev_addr.qual = SATA_ADDR_PMULT;
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,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang SATA_EVNT_DEVICE_RESET);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (rval);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
2fcbc377041d659446ded306a92901b4b0753b68yt * In all these scenarios, we need to send any pending unfinished
2fcbc377041d659446ded306a92901b4b0753b68yt * commands up to sata framework.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_mop_commands(ahci_ctl_t *ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp,
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t slot_status,
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t failed_tags,
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t timeout_tags,
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t aborted_tags,
2fcbc377041d659446ded306a92901b4b0753b68yt uint32_t reset_tags)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t unfinished_tags = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt int tmp_slot;
2fcbc377041d659446ded306a92901b4b0753b68yt sata_pkt_t *satapkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt int ncq_cmd_in_progress = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt int err_retri_cmd_in_progress = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int rdwr_pmult_cmd_in_progress = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_mop_commands entered: port: %d slot_status: 0x%x",
689d74b0a0dba643450e7fc74a03425c963657e7yt ahci_portp->ahciport_port_num, slot_status);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_ENTRY, ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt "ahci_mop_commands: failed_tags: 0x%x, "
2fcbc377041d659446ded306a92901b4b0753b68yt "timeout_tags: 0x%x aborted_tags: 0x%x, "
2fcbc377041d659446ded306a92901b4b0753b68yt "reset_tags: 0x%x", failed_tags,
2fcbc377041d659446ded306a92901b4b0753b68yt timeout_tags, aborted_tags, reset_tags);
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#ifdef AHCI_DEBUG
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_debug_flags & AHCIDBG_ERRS) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int i;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang char msg_buf[200] = {0, };
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang for (i = 0x1f; i >= 0; i--) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ahci_portp->ahciport_slot_pkts[i] != NULL)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang msg_buf[i] = 'X';
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang msg_buf[i] = '.';
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang msg_buf[0x20] = '\0';
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "port[%d] slots: %s",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_num, msg_buf);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang cmn_err(CE_NOTE, "[ERR-RT] %p [RW-PM] %p ",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)ahci_portp->ahciport_err_retri_pkt,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)ahci_portp->ahciport_rdwr_pmult_pkt);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#endif
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt unfinished_tags = slot_status &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_SLOT_MASK(ahci_ctlp) &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~failed_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~aborted_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~reset_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~timeout_tags;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_cmd_in_progress = 1;
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt unfinished_tags = slot_status &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_NCQ_SLOT_MASK(ahci_portp) &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~failed_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~aborted_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~reset_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~timeout_tags;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt /*
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 *
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 * slot
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt *
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt * Please note that the command is always sent down in Slot 0
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt */
82263d52a84b4a969aa53f8ededddff841646ad9yt err_retri_cmd_in_progress = 1;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_NCQ, ahci_ctlp,
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);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ASSERT(ahci_portp->ahciport_mop_in_progress > 1);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(slot_status == 0x1);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang rdwr_pmult_cmd_in_progress = 1;
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 ahci_portp->ahciport_port_num);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(slot_status == 0x1);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#ifdef AHCI_DEBUG
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);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#endif
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up finished packets with SATA_PKT_COMPLETED */
2fcbc377041d659446ded306a92901b4b0753b68yt while (finished_tags) {
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(finished_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INFO, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_COMPLETED",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt CLEAR_BIT(finished_tags, tmp_slot);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt aborted_tags |= tmp_slot;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt continue;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(finished_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_COMPLETED);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up failed packets with SATA_PKT_DEV_ERROR. */
2fcbc377041d659446ded306a92901b4b0753b68yt while (failed_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (err_retri_cmd_in_progress) {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(failed_tags == 0x1);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
82263d52a84b4a969aa53f8ededddff841646ad9yt (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
82263d52a84b4a969aa53f8ededddff841646ad9yt break;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rdwr_pmult_cmd_in_progress) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(satapkt != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_DEV_ERROR",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(failed_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_DEV_ERROR",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(failed_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_DEV_ERROR);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up timeout packets with SATA_PKT_TIMEOUT. */
2fcbc377041d659446ded306a92901b4b0753b68yt while (timeout_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (err_retri_cmd_in_progress) {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(timeout_tags == 0x1);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
82263d52a84b4a969aa53f8ededddff841646ad9yt (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
82263d52a84b4a969aa53f8ededddff841646ad9yt break;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rdwr_pmult_cmd_in_progress) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(satapkt != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_TIMEOUT",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(timeout_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_TIMEOUT",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(timeout_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_TIMEOUT);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up aborted packets with SATA_PKT_ABORTED */
2fcbc377041d659446ded306a92901b4b0753b68yt while (aborted_tags) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (err_retri_cmd_in_progress) {
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(satapkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(aborted_tags == 0x1);
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
82263d52a84b4a969aa53f8ededddff841646ad9yt "sending up pkt 0x%p with SATA_PKT_ABORTED",
82263d52a84b4a969aa53f8ededddff841646ad9yt (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
82263d52a84b4a969aa53f8ededddff841646ad9yt break;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rdwr_pmult_cmd_in_progress) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(satapkt != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(aborted_tags == 0x1);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_ABORTED",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(aborted_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_ABORTED",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(aborted_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_ABORTED);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up reset packets with SATA_PKT_RESET. */
2fcbc377041d659446ded306a92901b4b0753b68yt while (reset_tags) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (rdwr_pmult_cmd_in_progress) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang satapkt = ahci_portp->ahciport_rdwr_pmult_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(satapkt != NULL);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(aborted_tags == 0x1);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "ahci_mop_commands: sending up "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "rdwr pmult pkt 0x%p with SATA_PKT_RESET",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void *)satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(reset_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
2fcbc377041d659446ded306a92901b4b0753b68yt "sending up pkt 0x%p with SATA_PKT_RESET",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(reset_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Send up unfinished packets with SATA_PKT_RESET */
2fcbc377041d659446ded306a92901b4b0753b68yt while (unfinished_tags) {
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(unfinished_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt satapkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
2fcbc377041d659446ded306a92901b4b0753b68yt ASSERT(satapkt != NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp, "ahci_mop_commands: "
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "sending up pkt 0x%p with SATA_PKT_RESET",
2fcbc377041d659446ded306a92901b4b0753b68yt (void *)satapkt);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ncq_cmd_in_progress)
82263d52a84b4a969aa53f8ededddff841646ad9yt CLEAR_BIT(ahci_portp->ahciport_pending_ncq_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(ahci_portp->ahciport_pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(unfinished_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp->ahciport_slot_pkts[tmp_slot] = NULL;
2fcbc377041d659446ded306a92901b4b0753b68yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_add_doneq(ahci_portp, satapkt, SATA_PKT_RESET);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress--;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ASSERT(ahci_portp->ahciport_mop_in_progress >= 0);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_mop_in_progress == 0)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_MOPPING;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_flush_doneq(ahci_portp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt/*
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.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic uint32_t
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_get_rdlogext_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt uint8_t port)
82263d52a84b4a969aa53f8ededddff841646ad9yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_device_t sdevice;
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_pkt_t *rdlog_spkt, *spkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ddi_dma_handle_t buf_dma_handle;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
82263d52a84b4a969aa53f8ededddff841646ad9yt int loop_count;
82263d52a84b4a969aa53f8ededddff841646ad9yt int rval;
82263d52a84b4a969aa53f8ededddff841646ad9yt int failed_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t failed_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt struct sata_ncq_error_recovery_page *ncq_err_page;
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_NCQ, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_get_rdlogext_data enter: port %d", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Prepare the sdevice data */
82263d52a84b4a969aa53f8ededddff841646ad9yt bzero((void *)&sdevice, sizeof (sata_device_t));
82263d52a84b4a969aa53f8ededddff841646ad9yt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
82263d52a84b4a969aa53f8ededddff841646ad9yt sdevice.satadev_addr.pmport = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Translate sata_device.satadev_addr -> ahci_addr */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &sdevice, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Call the sata hba interface to get a rdlog spkt
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt loop_count = 0;
82263d52a84b4a969aa53f8ededddff841646ad9ytloop:
82263d52a84b4a969aa53f8ededddff841646ad9yt rdlog_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
82263d52a84b4a969aa53f8ededddff841646ad9yt &sdevice, SATA_ERR_RETR_PKT_TYPE_NCQ);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (rdlog_spkt == NULL) {
82263d52a84b4a969aa53f8ededddff841646ad9yt if (loop_count++ < AHCI_POLLRATE_GET_SPKT) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Sleep for a while */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
82263d52a84b4a969aa53f8ededddff841646ad9yt goto loop;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Timed out after 1s */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "failed to get rdlog spkt for port %d", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt return (failed_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(rdlog_spkt->satapkt_op_mode & SATA_OPMODE_SYNCH);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RDLOGEXT;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * This start is not supposed to fail because after port is restarted,
82263d52a84b4a969aa53f8ededddff841646ad9yt * the whole command list is empty.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_err_retri_pkt = rdlog_spkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr, rdlog_spkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_err_retri_pkt = NULL;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Remove the flag after READ LOG EXT command is completed */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RDLOGEXT;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (rdlog_spkt->satapkt_reason == SATA_PKT_COMPLETED) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Update the request log data */
82263d52a84b4a969aa53f8ededddff841646ad9yt buf_dma_handle = *(ddi_dma_handle_t *)
82263d52a84b4a969aa53f8ededddff841646ad9yt (rdlog_spkt->satapkt_cmd.satacmd_err_ret_buf_handle);
82263d52a84b4a969aa53f8ededddff841646ad9yt rval = ddi_dma_sync(buf_dma_handle, 0, 0,
82263d52a84b4a969aa53f8ededddff841646ad9yt DDI_DMA_SYNC_FORKERNEL);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (rval == DDI_SUCCESS) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_err_page =
82263d52a84b4a969aa53f8ededddff841646ad9yt (struct sata_ncq_error_recovery_page *)rdlog_spkt->
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt_cmd.satacmd_bp->b_un.b_addr;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Get the failed tag */
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_slot = ncq_err_page->ncq_tag;
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_get_rdlogext_data: port %d "
82263d52a84b4a969aa53f8ededddff841646ad9yt "failed slot %d", port, failed_slot);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (failed_slot & NQ) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "the failed slot is not a valid tag", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_slot &= NCQ_TAG_MASK;
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_get_rdlogext_data: failed spkt 0x%p",
82263d52a84b4a969aa53f8ededddff841646ad9yt (void *)spkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt if (spkt == NULL) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "the failed slot spkt is NULL", NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_tags = 0x1 << failed_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Fill out the error context */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_copy_ncq_err_page(&spkt->satapkt_cmd,
82263d52a84b4a969aa53f8ededddff841646ad9yt ncq_err_page);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_update_sata_registers(ahci_ctlp, port,
82263d52a84b4a969aa53f8ededddff841646ad9yt &spkt->satapkt_device);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9ytout:
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_free_error_retrieval_pkt(rdlog_spkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt return (failed_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt}
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_get_rqsense_data(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint8_t port, sata_pkt_t *spkt)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_device_t sdevice;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_pkt_t *rs_spkt;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_cmd_t *sata_cmd;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ddi_dma_handle_t buf_dma_handle;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int loop_count;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt struct scsi_extended_sense *rqsense;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_get_rqsense_data enter: port %d", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Prepare the sdevice data */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt bzero((void *)&sdevice, sizeof (sata_device_t));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.cport = ahci_ctlp->ahcictl_port_to_cport[port];
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sdevice.satadev_addr.pmport = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Translate sata_device.satadev_addr -> ahci_addr */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_get_ahci_addr(ahci_ctlp, &sdevice, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_cmd = &spkt->satapkt_cmd;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Call the sata hba interface to get a rs spkt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt loop_count = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytloop:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt rs_spkt = sata_get_error_retrieval_pkt(ahci_ctlp->ahcictl_dip,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt &sdevice, SATA_ERR_RETR_PKT_TYPE_ATAPI);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (rs_spkt == NULL) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (loop_count++ < AHCI_POLLRATE_GET_SPKT) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Sleep for a while */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_10MS_USECS);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto loop;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Timed out after 1s */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "failed to get rs spkt for port %d", port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt return;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ASSERT(rs_spkt->satapkt_op_mode & SATA_OPMODE_SYNCH);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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 */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_RQSENSE;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * This start is not supposed to fail because after port is restarted,
82263d52a84b4a969aa53f8ededddff841646ad9yt * the whole command list is empty.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_err_retri_pkt = rs_spkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_do_sync_start(ahci_ctlp, ahci_portp, &addr, rs_spkt);
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_err_retri_pkt = NULL;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Remove the flag after REQUEST SENSE command is completed */
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_flags &= ~AHCI_PORT_FLAG_RQSENSE;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (rs_spkt->satapkt_reason == SATA_PKT_COMPLETED) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Update the request sense data */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt buf_dma_handle = *(ddi_dma_handle_t *)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (rs_spkt->satapkt_cmd.satacmd_err_ret_buf_handle);
82263d52a84b4a969aa53f8ededddff841646ad9yt (void) ddi_dma_sync(buf_dma_handle, 0, 0,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt DDI_DMA_SYNC_FORKERNEL);
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Copy the request sense data */
82263d52a84b4a969aa53f8ededddff841646ad9yt bcopy(rs_spkt->
82263d52a84b4a969aa53f8ededddff841646ad9yt satapkt_cmd.satacmd_bp->b_un.b_addr,
82263d52a84b4a969aa53f8ededddff841646ad9yt &sata_cmd->satacmd_rqsense,
82263d52a84b4a969aa53f8ededddff841646ad9yt SATA_ATAPI_MIN_RQSENSE_LEN);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
82263d52a84b4a969aa53f8ededddff841646ad9yt rqsense = (struct scsi_extended_sense *)
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_cmd->satacmd_rqsense;
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Dump the sense data */
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp, "\n", NULL);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "Sense data for satapkt %p ATAPI cmd 0x%x",
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt, sata_cmd->satacmd_acdb[0]);
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_SENSEDATA, ahci_ctlp,
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",
82263d52a84b4a969aa53f8ededddff841646ad9yt rqsense->es_code, rqsense->es_class,
82263d52a84b4a969aa53f8ededddff841646ad9yt rqsense->es_key, rqsense->es_add_code,
82263d52a84b4a969aa53f8ededddff841646ad9yt rqsense->es_qual_code);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_free_error_retrieval_pkt(rs_spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
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 *
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 *
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * And software will complete the command that had the error with error mark
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * to higher level software.
2fcbc377041d659446ded306a92901b4b0753b68yt *
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
2fcbc377041d659446ded306a92901b4b0753b68yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_fatal_error_recovery_handler(ahci_ctl_t *ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_port_t *ahci_portp, ahci_addr_t *addrp, uint32_t intr_status)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_cmd_status;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t failed_tags = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int failed_slot;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int reset_flag = 0, flag = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_fis_d2h_register_t *ahci_rcvd_fisp;
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_cmd_t *sata_cmd = NULL;
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_pkt_t *spkt = NULL;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#if AHCI_DEBUG
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China ahci_cmd_header_t *cmd_header;
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#endif
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China uint8_t port = addrp->aa_port;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int rval;
2fcbc377041d659446ded306a92901b4b0753b68yt
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_fatal_error_recovery_handler enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 port, intr_status);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Force a port reset */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang flag = AHCI_PORT_RESET;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
82263d52a84b4a969aa53f8ededddff841646ad9yt ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxCI to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Read PxCMD.CCS to determine the slot that the HBA
82263d52a84b4a969aa53f8ededddff841646ad9yt * was processing when the error occurred.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_slot = (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_CMD_STATUS_CCS_SHIFT;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt = ahci_portp->ahciport_err_retri_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(spkt != NULL);
82263d52a84b4a969aa53f8ededddff841646ad9yt } else {
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt = ahci_portp->ahciport_slot_pkts[failed_slot];
82263d52a84b4a969aa53f8ededddff841646ad9yt if (spkt == NULL) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* May happen when interface errors occur? */
82263d52a84b4a969aa53f8ededddff841646ad9yt goto next;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#if AHCI_DEBUG
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China /*
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China * Debugging purpose...
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China */
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China if (ahci_portp->ahciport_prd_bytecounts[failed_slot]) {
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China cmd_header =
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China &ahci_portp->ahciport_cmd_list[failed_slot];
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
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]);
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China }
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China#endif
385470574fb49e32c324af06c01d697a16cc3c4bying tian - Beijing China
82263d52a84b4a969aa53f8ededddff841646ad9yt sata_cmd = &spkt->satapkt_cmd;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Fill out the status and error registers for PxIS.TFES */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (intr_status & AHCI_INTR_STATUS_TFES) {
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_rcvd_fisp = &(ahci_portp->ahciport_rcvd_fis->
82263d52a84b4a969aa53f8ededddff841646ad9yt ahcirf_d2h_register_fis);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Copy the error context back to the sata_cmd */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_copy_err_cnxt(sata_cmd, ahci_rcvd_fisp);
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* The failed command must be one of the outstanding commands */
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_tags = 0x1 << failed_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(failed_tags & slot_status);
82263d52a84b4a969aa53f8ededddff841646ad9yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Update the sata registers, especially PxSERR register */
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_update_sata_registers(ahci_ctlp, port,
82263d52a84b4a969aa53f8ededddff841646ad9yt &spkt->satapkt_device);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxSACT to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytnext:
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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 */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_fatal_error_recovery_handler: port %d REQUEST SENSE "
82263d52a84b4a969aa53f8ededddff841646ad9yt "command or READ LOG EXT command for error data retrieval "
82263d52a84b4a969aa53f8ededddff841646ad9yt "failed", port);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(slot_status == 0x1);
f8a673ad9145b262edb65a98fb3fb92027d23a05ying tian - Beijing China ASSERT(failed_slot == 0);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(spkt->satapkt_cmd.satacmd_acdb[0] ==
82263d52a84b4a969aa53f8ededddff841646ad9yt SCMD_REQUEST_SENSE ||
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt->satapkt_cmd.satacmd_cmd_reg ==
82263d52a84b4a969aa53f8ededddff841646ad9yt SATAC_READ_LOG_EXT);
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China rval = ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, flag, &reset_flag);
2fcbc377041d659446ded306a92901b4b0753b68yt
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 if (rval == AHCI_SUCCESS)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: error recovery for port %d "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "succeed", instance, port);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China else
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: error recovery for port %d "
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China "failed", instance, port);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China }
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (reset_flag ||
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_device_type == SATA_DTYPE_NONE ||
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt && spkt->satapkt_cmd.satacmd_cmd_reg == SATAC_ID_DEVICE ||
82263d52a84b4a969aa53f8ededddff841646ad9yt ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto out;
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt /*
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.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt failed_tags = ahci_get_rdlogext_data(ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp, port);
82263d52a84b4a969aa53f8ededddff841646ad9yt goto out;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
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);
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytout:
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
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",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, slot_status, ahci_portp->ahciport_pending_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags, failed_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status,
2fcbc377041d659446ded306a92901b4b0753b68yt failed_tags, /* failed tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* timeout tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0, /* aborted tags */
2fcbc377041d659446ded306a92901b4b0753b68yt 0); /* reset tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 *
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Currently code is neither completed nor tested.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void
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)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#ifndef __lock_lint
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang _NOTE(ARGUNUSED(intr_status))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang#endif
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang uint32_t port_fbs_ctrl;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang int loop_count = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
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 return;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (!(port_fbs_ctrl & AHCI_FBS_EN))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* FBS is not enabled. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Problem's getting complicated now. */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
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 */
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
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* Refer to spec(v1.2) 9.3.6.1 */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (port_fbs_ctrl & AHCI_FBS_SDE) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCIDBG(AHCIDBG_ERRS, ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "A Device Sepcific Error: port %d", port);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Controller has paused commands for all other
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * sub-devices until PxFBS.DEC is set.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_reject_all_abort_pkts(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, 0);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ddi_put32(ahci_ctlp->ahcictl_ahci_acc_handle,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (uint32_t *)AHCI_PORT_PxFBS(ahci_ctlp, port),
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_fbs_ctrl | AHCI_FBS_DEC);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Wait controller clear PxFBS.DEC,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * then we can continue.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang loop_count = 0;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang do {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port_fbs_ctrl = ddi_get32(ahci_ctlp->
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahcictl_ahci_acc_handle, (uint32_t *)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang AHCI_PORT_PxFBS(ahci_ctlp, port));
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (loop_count++ > 1000)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Esclate the error. Follow
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * non-device specific error
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * procedure.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang return;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang drv_usecwait(AHCI_100US_USECS);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } while (port_fbs_ctrl & AHCI_FBS_DEC);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /*
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * Issue a software reset to ensure drive is in
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang * a known state.
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang (void) ahci_software_reset(ahci_ctlp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp, &addr);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
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.");
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Handle events - fatal error recovery
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_events_handler(void *args)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_event_arg_t *ahci_event_arg;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctl_t *ahci_ctlp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_port_t *ahci_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *addrp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t event;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int instance;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_event_arg = (ahci_event_arg_t *)args;
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_ctlp = ahci_event_arg->ahciea_ctlp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp = ahci_event_arg->ahciea_portp;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp = ahci_event_arg->ahciea_addrp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt event = ahci_event_arg->ahciea_event;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR|AHCIDBG_ERRS, ahci_ctlp,
82263d52a84b4a969aa53f8ededddff841646ad9yt "ahci_events_handler enter: port %d intr_status = 0x%x",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_num, event);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_intr_phyrdy_change() may have rendered it to
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * SATA_DTYPE_NONE.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY|AHCIDBG_INTR, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_events_handler: port %d no device attached, "
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang "and just return without doing anything",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_portp->ahciport_port_num);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
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);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China }
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto out;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (event & (AHCI_INTR_STATUS_IFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBDS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_HBFS |
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt AHCI_INTR_STATUS_TFES))
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_fatal_error_recovery_handler(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang addrp, event);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytout:
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * ahci_watchdog_handler() and ahci_do_sync_start will call us if they
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * detect there are some commands which are timed out.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_timeout_pkts(ahci_ctl_t *ahci_ctlp, ahci_port_t *ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt uint8_t port, uint32_t tmp_timeout_tags)
2fcbc377041d659446ded306a92901b4b0753b68yt{
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t slot_status = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t finished_tags = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t timeout_tags = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_ENTRY, ahci_ctlp,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt "ahci_timeout_pkts enter: port %d", port);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp) ||
82263d52a84b4a969aa53f8ededddff841646ad9yt ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxCI to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxCI(ahci_ctlp, port));
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt /* Read PxSACT to see which commands are still outstanding */
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68yt /*
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.
2fcbc377041d659446ded306a92901b4b0753b68yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp)) {
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",
82263d52a84b4a969aa53f8ededddff841646ad9yt tmp_timeout_tags, slot_status,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_portp->ahciport_pending_ncq_tags);
82263d52a84b4a969aa53f8ededddff841646ad9yt ASSERT(slot_status == 0x1);
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",
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang tmp_timeout_tags, slot_status);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ASSERT(slot_status == 0x1);
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt#endif
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_flags |= AHCI_PORT_FLAG_MOPPING;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt ahci_portp->ahciport_mop_in_progress++;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) ahci_restart_port_wait_till_ready(ahci_ctlp, ahci_portp,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang port, AHCI_PORT_RESET, NULL);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * Re-identify timeout tags because some previously checked commands
2fcbc377041d659446ded306a92901b4b0753b68yt * could already complete.
2fcbc377041d659446ded306a92901b4b0753b68yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_SLOT_MASK(ahci_ctlp);
82263d52a84b4a969aa53f8ededddff841646ad9yt timeout_tags = tmp_timeout_tags & ~finished_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_TIMEOUT, ahci_ctlp,
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 port, finished_tags, timeout_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status, ahci_portp->ahciport_pending_tags);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt finished_tags = ahci_portp->ahciport_pending_ncq_tags &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~slot_status & AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt timeout_tags = tmp_timeout_tags & ~finished_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_TIMEOUT|AHCIDBG_NCQ, ahci_ctlp,
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 ",
82263d52a84b4a969aa53f8ededddff841646ad9yt port, finished_tags, timeout_tags,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status, ahci_portp->ahciport_pending_ncq_tags);
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang } else if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt timeout_tags = tmp_timeout_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_mop_commands(ahci_ctlp,
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt slot_status,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* failed tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang timeout_tags, /* timeout tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0, /* aborted tags */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang 0); /* reset tags */
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Watchdog handler kicks in every 5 seconds to timeout any commands pending
2fcbc377041d659446ded306a92901b4b0753b68yt * for long time.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_watchdog_handler(ahci_ctl_t *ahci_ctlp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_port_t *ahci_portp;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt sata_pkt_t *spkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t pending_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t timeout_tags;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t port_cmd_status;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t port_sactive;
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t port;
2fcbc377041d659446ded306a92901b4b0753b68yt int tmp_slot;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt int current_slot;
82263d52a84b4a969aa53f8ededddff841646ad9yt uint32_t current_tags;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ENTRY, ahci_ctlp,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci_watchdog_handler entered", NULL);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_portp = ahci_ctlp->ahcictl_ports[port];
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_portp->ahciport_device_type == SATA_DTYPE_NONE) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt continue;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /* Skip the check for those ports in error recovery */
82263d52a84b4a969aa53f8ededddff841646ad9yt if ((ahci_portp->ahciport_flags & AHCI_PORT_FLAG_MOPPING) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt !(ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt mutex_exit(&ahci_portp->ahciport_mutex);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt continue;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt pending_tags = 0;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt port_cmd_status = ddi_get32(ahci_ctlp->ahcictl_ahci_acc_handle,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt (uint32_t *)AHCI_PORT_PxCMD(ahci_ctlp, port));
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp) ||
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt current_slot = 0;
82263d52a84b4a969aa53f8ededddff841646ad9yt pending_tags = 0x1;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt current_slot =
82263d52a84b4a969aa53f8ededddff841646ad9yt (port_cmd_status & AHCI_CMD_STATUS_CCS) >>
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_CMD_STATUS_CCS_SHIFT;
82263d52a84b4a969aa53f8ededddff841646ad9yt pending_tags = ahci_portp->ahciport_pending_tags;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
82263d52a84b4a969aa53f8ededddff841646ad9yt port_sactive = ddi_get32(
82263d52a84b4a969aa53f8ededddff841646ad9yt ahci_ctlp->ahcictl_ahci_acc_handle,
82263d52a84b4a969aa53f8ededddff841646ad9yt (uint32_t *)AHCI_PORT_PxSACT(ahci_ctlp, port));
82263d52a84b4a969aa53f8ededddff841646ad9yt current_tags = port_sactive &
82263d52a84b4a969aa53f8ededddff841646ad9yt ~port_cmd_status &
82263d52a84b4a969aa53f8ededddff841646ad9yt AHCI_NCQ_SLOT_MASK(ahci_portp);
82263d52a84b4a969aa53f8ededddff841646ad9yt pending_tags = ahci_portp->ahciport_pending_ncq_tags;
82263d52a84b4a969aa53f8ededddff841646ad9yt }
82263d52a84b4a969aa53f8ededddff841646ad9yt
2fcbc377041d659446ded306a92901b4b0753b68yt timeout_tags = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt while (pending_tags) {
2fcbc377041d659446ded306a92901b4b0753b68yt tmp_slot = ddi_ffs(pending_tags) - 1;
2fcbc377041d659446ded306a92901b4b0753b68yt if (tmp_slot == -1) {
2fcbc377041d659446ded306a92901b4b0753b68yt break;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (ERR_RETRI_CMD_IN_PROGRESS(ahci_portp))
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt = ahci_portp->ahciport_err_retri_pkt;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang else if (RDWR_PMULT_CMD_IN_PROGRESS(ahci_portp))
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang spkt = ahci_portp->ahciport_rdwr_pmult_pkt;
82263d52a84b4a969aa53f8ededddff841646ad9yt else
82263d52a84b4a969aa53f8ededddff841646ad9yt spkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if ((spkt != NULL) && spkt->satapkt_time &&
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt !(spkt->satapkt_op_mode & SATA_OPMODE_POLLING)) {
2fcbc377041d659446ded306a92901b4b0753b68yt /*
2fcbc377041d659446ded306a92901b4b0753b68yt * If a packet has survived for more than it's
2fcbc377041d659446ded306a92901b4b0753b68yt * max life cycles, it is a candidate for time
2fcbc377041d659446ded306a92901b4b0753b68yt * out.
2fcbc377041d659446ded306a92901b4b0753b68yt */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout[tmp_slot] -=
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_watchdog_timeout;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (ahci_portp->ahciport_slot_timeout[tmp_slot]
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China > 0)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt goto next;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China#if AHCI_DEBUG
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China if (NCQ_CMD_IN_PROGRESS(ahci_portp)) {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp, "watchdog: the current "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "tags is 0x%x", current_tags);
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China } else {
f5f2d263454d943a366844932bdb677530ba733bFred Herard AHCIDBG(AHCIDBG_ERRS|AHCIDBG_TIMEOUT,
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China ahci_ctlp, "watchdog: the current "
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China "slot is %d", current_slot);
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China }
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China#endif
259105bc352a464b4cdf3f424b5575e5e5e3f247ying tian - Beijing China
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt /*
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.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
82263d52a84b4a969aa53f8ededddff841646ad9yt if (NON_NCQ_CMD_IN_PROGRESS(ahci_portp) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt (tmp_slot != current_slot) ||
82263d52a84b4a969aa53f8ededddff841646ad9yt NCQ_CMD_IN_PROGRESS(ahci_portp) &&
82263d52a84b4a969aa53f8ededddff841646ad9yt ((0x1 << tmp_slot) & current_tags)) {
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_slot_timeout \
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China [tmp_slot] = spkt->satapkt_time;
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt } else {
2fcbc377041d659446ded306a92901b4b0753b68yt timeout_tags |= (0x1 << tmp_slot);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(CE_WARN, "!ahci%d: watchdog "
2fcbc377041d659446ded306a92901b4b0753b68yt "port %d satapkt 0x%p timed out\n",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port, (void *)spkt);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytnext:
2fcbc377041d659446ded306a92901b4b0753b68yt CLEAR_BIT(pending_tags, tmp_slot);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt if (timeout_tags) {
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_timeout_pkts(ahci_ctlp, ahci_portp,
82263d52a84b4a969aa53f8ededddff841646ad9yt port, timeout_tags);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_portp->ahciport_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt /* Re-install the watchdog timeout handler */
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp->ahcictl_timeout_id != 0) {
2fcbc377041d659446ded306a92901b4b0753b68yt ahci_ctlp->ahcictl_timeout_id =
2fcbc377041d659446ded306a92901b4b0753b68yt timeout((void (*)(void *))ahci_watchdog_handler,
2fcbc377041d659446ded306a92901b4b0753b68yt (caddr_t)ahci_ctlp, ahci_watchdog_tick);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_ctlp->ahcictl_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Fill the error context into sata_cmd for non-queued command error.
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt */
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_copy_err_cnxt(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_status_reg = GET_RFIS_STATUS(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_error_reg = GET_RFIS_ERROR(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_low_lsb = GET_RFIS_CYL_LOW(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_mid_lsb = GET_RFIS_CYL_MID(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_high_lsb = GET_RFIS_CYL_HI(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_device_reg = GET_RFIS_DEV_HEAD(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (scmd->satacmd_addr_type == ATA_ADDR_LBA48) {
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_low_msb = GET_RFIS_CYL_LOW_EXP(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_mid_msb = GET_RFIS_CYL_MID_EXP(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt scmd->satacmd_lba_high_msb = GET_RFIS_CYL_HI_EXP(rfisp);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt }
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
82263d52a84b4a969aa53f8ededddff841646ad9yt/*
82263d52a84b4a969aa53f8ededddff841646ad9yt * Fill the ncq error page into sata_cmd for queued command error.
82263d52a84b4a969aa53f8ededddff841646ad9yt */
82263d52a84b4a969aa53f8ededddff841646ad9ytstatic void
82263d52a84b4a969aa53f8ededddff841646ad9ytahci_copy_ncq_err_page(sata_cmd_t *scmd,
82263d52a84b4a969aa53f8ededddff841646ad9yt struct sata_ncq_error_recovery_page *ncq_err_page)
82263d52a84b4a969aa53f8ededddff841646ad9yt{
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_mid_lsb = ncq_err_page->ncq_cyl_low;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_high_msb = ncq_err_page->ncq_cyl_high_ext;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_lba_high_lsb = ncq_err_page->ncq_cyl_high;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_device_reg = ncq_err_page->ncq_dev_head;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_status_reg = ncq_err_page->ncq_status;
82263d52a84b4a969aa53f8ededddff841646ad9yt scmd->satacmd_error_reg = ncq_err_page->ncq_error;
82263d52a84b4a969aa53f8ededddff841646ad9yt}
82263d52a84b4a969aa53f8ededddff841646ad9yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt/*
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt * Put the respective register value to sata_cmd_t for satacmd_flags.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_copy_out_regs(sata_cmd_t *scmd, ahci_fis_d2h_register_t *rfisp)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_sec_count_msb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_sec_count_msb = GET_RFIS_SECTOR_COUNT_EXP(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_low_msb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_low_msb = GET_RFIS_CYL_LOW_EXP(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_mid_msb = GET_RFIS_CYL_MID_EXP(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_high_msb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_high_msb = GET_RFIS_CYL_HI_EXP(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_sec_count_lsb = GET_RFIS_SECTOR_COUNT(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_low_lsb = GET_RFIS_CYL_LOW(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_mid_lsb = GET_RFIS_CYL_MID(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_lba_high_lsb = GET_RFIS_CYL_HI(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_device_reg)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_device_reg = GET_RFIS_DEV_HEAD(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt if (scmd->satacmd_flags.sata_copy_out_error_reg)
2fcbc377041d659446ded306a92901b4b0753b68yt scmd->satacmd_error_reg = GET_RFIS_ERROR(rfisp);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_log_fatal_error_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt uint32_t intr_status)
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt{
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt int instance = ddi_get_instance(ahci_ctlp->ahcictl_dip);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_IFS)
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has interface fatal "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "error", instance, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_HBDS)
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has bus data error",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_HBFS)
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has bus fatal error",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt if (intr_status & AHCI_INTR_STATUS_TFES)
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d has task file error",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt instance, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci%d: ahci port %d is trying to do error "
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "recovery", instance, port);
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt}
68d33a2562b5b41e4606c8b0f50f32fd26b05302yt
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing Chinastatic void
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing Chinaahci_dump_commands(ahci_ctl_t *ahci_ctlp, uint8_t port,
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China uint32_t slot_tags)
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China{
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_port_t *ahci_portp;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China int tmp_slot;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China sata_pkt_t *spkt;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China sata_cmd_t cmd;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ahci_portp = ahci_ctlp->ahcictl_ports[port];
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ASSERT(ahci_portp != NULL);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China while (slot_tags) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China tmp_slot = ddi_ffs(slot_tags) - 1;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (tmp_slot == -1) {
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China break;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China }
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China spkt = ahci_portp->ahciport_slot_pkts[tmp_slot];
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China ASSERT(spkt != NULL);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China cmd = spkt->satapkt_cmd;
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
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)));
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China CLEAR_BIT(slot_tags, tmp_slot);
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China }
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China}
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * Dump the serror message to the log.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
68d33a2562b5b41e4606c8b0f50f32fd26b05302ytahci_log_serror_message(ahci_ctl_t *ahci_ctlp, uint8_t port,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt uint32_t port_serror, int debug_only)
2fcbc377041d659446ded306a92901b4b0753b68yt{
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt static char err_buf[512];
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt static char err_msg_header[16];
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt char *err_msg = err_buf;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt *err_buf = '\0';
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt *err_msg_header = '\0';
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_DATA_ERR_FIXED) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tRecovered Data Integrity Error (I)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_COMM_ERR_FIXED) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tRecovered Communication Error (M)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_DATA_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tTransient Data Integrity Error (T)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_PERSISTENT_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tPersistent Communication or Data Integrity Error (C)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_PROTOCOL_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tProtocol Error (P)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_INT_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tInternal Error (E)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_PHY_RDY_CHG) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tPhyRdy Change (N)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_PHY_INT_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tPhy Internal Error (I)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_COMM_WAKE) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tComm Wake (W)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_10B_TO_8B_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\t10B to 8B Decode Error (B)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_DISPARITY_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tDisparity Error (D)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_CRC_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tCRC Error (C)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_HANDSHAKE_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tHandshake Error (H)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_LINK_SEQ_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tLink Sequence Error (S)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_TRANS_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg,
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt "\tTransport state transition error (T)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_FIS_TYPE) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tUnknown FIS Type (F)\n");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
82263d52a84b4a969aa53f8ededddff841646ad9yt if (port_serror & SERROR_EXCHANGED_ERR) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg = strcat(err_msg, "\tExchanged (X)\n");
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt }
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
3f022900c8601032b760c39b43b73a059a2d9f64ying tian - Beijing China if (*err_msg == '\0')
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt return;
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt if (debug_only) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt (void) sprintf(err_msg_header, "port %d", port);
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",
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt ddi_get_instance(ahci_ctlp->ahcictl_dip),
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt err_msg_header, err_msg);
f5f2d263454d943a366844932bdb677530ba733bFred Herard
f5f2d263454d943a366844932bdb677530ba733bFred Herard /* sata trace debug */
f5f2d263454d943a366844932bdb677530ba733bFred Herard sata_trace_debug(ahci_ctlp->ahcictl_dip,
f5f2d263454d943a366844932bdb677530ba733bFred Herard "ahci%d: %s %s", ddi_get_instance(ahci_ctlp->ahcictl_dip),
f5f2d263454d943a366844932bdb677530ba733bFred Herard err_msg_header, err_msg);
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt } else {
7095af1983f107c8b16839f70101fdf710c4e620ying tian - Beijing China cmn_err(CE_WARN, "!ahci: %s %s", err_msg_header, err_msg);
f5f2d263454d943a366844932bdb677530ba733bFred Herard
f5f2d263454d943a366844932bdb677530ba733bFred Herard /* sata trace debug */
f5f2d263454d943a366844932bdb677530ba733bFred Herard sata_trace_debug(NULL, "ahci: %s %s", err_msg_header, err_msg);
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang/*
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 Zhang */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangstatic void
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhangahci_get_ahci_addr(ahci_ctl_t *ahci_ctlp, sata_device_t *sd,
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addr_t *ahci_addrp)
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang{
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang sata_address_t *sata_addrp = &sd->satadev_addr;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_port =
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_ctlp->ahcictl_cport_to_port[sata_addrp->cport];
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_pmport = sata_addrp->pmport;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang switch (sata_addrp->qual) {
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_DCPORT:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_CPORT:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_qual = AHCI_ADDR_PORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_PMULT:
918304a3bd962ac065ad520336a044d94b40ad16Xiao-Yu Zhang case SATA_ADDR_PMULT_SPEC:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_qual = AHCI_ADDR_PMULT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_DPMPORT:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_PMPORT:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_qual = AHCI_ADDR_PMPORT;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang case SATA_ADDR_NULL:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang default:
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang /* something went wrong */
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang ahci_addrp->aa_qual = AHCI_ADDR_NULL;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang break;
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang }
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang}
8aa6aadbbfba50077655c6a46a5e269c880e4ab4Xiao-Yu Zhang
2fcbc377041d659446ded306a92901b4b0753b68yt/*
2fcbc377041d659446ded306a92901b4b0753b68yt * This routine is to calculate the total number of ports implemented
2fcbc377041d659446ded306a92901b4b0753b68yt * by the HBA.
2fcbc377041d659446ded306a92901b4b0753b68yt */
2fcbc377041d659446ded306a92901b4b0753b68ytstatic int
2fcbc377041d659446ded306a92901b4b0753b68ytahci_get_num_implemented_ports(uint32_t ports_implemented)
2fcbc377041d659446ded306a92901b4b0753b68yt{
2fcbc377041d659446ded306a92901b4b0753b68yt uint8_t i;
2fcbc377041d659446ded306a92901b4b0753b68yt int num = 0;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt for (i = 0; i < AHCI_MAX_PORTS; i++) {
2fcbc377041d659446ded306a92901b4b0753b68yt if (((uint32_t)0x1 << i) & ports_implemented)
2fcbc377041d659446ded306a92901b4b0753b68yt num++;
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt return (num);
2fcbc377041d659446ded306a92901b4b0753b68yt}
2fcbc377041d659446ded306a92901b4b0753b68yt
689d74b0a0dba643450e7fc74a03425c963657e7yt#if AHCI_DEBUG
2fcbc377041d659446ded306a92901b4b0753b68ytstatic void
2fcbc377041d659446ded306a92901b4b0753b68ytahci_log(ahci_ctl_t *ahci_ctlp, uint_t level, char *fmt, ...)
2fcbc377041d659446ded306a92901b4b0753b68yt{
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt static char name[16];
2fcbc377041d659446ded306a92901b4b0753b68yt va_list ap;
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_enter(&ahci_log_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt va_start(ap, fmt);
2fcbc377041d659446ded306a92901b4b0753b68yt if (ahci_ctlp) {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt (void) sprintf(name, "ahci%d: ",
2fcbc377041d659446ded306a92901b4b0753b68yt ddi_get_instance(ahci_ctlp->ahcictl_dip));
2fcbc377041d659446ded306a92901b4b0753b68yt } else {
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt (void) sprintf(name, "ahci: ");
2fcbc377041d659446ded306a92901b4b0753b68yt }
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt (void) vsprintf(ahci_log_buf, fmt, ap);
2fcbc377041d659446ded306a92901b4b0753b68yt va_end(ap);
2fcbc377041d659446ded306a92901b4b0753b68yt
a9440e8dda4d8a2be7e0201ca261df3118c86b5eyt cmn_err(level, "%s%s", name, ahci_log_buf);
2fcbc377041d659446ded306a92901b4b0753b68yt
2fcbc377041d659446ded306a92901b4b0753b68yt mutex_exit(&ahci_log_mutex);
2fcbc377041d659446ded306a92901b4b0753b68yt}
689d74b0a0dba643450e7fc74a03425c963657e7yt#endif
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore/*
193974072f41a843678abf5f61979c748687e66bSherry Moore * quiesce(9E) entry point.
193974072f41a843678abf5f61979c748687e66bSherry Moore *
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 * blocked.
193974072f41a843678abf5f61979c748687e66bSherry Moore *
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 */
193974072f41a843678abf5f61979c748687e66bSherry Moorestatic int
193974072f41a843678abf5f61979c748687e66bSherry Mooreahci_quiesce(dev_info_t *dip)
193974072f41a843678abf5f61979c748687e66bSherry Moore{
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_ctl_t *ahci_ctlp;
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_port_t *ahci_portp;
193974072f41a843678abf5f61979c748687e66bSherry Moore int instance, port;
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore instance = ddi_get_instance(dip);
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_ctlp = ddi_get_soft_state(ahci_statep, instance);
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore if (ahci_ctlp == NULL)
193974072f41a843678abf5f61979c748687e66bSherry Moore return (DDI_FAILURE);
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore#if AHCI_DEBUG
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_debug_flags = 0;
193974072f41a843678abf5f61979c748687e66bSherry Moore#endif
193974072f41a843678abf5f61979c748687e66bSherry Moore
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_ctlp->ahcictl_flags |= AHCI_QUIESCE;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
193974072f41a843678abf5f61979c748687e66bSherry Moore /* disable all the interrupts. */
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_disable_all_intrs(ahci_ctlp);
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore for (port = 0; port < ahci_ctlp->ahcictl_num_ports; port++) {
193974072f41a843678abf5f61979c748687e66bSherry Moore if (!AHCI_PORT_IMPLEMENTED(ahci_ctlp, port)) {
193974072f41a843678abf5f61979c748687e66bSherry Moore continue;
193974072f41a843678abf5f61979c748687e66bSherry Moore }
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_portp = ahci_ctlp->ahcictl_ports[port];
193974072f41a843678abf5f61979c748687e66bSherry Moore
193974072f41a843678abf5f61979c748687e66bSherry Moore /*
193974072f41a843678abf5f61979c748687e66bSherry Moore * Stop the port by clearing PxCMD.ST
193974072f41a843678abf5f61979c748687e66bSherry Moore *
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 */
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_disable_port_intrs(ahci_ctlp, port);
193974072f41a843678abf5f61979c748687e66bSherry Moore (void) ahci_put_port_into_notrunning_state(ahci_ctlp,
193974072f41a843678abf5f61979c748687e66bSherry Moore ahci_portp, port);
193974072f41a843678abf5f61979c748687e66bSherry Moore }
193974072f41a843678abf5f61979c748687e66bSherry Moore
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_ctlp->ahcictl_flags &= ~AHCI_QUIESCE;
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
193974072f41a843678abf5f61979c748687e66bSherry Moore return (DDI_SUCCESS);
193974072f41a843678abf5f61979c748687e66bSherry Moore}
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China/*
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * The function will add a sata packet to the done queue.
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic void
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinaahci_add_doneq(ahci_port_t *ahci_portp, sata_pkt_t *satapkt, int reason)
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China{
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ASSERT(satapkt != NULL);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /* set the reason for all packets */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_reason = reason;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_hba_driver_private = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (! (satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_comp) {
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /*
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 */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China *ahci_portp->ahciport_doneqtail = satapkt;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China ahci_portp->ahciport_doneqtail =
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China (sata_pkt_t **)&(satapkt->satapkt_hba_driver_private);
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ahci_portp->ahciport_doneq_len++;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
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 /*
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * for sync/non-poll mode, just call cv_broadcast
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China cv_broadcast(&ahci_portp->ahciport_cv);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China}
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China/*
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * The function will call completion callback of sata packet on the
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China * completed queue
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinastatic void
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing Chinaahci_flush_doneq(ahci_port_t *ahci_portp)
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China{
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China sata_pkt_t *satapkt, *next;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka ASSERT(MUTEX_HELD(&ahci_portp->ahciport_mutex));
265b5a40862f786981e8192cb44ebb70ecc9cfc8Marcel Telka
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China if (ahci_portp->ahciport_doneq) {
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt = ahci_portp->ahciport_doneq;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
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
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China mutex_exit(&ahci_portp->ahciport_mutex);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China while (satapkt != NULL) {
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China next = satapkt->satapkt_hba_driver_private;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt->satapkt_hba_driver_private = NULL;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China /* Call the callback */
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China (*satapkt->satapkt_comp)(satapkt);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China satapkt = next;
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China }
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China mutex_enter(&ahci_portp->ahciport_mutex);
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China }
6b62a23688770a1dc7887eb1dddb4c169eb7b786ying tian - Beijing China}