166f9d5cbSmlf /*
266f9d5cbSmlf  * CDDL HEADER START
366f9d5cbSmlf  *
466f9d5cbSmlf  * The contents of this file are subject to the terms of the
566f9d5cbSmlf  * Common Development and Distribution License (the "License").
666f9d5cbSmlf  * You may not use this file except in compliance with the License.
766f9d5cbSmlf  *
866f9d5cbSmlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
966f9d5cbSmlf  * or http://www.opensolaris.org/os/licensing.
1066f9d5cbSmlf  * See the License for the specific language governing permissions
1166f9d5cbSmlf  * and limitations under the License.
1266f9d5cbSmlf  *
1366f9d5cbSmlf  * When distributing Covered Code, include this CDDL HEADER in each
1466f9d5cbSmlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1566f9d5cbSmlf  * If applicable, add the following below this CDDL HEADER, with the
1666f9d5cbSmlf  * fields enclosed by brackets "[]" replaced with your own identifying
1766f9d5cbSmlf  * information: Portions Copyright [yyyy] [name of copyright owner]
1866f9d5cbSmlf  *
1966f9d5cbSmlf  * CDDL HEADER END
2066f9d5cbSmlf  */
2166f9d5cbSmlf 
2266f9d5cbSmlf /*
23a599d311SMartin Faltesek  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
2466f9d5cbSmlf  */
2566f9d5cbSmlf 
2666f9d5cbSmlf 
2766f9d5cbSmlf /*
28b74cec98SCharles Stephens  * SiliconImage 3124/3132/3531 sata controller driver
2966f9d5cbSmlf  */
3066f9d5cbSmlf 
3166f9d5cbSmlf /*
3266f9d5cbSmlf  *
3366f9d5cbSmlf  *
34*83dba8e1SToomas Soome  *			Few Design notes
3566f9d5cbSmlf  *
3666f9d5cbSmlf  *
3766f9d5cbSmlf  * I. General notes
3866f9d5cbSmlf  *
3966f9d5cbSmlf  * Even though the driver is named as si3124, it is actually meant to
40b74cec98SCharles Stephens  * work with SiI3124, SiI3132 and SiI3531 controllers.
4166f9d5cbSmlf  *
4266f9d5cbSmlf  * The current file si3124.c is the main driver code. The si3124reg.h
43b74cec98SCharles Stephens  * holds the register definitions from SiI 3124/3132/3531 data sheets. The
4466f9d5cbSmlf  * si3124var.h holds the driver specific definitions which are not
4566f9d5cbSmlf  * directly derived from data sheets.
4666f9d5cbSmlf  *
4766f9d5cbSmlf  *
4866f9d5cbSmlf  * II. Data structures
4966f9d5cbSmlf  *
5066f9d5cbSmlf  * si_ctl_state_t: This holds the driver private information for each
51*83dba8e1SToomas Soome  *	controller instance. Each of the sata ports within a single
5266f9d5cbSmlf  *	controller are represented by si_port_state_t. The
5366f9d5cbSmlf  *	sictl_global_acc_handle and sictl_global_address map the
5466f9d5cbSmlf  *	controller-wide global register space and are derived from pci
5566f9d5cbSmlf  *	BAR 0. The sictl_port_acc_handle and sictl_port_addr map the
5666f9d5cbSmlf  *	per-port register space and are derived from pci BAR 1.
5766f9d5cbSmlf  *
5866f9d5cbSmlf  * si_port_state_t: This holds the per port information. The siport_mutex
5966f9d5cbSmlf  *	holds the per port mutex. The siport_pending_tags is the bit mask of
60*83dba8e1SToomas Soome  *	commands posted to controller. The siport_slot_pkts[] holds the
61*83dba8e1SToomas Soome  *	pending sata packets. The siport_port_type holds the device type
6266f9d5cbSmlf  *	connected directly to the port while the siport_portmult_state
63*83dba8e1SToomas Soome  *	holds the similar information for the devices behind a port
6466f9d5cbSmlf  *	multiplier.
6566f9d5cbSmlf  *
6666f9d5cbSmlf  * si_prb_t: This contains the PRB being posted to the controller.
6766f9d5cbSmlf  *	The two SGE entries contained within si_prb_t itself are not
6866f9d5cbSmlf  *	really used to hold any scatter gather entries. The scatter gather
6966f9d5cbSmlf  *	list is maintained external to PRB and is linked from one
70*83dba8e1SToomas Soome  *	of the contained SGEs inside the PRB. For atapi devices, the
7166f9d5cbSmlf  *	first contained SGE holds the PACKET and second contained
7266f9d5cbSmlf  *	SGE holds the link to an external SGT. For non-atapi devices,
7366f9d5cbSmlf  *	the first contained SGE works as link to external SGT while
7466f9d5cbSmlf  *	second SGE is blank.
7566f9d5cbSmlf  *
7666f9d5cbSmlf  * external SGT tables: The external SGT tables pointed to from
7766f9d5cbSmlf  *	within si_prb_t are actually abstracted as si_sgblock_t. Each
7881a0678eSxun ni - Sun Microsystems - Beijing China  *	si_sgblock_t contains si_dma_sg_number number of
7981a0678eSxun ni - Sun Microsystems - Beijing China  *	SGT tables linked in a chain. Currently this default value of
8081a0678eSxun ni - Sun Microsystems - Beijing China  *	SGT tables per block is at 85 as  which translates
8181a0678eSxun ni - Sun Microsystems - Beijing China  *	to a maximum of 256 dma cookies per single dma transfer.
8281a0678eSxun ni - Sun Microsystems - Beijing China  *	This value can be changed through the global var: si_dma_sg_number
8381a0678eSxun ni - Sun Microsystems - Beijing China  *	in /etc/system, the maxium is at 21844 as which translates to 65535
8481a0678eSxun ni - Sun Microsystems - Beijing China  *	dma cookies per single dma transfer.
8566f9d5cbSmlf  *
8666f9d5cbSmlf  *
8766f9d5cbSmlf  * III. Driver operation
8866f9d5cbSmlf  *
8966f9d5cbSmlf  * Command Issuing: We use the "indirect method of command issuance". The
9066f9d5cbSmlf  *	PRB contains the command [and atapi PACKET] and a link to the
9166f9d5cbSmlf  *	external SGT chain. We write the physical address of the PRB into
9266f9d5cbSmlf  *	command activation register. There are 31 command slots for
9366f9d5cbSmlf  *	each port. After posting a command, we remember the posted slot &
9466f9d5cbSmlf  *	the sata packet in siport_pending_tags & siport_slot_pkts[]
9566f9d5cbSmlf  *	respectively.
9666f9d5cbSmlf  *
9766f9d5cbSmlf  * Command completion: On a successful completion, intr_command_complete()
98*83dba8e1SToomas Soome  *	receives the control. The slot_status register holds the outstanding
9966f9d5cbSmlf  *	commands. Any reading of slot_status register automatically clears
10066f9d5cbSmlf  *	the interrupt. By comparing the slot_status register contents with
10166f9d5cbSmlf  *	per port siport_pending_tags, we determine which of the previously
10266f9d5cbSmlf  *	posted commands have finished.
10366f9d5cbSmlf  *
10466f9d5cbSmlf  * Timeout handling: Every 5 seconds, the watchdog handler scans thru the
105*83dba8e1SToomas Soome  *	pending packets. The satapkt->satapkt_hba_driver_private field is
106*83dba8e1SToomas Soome  *	overloaded with the count of watchdog cycles a packet has survived.
10766f9d5cbSmlf  *	If a packet has not completed within satapkt->satapkt_time, it is
10866f9d5cbSmlf  *	failed with error code of SATA_PKT_TIMEOUT. There is one watchdog
10966f9d5cbSmlf  *	handler running for each instance of controller.
11066f9d5cbSmlf  *
11166f9d5cbSmlf  * Error handling: For 3124, whenever any single command has encountered
11266f9d5cbSmlf  *	an error, the whole port execution completely stalls; there is no
11366f9d5cbSmlf  *	way of canceling or aborting the particular failed command. If
114*83dba8e1SToomas Soome  *	the port is connected to a port multiplier, we can however RESUME
11566f9d5cbSmlf  *	other non-error devices connected to the port multiplier.
11666f9d5cbSmlf  *	The only way to recover the failed commands is to either initialize
11766f9d5cbSmlf  *	the port or reset the port/device. Both port initialize and reset
11866f9d5cbSmlf  *	operations result in discarding any of pending commands on the port.
11966f9d5cbSmlf  *	All such discarded commands are sent up to framework with PKT_RESET
12066f9d5cbSmlf  *	satapkt_reason. The assumption is that framework [and sd] would
12166f9d5cbSmlf  *	retry these commands again. The failed command itself however is
12266f9d5cbSmlf  *	sent up with PKT_DEV_ERROR.
12366f9d5cbSmlf  *
12466f9d5cbSmlf  *	Here is the implementation strategy based on SiliconImage email
12566f9d5cbSmlf  *	regarding how they handle the errors for their Windows driver:
12666f9d5cbSmlf  *
12766f9d5cbSmlf  *	  a) for DEVICEERROR:
12866f9d5cbSmlf  *		If the port is connected to port multiplier, then
12966f9d5cbSmlf  *		 1) Resume the port
13066f9d5cbSmlf  *		 2) Wait for all the non-failed commands to complete
13166f9d5cbSmlf  *		 3) Perform a Port Initialize
13266f9d5cbSmlf  *
13366f9d5cbSmlf  *		If the port is not connected to port multiplier, issue
13466f9d5cbSmlf  *		a Port Initialize.
13566f9d5cbSmlf  *
13666f9d5cbSmlf  *	  b) for SDBERROR: [SDBERROR means failed command is an NCQ command]
137*83dba8e1SToomas Soome  *		Handle exactly like DEVICEERROR handling.
13866f9d5cbSmlf  *		After the Port Initialize done, do a Read Log Extended.
13966f9d5cbSmlf  *
14066f9d5cbSmlf  *	  c) for SENDFISERROR:
14166f9d5cbSmlf  *		If the port is connected to port multiplier, then
14266f9d5cbSmlf  *		 1) Resume the port
14366f9d5cbSmlf  *		 2) Wait for all the non-failed commands to complete
14466f9d5cbSmlf  *		 3) Perform a Port Initialize
14566f9d5cbSmlf  *
14666f9d5cbSmlf  *		If the port is not connected to port multiplier, issue
147*83dba8e1SToomas Soome  *		a Device Reset.
14866f9d5cbSmlf  *
14966f9d5cbSmlf  *	  d) for DATAFISERROR:
15066f9d5cbSmlf  *		If the port was executing an NCQ command, issue a Device
15166f9d5cbSmlf  *		Reset.
15266f9d5cbSmlf  *
15366f9d5cbSmlf  *		Otherwise, follow the same error recovery as DEVICEERROR.
15466f9d5cbSmlf  *
15566f9d5cbSmlf  *	  e) for any other error, simply issue a Device Reset.
15666f9d5cbSmlf  *
157*83dba8e1SToomas Soome  *	To synchronize the interactions between various control flows (e.g.
15866f9d5cbSmlf  *	error recovery, timeout handling, si_poll_timeout, incoming flow
15966f9d5cbSmlf  *	from framework etc.), the following precautions are taken care of:
16066f9d5cbSmlf  *		a) During mopping_in_progress, no more commands are
16166f9d5cbSmlf  *		accepted from the framework.
16266f9d5cbSmlf  *
16366f9d5cbSmlf  *		b) While draining the port multiplier commands, we should
16466f9d5cbSmlf  *		handle the possibility of any of the other waited commands
16566f9d5cbSmlf  *		failing (possibly with a different error code)
16666f9d5cbSmlf  *
16766f9d5cbSmlf  * Atapi handling: For atapi devices, we use the first SGE within the PRB
168*83dba8e1SToomas Soome  *	to fill the scsi cdb while the second SGE points to external SGT.
16966f9d5cbSmlf  *
17066f9d5cbSmlf  * Queuing: Queue management is achieved external to the driver inside sd.
17166f9d5cbSmlf  *	Based on sata_hba_tran->qdepth and IDENTIFY data, the framework
17266f9d5cbSmlf  *	enables or disables the queuing. The qdepth for si3124 is 31
17366f9d5cbSmlf  *	commands.
17466f9d5cbSmlf  *
17566f9d5cbSmlf  * Port Multiplier: Enumeration of port multiplier is handled during the
17666f9d5cbSmlf  *	controller initialization and also during the a hotplug operation.
17766f9d5cbSmlf  *	Current logic takes care of situation where a port multiplier
17866f9d5cbSmlf  *	is hotplugged into a port which had a cdisk connected previously
17966f9d5cbSmlf  *	and vice versa.
18066f9d5cbSmlf  *
18166f9d5cbSmlf  * Register poll timeouts: Currently most of poll timeouts on register
18266f9d5cbSmlf  *	reads is set to 0.5 seconds except for a value of 10 seconds
18366f9d5cbSmlf  *	while reading the device signature. [Such a big timeout values
18466f9d5cbSmlf  *	for device signature were found needed during cold reboots
18566f9d5cbSmlf  *	for devices behind port multiplier].
18666f9d5cbSmlf  *
18766f9d5cbSmlf  *
18866f9d5cbSmlf  * IV. Known Issues
18966f9d5cbSmlf  *
19066f9d5cbSmlf  * 1) Currently the atapi packet length is hard coded to 12 bytes
19166f9d5cbSmlf  *	This is wrong. The framework should determine it just like they
192*83dba8e1SToomas Soome  *	determine ad_cdb_len in legacy atapi.c. It should even reject
19366f9d5cbSmlf  *	init_pkt() for greater CDB lengths. See atapi.c. Revisit this
19466f9d5cbSmlf  *	in 2nd phase of framework project.
19566f9d5cbSmlf  *
19666f9d5cbSmlf  * 2) Do real REQUEST SENSE command instead of faking for ATAPI case.
19766f9d5cbSmlf  *
19866f9d5cbSmlf  */
19966f9d5cbSmlf 
20066f9d5cbSmlf 
20166f9d5cbSmlf #include <sys/note.h>
20266f9d5cbSmlf #include <sys/scsi/scsi.h>
20366f9d5cbSmlf #include <sys/pci.h>
20466f9d5cbSmlf #include <sys/sata/sata_hba.h>
20566f9d5cbSmlf #include <sys/sata/adapters/si3124/si3124reg.h>
20666f9d5cbSmlf #include <sys/sata/adapters/si3124/si3124var.h>
207a599d311SMartin Faltesek #include <sys/sdt.h>
20866f9d5cbSmlf 
209ab0d082fSMark Logan /*
210ab0d082fSMark Logan  * FMA header files
211ab0d082fSMark Logan  */
212ab0d082fSMark Logan #include <sys/ddifm.h>
213ab0d082fSMark Logan #include <sys/fm/protocol.h>
214ab0d082fSMark Logan #include <sys/fm/util.h>
215ab0d082fSMark Logan #include <sys/fm/io/ddi.h>
216ab0d082fSMark Logan 
21766f9d5cbSmlf /*
21866f9d5cbSmlf  * Function prototypes for driver entry points
21966f9d5cbSmlf  */
22066f9d5cbSmlf static	int si_attach(dev_info_t *, ddi_attach_cmd_t);
22166f9d5cbSmlf static	int si_detach(dev_info_t *, ddi_detach_cmd_t);
22266f9d5cbSmlf static	int si_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2232d9382f4Sxun ni - Sun Microsystems - Beijing China static	int si_power(dev_info_t *, int, int);
2242d9382f4Sxun ni - Sun Microsystems - Beijing China static	int si_quiesce(dev_info_t *);
22566f9d5cbSmlf /*
22666f9d5cbSmlf  * Function prototypes for SATA Framework interfaces
22766f9d5cbSmlf  */
22866f9d5cbSmlf static	int si_register_sata_hba_tran(si_ctl_state_t *);
22966f9d5cbSmlf static	int si_unregister_sata_hba_tran(si_ctl_state_t *);
23066f9d5cbSmlf 
23166f9d5cbSmlf static	int si_tran_probe_port(dev_info_t *, sata_device_t *);
23266f9d5cbSmlf static	int si_tran_start(dev_info_t *, sata_pkt_t *spkt);
23366f9d5cbSmlf static	int si_tran_abort(dev_info_t *, sata_pkt_t *, int);
23466f9d5cbSmlf static	int si_tran_reset_dport(dev_info_t *, sata_device_t *);
23566f9d5cbSmlf static	int si_tran_hotplug_port_activate(dev_info_t *, sata_device_t *);
23666f9d5cbSmlf static	int si_tran_hotplug_port_deactivate(dev_info_t *, sata_device_t *);
23766f9d5cbSmlf 
23866f9d5cbSmlf /*
23966f9d5cbSmlf  * Local function prototypes
24066f9d5cbSmlf  */
24166f9d5cbSmlf 
24266f9d5cbSmlf static	int si_alloc_port_state(si_ctl_state_t *, int);
24366f9d5cbSmlf static	void si_dealloc_port_state(si_ctl_state_t *, int);
24466f9d5cbSmlf static	int si_alloc_sgbpool(si_ctl_state_t *, int);
24566f9d5cbSmlf static	void si_dealloc_sgbpool(si_ctl_state_t *, int);
24666f9d5cbSmlf static	int si_alloc_prbpool(si_ctl_state_t *, int);
24766f9d5cbSmlf static	void si_dealloc_prbpool(si_ctl_state_t *, int);
24866f9d5cbSmlf 
24966f9d5cbSmlf static void si_find_dev_signature(si_ctl_state_t *, si_port_state_t *,
25066f9d5cbSmlf 						int, int);
25166f9d5cbSmlf static void si_poll_cmd(si_ctl_state_t *, si_port_state_t *, int, int,
25266f9d5cbSmlf 						sata_pkt_t *);
25366f9d5cbSmlf static	int si_claim_free_slot(si_ctl_state_t *, si_port_state_t *, int);
25466f9d5cbSmlf static	int si_deliver_satapkt(si_ctl_state_t *, si_port_state_t *, int,
25566f9d5cbSmlf 						sata_pkt_t *);
25666f9d5cbSmlf 
25766f9d5cbSmlf static	int si_initialize_controller(si_ctl_state_t *);
258a599d311SMartin Faltesek static	void si_deinitialize_controller(si_ctl_state_t *);
25966f9d5cbSmlf static void si_init_port(si_ctl_state_t *, int);
26066f9d5cbSmlf static	int si_enumerate_port_multiplier(si_ctl_state_t *,
26166f9d5cbSmlf 						si_port_state_t *, int);
26266f9d5cbSmlf static int si_read_portmult_reg(si_ctl_state_t *, si_port_state_t *,
26366f9d5cbSmlf 						int, int, int, uint32_t *);
26466f9d5cbSmlf static int si_write_portmult_reg(si_ctl_state_t *, si_port_state_t *,
26566f9d5cbSmlf 						int, int, int, uint32_t);
26666f9d5cbSmlf static void si_set_sense_data(sata_pkt_t *, int);
26766f9d5cbSmlf 
26866f9d5cbSmlf static uint_t si_intr(caddr_t, caddr_t);
26966f9d5cbSmlf static int si_intr_command_complete(si_ctl_state_t *,
27066f9d5cbSmlf 					si_port_state_t *, int);
271832d3fc2SMark Logan static void si_schedule_intr_command_error(si_ctl_state_t *,
272832d3fc2SMark Logan 					si_port_state_t *, int);
273832d3fc2SMark Logan static void si_do_intr_command_error(void *);
27466f9d5cbSmlf static int si_intr_command_error(si_ctl_state_t *,
27566f9d5cbSmlf 					si_port_state_t *, int);
27666f9d5cbSmlf static void si_error_recovery_DEVICEERROR(si_ctl_state_t *,
27766f9d5cbSmlf 					si_port_state_t *, int);
27866f9d5cbSmlf static void si_error_recovery_SDBERROR(si_ctl_state_t *,
27966f9d5cbSmlf 					si_port_state_t *, int);
28066f9d5cbSmlf static void si_error_recovery_DATAFISERROR(si_ctl_state_t *,
28166f9d5cbSmlf 					si_port_state_t *, int);
28266f9d5cbSmlf static void si_error_recovery_SENDFISERROR(si_ctl_state_t *,
28366f9d5cbSmlf 					si_port_state_t *, int);
28466f9d5cbSmlf static void si_error_recovery_default(si_ctl_state_t *,
28566f9d5cbSmlf 					si_port_state_t *, int);
28666f9d5cbSmlf static uint8_t si_read_log_ext(si_ctl_state_t *,
28766f9d5cbSmlf 					si_port_state_t *si_portp, int);
28866f9d5cbSmlf static void si_log_error_message(si_ctl_state_t *, int, uint32_t);
28966f9d5cbSmlf static int si_intr_port_ready(si_ctl_state_t *, si_port_state_t *, int);
29066f9d5cbSmlf static int si_intr_pwr_change(si_ctl_state_t *, si_port_state_t *, int);
29166f9d5cbSmlf static int si_intr_phy_ready_change(si_ctl_state_t *, si_port_state_t *, int);
29266f9d5cbSmlf static int si_intr_comwake_rcvd(si_ctl_state_t *, si_port_state_t *, int);
29366f9d5cbSmlf static int si_intr_unrecognised_fis(si_ctl_state_t *, si_port_state_t *, int);
29466f9d5cbSmlf static int si_intr_dev_xchanged(si_ctl_state_t *, si_port_state_t *, int);
29566f9d5cbSmlf static int si_intr_decode_err_threshold(si_ctl_state_t *,
29666f9d5cbSmlf 					si_port_state_t *, int);
29766f9d5cbSmlf static int si_intr_crc_err_threshold(si_ctl_state_t *, si_port_state_t *, int);
29866f9d5cbSmlf static int si_intr_handshake_err_threshold(si_ctl_state_t *,
29966f9d5cbSmlf 					si_port_state_t *, int);
30066f9d5cbSmlf static int si_intr_set_devbits_notify(si_ctl_state_t *, si_port_state_t *, int);
30166f9d5cbSmlf 
30266f9d5cbSmlf static	void si_enable_port_interrupts(si_ctl_state_t *, int);
30366f9d5cbSmlf static	void si_enable_all_interrupts(si_ctl_state_t *);
30466f9d5cbSmlf static	void si_disable_port_interrupts(si_ctl_state_t *, int);
30566f9d5cbSmlf static	void si_disable_all_interrupts(si_ctl_state_t *);
306*83dba8e1SToomas Soome static	void fill_dev_sregisters(si_ctl_state_t *, int, sata_device_t *);
307*83dba8e1SToomas Soome static	int si_add_legacy_intrs(si_ctl_state_t *);
308*83dba8e1SToomas Soome static	int si_add_msi_intrs(si_ctl_state_t *);
309*83dba8e1SToomas Soome static	void si_rem_intrs(si_ctl_state_t *);
31066f9d5cbSmlf 
31166f9d5cbSmlf static	int si_reset_dport_wait_till_ready(si_ctl_state_t *,
31266f9d5cbSmlf 				si_port_state_t *, int, int);
3132d9382f4Sxun ni - Sun Microsystems - Beijing China static int si_clear_port(si_ctl_state_t *, int);
314832d3fc2SMark Logan static void si_schedule_port_initialize(si_ctl_state_t *,
315832d3fc2SMark Logan 				si_port_state_t *, int);
316832d3fc2SMark Logan static void si_do_initialize_port(void *);
31766f9d5cbSmlf static	int si_initialize_port_wait_till_ready(si_ctl_state_t *, int);
31866f9d5cbSmlf 
31966f9d5cbSmlf static void si_timeout_pkts(si_ctl_state_t *, si_port_state_t *, int, uint32_t);
32066f9d5cbSmlf static	void si_watchdog_handler(si_ctl_state_t *);
32166f9d5cbSmlf 
322ab0d082fSMark Logan /*
323ab0d082fSMark Logan  * FMA Prototypes
324ab0d082fSMark Logan  */
325ab0d082fSMark Logan static void si_fm_init(si_ctl_state_t *);
326ab0d082fSMark Logan static void si_fm_fini(si_ctl_state_t *);
327ab0d082fSMark Logan static int si_fm_error_cb(dev_info_t *, ddi_fm_error_t *, const void *);
328ab0d082fSMark Logan static int si_check_acc_handle(ddi_acc_handle_t);
329ab0d082fSMark Logan static int si_check_dma_handle(ddi_dma_handle_t);
330ab0d082fSMark Logan static int si_check_ctl_handles(si_ctl_state_t *);
331ab0d082fSMark Logan static int si_check_port_handles(si_port_state_t *);
332ab0d082fSMark Logan static void si_fm_ereport(si_ctl_state_t *, char *, char *);
333ab0d082fSMark Logan 
334e57ece5bSPraveen Kumar Dasaraju Rama static	void si_log(si_ctl_state_t *, si_port_state_t *, char *, ...);
33566f9d5cbSmlf 
336a599d311SMartin Faltesek static void si_copy_out_regs(sata_cmd_t *, si_ctl_state_t *, uint8_t, uint8_t);
33766f9d5cbSmlf 
33866f9d5cbSmlf /*
33966f9d5cbSmlf  * DMA attributes for the data buffer
34066f9d5cbSmlf  */
34166f9d5cbSmlf 
34266f9d5cbSmlf static ddi_dma_attr_t buffer_dma_attr = {
34366f9d5cbSmlf 	DMA_ATTR_V0,		/* dma_attr_version */
34466f9d5cbSmlf 	0,			/* dma_attr_addr_lo: lowest bus address */
34566f9d5cbSmlf 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
34666f9d5cbSmlf 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
34766f9d5cbSmlf 	1,			/* dma_attr_align: single byte aligned */
34866f9d5cbSmlf 	1,			/* dma_attr_burstsizes */
34966f9d5cbSmlf 	1,			/* dma_attr_minxfer */
35066f9d5cbSmlf 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
35166f9d5cbSmlf 	0xffffffffull,		/* dma_attr_seg */
35281a0678eSxun ni - Sun Microsystems - Beijing China 	SI_DEFAULT_SGL_LENGTH,	/* dma_attr_sgllen */
35366f9d5cbSmlf 	512,			/* dma_attr_granular */
35466f9d5cbSmlf 	0,			/* dma_attr_flags */
35566f9d5cbSmlf };
35666f9d5cbSmlf 
35766f9d5cbSmlf /*
35866f9d5cbSmlf  * DMA attributes for incore RPB and SGT pool
35966f9d5cbSmlf  */
36066f9d5cbSmlf static ddi_dma_attr_t prb_sgt_dma_attr = {
36166f9d5cbSmlf 	DMA_ATTR_V0,		/* dma_attr_version */
36266f9d5cbSmlf 	0,			/* dma_attr_addr_lo: lowest bus address */
36366f9d5cbSmlf 	0xffffffffffffffffull,	/* dma_attr_addr_hi: highest bus address */
36466f9d5cbSmlf 	0xffffffffull,		/* dma_attr_count_max i.e. for one cookie */
36566f9d5cbSmlf 	8,			/* dma_attr_align: quad word aligned */
36666f9d5cbSmlf 	1,			/* dma_attr_burstsizes */
36766f9d5cbSmlf 	1,			/* dma_attr_minxfer */
36866f9d5cbSmlf 	0xffffffffull,		/* dma_attr_maxxfer i.e. includes all cookies */
36966f9d5cbSmlf 	0xffffffffull,		/* dma_attr_seg */
37066f9d5cbSmlf 	1,			/* dma_attr_sgllen */
37166f9d5cbSmlf 	1,			/* dma_attr_granular */
37266f9d5cbSmlf 	0,			/* dma_attr_flags */
37366f9d5cbSmlf };
37466f9d5cbSmlf 
37566f9d5cbSmlf /* Device access attributes */
37666f9d5cbSmlf static ddi_device_acc_attr_t accattr = {
377ab0d082fSMark Logan     DDI_DEVICE_ATTR_V1,
37866f9d5cbSmlf     DDI_STRUCTURE_LE_ACC,
379ab0d082fSMark Logan     DDI_STRICTORDER_ACC,
380ab0d082fSMark Logan     DDI_DEFAULT_ACC
38166f9d5cbSmlf };
38266f9d5cbSmlf 
38366f9d5cbSmlf 
38466f9d5cbSmlf static struct dev_ops sictl_dev_ops = {
38566f9d5cbSmlf 	DEVO_REV,		/* devo_rev */
38666f9d5cbSmlf 	0,			/* refcnt  */
38766f9d5cbSmlf 	si_getinfo,		/* info */
38866f9d5cbSmlf 	nulldev,		/* identify */
38966f9d5cbSmlf 	nulldev,		/* probe */
39066f9d5cbSmlf 	si_attach,		/* attach */
39166f9d5cbSmlf 	si_detach,		/* detach */
39266f9d5cbSmlf 	nodev,			/* no reset */
39366f9d5cbSmlf 	(struct cb_ops *)0,	/* driver operations */
39466f9d5cbSmlf 	NULL,			/* bus operations */
39519397407SSherry Moore 	si_power,		/* power */
3962d9382f4Sxun ni - Sun Microsystems - Beijing China 	si_quiesce,		/* devo_quiesce */
39766f9d5cbSmlf };
39866f9d5cbSmlf 
39966f9d5cbSmlf static sata_tran_hotplug_ops_t si_tran_hotplug_ops = {
40066f9d5cbSmlf 	SATA_TRAN_HOTPLUG_OPS_REV_1,
40166f9d5cbSmlf 	si_tran_hotplug_port_activate,
40266f9d5cbSmlf 	si_tran_hotplug_port_deactivate
40366f9d5cbSmlf };
40466f9d5cbSmlf 
40566f9d5cbSmlf 
40666f9d5cbSmlf static int si_watchdog_timeout = 5; /* 5 seconds */
40766f9d5cbSmlf static int si_watchdog_tick;
40866f9d5cbSmlf 
40966f9d5cbSmlf extern struct mod_ops mod_driverops;
41066f9d5cbSmlf 
41166f9d5cbSmlf static  struct modldrv modldrv = {
41266f9d5cbSmlf 	&mod_driverops,	/* driverops */
41319397407SSherry Moore 	"si3124 driver",
41466f9d5cbSmlf 	&sictl_dev_ops,	/* driver ops */
41566f9d5cbSmlf };
41666f9d5cbSmlf 
41766f9d5cbSmlf static  struct modlinkage modlinkage = {
41866f9d5cbSmlf 	MODREV_1,
41966f9d5cbSmlf 	&modldrv,
42066f9d5cbSmlf 	NULL
42166f9d5cbSmlf };
42266f9d5cbSmlf 
42366f9d5cbSmlf 
42466f9d5cbSmlf /* The following are needed for si_log() */
42566f9d5cbSmlf static kmutex_t si_log_mutex;
426e57ece5bSPraveen Kumar Dasaraju Rama static char si_log_buf[SI_LOGBUF_LEN];
427e57ece5bSPraveen Kumar Dasaraju Rama uint32_t si_debug_flags =
428e57ece5bSPraveen Kumar Dasaraju Rama     SIDBG_ERRS|SIDBG_INIT|SIDBG_EVENT|SIDBG_TIMEOUT|SIDBG_RESET;
429e57ece5bSPraveen Kumar Dasaraju Rama 
43066f9d5cbSmlf static int is_msi_supported = 0;
43166f9d5cbSmlf 
43281a0678eSxun ni - Sun Microsystems - Beijing China /*
43381a0678eSxun ni - Sun Microsystems - Beijing China  * The below global variables are tunable via /etc/system
43481a0678eSxun ni - Sun Microsystems - Beijing China  *
43581a0678eSxun ni - Sun Microsystems - Beijing China  * si_dma_sg_number
43681a0678eSxun ni - Sun Microsystems - Beijing China  */
43781a0678eSxun ni - Sun Microsystems - Beijing China 
43881a0678eSxun ni - Sun Microsystems - Beijing China int si_dma_sg_number = SI_DEFAULT_SGT_TABLES_PER_PRB;
43981a0678eSxun ni - Sun Microsystems - Beijing China 
44066f9d5cbSmlf /* Opaque state pointer to be initialized by ddi_soft_state_init() */
44166f9d5cbSmlf static void *si_statep	= NULL;
44266f9d5cbSmlf 
44366f9d5cbSmlf /*
44466f9d5cbSmlf  *  si3124 module initialization.
44566f9d5cbSmlf  *
44666f9d5cbSmlf  */
44766f9d5cbSmlf int
_init(void)44866f9d5cbSmlf _init(void)
44966f9d5cbSmlf {
45066f9d5cbSmlf 	int	error;
45166f9d5cbSmlf 
45266f9d5cbSmlf 	error = ddi_soft_state_init(&si_statep, sizeof (si_ctl_state_t), 0);
45366f9d5cbSmlf 	if (error != 0) {
45466f9d5cbSmlf 		return (error);
45566f9d5cbSmlf 	}
45666f9d5cbSmlf 
45766f9d5cbSmlf 	mutex_init(&si_log_mutex, NULL, MUTEX_DRIVER, NULL);
45866f9d5cbSmlf 
45966f9d5cbSmlf 	if ((error = sata_hba_init(&modlinkage)) != 0) {
46066f9d5cbSmlf 		mutex_destroy(&si_log_mutex);
46166f9d5cbSmlf 		ddi_soft_state_fini(&si_statep);
46266f9d5cbSmlf 		return (error);
46366f9d5cbSmlf 	}
46466f9d5cbSmlf 
46566f9d5cbSmlf 	error = mod_install(&modlinkage);
46666f9d5cbSmlf 	if (error != 0) {
46766f9d5cbSmlf 		sata_hba_fini(&modlinkage);
46866f9d5cbSmlf 		mutex_destroy(&si_log_mutex);
46966f9d5cbSmlf 		ddi_soft_state_fini(&si_statep);
47066f9d5cbSmlf 		return (error);
47166f9d5cbSmlf 	}
47266f9d5cbSmlf 
47366f9d5cbSmlf 	si_watchdog_tick = drv_usectohz((clock_t)si_watchdog_timeout * 1000000);
47466f9d5cbSmlf 
47566f9d5cbSmlf 	return (error);
47666f9d5cbSmlf }
47766f9d5cbSmlf 
47866f9d5cbSmlf /*
47966f9d5cbSmlf  * si3124 module uninitialize.
48066f9d5cbSmlf  *
48166f9d5cbSmlf  */
48266f9d5cbSmlf int
_fini(void)48366f9d5cbSmlf _fini(void)
48466f9d5cbSmlf {
48566f9d5cbSmlf 	int	error;
48666f9d5cbSmlf 
48766f9d5cbSmlf 	error = mod_remove(&modlinkage);
48866f9d5cbSmlf 	if (error != 0) {
48966f9d5cbSmlf 		return (error);
49066f9d5cbSmlf 	}
49166f9d5cbSmlf 
49266f9d5cbSmlf 	/* Remove the resources allocated in _init(). */
49366f9d5cbSmlf 	sata_hba_fini(&modlinkage);
49466f9d5cbSmlf 	mutex_destroy(&si_log_mutex);
49566f9d5cbSmlf 	ddi_soft_state_fini(&si_statep);
49666f9d5cbSmlf 
49766f9d5cbSmlf 	return (error);
49866f9d5cbSmlf }
49966f9d5cbSmlf 
50066f9d5cbSmlf /*
50166f9d5cbSmlf  * _info entry point
50266f9d5cbSmlf  *
50366f9d5cbSmlf  */
50466f9d5cbSmlf int
_info(struct modinfo * modinfop)50566f9d5cbSmlf _info(struct modinfo *modinfop)
50666f9d5cbSmlf {
50766f9d5cbSmlf 	return (mod_info(&modlinkage, modinfop));
50866f9d5cbSmlf }
50966f9d5cbSmlf 
51066f9d5cbSmlf 
51166f9d5cbSmlf /*
51266f9d5cbSmlf  * The attach entry point for dev_ops.
51366f9d5cbSmlf  *
51466f9d5cbSmlf  * We initialize the controller, initialize the soft state, register
51566f9d5cbSmlf  * the interrupt handlers and then register ourselves with sata framework.
51666f9d5cbSmlf  */
51766f9d5cbSmlf static int
si_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)51866f9d5cbSmlf si_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
51966f9d5cbSmlf {
52066f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
52166f9d5cbSmlf 	int instance;
52266f9d5cbSmlf 	int status;
52366f9d5cbSmlf 	int attach_state;
52466f9d5cbSmlf 	int intr_types;
52566f9d5cbSmlf 	sata_device_t sdevice;
52666f9d5cbSmlf 
527e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG(SIDBG_ENTRY, "si_attach enter", NULL);
52866f9d5cbSmlf 	instance = ddi_get_instance(dip);
52966f9d5cbSmlf 	attach_state = ATTACH_PROGRESS_NONE;
53066f9d5cbSmlf 
53166f9d5cbSmlf 	switch (cmd) {
53266f9d5cbSmlf 
53366f9d5cbSmlf 	case DDI_ATTACH:
53466f9d5cbSmlf 
53566f9d5cbSmlf 		/* Allocate si_softc. */
53666f9d5cbSmlf 		status = ddi_soft_state_zalloc(si_statep, instance);
53766f9d5cbSmlf 		if (status != DDI_SUCCESS) {
53866f9d5cbSmlf 			goto err_out;
53966f9d5cbSmlf 		}
54066f9d5cbSmlf 
54166f9d5cbSmlf 		si_ctlp = ddi_get_soft_state(si_statep, instance);
54266f9d5cbSmlf 		si_ctlp->sictl_devinfop = dip;
54366f9d5cbSmlf 
54466f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_STATEP_ALLOC;
54566f9d5cbSmlf 
546ab0d082fSMark Logan 		/* Initialize FMA */
547ab0d082fSMark Logan 		si_ctlp->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, dip,
548ab0d082fSMark Logan 		    DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS, "fm-capable",
549ab0d082fSMark Logan 		    DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
550ab0d082fSMark Logan 		    DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
551ab0d082fSMark Logan 
552ab0d082fSMark Logan 		si_fm_init(si_ctlp);
553ab0d082fSMark Logan 
554ab0d082fSMark Logan 		attach_state |= ATTACH_PROGRESS_INIT_FMA;
555ab0d082fSMark Logan 
55666f9d5cbSmlf 		/* Configure pci config space handle. */
55766f9d5cbSmlf 		status = pci_config_setup(dip, &si_ctlp->sictl_pci_conf_handle);
55866f9d5cbSmlf 		if (status != DDI_SUCCESS) {
55966f9d5cbSmlf 			goto err_out;
56066f9d5cbSmlf 		}
56166f9d5cbSmlf 
56266f9d5cbSmlf 		si_ctlp->sictl_devid =
56319397407SSherry Moore 		    pci_config_get16(si_ctlp->sictl_pci_conf_handle,
56419397407SSherry Moore 		    PCI_CONF_DEVID);
565b74cec98SCharles Stephens 		switch (si_ctlp->sictl_devid) {
566b74cec98SCharles Stephens 			case SI3124_DEV_ID:
567b74cec98SCharles Stephens 				si_ctlp->sictl_num_ports = SI3124_MAX_PORTS;
568b74cec98SCharles Stephens 				break;
569b74cec98SCharles Stephens 
570b74cec98SCharles Stephens 			case SI3132_DEV_ID:
571b74cec98SCharles Stephens 				si_ctlp->sictl_num_ports = SI3132_MAX_PORTS;
572b74cec98SCharles Stephens 				break;
573b74cec98SCharles Stephens 
574b74cec98SCharles Stephens 			case SI3531_DEV_ID:
575b74cec98SCharles Stephens 				si_ctlp->sictl_num_ports = SI3531_MAX_PORTS;
576b74cec98SCharles Stephens 				break;
577b74cec98SCharles Stephens 
578b74cec98SCharles Stephens 			default:
579b74cec98SCharles Stephens 				/*
580b74cec98SCharles Stephens 				 * Driver should not have attatched if device
581b74cec98SCharles Stephens 				 * ID is not already known and is supported.
582b74cec98SCharles Stephens 				 */
583b74cec98SCharles Stephens 				goto err_out;
58466f9d5cbSmlf 		}
58566f9d5cbSmlf 
58666f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_CONF_HANDLE;
58766f9d5cbSmlf 
58866f9d5cbSmlf 		/* Now map the bar0; the bar0 contains the global registers. */
58966f9d5cbSmlf 		status = ddi_regs_map_setup(dip,
59019397407SSherry Moore 		    PCI_BAR0,
59119397407SSherry Moore 		    (caddr_t *)&si_ctlp->sictl_global_addr,
59219397407SSherry Moore 		    0,
59319397407SSherry Moore 		    0,
59419397407SSherry Moore 		    &accattr,
59519397407SSherry Moore 		    &si_ctlp->sictl_global_acc_handle);
59666f9d5cbSmlf 		if (status != DDI_SUCCESS) {
59766f9d5cbSmlf 			goto err_out;
59866f9d5cbSmlf 		}
59966f9d5cbSmlf 
60066f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_BAR0_MAP;
60166f9d5cbSmlf 
60266f9d5cbSmlf 		/* Now map bar1; the bar1 contains the port registers. */
60366f9d5cbSmlf 		status = ddi_regs_map_setup(dip,
60419397407SSherry Moore 		    PCI_BAR1,
60519397407SSherry Moore 		    (caddr_t *)&si_ctlp->sictl_port_addr,
60619397407SSherry Moore 		    0,
60719397407SSherry Moore 		    0,
60819397407SSherry Moore 		    &accattr,
60919397407SSherry Moore 		    &si_ctlp->sictl_port_acc_handle);
61066f9d5cbSmlf 		if (status != DDI_SUCCESS) {
61166f9d5cbSmlf 			goto err_out;
61266f9d5cbSmlf 		}
61366f9d5cbSmlf 
61466f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_BAR1_MAP;
61566f9d5cbSmlf 
61666f9d5cbSmlf 		/*
61766f9d5cbSmlf 		 * Disable all the interrupts before adding interrupt
61866f9d5cbSmlf 		 * handler(s). The interrupts shall be re-enabled selectively
61966f9d5cbSmlf 		 * out of si_init_port().
62066f9d5cbSmlf 		 */
62166f9d5cbSmlf 		si_disable_all_interrupts(si_ctlp);
62266f9d5cbSmlf 
62366f9d5cbSmlf 		/* Get supported interrupt types. */
62466f9d5cbSmlf 		if (ddi_intr_get_supported_types(dip, &intr_types)
62519397407SSherry Moore 		    != DDI_SUCCESS) {
626e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_INIT, si_ctlp,
627e57ece5bSPraveen Kumar Dasaraju Rama 			    "ddi_intr_get_supported_types failed", NULL);
62866f9d5cbSmlf 			goto err_out;
62966f9d5cbSmlf 		}
63066f9d5cbSmlf 
631e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_INIT, si_ctlp,
63219397407SSherry Moore 		    "ddi_intr_get_supported_types() returned: 0x%x",
63319397407SSherry Moore 		    intr_types);
63466f9d5cbSmlf 
63566f9d5cbSmlf 		if (is_msi_supported && (intr_types & DDI_INTR_TYPE_MSI)) {
636e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_INIT, si_ctlp,
637e57ece5bSPraveen Kumar Dasaraju Rama 			    "Using MSI interrupt type", NULL);
63866f9d5cbSmlf 
63966f9d5cbSmlf 			/*
64066f9d5cbSmlf 			 * Try MSI first, but fall back to legacy if MSI
64166f9d5cbSmlf 			 * attach fails.
64266f9d5cbSmlf 			 */
64366f9d5cbSmlf 			if (si_add_msi_intrs(si_ctlp) == DDI_SUCCESS) {
64466f9d5cbSmlf 				si_ctlp->sictl_intr_type = DDI_INTR_TYPE_MSI;
64566f9d5cbSmlf 				attach_state |= ATTACH_PROGRESS_INTR_ADDED;
646e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_C(SIDBG_INIT, si_ctlp,
647e57ece5bSPraveen Kumar Dasaraju Rama 				    "MSI interrupt setup done", NULL);
648e57ece5bSPraveen Kumar Dasaraju Rama 			} else {
649e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_C(SIDBG_INIT, si_ctlp,
65019397407SSherry Moore 				    "MSI registration failed "
651e57ece5bSPraveen Kumar Dasaraju Rama 				    "will try Legacy interrupts", NULL);
65266f9d5cbSmlf 			}
65366f9d5cbSmlf 		}
65466f9d5cbSmlf 
65566f9d5cbSmlf 		if (!(attach_state & ATTACH_PROGRESS_INTR_ADDED) &&
65619397407SSherry Moore 		    (intr_types & DDI_INTR_TYPE_FIXED)) {
65766f9d5cbSmlf 			/*
65866f9d5cbSmlf 			 * Either the MSI interrupt setup has failed or only
65966f9d5cbSmlf 			 * fixed interrupts are available on the system.
66066f9d5cbSmlf 			 */
661e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_INIT, si_ctlp,
662e57ece5bSPraveen Kumar Dasaraju Rama 			    "Using Legacy interrupt type", NULL);
66366f9d5cbSmlf 
66466f9d5cbSmlf 			if (si_add_legacy_intrs(si_ctlp) == DDI_SUCCESS) {
66566f9d5cbSmlf 				si_ctlp->sictl_intr_type = DDI_INTR_TYPE_FIXED;
66666f9d5cbSmlf 				attach_state |= ATTACH_PROGRESS_INTR_ADDED;
667e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_C(SIDBG_INIT, si_ctlp,
668e57ece5bSPraveen Kumar Dasaraju Rama 				    "Legacy interrupt setup done", NULL);
66966f9d5cbSmlf 			} else {
670e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_C(SIDBG_INIT, si_ctlp,
671e57ece5bSPraveen Kumar Dasaraju Rama 				    "legacy interrupt setup failed", NULL);
67266f9d5cbSmlf 				goto err_out;
67366f9d5cbSmlf 			}
67466f9d5cbSmlf 		}
67566f9d5cbSmlf 
67666f9d5cbSmlf 		if (!(attach_state & ATTACH_PROGRESS_INTR_ADDED)) {
677e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_INIT, si_ctlp,
678e57ece5bSPraveen Kumar Dasaraju Rama 			    "si3124: No interrupts registered", NULL);
67966f9d5cbSmlf 			goto err_out;
68066f9d5cbSmlf 		}
68166f9d5cbSmlf 
68266f9d5cbSmlf 
68366f9d5cbSmlf 		/* Initialize the mutex. */
68466f9d5cbSmlf 		mutex_init(&si_ctlp->sictl_mutex, NULL, MUTEX_DRIVER,
68519397407SSherry Moore 		    (void *)(uintptr_t)si_ctlp->sictl_intr_pri);
68666f9d5cbSmlf 
68766f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_MUTEX_INIT;
68866f9d5cbSmlf 
68966f9d5cbSmlf 		/*
69066f9d5cbSmlf 		 * Initialize the controller and driver core.
69166f9d5cbSmlf 		 */
69266f9d5cbSmlf 		si_ctlp->sictl_flags |= SI_ATTACH;
69366f9d5cbSmlf 		status = si_initialize_controller(si_ctlp);
69466f9d5cbSmlf 		si_ctlp->sictl_flags &= ~SI_ATTACH;
69566f9d5cbSmlf 		if (status) {
69666f9d5cbSmlf 			goto err_out;
69766f9d5cbSmlf 		}
69866f9d5cbSmlf 
69966f9d5cbSmlf 		attach_state |= ATTACH_PROGRESS_HW_INIT;
70066f9d5cbSmlf 
70166f9d5cbSmlf 		if (si_register_sata_hba_tran(si_ctlp)) {
702e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_INIT, si_ctlp,
703e57ece5bSPraveen Kumar Dasaraju Rama 			    "si3124: setting sata hba tran failed", NULL);
70466f9d5cbSmlf 			goto err_out;
70566f9d5cbSmlf 		}
70666f9d5cbSmlf 
70766f9d5cbSmlf 		si_ctlp->sictl_timeout_id = timeout(
70819397407SSherry Moore 		    (void (*)(void *))si_watchdog_handler,
70919397407SSherry Moore 		    (caddr_t)si_ctlp, si_watchdog_tick);
71066f9d5cbSmlf 
71166f9d5cbSmlf 		si_ctlp->sictl_power_level = PM_LEVEL_D0;
71266f9d5cbSmlf 
71366f9d5cbSmlf 		return (DDI_SUCCESS);
71466f9d5cbSmlf 
71566f9d5cbSmlf 	case DDI_RESUME:
71666f9d5cbSmlf 		si_ctlp = ddi_get_soft_state(si_statep, instance);
71766f9d5cbSmlf 
71866f9d5cbSmlf 		status = si_initialize_controller(si_ctlp);
71966f9d5cbSmlf 		if (status) {
72066f9d5cbSmlf 			return (DDI_FAILURE);
72166f9d5cbSmlf 		}
72266f9d5cbSmlf 
72366f9d5cbSmlf 		si_ctlp->sictl_timeout_id = timeout(
72419397407SSherry Moore 		    (void (*)(void *))si_watchdog_handler,
72519397407SSherry Moore 		    (caddr_t)si_ctlp, si_watchdog_tick);
72666f9d5cbSmlf 
72766f9d5cbSmlf 		(void) pm_power_has_changed(dip, 0, PM_LEVEL_D0);
72866f9d5cbSmlf 
72966f9d5cbSmlf 		/* Notify SATA framework about RESUME. */
73066f9d5cbSmlf 		if (sata_hba_attach(si_ctlp->sictl_devinfop,
73119397407SSherry Moore 		    si_ctlp->sictl_sata_hba_tran,
73219397407SSherry Moore 		    DDI_RESUME) != DDI_SUCCESS) {
73366f9d5cbSmlf 			return (DDI_FAILURE);
73466f9d5cbSmlf 		}
73566f9d5cbSmlf 
73666f9d5cbSmlf 		/*
73766f9d5cbSmlf 		 * Notify the "framework" that it should reprobe ports to see
73866f9d5cbSmlf 		 * if any device got changed while suspended.
73966f9d5cbSmlf 		 */
74066f9d5cbSmlf 		bzero((void *)&sdevice, sizeof (sata_device_t));
74166f9d5cbSmlf 		sata_hba_event_notify(dip, &sdevice,
74219397407SSherry Moore 		    SATA_EVNT_PWR_LEVEL_CHANGED);
743e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_INIT|SIDBG_EVENT, si_ctlp,
744e57ece5bSPraveen Kumar Dasaraju Rama 		    "sending event up: SATA_EVNT_PWR_LEVEL_CHANGED", NULL);
74566f9d5cbSmlf 
74666f9d5cbSmlf 		(void) pm_idle_component(si_ctlp->sictl_devinfop, 0);
74766f9d5cbSmlf 
74866f9d5cbSmlf 		si_ctlp->sictl_power_level = PM_LEVEL_D0;
74966f9d5cbSmlf 
75066f9d5cbSmlf 		return (DDI_SUCCESS);
75166f9d5cbSmlf 
75266f9d5cbSmlf 	default:
75366f9d5cbSmlf 		return (DDI_FAILURE);
75466f9d5cbSmlf 
75566f9d5cbSmlf 	}
75666f9d5cbSmlf 
75766f9d5cbSmlf err_out:
75866f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_HW_INIT) {
75966f9d5cbSmlf 		si_ctlp->sictl_flags |= SI_DETACH;
76066f9d5cbSmlf 		/* We want to set SI_DETACH to deallocate all memory */
761a599d311SMartin Faltesek 		si_deinitialize_controller(si_ctlp);
76266f9d5cbSmlf 		si_ctlp->sictl_flags &= ~SI_DETACH;
76366f9d5cbSmlf 	}
76466f9d5cbSmlf 
76566f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_MUTEX_INIT) {
76666f9d5cbSmlf 		mutex_destroy(&si_ctlp->sictl_mutex);
76766f9d5cbSmlf 	}
76866f9d5cbSmlf 
76966f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_INTR_ADDED) {
77066f9d5cbSmlf 		si_rem_intrs(si_ctlp);
77166f9d5cbSmlf 	}
77266f9d5cbSmlf 
77366f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_BAR1_MAP) {
77466f9d5cbSmlf 		ddi_regs_map_free(&si_ctlp->sictl_port_acc_handle);
77566f9d5cbSmlf 	}
77666f9d5cbSmlf 
77766f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_BAR0_MAP) {
77866f9d5cbSmlf 		ddi_regs_map_free(&si_ctlp->sictl_global_acc_handle);
77966f9d5cbSmlf 	}
78066f9d5cbSmlf 
78166f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_CONF_HANDLE) {
78266f9d5cbSmlf 		pci_config_teardown(&si_ctlp->sictl_pci_conf_handle);
78366f9d5cbSmlf 	}
78466f9d5cbSmlf 
785ab0d082fSMark Logan 	if (attach_state & ATTACH_PROGRESS_INIT_FMA) {
786ab0d082fSMark Logan 		si_fm_fini(si_ctlp);
787ab0d082fSMark Logan 	}
788ab0d082fSMark Logan 
78966f9d5cbSmlf 	if (attach_state & ATTACH_PROGRESS_STATEP_ALLOC) {
79066f9d5cbSmlf 		ddi_soft_state_free(si_statep, instance);
79166f9d5cbSmlf 	}
79266f9d5cbSmlf 
79366f9d5cbSmlf 	return (DDI_FAILURE);
79466f9d5cbSmlf }
79566f9d5cbSmlf 
79666f9d5cbSmlf 
79766f9d5cbSmlf /*
79866f9d5cbSmlf  * The detach entry point for dev_ops.
79966f9d5cbSmlf  *
80066f9d5cbSmlf  * We undo the things we did in si_attach().
80166f9d5cbSmlf  */
80266f9d5cbSmlf static int
si_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)80366f9d5cbSmlf si_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
80466f9d5cbSmlf {
80566f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
80666f9d5cbSmlf 	int instance;
80766f9d5cbSmlf 
808e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG(SIDBG_ENTRY, "si_detach enter", NULL);
80966f9d5cbSmlf 	instance = ddi_get_instance(dip);
81066f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, instance);
81166f9d5cbSmlf 
81266f9d5cbSmlf 	switch (cmd) {
81366f9d5cbSmlf 
81466f9d5cbSmlf 	case DDI_DETACH:
81566f9d5cbSmlf 
81666f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
81766f9d5cbSmlf 
81866f9d5cbSmlf 		/* disable the interrupts for an uninterrupted detach */
81966f9d5cbSmlf 		si_disable_all_interrupts(si_ctlp);
82066f9d5cbSmlf 
82166f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
82266f9d5cbSmlf 		/* unregister from the sata framework. */
82366f9d5cbSmlf 		if (si_unregister_sata_hba_tran(si_ctlp) != SI_SUCCESS) {
82466f9d5cbSmlf 			si_enable_all_interrupts(si_ctlp);
82566f9d5cbSmlf 			return (DDI_FAILURE);
82666f9d5cbSmlf 		}
82766f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
82866f9d5cbSmlf 
82966f9d5cbSmlf 		/* now cancel the timeout handler. */
83066f9d5cbSmlf 		si_ctlp->sictl_flags |= SI_NO_TIMEOUTS;
83166f9d5cbSmlf 		(void) untimeout(si_ctlp->sictl_timeout_id);
83266f9d5cbSmlf 		si_ctlp->sictl_flags &= ~SI_NO_TIMEOUTS;
83366f9d5cbSmlf 
834a599d311SMartin Faltesek 		/* de-initialize the controller. */
83566f9d5cbSmlf 		si_ctlp->sictl_flags |= SI_DETACH;
836a599d311SMartin Faltesek 		si_deinitialize_controller(si_ctlp);
83766f9d5cbSmlf 		si_ctlp->sictl_flags &= ~SI_DETACH;
83866f9d5cbSmlf 
83966f9d5cbSmlf 		/* destroy any mutexes */
84066f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
84166f9d5cbSmlf 		mutex_destroy(&si_ctlp->sictl_mutex);
84266f9d5cbSmlf 
84366f9d5cbSmlf 		/* remove the interrupts */
84466f9d5cbSmlf 		si_rem_intrs(si_ctlp);
84566f9d5cbSmlf 
84666f9d5cbSmlf 		/* remove the reg maps. */
84766f9d5cbSmlf 		ddi_regs_map_free(&si_ctlp->sictl_port_acc_handle);
84866f9d5cbSmlf 		ddi_regs_map_free(&si_ctlp->sictl_global_acc_handle);
84966f9d5cbSmlf 		pci_config_teardown(&si_ctlp->sictl_pci_conf_handle);
85066f9d5cbSmlf 
851ab0d082fSMark Logan 		/* deinit FMA */
852ab0d082fSMark Logan 		si_fm_fini(si_ctlp);
853ab0d082fSMark Logan 
85466f9d5cbSmlf 		/* free the soft state. */
85566f9d5cbSmlf 		ddi_soft_state_free(si_statep, instance);
85666f9d5cbSmlf 
85766f9d5cbSmlf 		return (DDI_SUCCESS);
85866f9d5cbSmlf 
85966f9d5cbSmlf 	case DDI_SUSPEND:
86066f9d5cbSmlf 		/* Inform SATA framework */
86166f9d5cbSmlf 		if (sata_hba_detach(dip, cmd) != DDI_SUCCESS) {
86266f9d5cbSmlf 			return (DDI_FAILURE);
86366f9d5cbSmlf 		}
86466f9d5cbSmlf 
86566f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
86666f9d5cbSmlf 
86766f9d5cbSmlf 		/*
86866f9d5cbSmlf 		 * Device needs to be at full power in case it is needed to
86966f9d5cbSmlf 		 * handle dump(9e) to save CPR state after DDI_SUSPEND
87066f9d5cbSmlf 		 * completes.  This is OK since presumably power will be
87166f9d5cbSmlf 		 * removed anyways.  No outstanding transactions should be
872a599d311SMartin Faltesek 		 * on the controller since the children are already quiesced.
87366f9d5cbSmlf 		 *
87466f9d5cbSmlf 		 * If any ioctls/cfgadm support is added that touches
87566f9d5cbSmlf 		 * hardware, those entry points will need to check for
87666f9d5cbSmlf 		 * suspend and then block or return errors until resume.
87766f9d5cbSmlf 		 *
87866f9d5cbSmlf 		 */
87966f9d5cbSmlf 		if (pm_busy_component(si_ctlp->sictl_devinfop, 0) ==
88019397407SSherry Moore 		    DDI_SUCCESS) {
88166f9d5cbSmlf 			mutex_exit(&si_ctlp->sictl_mutex);
88266f9d5cbSmlf 			(void) pm_raise_power(si_ctlp->sictl_devinfop, 0,
88319397407SSherry Moore 			    PM_LEVEL_D0);
88466f9d5cbSmlf 			mutex_enter(&si_ctlp->sictl_mutex);
88566f9d5cbSmlf 		}
88666f9d5cbSmlf 
887a599d311SMartin Faltesek 		si_deinitialize_controller(si_ctlp);
88866f9d5cbSmlf 
88966f9d5cbSmlf 		si_ctlp->sictl_flags |= SI_NO_TIMEOUTS;
89066f9d5cbSmlf 		(void) untimeout(si_ctlp->sictl_timeout_id);
89166f9d5cbSmlf 		si_ctlp->sictl_flags &= ~SI_NO_TIMEOUTS;
89266f9d5cbSmlf 
893e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_POWER, si_ctlp, "si3124%d: DDI_SUSPEND",
894e57ece5bSPraveen Kumar Dasaraju Rama 		    instance);
89566f9d5cbSmlf 
89666f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
89766f9d5cbSmlf 
89866f9d5cbSmlf 		return (DDI_SUCCESS);
89966f9d5cbSmlf 
90066f9d5cbSmlf 	default:
90166f9d5cbSmlf 		return (DDI_FAILURE);
90266f9d5cbSmlf 
90366f9d5cbSmlf 	}
90466f9d5cbSmlf 
90566f9d5cbSmlf }
90666f9d5cbSmlf 
90766f9d5cbSmlf static int
si_power(dev_info_t * dip,int component,int level)90866f9d5cbSmlf si_power(dev_info_t *dip, int component, int level)
90966f9d5cbSmlf {
91066f9d5cbSmlf #ifndef __lock_lint
91166f9d5cbSmlf 	_NOTE(ARGUNUSED(component))
91266f9d5cbSmlf #endif /* __lock_lint */
91366f9d5cbSmlf 
91466f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
91566f9d5cbSmlf 	int instance = ddi_get_instance(dip);
91666f9d5cbSmlf 	int rval = DDI_SUCCESS;
91766f9d5cbSmlf 	int old_level;
91866f9d5cbSmlf 	sata_device_t sdevice;
91966f9d5cbSmlf 
92066f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, instance);
92166f9d5cbSmlf 
92266f9d5cbSmlf 	if (si_ctlp == NULL) {
92366f9d5cbSmlf 		return (DDI_FAILURE);
92466f9d5cbSmlf 	}
92566f9d5cbSmlf 
926e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_ENTRY, si_ctlp, "si_power enter", NULL);
92766f9d5cbSmlf 
92866f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
92966f9d5cbSmlf 	old_level = si_ctlp->sictl_power_level;
93066f9d5cbSmlf 
93166f9d5cbSmlf 	switch (level) {
93266f9d5cbSmlf 	case PM_LEVEL_D0: /* fully on */
93366f9d5cbSmlf 		pci_config_put16(si_ctlp->sictl_pci_conf_handle,
93419397407SSherry Moore 		    PM_CSR(si_ctlp->sictl_devid), PCI_PMCSR_D0);
93566f9d5cbSmlf #ifndef __lock_lint
93666f9d5cbSmlf 		delay(drv_usectohz(10000));
9370cfc6e4aSxun ni - Sun Microsystems - Beijing China #endif  /* __lock_lint */
93866f9d5cbSmlf 		si_ctlp->sictl_power_level = PM_LEVEL_D0;
93966f9d5cbSmlf 		(void) pci_restore_config_regs(si_ctlp->sictl_devinfop);
94066f9d5cbSmlf 
941e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_POWER, si_ctlp,
94219397407SSherry Moore 		    "si3124%d: turning power ON. old level %d",
94319397407SSherry Moore 		    instance, old_level);
94466f9d5cbSmlf 		/*
94566f9d5cbSmlf 		 * If called from attach, just raise device power,
94666f9d5cbSmlf 		 * restore config registers (if they were saved
94766f9d5cbSmlf 		 * from a previous detach that lowered power),
94866f9d5cbSmlf 		 * and exit.
94966f9d5cbSmlf 		 */
95066f9d5cbSmlf 		if (si_ctlp->sictl_flags & SI_ATTACH)
95166f9d5cbSmlf 			break;
95266f9d5cbSmlf 
95366f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
95466f9d5cbSmlf 		(void) si_initialize_controller(si_ctlp);
95566f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
95666f9d5cbSmlf 
95766f9d5cbSmlf 		si_ctlp->sictl_timeout_id = timeout(
95819397407SSherry Moore 		    (void (*)(void *))si_watchdog_handler,
95919397407SSherry Moore 		    (caddr_t)si_ctlp, si_watchdog_tick);
96066f9d5cbSmlf 
96166f9d5cbSmlf 		bzero((void *)&sdevice, sizeof (sata_device_t));
96266f9d5cbSmlf 		sata_hba_event_notify(
96319397407SSherry Moore 		    si_ctlp->sictl_sata_hba_tran->sata_tran_hba_dip,
96419397407SSherry Moore 		    &sdevice, SATA_EVNT_PWR_LEVEL_CHANGED);
965e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_EVENT|SIDBG_POWER, si_ctlp,
966e57ece5bSPraveen Kumar Dasaraju Rama 		    "sending event up: PWR_LEVEL_CHANGED", NULL);
96766f9d5cbSmlf 
96866f9d5cbSmlf 		break;
96966f9d5cbSmlf 
97066f9d5cbSmlf 	case PM_LEVEL_D3: /* fully off */
97166f9d5cbSmlf 		if (!(si_ctlp->sictl_flags & SI_DETACH)) {
97266f9d5cbSmlf 			si_ctlp->sictl_flags |= SI_NO_TIMEOUTS;
97366f9d5cbSmlf 			(void) untimeout(si_ctlp->sictl_timeout_id);
97466f9d5cbSmlf 			si_ctlp->sictl_flags &= ~SI_NO_TIMEOUTS;
97566f9d5cbSmlf 
976a599d311SMartin Faltesek 			si_deinitialize_controller(si_ctlp);
97766f9d5cbSmlf 
97866f9d5cbSmlf 			si_ctlp->sictl_power_level = PM_LEVEL_D3;
97966f9d5cbSmlf 		}
98066f9d5cbSmlf 
98166f9d5cbSmlf 		(void) pci_save_config_regs(si_ctlp->sictl_devinfop);
98266f9d5cbSmlf 
98366f9d5cbSmlf 		pci_config_put16(si_ctlp->sictl_pci_conf_handle,
98419397407SSherry Moore 		    PM_CSR(si_ctlp->sictl_devid), PCI_PMCSR_D3HOT);
98566f9d5cbSmlf 
986e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_POWER, si_ctlp, "si3124%d: turning power OFF. "
98766f9d5cbSmlf 		    "old level %d", instance, old_level);
98866f9d5cbSmlf 
98966f9d5cbSmlf 		break;
99066f9d5cbSmlf 
99166f9d5cbSmlf 	default:
992e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_POWER, si_ctlp, "si3124%d: turning power OFF. "
99366f9d5cbSmlf 		    "old level %d", instance, old_level);
99466f9d5cbSmlf 		rval = DDI_FAILURE;
99566f9d5cbSmlf 		break;
99666f9d5cbSmlf 	}
99766f9d5cbSmlf 
99866f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
99966f9d5cbSmlf 
100066f9d5cbSmlf 	return (rval);
100166f9d5cbSmlf }
100266f9d5cbSmlf 
100366f9d5cbSmlf 
100466f9d5cbSmlf /*
100566f9d5cbSmlf  * The info entry point for dev_ops.
100666f9d5cbSmlf  *
100766f9d5cbSmlf  */
100866f9d5cbSmlf static int
si_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)1009*83dba8e1SToomas Soome si_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
101066f9d5cbSmlf {
101166f9d5cbSmlf #ifndef __lock_lint
101266f9d5cbSmlf 	_NOTE(ARGUNUSED(dip))
101366f9d5cbSmlf #endif /* __lock_lint */
101466f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
101566f9d5cbSmlf 	int instance;
101666f9d5cbSmlf 	dev_t dev;
101766f9d5cbSmlf 
101866f9d5cbSmlf 	dev = (dev_t)arg;
101966f9d5cbSmlf 	instance = getminor(dev);
102066f9d5cbSmlf 
102166f9d5cbSmlf 	switch (infocmd) {
102266f9d5cbSmlf 		case DDI_INFO_DEVT2DEVINFO:
102366f9d5cbSmlf 			si_ctlp = ddi_get_soft_state(si_statep,  instance);
102466f9d5cbSmlf 			if (si_ctlp != NULL) {
102566f9d5cbSmlf 				*result = si_ctlp->sictl_devinfop;
102666f9d5cbSmlf 				return (DDI_SUCCESS);
102766f9d5cbSmlf 			} else {
102866f9d5cbSmlf 				*result = NULL;
102966f9d5cbSmlf 				return (DDI_FAILURE);
103066f9d5cbSmlf 			}
103166f9d5cbSmlf 		case DDI_INFO_DEVT2INSTANCE:
103266f9d5cbSmlf 			*(int *)result = instance;
103366f9d5cbSmlf 			break;
103466f9d5cbSmlf 		default:
103566f9d5cbSmlf 			break;
103666f9d5cbSmlf 	}
103766f9d5cbSmlf 	return (DDI_SUCCESS);
103866f9d5cbSmlf }
103966f9d5cbSmlf 
104066f9d5cbSmlf 
104166f9d5cbSmlf 
104266f9d5cbSmlf /*
104366f9d5cbSmlf  * Registers the si3124 with sata framework.
104466f9d5cbSmlf  */
104566f9d5cbSmlf static int
si_register_sata_hba_tran(si_ctl_state_t * si_ctlp)104666f9d5cbSmlf si_register_sata_hba_tran(si_ctl_state_t *si_ctlp)
104766f9d5cbSmlf {
1048*83dba8e1SToomas Soome 	struct	sata_hba_tran	*sata_hba_tran;
104966f9d5cbSmlf 
1050e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_ENTRY, si_ctlp,
1051e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_register_sata_hba_tran entry", NULL);
105266f9d5cbSmlf 
105366f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
105466f9d5cbSmlf 
105566f9d5cbSmlf 	/* Allocate memory for the sata_hba_tran  */
105666f9d5cbSmlf 	sata_hba_tran = kmem_zalloc(sizeof (sata_hba_tran_t), KM_SLEEP);
105766f9d5cbSmlf 
105866f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_rev = SATA_TRAN_HBA_REV;
105966f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_dip = si_ctlp->sictl_devinfop;
106081a0678eSxun ni - Sun Microsystems - Beijing China 
106181a0678eSxun ni - Sun Microsystems - Beijing China 	if (si_dma_sg_number > SI_MAX_SGT_TABLES_PER_PRB) {
106281a0678eSxun ni - Sun Microsystems - Beijing China 		si_dma_sg_number = SI_MAX_SGT_TABLES_PER_PRB;
106381a0678eSxun ni - Sun Microsystems - Beijing China 	} else if (si_dma_sg_number < SI_MIN_SGT_TABLES_PER_PRB) {
106481a0678eSxun ni - Sun Microsystems - Beijing China 		si_dma_sg_number = SI_MIN_SGT_TABLES_PER_PRB;
106581a0678eSxun ni - Sun Microsystems - Beijing China 	}
106681a0678eSxun ni - Sun Microsystems - Beijing China 
106781a0678eSxun ni - Sun Microsystems - Beijing China 	if (si_dma_sg_number != SI_DEFAULT_SGT_TABLES_PER_PRB) {
106881a0678eSxun ni - Sun Microsystems - Beijing China 		buffer_dma_attr.dma_attr_sgllen = SGE_LENGTH(si_dma_sg_number);
106981a0678eSxun ni - Sun Microsystems - Beijing China 	}
107066f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_dma_attr = &buffer_dma_attr;
107166f9d5cbSmlf 
107266f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_num_cports = si_ctlp->sictl_num_ports;
107366f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_features_support = 0;
107466f9d5cbSmlf 	sata_hba_tran->sata_tran_hba_qdepth = SI_NUM_SLOTS;
107566f9d5cbSmlf 
107666f9d5cbSmlf 	sata_hba_tran->sata_tran_probe_port = si_tran_probe_port;
107766f9d5cbSmlf 	sata_hba_tran->sata_tran_start = si_tran_start;
107866f9d5cbSmlf 	sata_hba_tran->sata_tran_abort = si_tran_abort;
107966f9d5cbSmlf 	sata_hba_tran->sata_tran_reset_dport = si_tran_reset_dport;
108066f9d5cbSmlf 	sata_hba_tran->sata_tran_selftest = NULL;
108166f9d5cbSmlf 	sata_hba_tran->sata_tran_hotplug_ops = &si_tran_hotplug_ops;
108266f9d5cbSmlf 	sata_hba_tran->sata_tran_pwrmgt_ops = NULL;
108366f9d5cbSmlf 	sata_hba_tran->sata_tran_ioctl = NULL;
108466f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
108566f9d5cbSmlf 
108666f9d5cbSmlf 	/* Attach it to SATA framework */
108766f9d5cbSmlf 	if (sata_hba_attach(si_ctlp->sictl_devinfop, sata_hba_tran, DDI_ATTACH)
108819397407SSherry Moore 	    != DDI_SUCCESS) {
108966f9d5cbSmlf 		kmem_free((void *)sata_hba_tran, sizeof (sata_hba_tran_t));
109066f9d5cbSmlf 		return (SI_FAILURE);
109166f9d5cbSmlf 	}
109266f9d5cbSmlf 
109366f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
109466f9d5cbSmlf 	si_ctlp->sictl_sata_hba_tran = sata_hba_tran;
109566f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
109666f9d5cbSmlf 
109766f9d5cbSmlf 	return (SI_SUCCESS);
109866f9d5cbSmlf }
109966f9d5cbSmlf 
110066f9d5cbSmlf 
110166f9d5cbSmlf /*
110266f9d5cbSmlf  * Unregisters the si3124 with sata framework.
110366f9d5cbSmlf  */
110466f9d5cbSmlf static int
si_unregister_sata_hba_tran(si_ctl_state_t * si_ctlp)110566f9d5cbSmlf si_unregister_sata_hba_tran(si_ctl_state_t *si_ctlp)
110666f9d5cbSmlf {
110766f9d5cbSmlf 
110866f9d5cbSmlf 	/* Detach from the SATA framework. */
110966f9d5cbSmlf 	if (sata_hba_detach(si_ctlp->sictl_devinfop, DDI_DETACH) !=
111019397407SSherry Moore 	    DDI_SUCCESS) {
111166f9d5cbSmlf 		return (SI_FAILURE);
111266f9d5cbSmlf 	}
111366f9d5cbSmlf 
111466f9d5cbSmlf 	/* Deallocate sata_hba_tran. */
111566f9d5cbSmlf 	kmem_free((void *)si_ctlp->sictl_sata_hba_tran,
111619397407SSherry Moore 	    sizeof (sata_hba_tran_t));
111766f9d5cbSmlf 
111866f9d5cbSmlf 	si_ctlp->sictl_sata_hba_tran = NULL;
111966f9d5cbSmlf 
112066f9d5cbSmlf 	return (SI_SUCCESS);
112166f9d5cbSmlf }
112266f9d5cbSmlf 
112366f9d5cbSmlf /*
112466f9d5cbSmlf  * Called by sata framework to probe a port. We return the
112566f9d5cbSmlf  * cached information from a previous hardware probe.
112666f9d5cbSmlf  *
112766f9d5cbSmlf  * The actual hardware probing itself was done either from within
112866f9d5cbSmlf  * si_initialize_controller() during the driver attach or
112966f9d5cbSmlf  * from a phy ready change interrupt handler.
113066f9d5cbSmlf  */
113166f9d5cbSmlf static int
si_tran_probe_port(dev_info_t * dip,sata_device_t * sd)113266f9d5cbSmlf si_tran_probe_port(dev_info_t *dip, sata_device_t *sd)
113366f9d5cbSmlf {
113466f9d5cbSmlf 
113566f9d5cbSmlf 	si_ctl_state_t	*si_ctlp;
113666f9d5cbSmlf 	uint8_t cport = sd->satadev_addr.cport;
113766f9d5cbSmlf 	uint8_t pmport = sd->satadev_addr.pmport;
113866f9d5cbSmlf 	uint8_t qual = sd->satadev_addr.qual;
113966f9d5cbSmlf 	uint8_t port_type;
114066f9d5cbSmlf 	si_port_state_t *si_portp;
114166f9d5cbSmlf 	si_portmult_state_t *si_portmultp;
114266f9d5cbSmlf 
114366f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
114466f9d5cbSmlf 
1145e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_ENTRY, si_ctlp,
114619397407SSherry Moore 	    "si_tran_probe_port: cport: 0x%x, pmport: 0x%x, qual: 0x%x",
114719397407SSherry Moore 	    cport, pmport, qual);
114866f9d5cbSmlf 
114966f9d5cbSmlf 	if (cport >= SI_MAX_PORTS) {
115066f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_NONE;
11514372d277Spawelw 		sd->satadev_state = SATA_STATE_UNKNOWN; /* invalid port */
115266f9d5cbSmlf 		return (SATA_FAILURE);
115366f9d5cbSmlf 	}
115466f9d5cbSmlf 
115566f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
115666f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[cport];
115766f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
115866f9d5cbSmlf 	if (si_portp == NULL) {
115966f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_NONE;
11604372d277Spawelw 		sd->satadev_state = SATA_STATE_UNKNOWN;
116166f9d5cbSmlf 		return (SATA_FAILURE);
116266f9d5cbSmlf 	}
116366f9d5cbSmlf 
116466f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
116566f9d5cbSmlf 
116666f9d5cbSmlf 	if (qual == SATA_ADDR_PMPORT) {
116766f9d5cbSmlf 		if (pmport >= si_portp->siport_portmult_state.sipm_num_ports) {
116866f9d5cbSmlf 			sd->satadev_type = SATA_DTYPE_NONE;
11694372d277Spawelw 			sd->satadev_state = SATA_STATE_UNKNOWN;
117066f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
117166f9d5cbSmlf 			return (SATA_FAILURE);
117266f9d5cbSmlf 		} else {
1173*83dba8e1SToomas Soome 			si_portmultp = &si_portp->siport_portmult_state;
117466f9d5cbSmlf 			port_type = si_portmultp->sipm_port_type[pmport];
117566f9d5cbSmlf 		}
117666f9d5cbSmlf 	} else {
117766f9d5cbSmlf 		port_type = si_portp->siport_port_type;
117866f9d5cbSmlf 	}
117966f9d5cbSmlf 
118066f9d5cbSmlf 	switch (port_type) {
118166f9d5cbSmlf 
118266f9d5cbSmlf 	case PORT_TYPE_DISK:
118366f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_ATADISK;
118466f9d5cbSmlf 		break;
118566f9d5cbSmlf 
118666f9d5cbSmlf 	case PORT_TYPE_ATAPI:
118766f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_ATAPICD;
118866f9d5cbSmlf 		break;
118966f9d5cbSmlf 
119066f9d5cbSmlf 	case PORT_TYPE_MULTIPLIER:
119166f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_PMULT;
119266f9d5cbSmlf 		sd->satadev_add_info =
119319397407SSherry Moore 		    si_portp->siport_portmult_state.sipm_num_ports;
119466f9d5cbSmlf 		break;
119566f9d5cbSmlf 
119666f9d5cbSmlf 	case PORT_TYPE_UNKNOWN:
119766f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_UNKNOWN;
11984372d277Spawelw 		break;
119966f9d5cbSmlf 
120066f9d5cbSmlf 	default:
120166f9d5cbSmlf 		/* we don't support any other device types. */
120266f9d5cbSmlf 		sd->satadev_type = SATA_DTYPE_NONE;
120366f9d5cbSmlf 		break;
120466f9d5cbSmlf 	}
12054372d277Spawelw 	sd->satadev_state = SATA_STATE_READY;
120666f9d5cbSmlf 
120766f9d5cbSmlf 	if (qual == SATA_ADDR_PMPORT) {
120866f9d5cbSmlf 		(void) si_read_portmult_reg(si_ctlp, si_portp, cport,
120919397407SSherry Moore 		    pmport, PSCR_REG0, &sd->satadev_scr.sstatus);
121066f9d5cbSmlf 		(void) si_read_portmult_reg(si_ctlp, si_portp, cport,
121119397407SSherry Moore 		    pmport, PSCR_REG1, &sd->satadev_scr.serror);
121266f9d5cbSmlf 		(void) si_read_portmult_reg(si_ctlp, si_portp, cport,
121319397407SSherry Moore 		    pmport, PSCR_REG2, &sd->satadev_scr.scontrol);
121466f9d5cbSmlf 		(void) si_read_portmult_reg(si_ctlp, si_portp, cport,
121519397407SSherry Moore 		    pmport, PSCR_REG3, &sd->satadev_scr.sactive);
121666f9d5cbSmlf 	} else {
121766f9d5cbSmlf 		fill_dev_sregisters(si_ctlp, cport, sd);
121866f9d5cbSmlf 		if (!(si_portp->siport_active)) {
121966f9d5cbSmlf 			/*
122066f9d5cbSmlf 			 * Since we are implementing the port deactivation
122166f9d5cbSmlf 			 * in software only, we need to fake a valid value
122266f9d5cbSmlf 			 * for sstatus when the device is in deactivated state.
122366f9d5cbSmlf 			 */
122466f9d5cbSmlf 			SSTATUS_SET_DET(sd->satadev_scr.sstatus,
122519397407SSherry Moore 			    SSTATUS_DET_PHYOFFLINE);
122666f9d5cbSmlf 			SSTATUS_SET_IPM(sd->satadev_scr.sstatus,
122719397407SSherry Moore 			    SSTATUS_IPM_NODEV_NOPHY);
12284372d277Spawelw 			sd->satadev_state = SATA_PSTATE_SHUTDOWN;
122966f9d5cbSmlf 		}
123066f9d5cbSmlf 	}
123166f9d5cbSmlf 
123266f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
123366f9d5cbSmlf 	return (SATA_SUCCESS);
123466f9d5cbSmlf }
123566f9d5cbSmlf 
123666f9d5cbSmlf /*
123766f9d5cbSmlf  * Called by sata framework to transport a sata packet down stream.
123866f9d5cbSmlf  *
123966f9d5cbSmlf  * The actual work of building the FIS & transporting it to the hardware
124066f9d5cbSmlf  * is done out of the subroutine si_deliver_satapkt().
124166f9d5cbSmlf  */
124266f9d5cbSmlf static int
si_tran_start(dev_info_t * dip,sata_pkt_t * spkt)124366f9d5cbSmlf si_tran_start(dev_info_t *dip, sata_pkt_t *spkt)
124466f9d5cbSmlf {
124566f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
124666f9d5cbSmlf 	uint8_t	cport;
124766f9d5cbSmlf 	si_port_state_t *si_portp;
124866f9d5cbSmlf 	int slot;
124966f9d5cbSmlf 
125066f9d5cbSmlf 	cport = spkt->satapkt_device.satadev_addr.cport;
125166f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
125266f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
125366f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[cport];
125466f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
125566f9d5cbSmlf 
1256e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp,
1257e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_tran_start entry", NULL);
125866f9d5cbSmlf 
125966f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
126066f9d5cbSmlf 
126166f9d5cbSmlf 	if ((si_portp->siport_port_type == PORT_TYPE_NODEV) ||
126219397407SSherry Moore 	    !si_portp->siport_active) {
126366f9d5cbSmlf 		/*
126466f9d5cbSmlf 		 * si_intr_phy_ready_change() may have rendered it to
126566f9d5cbSmlf 		 * PORT_TYPE_NODEV. cfgadm operation may have rendered
126666f9d5cbSmlf 		 * it inactive.
126766f9d5cbSmlf 		 */
126866f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
126966f9d5cbSmlf 		fill_dev_sregisters(si_ctlp, cport, &spkt->satapkt_device);
127066f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
127166f9d5cbSmlf 		return (SATA_TRAN_PORT_ERROR);
127266f9d5cbSmlf 	}
127366f9d5cbSmlf 
1274c03acfcaSls 	if (spkt->satapkt_cmd.satacmd_flags.sata_clear_dev_reset) {
127566f9d5cbSmlf 		si_portp->siport_reset_in_progress = 0;
1276e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_RESET, si_portp,
127719397407SSherry Moore 		    "si_tran_start clearing the "
1278e57ece5bSPraveen Kumar Dasaraju Rama 		    "reset_in_progress for port", NULL);
127966f9d5cbSmlf 	}
128066f9d5cbSmlf 
128166f9d5cbSmlf 	if (si_portp->siport_reset_in_progress &&
128219397407SSherry Moore 	    ! spkt->satapkt_cmd.satacmd_flags.sata_ignore_dev_reset &&
128319397407SSherry Moore 	    ! ddi_in_panic()) {
128466f9d5cbSmlf 
128566f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_BUSY;
1286e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_RESET, si_portp,
128719397407SSherry Moore 		    "si_tran_start returning BUSY while "
1288e57ece5bSPraveen Kumar Dasaraju Rama 		    "reset in progress for port", NULL);
128966f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
129066f9d5cbSmlf 		return (SATA_TRAN_BUSY);
129166f9d5cbSmlf 	}
129266f9d5cbSmlf 
1293cf6ed809SMark Logan 	if (si_portp->mopping_in_progress > 0) {
129466f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_BUSY;
1295e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_RESET, si_portp,
129619397407SSherry Moore 		    "si_tran_start returning BUSY while "
1297e57ece5bSPraveen Kumar Dasaraju Rama 		    "mopping in progress for port", NULL);
129866f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
129966f9d5cbSmlf 		return (SATA_TRAN_BUSY);
130066f9d5cbSmlf 	}
130166f9d5cbSmlf 
130266f9d5cbSmlf 	if ((slot = si_deliver_satapkt(si_ctlp, si_portp, cport, spkt))
130319397407SSherry Moore 	    == SI_FAILURE) {
130466f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_QUEUE_FULL;
1305e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
1306e57ece5bSPraveen Kumar Dasaraju Rama 		    "si_tran_start returning QUEUE_FULL",
1307e57ece5bSPraveen Kumar Dasaraju Rama 		    NULL);
130866f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
130966f9d5cbSmlf 		return (SATA_TRAN_QUEUE_FULL);
131066f9d5cbSmlf 	}
131166f9d5cbSmlf 
131266f9d5cbSmlf 	if (spkt->satapkt_op_mode & (SATA_OPMODE_POLLING|SATA_OPMODE_SYNCH)) {
131366f9d5cbSmlf 		/* we need to poll now */
131466f9d5cbSmlf 		si_poll_cmd(si_ctlp, si_portp, cport, slot, spkt);
1315ed385ad9SMark Logan 		/*
1316ed385ad9SMark Logan 		 * The command has completed, and spkt will be freed by the
1317ed385ad9SMark Logan 		 * sata module, so don't keep a pointer to it lying around.
1318ed385ad9SMark Logan 		 */
1319ed385ad9SMark Logan 		si_portp->siport_slot_pkts[slot] = NULL;
132066f9d5cbSmlf 	}
132166f9d5cbSmlf 
132266f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
132366f9d5cbSmlf 	return (SATA_TRAN_ACCEPTED);
132466f9d5cbSmlf }
132566f9d5cbSmlf 
132666f9d5cbSmlf #define	SENDUP_PACKET(si_portp, satapkt, reason)			\
1327ab0d082fSMark Logan 	if (satapkt) {							\
1328ab0d082fSMark Logan 		if ((satapkt->satapkt_cmd.satacmd_cmd_reg ==		\
132966f9d5cbSmlf 					SATAC_WRITE_FPDMA_QUEUED) ||	\
1330ab0d082fSMark Logan 		    (satapkt->satapkt_cmd.satacmd_cmd_reg ==		\
133166f9d5cbSmlf 					SATAC_READ_FPDMA_QUEUED)) {	\
1332ab0d082fSMark Logan 			si_portp->siport_pending_ncq_count--;		\
1333ab0d082fSMark Logan 		}							\
133466f9d5cbSmlf 		satapkt->satapkt_reason = reason;			\
133566f9d5cbSmlf 		/*							\
133666f9d5cbSmlf 		 * We set the satapkt_reason in both synch and		\
133766f9d5cbSmlf 		 * non-synch cases.					\
133866f9d5cbSmlf 		 */							\
1339ab0d082fSMark Logan 		if (!(satapkt->satapkt_op_mode & SATA_OPMODE_SYNCH) &&	\
1340ab0d082fSMark Logan 			satapkt->satapkt_comp) {			\
1341ab0d082fSMark Logan 			mutex_exit(&si_portp->siport_mutex);		\
1342ab0d082fSMark Logan 			(*satapkt->satapkt_comp)(satapkt);		\
1343ab0d082fSMark Logan 			mutex_enter(&si_portp->siport_mutex);		\
1344ab0d082fSMark Logan 		}							\
134566f9d5cbSmlf 	}
134666f9d5cbSmlf 
134766f9d5cbSmlf /*
134866f9d5cbSmlf  * Mopping is necessitated because of the si3124 hardware limitation.
134966f9d5cbSmlf  * The only way to recover from errors or to abort a command is to
135066f9d5cbSmlf  * reset the port/device but such a reset also results in throwing
135166f9d5cbSmlf  * away all the unfinished pending commands.
135266f9d5cbSmlf  *
135366f9d5cbSmlf  * A port or device is reset in four scenarios:
135466f9d5cbSmlf  *	a) some commands failed with errors
135566f9d5cbSmlf  *	b) or we need to timeout some commands
135666f9d5cbSmlf  *	c) or we need to abort some commands
135766f9d5cbSmlf  *	d) or we need reset the port at the request of sata framework
135866f9d5cbSmlf  *
135966f9d5cbSmlf  * In all these scenarios, we need to send any pending unfinished
136066f9d5cbSmlf  * commands up to sata framework.
136166f9d5cbSmlf  *
1362cf6ed809SMark Logan  * WARNING!!! siport_mutex should be acquired before the function is called.
136366f9d5cbSmlf  */
136466f9d5cbSmlf static void
si_mop_commands(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,uint8_t port,uint32_t slot_status,uint32_t failed_tags,uint32_t timedout_tags,uint32_t aborting_tags,uint32_t reset_tags)1365*83dba8e1SToomas Soome si_mop_commands(si_ctl_state_t *si_ctlp, si_port_state_t *si_portp,
1366*83dba8e1SToomas Soome     uint8_t port, uint32_t slot_status, uint32_t failed_tags,
1367*83dba8e1SToomas Soome     uint32_t timedout_tags, uint32_t aborting_tags, uint32_t reset_tags)
136866f9d5cbSmlf {
136966f9d5cbSmlf 	uint32_t finished_tags, unfinished_tags;
137066f9d5cbSmlf 	int tmpslot;
137166f9d5cbSmlf 	sata_pkt_t *satapkt;
1372a599d311SMartin Faltesek 	struct sata_cmd_flags *flagsp;
137366f9d5cbSmlf 
1374e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
137519397407SSherry Moore 	    "si_mop_commands entered: slot_status: 0x%x",
137619397407SSherry Moore 	    slot_status);
137766f9d5cbSmlf 
1378e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
137919397407SSherry Moore 	    "si_mop_commands: failed_tags: 0x%x, timedout_tags: 0x%x"
138019397407SSherry Moore 	    "aborting_tags: 0x%x, reset_tags: 0x%x",
138119397407SSherry Moore 	    failed_tags,
138219397407SSherry Moore 	    timedout_tags,
138319397407SSherry Moore 	    aborting_tags,
138419397407SSherry Moore 	    reset_tags);
1385cf6ed809SMark Logan 
138666f9d5cbSmlf 	/*
138766f9d5cbSmlf 	 * We could be here for four reasons: abort, reset,
138866f9d5cbSmlf 	 * timeout or error handling. Only one such mopping
138966f9d5cbSmlf 	 * is allowed at a time.
139066f9d5cbSmlf 	 */
139166f9d5cbSmlf 
139266f9d5cbSmlf 	finished_tags =  si_portp->siport_pending_tags &
139319397407SSherry Moore 	    ~slot_status & SI_SLOT_MASK;
139466f9d5cbSmlf 
139566f9d5cbSmlf 	unfinished_tags = slot_status & SI_SLOT_MASK &
139619397407SSherry Moore 	    ~failed_tags &
139719397407SSherry Moore 	    ~aborting_tags &
139819397407SSherry Moore 	    ~reset_tags &
139919397407SSherry Moore 	    ~timedout_tags;
140066f9d5cbSmlf 
140166f9d5cbSmlf 	/* Send up the finished_tags with SATA_PKT_COMPLETED. */
140266f9d5cbSmlf 	while (finished_tags) {
140366f9d5cbSmlf 		tmpslot = ddi_ffs(finished_tags) - 1;
140466f9d5cbSmlf 		if (tmpslot == -1) {
140566f9d5cbSmlf 			break;
140666f9d5cbSmlf 		}
140766f9d5cbSmlf 
140866f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
1409a599d311SMartin Faltesek 
1410ed385ad9SMark Logan 		if (satapkt != NULL &&
1411ed385ad9SMark Logan 		    satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
1412a599d311SMartin Faltesek 			si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp,
1413a599d311SMartin Faltesek 			    port, tmpslot);
1414a599d311SMartin Faltesek 		}
1415c03acfcaSls 
1416e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
141719397407SSherry Moore 		    "si_mop_commands sending up completed satapkt: %x",
141819397407SSherry Moore 		    satapkt);
141966f9d5cbSmlf 
142066f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
142166f9d5cbSmlf 		CLEAR_BIT(finished_tags, tmpslot);
1422a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_COMPLETED);
142366f9d5cbSmlf 	}
142466f9d5cbSmlf 
142566f9d5cbSmlf 	ASSERT(finished_tags == 0);
142666f9d5cbSmlf 
142766f9d5cbSmlf 	/* Send up failed_tags with SATA_PKT_DEV_ERROR. */
142866f9d5cbSmlf 	while (failed_tags) {
142966f9d5cbSmlf 		tmpslot = ddi_ffs(failed_tags) - 1;
143066f9d5cbSmlf 		if (tmpslot == -1) {
143166f9d5cbSmlf 			break;
143266f9d5cbSmlf 		}
1433e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp, "si3124: si_mop_commands: "
143419397407SSherry Moore 		    "handling failed slot: 0x%x", tmpslot);
143566f9d5cbSmlf 
143666f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
143766f9d5cbSmlf 
1438ed385ad9SMark Logan 		if (satapkt != NULL) {
14390cfc6e4aSxun ni - Sun Microsystems - Beijing China 
1440ed385ad9SMark Logan 			if (satapkt->satapkt_device.satadev_type ==
1441ed385ad9SMark Logan 			    SATA_DTYPE_ATAPICD) {
1442ed385ad9SMark Logan 				si_set_sense_data(satapkt, SATA_PKT_DEV_ERROR);
1443ed385ad9SMark Logan 			}
144466f9d5cbSmlf 
1445c03acfcaSls 
1446ed385ad9SMark Logan 			flagsp = &satapkt->satapkt_cmd.satacmd_flags;
144766f9d5cbSmlf 
1448ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_low_msb = B_TRUE;
1449ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_mid_msb = B_TRUE;
1450ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_high_msb = B_TRUE;
1451ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_low_lsb = B_TRUE;
1452ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_mid_lsb = B_TRUE;
1453ed385ad9SMark Logan 			flagsp->sata_copy_out_lba_high_lsb = B_TRUE;
1454ed385ad9SMark Logan 			flagsp->sata_copy_out_error_reg = B_TRUE;
1455ed385ad9SMark Logan 			flagsp->sata_copy_out_sec_count_msb = B_TRUE;
1456ed385ad9SMark Logan 			flagsp->sata_copy_out_sec_count_lsb = B_TRUE;
1457ed385ad9SMark Logan 			flagsp->sata_copy_out_device_reg = B_TRUE;
1458ed385ad9SMark Logan 
1459ed385ad9SMark Logan 			si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp,
1460ed385ad9SMark Logan 			    port, tmpslot);
1461ed385ad9SMark Logan 
1462ed385ad9SMark Logan 			/*
1463ed385ad9SMark Logan 			 * In the case of NCQ command failures, the error is
1464ed385ad9SMark Logan 			 * overwritten by the one obtained from issuing of a
1465ed385ad9SMark Logan 			 * READ LOG EXTENDED command.
1466ed385ad9SMark Logan 			 */
1467ed385ad9SMark Logan 			if (si_portp->siport_err_tags_SDBERROR &
1468ed385ad9SMark Logan 			    (1 << tmpslot)) {
1469ed385ad9SMark Logan 				satapkt->satapkt_cmd.satacmd_error_reg =
1470ed385ad9SMark Logan 				    si_read_log_ext(si_ctlp, si_portp, port);
1471ed385ad9SMark Logan 			}
147266f9d5cbSmlf 		}
147366f9d5cbSmlf 
147466f9d5cbSmlf 		CLEAR_BIT(failed_tags, tmpslot);
147566f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
1476a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_DEV_ERROR);
147766f9d5cbSmlf 	}
147866f9d5cbSmlf 
147966f9d5cbSmlf 	ASSERT(failed_tags == 0);
148066f9d5cbSmlf 
148166f9d5cbSmlf 	/* Send up timedout_tags with SATA_PKT_TIMEOUT. */
148266f9d5cbSmlf 	while (timedout_tags) {
148366f9d5cbSmlf 		tmpslot = ddi_ffs(timedout_tags) - 1;
148466f9d5cbSmlf 		if (tmpslot == -1) {
148566f9d5cbSmlf 			break;
148666f9d5cbSmlf 		}
148766f9d5cbSmlf 
148866f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
1489e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
149019397407SSherry Moore 		    "si_mop_commands sending "
149119397407SSherry Moore 		    "spkt up with PKT_TIMEOUT: %x",
149219397407SSherry Moore 		    satapkt);
149366f9d5cbSmlf 
149466f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
149566f9d5cbSmlf 		CLEAR_BIT(timedout_tags, tmpslot);
1496a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_TIMEOUT);
149766f9d5cbSmlf 	}
149866f9d5cbSmlf 
149966f9d5cbSmlf 	ASSERT(timedout_tags == 0);
150066f9d5cbSmlf 
150166f9d5cbSmlf 	/* Send up aborting packets with SATA_PKT_ABORTED. */
150266f9d5cbSmlf 	while (aborting_tags) {
1503cf6ed809SMark Logan 		tmpslot = ddi_ffs(aborting_tags) - 1;
150466f9d5cbSmlf 		if (tmpslot == -1) {
150566f9d5cbSmlf 			break;
150666f9d5cbSmlf 		}
150766f9d5cbSmlf 
150866f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
1509e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
151019397407SSherry Moore 		    "si_mop_commands aborting spkt: %x",
151119397407SSherry Moore 		    satapkt);
1512ed385ad9SMark Logan 		if (satapkt != NULL && satapkt->satapkt_device.satadev_type ==
151319397407SSherry Moore 		    SATA_DTYPE_ATAPICD) {
151466f9d5cbSmlf 			si_set_sense_data(satapkt, SATA_PKT_ABORTED);
151566f9d5cbSmlf 		}
151666f9d5cbSmlf 
151766f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
151866f9d5cbSmlf 		CLEAR_BIT(aborting_tags, tmpslot);
1519a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_ABORTED);
152066f9d5cbSmlf 
152166f9d5cbSmlf 	}
152266f9d5cbSmlf 
152366f9d5cbSmlf 	ASSERT(aborting_tags == 0);
152466f9d5cbSmlf 
152566f9d5cbSmlf 	/* Reset tags are sent up to framework with SATA_PKT_RESET. */
152666f9d5cbSmlf 	while (reset_tags) {
152766f9d5cbSmlf 		tmpslot = ddi_ffs(reset_tags) - 1;
152866f9d5cbSmlf 		if (tmpslot == -1) {
152966f9d5cbSmlf 			break;
153066f9d5cbSmlf 		}
153166f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
1532e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
153319397407SSherry Moore 		    "si_mop_commands sending PKT_RESET for "
153419397407SSherry Moore 		    "reset spkt: %x",
153519397407SSherry Moore 		    satapkt);
153666f9d5cbSmlf 
153766f9d5cbSmlf 		CLEAR_BIT(reset_tags, tmpslot);
153866f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
1539a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_RESET);
154066f9d5cbSmlf 	}
154166f9d5cbSmlf 
154266f9d5cbSmlf 	ASSERT(reset_tags == 0);
154366f9d5cbSmlf 
1544832d3fc2SMark Logan 	/* Send up the unfinished_tags with SATA_PKT_RESET. */
154566f9d5cbSmlf 	while (unfinished_tags) {
154666f9d5cbSmlf 		tmpslot = ddi_ffs(unfinished_tags) - 1;
154766f9d5cbSmlf 		if (tmpslot == -1) {
154866f9d5cbSmlf 			break;
154966f9d5cbSmlf 		}
155066f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[tmpslot];
1551e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
1552832d3fc2SMark Logan 		    "si_mop_commands sending SATA_PKT_RESET for "
155319397407SSherry Moore 		    "retry spkt: %x",
155419397407SSherry Moore 		    satapkt);
155566f9d5cbSmlf 
155666f9d5cbSmlf 		CLEAR_BIT(unfinished_tags, tmpslot);
155766f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, tmpslot);
1558832d3fc2SMark Logan 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_RESET);
155966f9d5cbSmlf 	}
156066f9d5cbSmlf 
156166f9d5cbSmlf 	ASSERT(unfinished_tags == 0);
156266f9d5cbSmlf 
1563cf6ed809SMark Logan 	si_portp->mopping_in_progress--;
1564cf6ed809SMark Logan 	ASSERT(si_portp->mopping_in_progress >= 0);
156566f9d5cbSmlf }
156666f9d5cbSmlf 
156766f9d5cbSmlf /*
156866f9d5cbSmlf  * Called by the sata framework to abort the previously sent packet(s).
156966f9d5cbSmlf  *
157066f9d5cbSmlf  * We reset the device and mop the commands on the port.
157166f9d5cbSmlf  */
157266f9d5cbSmlf static int
si_tran_abort(dev_info_t * dip,sata_pkt_t * spkt,int flag)157366f9d5cbSmlf si_tran_abort(dev_info_t *dip, sata_pkt_t *spkt, int flag)
157466f9d5cbSmlf {
157566f9d5cbSmlf 	uint32_t slot_status;
157666f9d5cbSmlf 	uint8_t	port;
157766f9d5cbSmlf 	int tmpslot;
157866f9d5cbSmlf 	uint32_t aborting_tags;
157966f9d5cbSmlf 	uint32_t finished_tags;
158066f9d5cbSmlf 	si_port_state_t *si_portp;
158166f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
158266f9d5cbSmlf 
158366f9d5cbSmlf 	port = spkt->satapkt_device.satadev_addr.cport;
158466f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
158566f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
158666f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
158766f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
158866f9d5cbSmlf 
1589e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp, "si_tran_abort on port: %x", port);
159066f9d5cbSmlf 
159166f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
159266f9d5cbSmlf 
1593cf6ed809SMark Logan 	/*
1594cf6ed809SMark Logan 	 * If already mopping, then no need to abort anything.
1595cf6ed809SMark Logan 	 */
1596cf6ed809SMark Logan 	if (si_portp->mopping_in_progress > 0) {
1597e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_ERRS, si_portp,
1598cf6ed809SMark Logan 		    "si_tran_abort: port %d mopping "
1599cf6ed809SMark Logan 		    "in progress, so just return", port);
1600cf6ed809SMark Logan 		mutex_exit(&si_portp->siport_mutex);
1601cf6ed809SMark Logan 		return (SATA_SUCCESS);
1602cf6ed809SMark Logan 	}
1603cf6ed809SMark Logan 
160466f9d5cbSmlf 	if ((si_portp->siport_port_type == PORT_TYPE_NODEV) ||
160519397407SSherry Moore 	    !si_portp->siport_active) {
160666f9d5cbSmlf 		/*
160766f9d5cbSmlf 		 * si_intr_phy_ready_change() may have rendered it to
160866f9d5cbSmlf 		 * PORT_TYPE_NODEV. cfgadm operation may have rendered
160966f9d5cbSmlf 		 * it inactive.
161066f9d5cbSmlf 		 */
161166f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
161266f9d5cbSmlf 		fill_dev_sregisters(si_ctlp, port, &spkt->satapkt_device);
161366f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
161466f9d5cbSmlf 		return (SATA_FAILURE);
161566f9d5cbSmlf 	}
161666f9d5cbSmlf 
161766f9d5cbSmlf 	if (flag == SATA_ABORT_ALL_PACKETS) {
161866f9d5cbSmlf 		aborting_tags = si_portp->siport_pending_tags;
161966f9d5cbSmlf 	} else {
162066f9d5cbSmlf 		/*
162166f9d5cbSmlf 		 * Need to abort a single packet.
162266f9d5cbSmlf 		 * Search our siport_slot_pkts[] list for matching spkt.
162366f9d5cbSmlf 		 */
162466f9d5cbSmlf 		aborting_tags = 0xffffffff; /* 0xffffffff is impossible tag */
162566f9d5cbSmlf 		for (tmpslot = 0; tmpslot < SI_NUM_SLOTS; tmpslot++) {
162666f9d5cbSmlf 			if (si_portp->siport_slot_pkts[tmpslot] == spkt) {
162766f9d5cbSmlf 				aborting_tags = (0x1 << tmpslot);
162866f9d5cbSmlf 				break;
162966f9d5cbSmlf 			}
163066f9d5cbSmlf 		}
163166f9d5cbSmlf 
163266f9d5cbSmlf 		if (aborting_tags == 0xffffffff) {
163366f9d5cbSmlf 			/* requested packet is not on pending list. */
163466f9d5cbSmlf 			fill_dev_sregisters(si_ctlp, port,
163519397407SSherry Moore 			    &spkt->satapkt_device);
163666f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
163766f9d5cbSmlf 			return (SATA_FAILURE);
163866f9d5cbSmlf 		}
163966f9d5cbSmlf 	}
164066f9d5cbSmlf 
1641cf6ed809SMark Logan 	si_portp->mopping_in_progress++;
164266f9d5cbSmlf 
164366f9d5cbSmlf 	slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
164419397407SSherry Moore 	    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
164566f9d5cbSmlf 	(void) si_reset_dport_wait_till_ready(si_ctlp, si_portp,
164619397407SSherry Moore 	    port, SI_DEVICE_RESET);
164766f9d5cbSmlf 
164866f9d5cbSmlf 	/*
164966f9d5cbSmlf 	 * Compute which have finished and which need to be retried.
165066f9d5cbSmlf 	 *
165166f9d5cbSmlf 	 * The finished tags are siport_pending_tags minus the slot_status.
165266f9d5cbSmlf 	 * The aborting_tags have to be reduced by finished_tags since we
165366f9d5cbSmlf 	 * can't possibly abort a tag which had finished already.
165466f9d5cbSmlf 	 */
165566f9d5cbSmlf 	finished_tags =  si_portp->siport_pending_tags &
165619397407SSherry Moore 	    ~slot_status & SI_SLOT_MASK;
165766f9d5cbSmlf 	aborting_tags &= ~finished_tags;
165866f9d5cbSmlf 
165966f9d5cbSmlf 	si_mop_commands(si_ctlp,
166019397407SSherry Moore 	    si_portp,
166119397407SSherry Moore 	    port,
166219397407SSherry Moore 	    slot_status,
166319397407SSherry Moore 	    0, /* failed_tags */
166419397407SSherry Moore 	    0, /* timedout_tags */
166519397407SSherry Moore 	    aborting_tags,
166619397407SSherry Moore 	    0); /* reset_tags */
166766f9d5cbSmlf 
166866f9d5cbSmlf 	fill_dev_sregisters(si_ctlp, port, &spkt->satapkt_device);
166966f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
167066f9d5cbSmlf 	return (SATA_SUCCESS);
167166f9d5cbSmlf }
167266f9d5cbSmlf 
167366f9d5cbSmlf 
167466f9d5cbSmlf /*
167566f9d5cbSmlf  * Used to reject all the pending packets on a port during a reset
167666f9d5cbSmlf  * operation.
167766f9d5cbSmlf  *
167866f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
167966f9d5cbSmlf  * before calling us.
168066f9d5cbSmlf  */
168166f9d5cbSmlf static void
si_reject_all_reset_pkts(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)168266f9d5cbSmlf si_reject_all_reset_pkts(
168366f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
168466f9d5cbSmlf 	si_port_state_t *si_portp,
168566f9d5cbSmlf 	int port)
168666f9d5cbSmlf {
168766f9d5cbSmlf 	uint32_t slot_status;
168866f9d5cbSmlf 	uint32_t reset_tags;
168966f9d5cbSmlf 
169066f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
169166f9d5cbSmlf 
1692e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_RESET, si_portp,
169319397407SSherry Moore 	    "si_reject_all_reset_pkts on port: %x",
169419397407SSherry Moore 	    port);
169566f9d5cbSmlf 
169666f9d5cbSmlf 	slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
169719397407SSherry Moore 	    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
169866f9d5cbSmlf 
169966f9d5cbSmlf 	/* Compute which tags need to be sent up. */
170066f9d5cbSmlf 	reset_tags = slot_status & SI_SLOT_MASK;
170166f9d5cbSmlf 
1702cf6ed809SMark Logan 	si_portp->mopping_in_progress++;
1703cf6ed809SMark Logan 
170466f9d5cbSmlf 	si_mop_commands(si_ctlp,
170519397407SSherry Moore 	    si_portp,
170619397407SSherry Moore 	    port,
170719397407SSherry Moore 	    slot_status,
170819397407SSherry Moore 	    0, /* failed_tags */
170919397407SSherry Moore 	    0, /* timedout_tags */
171019397407SSherry Moore 	    0, /* aborting_tags */
171119397407SSherry Moore 	    reset_tags);
171266f9d5cbSmlf }
171366f9d5cbSmlf 
171466f9d5cbSmlf 
171566f9d5cbSmlf /*
171666f9d5cbSmlf  * Called by sata framework to reset a port(s) or device.
171766f9d5cbSmlf  *
171866f9d5cbSmlf  */
171966f9d5cbSmlf static int
si_tran_reset_dport(dev_info_t * dip,sata_device_t * sd)172066f9d5cbSmlf si_tran_reset_dport(dev_info_t *dip, sata_device_t *sd)
172166f9d5cbSmlf {
172266f9d5cbSmlf 	si_ctl_state_t	*si_ctlp;
172366f9d5cbSmlf 	uint8_t port = sd->satadev_addr.cport;
172466f9d5cbSmlf 	int i;
172566f9d5cbSmlf 	si_port_state_t *si_portp;
172666f9d5cbSmlf 	int retval = SI_SUCCESS;
172766f9d5cbSmlf 
172866f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
1729e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_RESET, si_ctlp,
173019397407SSherry Moore 	    "si_tran_reset_port entry: port: 0x%x",
173119397407SSherry Moore 	    port);
173266f9d5cbSmlf 
173366f9d5cbSmlf 	switch (sd->satadev_addr.qual) {
173466f9d5cbSmlf 	case SATA_ADDR_CPORT:
173566f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
173666f9d5cbSmlf 		si_portp = si_ctlp->sictl_ports[port];
173766f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
173866f9d5cbSmlf 
173966f9d5cbSmlf 		mutex_enter(&si_portp->siport_mutex);
1740cf6ed809SMark Logan 
1741cf6ed809SMark Logan 		/*
1742cf6ed809SMark Logan 		 * If already mopping, then no need to reset or mop again.
1743cf6ed809SMark Logan 		 */
1744cf6ed809SMark Logan 		if (si_portp->mopping_in_progress > 0) {
1745e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_RESET, si_portp,
1746cf6ed809SMark Logan 			    "si_tran_reset_dport: CPORT port %d mopping "
1747cf6ed809SMark Logan 			    "in progress, so just return", port);
1748cf6ed809SMark Logan 			mutex_exit(&si_portp->siport_mutex);
1749cf6ed809SMark Logan 			retval = SI_SUCCESS;
1750cf6ed809SMark Logan 			break;
1751cf6ed809SMark Logan 		}
1752cf6ed809SMark Logan 
175366f9d5cbSmlf 		retval = si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
175419397407SSherry Moore 		    SI_PORT_RESET);
175566f9d5cbSmlf 		si_reject_all_reset_pkts(si_ctlp,  si_portp, port);
175666f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
175766f9d5cbSmlf 
175866f9d5cbSmlf 		break;
175966f9d5cbSmlf 
176066f9d5cbSmlf 	case SATA_ADDR_DCPORT:
176166f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
176266f9d5cbSmlf 		si_portp = si_ctlp->sictl_ports[port];
176366f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
176466f9d5cbSmlf 
176566f9d5cbSmlf 		mutex_enter(&si_portp->siport_mutex);
176666f9d5cbSmlf 
176766f9d5cbSmlf 		if ((si_portp->siport_port_type == PORT_TYPE_NODEV) ||
176819397407SSherry Moore 		    !si_portp->siport_active) {
176966f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
177066f9d5cbSmlf 			retval = SI_FAILURE;
177166f9d5cbSmlf 			break;
177266f9d5cbSmlf 		}
177366f9d5cbSmlf 
1774cf6ed809SMark Logan 		/*
1775cf6ed809SMark Logan 		 * If already mopping, then no need to reset or mop again.
1776cf6ed809SMark Logan 		 */
1777cf6ed809SMark Logan 		if (si_portp->mopping_in_progress > 0) {
1778e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_RESET, si_portp,
1779cf6ed809SMark Logan 			    "si_tran_reset_dport: DCPORT port %d mopping "
1780cf6ed809SMark Logan 			    "in progress, so just return", port);
1781cf6ed809SMark Logan 			mutex_exit(&si_portp->siport_mutex);
1782cf6ed809SMark Logan 			retval = SI_SUCCESS;
1783cf6ed809SMark Logan 			break;
1784cf6ed809SMark Logan 		}
1785cf6ed809SMark Logan 
178666f9d5cbSmlf 		retval = si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
178719397407SSherry Moore 		    SI_DEVICE_RESET);
178866f9d5cbSmlf 		si_reject_all_reset_pkts(si_ctlp,  si_portp, port);
178966f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
179066f9d5cbSmlf 
179166f9d5cbSmlf 		break;
179266f9d5cbSmlf 
179366f9d5cbSmlf 	case SATA_ADDR_CNTRL:
179466f9d5cbSmlf 		for (i = 0; i < si_ctlp->sictl_num_ports; i++) {
179566f9d5cbSmlf 			mutex_enter(&si_ctlp->sictl_mutex);
1796cf6ed809SMark Logan 			si_portp = si_ctlp->sictl_ports[i];
179766f9d5cbSmlf 			mutex_exit(&si_ctlp->sictl_mutex);
179866f9d5cbSmlf 
179966f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
1800cf6ed809SMark Logan 
1801cf6ed809SMark Logan 			/*
1802cf6ed809SMark Logan 			 * If mopping, then all the pending commands are being
1803cf6ed809SMark Logan 			 * mopped, therefore there is nothing else to do.
1804cf6ed809SMark Logan 			 */
1805cf6ed809SMark Logan 			if (si_portp->mopping_in_progress > 0) {
1806e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_P(SIDBG_RESET, si_portp,
1807cf6ed809SMark Logan 				    "si_tran_reset_dport: CNTRL port %d mopping"
1808cf6ed809SMark Logan 				    " in progress, so just return", i);
1809cf6ed809SMark Logan 				mutex_exit(&si_portp->siport_mutex);
1810cf6ed809SMark Logan 				retval = SI_SUCCESS;
1811cf6ed809SMark Logan 				break;
1812cf6ed809SMark Logan 			}
1813cf6ed809SMark Logan 
181466f9d5cbSmlf 			retval = si_reset_dport_wait_till_ready(si_ctlp,
181519397407SSherry Moore 			    si_portp, i, SI_PORT_RESET);
181666f9d5cbSmlf 			if (retval) {
181766f9d5cbSmlf 				mutex_exit(&si_portp->siport_mutex);
181866f9d5cbSmlf 				break;
181966f9d5cbSmlf 			}
1820cf6ed809SMark Logan 			si_reject_all_reset_pkts(si_ctlp,  si_portp, i);
182166f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
182266f9d5cbSmlf 		}
182366f9d5cbSmlf 		break;
182466f9d5cbSmlf 
182566f9d5cbSmlf 	case SATA_ADDR_PMPORT:
182666f9d5cbSmlf 	case SATA_ADDR_DPMPORT:
1827e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_RESET, si_portp,
1828e57ece5bSPraveen Kumar Dasaraju Rama 		    "port mult reset not implemented yet", NULL);
18297b839a17SToomas Soome 		/* FALLTHROUGH */
183066f9d5cbSmlf 
183166f9d5cbSmlf 	default:
183266f9d5cbSmlf 		retval = SI_FAILURE;
183366f9d5cbSmlf 
183466f9d5cbSmlf 	}
183566f9d5cbSmlf 
183666f9d5cbSmlf 	return (retval);
183766f9d5cbSmlf }
183866f9d5cbSmlf 
183966f9d5cbSmlf 
184066f9d5cbSmlf /*
184166f9d5cbSmlf  * Called by sata framework to activate a port as part of hotplug.
184266f9d5cbSmlf  *
184366f9d5cbSmlf  * Note: Not port-mult aware.
184466f9d5cbSmlf  */
184566f9d5cbSmlf static int
si_tran_hotplug_port_activate(dev_info_t * dip,sata_device_t * satadev)184666f9d5cbSmlf si_tran_hotplug_port_activate(dev_info_t *dip, sata_device_t *satadev)
184766f9d5cbSmlf {
184866f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
184966f9d5cbSmlf 	si_port_state_t *si_portp;
185066f9d5cbSmlf 	uint8_t	port;
185166f9d5cbSmlf 
185266f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
185366f9d5cbSmlf 	port = satadev->satadev_addr.cport;
185466f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
185566f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
185666f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
185766f9d5cbSmlf 
1858e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_EVENT, si_portp, "si_tran_hotplug_port_activate entry",
1859e57ece5bSPraveen Kumar Dasaraju Rama 	    NULL);
186066f9d5cbSmlf 
186166f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
186266f9d5cbSmlf 	si_enable_port_interrupts(si_ctlp, port);
186366f9d5cbSmlf 
186466f9d5cbSmlf 	/*
186566f9d5cbSmlf 	 * Reset the device so that a si_find_dev_signature() would trigger.
186666f9d5cbSmlf 	 * But this reset is an internal operation; the sata framework does
186766f9d5cbSmlf 	 * not need to know about it.
186866f9d5cbSmlf 	 */
186966f9d5cbSmlf 	(void) si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
187019397407SSherry Moore 	    SI_DEVICE_RESET|SI_RESET_NO_EVENTS_UP);
187166f9d5cbSmlf 
187266f9d5cbSmlf 	satadev->satadev_state = SATA_STATE_READY;
187366f9d5cbSmlf 
187466f9d5cbSmlf 	si_portp->siport_active = PORT_ACTIVE;
187566f9d5cbSmlf 
187666f9d5cbSmlf 	fill_dev_sregisters(si_ctlp, port, satadev);
187766f9d5cbSmlf 
187866f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
187966f9d5cbSmlf 	return (SATA_SUCCESS);
188066f9d5cbSmlf }
188166f9d5cbSmlf 
188266f9d5cbSmlf /*
188366f9d5cbSmlf  * Called by sata framework to deactivate a port as part of hotplug.
188466f9d5cbSmlf  *
188566f9d5cbSmlf  * Note: Not port-mult aware.
188666f9d5cbSmlf  */
188766f9d5cbSmlf static int
si_tran_hotplug_port_deactivate(dev_info_t * dip,sata_device_t * satadev)188866f9d5cbSmlf si_tran_hotplug_port_deactivate(dev_info_t *dip, sata_device_t *satadev)
188966f9d5cbSmlf {
189066f9d5cbSmlf 	si_ctl_state_t *si_ctlp;
189166f9d5cbSmlf 	si_port_state_t *si_portp;
189266f9d5cbSmlf 	uint8_t	port;
189366f9d5cbSmlf 
189466f9d5cbSmlf 	si_ctlp = ddi_get_soft_state(si_statep, ddi_get_instance(dip));
189566f9d5cbSmlf 	port = satadev->satadev_addr.cport;
189666f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
189766f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
189866f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
189966f9d5cbSmlf 
1900e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG(SIDBG_EVENT, "si_tran_hotplug_port_deactivate entry", NULL);
190166f9d5cbSmlf 
190266f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
190366f9d5cbSmlf 	if (si_portp->siport_pending_tags & SI_SLOT_MASK) {
190466f9d5cbSmlf 		/*
190566f9d5cbSmlf 		 * There are pending commands on this port.
190666f9d5cbSmlf 		 * Fail the deactivate request.
190766f9d5cbSmlf 		 */
190866f9d5cbSmlf 		satadev->satadev_state = SATA_STATE_READY;
190966f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
191066f9d5cbSmlf 		return (SATA_FAILURE);
191166f9d5cbSmlf 	}
191266f9d5cbSmlf 
191366f9d5cbSmlf 	/* mark the device as not accessible any more. */
191466f9d5cbSmlf 	si_portp->siport_active = PORT_INACTIVE;
191566f9d5cbSmlf 
191666f9d5cbSmlf 	/* disable the interrupts on the port. */
191766f9d5cbSmlf 	si_disable_port_interrupts(si_ctlp, port);
191866f9d5cbSmlf 
191966f9d5cbSmlf 	satadev->satadev_state = SATA_PSTATE_SHUTDOWN;
192066f9d5cbSmlf 
192166f9d5cbSmlf 	fill_dev_sregisters(si_ctlp, port, satadev);
192266f9d5cbSmlf 	/*
192366f9d5cbSmlf 	 * Since we are implementing the port deactivation in software only,
192466f9d5cbSmlf 	 * we need to fake a valid value for sstatus.
192566f9d5cbSmlf 	 */
192666f9d5cbSmlf 	SSTATUS_SET_DET(satadev->satadev_scr.sstatus, SSTATUS_DET_PHYOFFLINE);
192766f9d5cbSmlf 	SSTATUS_SET_IPM(satadev->satadev_scr.sstatus, SSTATUS_IPM_NODEV_NOPHY);
192866f9d5cbSmlf 
192966f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
193066f9d5cbSmlf 	return (SATA_SUCCESS);
193166f9d5cbSmlf }
193266f9d5cbSmlf 
193366f9d5cbSmlf 
193466f9d5cbSmlf /*
193566f9d5cbSmlf  * Allocates the si_port_state_t.
193666f9d5cbSmlf  */
193766f9d5cbSmlf static int
si_alloc_port_state(si_ctl_state_t * si_ctlp,int port)193866f9d5cbSmlf si_alloc_port_state(si_ctl_state_t *si_ctlp, int port)
193966f9d5cbSmlf {
194066f9d5cbSmlf 	si_port_state_t *si_portp;
194166f9d5cbSmlf 
194266f9d5cbSmlf 	si_ctlp->sictl_ports[port] = (si_port_state_t *)kmem_zalloc(
194319397407SSherry Moore 	    sizeof (si_port_state_t), KM_SLEEP);
194466f9d5cbSmlf 
194566f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
194666f9d5cbSmlf 	mutex_init(&si_portp->siport_mutex, NULL, MUTEX_DRIVER,
194719397407SSherry Moore 	    (void *)(uintptr_t)si_ctlp->sictl_intr_pri);
194866f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
194966f9d5cbSmlf 
195066f9d5cbSmlf 	/* allocate prb & sgt pkts for this port. */
195166f9d5cbSmlf 	if (si_alloc_prbpool(si_ctlp, port)) {
195266f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
195366f9d5cbSmlf 		kmem_free(si_ctlp->sictl_ports[port], sizeof (si_port_state_t));
195466f9d5cbSmlf 		return (SI_FAILURE);
195566f9d5cbSmlf 	}
195666f9d5cbSmlf 	if (si_alloc_sgbpool(si_ctlp, port)) {
195766f9d5cbSmlf 		si_dealloc_prbpool(si_ctlp, port);
195866f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
195966f9d5cbSmlf 		kmem_free(si_ctlp->sictl_ports[port], sizeof (si_port_state_t));
196066f9d5cbSmlf 		return (SI_FAILURE);
196166f9d5cbSmlf 	}
196266f9d5cbSmlf 
1963832d3fc2SMark Logan 	/* Allocate the argument for the timeout */
1964832d3fc2SMark Logan 	si_portp->siport_event_args =
1965832d3fc2SMark Logan 	    kmem_zalloc(sizeof (si_event_arg_t), KM_SLEEP);
1966832d3fc2SMark Logan 
196766f9d5cbSmlf 	si_portp->siport_active = PORT_ACTIVE;
196866f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
196966f9d5cbSmlf 
197066f9d5cbSmlf 	return (SI_SUCCESS);
197166f9d5cbSmlf 
197266f9d5cbSmlf }
197366f9d5cbSmlf 
197466f9d5cbSmlf /*
197566f9d5cbSmlf  * Deallocates the si_port_state_t.
197666f9d5cbSmlf  */
197766f9d5cbSmlf static void
si_dealloc_port_state(si_ctl_state_t * si_ctlp,int port)197866f9d5cbSmlf si_dealloc_port_state(si_ctl_state_t *si_ctlp, int port)
197966f9d5cbSmlf {
198066f9d5cbSmlf 	si_port_state_t *si_portp;
198166f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
198266f9d5cbSmlf 
198366f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
1984832d3fc2SMark Logan 	kmem_free(si_portp->siport_event_args, sizeof (si_event_arg_t));
198566f9d5cbSmlf 	si_dealloc_sgbpool(si_ctlp, port);
198666f9d5cbSmlf 	si_dealloc_prbpool(si_ctlp, port);
198766f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
198866f9d5cbSmlf 
198966f9d5cbSmlf 	mutex_destroy(&si_portp->siport_mutex);
199066f9d5cbSmlf 
199166f9d5cbSmlf 	kmem_free(si_ctlp->sictl_ports[port], sizeof (si_port_state_t));
199266f9d5cbSmlf 
199366f9d5cbSmlf }
199466f9d5cbSmlf 
199566f9d5cbSmlf /*
199666f9d5cbSmlf  * Allocates the SGB (Scatter Gather Block) incore buffer.
199766f9d5cbSmlf  */
199866f9d5cbSmlf static int
si_alloc_sgbpool(si_ctl_state_t * si_ctlp,int port)199966f9d5cbSmlf si_alloc_sgbpool(si_ctl_state_t *si_ctlp, int port)
200066f9d5cbSmlf {
200166f9d5cbSmlf 	si_port_state_t *si_portp;
200266f9d5cbSmlf 	uint_t cookie_count;
200381a0678eSxun ni - Sun Microsystems - Beijing China 	size_t incore_sgbpool_size = SI_NUM_SLOTS * sizeof (si_sgblock_t)
200481a0678eSxun ni - Sun Microsystems - Beijing China 	    * si_dma_sg_number;
200566f9d5cbSmlf 	size_t ret_len;
200666f9d5cbSmlf 	ddi_dma_cookie_t sgbpool_dma_cookie;
200766f9d5cbSmlf 
200866f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
200966f9d5cbSmlf 
201066f9d5cbSmlf 	/* allocate sgbpool dma handle. */
201166f9d5cbSmlf 	if (ddi_dma_alloc_handle(si_ctlp->sictl_devinfop,
201219397407SSherry Moore 	    &prb_sgt_dma_attr,
201319397407SSherry Moore 	    DDI_DMA_SLEEP,
201419397407SSherry Moore 	    NULL,
201519397407SSherry Moore 	    &si_portp->siport_sgbpool_dma_handle) !=
201619397407SSherry Moore 	    DDI_SUCCESS) {
201766f9d5cbSmlf 
201866f9d5cbSmlf 		return (SI_FAILURE);
201966f9d5cbSmlf 	}
202066f9d5cbSmlf 
202166f9d5cbSmlf 	/* allocate the memory for sgbpool. */
202266f9d5cbSmlf 	if (ddi_dma_mem_alloc(si_portp->siport_sgbpool_dma_handle,
202319397407SSherry Moore 	    incore_sgbpool_size,
202419397407SSherry Moore 	    &accattr,
202519397407SSherry Moore 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
202619397407SSherry Moore 	    DDI_DMA_SLEEP,
202719397407SSherry Moore 	    NULL,
202819397407SSherry Moore 	    (caddr_t *)&si_portp->siport_sgbpool,
202919397407SSherry Moore 	    &ret_len,
2030*83dba8e1SToomas Soome 	    &si_portp->siport_sgbpool_acc_handle) != DDI_SUCCESS) {
203166f9d5cbSmlf 
203266f9d5cbSmlf 		/*  error.. free the dma handle. */
203366f9d5cbSmlf 		ddi_dma_free_handle(&si_portp->siport_sgbpool_dma_handle);
203466f9d5cbSmlf 		return (SI_FAILURE);
203566f9d5cbSmlf 	}
203666f9d5cbSmlf 
203766f9d5cbSmlf 	/* now bind it */
203866f9d5cbSmlf 	if (ddi_dma_addr_bind_handle(si_portp->siport_sgbpool_dma_handle,
203919397407SSherry Moore 	    NULL,
204019397407SSherry Moore 	    (caddr_t)si_portp->siport_sgbpool,
204119397407SSherry Moore 	    incore_sgbpool_size,
204219397407SSherry Moore 	    DDI_DMA_CONSISTENT,
204319397407SSherry Moore 	    DDI_DMA_SLEEP,
204419397407SSherry Moore 	    NULL,
204519397407SSherry Moore 	    &sgbpool_dma_cookie,
204619397407SSherry Moore 	    &cookie_count) !=  DDI_DMA_MAPPED) {
204766f9d5cbSmlf 		/*  error.. free the dma handle & free the memory. */
204866f9d5cbSmlf 		ddi_dma_mem_free(&si_portp->siport_sgbpool_acc_handle);
204966f9d5cbSmlf 		ddi_dma_free_handle(&si_portp->siport_sgbpool_dma_handle);
205066f9d5cbSmlf 		return (SI_FAILURE);
205166f9d5cbSmlf 	}
205266f9d5cbSmlf 
205366f9d5cbSmlf 	si_portp->siport_sgbpool_physaddr = sgbpool_dma_cookie.dmac_laddress;
205466f9d5cbSmlf 	return (SI_SUCCESS);
205566f9d5cbSmlf }
205666f9d5cbSmlf 
205766f9d5cbSmlf /*
205866f9d5cbSmlf  * Deallocates the SGB (Scatter Gather Block) incore buffer.
205966f9d5cbSmlf  */
206066f9d5cbSmlf static void
si_dealloc_sgbpool(si_ctl_state_t * si_ctlp,int port)206166f9d5cbSmlf si_dealloc_sgbpool(si_ctl_state_t *si_ctlp, int port)
206266f9d5cbSmlf {
206366f9d5cbSmlf 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
206466f9d5cbSmlf 
206566f9d5cbSmlf 	/* Unbind the dma handle first. */
206666f9d5cbSmlf 	(void) ddi_dma_unbind_handle(si_portp->siport_sgbpool_dma_handle);
206766f9d5cbSmlf 
206866f9d5cbSmlf 	/* Then free the underlying memory. */
206966f9d5cbSmlf 	ddi_dma_mem_free(&si_portp->siport_sgbpool_acc_handle);
207066f9d5cbSmlf 
207166f9d5cbSmlf 	/* Now free the handle itself. */
207266f9d5cbSmlf 	ddi_dma_free_handle(&si_portp->siport_sgbpool_dma_handle);
207366f9d5cbSmlf 
207466f9d5cbSmlf }
207566f9d5cbSmlf 
207666f9d5cbSmlf /*
207766f9d5cbSmlf  * Allocates the PRB (Port Request Block) incore packets.
207866f9d5cbSmlf  */
207966f9d5cbSmlf static int
si_alloc_prbpool(si_ctl_state_t * si_ctlp,int port)208066f9d5cbSmlf si_alloc_prbpool(si_ctl_state_t *si_ctlp, int port)
208166f9d5cbSmlf {
208266f9d5cbSmlf 	si_port_state_t *si_portp;
208366f9d5cbSmlf 	uint_t cookie_count;
208466f9d5cbSmlf 	size_t incore_pkt_size = SI_NUM_SLOTS * sizeof (si_prb_t);
208566f9d5cbSmlf 	size_t ret_len;
208666f9d5cbSmlf 	ddi_dma_cookie_t prbpool_dma_cookie;
208766f9d5cbSmlf 
208866f9d5cbSmlf 	si_portp = si_ctlp->sictl_ports[port];
208966f9d5cbSmlf 
209066f9d5cbSmlf 	/* allocate prb pkts. */
209166f9d5cbSmlf 	if (ddi_dma_alloc_handle(si_ctlp->sictl_devinfop,
209219397407SSherry Moore 	    &prb_sgt_dma_attr,
209319397407SSherry Moore 	    DDI_DMA_SLEEP,
209419397407SSherry Moore 	    NULL,
209519397407SSherry Moore 	    &si_portp->siport_prbpool_dma_handle) !=
209619397407SSherry Moore 	    DDI_SUCCESS) {
209766f9d5cbSmlf 
209866f9d5cbSmlf 		return (SI_FAILURE);
209966f9d5cbSmlf 	}
210066f9d5cbSmlf 
210166f9d5cbSmlf 	if (ddi_dma_mem_alloc(si_portp->siport_prbpool_dma_handle,
210219397407SSherry Moore 	    incore_pkt_size,
210319397407SSherry Moore 	    &accattr,
210419397407SSherry Moore 	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
210519397407SSherry Moore 	    DDI_DMA_SLEEP,
210619397407SSherry Moore 	    NULL,
210719397407SSherry Moore 	    (caddr_t *)&si_portp->siport_prbpool,
210819397407SSherry Moore 	    &ret_len,
2109*83dba8e1SToomas Soome 	    &si_portp->siport_prbpool_acc_handle) != DDI_SUCCESS) {
211066f9d5cbSmlf 
211166f9d5cbSmlf 		/* error.. free the dma handle. */
211266f9d5cbSmlf 		ddi_dma_free_handle(&si_portp->siport_prbpool_dma_handle);
211366f9d5cbSmlf 		return (SI_FAILURE);
211466f9d5cbSmlf 	}
211566f9d5cbSmlf 
211666f9d5cbSmlf 	if (ddi_dma_addr_bind_handle(si_portp->siport_prbpool_dma_handle,
211719397407SSherry Moore 	    NULL,
211819397407SSherry Moore 	    (caddr_t)si_portp->siport_prbpool,
211919397407SSherry Moore 	    incore_pkt_size,
212019397407SSherry Moore 	    DDI_DMA_CONSISTENT,
212119397407SSherry Moore 	    DDI_DMA_SLEEP,
212219397407SSherry Moore 	    NULL,
212319397407SSherry Moore 	    &prbpool_dma_cookie,
212419397407SSherry Moore 	    &cookie_count) !=  DDI_DMA_MAPPED) {
212566f9d5cbSmlf 		/*  error.. free the dma handle & free the memory. */
212666f9d5cbSmlf 		ddi_dma_mem_free(&si_portp->siport_prbpool_acc_handle);
212766f9d5cbSmlf 		ddi_dma_free_handle(&si_portp->siport_prbpool_dma_handle);
212866f9d5cbSmlf 		return (SI_FAILURE);
212966f9d5cbSmlf 	}
213066f9d5cbSmlf 
213166f9d5cbSmlf 	si_portp->siport_prbpool_physaddr =
213219397407SSherry Moore 	    prbpool_dma_cookie.dmac_laddress;
213366f9d5cbSmlf 	return (SI_SUCCESS);
213466f9d5cbSmlf }
213566f9d5cbSmlf 
213666f9d5cbSmlf /*
213766f9d5cbSmlf  * Deallocates the PRB (Port Request Block) incore packets.
213866f9d5cbSmlf  */
213966f9d5cbSmlf static void
si_dealloc_prbpool(si_ctl_state_t * si_ctlp,int port)214066f9d5cbSmlf si_dealloc_prbpool(si_ctl_state_t *si_ctlp, int port)
214166f9d5cbSmlf {
214266f9d5cbSmlf 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
214366f9d5cbSmlf 
214466f9d5cbSmlf 	/* Unbind the prb dma handle first. */
214566f9d5cbSmlf 	(void) ddi_dma_unbind_handle(si_portp->siport_prbpool_dma_handle);
214666f9d5cbSmlf 
214766f9d5cbSmlf 	/* Then free the underlying memory. */
214866f9d5cbSmlf 	ddi_dma_mem_free(&si_portp->siport_prbpool_acc_handle);
214966f9d5cbSmlf 
215066f9d5cbSmlf 	/* Now free the handle itself. */
215166f9d5cbSmlf 	ddi_dma_free_handle(&si_portp->siport_prbpool_dma_handle);
215266f9d5cbSmlf 
215366f9d5cbSmlf }
215466f9d5cbSmlf 
215566f9d5cbSmlf 
215666f9d5cbSmlf 
215766f9d5cbSmlf /*
215866f9d5cbSmlf  * Soft-reset the port to find the signature of the device connected to
215966f9d5cbSmlf  * the port.
216066f9d5cbSmlf  */
216166f9d5cbSmlf static void
si_find_dev_signature(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,int pmp)216266f9d5cbSmlf si_find_dev_signature(
216366f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
216466f9d5cbSmlf 	si_port_state_t *si_portp,
216566f9d5cbSmlf 	int port,
216666f9d5cbSmlf 	int pmp)
216766f9d5cbSmlf {
216866f9d5cbSmlf 	si_prb_t *prb;
216966f9d5cbSmlf 	uint32_t slot_status, signature;
217066f9d5cbSmlf 	int slot, loop_count;
217166f9d5cbSmlf 
2172e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp,
217319397407SSherry Moore 	    "si_find_dev_signature enter: port: %x, pmp: %x",
217419397407SSherry Moore 	    port, pmp);
217566f9d5cbSmlf 
217666f9d5cbSmlf 	/* Build a Soft Reset PRB in host memory. */
217766f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
217866f9d5cbSmlf 
217966f9d5cbSmlf 	slot = si_claim_free_slot(si_ctlp, si_portp, port);
2180ab0d082fSMark Logan 	if (slot == SI_FAILURE) {
218166f9d5cbSmlf 		/* Empty slot could not be found. */
218266f9d5cbSmlf 		if (pmp != PORTMULT_CONTROL_PORT) {
218366f9d5cbSmlf 			/* We are behind port multiplier. */
218466f9d5cbSmlf 			si_portp->siport_portmult_state.sipm_port_type[pmp] =
218519397407SSherry Moore 			    PORT_TYPE_NODEV;
218666f9d5cbSmlf 		} else {
218766f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_NODEV;
218866f9d5cbSmlf 		}
218966f9d5cbSmlf 
219066f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
219166f9d5cbSmlf 		return;
219266f9d5cbSmlf 	}
219366f9d5cbSmlf 	prb = &si_portp->siport_prbpool[slot];
219466f9d5cbSmlf 	bzero((void *)prb, sizeof (si_prb_t));
219566f9d5cbSmlf 
219666f9d5cbSmlf 	SET_FIS_PMP(prb->prb_fis, pmp);
219766f9d5cbSmlf 	SET_PRB_CONTROL_SOFT_RESET(prb);
219866f9d5cbSmlf 
219966f9d5cbSmlf #if SI_DEBUG
220066f9d5cbSmlf 	if (si_debug_flags & SIDBG_DUMP_PRB) {
220166f9d5cbSmlf 		char *ptr;
220266f9d5cbSmlf 		int j;
220366f9d5cbSmlf 
220466f9d5cbSmlf 		ptr = (char *)prb;
220566f9d5cbSmlf 		cmn_err(CE_WARN, "si_find_dev_signature, prb: ");
220666f9d5cbSmlf 		for (j = 0; j < (sizeof (si_prb_t)); j++) {
220766f9d5cbSmlf 			if (j%4 == 0) {
220866f9d5cbSmlf 				cmn_err(CE_WARN, "----");
220966f9d5cbSmlf 			}
221066f9d5cbSmlf 			cmn_err(CE_WARN, "%x ", ptr[j]);
221166f9d5cbSmlf 		}
221266f9d5cbSmlf 
221366f9d5cbSmlf 	}
221466f9d5cbSmlf #endif /* SI_DEBUG */
221566f9d5cbSmlf 
221666f9d5cbSmlf 	/* deliver soft reset prb to empty slot. */
221766f9d5cbSmlf 	POST_PRB_ADDR(si_ctlp, si_portp, port, slot);
221866f9d5cbSmlf 
221966f9d5cbSmlf 	loop_count = 0;
222066f9d5cbSmlf 	/* Loop till the soft reset is finished. */
222166f9d5cbSmlf 	do {
222266f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
222319397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
222466f9d5cbSmlf 
222566f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_SOFT_RESET) {
222666f9d5cbSmlf 			/* We are effectively timing out after 10 sec. */
222766f9d5cbSmlf 			break;
222866f9d5cbSmlf 		}
222966f9d5cbSmlf 
223066f9d5cbSmlf 		/* Wait for 10 millisec */
223166f9d5cbSmlf #ifndef __lock_lint
223266f9d5cbSmlf 		delay(SI_10MS_TICKS);
223366f9d5cbSmlf #endif /* __lock_lint */
223466f9d5cbSmlf 
223566f9d5cbSmlf 	} while (slot_status & SI_SLOT_MASK & (0x1 << slot));
223666f9d5cbSmlf 
2237e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
223819397407SSherry Moore 	    "si_find_dev_signature: loop count: %d, slot_status: 0x%x",
223919397407SSherry Moore 	    loop_count, slot_status);
224066f9d5cbSmlf 
224166f9d5cbSmlf 	CLEAR_BIT(si_portp->siport_pending_tags, slot);
224266f9d5cbSmlf 
224366f9d5cbSmlf 	/* Read device signature from command slot. */
224466f9d5cbSmlf 	signature = ddi_get32(si_ctlp->sictl_port_acc_handle,
224519397407SSherry Moore 	    (uint32_t *)(PORT_SIGNATURE_MSB(si_ctlp, port, slot)));
224666f9d5cbSmlf 	signature <<= 8;
224766f9d5cbSmlf 	signature |= (0xff & ddi_get32(si_ctlp->sictl_port_acc_handle,
224819397407SSherry Moore 	    (uint32_t *)(PORT_SIGNATURE_LSB(si_ctlp,
224919397407SSherry Moore 	    port, slot))));
225066f9d5cbSmlf 
2251e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp, "Device signature: 0x%x", signature);
225266f9d5cbSmlf 
225366f9d5cbSmlf 	if (signature == SI_SIGNATURE_PORT_MULTIPLIER) {
225466f9d5cbSmlf 
2255e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_INIT, si_portp,
225619397407SSherry Moore 		    "Found multiplier at cport: 0x%d, pmport: 0x%x",
225719397407SSherry Moore 		    port, pmp);
225866f9d5cbSmlf 
225966f9d5cbSmlf 		if (pmp != PORTMULT_CONTROL_PORT) {
226066f9d5cbSmlf 			/*
226166f9d5cbSmlf 			 * It is wrong to chain a port multiplier behind
226266f9d5cbSmlf 			 * another port multiplier.
226366f9d5cbSmlf 			 */
226466f9d5cbSmlf 			si_portp->siport_portmult_state.sipm_port_type[pmp] =
226519397407SSherry Moore 			    PORT_TYPE_NODEV;
226666f9d5cbSmlf 		} else {
226766f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_MULTIPLIER;
226866f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
226966f9d5cbSmlf 			(void) si_enumerate_port_multiplier(si_ctlp,
227019397407SSherry Moore 			    si_portp, port);
227166f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
227266f9d5cbSmlf 		}
227366f9d5cbSmlf 		si_init_port(si_ctlp, port);
227466f9d5cbSmlf 
227566f9d5cbSmlf 	} else if (signature == SI_SIGNATURE_ATAPI) {
227666f9d5cbSmlf 		if (pmp != PORTMULT_CONTROL_PORT) {
227766f9d5cbSmlf 			/* We are behind port multiplier. */
227866f9d5cbSmlf 			si_portp->siport_portmult_state.sipm_port_type[pmp] =
227919397407SSherry Moore 			    PORT_TYPE_ATAPI;
228066f9d5cbSmlf 		} else {
228166f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_ATAPI;
228266f9d5cbSmlf 			si_init_port(si_ctlp, port);
228366f9d5cbSmlf 		}
2284e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_INIT, si_portp,
228519397407SSherry Moore 		    "Found atapi at : cport: %x, pmport: %x",
228619397407SSherry Moore 		    port, pmp);
228766f9d5cbSmlf 
228866f9d5cbSmlf 	} else if (signature == SI_SIGNATURE_DISK) {
228966f9d5cbSmlf 
229066f9d5cbSmlf 		if (pmp != PORTMULT_CONTROL_PORT) {
229166f9d5cbSmlf 			/* We are behind port multiplier. */
229266f9d5cbSmlf 			si_portp->siport_portmult_state.sipm_port_type[pmp] =
229319397407SSherry Moore 			    PORT_TYPE_DISK;
229466f9d5cbSmlf 		} else {
229566f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_DISK;
229666f9d5cbSmlf 			si_init_port(si_ctlp, port);
229766f9d5cbSmlf 		}
2298e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_INIT, si_portp,
229919397407SSherry Moore 		    "found disk at : cport: %x, pmport: %x",
230019397407SSherry Moore 		    port, pmp);
230166f9d5cbSmlf 
230266f9d5cbSmlf 	} else {
230366f9d5cbSmlf 		if (pmp != PORTMULT_CONTROL_PORT) {
230466f9d5cbSmlf 			/* We are behind port multiplier. */
230566f9d5cbSmlf 			si_portp->siport_portmult_state.sipm_port_type[pmp] =
230619397407SSherry Moore 			    PORT_TYPE_UNKNOWN;
230766f9d5cbSmlf 		} else {
230866f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_UNKNOWN;
230966f9d5cbSmlf 		}
2310e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_INIT, si_portp,
231119397407SSherry Moore 		    "Found unknown signature 0x%x at: port: %x, pmp: %x",
231219397407SSherry Moore 		    signature, port, pmp);
231366f9d5cbSmlf 	}
231466f9d5cbSmlf 
231566f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
231666f9d5cbSmlf }
231766f9d5cbSmlf 
231866f9d5cbSmlf 
231966f9d5cbSmlf /*
232066f9d5cbSmlf  * Polls for the completion of the command. This is safe with both
232166f9d5cbSmlf  * interrupts enabled or disabled.
232266f9d5cbSmlf  */
232366f9d5cbSmlf static void
si_poll_cmd(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,int slot,sata_pkt_t * satapkt)232466f9d5cbSmlf si_poll_cmd(
232566f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
232666f9d5cbSmlf 	si_port_state_t *si_portp,
232766f9d5cbSmlf 	int port,
232866f9d5cbSmlf 	int slot,
232966f9d5cbSmlf 	sata_pkt_t *satapkt)
233066f9d5cbSmlf {
233166f9d5cbSmlf 	uint32_t slot_status;
233266f9d5cbSmlf 	int pkt_timeout_ticks;
233366f9d5cbSmlf 	uint32_t port_intr_status;
233466f9d5cbSmlf 	int in_panic = ddi_in_panic();
233566f9d5cbSmlf 
2336e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp, "si_poll_cmd entered: port: 0x%x", port);
233766f9d5cbSmlf 
233866f9d5cbSmlf 	pkt_timeout_ticks = drv_usectohz((clock_t)satapkt->satapkt_time *
233919397407SSherry Moore 	    1000000);
234066f9d5cbSmlf 
234166f9d5cbSmlf 
234266f9d5cbSmlf 	/* we start out with SATA_PKT_COMPLETED as the satapkt_reason */
234366f9d5cbSmlf 	satapkt->satapkt_reason = SATA_PKT_COMPLETED;
234466f9d5cbSmlf 
234566f9d5cbSmlf 	do {
234666f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
234719397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
234866f9d5cbSmlf 
234966f9d5cbSmlf 		if (slot_status & SI_SLOT_MASK & (0x1 << slot)) {
235066f9d5cbSmlf 			if (in_panic) {
235166f9d5cbSmlf 				/*
235266f9d5cbSmlf 				 * If we are in panic, we can't rely on
235366f9d5cbSmlf 				 * timers; so, busy wait instead of delay().
235466f9d5cbSmlf 				 */
235566f9d5cbSmlf 				mutex_exit(&si_portp->siport_mutex);
235666f9d5cbSmlf 				drv_usecwait(SI_1MS_USECS);
235766f9d5cbSmlf 				mutex_enter(&si_portp->siport_mutex);
235866f9d5cbSmlf 			} else {
235966f9d5cbSmlf 				mutex_exit(&si_portp->siport_mutex);
236066f9d5cbSmlf #ifndef __lock_lint
236166f9d5cbSmlf 				delay(SI_1MS_TICKS);
236266f9d5cbSmlf #endif /* __lock_lint */
236366f9d5cbSmlf 				mutex_enter(&si_portp->siport_mutex);
236466f9d5cbSmlf 			}
236566f9d5cbSmlf 		} else {
236666f9d5cbSmlf 			break;
236766f9d5cbSmlf 		}
236866f9d5cbSmlf 
236966f9d5cbSmlf 		pkt_timeout_ticks -= SI_1MS_TICKS;
237066f9d5cbSmlf 
237166f9d5cbSmlf 	} while (pkt_timeout_ticks > 0);
237266f9d5cbSmlf 
237366f9d5cbSmlf 	if (satapkt->satapkt_reason != SATA_PKT_COMPLETED) {
237466f9d5cbSmlf 		/* The si_mop_command() got to our packet before us */
2375a599d311SMartin Faltesek 
2376a599d311SMartin Faltesek 		return;
237766f9d5cbSmlf 	}
237866f9d5cbSmlf 
237966f9d5cbSmlf 	/*
238066f9d5cbSmlf 	 * Interrupts and timers may not be working properly in a crash dump
238166f9d5cbSmlf 	 * situation; we may need to handle all the three conditions here:
238266f9d5cbSmlf 	 * successful completion, packet failure and packet timeout.
238366f9d5cbSmlf 	 */
238466f9d5cbSmlf 	if (IS_ATTENTION_RAISED(slot_status)) { /* error seen on port */
238566f9d5cbSmlf 
238666f9d5cbSmlf 		port_intr_status = ddi_get32(si_ctlp->sictl_global_acc_handle,
238719397407SSherry Moore 		    (uint32_t *)PORT_INTERRUPT_STATUS(si_ctlp, port));
238866f9d5cbSmlf 
2389e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
239019397407SSherry Moore 		    "si_poll_cmd: port_intr_status: 0x%x, port: %x",
239119397407SSherry Moore 		    port_intr_status, port);
239266f9d5cbSmlf 
239366f9d5cbSmlf 		if (port_intr_status & INTR_COMMAND_ERROR) {
239466f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
239566f9d5cbSmlf 			(void) si_intr_command_error(si_ctlp, si_portp, port);
239666f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
239766f9d5cbSmlf 
2398a599d311SMartin Faltesek 			return;
239966f9d5cbSmlf 
240066f9d5cbSmlf 			/*
240166f9d5cbSmlf 			 * Why do we need to call si_intr_command_error() ?
240266f9d5cbSmlf 			 *
240366f9d5cbSmlf 			 * Answer: Even if the current packet is not the
240466f9d5cbSmlf 			 * offending command, we need to restart the stalled
240566f9d5cbSmlf 			 * port; (may be, the interrupts are not working well
240666f9d5cbSmlf 			 * in panic condition). The call to routine
240766f9d5cbSmlf 			 * si_intr_command_error() will achieve that.
240866f9d5cbSmlf 			 *
240966f9d5cbSmlf 			 * What if the interrupts are working fine and the
241066f9d5cbSmlf 			 * si_intr_command_error() gets called once more from
241166f9d5cbSmlf 			 * interrupt context ?
241266f9d5cbSmlf 			 *
241366f9d5cbSmlf 			 * Answer: The second instance of routine
241466f9d5cbSmlf 			 * si_intr_command_error() will not mop anything
241566f9d5cbSmlf 			 * since the first error handler has already blown
241666f9d5cbSmlf 			 * away the hardware pending queues through reset.
241766f9d5cbSmlf 			 *
241866f9d5cbSmlf 			 * Will the si_intr_command_error() hurt current
241966f9d5cbSmlf 			 * packet ?
242066f9d5cbSmlf 			 *
242166f9d5cbSmlf 			 * Answer: No.
242266f9d5cbSmlf 			 */
242366f9d5cbSmlf 		} else {
242466f9d5cbSmlf 			/* Ignore any non-error interrupts at this stage */
242566f9d5cbSmlf 			ddi_put32(si_ctlp->sictl_port_acc_handle,
242619397407SSherry Moore 			    (uint32_t *)(PORT_INTERRUPT_STATUS(si_ctlp,
242719397407SSherry Moore 			    port)),
242819397407SSherry Moore 			    port_intr_status & INTR_MASK);
242966f9d5cbSmlf 		}
243066f9d5cbSmlf 
243166f9d5cbSmlf 	} else if (slot_status & SI_SLOT_MASK & (0x1 << slot)) {
243266f9d5cbSmlf 		satapkt->satapkt_reason = SATA_PKT_TIMEOUT;
2433a599d311SMartin Faltesek 
243466f9d5cbSmlf 	} /* else: the command completed successfully */
243566f9d5cbSmlf 
2436a599d311SMartin Faltesek 	if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
2437a599d311SMartin Faltesek 		si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp, port, slot);
2438a599d311SMartin Faltesek 	}
2439a599d311SMartin Faltesek 
244066f9d5cbSmlf 	if ((satapkt->satapkt_cmd.satacmd_cmd_reg ==
244119397407SSherry Moore 	    SATAC_WRITE_FPDMA_QUEUED) ||
244266f9d5cbSmlf 	    (satapkt->satapkt_cmd.satacmd_cmd_reg ==
244319397407SSherry Moore 	    SATAC_READ_FPDMA_QUEUED)) {
244466f9d5cbSmlf 		si_portp->siport_pending_ncq_count--;
244566f9d5cbSmlf 	}
244666f9d5cbSmlf 
244766f9d5cbSmlf 	CLEAR_BIT(si_portp->siport_pending_tags, slot);
244866f9d5cbSmlf 
244966f9d5cbSmlf 	/*
245066f9d5cbSmlf 	 * tidbit: What is the interaction of abort with polling ?
245166f9d5cbSmlf 	 * What happens if the current polled pkt is aborted in parallel ?
245266f9d5cbSmlf 	 *
245366f9d5cbSmlf 	 * Answer: Assuming that the si_mop_commands() completes ahead
245466f9d5cbSmlf 	 * of polling, all it does is to set the satapkt_reason to
245566f9d5cbSmlf 	 * SPKT_PKT_ABORTED. That would be fine with us.
245666f9d5cbSmlf 	 *
245766f9d5cbSmlf 	 * The same logic applies to reset interacting with polling.
245866f9d5cbSmlf 	 */
245966f9d5cbSmlf }
246066f9d5cbSmlf 
246166f9d5cbSmlf 
246266f9d5cbSmlf /*
246366f9d5cbSmlf  * Searches for and claims a free slot.
246466f9d5cbSmlf  *
2465*83dba8e1SToomas Soome  * Returns:	SI_FAILURE if no slots found
246666f9d5cbSmlf  *		claimed slot number if successful
246766f9d5cbSmlf  *
246866f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
246966f9d5cbSmlf  * before calling us.
247066f9d5cbSmlf  */
247166f9d5cbSmlf /*ARGSUSED*/
247266f9d5cbSmlf static int
si_claim_free_slot(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)247366f9d5cbSmlf si_claim_free_slot(si_ctl_state_t *si_ctlp, si_port_state_t *si_portp, int port)
247466f9d5cbSmlf {
247566f9d5cbSmlf 	uint32_t free_slots;
247666f9d5cbSmlf 	int slot;
247766f9d5cbSmlf 
247866f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
247966f9d5cbSmlf 
2480e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp,
248119397407SSherry Moore 	    "si_claim_free_slot entry: siport_pending_tags: %x",
248219397407SSherry Moore 	    si_portp->siport_pending_tags);
248366f9d5cbSmlf 
248466f9d5cbSmlf 	free_slots = (~si_portp->siport_pending_tags) & SI_SLOT_MASK;
248566f9d5cbSmlf 	slot = ddi_ffs(free_slots) - 1;
248666f9d5cbSmlf 	if (slot == -1) {
2487e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
2488e57ece5bSPraveen Kumar Dasaraju Rama 		    "si_claim_free_slot: no empty slots", NULL);
248966f9d5cbSmlf 		return (SI_FAILURE);
249066f9d5cbSmlf 	}
249166f9d5cbSmlf 
249266f9d5cbSmlf 	si_portp->siport_pending_tags |= (0x1 << slot);
2493e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_VERBOSE, si_portp, "si_claim_free_slot: found slot: 0x%x",
249419397407SSherry Moore 	    slot);
249566f9d5cbSmlf 	return (slot);
249666f9d5cbSmlf }
249766f9d5cbSmlf 
249866f9d5cbSmlf /*
249966f9d5cbSmlf  * Builds the PRB for the sata packet and delivers it to controller.
250066f9d5cbSmlf  *
250166f9d5cbSmlf  * Returns:
250266f9d5cbSmlf  *	slot number if we can obtain a slot successfully
250366f9d5cbSmlf  *	otherwise, return SI_FAILURE
250466f9d5cbSmlf  *
250566f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
250666f9d5cbSmlf  * before calling us.
250766f9d5cbSmlf  */
250866f9d5cbSmlf static int
si_deliver_satapkt(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,sata_pkt_t * spkt)250966f9d5cbSmlf si_deliver_satapkt(
251066f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
251166f9d5cbSmlf 	si_port_state_t *si_portp,
251266f9d5cbSmlf 	int port,
251366f9d5cbSmlf 	sata_pkt_t *spkt)
251466f9d5cbSmlf {
251566f9d5cbSmlf 	int slot;
251666f9d5cbSmlf 	si_prb_t *prb;
251766f9d5cbSmlf 	sata_cmd_t *cmd;
251866f9d5cbSmlf 	si_sge_t *sgep; /* scatter gather entry pointer */
251966f9d5cbSmlf 	si_sgt_t *sgtp; /* scatter gather table pointer */
252066f9d5cbSmlf 	si_sgblock_t *sgbp; /* scatter gather block pointer */
252166f9d5cbSmlf 	int i, j, cookie_index;
252266f9d5cbSmlf 	int ncookies;
252366f9d5cbSmlf 	int is_atapi = 0;
252466f9d5cbSmlf 	ddi_dma_cookie_t cookie;
252566f9d5cbSmlf 
252666f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
252766f9d5cbSmlf 
252866f9d5cbSmlf 	slot = si_claim_free_slot(si_ctlp, si_portp, port);
2529ab0d082fSMark Logan 	if (slot == SI_FAILURE) {
253066f9d5cbSmlf 		return (SI_FAILURE);
253166f9d5cbSmlf 	}
253266f9d5cbSmlf 
253366f9d5cbSmlf 	if (spkt->satapkt_device.satadev_type == SATA_DTYPE_ATAPICD) {
253466f9d5cbSmlf 		is_atapi = 1;
253566f9d5cbSmlf 	}
253666f9d5cbSmlf 
253766f9d5cbSmlf 	if ((si_portp->siport_port_type == PORT_TYPE_NODEV) ||
253819397407SSherry Moore 	    !si_portp->siport_active) {
253966f9d5cbSmlf 		/*
254066f9d5cbSmlf 		 * si_intr_phy_ready_change() may have rendered it to
254166f9d5cbSmlf 		 * PORT_TYPE_NODEV. cfgadm operation may have rendered
254266f9d5cbSmlf 		 * it inactive.
254366f9d5cbSmlf 		 */
254466f9d5cbSmlf 		spkt->satapkt_reason = SATA_PKT_PORT_ERROR;
254566f9d5cbSmlf 		fill_dev_sregisters(si_ctlp, port, &spkt->satapkt_device);
2546832d3fc2SMark Logan 		CLEAR_BIT(si_portp->siport_pending_tags, slot);
254766f9d5cbSmlf 
254866f9d5cbSmlf 		return (SI_FAILURE);
254966f9d5cbSmlf 	}
255066f9d5cbSmlf 
255166f9d5cbSmlf 
255266f9d5cbSmlf 	prb =  &(si_portp->siport_prbpool[slot]);
255366f9d5cbSmlf 	bzero((void *)prb, sizeof (si_prb_t));
255466f9d5cbSmlf 
255566f9d5cbSmlf 	cmd = &spkt->satapkt_cmd;
255666f9d5cbSmlf 
2557e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp,
255819397407SSherry Moore 	    "si_deliver_satpkt entry: cmd_reg: 0x%x, slot: 0x%x, \
255966f9d5cbSmlf 		port: %x, satapkt: %x",
256019397407SSherry Moore 	    cmd->satacmd_cmd_reg, slot, port, (uint32_t)(intptr_t)spkt);
256166f9d5cbSmlf 
256266f9d5cbSmlf 	/* Now fill the prb. */
256366f9d5cbSmlf 	if (is_atapi) {
2564c03acfcaSls 		if (spkt->satapkt_cmd.satacmd_flags.sata_data_direction ==
2565c03acfcaSls 		    SATA_DIR_READ) {
256666f9d5cbSmlf 			SET_PRB_CONTROL_PKT_READ(prb);
2567c03acfcaSls 		} else if (spkt->satapkt_cmd.satacmd_flags.sata_data_direction
2568c03acfcaSls 		    == SATA_DIR_WRITE) {
256966f9d5cbSmlf 			SET_PRB_CONTROL_PKT_WRITE(prb);
257066f9d5cbSmlf 		}
257166f9d5cbSmlf 	}
257266f9d5cbSmlf 
257366f9d5cbSmlf 	SET_FIS_TYPE(prb->prb_fis, REGISTER_FIS_H2D);
257466f9d5cbSmlf 	if ((spkt->satapkt_device.satadev_addr.qual == SATA_ADDR_PMPORT) ||
257566f9d5cbSmlf 	    (spkt->satapkt_device.satadev_addr.qual == SATA_ADDR_DPMPORT)) {
257666f9d5cbSmlf 		SET_FIS_PMP(prb->prb_fis,
257719397407SSherry Moore 		    spkt->satapkt_device.satadev_addr.pmport);
257866f9d5cbSmlf 	}
257966f9d5cbSmlf 	SET_FIS_CDMDEVCTL(prb->prb_fis, 1);
258066f9d5cbSmlf 	SET_FIS_COMMAND(prb->prb_fis, cmd->satacmd_cmd_reg);
258166f9d5cbSmlf 	SET_FIS_FEATURES(prb->prb_fis, cmd->satacmd_features_reg);
258266f9d5cbSmlf 	SET_FIS_SECTOR_COUNT(prb->prb_fis, cmd->satacmd_sec_count_lsb);
258366f9d5cbSmlf 
258466f9d5cbSmlf 	switch (cmd->satacmd_addr_type) {
258566f9d5cbSmlf 
25861aae9af0SPraveen Kumar Dasaraju Rama 	case 0:
25871aae9af0SPraveen Kumar Dasaraju Rama 		/*
25881aae9af0SPraveen Kumar Dasaraju Rama 		 * satacmd_addr_type will be 0 for the commands below:
2589*83dba8e1SToomas Soome 		 *	SATAC_PACKET
2590*83dba8e1SToomas Soome 		 *	SATAC_IDLE_IM
2591*83dba8e1SToomas Soome 		 *	SATAC_STANDBY_IM
2592*83dba8e1SToomas Soome 		 *	SATAC_DOWNLOAD_MICROCODE
2593*83dba8e1SToomas Soome 		 *	SATAC_FLUSH_CACHE
2594*83dba8e1SToomas Soome 		 *	SATAC_SET_FEATURES
2595*83dba8e1SToomas Soome 		 *	SATAC_SMART
2596*83dba8e1SToomas Soome 		 *	SATAC_ID_PACKET_DEVICE
2597*83dba8e1SToomas Soome 		 *	SATAC_ID_DEVICE
2598*83dba8e1SToomas Soome 		 *	SATAC_READ_PORTMULT
2599*83dba8e1SToomas Soome 		 *	SATAC_WRITE_PORTMULT
26001aae9af0SPraveen Kumar Dasaraju Rama 		 */
26011aae9af0SPraveen Kumar Dasaraju Rama 		/* FALLTHRU */
26021aae9af0SPraveen Kumar Dasaraju Rama 
260366f9d5cbSmlf 	case ATA_ADDR_LBA:
26041aae9af0SPraveen Kumar Dasaraju Rama 		/* FALLTHRU */
260566f9d5cbSmlf 
260666f9d5cbSmlf 	case ATA_ADDR_LBA28:
260766f9d5cbSmlf 		/* LBA[7:0] */
260866f9d5cbSmlf 		SET_FIS_SECTOR(prb->prb_fis, cmd->satacmd_lba_low_lsb);
260966f9d5cbSmlf 
261066f9d5cbSmlf 		/* LBA[15:8] */
261166f9d5cbSmlf 		SET_FIS_CYL_LOW(prb->prb_fis, cmd->satacmd_lba_mid_lsb);
261266f9d5cbSmlf 
261366f9d5cbSmlf 		/* LBA[23:16] */
261466f9d5cbSmlf 		SET_FIS_CYL_HI(prb->prb_fis, cmd->satacmd_lba_high_lsb);
261566f9d5cbSmlf 
261666f9d5cbSmlf 		/* LBA [27:24] (also called dev_head) */
261766f9d5cbSmlf 		SET_FIS_DEV_HEAD(prb->prb_fis, cmd->satacmd_device_reg);
261866f9d5cbSmlf 
261966f9d5cbSmlf 		break;
262066f9d5cbSmlf 
262166f9d5cbSmlf 	case ATA_ADDR_LBA48:
262266f9d5cbSmlf 		/* LBA[7:0] */
262366f9d5cbSmlf 		SET_FIS_SECTOR(prb->prb_fis, cmd->satacmd_lba_low_lsb);
262466f9d5cbSmlf 
262566f9d5cbSmlf 		/* LBA[15:8] */
262666f9d5cbSmlf 		SET_FIS_CYL_LOW(prb->prb_fis, cmd->satacmd_lba_mid_lsb);
262766f9d5cbSmlf 
262866f9d5cbSmlf 		/* LBA[23:16] */
262966f9d5cbSmlf 		SET_FIS_CYL_HI(prb->prb_fis, cmd->satacmd_lba_high_lsb);
263066f9d5cbSmlf 
263166f9d5cbSmlf 		/* LBA [31:24] */
263266f9d5cbSmlf 		SET_FIS_SECTOR_EXP(prb->prb_fis, cmd->satacmd_lba_low_msb);
263366f9d5cbSmlf 
263466f9d5cbSmlf 		/* LBA [39:32] */
263566f9d5cbSmlf 		SET_FIS_CYL_LOW_EXP(prb->prb_fis, cmd->satacmd_lba_mid_msb);
263666f9d5cbSmlf 
263766f9d5cbSmlf 		/* LBA [47:40] */
263866f9d5cbSmlf 		SET_FIS_CYL_HI_EXP(prb->prb_fis, cmd->satacmd_lba_high_msb);
263966f9d5cbSmlf 
264066f9d5cbSmlf 		/* Set dev_head */
264166f9d5cbSmlf 		SET_FIS_DEV_HEAD(prb->prb_fis, cmd->satacmd_device_reg);
264266f9d5cbSmlf 
264366f9d5cbSmlf 		/* Set the extended sector count and features */
264466f9d5cbSmlf 		SET_FIS_SECTOR_COUNT_EXP(prb->prb_fis,
264519397407SSherry Moore 		    cmd->satacmd_sec_count_msb);
264666f9d5cbSmlf 		SET_FIS_FEATURES_EXP(prb->prb_fis,
264719397407SSherry Moore 		    cmd->satacmd_features_reg_ext);
264866f9d5cbSmlf 
264966f9d5cbSmlf 		break;
265066f9d5cbSmlf 
265166f9d5cbSmlf 	}
265266f9d5cbSmlf 
2653c03acfcaSls 	if (cmd->satacmd_flags.sata_queued) {
265466f9d5cbSmlf 		/*
265566f9d5cbSmlf 		 * For queued commands, the TAG for the sector count lsb is
265666f9d5cbSmlf 		 * generated from current slot number.
265766f9d5cbSmlf 		 */
265866f9d5cbSmlf 		SET_FIS_SECTOR_COUNT(prb->prb_fis, slot << 3);
265966f9d5cbSmlf 	}
266066f9d5cbSmlf 
266166f9d5cbSmlf 	if ((cmd->satacmd_cmd_reg == SATAC_WRITE_FPDMA_QUEUED) ||
266266f9d5cbSmlf 	    (cmd->satacmd_cmd_reg == SATAC_READ_FPDMA_QUEUED)) {
266366f9d5cbSmlf 		si_portp->siport_pending_ncq_count++;
266466f9d5cbSmlf 	}
266566f9d5cbSmlf 
266666f9d5cbSmlf 	/* *** now fill the scatter gather list ******* */
266766f9d5cbSmlf 
266866f9d5cbSmlf 	if (is_atapi) { /* It is an ATAPI drive */
266966f9d5cbSmlf 		/* atapi command goes into sge0 */
267066f9d5cbSmlf 		bcopy(cmd->satacmd_acdb, &prb->prb_sge0, sizeof (si_sge_t));
267166f9d5cbSmlf 
267266f9d5cbSmlf 		/* Now fill sge1 with pointer to external SGT. */
267366f9d5cbSmlf 		if (spkt->satapkt_cmd.satacmd_num_dma_cookies) {
267466f9d5cbSmlf 			prb->prb_sge1.sge_addr =
267519397407SSherry Moore 			    si_portp->siport_sgbpool_physaddr +
267681a0678eSxun ni - Sun Microsystems - Beijing China 			    slot * sizeof (si_sgblock_t) * si_dma_sg_number;
267766f9d5cbSmlf 			SET_SGE_LNK(prb->prb_sge1);
267866f9d5cbSmlf 		} else {
267966f9d5cbSmlf 			SET_SGE_TRM(prb->prb_sge1);
268066f9d5cbSmlf 		}
268166f9d5cbSmlf 	} else {
268266f9d5cbSmlf 		/* Fill the sge0 */
268366f9d5cbSmlf 		if (spkt->satapkt_cmd.satacmd_num_dma_cookies) {
268466f9d5cbSmlf 			prb->prb_sge0.sge_addr =
268519397407SSherry Moore 			    si_portp->siport_sgbpool_physaddr +
268681a0678eSxun ni - Sun Microsystems - Beijing China 			    slot * sizeof (si_sgblock_t) * si_dma_sg_number;
268766f9d5cbSmlf 			SET_SGE_LNK(prb->prb_sge0);
268866f9d5cbSmlf 
268966f9d5cbSmlf 		} else {
269066f9d5cbSmlf 			SET_SGE_TRM(prb->prb_sge0);
269166f9d5cbSmlf 		}
269266f9d5cbSmlf 
269366f9d5cbSmlf 		/* sge1 is left empty in non-ATAPI case */
269466f9d5cbSmlf 	}
269566f9d5cbSmlf 
269681a0678eSxun ni - Sun Microsystems - Beijing China 	bzero(&si_portp->siport_sgbpool[slot * si_dma_sg_number],
269781a0678eSxun ni - Sun Microsystems - Beijing China 	    sizeof (si_sgblock_t) * si_dma_sg_number);
269866f9d5cbSmlf 
269966f9d5cbSmlf 	ncookies = spkt->satapkt_cmd.satacmd_num_dma_cookies;
270081a0678eSxun ni - Sun Microsystems - Beijing China 	ASSERT(ncookies <= (SGE_LENGTH(si_dma_sg_number)));
270166f9d5cbSmlf 
2702e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_COOKIES, si_portp, "total ncookies: %d", ncookies);
270366f9d5cbSmlf 	if (ncookies == 0) {
270481a0678eSxun ni - Sun Microsystems - Beijing China 		sgbp = &si_portp->siport_sgbpool[slot * si_dma_sg_number];
270566f9d5cbSmlf 		sgtp = &sgbp->sgb_sgt[0];
270666f9d5cbSmlf 		sgep = &sgtp->sgt_sge[0];
270766f9d5cbSmlf 
270866f9d5cbSmlf 		/* No cookies. Terminate the chain. */
2709e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_COOKIES, si_portp, "empty cookies: terminating.",
2710e57ece5bSPraveen Kumar Dasaraju Rama 		    NULL);
271166f9d5cbSmlf 
271266f9d5cbSmlf 		sgep->sge_addr_low = 0;
271366f9d5cbSmlf 		sgep->sge_addr_high = 0;
271466f9d5cbSmlf 		sgep->sge_data_count = 0;
271566f9d5cbSmlf 		SET_SGE_TRM((*sgep));
271666f9d5cbSmlf 
271766f9d5cbSmlf 		goto sgl_fill_done;
271866f9d5cbSmlf 	}
271966f9d5cbSmlf 
272081a0678eSxun ni - Sun Microsystems - Beijing China 	for (i = 0, cookie_index = 0,
272181a0678eSxun ni - Sun Microsystems - Beijing China 	    sgbp = &si_portp->siport_sgbpool[slot * si_dma_sg_number];
272281a0678eSxun ni - Sun Microsystems - Beijing China 	    i < si_dma_sg_number; i++) {
272366f9d5cbSmlf 
272481a0678eSxun ni - Sun Microsystems - Beijing China 		sgtp = &sgbp->sgb_sgt[0] + i;
272566f9d5cbSmlf 
272666f9d5cbSmlf 		/* Now fill the first 3 entries of SGT in the loop below. */
272766f9d5cbSmlf 		for (j = 0, sgep = &sgtp->sgt_sge[0];
272819397407SSherry Moore 		    ((j < 3) && (cookie_index < ncookies-1));
272919397407SSherry Moore 		    j++, cookie_index++, sgep++)  {
273066f9d5cbSmlf 			ASSERT(cookie_index < ncookies);
2731e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_COOKIES, si_portp,
273219397407SSherry Moore 			    "inner loop: cookie_index: %d, ncookies: %d",
273319397407SSherry Moore 			    cookie_index,
273419397407SSherry Moore 			    ncookies);
273566f9d5cbSmlf 			cookie = spkt->satapkt_cmd.
273619397407SSherry Moore 			    satacmd_dma_cookie_list[cookie_index];
273766f9d5cbSmlf 
273866f9d5cbSmlf 			sgep->sge_addr_low = cookie._dmu._dmac_la[0];
273966f9d5cbSmlf 			sgep->sge_addr_high = cookie._dmu._dmac_la[1];
27400cfc6e4aSxun ni - Sun Microsystems - Beijing China 			sgep->sge_data_count = (uint32_t)cookie.dmac_size;
274166f9d5cbSmlf 		}
274266f9d5cbSmlf 
274366f9d5cbSmlf 		/*
274466f9d5cbSmlf 		 * If this happens to be the last cookie, we terminate it here.
274566f9d5cbSmlf 		 * Otherwise, we link to next SGT.
274666f9d5cbSmlf 		 */
274766f9d5cbSmlf 
274866f9d5cbSmlf 		if (cookie_index == ncookies-1) {
274966f9d5cbSmlf 			/* This is the last cookie. Terminate the chain. */
2750e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_COOKIES, si_portp,
275119397407SSherry Moore 			    "filling the last: cookie_index: %d, "
275219397407SSherry Moore 			    "ncookies: %d",
275319397407SSherry Moore 			    cookie_index,
275419397407SSherry Moore 			    ncookies);
275566f9d5cbSmlf 			cookie = spkt->satapkt_cmd.
275619397407SSherry Moore 			    satacmd_dma_cookie_list[cookie_index];
275766f9d5cbSmlf 
275866f9d5cbSmlf 			sgep->sge_addr_low = cookie._dmu._dmac_la[0];
275966f9d5cbSmlf 			sgep->sge_addr_high = cookie._dmu._dmac_la[1];
27600cfc6e4aSxun ni - Sun Microsystems - Beijing China 			sgep->sge_data_count = (uint32_t)cookie.dmac_size;
276166f9d5cbSmlf 			SET_SGE_TRM((*sgep));
276266f9d5cbSmlf 
276366f9d5cbSmlf 			break; /* we break the loop */
276466f9d5cbSmlf 
276566f9d5cbSmlf 		} else {
276666f9d5cbSmlf 			/* This is not the last one. So link it. */
2767e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_COOKIES, si_portp,
276819397407SSherry Moore 			    "linking SGT: cookie_index: %d, ncookies: %d",
276919397407SSherry Moore 			    cookie_index,
277019397407SSherry Moore 			    ncookies);
277166f9d5cbSmlf 			sgep->sge_addr = si_portp->siport_sgbpool_physaddr +
277281a0678eSxun ni - Sun Microsystems - Beijing China 			    slot * sizeof (si_sgblock_t) * si_dma_sg_number +
277319397407SSherry Moore 			    (i+1) * sizeof (si_sgt_t);
277466f9d5cbSmlf 
277566f9d5cbSmlf 			SET_SGE_LNK((*sgep));
277666f9d5cbSmlf 		}
277766f9d5cbSmlf 
277866f9d5cbSmlf 	}
277966f9d5cbSmlf 
278066f9d5cbSmlf 	/* *** finished filling the scatter gather list ******* */
278166f9d5cbSmlf 
278266f9d5cbSmlf sgl_fill_done:
278366f9d5cbSmlf 	/* Now remember the sata packet in siport_slot_pkts[]. */
278466f9d5cbSmlf 	si_portp->siport_slot_pkts[slot] = spkt;
278566f9d5cbSmlf 
278666f9d5cbSmlf 	/*
278766f9d5cbSmlf 	 * We are overloading satapkt_hba_driver_private with
278866f9d5cbSmlf 	 * watched_cycle count.
278966f9d5cbSmlf 	 */
279066f9d5cbSmlf 	spkt->satapkt_hba_driver_private = (void *)(intptr_t)0;
279166f9d5cbSmlf 
279266f9d5cbSmlf 	if (is_atapi) {
279366f9d5cbSmlf 		/* program the packet_lenth if it is atapi device. */
279466f9d5cbSmlf 
279566f9d5cbSmlf 
279666f9d5cbSmlf #ifdef ATAPI_2nd_PHASE
279766f9d5cbSmlf 		/*
279866f9d5cbSmlf 		 * Framework needs to calculate the acdb_len based on
279966f9d5cbSmlf 		 * identify packet data. This needs to be accomplished
280066f9d5cbSmlf 		 * in second phase of the project.
280166f9d5cbSmlf 		 */
280266f9d5cbSmlf 		ASSERT((cmd->satacmd_acdb_len == 12) ||
280319397407SSherry Moore 		    (cmd->satacmd_acdb_len == 16));
2804e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp, "deliver: acdb_len: %d",
280519397407SSherry Moore 		    cmd->satacmd_acdb_len);
280666f9d5cbSmlf 
280766f9d5cbSmlf 		if (cmd->satacmd_acdb_len == 16) {
280866f9d5cbSmlf 			ddi_put32(si_ctlp->sictl_port_acc_handle,
280919397407SSherry Moore 			    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
281019397407SSherry Moore 			    PORT_CONTROL_SET_BITS_PACKET_LEN);
281166f9d5cbSmlf 		} else {
281266f9d5cbSmlf 			ddi_put32(si_ctlp->sictl_port_acc_handle,
281319397407SSherry Moore 			    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
281419397407SSherry Moore 			    PORT_CONTROL_CLEAR_BITS_PACKET_LEN);
281566f9d5cbSmlf 		}
281666f9d5cbSmlf 
281766f9d5cbSmlf #else /* ATAPI_2nd_PHASE */
281866f9d5cbSmlf 		/* hard coding for now to 12 bytes */
281966f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
282019397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
282119397407SSherry Moore 		    PORT_CONTROL_CLEAR_BITS_PACKET_LEN);
282266f9d5cbSmlf #endif /* ATAPI_2nd_PHASE */
282366f9d5cbSmlf 	}
282466f9d5cbSmlf 
282566f9d5cbSmlf 
282666f9d5cbSmlf #if SI_DEBUG
282766f9d5cbSmlf 	if (si_debug_flags & SIDBG_DUMP_PRB) {
282866f9d5cbSmlf 		if (!(is_atapi && (prb->prb_sge0.sge_addr_low == 0))) {
282966f9d5cbSmlf 			/*
283066f9d5cbSmlf 			 * Do not dump the atapi Test-Unit-Ready commands.
283166f9d5cbSmlf 			 * The sd_media_watch spews too many of these.
283266f9d5cbSmlf 			 */
283366f9d5cbSmlf 			int *ptr;
283466f9d5cbSmlf 			si_sge_t *tmpsgep;
283566f9d5cbSmlf 			int j;
283666f9d5cbSmlf 
28370cfc6e4aSxun ni - Sun Microsystems - Beijing China 			ptr = (int *)(void *)prb;
283866f9d5cbSmlf 			cmn_err(CE_WARN, "si_deliver_satpkt prb: ");
283966f9d5cbSmlf 			for (j = 0; j < (sizeof (si_prb_t)/4); j++) {
284066f9d5cbSmlf 				cmn_err(CE_WARN, "%x ", ptr[j]);
284166f9d5cbSmlf 			}
284266f9d5cbSmlf 
284366f9d5cbSmlf 			cmn_err(CE_WARN,
284419397407SSherry Moore 			    "si_deliver_satpkt sgt: low, high, count link");
284566f9d5cbSmlf 			for (j = 0,
284619397407SSherry Moore 			    tmpsgep = (si_sge_t *)
284781a0678eSxun ni - Sun Microsystems - Beijing China 			    &si_portp->siport_sgbpool[slot * si_dma_sg_number];
284881a0678eSxun ni - Sun Microsystems - Beijing China 			    j < (sizeof (si_sgblock_t)/ sizeof (si_sge_t))
284981a0678eSxun ni - Sun Microsystems - Beijing China 			    *si_dma_sg_number;
285019397407SSherry Moore 			    j++, tmpsgep++) {
28510cfc6e4aSxun ni - Sun Microsystems - Beijing China 				ptr = (int *)(void *)tmpsgep;
285266f9d5cbSmlf 				cmn_err(CE_WARN, "%x %x %x %x",
285319397407SSherry Moore 				    ptr[0],
285419397407SSherry Moore 				    ptr[1],
285519397407SSherry Moore 				    ptr[2],
285619397407SSherry Moore 				    ptr[3]);
285766f9d5cbSmlf 				if (IS_SGE_TRM_SET((*tmpsgep))) {
285866f9d5cbSmlf 					break;
285966f9d5cbSmlf 				}
286066f9d5cbSmlf 
286166f9d5cbSmlf 			}
286266f9d5cbSmlf 		}
286366f9d5cbSmlf 
286466f9d5cbSmlf 	}
286566f9d5cbSmlf #endif  /* SI_DEBUG */
286666f9d5cbSmlf 
286766f9d5cbSmlf 	/* Deliver PRB */
286866f9d5cbSmlf 	POST_PRB_ADDR(si_ctlp, si_portp, port, slot);
286966f9d5cbSmlf 
287066f9d5cbSmlf 	return (slot);
287166f9d5cbSmlf }
287266f9d5cbSmlf 
287366f9d5cbSmlf /*
287466f9d5cbSmlf  * Initialize the controller and set up driver data structures.
287566f9d5cbSmlf  *
287666f9d5cbSmlf  * This routine can be called from three separate cases: DDI_ATTACH, PM_LEVEL_D0
287766f9d5cbSmlf  * and DDI_RESUME. The DDI_ATTACH case is different from other two cases; the
287866f9d5cbSmlf  * memory allocation & device signature probing are attempted only during
287966f9d5cbSmlf  * DDI_ATTACH case. In the case of PM_LEVEL_D0 & DDI_RESUME, we are starting
288066f9d5cbSmlf  * from a previously initialized state; so there is no need to allocate memory
288166f9d5cbSmlf  * or to attempt probing the device signatures.
288266f9d5cbSmlf  */
288366f9d5cbSmlf static int
si_initialize_controller(si_ctl_state_t * si_ctlp)288466f9d5cbSmlf si_initialize_controller(si_ctl_state_t *si_ctlp)
288566f9d5cbSmlf {
288666f9d5cbSmlf 	uint32_t port_status;
288766f9d5cbSmlf 	uint32_t SStatus;
288866f9d5cbSmlf 	uint32_t SControl;
2889e57ece5bSPraveen Kumar Dasaraju Rama 	uint8_t port;
289066f9d5cbSmlf 	int loop_count = 0;
289166f9d5cbSmlf 	si_port_state_t *si_portp;
289266f9d5cbSmlf 
2893e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp,
2894e57ece5bSPraveen Kumar Dasaraju Rama 	    "si3124: si_initialize_controller entered", NULL);
289566f9d5cbSmlf 
289666f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
289766f9d5cbSmlf 
289866f9d5cbSmlf 	/* Remove the Global Reset. */
289966f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_global_acc_handle,
290019397407SSherry Moore 	    (uint32_t *)GLOBAL_CONTROL_REG(si_ctlp),
290119397407SSherry Moore 	    GLOBAL_CONTROL_REG_BITS_CLEAR);
290266f9d5cbSmlf 
290366f9d5cbSmlf 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
290466f9d5cbSmlf 
290566f9d5cbSmlf 		if (si_ctlp->sictl_flags & SI_ATTACH) {
290666f9d5cbSmlf 			/*
290766f9d5cbSmlf 			 * We allocate the port state only during attach
290866f9d5cbSmlf 			 * sequence. We don't want to do it during
290966f9d5cbSmlf 			 * suspend/resume sequence.
291066f9d5cbSmlf 			 */
291166f9d5cbSmlf 			if (si_alloc_port_state(si_ctlp, port)) {
291266f9d5cbSmlf 				mutex_exit(&si_ctlp->sictl_mutex);
291366f9d5cbSmlf 				return (SI_FAILURE);
291466f9d5cbSmlf 			}
291566f9d5cbSmlf 		}
291666f9d5cbSmlf 
291766f9d5cbSmlf 		si_portp = si_ctlp->sictl_ports[port];
291866f9d5cbSmlf 		mutex_enter(&si_portp->siport_mutex);
2919e57ece5bSPraveen Kumar Dasaraju Rama 		si_portp->siport_ctlp = si_ctlp;
2920e57ece5bSPraveen Kumar Dasaraju Rama 		si_portp->siport_port_num = port;
292166f9d5cbSmlf 
292266f9d5cbSmlf 		/* Clear Port Reset. */
29230b0c3d30Sjohansen 		ddi_put32(si_ctlp->sictl_port_acc_handle,
292419397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
292519397407SSherry Moore 		    PORT_CONTROL_SET_BITS_PORT_RESET);
292666f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
292719397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
292819397407SSherry Moore 		    PORT_CONTROL_CLEAR_BITS_PORT_RESET);
292966f9d5cbSmlf 
293066f9d5cbSmlf 		/*
293166f9d5cbSmlf 		 * Arm the interrupts for: Cmd completion, Cmd error,
293266f9d5cbSmlf 		 * Port Ready, PM Change, PhyRdyChange, Commwake,
293366f9d5cbSmlf 		 * UnrecFIS, Devxchanged, SDBNotify.
293466f9d5cbSmlf 		 */
293566f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
293619397407SSherry Moore 		    (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port),
293719397407SSherry Moore 		    (INTR_COMMAND_COMPLETE |
293819397407SSherry Moore 		    INTR_COMMAND_ERROR |
293919397407SSherry Moore 		    INTR_PORT_READY |
294019397407SSherry Moore 		    INTR_POWER_CHANGE |
294119397407SSherry Moore 		    INTR_PHYRDY_CHANGE |
294219397407SSherry Moore 		    INTR_COMWAKE_RECEIVED |
294319397407SSherry Moore 		    INTR_UNRECOG_FIS |
294419397407SSherry Moore 		    INTR_DEV_XCHANGED |
294519397407SSherry Moore 		    INTR_SETDEVBITS_NOTIFY));
294666f9d5cbSmlf 
294766f9d5cbSmlf 		/* Now enable the interrupts. */
294866f9d5cbSmlf 		si_enable_port_interrupts(si_ctlp, port);
294966f9d5cbSmlf 
295066f9d5cbSmlf 		/*
295166f9d5cbSmlf 		 * The following PHY initialization is redundant in
295266f9d5cbSmlf 		 * in x86 since the BIOS anyway does this as part of
295366f9d5cbSmlf 		 * device enumeration during the power up. But this
295466f9d5cbSmlf 		 * is a required step in sparc since there is no BIOS.
295566f9d5cbSmlf 		 *
295666f9d5cbSmlf 		 * The way to initialize the PHY is to write a 1 and then
295766f9d5cbSmlf 		 * a 0 to DET field of SControl register.
295866f9d5cbSmlf 		 */
295966f9d5cbSmlf 
296066f9d5cbSmlf 		/*
296166f9d5cbSmlf 		 * Fetch the current SControl before writing the
296266f9d5cbSmlf 		 * DET part with 1
296366f9d5cbSmlf 		 */
296466f9d5cbSmlf 		SControl = ddi_get32(si_ctlp->sictl_port_acc_handle,
296519397407SSherry Moore 		    (uint32_t *)PORT_SCONTROL(si_ctlp, port));
296666f9d5cbSmlf 		SCONTROL_SET_DET(SControl, SCONTROL_DET_COMRESET);
296766f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
296819397407SSherry Moore 		    (uint32_t *)(PORT_SCONTROL(si_ctlp, port)),
296919397407SSherry Moore 		    SControl);
297066f9d5cbSmlf #ifndef __lock_lint
297166f9d5cbSmlf 		delay(SI_10MS_TICKS); /* give time for COMRESET to percolate */
297266f9d5cbSmlf #endif /* __lock_lint */
297366f9d5cbSmlf 
297466f9d5cbSmlf 		/*
297566f9d5cbSmlf 		 * Now fetch the SControl again and rewrite the
297666f9d5cbSmlf 		 * DET part with 0
297766f9d5cbSmlf 		 */
297866f9d5cbSmlf 		SControl = ddi_get32(si_ctlp->sictl_port_acc_handle,
297919397407SSherry Moore 		    (uint32_t *)PORT_SCONTROL(si_ctlp, port));
298066f9d5cbSmlf 		SCONTROL_SET_DET(SControl, SCONTROL_DET_NOACTION);
298166f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
298219397407SSherry Moore 		    (uint32_t *)(PORT_SCONTROL(si_ctlp, port)),
298319397407SSherry Moore 		    SControl);
298466f9d5cbSmlf 
298566f9d5cbSmlf 		/*
298666f9d5cbSmlf 		 * PHY may be initialized by now. Check the DET field of
298766f9d5cbSmlf 		 * SStatus to determine if there is a device present.
298866f9d5cbSmlf 		 *
298966f9d5cbSmlf 		 * The DET field is valid only if IPM field indicates that
299066f9d5cbSmlf 		 * the interface is in active state.
299166f9d5cbSmlf 		 */
299266f9d5cbSmlf 
299366f9d5cbSmlf 		loop_count = 0;
299466f9d5cbSmlf 		do {
299566f9d5cbSmlf 			SStatus = ddi_get32(si_ctlp->sictl_port_acc_handle,
299619397407SSherry Moore 			    (uint32_t *)PORT_SSTATUS(si_ctlp, port));
299766f9d5cbSmlf 
299866f9d5cbSmlf 			if (SSTATUS_GET_IPM(SStatus) !=
299919397407SSherry Moore 			    SSTATUS_IPM_INTERFACE_ACTIVE) {
300066f9d5cbSmlf 				/*
300166f9d5cbSmlf 				 * If the interface is not active, the DET field
300266f9d5cbSmlf 				 * is considered not accurate. So we want to
300366f9d5cbSmlf 				 * continue looping.
300466f9d5cbSmlf 				 */
300566f9d5cbSmlf 				SSTATUS_SET_DET(SStatus,
300619397407SSherry Moore 				    SSTATUS_DET_NODEV_NOPHY);
300766f9d5cbSmlf 			}
300866f9d5cbSmlf 
300966f9d5cbSmlf 			if (loop_count++ > SI_POLLRATE_SSTATUS) {
301066f9d5cbSmlf 				/*
301166f9d5cbSmlf 				 * We are effectively timing out after 0.1 sec.
301266f9d5cbSmlf 				 */
301366f9d5cbSmlf 				break;
301466f9d5cbSmlf 			}
301566f9d5cbSmlf 
301666f9d5cbSmlf 			/* Wait for 10 millisec */
301766f9d5cbSmlf #ifndef __lock_lint
301866f9d5cbSmlf 			delay(SI_10MS_TICKS);
301966f9d5cbSmlf #endif /* __lock_lint */
302066f9d5cbSmlf 
302166f9d5cbSmlf 		} while (SSTATUS_GET_DET(SStatus) !=
302219397407SSherry Moore 		    SSTATUS_DET_DEVPRESENT_PHYONLINE);
302366f9d5cbSmlf 
3024e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
302519397407SSherry Moore 		    "si_initialize_controller: 1st loop count: %d, "
302619397407SSherry Moore 		    "SStatus: 0x%x",
302719397407SSherry Moore 		    loop_count,
302819397407SSherry Moore 		    SStatus);
302966f9d5cbSmlf 
303066f9d5cbSmlf 		if ((SSTATUS_GET_IPM(SStatus) !=
303119397407SSherry Moore 		    SSTATUS_IPM_INTERFACE_ACTIVE) ||
303219397407SSherry Moore 		    (SSTATUS_GET_DET(SStatus) !=
303319397407SSherry Moore 		    SSTATUS_DET_DEVPRESENT_PHYONLINE)) {
303466f9d5cbSmlf 			/*
303566f9d5cbSmlf 			 * Either the port is not active or there
303666f9d5cbSmlf 			 * is no device present.
303766f9d5cbSmlf 			 */
303866f9d5cbSmlf 			si_ctlp->sictl_ports[port]->siport_port_type =
303919397407SSherry Moore 			    PORT_TYPE_NODEV;
304066f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
304166f9d5cbSmlf 			continue;
304266f9d5cbSmlf 		}
304366f9d5cbSmlf 
304466f9d5cbSmlf 		/* Wait until Port Ready */
304566f9d5cbSmlf 		loop_count = 0;
304666f9d5cbSmlf 		do {
304766f9d5cbSmlf 			port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
304819397407SSherry Moore 			    (uint32_t *)PORT_STATUS(si_ctlp, port));
304966f9d5cbSmlf 
305066f9d5cbSmlf 			if (loop_count++ > SI_POLLRATE_PORTREADY) {
305166f9d5cbSmlf 				/*
305266f9d5cbSmlf 				 * We are effectively timing out after 0.5 sec.
305366f9d5cbSmlf 				 */
305466f9d5cbSmlf 				break;
305566f9d5cbSmlf 			}
305666f9d5cbSmlf 
305766f9d5cbSmlf 			/* Wait for 10 millisec */
305866f9d5cbSmlf #ifndef __lock_lint
305966f9d5cbSmlf 			delay(SI_10MS_TICKS);
306066f9d5cbSmlf #endif /* __lock_lint */
306166f9d5cbSmlf 
306266f9d5cbSmlf 		} while (!(port_status & PORT_STATUS_BITS_PORT_READY));
306366f9d5cbSmlf 
3064e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
306519397407SSherry Moore 		    "si_initialize_controller: 2nd loop count: %d",
306619397407SSherry Moore 		    loop_count);
306766f9d5cbSmlf 
306866f9d5cbSmlf 		if (si_ctlp->sictl_flags & SI_ATTACH) {
306966f9d5cbSmlf 			/*
307066f9d5cbSmlf 			 * We want to probe for dev signature only during attach
307166f9d5cbSmlf 			 * case. Don't do it during suspend/resume sequence.
307266f9d5cbSmlf 			 */
307366f9d5cbSmlf 			if (port_status & PORT_STATUS_BITS_PORT_READY) {
307466f9d5cbSmlf 				mutex_exit(&si_portp->siport_mutex);
307566f9d5cbSmlf 				si_find_dev_signature(si_ctlp, si_portp, port,
307619397407SSherry Moore 				    PORTMULT_CONTROL_PORT);
307766f9d5cbSmlf 				mutex_enter(&si_portp->siport_mutex);
307866f9d5cbSmlf 			} else {
307966f9d5cbSmlf 				si_ctlp->sictl_ports[port]->siport_port_type =
308019397407SSherry Moore 				    PORT_TYPE_NODEV;
308166f9d5cbSmlf 			}
308266f9d5cbSmlf 		}
308366f9d5cbSmlf 
3084ab0d082fSMark Logan 		if (si_check_ctl_handles(si_ctlp) != DDI_SUCCESS ||
3085ab0d082fSMark Logan 		    si_check_port_handles(si_portp) != DDI_SUCCESS) {
3086ab0d082fSMark Logan 			ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3087ab0d082fSMark Logan 			    DDI_SERVICE_LOST);
3088ab0d082fSMark Logan 			mutex_exit(&si_portp->siport_mutex);
3089ab0d082fSMark Logan 			mutex_exit(&si_ctlp->sictl_mutex);
3090ab0d082fSMark Logan 			return (SI_FAILURE);
3091ab0d082fSMark Logan 		}
3092ab0d082fSMark Logan 
309366f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
309466f9d5cbSmlf 	}
309566f9d5cbSmlf 
309666f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
309766f9d5cbSmlf 	return (SI_SUCCESS);
309866f9d5cbSmlf }
309966f9d5cbSmlf 
310066f9d5cbSmlf /*
310166f9d5cbSmlf  * Reverse of si_initialize_controller().
310266f9d5cbSmlf  *
310366f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the sictl_mutex
310466f9d5cbSmlf  * before calling us.
310566f9d5cbSmlf  */
310666f9d5cbSmlf static void
si_deinitialize_controller(si_ctl_state_t * si_ctlp)3107a599d311SMartin Faltesek si_deinitialize_controller(si_ctl_state_t *si_ctlp)
310866f9d5cbSmlf {
310966f9d5cbSmlf 	int port;
311066f9d5cbSmlf 
311166f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_ctlp))
311266f9d5cbSmlf 
3113e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp,
3114e57ece5bSPraveen Kumar Dasaraju Rama 	    "si3124: si_deinitialize_controller entered", NULL);
311566f9d5cbSmlf 
311666f9d5cbSmlf 	/* disable all the interrupts. */
311766f9d5cbSmlf 	si_disable_all_interrupts(si_ctlp);
311866f9d5cbSmlf 
311966f9d5cbSmlf 	if (si_ctlp->sictl_flags & SI_DETACH) {
312066f9d5cbSmlf 		/*
312166f9d5cbSmlf 		 * We want to dealloc all the memory in detach case.
312266f9d5cbSmlf 		 */
312366f9d5cbSmlf 		for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
312466f9d5cbSmlf 			si_dealloc_port_state(si_ctlp, port);
312566f9d5cbSmlf 		}
312666f9d5cbSmlf 	}
312766f9d5cbSmlf 
312866f9d5cbSmlf }
312966f9d5cbSmlf 
313066f9d5cbSmlf /*
313166f9d5cbSmlf  * Prepare the port ready for usage.
313266f9d5cbSmlf  *
313366f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
313466f9d5cbSmlf  * before calling us.
313566f9d5cbSmlf  */
313666f9d5cbSmlf static void
si_init_port(si_ctl_state_t * si_ctlp,int port)313766f9d5cbSmlf si_init_port(si_ctl_state_t *si_ctlp, int port)
313866f9d5cbSmlf {
313966f9d5cbSmlf 
3140e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp,
314119397407SSherry Moore 	    "si_init_port entered: port: 0x%x",
314219397407SSherry Moore 	    port);
314366f9d5cbSmlf 
314466f9d5cbSmlf 	/* Initialize the port. */
314566f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
314619397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
314719397407SSherry Moore 	    PORT_CONTROL_SET_BITS_PORT_INITIALIZE);
314866f9d5cbSmlf 
314966f9d5cbSmlf 	/*
3150a599d311SMartin Faltesek 	 * Clear the InterruptNCOR (Interrupt No Clear on Read).
315166f9d5cbSmlf 	 * This step ensures that a mere reading of slot_status will clear
315266f9d5cbSmlf 	 * the interrupt; no explicit clearing of interrupt condition
315366f9d5cbSmlf 	 * will be needed for successful completion of commands.
315466f9d5cbSmlf 	 */
315566f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
315619397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
315719397407SSherry Moore 	    PORT_CONTROL_CLEAR_BITS_INTR_NCoR);
315866f9d5cbSmlf 
315966f9d5cbSmlf 	/* clear any pending interrupts at this point */
316066f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
316119397407SSherry Moore 	    (uint32_t *)(PORT_INTERRUPT_STATUS(si_ctlp, port)),
316219397407SSherry Moore 	    INTR_MASK);
316366f9d5cbSmlf 
316466f9d5cbSmlf }
316566f9d5cbSmlf 
316666f9d5cbSmlf 
316766f9d5cbSmlf /*
316866f9d5cbSmlf  * Enumerate the devices connected to the port multiplier.
316966f9d5cbSmlf  * Once a device is detected, we call si_find_dev_signature()
317066f9d5cbSmlf  * to find the type of device connected. Even though we are
317166f9d5cbSmlf  * called from within si_find_dev_signature(), there is no
317266f9d5cbSmlf  * recursion possible.
317366f9d5cbSmlf  */
317466f9d5cbSmlf static int
si_enumerate_port_multiplier(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)317566f9d5cbSmlf si_enumerate_port_multiplier(
317666f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
317766f9d5cbSmlf 	si_port_state_t *si_portp,
317866f9d5cbSmlf 	int port)
317966f9d5cbSmlf {
318066f9d5cbSmlf 	uint32_t num_dev_ports = 0;
318166f9d5cbSmlf 	int pmport;
318266f9d5cbSmlf 	uint32_t SControl = 0;
318366f9d5cbSmlf 	uint32_t SStatus = 0;
318466f9d5cbSmlf 	uint32_t SError = 0;
318566f9d5cbSmlf 	int loop_count = 0;
318666f9d5cbSmlf 
3187e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp,
318819397407SSherry Moore 	    "si_enumerate_port_multiplier entered: port: %d",
318919397407SSherry Moore 	    port);
319066f9d5cbSmlf 
319166f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
319266f9d5cbSmlf 
319366f9d5cbSmlf 	/* Enable Port Multiplier context switching. */
319466f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
319519397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
319619397407SSherry Moore 	    PORT_CONTROL_SET_BITS_PM_ENABLE);
319766f9d5cbSmlf 
319866f9d5cbSmlf 	/*
319966f9d5cbSmlf 	 * Read the num dev ports connected.
320066f9d5cbSmlf 	 * GSCR[2] contains the number of device ports.
320166f9d5cbSmlf 	 */
320266f9d5cbSmlf 	if (si_read_portmult_reg(si_ctlp, si_portp, port, PORTMULT_CONTROL_PORT,
320319397407SSherry Moore 	    PSCR_REG2, &num_dev_ports)) {
320466f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
320566f9d5cbSmlf 		return (SI_FAILURE);
320666f9d5cbSmlf 	}
320766f9d5cbSmlf 	si_portp->siport_portmult_state.sipm_num_ports = num_dev_ports;
320866f9d5cbSmlf 
3209e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp,
321019397407SSherry Moore 	    "si_enumerate_port_multiplier: ports found: %d",
321119397407SSherry Moore 	    num_dev_ports);
321266f9d5cbSmlf 
321366f9d5cbSmlf 	for (pmport = 0; pmport < num_dev_ports-1; pmport++) {
321466f9d5cbSmlf 		/*
321566f9d5cbSmlf 		 * Enable PHY by writing a 1, then a 0 to SControl
321666f9d5cbSmlf 		 * (i.e. PSCR[2]) DET field.
321766f9d5cbSmlf 		 */
321866f9d5cbSmlf 		if (si_read_portmult_reg(si_ctlp, si_portp, port, pmport,
321919397407SSherry Moore 		    PSCR_REG2, &SControl)) {
322066f9d5cbSmlf 			continue;
322166f9d5cbSmlf 		}
322266f9d5cbSmlf 
322366f9d5cbSmlf 		/* First write a 1 to DET field of SControl. */
322466f9d5cbSmlf 		SCONTROL_SET_DET(SControl, SCONTROL_DET_COMRESET);
322566f9d5cbSmlf 		if (si_write_portmult_reg(si_ctlp, si_portp, port, pmport,
322619397407SSherry Moore 		    PSCR_REG2, SControl)) {
322766f9d5cbSmlf 			continue;
322866f9d5cbSmlf 		}
322966f9d5cbSmlf #ifndef __lock_lint
323066f9d5cbSmlf 		delay(SI_10MS_TICKS); /* give time for COMRESET to percolate */
323166f9d5cbSmlf #endif /* __lock_lint */
323266f9d5cbSmlf 
323366f9d5cbSmlf 		/* Then write a 0 to the DET field of SControl. */
323466f9d5cbSmlf 		SCONTROL_SET_DET(SControl, SCONTROL_DET_NOACTION);
323566f9d5cbSmlf 		if (si_write_portmult_reg(si_ctlp, si_portp, port, pmport,
323619397407SSherry Moore 		    PSCR_REG2, SControl)) {
323766f9d5cbSmlf 			continue;
323866f9d5cbSmlf 		}
323966f9d5cbSmlf 
324066f9d5cbSmlf 		/* Wait for PHYRDY by polling SStatus (i.e. PSCR[0]). */
324166f9d5cbSmlf 		loop_count = 0;
324266f9d5cbSmlf 		do {
324366f9d5cbSmlf 			if (si_read_portmult_reg(si_ctlp, si_portp, port,
324419397407SSherry Moore 			    pmport, PSCR_REG0, &SStatus)) {
324566f9d5cbSmlf 				break;
324666f9d5cbSmlf 			}
3247e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_POLL_LOOP, si_portp,
324819397407SSherry Moore 			    "looping for PHYRDY: SStatus: %x",
324919397407SSherry Moore 			    SStatus);
325066f9d5cbSmlf 
325166f9d5cbSmlf 			if (SSTATUS_GET_IPM(SStatus) !=
325219397407SSherry Moore 			    SSTATUS_IPM_INTERFACE_ACTIVE) {
325366f9d5cbSmlf 				/*
325466f9d5cbSmlf 				 * If the interface is not active, the DET field
325566f9d5cbSmlf 				 * is considered not accurate. So we want to
325666f9d5cbSmlf 				 * continue looping.
325766f9d5cbSmlf 				 */
325866f9d5cbSmlf 				SSTATUS_SET_DET(SStatus,
325919397407SSherry Moore 				    SSTATUS_DET_NODEV_NOPHY);
326066f9d5cbSmlf 			}
326166f9d5cbSmlf 
326266f9d5cbSmlf 			if (loop_count++ > SI_POLLRATE_SSTATUS) {
326366f9d5cbSmlf 				/*
326466f9d5cbSmlf 				 * We are effectively timing out after 0.1 sec.
326566f9d5cbSmlf 				 */
326666f9d5cbSmlf 				break;
326766f9d5cbSmlf 			}
326866f9d5cbSmlf 
326966f9d5cbSmlf 			/* Wait for 10 millisec */
327066f9d5cbSmlf #ifndef __lock_lint
327166f9d5cbSmlf 			delay(SI_10MS_TICKS);
327266f9d5cbSmlf #endif /* __lock_lint */
327366f9d5cbSmlf 
327466f9d5cbSmlf 		} while (SSTATUS_GET_DET(SStatus) !=
327519397407SSherry Moore 		    SSTATUS_DET_DEVPRESENT_PHYONLINE);
327666f9d5cbSmlf 
3277e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
327819397407SSherry Moore 		    "si_enumerate_port_multiplier: "
327919397407SSherry Moore 		    "loop count: %d, SStatus: 0x%x",
328019397407SSherry Moore 		    loop_count,
328119397407SSherry Moore 		    SStatus);
328266f9d5cbSmlf 
328366f9d5cbSmlf 		if ((SSTATUS_GET_IPM(SStatus) ==
328419397407SSherry Moore 		    SSTATUS_IPM_INTERFACE_ACTIVE) &&
328519397407SSherry Moore 		    (SSTATUS_GET_DET(SStatus) ==
328619397407SSherry Moore 		    SSTATUS_DET_DEVPRESENT_PHYONLINE)) {
328766f9d5cbSmlf 			/* The interface is active and the device is present */
3288e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INIT, si_portp,
328919397407SSherry Moore 			    "Status: %x, device exists",
329019397407SSherry Moore 			    SStatus);
329166f9d5cbSmlf 			/*
329266f9d5cbSmlf 			 * Clear error bits in SError register (i.e. PSCR[1]
329366f9d5cbSmlf 			 * by writing back error bits.
329466f9d5cbSmlf 			 */
329566f9d5cbSmlf 			if (si_read_portmult_reg(si_ctlp, si_portp, port,
329619397407SSherry Moore 			    pmport, PSCR_REG1, &SError)) {
329766f9d5cbSmlf 				continue;
329866f9d5cbSmlf 			}
3299e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INIT, si_portp,
330019397407SSherry Moore 			    "SError bits are: %x", SError);
330166f9d5cbSmlf 			if (si_write_portmult_reg(si_ctlp, si_portp, port,
330219397407SSherry Moore 			    pmport, PSCR_REG1, SError)) {
330366f9d5cbSmlf 				continue;
330466f9d5cbSmlf 			}
330566f9d5cbSmlf 
330666f9d5cbSmlf 			/* There exists a device. */
330766f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
330866f9d5cbSmlf 			si_find_dev_signature(si_ctlp, si_portp, port, pmport);
330966f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
331066f9d5cbSmlf 		}
331166f9d5cbSmlf 	}
331266f9d5cbSmlf 
331366f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
331466f9d5cbSmlf 
331566f9d5cbSmlf 	return (SI_SUCCESS);
331666f9d5cbSmlf }
331766f9d5cbSmlf 
331866f9d5cbSmlf 
331966f9d5cbSmlf /*
332066f9d5cbSmlf  * Read a port multiplier register.
332166f9d5cbSmlf  *
332266f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
332366f9d5cbSmlf  * before calling us.
332466f9d5cbSmlf  */
332566f9d5cbSmlf static int
si_read_portmult_reg(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,int pmport,int regnum,uint32_t * regval)332666f9d5cbSmlf si_read_portmult_reg(
332766f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
332866f9d5cbSmlf 	si_port_state_t *si_portp,
332966f9d5cbSmlf 	int port,
333066f9d5cbSmlf 	int pmport,
333166f9d5cbSmlf 	int regnum,
333266f9d5cbSmlf 	uint32_t *regval)
333366f9d5cbSmlf {
333466f9d5cbSmlf 	int slot;
333566f9d5cbSmlf 	si_prb_t *prb;
333666f9d5cbSmlf 	uint32_t *prb_word_ptr;
333766f9d5cbSmlf 	int i;
333866f9d5cbSmlf 	uint32_t slot_status;
333966f9d5cbSmlf 	int loop_count = 0;
334066f9d5cbSmlf 
334166f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
334266f9d5cbSmlf 
3343e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp, "si_read_portmult_reg: port: %x,"
334419397407SSherry Moore 	    "pmport: %x, regnum: %x",
334519397407SSherry Moore 	    port, pmport, regnum);
334666f9d5cbSmlf 
334766f9d5cbSmlf 	slot = si_claim_free_slot(si_ctlp, si_portp, port);
3348ab0d082fSMark Logan 	if (slot == SI_FAILURE) {
334966f9d5cbSmlf 		return (SI_FAILURE);
335066f9d5cbSmlf 	}
335166f9d5cbSmlf 
335266f9d5cbSmlf 	prb =  &(si_portp->siport_prbpool[slot]);
335366f9d5cbSmlf 	bzero((void *)prb, sizeof (si_prb_t));
335466f9d5cbSmlf 
335566f9d5cbSmlf 	/* Now fill the prb. */
335666f9d5cbSmlf 	SET_FIS_TYPE(prb->prb_fis, REGISTER_FIS_H2D);
335766f9d5cbSmlf 	SET_FIS_PMP(prb->prb_fis, PORTMULT_CONTROL_PORT);
335866f9d5cbSmlf 	SET_FIS_CDMDEVCTL(prb->prb_fis, 1);
335966f9d5cbSmlf 	SET_FIS_COMMAND(prb->prb_fis, SATAC_READ_PM_REG);
336066f9d5cbSmlf 
336166f9d5cbSmlf 	SET_FIS_DEV_HEAD(prb->prb_fis, pmport);
336266f9d5cbSmlf 	SET_FIS_FEATURES(prb->prb_fis, regnum);
336366f9d5cbSmlf 
336466f9d5cbSmlf 	/* no real data transfer is involved. */
336566f9d5cbSmlf 	SET_SGE_TRM(prb->prb_sge0);
336666f9d5cbSmlf 
336766f9d5cbSmlf #if SI_DEBUG
336866f9d5cbSmlf 	if (si_debug_flags & SIDBG_DUMP_PRB) {
336966f9d5cbSmlf 		int *ptr;
337066f9d5cbSmlf 		int j;
337166f9d5cbSmlf 
33720cfc6e4aSxun ni - Sun Microsystems - Beijing China 		ptr = (int *)(void *)prb;
337366f9d5cbSmlf 		cmn_err(CE_WARN, "read_port_mult_reg, prb: ");
337466f9d5cbSmlf 		for (j = 0; j < (sizeof (si_prb_t)/4); j++) {
337566f9d5cbSmlf 			cmn_err(CE_WARN, "%x ", ptr[j]);
337666f9d5cbSmlf 		}
337766f9d5cbSmlf 
337866f9d5cbSmlf 	}
337966f9d5cbSmlf #endif /* SI_DEBUG */
338066f9d5cbSmlf 
338166f9d5cbSmlf 	/* Deliver PRB */
338266f9d5cbSmlf 	POST_PRB_ADDR(si_ctlp, si_portp, port, slot);
338366f9d5cbSmlf 
338466f9d5cbSmlf 	/* Loop till the command is finished. */
338566f9d5cbSmlf 	do {
338666f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
338719397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
338866f9d5cbSmlf 
3389e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
339019397407SSherry Moore 		    "looping read_pm slot_status: 0x%x",
339119397407SSherry Moore 		    slot_status);
339266f9d5cbSmlf 
339366f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_SLOTSTATUS) {
339466f9d5cbSmlf 			/* We are effectively timing out after 0.5 sec. */
339566f9d5cbSmlf 			break;
339666f9d5cbSmlf 		}
339766f9d5cbSmlf 
339866f9d5cbSmlf 		/* Wait for 10 millisec */
339966f9d5cbSmlf #ifndef __lock_lint
340066f9d5cbSmlf 		delay(SI_10MS_TICKS);
340166f9d5cbSmlf #endif /* __lock_lint */
340266f9d5cbSmlf 
340366f9d5cbSmlf 	} while (slot_status & SI_SLOT_MASK & (0x1 << slot));
340466f9d5cbSmlf 
3405e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
340619397407SSherry Moore 	    "read_portmult_reg: loop count: %d",
340719397407SSherry Moore 	    loop_count);
340866f9d5cbSmlf 
340966f9d5cbSmlf 	CLEAR_BIT(si_portp->siport_pending_tags, slot);
341066f9d5cbSmlf 
341166f9d5cbSmlf 	/* Now inspect the port LRAM for the modified FIS. */
34120cfc6e4aSxun ni - Sun Microsystems - Beijing China 	prb_word_ptr = (uint32_t *)(void *)prb;
341366f9d5cbSmlf 	for (i = 0; i < (sizeof (si_prb_t)/4); i++) {
341466f9d5cbSmlf 		prb_word_ptr[i] = ddi_get32(si_ctlp->sictl_port_acc_handle,
341519397407SSherry Moore 		    (uint32_t *)(PORT_LRAM(si_ctlp, port, slot)+i*4));
341666f9d5cbSmlf 	}
341766f9d5cbSmlf 
3418ab0d082fSMark Logan 	if (si_check_ctl_handles(si_ctlp) != DDI_SUCCESS ||
3419ab0d082fSMark Logan 	    si_check_port_handles(si_portp) != DDI_SUCCESS) {
3420ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3421ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
3422ab0d082fSMark Logan 		return (SI_FAILURE);
3423ab0d082fSMark Logan 	}
3424ab0d082fSMark Logan 
342566f9d5cbSmlf 	if (((GET_FIS_COMMAND(prb->prb_fis) & 0x1) != 0) ||
342666f9d5cbSmlf 	    (GET_FIS_FEATURES(prb->prb_fis) != 0)) {
342766f9d5cbSmlf 		/* command failed. */
342866f9d5cbSmlf 		return (SI_FAILURE);
342966f9d5cbSmlf 	}
343066f9d5cbSmlf 
343166f9d5cbSmlf 	/* command succeeded. */
343266f9d5cbSmlf 	*regval = (GET_FIS_SECTOR_COUNT(prb->prb_fis) & 0xff) |
343319397407SSherry Moore 	    ((GET_FIS_SECTOR(prb->prb_fis) << 8)  & 0xff00) |
343419397407SSherry Moore 	    ((GET_FIS_CYL_LOW(prb->prb_fis) << 16)  & 0xff0000) |
343519397407SSherry Moore 	    ((GET_FIS_CYL_HI(prb->prb_fis) << 24)  & 0xff000000);
343666f9d5cbSmlf 
343766f9d5cbSmlf 	return (SI_SUCCESS);
343866f9d5cbSmlf }
343966f9d5cbSmlf 
344066f9d5cbSmlf /*
344166f9d5cbSmlf  * Write a port multiplier register.
344266f9d5cbSmlf  *
344366f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
344466f9d5cbSmlf  * before calling us.
344566f9d5cbSmlf  */
344666f9d5cbSmlf static int
si_write_portmult_reg(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,int pmport,int regnum,uint32_t regval)344766f9d5cbSmlf si_write_portmult_reg(
344866f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
344966f9d5cbSmlf 	si_port_state_t *si_portp,
345066f9d5cbSmlf 	int port,
345166f9d5cbSmlf 	int pmport,
345266f9d5cbSmlf 	int regnum,
345366f9d5cbSmlf 	uint32_t regval)
345466f9d5cbSmlf {
345566f9d5cbSmlf 	int slot;
345666f9d5cbSmlf 	si_prb_t *prb;
345766f9d5cbSmlf 	uint32_t *prb_word_ptr;
345866f9d5cbSmlf 	uint32_t slot_status;
345966f9d5cbSmlf 	int i;
346066f9d5cbSmlf 	int loop_count = 0;
346166f9d5cbSmlf 
346266f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
346366f9d5cbSmlf 
3464e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ENTRY, si_portp,
346519397407SSherry Moore 	    "si_write_portmult_reg: port: %x, pmport: %x,"
346619397407SSherry Moore 	    "regnum: %x, regval: %x",
346719397407SSherry Moore 	    port, pmport, regnum, regval);
346866f9d5cbSmlf 
346966f9d5cbSmlf 	slot = si_claim_free_slot(si_ctlp, si_portp, port);
3470ab0d082fSMark Logan 	if (slot == SI_FAILURE) {
347166f9d5cbSmlf 		return (SI_FAILURE);
347266f9d5cbSmlf 	}
347366f9d5cbSmlf 
347466f9d5cbSmlf 	prb =  &(si_portp->siport_prbpool[slot]);
347566f9d5cbSmlf 	bzero((void *)prb, sizeof (si_prb_t));
347666f9d5cbSmlf 
347766f9d5cbSmlf 	/* Now fill the prb. */
347866f9d5cbSmlf 	SET_FIS_TYPE(prb->prb_fis, REGISTER_FIS_H2D);
347966f9d5cbSmlf 	SET_FIS_PMP(prb->prb_fis, PORTMULT_CONTROL_PORT);
348066f9d5cbSmlf 	SET_FIS_CDMDEVCTL(prb->prb_fis, 1);
348166f9d5cbSmlf 
348266f9d5cbSmlf 	SET_FIS_COMMAND(prb->prb_fis, SATAC_WRITE_PM_REG);
348366f9d5cbSmlf 	SET_FIS_DEV_HEAD(prb->prb_fis, pmport);
348466f9d5cbSmlf 	SET_FIS_FEATURES(prb->prb_fis, regnum);
348566f9d5cbSmlf 
348666f9d5cbSmlf 	SET_FIS_SECTOR_COUNT(prb->prb_fis, regval & 0xff);
348766f9d5cbSmlf 	SET_FIS_SECTOR(prb->prb_fis, (regval >> 8) & 0xff);
348866f9d5cbSmlf 	SET_FIS_CYL_LOW(prb->prb_fis, (regval >> 16) & 0xff);
348966f9d5cbSmlf 	SET_FIS_CYL_HI(prb->prb_fis, (regval >> 24)  & 0xff);
349066f9d5cbSmlf 
349166f9d5cbSmlf 	/* no real data transfer is involved. */
349266f9d5cbSmlf 	SET_SGE_TRM(prb->prb_sge0);
349366f9d5cbSmlf 
349466f9d5cbSmlf #if SI_DEBUG
349566f9d5cbSmlf 	if (si_debug_flags & SIDBG_DUMP_PRB) {
349666f9d5cbSmlf 		int *ptr;
349766f9d5cbSmlf 		int j;
349866f9d5cbSmlf 
34990cfc6e4aSxun ni - Sun Microsystems - Beijing China 		ptr = (int *)(void *)prb;
350066f9d5cbSmlf 		cmn_err(CE_WARN, "read_port_mult_reg, prb: ");
350166f9d5cbSmlf 		for (j = 0; j < (sizeof (si_prb_t)/4); j++) {
350266f9d5cbSmlf 			cmn_err(CE_WARN, "%x ", ptr[j]);
350366f9d5cbSmlf 		}
350466f9d5cbSmlf 
350566f9d5cbSmlf 	}
350666f9d5cbSmlf #endif /* SI_DEBUG */
350766f9d5cbSmlf 
350866f9d5cbSmlf 	/* Deliver PRB */
350966f9d5cbSmlf 	POST_PRB_ADDR(si_ctlp, si_portp, port, slot);
351066f9d5cbSmlf 
351166f9d5cbSmlf 	/* Loop till the command is finished. */
351266f9d5cbSmlf 	do {
351366f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
351419397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
351566f9d5cbSmlf 
3516e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
351719397407SSherry Moore 		    "looping write_pmp slot_status: 0x%x",
351819397407SSherry Moore 		    slot_status);
351966f9d5cbSmlf 
352066f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_SLOTSTATUS) {
352166f9d5cbSmlf 			/* We are effectively timing out after 0.5 sec. */
352266f9d5cbSmlf 			break;
352366f9d5cbSmlf 		}
352466f9d5cbSmlf 
352566f9d5cbSmlf 		/* Wait for 10 millisec */
352666f9d5cbSmlf #ifndef __lock_lint
352766f9d5cbSmlf 		delay(SI_10MS_TICKS);
352866f9d5cbSmlf #endif /* __lock_lint */
352966f9d5cbSmlf 
353066f9d5cbSmlf 	} while (slot_status & SI_SLOT_MASK & (0x1 << slot));
353166f9d5cbSmlf 
3532e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
353319397407SSherry Moore 	    "write_portmult_reg: loop count: %d",
353419397407SSherry Moore 	    loop_count);
353566f9d5cbSmlf 
353666f9d5cbSmlf 	CLEAR_BIT(si_portp->siport_pending_tags, slot);
353766f9d5cbSmlf 
353866f9d5cbSmlf 	/* Now inspect the port LRAM for the modified FIS. */
35390cfc6e4aSxun ni - Sun Microsystems - Beijing China 	prb_word_ptr = (uint32_t *)(void *)prb;
354066f9d5cbSmlf 	for (i = 0; i < (sizeof (si_prb_t)/4); i++) {
354166f9d5cbSmlf 		prb_word_ptr[i] = ddi_get32(si_ctlp->sictl_port_acc_handle,
354219397407SSherry Moore 		    (uint32_t *)(PORT_LRAM(si_ctlp, port, slot)+i*4));
354366f9d5cbSmlf 	}
354466f9d5cbSmlf 
3545ab0d082fSMark Logan 	if (si_check_ctl_handles(si_ctlp) != DDI_SUCCESS ||
3546ab0d082fSMark Logan 	    si_check_port_handles(si_portp) != DDI_SUCCESS) {
3547ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3548ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
3549ab0d082fSMark Logan 		return (SI_FAILURE);
3550ab0d082fSMark Logan 	}
3551ab0d082fSMark Logan 
355266f9d5cbSmlf 	if (((GET_FIS_COMMAND(prb->prb_fis) & 0x1) != 0) ||
355366f9d5cbSmlf 	    (GET_FIS_FEATURES(prb->prb_fis) != 0)) {
355466f9d5cbSmlf 		/* command failed */
355566f9d5cbSmlf 		return (SI_FAILURE);
355666f9d5cbSmlf 	}
355766f9d5cbSmlf 
355866f9d5cbSmlf 	/* command succeeded */
355966f9d5cbSmlf 	return (SI_SUCCESS);
356066f9d5cbSmlf }
356166f9d5cbSmlf 
356266f9d5cbSmlf 
356366f9d5cbSmlf /*
356466f9d5cbSmlf  * Set the auto sense data for ATAPI devices.
356566f9d5cbSmlf  *
356666f9d5cbSmlf  * Note: Currently the sense data is simulated; this code will be enhanced
356766f9d5cbSmlf  * in second phase to fetch the real sense data from the atapi device.
356866f9d5cbSmlf  */
356966f9d5cbSmlf static void
si_set_sense_data(sata_pkt_t * satapkt,int reason)357066f9d5cbSmlf si_set_sense_data(sata_pkt_t *satapkt, int reason)
357166f9d5cbSmlf {
357266f9d5cbSmlf 	struct scsi_extended_sense *sense;
357366f9d5cbSmlf 
357466f9d5cbSmlf 	sense = (struct scsi_extended_sense *)
357519397407SSherry Moore 	    satapkt->satapkt_cmd.satacmd_rqsense;
357666f9d5cbSmlf 	bzero(sense, sizeof (struct scsi_extended_sense));
357766f9d5cbSmlf 	sense->es_valid = 1;		/* Valid sense */
357866f9d5cbSmlf 	sense->es_class = 7;		/* Response code 0x70 - current err */
357966f9d5cbSmlf 	sense->es_key = 0;
358066f9d5cbSmlf 	sense->es_info_1 = 0;
358166f9d5cbSmlf 	sense->es_info_2 = 0;
358266f9d5cbSmlf 	sense->es_info_3 = 0;
358366f9d5cbSmlf 	sense->es_info_4 = 0;
358466f9d5cbSmlf 	sense->es_add_len = 6;		/* Additional length */
358566f9d5cbSmlf 	sense->es_cmd_info[0] = 0;
358666f9d5cbSmlf 	sense->es_cmd_info[1] = 0;
358766f9d5cbSmlf 	sense->es_cmd_info[2] = 0;
358866f9d5cbSmlf 	sense->es_cmd_info[3] = 0;
358966f9d5cbSmlf 	sense->es_add_code = 0;
359066f9d5cbSmlf 	sense->es_qual_code = 0;
359166f9d5cbSmlf 
359266f9d5cbSmlf 	if ((reason == SATA_PKT_DEV_ERROR) || (reason == SATA_PKT_TIMEOUT)) {
359366f9d5cbSmlf 		sense->es_key = KEY_HARDWARE_ERROR;
359466f9d5cbSmlf 	}
359566f9d5cbSmlf }
359666f9d5cbSmlf 
359766f9d5cbSmlf 
359866f9d5cbSmlf /*
359966f9d5cbSmlf  * Interrupt service handler. We loop through each of the ports to find
360066f9d5cbSmlf  * if the interrupt belongs to any of them.
360166f9d5cbSmlf  *
360266f9d5cbSmlf  * Bulk of the interrupt handling is actually done out of subroutines
360366f9d5cbSmlf  * like si_intr_command_complete() etc.
360466f9d5cbSmlf  */
360566f9d5cbSmlf /*ARGSUSED*/
360666f9d5cbSmlf static uint_t
si_intr(caddr_t arg1,caddr_t arg2)360766f9d5cbSmlf si_intr(caddr_t arg1, caddr_t arg2)
360866f9d5cbSmlf {
36090cfc6e4aSxun ni - Sun Microsystems - Beijing China 	si_ctl_state_t *si_ctlp = (si_ctl_state_t *)(void *)arg1;
361066f9d5cbSmlf 	si_port_state_t *si_portp;
361166f9d5cbSmlf 	uint32_t global_intr_status;
361266f9d5cbSmlf 	uint32_t mask, port_intr_status;
361366f9d5cbSmlf 	int port;
361466f9d5cbSmlf 
361566f9d5cbSmlf 	global_intr_status = ddi_get32(si_ctlp->sictl_global_acc_handle,
361619397407SSherry Moore 	    (uint32_t *)GLOBAL_INTERRUPT_STATUS(si_ctlp));
361766f9d5cbSmlf 
3618e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INTR, si_ctlp,
361919397407SSherry Moore 	    "si_intr: global_int_status: 0x%x",
362019397407SSherry Moore 	    global_intr_status);
362166f9d5cbSmlf 
3622ab0d082fSMark Logan 	if (si_check_acc_handle(si_ctlp->sictl_global_acc_handle) !=
3623ab0d082fSMark Logan 	    DDI_SUCCESS) {
3624ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3625ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
3626ab0d082fSMark Logan 		return (DDI_INTR_UNCLAIMED);
3627ab0d082fSMark Logan 	}
3628ab0d082fSMark Logan 
362966f9d5cbSmlf 	if (!(global_intr_status & SI31xx_INTR_PORT_MASK)) {
363066f9d5cbSmlf 		/* Sorry, the interrupt is not ours. */
363166f9d5cbSmlf 		return (DDI_INTR_UNCLAIMED);
363266f9d5cbSmlf 	}
363366f9d5cbSmlf 
363466f9d5cbSmlf 	/* Loop for all the ports. */
363566f9d5cbSmlf 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
363666f9d5cbSmlf 
363766f9d5cbSmlf 		mask = 0x1 << port;
363866f9d5cbSmlf 		if (!(global_intr_status & mask)) {
363966f9d5cbSmlf 			continue;
364066f9d5cbSmlf 		}
364166f9d5cbSmlf 
364266f9d5cbSmlf 		mutex_enter(&si_ctlp->sictl_mutex);
364366f9d5cbSmlf 		si_portp = si_ctlp->sictl_ports[port];
364466f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
364566f9d5cbSmlf 
364666f9d5cbSmlf 		port_intr_status = ddi_get32(si_ctlp->sictl_global_acc_handle,
364719397407SSherry Moore 		    (uint32_t *)PORT_INTERRUPT_STATUS(si_ctlp, port));
364866f9d5cbSmlf 
3649e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
365019397407SSherry Moore 		    "s_intr: port_intr_status: 0x%x, port: %x",
365119397407SSherry Moore 		    port_intr_status,
365219397407SSherry Moore 		    port);
365366f9d5cbSmlf 
365466f9d5cbSmlf 		if (port_intr_status & INTR_COMMAND_COMPLETE) {
365566f9d5cbSmlf 			(void) si_intr_command_complete(si_ctlp, si_portp,
365619397407SSherry Moore 			    port);
3657ab0d082fSMark Logan 
3658ab0d082fSMark Logan 			mutex_enter(&si_portp->siport_mutex);
3659ab0d082fSMark Logan 			if (si_check_ctl_handles(si_ctlp) != DDI_SUCCESS ||
3660ab0d082fSMark Logan 			    si_check_port_handles(si_portp) != DDI_SUCCESS) {
3661ab0d082fSMark Logan 				ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3662ab0d082fSMark Logan 				    DDI_SERVICE_UNAFFECTED);
3663832d3fc2SMark Logan 				si_schedule_port_initialize(si_ctlp, si_portp,
3664832d3fc2SMark Logan 				    port);
3665ab0d082fSMark Logan 			}
3666832d3fc2SMark Logan 			mutex_exit(&si_portp->siport_mutex);
36670b0c3d30Sjohansen 		} else {
36680b0c3d30Sjohansen 			/* Clear the interrupts */
36690b0c3d30Sjohansen 			ddi_put32(si_ctlp->sictl_port_acc_handle,
36700b0c3d30Sjohansen 			    (uint32_t *)(PORT_INTERRUPT_STATUS(si_ctlp, port)),
36710b0c3d30Sjohansen 			    port_intr_status & INTR_MASK);
367266f9d5cbSmlf 		}
367366f9d5cbSmlf 
367466f9d5cbSmlf 		/*
367566f9d5cbSmlf 		 * Note that we did not clear the interrupt for command
367666f9d5cbSmlf 		 * completion interrupt. Reading of slot_status takes care
367766f9d5cbSmlf 		 * of clearing the interrupt for command completion case.
367866f9d5cbSmlf 		 */
367966f9d5cbSmlf 
368066f9d5cbSmlf 		if (port_intr_status & INTR_COMMAND_ERROR) {
3681832d3fc2SMark Logan 			si_schedule_intr_command_error(si_ctlp, si_portp, port);
368266f9d5cbSmlf 		}
368366f9d5cbSmlf 
368466f9d5cbSmlf 		if (port_intr_status & INTR_PORT_READY) {
368566f9d5cbSmlf 			(void) si_intr_port_ready(si_ctlp, si_portp, port);
368666f9d5cbSmlf 		}
368766f9d5cbSmlf 
368866f9d5cbSmlf 		if (port_intr_status & INTR_POWER_CHANGE) {
368966f9d5cbSmlf 			(void) si_intr_pwr_change(si_ctlp, si_portp, port);
369066f9d5cbSmlf 		}
369166f9d5cbSmlf 
369266f9d5cbSmlf 		if (port_intr_status & INTR_PHYRDY_CHANGE) {
369366f9d5cbSmlf 			(void) si_intr_phy_ready_change(si_ctlp, si_portp,
369419397407SSherry Moore 			    port);
369566f9d5cbSmlf 		}
369666f9d5cbSmlf 
369766f9d5cbSmlf 		if (port_intr_status & INTR_COMWAKE_RECEIVED) {
369866f9d5cbSmlf 			(void) si_intr_comwake_rcvd(si_ctlp, si_portp,
369919397407SSherry Moore 			    port);
370066f9d5cbSmlf 		}
370166f9d5cbSmlf 
370266f9d5cbSmlf 		if (port_intr_status & INTR_UNRECOG_FIS) {
370366f9d5cbSmlf 			(void) si_intr_unrecognised_fis(si_ctlp, si_portp,
370419397407SSherry Moore 			    port);
370566f9d5cbSmlf 		}
370666f9d5cbSmlf 
370766f9d5cbSmlf 		if (port_intr_status & INTR_DEV_XCHANGED) {
370866f9d5cbSmlf 			(void) si_intr_dev_xchanged(si_ctlp, si_portp, port);
370966f9d5cbSmlf 		}
371066f9d5cbSmlf 
371166f9d5cbSmlf 		if (port_intr_status & INTR_8B10B_DECODE_ERROR) {
371266f9d5cbSmlf 			(void) si_intr_decode_err_threshold(si_ctlp, si_portp,
371319397407SSherry Moore 			    port);
371466f9d5cbSmlf 		}
371566f9d5cbSmlf 
371666f9d5cbSmlf 		if (port_intr_status & INTR_CRC_ERROR) {
371766f9d5cbSmlf 			(void) si_intr_crc_err_threshold(si_ctlp, si_portp,
371819397407SSherry Moore 			    port);
371966f9d5cbSmlf 		}
372066f9d5cbSmlf 
372166f9d5cbSmlf 		if (port_intr_status & INTR_HANDSHAKE_ERROR) {
372266f9d5cbSmlf 			(void) si_intr_handshake_err_threshold(si_ctlp,
372319397407SSherry Moore 			    si_portp, port);
372466f9d5cbSmlf 		}
372566f9d5cbSmlf 
372666f9d5cbSmlf 		if (port_intr_status & INTR_SETDEVBITS_NOTIFY) {
372766f9d5cbSmlf 			(void) si_intr_set_devbits_notify(si_ctlp, si_portp,
372819397407SSherry Moore 			    port);
372966f9d5cbSmlf 		}
373066f9d5cbSmlf 	}
373166f9d5cbSmlf 
373266f9d5cbSmlf 	return (DDI_INTR_CLAIMED);
373366f9d5cbSmlf }
373466f9d5cbSmlf 
373566f9d5cbSmlf /*
373666f9d5cbSmlf  * Interrupt which indicates that one or more commands have successfully
373766f9d5cbSmlf  * completed.
373866f9d5cbSmlf  *
373966f9d5cbSmlf  * Since we disabled W1C (write-one-to-clear) previously, mere reading
374066f9d5cbSmlf  * of slot_status register clears the interrupt. There is no need to
374166f9d5cbSmlf  * explicitly clear the interrupt.
374266f9d5cbSmlf  */
374366f9d5cbSmlf static int
si_intr_command_complete(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)374466f9d5cbSmlf si_intr_command_complete(
374566f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
374666f9d5cbSmlf 	si_port_state_t *si_portp,
374766f9d5cbSmlf 	int port)
374866f9d5cbSmlf {
374966f9d5cbSmlf 
375066f9d5cbSmlf 	uint32_t slot_status;
375166f9d5cbSmlf 	uint32_t finished_tags;
375266f9d5cbSmlf 	int finished_slot;
375366f9d5cbSmlf 	sata_pkt_t *satapkt;
375466f9d5cbSmlf 
3755e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
3756e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_command_complete enter", NULL);
375766f9d5cbSmlf 
375866f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
375966f9d5cbSmlf 
376066f9d5cbSmlf 	slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
376119397407SSherry Moore 	    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
376266f9d5cbSmlf 
376366f9d5cbSmlf 	if (!si_portp->siport_pending_tags) {
376466f9d5cbSmlf 		/*
376566f9d5cbSmlf 		 * Spurious interrupt. Nothing to be done.
37660b0c3d30Sjohansen 		 * The interrupt was cleared when slot_status was read.
376766f9d5cbSmlf 		 */
376866f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
376966f9d5cbSmlf 		return (SI_SUCCESS);
377066f9d5cbSmlf 	}
377166f9d5cbSmlf 
3772e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_VERBOSE, si_portp, "si3124: si_intr_command_complete: "
377319397407SSherry Moore 	    "pending_tags: %x, slot_status: %x",
377419397407SSherry Moore 	    si_portp->siport_pending_tags,
377519397407SSherry Moore 	    slot_status);
377666f9d5cbSmlf 
377766f9d5cbSmlf 	finished_tags =  si_portp->siport_pending_tags &
377819397407SSherry Moore 	    ~slot_status & SI_SLOT_MASK;
377966f9d5cbSmlf 	while (finished_tags) {
3780c03acfcaSls 
378166f9d5cbSmlf 		finished_slot = ddi_ffs(finished_tags) - 1;
378266f9d5cbSmlf 		if (finished_slot == -1) {
378366f9d5cbSmlf 			break;
378466f9d5cbSmlf 		}
378566f9d5cbSmlf 
378666f9d5cbSmlf 		satapkt = si_portp->siport_slot_pkts[finished_slot];
3787c03acfcaSls 
3788a599d311SMartin Faltesek 		if (satapkt->satapkt_cmd.satacmd_flags.sata_special_regs) {
3789a599d311SMartin Faltesek 			si_copy_out_regs(&satapkt->satapkt_cmd, si_ctlp, port,
3790a599d311SMartin Faltesek 			    finished_slot);
3791a599d311SMartin Faltesek 		}
379266f9d5cbSmlf 
379366f9d5cbSmlf 		CLEAR_BIT(si_portp->siport_pending_tags, finished_slot);
379466f9d5cbSmlf 		CLEAR_BIT(finished_tags, finished_slot);
3795a3f55fb1Sxun ni - Sun Microsystems - Beijing China 		SENDUP_PACKET(si_portp, satapkt, SATA_PKT_COMPLETED);
379666f9d5cbSmlf 	}
379766f9d5cbSmlf 
3798e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_PKTCOMP, si_portp,
379919397407SSherry Moore 	    "command_complete done: pend_tags: 0x%x, slot_status: 0x%x",
380019397407SSherry Moore 	    si_portp->siport_pending_tags,
380119397407SSherry Moore 	    slot_status);
380266f9d5cbSmlf 
380366f9d5cbSmlf 	/*
380466f9d5cbSmlf 	 * tidbit: no need to clear the interrupt since reading of
380566f9d5cbSmlf 	 * slot_status automatically clears the interrupt in the case
380666f9d5cbSmlf 	 * of a successful command completion.
380766f9d5cbSmlf 	 */
380866f9d5cbSmlf 
380966f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
381066f9d5cbSmlf 
381166f9d5cbSmlf 	return (SI_SUCCESS);
381266f9d5cbSmlf }
381366f9d5cbSmlf 
3814832d3fc2SMark Logan /*
3815832d3fc2SMark Logan  * Schedule a call to si_intr_command_error using a timeout to get it done
3816832d3fc2SMark Logan  * off the interrupt thread.
3817832d3fc2SMark Logan  */
3818832d3fc2SMark Logan static void
si_schedule_intr_command_error(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)3819832d3fc2SMark Logan si_schedule_intr_command_error(
3820832d3fc2SMark Logan 	si_ctl_state_t *si_ctlp,
3821832d3fc2SMark Logan 	si_port_state_t *si_portp,
3822832d3fc2SMark Logan 	int port)
3823832d3fc2SMark Logan {
3824832d3fc2SMark Logan 	si_event_arg_t *args;
3825832d3fc2SMark Logan 
3826832d3fc2SMark Logan 	mutex_enter(&si_portp->siport_mutex);
3827832d3fc2SMark Logan 
3828832d3fc2SMark Logan 	args = si_portp->siport_event_args;
3829832d3fc2SMark Logan 	if (args->siea_ctlp != NULL) {
3830832d3fc2SMark Logan 		cmn_err(CE_WARN, "si_schedule_intr_command_error: "
3831832d3fc2SMark Logan 		    "args->si_ctlp != NULL");
3832832d3fc2SMark Logan 		mutex_exit(&si_portp->siport_mutex);
3833832d3fc2SMark Logan 		return;
3834832d3fc2SMark Logan 	}
3835832d3fc2SMark Logan 
3836832d3fc2SMark Logan 	args->siea_ctlp = si_ctlp;
3837832d3fc2SMark Logan 	args->siea_port = port;
3838832d3fc2SMark Logan 
38396d0510caSMark Logan 	(void) timeout(si_do_intr_command_error, si_portp, 1);
3840832d3fc2SMark Logan 
3841832d3fc2SMark Logan 	mutex_exit(&si_portp->siport_mutex);
3842832d3fc2SMark Logan }
3843832d3fc2SMark Logan 
3844832d3fc2SMark Logan /*
3845832d3fc2SMark Logan  * Called from timeout()
3846832d3fc2SMark Logan  * Unpack the arguments and call si_intr_command_error()
3847832d3fc2SMark Logan  */
3848832d3fc2SMark Logan static void
si_do_intr_command_error(void * arg)3849832d3fc2SMark Logan si_do_intr_command_error(void *arg)
3850832d3fc2SMark Logan {
3851832d3fc2SMark Logan 	si_event_arg_t *args;
3852832d3fc2SMark Logan 	si_ctl_state_t *si_ctlp;
3853832d3fc2SMark Logan 	si_port_state_t *si_portp;
3854832d3fc2SMark Logan 	int port;
3855832d3fc2SMark Logan 
38566d0510caSMark Logan 	si_portp = arg;
38576d0510caSMark Logan 	mutex_enter(&si_portp->siport_mutex);
38586d0510caSMark Logan 
38596d0510caSMark Logan 	args = si_portp->siport_event_args;
3860832d3fc2SMark Logan 	si_ctlp = args->siea_ctlp;
3861832d3fc2SMark Logan 	port = args->siea_port;
3862832d3fc2SMark Logan 	args->siea_ctlp = NULL;	/* mark siport_event_args as free */
38636d0510caSMark Logan 
3864832d3fc2SMark Logan 	mutex_exit(&si_portp->siport_mutex);
3865832d3fc2SMark Logan 	(void) si_intr_command_error(si_ctlp, si_portp, port);
3866832d3fc2SMark Logan }
3867832d3fc2SMark Logan 
386866f9d5cbSmlf /*
386966f9d5cbSmlf  * Interrupt which indicates that a command did not complete successfully.
387066f9d5cbSmlf  *
387166f9d5cbSmlf  * The port halts whenever a command error interrupt is received.
387266f9d5cbSmlf  * The only way to restart it is to reset or reinitialize the port
387366f9d5cbSmlf  * but such an operation throws away all the pending commands on
387466f9d5cbSmlf  * the port.
387566f9d5cbSmlf  *
387666f9d5cbSmlf  * We reset the device and mop the commands on the port.
387766f9d5cbSmlf  */
387866f9d5cbSmlf static int
si_intr_command_error(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)387966f9d5cbSmlf si_intr_command_error(
388066f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
388166f9d5cbSmlf 	si_port_state_t *si_portp,
388266f9d5cbSmlf 	int port)
388366f9d5cbSmlf {
388466f9d5cbSmlf 	uint32_t command_error, slot_status;
388566f9d5cbSmlf 	uint32_t failed_tags;
388666f9d5cbSmlf 
388766f9d5cbSmlf 	command_error = ddi_get32(si_ctlp->sictl_port_acc_handle,
388819397407SSherry Moore 	    (uint32_t *)(PORT_COMMAND_ERROR(si_ctlp, port)));
388966f9d5cbSmlf 
3890e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
389119397407SSherry Moore 	    "si_intr_command_error: command_error: 0x%x",
389219397407SSherry Moore 	    command_error);
389366f9d5cbSmlf 
389466f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
389566f9d5cbSmlf 
389666f9d5cbSmlf 	/*
389766f9d5cbSmlf 	 * Remember the slot_status since any of the recovery handler
389866f9d5cbSmlf 	 * can blow it away with reset operation.
389966f9d5cbSmlf 	 */
390066f9d5cbSmlf 	slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
390119397407SSherry Moore 	    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
390266f9d5cbSmlf 
390366f9d5cbSmlf 	si_log_error_message(si_ctlp, port, command_error);
390466f9d5cbSmlf 
390566f9d5cbSmlf 	switch (command_error) {
390666f9d5cbSmlf 
390766f9d5cbSmlf 	case CMD_ERR_DEVICEERRROR:
390866f9d5cbSmlf 		si_error_recovery_DEVICEERROR(si_ctlp, si_portp, port);
390966f9d5cbSmlf 		break;
391066f9d5cbSmlf 
391166f9d5cbSmlf 	case CMD_ERR_SDBERROR:
3912ab0d082fSMark Logan 		si_fm_ereport(si_ctlp, DDI_FM_DEVICE_INTERN_CORR, "SBD error");
391366f9d5cbSmlf 		si_error_recovery_SDBERROR(si_ctlp, si_portp, port);
3914ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3915ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
391666f9d5cbSmlf 		break;
391766f9d5cbSmlf 
391866f9d5cbSmlf 	case CMD_ERR_DATAFISERROR:
3919ab0d082fSMark Logan 		si_fm_ereport(si_ctlp, DDI_FM_DEVICE_INTERN_CORR,
3920ab0d082fSMark Logan 		    "Data FIS error");
392166f9d5cbSmlf 		si_error_recovery_DATAFISERROR(si_ctlp, si_portp, port);
3922ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3923ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
392466f9d5cbSmlf 		break;
392566f9d5cbSmlf 
392666f9d5cbSmlf 	case CMD_ERR_SENDFISERROR:
3927ab0d082fSMark Logan 		si_fm_ereport(si_ctlp, DDI_FM_DEVICE_INTERN_CORR,
3928ab0d082fSMark Logan 		    "Send FIS error");
392966f9d5cbSmlf 		si_error_recovery_SENDFISERROR(si_ctlp, si_portp, port);
3930ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3931ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
393266f9d5cbSmlf 		break;
393366f9d5cbSmlf 
393466f9d5cbSmlf 	default:
3935ab0d082fSMark Logan 		si_fm_ereport(si_ctlp, DDI_FM_DEVICE_INTERN_CORR,
3936ab0d082fSMark Logan 		    "Unknown error");
393766f9d5cbSmlf 		si_error_recovery_default(si_ctlp, si_portp, port);
3938ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
3939ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
394066f9d5cbSmlf 		break;
394166f9d5cbSmlf 
394266f9d5cbSmlf 	}
394366f9d5cbSmlf 
394466f9d5cbSmlf 	/*
394566f9d5cbSmlf 	 * Compute the failed_tags by adding up the error tags.
394666f9d5cbSmlf 	 *
394766f9d5cbSmlf 	 * The siport_err_tags_SDBERROR and siport_err_tags_nonSDBERROR
394866f9d5cbSmlf 	 * were filled in by the si_error_recovery_* routines.
394966f9d5cbSmlf 	 */
395066f9d5cbSmlf 	failed_tags = si_portp->siport_pending_tags &
395119397407SSherry Moore 	    (si_portp->siport_err_tags_SDBERROR |
395219397407SSherry Moore 	    si_portp->siport_err_tags_nonSDBERROR);
395366f9d5cbSmlf 
3954e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp, "si_intr_command_error: "
395519397407SSherry Moore 	    "err_tags_SDBERROR: 0x%x, "
395619397407SSherry Moore 	    "err_tags_nonSDBERRROR: 0x%x, "
395719397407SSherry Moore 	    "failed_tags: 0x%x",
395819397407SSherry Moore 	    si_portp->siport_err_tags_SDBERROR,
395919397407SSherry Moore 	    si_portp->siport_err_tags_nonSDBERROR,
396019397407SSherry Moore 	    failed_tags);
396166f9d5cbSmlf 
3962e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
3963e57ece5bSPraveen Kumar Dasaraju Rama 	    "si3124: si_intr_command_error: "
396419397407SSherry Moore 	    "slot_status:0x%x, pending_tags: 0x%x",
396519397407SSherry Moore 	    slot_status,
396619397407SSherry Moore 	    si_portp->siport_pending_tags);
396766f9d5cbSmlf 
3968cf6ed809SMark Logan 	si_portp->mopping_in_progress++;
3969cf6ed809SMark Logan 
397066f9d5cbSmlf 	si_mop_commands(si_ctlp,
397119397407SSherry Moore 	    si_portp,
397219397407SSherry Moore 	    port,
397319397407SSherry Moore 	    slot_status,
397419397407SSherry Moore 	    failed_tags,
3975*83dba8e1SToomas Soome 	    0,	/* timedout_tags */
3976*83dba8e1SToomas Soome 	    0,	/* aborting_tags */
3977*83dba8e1SToomas Soome 	    0);	/* reset_tags */
397866f9d5cbSmlf 
397966f9d5cbSmlf 	ASSERT(si_portp->siport_pending_tags == 0);
398066f9d5cbSmlf 
398166f9d5cbSmlf 	si_portp->siport_err_tags_SDBERROR = 0;
398266f9d5cbSmlf 	si_portp->siport_err_tags_nonSDBERROR = 0;
398366f9d5cbSmlf 
398466f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
398566f9d5cbSmlf 
398666f9d5cbSmlf 	return (SI_SUCCESS);
398766f9d5cbSmlf }
398866f9d5cbSmlf 
398966f9d5cbSmlf /*
399066f9d5cbSmlf  * There is a subtle difference between errors on a normal port and
399166f9d5cbSmlf  * a port-mult port. When an error happens on a normal port, the port
399266f9d5cbSmlf  * is halted effectively until the port is reset or initialized.
399366f9d5cbSmlf  * However, in port-mult port errors, port does not get halted since
399466f9d5cbSmlf  * other non-error devices behind the port multiplier can still
399566f9d5cbSmlf  * continue to operate. So we wait till all the commands are drained
399666f9d5cbSmlf  * instead of resetting it right away.
399766f9d5cbSmlf  *
399866f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
399966f9d5cbSmlf  * before calling us.
400066f9d5cbSmlf  */
400166f9d5cbSmlf static void
si_recover_portmult_errors(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)400266f9d5cbSmlf si_recover_portmult_errors(
400366f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
400466f9d5cbSmlf 	si_port_state_t *si_portp,
400566f9d5cbSmlf 	int port)
400666f9d5cbSmlf {
400766f9d5cbSmlf 	uint32_t command_error, slot_status, port_status;
400866f9d5cbSmlf 	int failed_slot;
400966f9d5cbSmlf 	int loop_count = 0;
401066f9d5cbSmlf 
401166f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
401266f9d5cbSmlf 
4013e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
401419397407SSherry Moore 	    "si_recover_portmult_errors: port: 0x%x",
401519397407SSherry Moore 	    port);
401666f9d5cbSmlf 
401766f9d5cbSmlf 	/* Resume the port */
401866f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
401919397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
402019397407SSherry Moore 	    PORT_CONTROL_SET_BITS_RESUME);
402166f9d5cbSmlf 
402266f9d5cbSmlf 	port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
402319397407SSherry Moore 	    (uint32_t *)PORT_STATUS(si_ctlp, port));
402466f9d5cbSmlf 
402566f9d5cbSmlf 	failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
402666f9d5cbSmlf 	command_error = ddi_get32(si_ctlp->sictl_port_acc_handle,
402719397407SSherry Moore 	    (uint32_t *)(PORT_COMMAND_ERROR(si_ctlp, port)));
402866f9d5cbSmlf 
402966f9d5cbSmlf 	if (command_error ==  CMD_ERR_SDBERROR) {
403066f9d5cbSmlf 		si_portp->siport_err_tags_SDBERROR |= (0x1 << failed_slot);
403166f9d5cbSmlf 	} else {
403266f9d5cbSmlf 		si_portp->siport_err_tags_nonSDBERROR |= (0x1 << failed_slot);
403366f9d5cbSmlf 	}
403466f9d5cbSmlf 
403566f9d5cbSmlf 	/* Now we drain the pending commands. */
403666f9d5cbSmlf 	do {
403766f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
403819397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
403966f9d5cbSmlf 
404066f9d5cbSmlf 		/*
404166f9d5cbSmlf 		 * Since we have not yet returned DDI_INTR_CLAIMED,
404266f9d5cbSmlf 		 * our interrupt handler is guaranteed not to be called again.
404366f9d5cbSmlf 		 * So we need to check IS_ATTENTION_RAISED() for further
404466f9d5cbSmlf 		 * decisions.
404566f9d5cbSmlf 		 *
404666f9d5cbSmlf 		 * This is a too big a delay for an interrupt context.
404766f9d5cbSmlf 		 * But this is supposed to be a rare condition.
404866f9d5cbSmlf 		 */
404966f9d5cbSmlf 
405066f9d5cbSmlf 		if (IS_ATTENTION_RAISED(slot_status)) {
405166f9d5cbSmlf 			/* Resume again */
405266f9d5cbSmlf 			ddi_put32(si_ctlp->sictl_port_acc_handle,
405319397407SSherry Moore 			    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
405419397407SSherry Moore 			    PORT_CONTROL_SET_BITS_RESUME);
405566f9d5cbSmlf 
405666f9d5cbSmlf 			port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
405719397407SSherry Moore 			    (uint32_t *)PORT_STATUS(si_ctlp, port));
405866f9d5cbSmlf 			failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
405966f9d5cbSmlf 			command_error = ddi_get32(
406019397407SSherry Moore 			    si_ctlp->sictl_port_acc_handle,
406119397407SSherry Moore 			    (uint32_t *)(PORT_COMMAND_ERROR(si_ctlp,
406219397407SSherry Moore 			    port)));
406366f9d5cbSmlf 			if (command_error ==  CMD_ERR_SDBERROR) {
406466f9d5cbSmlf 				si_portp->siport_err_tags_SDBERROR |=
406519397407SSherry Moore 				    (0x1 << failed_slot);
406666f9d5cbSmlf 			} else {
406766f9d5cbSmlf 				si_portp->siport_err_tags_nonSDBERROR |=
406819397407SSherry Moore 				    (0x1 << failed_slot);
406966f9d5cbSmlf 			}
407066f9d5cbSmlf 		}
407166f9d5cbSmlf 
407266f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_RECOVERPORTMULT) {
407366f9d5cbSmlf 			/* We are effectively timing out after 10 sec. */
407466f9d5cbSmlf 			break;
407566f9d5cbSmlf 		}
407666f9d5cbSmlf 
407766f9d5cbSmlf 		/* Wait for 10 millisec */
407866f9d5cbSmlf #ifndef __lock_lint
407966f9d5cbSmlf 		delay(SI_10MS_TICKS);
408066f9d5cbSmlf #endif /* __lock_lint */
408166f9d5cbSmlf 
408266f9d5cbSmlf 	} while (slot_status & SI_SLOT_MASK);
408366f9d5cbSmlf 
408466f9d5cbSmlf 	/*
408566f9d5cbSmlf 	 * The above loop can be improved for 3132 since we could obtain the
408666f9d5cbSmlf 	 * Port Multiplier Context of the device in error. Then we could
408766f9d5cbSmlf 	 * do a better job in filtering out commands for the device in error.
408866f9d5cbSmlf 	 * The loop could finish much earlier with such a logic.
408966f9d5cbSmlf 	 */
409066f9d5cbSmlf 
409166f9d5cbSmlf 	/* Clear the RESUME bit. */
409266f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
409319397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
409419397407SSherry Moore 	    PORT_CONTROL_CLEAR_BITS_RESUME);
409566f9d5cbSmlf 
409666f9d5cbSmlf }
409766f9d5cbSmlf 
409866f9d5cbSmlf /*
409966f9d5cbSmlf  * If we are connected to port multiplier, drain the non-failed devices.
410066f9d5cbSmlf  * Otherwise, we initialize the port (which effectively fails all the
410166f9d5cbSmlf  * pending commands in the hope that sd would retry them later).
410266f9d5cbSmlf  *
410366f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
410466f9d5cbSmlf  * before calling us.
410566f9d5cbSmlf  */
410666f9d5cbSmlf static void
si_error_recovery_DEVICEERROR(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)410766f9d5cbSmlf si_error_recovery_DEVICEERROR(
410866f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
410966f9d5cbSmlf 	si_port_state_t *si_portp,
411066f9d5cbSmlf 	int port)
411166f9d5cbSmlf {
411266f9d5cbSmlf 	uint32_t port_status;
411366f9d5cbSmlf 	int failed_slot;
411466f9d5cbSmlf 
411566f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
411666f9d5cbSmlf 
4117e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
411819397407SSherry Moore 	    "si_error_recovery_DEVICEERROR: port: 0x%x",
411919397407SSherry Moore 	    port);
412066f9d5cbSmlf 
412166f9d5cbSmlf 	if (si_portp->siport_port_type == PORT_TYPE_MULTIPLIER) {
412266f9d5cbSmlf 		si_recover_portmult_errors(si_ctlp, si_portp, port);
412366f9d5cbSmlf 	} else {
412466f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
412519397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
412666f9d5cbSmlf 		failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
412766f9d5cbSmlf 		si_portp->siport_err_tags_nonSDBERROR |= (0x1 << failed_slot);
412866f9d5cbSmlf 	}
412966f9d5cbSmlf 
413066f9d5cbSmlf 	/* In either case (port-mult or not), we reinitialize the port. */
413166f9d5cbSmlf 	(void) si_initialize_port_wait_till_ready(si_ctlp, port);
413266f9d5cbSmlf }
413366f9d5cbSmlf 
413466f9d5cbSmlf /*
413566f9d5cbSmlf  * Handle exactly like DEVICEERROR. Remember the tags with SDBERROR
413666f9d5cbSmlf  * to perform read_log_ext on them later. SDBERROR means that the
413766f9d5cbSmlf  * error was for an NCQ command.
413866f9d5cbSmlf  *
413966f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
414066f9d5cbSmlf  * before calling us.
414166f9d5cbSmlf  */
414266f9d5cbSmlf static void
si_error_recovery_SDBERROR(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)414366f9d5cbSmlf si_error_recovery_SDBERROR(
414466f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
414566f9d5cbSmlf 	si_port_state_t *si_portp,
414666f9d5cbSmlf 	int port)
414766f9d5cbSmlf {
414866f9d5cbSmlf 	uint32_t port_status;
414966f9d5cbSmlf 	int failed_slot;
415066f9d5cbSmlf 
415166f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
415266f9d5cbSmlf 
4153e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
415419397407SSherry Moore 	    "si3124: si_error_recovery_SDBERROR: port: 0x%x",
415519397407SSherry Moore 	    port);
415666f9d5cbSmlf 
415766f9d5cbSmlf 	if (si_portp->siport_port_type == PORT_TYPE_MULTIPLIER) {
415866f9d5cbSmlf 		si_recover_portmult_errors(si_ctlp, si_portp, port);
415966f9d5cbSmlf 	} else {
416066f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
416119397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
416266f9d5cbSmlf 		failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
416366f9d5cbSmlf 		si_portp->siport_err_tags_SDBERROR |= (0x1 << failed_slot);
416466f9d5cbSmlf 	}
416566f9d5cbSmlf 
416666f9d5cbSmlf 	/* In either case (port-mult or not), we reinitialize the port. */
416766f9d5cbSmlf 	(void) si_initialize_port_wait_till_ready(si_ctlp, port);
416866f9d5cbSmlf }
416966f9d5cbSmlf 
417066f9d5cbSmlf /*
417166f9d5cbSmlf  * Handle exactly like DEVICEERROR except resetting the port if there was
417266f9d5cbSmlf  * an NCQ command on the port.
417366f9d5cbSmlf  *
417466f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
417566f9d5cbSmlf  * before calling us.
417666f9d5cbSmlf  */
417766f9d5cbSmlf static void
si_error_recovery_DATAFISERROR(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)417866f9d5cbSmlf si_error_recovery_DATAFISERROR(
417966f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
418066f9d5cbSmlf 	si_port_state_t *si_portp,
418166f9d5cbSmlf 	int port)
418266f9d5cbSmlf {
418366f9d5cbSmlf 	uint32_t port_status;
418466f9d5cbSmlf 	int failed_slot;
418566f9d5cbSmlf 
418666f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
418766f9d5cbSmlf 
4188e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
418919397407SSherry Moore 	    "si3124: si_error_recovery_DATAFISERROR: port: 0x%x",
419019397407SSherry Moore 	    port);
419166f9d5cbSmlf 
419266f9d5cbSmlf 	/* reset device if we were waiting for any ncq commands. */
419366f9d5cbSmlf 	if (si_portp->siport_pending_ncq_count) {
419466f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
419519397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
419666f9d5cbSmlf 		failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
419766f9d5cbSmlf 		si_portp->siport_err_tags_nonSDBERROR |= (0x1 << failed_slot);
419866f9d5cbSmlf 		(void) si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
419919397407SSherry Moore 		    SI_DEVICE_RESET);
420066f9d5cbSmlf 		return;
420166f9d5cbSmlf 	}
420266f9d5cbSmlf 
420366f9d5cbSmlf 	/*
420466f9d5cbSmlf 	 * If we don't have any ncq commands pending, the rest of
420566f9d5cbSmlf 	 * the process is similar to the one for DEVICEERROR.
420666f9d5cbSmlf 	 */
420766f9d5cbSmlf 	si_error_recovery_DEVICEERROR(si_ctlp, si_portp, port);
420866f9d5cbSmlf }
420966f9d5cbSmlf 
421066f9d5cbSmlf /*
421166f9d5cbSmlf  * We handle just like DEVICERROR except that we reset the device instead
421266f9d5cbSmlf  * of initializing the port.
421366f9d5cbSmlf  *
421466f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
421566f9d5cbSmlf  * before calling us.
421666f9d5cbSmlf  */
421766f9d5cbSmlf static void
si_error_recovery_SENDFISERROR(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)421866f9d5cbSmlf si_error_recovery_SENDFISERROR(
421966f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
422066f9d5cbSmlf 	si_port_state_t *si_portp,
422166f9d5cbSmlf 	int port)
422266f9d5cbSmlf {
422366f9d5cbSmlf 	uint32_t port_status;
422466f9d5cbSmlf 	int failed_slot;
422566f9d5cbSmlf 
422666f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
422766f9d5cbSmlf 
4228e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
422919397407SSherry Moore 	    "si3124: si_error_recovery_SENDFISERROR: port: 0x%x",
423019397407SSherry Moore 	    port);
423166f9d5cbSmlf 
423266f9d5cbSmlf 	if (si_portp->siport_port_type == PORT_TYPE_MULTIPLIER) {
423366f9d5cbSmlf 		si_recover_portmult_errors(si_ctlp, si_portp, port);
423466f9d5cbSmlf 	} else {
423566f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
423619397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
423766f9d5cbSmlf 		failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
423866f9d5cbSmlf 		si_portp->siport_err_tags_nonSDBERROR |= (0x1 << failed_slot);
423966f9d5cbSmlf 		(void) si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
424019397407SSherry Moore 		    SI_DEVICE_RESET);
424166f9d5cbSmlf 	}
424266f9d5cbSmlf }
424366f9d5cbSmlf 
424466f9d5cbSmlf /*
424566f9d5cbSmlf  * The default behavior for all other errors is to reset the device.
424666f9d5cbSmlf  *
424766f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
424866f9d5cbSmlf  * before calling us.
424966f9d5cbSmlf  */
425066f9d5cbSmlf static void
si_error_recovery_default(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)425166f9d5cbSmlf si_error_recovery_default(
425266f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
425366f9d5cbSmlf 	si_port_state_t *si_portp,
425466f9d5cbSmlf 	int port)
425566f9d5cbSmlf {
425666f9d5cbSmlf 	uint32_t port_status;
425766f9d5cbSmlf 	int failed_slot;
425866f9d5cbSmlf 
425966f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
426066f9d5cbSmlf 
4261e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
426219397407SSherry Moore 	    "si3124: si_error_recovery_default: port: 0x%x",
426319397407SSherry Moore 	    port);
426466f9d5cbSmlf 
426566f9d5cbSmlf 	port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
426619397407SSherry Moore 	    (uint32_t *)PORT_STATUS(si_ctlp, port));
426766f9d5cbSmlf 	failed_slot = (port_status >> 16) & SI_NUM_SLOTS;
426866f9d5cbSmlf 	si_portp->siport_err_tags_nonSDBERROR |= (0x1 << failed_slot);
426966f9d5cbSmlf 
427066f9d5cbSmlf 	(void) si_reset_dport_wait_till_ready(si_ctlp, si_portp, port,
427119397407SSherry Moore 	    SI_DEVICE_RESET);
427266f9d5cbSmlf }
427366f9d5cbSmlf 
427466f9d5cbSmlf /*
427566f9d5cbSmlf  * Read Log Ext with PAGE 10 to retrieve the error for an NCQ command.
427666f9d5cbSmlf  *
427766f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
427866f9d5cbSmlf  * before calling us.
427966f9d5cbSmlf  */
428066f9d5cbSmlf static uint8_t
si_read_log_ext(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)428166f9d5cbSmlf si_read_log_ext(si_ctl_state_t *si_ctlp, si_port_state_t *si_portp, int port)
428266f9d5cbSmlf {
428366f9d5cbSmlf 	int slot;
428466f9d5cbSmlf 	si_prb_t *prb;
428566f9d5cbSmlf 	int i;
428666f9d5cbSmlf 	uint32_t slot_status;
428766f9d5cbSmlf 	int loop_count = 0;
428866f9d5cbSmlf 	uint32_t *prb_word_ptr;
428966f9d5cbSmlf 	uint8_t error;
429066f9d5cbSmlf 
429166f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
429266f9d5cbSmlf 
4293e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
429419397407SSherry Moore 	    "si_read_log_ext: port: %x", port);
429566f9d5cbSmlf 
429666f9d5cbSmlf 	slot = si_claim_free_slot(si_ctlp, si_portp, port);
4297ab0d082fSMark Logan 	if (slot == SI_FAILURE) {
429866f9d5cbSmlf 		return (0);
429966f9d5cbSmlf 	}
430066f9d5cbSmlf 
430166f9d5cbSmlf 	prb =  &(si_portp->siport_prbpool[slot]);
430266f9d5cbSmlf 	bzero((void *)prb, sizeof (si_prb_t));
430366f9d5cbSmlf 
430466f9d5cbSmlf 	/* Now fill the prb */
430566f9d5cbSmlf 	SET_FIS_TYPE(prb->prb_fis, REGISTER_FIS_H2D);
430666f9d5cbSmlf 	SET_FIS_PMP(prb->prb_fis, PORTMULT_CONTROL_PORT);
430766f9d5cbSmlf 	SET_FIS_CDMDEVCTL(prb->prb_fis, 1);
430866f9d5cbSmlf 	SET_FIS_COMMAND(prb->prb_fis, SATAC_READ_LOG_EXT);
430966f9d5cbSmlf 	SET_FIS_SECTOR(prb->prb_fis, SATA_LOG_PAGE_10);
431066f9d5cbSmlf 
431166f9d5cbSmlf 	/* no real data transfer is involved */
431266f9d5cbSmlf 	SET_SGE_TRM(prb->prb_sge0);
431366f9d5cbSmlf 
431466f9d5cbSmlf #if SI_DEBUG
431566f9d5cbSmlf 	if (si_debug_flags & SIDBG_DUMP_PRB) {
431666f9d5cbSmlf 		int *ptr;
431766f9d5cbSmlf 		int j;
431866f9d5cbSmlf 
43190cfc6e4aSxun ni - Sun Microsystems - Beijing China 		ptr = (int *)(void *)prb;
432066f9d5cbSmlf 		cmn_err(CE_WARN, "read_port_mult_reg, prb: ");
432166f9d5cbSmlf 		for (j = 0; j < (sizeof (si_prb_t)/4); j++) {
432266f9d5cbSmlf 			cmn_err(CE_WARN, "%x ", ptr[j]);
432366f9d5cbSmlf 		}
432466f9d5cbSmlf 
432566f9d5cbSmlf 	}
432666f9d5cbSmlf #endif /* SI_DEBUG */
432766f9d5cbSmlf 
432866f9d5cbSmlf 	/* Deliver PRB */
432966f9d5cbSmlf 	POST_PRB_ADDR(si_ctlp, si_portp, port, slot);
433066f9d5cbSmlf 
433166f9d5cbSmlf 	/* Loop till the command is finished. */
433266f9d5cbSmlf 	do {
433366f9d5cbSmlf 		slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
433419397407SSherry Moore 		    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
433566f9d5cbSmlf 
4336e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_POLL_LOOP, si_portp,
433719397407SSherry Moore 		    "looping read_log_ext slot_status: 0x%x",
433819397407SSherry Moore 		    slot_status);
433966f9d5cbSmlf 
434066f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_SLOTSTATUS) {
434166f9d5cbSmlf 			/* We are effectively timing out after 0.5 sec. */
434266f9d5cbSmlf 			break;
434366f9d5cbSmlf 		}
434466f9d5cbSmlf 
434566f9d5cbSmlf 		/* Wait for 10 millisec */
434666f9d5cbSmlf #ifndef __lock_lint
434766f9d5cbSmlf 		delay(SI_10MS_TICKS);
434866f9d5cbSmlf #endif /* __lock_lint */
434966f9d5cbSmlf 
435066f9d5cbSmlf 	} while (slot_status & SI_SLOT_MASK & (0x1 << slot));
435166f9d5cbSmlf 
435266f9d5cbSmlf 	if (slot_status & SI_SLOT_MASK & (0x1 << slot)) {
435366f9d5cbSmlf 		/*
435466f9d5cbSmlf 		 * If we fail with the READ LOG EXT command, we need to
435566f9d5cbSmlf 		 * initialize the port to clear the slot_status register.
435666f9d5cbSmlf 		 * We don't need to worry about any other valid commands
435766f9d5cbSmlf 		 * being thrown away because we are already in recovery
435866f9d5cbSmlf 		 * mode and READ LOG EXT is the only pending command.
435966f9d5cbSmlf 		 */
436066f9d5cbSmlf 		(void) si_initialize_port_wait_till_ready(si_ctlp, port);
436166f9d5cbSmlf 	}
436266f9d5cbSmlf 
4363e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
436419397407SSherry Moore 	    "read_portmult_reg: loop count: %d",
436519397407SSherry Moore 	    loop_count);
436666f9d5cbSmlf 
436766f9d5cbSmlf 	/*
436866f9d5cbSmlf 	 * The LRAM contains the the modified FIS.
436966f9d5cbSmlf 	 * Read the modified FIS to obtain the Error.
437066f9d5cbSmlf 	 */
43710cfc6e4aSxun ni - Sun Microsystems - Beijing China 	prb_word_ptr = (uint32_t *)(void *)prb;
437266f9d5cbSmlf 	for (i = 0; i < (sizeof (si_prb_t)/4); i++) {
437366f9d5cbSmlf 		prb_word_ptr[i] = ddi_get32(si_ctlp->sictl_port_acc_handle,
437419397407SSherry Moore 		    (uint32_t *)(PORT_LRAM(si_ctlp, port, slot)+i*4));
437566f9d5cbSmlf 	}
4376ab0d082fSMark Logan 
4377ab0d082fSMark Logan 	if (si_check_ctl_handles(si_ctlp) != DDI_SUCCESS ||
4378ab0d082fSMark Logan 	    si_check_port_handles(si_portp) != DDI_SUCCESS) {
4379ab0d082fSMark Logan 		ddi_fm_service_impact(si_ctlp->sictl_devinfop,
4380ab0d082fSMark Logan 		    DDI_SERVICE_UNAFFECTED);
4381ab0d082fSMark Logan 	}
4382ab0d082fSMark Logan 
438366f9d5cbSmlf 	error = GET_FIS_FEATURES(prb->prb_fis);
438466f9d5cbSmlf 
438566f9d5cbSmlf 	CLEAR_BIT(si_portp->siport_pending_tags, slot);
438666f9d5cbSmlf 
438766f9d5cbSmlf 	return (error);
438866f9d5cbSmlf 
438966f9d5cbSmlf }
439066f9d5cbSmlf 
439166f9d5cbSmlf /*
439266f9d5cbSmlf  * Dump the error message to the log.
439366f9d5cbSmlf  */
439466f9d5cbSmlf static void
si_log_error_message(si_ctl_state_t * si_ctlp,int port,uint32_t command_error)439566f9d5cbSmlf si_log_error_message(si_ctl_state_t *si_ctlp, int port, uint32_t command_error)
439666f9d5cbSmlf {
43970cfc6e4aSxun ni - Sun Microsystems - Beijing China #if SI_DEBUG
43980cfc6e4aSxun ni - Sun Microsystems - Beijing China #ifndef __lock_lint
43990cfc6e4aSxun ni - Sun Microsystems - Beijing China 	_NOTE(ARGUNUSED(si_ctlp))
4400e57ece5bSPraveen Kumar Dasaraju Rama         _NOTE(ARGUNUSED(port))
44010cfc6e4aSxun ni - Sun Microsystems - Beijing China #endif  /* __lock_lint */
44020cfc6e4aSxun ni - Sun Microsystems - Beijing China 
440366f9d5cbSmlf 	char *errstr;
4404e57ece5bSPraveen Kumar Dasaraju Rama 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
440566f9d5cbSmlf 
440666f9d5cbSmlf 	switch (command_error) {
440766f9d5cbSmlf 
440866f9d5cbSmlf 	case CMD_ERR_DEVICEERRROR:
440966f9d5cbSmlf 		errstr = "Standard Error: Error bit set in register - device"
441019397407SSherry Moore 		    " to host FIS";
441166f9d5cbSmlf 		break;
441266f9d5cbSmlf 
441366f9d5cbSmlf 	case CMD_ERR_SDBERROR:
441466f9d5cbSmlf 		errstr = "NCQ Error: Error bit set in register - device"
441519397407SSherry Moore 		    " to host FIS";
441666f9d5cbSmlf 		break;
441766f9d5cbSmlf 
441866f9d5cbSmlf 	case CMD_ERR_DATAFISERROR:
441966f9d5cbSmlf 		errstr = "Error in data FIS not detected by device";
442066f9d5cbSmlf 		break;
442166f9d5cbSmlf 
442266f9d5cbSmlf 	case CMD_ERR_SENDFISERROR:
442366f9d5cbSmlf 		errstr = "Initial command FIS transmission failed";
442466f9d5cbSmlf 		break;
442566f9d5cbSmlf 
442666f9d5cbSmlf 	case CMD_ERR_INCONSISTENTSTATE:
442766f9d5cbSmlf 		errstr = "Inconsistency in protocol";
442866f9d5cbSmlf 		break;
442966f9d5cbSmlf 
443066f9d5cbSmlf 	case CMD_ERR_DIRECTIONERROR:
443166f9d5cbSmlf 		errstr = "DMA direction flag does not match the command";
443266f9d5cbSmlf 		break;
443366f9d5cbSmlf 
443466f9d5cbSmlf 	case CMD_ERR_UNDERRUNERROR:
443566f9d5cbSmlf 		errstr = "Run out of scatter gather entries while writing data";
443666f9d5cbSmlf 		break;
443766f9d5cbSmlf 
443866f9d5cbSmlf 	case CMD_ERR_OVERRUNERROR:
443966f9d5cbSmlf 		errstr = "Run out of scatter gather entries while reading data";
444066f9d5cbSmlf 		break;
444166f9d5cbSmlf 
444266f9d5cbSmlf 	case CMD_ERR_PACKETPROTOCOLERROR:
444366f9d5cbSmlf 		errstr = "Packet protocol error";
444466f9d5cbSmlf 		break;
444566f9d5cbSmlf 
444666f9d5cbSmlf 	case CMD_ERR_PLDSGTERRORBOUNDARY:
444766f9d5cbSmlf 		errstr = "Scatter/gather table not on quadword boundary";
444866f9d5cbSmlf 		break;
444966f9d5cbSmlf 
445066f9d5cbSmlf 	case CMD_ERR_PLDSGTERRORTARETABORT:
445166f9d5cbSmlf 		errstr = "PCI(X) Target abort while fetching scatter/gather"
445219397407SSherry Moore 		    " table";
445366f9d5cbSmlf 		break;
445466f9d5cbSmlf 
445566f9d5cbSmlf 	case CMD_ERR_PLDSGTERRORMASTERABORT:
445666f9d5cbSmlf 		errstr = "PCI(X) Master abort while fetching scatter/gather"
445719397407SSherry Moore 		    " table";
445866f9d5cbSmlf 		break;
445966f9d5cbSmlf 
446066f9d5cbSmlf 	case CMD_ERR_PLDSGTERRORPCIERR:
446166f9d5cbSmlf 		errstr = "PCI(X) parity error while fetching scatter/gather"
446219397407SSherry Moore 		    " table";
446366f9d5cbSmlf 		break;
446466f9d5cbSmlf 
446566f9d5cbSmlf 	case CMD_ERR_PLDCMDERRORBOUNDARY:
446666f9d5cbSmlf 		errstr = "PRB not on quadword boundary";
446766f9d5cbSmlf 		break;
446866f9d5cbSmlf 
446966f9d5cbSmlf 	case CMD_ERR_PLDCMDERRORTARGETABORT:
447066f9d5cbSmlf 		errstr = "PCI(X) Target abort while fetching PRB";
447166f9d5cbSmlf 		break;
447266f9d5cbSmlf 
447366f9d5cbSmlf 	case CMD_ERR_PLDCMDERRORMASTERABORT:
447466f9d5cbSmlf 		errstr = "PCI(X) Master abort while fetching PRB";
447566f9d5cbSmlf 		break;
447666f9d5cbSmlf 
447766f9d5cbSmlf 	case CMD_ERR_PLDCMDERORPCIERR:
447866f9d5cbSmlf 		errstr = "PCI(X) parity error while fetching PRB";
447966f9d5cbSmlf 		break;
448066f9d5cbSmlf 
448166f9d5cbSmlf 	case CMD_ERR_PSDERRORTARGETABORT:
448266f9d5cbSmlf 		errstr = "PCI(X) Target abort during data transfer";
448366f9d5cbSmlf 		break;
448466f9d5cbSmlf 
448566f9d5cbSmlf 	case CMD_ERR_PSDERRORMASTERABORT:
448666f9d5cbSmlf 		errstr = "PCI(X) Master abort during data transfer";
448766f9d5cbSmlf 		break;
448866f9d5cbSmlf 
448966f9d5cbSmlf 	case CMD_ERR_PSDERRORPCIERR:
449066f9d5cbSmlf 		errstr = "PCI(X) parity error during data transfer";
449166f9d5cbSmlf 		break;
449266f9d5cbSmlf 
449366f9d5cbSmlf 	case CMD_ERR_SENDSERVICEERROR:
449466f9d5cbSmlf 		errstr = "FIS received while sending service FIS in"
449519397407SSherry Moore 		    " legacy queuing operation";
449666f9d5cbSmlf 		break;
449766f9d5cbSmlf 
449866f9d5cbSmlf 	default:
449966f9d5cbSmlf 		errstr = "Unknown Error";
450066f9d5cbSmlf 		break;
450166f9d5cbSmlf 
450266f9d5cbSmlf 	}
450366f9d5cbSmlf 
4504e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_ERRS, si_portp,
4505e57ece5bSPraveen Kumar Dasaraju Rama 	    "command error: error: %s",
450619397407SSherry Moore 	    errstr);
45070cfc6e4aSxun ni - Sun Microsystems - Beijing China #else
45080cfc6e4aSxun ni - Sun Microsystems - Beijing China #ifndef __lock_lint
4509e57ece5bSPraveen Kumar Dasaraju Rama         _NOTE(ARGUNUSED(si_ctlp))
4510e57ece5bSPraveen Kumar Dasaraju Rama         _NOTE(ARGUNUSED(port))
4511e57ece5bSPraveen Kumar Dasaraju Rama         _NOTE(ARGUNUSED(command_error))
45120cfc6e4aSxun ni - Sun Microsystems - Beijing China #endif  /* __lock_lint */
451366f9d5cbSmlf 
45140cfc6e4aSxun ni - Sun Microsystems - Beijing China #endif	/* SI_DEBUG */
451566f9d5cbSmlf }
451666f9d5cbSmlf 
451766f9d5cbSmlf 
451866f9d5cbSmlf /*
451966f9d5cbSmlf  * Interrupt which indicates that the Port Ready state has changed
452066f9d5cbSmlf  * from zero to one.
452166f9d5cbSmlf  *
452266f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
452366f9d5cbSmlf  */
452466f9d5cbSmlf /*ARGSUSED*/
452566f9d5cbSmlf static int
si_intr_port_ready(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)452666f9d5cbSmlf si_intr_port_ready(
452766f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
452866f9d5cbSmlf 	si_port_state_t *si_portp,
452966f9d5cbSmlf 	int port)
453066f9d5cbSmlf {
4531e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp, "si_intr_ready", NULL);
453266f9d5cbSmlf 	return (SI_SUCCESS);
453366f9d5cbSmlf }
453466f9d5cbSmlf 
453566f9d5cbSmlf /*
453666f9d5cbSmlf  * Interrupt which indicates that the port power management state
453766f9d5cbSmlf  * has been modified.
453866f9d5cbSmlf  *
453966f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
454066f9d5cbSmlf  */
454166f9d5cbSmlf /*ARGSUSED*/
454266f9d5cbSmlf static int
si_intr_pwr_change(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)454366f9d5cbSmlf si_intr_pwr_change(
454466f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
454566f9d5cbSmlf 	si_port_state_t *si_portp,
454666f9d5cbSmlf 	int port)
454766f9d5cbSmlf {
4548e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp, "si_intr_pwr_change", NULL);
454966f9d5cbSmlf 	return (SI_SUCCESS);
455066f9d5cbSmlf }
455166f9d5cbSmlf 
455266f9d5cbSmlf /*
4553ab0d082fSMark Logan  * Interrupt which indicates that the PHY state has changed either from
455466f9d5cbSmlf  * Not-Ready to Ready or from Ready to Not-Ready.
455566f9d5cbSmlf  */
455666f9d5cbSmlf static int
si_intr_phy_ready_change(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)455766f9d5cbSmlf si_intr_phy_ready_change(
455866f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
455966f9d5cbSmlf 	si_port_state_t *si_portp,
456066f9d5cbSmlf 	int port)
456166f9d5cbSmlf {
456266f9d5cbSmlf 	sata_device_t sdevice;
456366f9d5cbSmlf 	uint32_t SStatus = 0; /* No dev present & PHY not established. */
456466f9d5cbSmlf 	int dev_exists_now = 0;
456566f9d5cbSmlf 	int dev_existed_previously = 0;
456666f9d5cbSmlf 
4567e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4568e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_phy_rdy_change", NULL);
456966f9d5cbSmlf 
457066f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
457166f9d5cbSmlf 	if ((si_ctlp->sictl_sata_hba_tran == NULL) || (si_portp == NULL)) {
457266f9d5cbSmlf 		/* the whole controller setup is not yet done. */
457366f9d5cbSmlf 		mutex_exit(&si_ctlp->sictl_mutex);
457466f9d5cbSmlf 		return (SI_SUCCESS);
457566f9d5cbSmlf 	}
457666f9d5cbSmlf 
457766f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
457866f9d5cbSmlf 
457966f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
458066f9d5cbSmlf 
458166f9d5cbSmlf 	/* SStatus tells the presence of device. */
458266f9d5cbSmlf 	SStatus = ddi_get32(si_ctlp->sictl_port_acc_handle,
458319397407SSherry Moore 	    (uint32_t *)PORT_SSTATUS(si_ctlp, port));
458466f9d5cbSmlf 	dev_exists_now =
458519397407SSherry Moore 	    (SSTATUS_GET_DET(SStatus) == SSTATUS_DET_DEVPRESENT_PHYONLINE);
458666f9d5cbSmlf 
458766f9d5cbSmlf 	if (si_portp->siport_port_type != PORT_TYPE_NODEV) {
458866f9d5cbSmlf 		dev_existed_previously = 1;
458966f9d5cbSmlf 	}
459066f9d5cbSmlf 
459166f9d5cbSmlf 	bzero((void *)&sdevice, sizeof (sata_device_t));
45920cfc6e4aSxun ni - Sun Microsystems - Beijing China 
45930cfc6e4aSxun ni - Sun Microsystems - Beijing China 	sdevice.satadev_addr.cport = (uint8_t)port;
459466f9d5cbSmlf 	sdevice.satadev_addr.pmport = PORTMULT_CONTROL_PORT;
459566f9d5cbSmlf 
459666f9d5cbSmlf 	/* we don't have a way of determining the exact port-mult port. */
459766f9d5cbSmlf 	if (si_portp->siport_port_type == PORT_TYPE_MULTIPLIER) {
459866f9d5cbSmlf 		sdevice.satadev_addr.qual = SATA_ADDR_PMPORT;
459966f9d5cbSmlf 	} else {
460066f9d5cbSmlf 		sdevice.satadev_addr.qual = SATA_ADDR_CPORT;
460166f9d5cbSmlf 	}
460266f9d5cbSmlf 
46034372d277Spawelw 	sdevice.satadev_state = SATA_STATE_READY; /* port state */
460466f9d5cbSmlf 
460566f9d5cbSmlf 	if (dev_exists_now) {
460666f9d5cbSmlf 		if (dev_existed_previously) {
460766f9d5cbSmlf 
460866f9d5cbSmlf 			/* Things are fine now. The loss was temporary. */
4609e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INTR, si_portp,
4610e57ece5bSPraveen Kumar Dasaraju Rama 			    "phyrdy: doing BOTH EVENTS TOGETHER", NULL);
461166f9d5cbSmlf 			if (si_portp->siport_active) {
4612e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_P(SIDBG_EVENT, si_portp,
461319397407SSherry Moore 				    "sending event: LINK_LOST & "
4614e57ece5bSPraveen Kumar Dasaraju Rama 				    "LINK_ESTABLISHED", NULL);
461566f9d5cbSmlf 
461666f9d5cbSmlf 				sata_hba_event_notify(
461719397407SSherry Moore 				    si_ctlp->sictl_sata_hba_tran->\
461819397407SSherry Moore 				    sata_tran_hba_dip,
461919397407SSherry Moore 				    &sdevice,
462019397407SSherry Moore 				    SATA_EVNT_LINK_LOST|
462119397407SSherry Moore 				    SATA_EVNT_LINK_ESTABLISHED);
462266f9d5cbSmlf 			}
462366f9d5cbSmlf 
462466f9d5cbSmlf 		} else {
462566f9d5cbSmlf 
462666f9d5cbSmlf 			/* A new device has been detected. */
462766f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
462866f9d5cbSmlf 			si_find_dev_signature(si_ctlp, si_portp, port,
462919397407SSherry Moore 			    PORTMULT_CONTROL_PORT);
463066f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
4631e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INTR, si_portp,
4632e57ece5bSPraveen Kumar Dasaraju Rama 			    "phyrdy: doing ATTACH event", NULL);
463366f9d5cbSmlf 			if (si_portp->siport_active) {
4634e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_P(SIDBG_EVENT, si_portp,
4635e57ece5bSPraveen Kumar Dasaraju Rama 				    "sending event up: LINK_ESTABLISHED", NULL);
463666f9d5cbSmlf 
463766f9d5cbSmlf 				sata_hba_event_notify(
463819397407SSherry Moore 				    si_ctlp->sictl_sata_hba_tran->\
463919397407SSherry Moore 				    sata_tran_hba_dip,
464019397407SSherry Moore 				    &sdevice,
464119397407SSherry Moore 				    SATA_EVNT_LINK_ESTABLISHED);
464266f9d5cbSmlf 			}
464366f9d5cbSmlf 
464466f9d5cbSmlf 		}
464566f9d5cbSmlf 	} else { /* No device exists now */
464666f9d5cbSmlf 
464766f9d5cbSmlf 		if (dev_existed_previously) {
464866f9d5cbSmlf 
464966f9d5cbSmlf 			/* An existing device is lost. */
465066f9d5cbSmlf 			if (si_portp->siport_active) {
4651e57ece5bSPraveen Kumar Dasaraju Rama 				SIDBG_P(SIDBG_EVENT, si_portp,
4652e57ece5bSPraveen Kumar Dasaraju Rama 				    "sending event up: LINK_LOST", NULL);
465366f9d5cbSmlf 
465466f9d5cbSmlf 				sata_hba_event_notify(
465519397407SSherry Moore 				    si_ctlp->sictl_sata_hba_tran->
465619397407SSherry Moore 				    sata_tran_hba_dip,
465719397407SSherry Moore 				    &sdevice,
465819397407SSherry Moore 				    SATA_EVNT_LINK_LOST);
465966f9d5cbSmlf 			}
466066f9d5cbSmlf 			si_portp->siport_port_type = PORT_TYPE_NODEV;
466166f9d5cbSmlf 
4662e57ece5bSPraveen Kumar Dasaraju Rama 		} else {
466366f9d5cbSmlf 
466466f9d5cbSmlf 			/* spurious interrupt */
4665e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INTR, si_portp,
4666e57ece5bSPraveen Kumar Dasaraju Rama 			    "spurious phy ready interrupt", NULL);
466766f9d5cbSmlf 		}
466866f9d5cbSmlf 	}
466966f9d5cbSmlf 
467066f9d5cbSmlf 	mutex_exit(&si_portp->siport_mutex);
467166f9d5cbSmlf 	return (SI_SUCCESS);
467266f9d5cbSmlf }
467366f9d5cbSmlf 
467466f9d5cbSmlf 
467566f9d5cbSmlf /*
467666f9d5cbSmlf  * Interrupt which indicates that a COMWAKE OOB signal has been decoded
467766f9d5cbSmlf  * on the receiver.
467866f9d5cbSmlf  *
467966f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
468066f9d5cbSmlf  */
468166f9d5cbSmlf /*ARGSUSED*/
468266f9d5cbSmlf static int
si_intr_comwake_rcvd(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)468366f9d5cbSmlf si_intr_comwake_rcvd(
468466f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
468566f9d5cbSmlf 	si_port_state_t *si_portp,
468666f9d5cbSmlf 	int port)
468766f9d5cbSmlf {
4688e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4689e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_commwake_rcvd", NULL);
469066f9d5cbSmlf 	return (SI_SUCCESS);
469166f9d5cbSmlf }
469266f9d5cbSmlf 
469366f9d5cbSmlf /*
469466f9d5cbSmlf  * Interrupt which indicates that the F-bit has been set in SError
469566f9d5cbSmlf  * Diag field.
469666f9d5cbSmlf  *
469766f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
469866f9d5cbSmlf  */
469966f9d5cbSmlf /*ARGSUSED*/
470066f9d5cbSmlf static int
si_intr_unrecognised_fis(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)470166f9d5cbSmlf si_intr_unrecognised_fis(
470266f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
470366f9d5cbSmlf 	si_port_state_t *si_portp,
470466f9d5cbSmlf 	int port)
470566f9d5cbSmlf {
4706e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4707e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_unrecognised_fis", NULL);
470866f9d5cbSmlf 	return (SI_SUCCESS);
470966f9d5cbSmlf }
471066f9d5cbSmlf 
471166f9d5cbSmlf /*
471266f9d5cbSmlf  * Interrupt which indicates that the X-bit has been set in SError
471366f9d5cbSmlf  * Diag field.
471466f9d5cbSmlf  *
471566f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
471666f9d5cbSmlf  */
471766f9d5cbSmlf /*ARGSUSED*/
471866f9d5cbSmlf static int
si_intr_dev_xchanged(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)471966f9d5cbSmlf si_intr_dev_xchanged(
472066f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
472166f9d5cbSmlf 	si_port_state_t *si_portp,
472266f9d5cbSmlf 	int port)
472366f9d5cbSmlf {
472466f9d5cbSmlf 
4725e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4726e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_dev_xchanged", NULL);
472766f9d5cbSmlf 	return (SI_SUCCESS);
472866f9d5cbSmlf }
472966f9d5cbSmlf 
473066f9d5cbSmlf /*
4731ab0d082fSMark Logan  * Interrupt which indicates that the 8b/10b Decode Error counter has
473266f9d5cbSmlf  * exceeded the programmed non-zero threshold value.
473366f9d5cbSmlf  *
473466f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
473566f9d5cbSmlf  */
473666f9d5cbSmlf /*ARGSUSED*/
473766f9d5cbSmlf static int
si_intr_decode_err_threshold(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)473866f9d5cbSmlf si_intr_decode_err_threshold(
473966f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
474066f9d5cbSmlf 	si_port_state_t *si_portp,
474166f9d5cbSmlf 	int port)
474266f9d5cbSmlf {
4743e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4744e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_err_threshold", NULL);
474566f9d5cbSmlf 	return (SI_SUCCESS);
474666f9d5cbSmlf }
474766f9d5cbSmlf 
474866f9d5cbSmlf /*
474966f9d5cbSmlf  * Interrupt which indicates that the CRC Error counter has exceeded the
475066f9d5cbSmlf  * programmed non-zero threshold value.
475166f9d5cbSmlf  *
475266f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
475366f9d5cbSmlf  */
475466f9d5cbSmlf /*ARGSUSED*/
475566f9d5cbSmlf static int
si_intr_crc_err_threshold(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)475666f9d5cbSmlf si_intr_crc_err_threshold(
475766f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
475866f9d5cbSmlf 	si_port_state_t *si_portp,
475966f9d5cbSmlf 	int port)
476066f9d5cbSmlf {
4761e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4762e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_crc_threshold", NULL);
476366f9d5cbSmlf 	return (SI_SUCCESS);
476466f9d5cbSmlf }
476566f9d5cbSmlf 
476666f9d5cbSmlf /*
476766f9d5cbSmlf  * Interrupt which indicates that the Handshake Error counter has
476866f9d5cbSmlf  * exceeded the programmed non-zero threshold value.
476966f9d5cbSmlf  *
477066f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
477166f9d5cbSmlf  */
477266f9d5cbSmlf /*ARGSUSED*/
477366f9d5cbSmlf static int
si_intr_handshake_err_threshold(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)477466f9d5cbSmlf si_intr_handshake_err_threshold(
477566f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
477666f9d5cbSmlf 	si_port_state_t *si_portp,
477766f9d5cbSmlf 	int port)
477866f9d5cbSmlf {
4779e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4780e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_handshake_err_threshold", NULL);
478166f9d5cbSmlf 	return (SI_SUCCESS);
478266f9d5cbSmlf }
478366f9d5cbSmlf 
478466f9d5cbSmlf /*
478566f9d5cbSmlf  * Interrupt which indicates that a "Set Device Bits" FIS has been
478666f9d5cbSmlf  * received with N-bit set in the control field.
478766f9d5cbSmlf  *
478866f9d5cbSmlf  * We are not interested in this interrupt; we just log a debug message.
478966f9d5cbSmlf  */
479066f9d5cbSmlf /*ARGSUSED*/
479166f9d5cbSmlf static int
si_intr_set_devbits_notify(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)479266f9d5cbSmlf si_intr_set_devbits_notify(
479366f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
479466f9d5cbSmlf 	si_port_state_t *si_portp,
479566f9d5cbSmlf 	int port)
479666f9d5cbSmlf {
4797e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INTR, si_portp,
4798e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_intr_set_devbits_notify", NULL);
479966f9d5cbSmlf 	return (SI_SUCCESS);
480066f9d5cbSmlf }
480166f9d5cbSmlf 
480266f9d5cbSmlf 
480366f9d5cbSmlf /*
480466f9d5cbSmlf  * Enable the interrupts for a particular port.
480566f9d5cbSmlf  *
480666f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
480766f9d5cbSmlf  * before calling us.
480866f9d5cbSmlf  */
480966f9d5cbSmlf static void
si_enable_port_interrupts(si_ctl_state_t * si_ctlp,int port)481066f9d5cbSmlf si_enable_port_interrupts(si_ctl_state_t *si_ctlp, int port)
481166f9d5cbSmlf {
481266f9d5cbSmlf 	uint32_t mask;
4813e57ece5bSPraveen Kumar Dasaraju Rama 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
481466f9d5cbSmlf 
481566f9d5cbSmlf 	/* get the current settings first. */
481666f9d5cbSmlf 	mask = ddi_get32(si_ctlp->sictl_global_acc_handle,
481719397407SSherry Moore 	    (uint32_t *)GLOBAL_CONTROL_REG(si_ctlp));
481866f9d5cbSmlf 
4819e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp,
482019397407SSherry Moore 	    "si_enable_port_interrupts: current mask: 0x%x",
482119397407SSherry Moore 	    mask);
482266f9d5cbSmlf 
482366f9d5cbSmlf 	/* enable the bit for current port. */
482466f9d5cbSmlf 	SET_BIT(mask, port);
482566f9d5cbSmlf 
482666f9d5cbSmlf 	/* now use this mask to enable the interrupt. */
482766f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_global_acc_handle,
482819397407SSherry Moore 	    (uint32_t *)GLOBAL_CONTROL_REG(si_ctlp),
482919397407SSherry Moore 	    mask);
483066f9d5cbSmlf }
483166f9d5cbSmlf 
483266f9d5cbSmlf /*
483366f9d5cbSmlf  * Enable interrupts for all the ports.
483466f9d5cbSmlf  */
483566f9d5cbSmlf static void
si_enable_all_interrupts(si_ctl_state_t * si_ctlp)483666f9d5cbSmlf si_enable_all_interrupts(si_ctl_state_t *si_ctlp)
483766f9d5cbSmlf {
483866f9d5cbSmlf 	int port;
483966f9d5cbSmlf 
484066f9d5cbSmlf 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
484166f9d5cbSmlf 		si_enable_port_interrupts(si_ctlp, port);
484266f9d5cbSmlf 	}
484366f9d5cbSmlf }
484466f9d5cbSmlf 
484566f9d5cbSmlf /*
484666f9d5cbSmlf  * Disable interrupts for a particular port.
484766f9d5cbSmlf  *
484866f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
484966f9d5cbSmlf  * before calling us.
485066f9d5cbSmlf  */
485166f9d5cbSmlf static void
si_disable_port_interrupts(si_ctl_state_t * si_ctlp,int port)485266f9d5cbSmlf si_disable_port_interrupts(si_ctl_state_t *si_ctlp, int port)
485366f9d5cbSmlf {
485466f9d5cbSmlf 	uint32_t mask;
485566f9d5cbSmlf 
485666f9d5cbSmlf 	/* get the current settings first. */
485766f9d5cbSmlf 	mask = ddi_get32(si_ctlp->sictl_global_acc_handle,
485819397407SSherry Moore 	    (uint32_t *)GLOBAL_CONTROL_REG(si_ctlp));
485966f9d5cbSmlf 
486066f9d5cbSmlf 	/* clear the bit for current port. */
486166f9d5cbSmlf 	CLEAR_BIT(mask, port);
486266f9d5cbSmlf 
486366f9d5cbSmlf 	/* now use this mask to disable the interrupt. */
486466f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_global_acc_handle,
486519397407SSherry Moore 	    (uint32_t *)GLOBAL_CONTROL_REG(si_ctlp),
486619397407SSherry Moore 	    mask);
486766f9d5cbSmlf 
486866f9d5cbSmlf }
486966f9d5cbSmlf 
487066f9d5cbSmlf /*
487166f9d5cbSmlf  * Disable interrupts for all the ports.
487266f9d5cbSmlf  */
487366f9d5cbSmlf static void
si_disable_all_interrupts(si_ctl_state_t * si_ctlp)487466f9d5cbSmlf si_disable_all_interrupts(si_ctl_state_t *si_ctlp)
487566f9d5cbSmlf {
487666f9d5cbSmlf 	int port;
487766f9d5cbSmlf 
487866f9d5cbSmlf 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
487966f9d5cbSmlf 		si_disable_port_interrupts(si_ctlp, port);
488066f9d5cbSmlf 	}
488166f9d5cbSmlf }
488266f9d5cbSmlf 
488366f9d5cbSmlf /*
488466f9d5cbSmlf  * Fetches the latest sstatus, scontrol, serror, sactive registers
488566f9d5cbSmlf  * and stuffs them into sata_device_t structure.
488666f9d5cbSmlf  */
488766f9d5cbSmlf static void
fill_dev_sregisters(si_ctl_state_t * si_ctlp,int port,sata_device_t * satadev)488866f9d5cbSmlf fill_dev_sregisters(si_ctl_state_t *si_ctlp, int port, sata_device_t *satadev)
488966f9d5cbSmlf {
489066f9d5cbSmlf 	satadev->satadev_scr.sstatus = ddi_get32(si_ctlp->sictl_port_acc_handle,
489119397407SSherry Moore 	    (uint32_t *)(PORT_SSTATUS(si_ctlp, port)));
489266f9d5cbSmlf 	satadev->satadev_scr.serror = ddi_get32(si_ctlp->sictl_port_acc_handle,
489319397407SSherry Moore 	    (uint32_t *)(PORT_SERROR(si_ctlp, port)));
489466f9d5cbSmlf 	satadev->satadev_scr.sactive = ddi_get32(si_ctlp->sictl_port_acc_handle,
489519397407SSherry Moore 	    (uint32_t *)(PORT_SACTIVE(si_ctlp, port)));
489666f9d5cbSmlf 	satadev->satadev_scr.scontrol =
489719397407SSherry Moore 	    ddi_get32(si_ctlp->sictl_port_acc_handle,
489819397407SSherry Moore 	    (uint32_t *)(PORT_SCONTROL(si_ctlp, port)));
489966f9d5cbSmlf 
490066f9d5cbSmlf }
490166f9d5cbSmlf 
490266f9d5cbSmlf /*
490366f9d5cbSmlf  * si_add_legacy_intrs() handles INTx and legacy interrupts.
490466f9d5cbSmlf  */
490566f9d5cbSmlf static int
si_add_legacy_intrs(si_ctl_state_t * si_ctlp)490666f9d5cbSmlf si_add_legacy_intrs(si_ctl_state_t *si_ctlp)
490766f9d5cbSmlf {
490866f9d5cbSmlf 	dev_info_t	*devinfo = si_ctlp->sictl_devinfop;
490966f9d5cbSmlf 	int		actual, count = 0;
491066f9d5cbSmlf 	int		x, y, rc, inum = 0;
491166f9d5cbSmlf 
4912e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp, "si_add_legacy_intrs", NULL);
491366f9d5cbSmlf 
491466f9d5cbSmlf 	/* get number of interrupts. */
491566f9d5cbSmlf 	rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_FIXED, &count);
491666f9d5cbSmlf 	if ((rc != DDI_SUCCESS) || (count == 0)) {
4917e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
491819397407SSherry Moore 		    "ddi_intr_get_nintrs() failed, "
491919397407SSherry Moore 		    "rc %d count %d\n", rc, count);
492066f9d5cbSmlf 		return (DDI_FAILURE);
492166f9d5cbSmlf 	}
492266f9d5cbSmlf 
492366f9d5cbSmlf 	/* Allocate an array of interrupt handles. */
492466f9d5cbSmlf 	si_ctlp->sictl_intr_size = count * sizeof (ddi_intr_handle_t);
492566f9d5cbSmlf 	si_ctlp->sictl_htable = kmem_zalloc(si_ctlp->sictl_intr_size, KM_SLEEP);
492666f9d5cbSmlf 
492766f9d5cbSmlf 	/* call ddi_intr_alloc(). */
492866f9d5cbSmlf 	rc = ddi_intr_alloc(devinfo, si_ctlp->sictl_htable, DDI_INTR_TYPE_FIXED,
492919397407SSherry Moore 	    inum, count, &actual, DDI_INTR_ALLOC_STRICT);
493066f9d5cbSmlf 
493166f9d5cbSmlf 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
4932e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
493319397407SSherry Moore 		    "ddi_intr_alloc() failed, rc %d\n", rc);
493466f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
493566f9d5cbSmlf 		return (DDI_FAILURE);
493666f9d5cbSmlf 	}
493766f9d5cbSmlf 
493866f9d5cbSmlf 	if (actual < count) {
4939e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
494019397407SSherry Moore 		    "Requested: %d, Received: %d", count, actual);
494166f9d5cbSmlf 
494266f9d5cbSmlf 		for (x = 0; x < actual; x++) {
494366f9d5cbSmlf 			(void) ddi_intr_free(si_ctlp->sictl_htable[x]);
494466f9d5cbSmlf 		}
494566f9d5cbSmlf 
494666f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
494766f9d5cbSmlf 		return (DDI_FAILURE);
494866f9d5cbSmlf 	}
494966f9d5cbSmlf 
495066f9d5cbSmlf 	si_ctlp->sictl_intr_cnt = actual;
495166f9d5cbSmlf 
495266f9d5cbSmlf 	/* Get intr priority. */
495366f9d5cbSmlf 	if (ddi_intr_get_pri(si_ctlp->sictl_htable[0],
495419397407SSherry Moore 	    &si_ctlp->sictl_intr_pri) != DDI_SUCCESS) {
4955e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
4956e57ece5bSPraveen Kumar Dasaraju Rama 		    "ddi_intr_get_pri() failed", NULL);
495766f9d5cbSmlf 
495866f9d5cbSmlf 		for (x = 0; x < actual; x++) {
495966f9d5cbSmlf 			(void) ddi_intr_free(si_ctlp->sictl_htable[x]);
496066f9d5cbSmlf 		}
496166f9d5cbSmlf 
496266f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
496366f9d5cbSmlf 		return (DDI_FAILURE);
496466f9d5cbSmlf 	}
496566f9d5cbSmlf 
496666f9d5cbSmlf 	/* Test for high level mutex. */
496766f9d5cbSmlf 	if (si_ctlp->sictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
4968e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
4969e57ece5bSPraveen Kumar Dasaraju Rama 		    "si_add_legacy_intrs: Hi level intr not supported", NULL);
497066f9d5cbSmlf 
497166f9d5cbSmlf 		for (x = 0; x < actual; x++) {
497266f9d5cbSmlf 			(void) ddi_intr_free(si_ctlp->sictl_htable[x]);
497366f9d5cbSmlf 		}
497466f9d5cbSmlf 
497566f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, sizeof (ddi_intr_handle_t));
497666f9d5cbSmlf 
497766f9d5cbSmlf 		return (DDI_FAILURE);
497866f9d5cbSmlf 	}
497966f9d5cbSmlf 
498066f9d5cbSmlf 	/* Call ddi_intr_add_handler(). */
498166f9d5cbSmlf 	for (x = 0; x < actual; x++) {
498266f9d5cbSmlf 		if (ddi_intr_add_handler(si_ctlp->sictl_htable[x], si_intr,
498366f9d5cbSmlf 		    (caddr_t)si_ctlp, NULL) != DDI_SUCCESS) {
4984e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_ERRS, si_ctlp,
4985e57ece5bSPraveen Kumar Dasaraju Rama 			    "ddi_intr_add_handler() failed", NULL);
498666f9d5cbSmlf 
498766f9d5cbSmlf 			for (y = 0; y < actual; y++) {
498866f9d5cbSmlf 				(void) ddi_intr_free(si_ctlp->sictl_htable[y]);
498966f9d5cbSmlf 			}
499066f9d5cbSmlf 
499166f9d5cbSmlf 			kmem_free(si_ctlp->sictl_htable,
499219397407SSherry Moore 			    si_ctlp->sictl_intr_size);
499366f9d5cbSmlf 			return (DDI_FAILURE);
499466f9d5cbSmlf 		}
499566f9d5cbSmlf 	}
499666f9d5cbSmlf 
499766f9d5cbSmlf 	/* Call ddi_intr_enable() for legacy interrupts. */
499866f9d5cbSmlf 	for (x = 0; x < si_ctlp->sictl_intr_cnt; x++) {
499966f9d5cbSmlf 		(void) ddi_intr_enable(si_ctlp->sictl_htable[x]);
500066f9d5cbSmlf 	}
500166f9d5cbSmlf 
500266f9d5cbSmlf 	return (DDI_SUCCESS);
500366f9d5cbSmlf }
500466f9d5cbSmlf 
500566f9d5cbSmlf /*
500666f9d5cbSmlf  * si_add_msictl_intrs() handles MSI interrupts.
500766f9d5cbSmlf  */
500866f9d5cbSmlf static int
si_add_msi_intrs(si_ctl_state_t * si_ctlp)500966f9d5cbSmlf si_add_msi_intrs(si_ctl_state_t *si_ctlp)
501066f9d5cbSmlf {
501166f9d5cbSmlf 	dev_info_t	*devinfo = si_ctlp->sictl_devinfop;
501266f9d5cbSmlf 	int		count, avail, actual;
501366f9d5cbSmlf 	int		x, y, rc, inum = 0;
501466f9d5cbSmlf 
5015e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp, "si_add_msi_intrs", NULL);
501666f9d5cbSmlf 
501766f9d5cbSmlf 	/* get number of interrupts. */
501866f9d5cbSmlf 	rc = ddi_intr_get_nintrs(devinfo, DDI_INTR_TYPE_MSI, &count);
501966f9d5cbSmlf 	if ((rc != DDI_SUCCESS) || (count == 0)) {
5020e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
502119397407SSherry Moore 		    "ddi_intr_get_nintrs() failed, "
502219397407SSherry Moore 		    "rc %d count %d\n", rc, count);
502366f9d5cbSmlf 		return (DDI_FAILURE);
502466f9d5cbSmlf 	}
502566f9d5cbSmlf 
502666f9d5cbSmlf 	/* get number of available interrupts. */
502766f9d5cbSmlf 	rc = ddi_intr_get_navail(devinfo, DDI_INTR_TYPE_MSI, &avail);
502866f9d5cbSmlf 	if ((rc != DDI_SUCCESS) || (avail == 0)) {
5029e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
503019397407SSherry Moore 		    "ddi_intr_get_navail() failed, "
503119397407SSherry Moore 		    "rc %d avail %d\n", rc, avail);
503266f9d5cbSmlf 		return (DDI_FAILURE);
503366f9d5cbSmlf 	}
503466f9d5cbSmlf 
503566f9d5cbSmlf 	if (avail < count) {
5036e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_INIT, si_ctlp,
503719397407SSherry Moore 		    "ddi_intr_get_nvail returned %d, navail() returned %d",
503819397407SSherry Moore 		    count, avail);
503966f9d5cbSmlf 	}
504066f9d5cbSmlf 
504166f9d5cbSmlf 	/* Allocate an array of interrupt handles. */
504266f9d5cbSmlf 	si_ctlp->sictl_intr_size = count * sizeof (ddi_intr_handle_t);
504366f9d5cbSmlf 	si_ctlp->sictl_htable = kmem_alloc(si_ctlp->sictl_intr_size, KM_SLEEP);
504466f9d5cbSmlf 
504566f9d5cbSmlf 	/* call ddi_intr_alloc(). */
504666f9d5cbSmlf 	rc = ddi_intr_alloc(devinfo, si_ctlp->sictl_htable, DDI_INTR_TYPE_MSI,
504719397407SSherry Moore 	    inum, count, &actual, DDI_INTR_ALLOC_NORMAL);
504866f9d5cbSmlf 
504966f9d5cbSmlf 	if ((rc != DDI_SUCCESS) || (actual == 0)) {
5050e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
505119397407SSherry Moore 		    "ddi_intr_alloc() failed, rc %d\n", rc);
505266f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
505366f9d5cbSmlf 		return (DDI_FAILURE);
505466f9d5cbSmlf 	}
505566f9d5cbSmlf 
505666f9d5cbSmlf 	/* use interrupt count returned */
505766f9d5cbSmlf 	if (actual < count) {
5058e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_INIT, si_ctlp,
505919397407SSherry Moore 		    "Requested: %d, Received: %d", count, actual);
506066f9d5cbSmlf 	}
506166f9d5cbSmlf 
506266f9d5cbSmlf 	si_ctlp->sictl_intr_cnt = actual;
506366f9d5cbSmlf 
506466f9d5cbSmlf 	/*
506566f9d5cbSmlf 	 * Get priority for first msi, assume remaining are all the same.
506666f9d5cbSmlf 	 */
506766f9d5cbSmlf 	if (ddi_intr_get_pri(si_ctlp->sictl_htable[0],
506819397407SSherry Moore 	    &si_ctlp->sictl_intr_pri) != DDI_SUCCESS) {
5069e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp, "ddi_intr_get_pri() failed", NULL);
507066f9d5cbSmlf 
507166f9d5cbSmlf 		/* Free already allocated intr. */
507266f9d5cbSmlf 		for (y = 0; y < actual; y++) {
507366f9d5cbSmlf 			(void) ddi_intr_free(si_ctlp->sictl_htable[y]);
507466f9d5cbSmlf 		}
507566f9d5cbSmlf 
507666f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
507766f9d5cbSmlf 		return (DDI_FAILURE);
507866f9d5cbSmlf 	}
507966f9d5cbSmlf 
508066f9d5cbSmlf 	/* Test for high level mutex. */
508166f9d5cbSmlf 	if (si_ctlp->sictl_intr_pri >= ddi_intr_get_hilevel_pri()) {
5082e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_C(SIDBG_ERRS, si_ctlp,
5083e57ece5bSPraveen Kumar Dasaraju Rama 		    "si_add_msi_intrs: Hi level intr not supported", NULL);
508466f9d5cbSmlf 
508566f9d5cbSmlf 		/* Free already allocated intr. */
508666f9d5cbSmlf 		for (y = 0; y < actual; y++) {
508766f9d5cbSmlf 			(void) ddi_intr_free(si_ctlp->sictl_htable[y]);
508866f9d5cbSmlf 		}
508966f9d5cbSmlf 
509066f9d5cbSmlf 		kmem_free(si_ctlp->sictl_htable, sizeof (ddi_intr_handle_t));
509166f9d5cbSmlf 
509266f9d5cbSmlf 		return (DDI_FAILURE);
509366f9d5cbSmlf 	}
509466f9d5cbSmlf 
509566f9d5cbSmlf 	/* Call ddi_intr_add_handler(). */
509666f9d5cbSmlf 	for (x = 0; x < actual; x++) {
509766f9d5cbSmlf 		if (ddi_intr_add_handler(si_ctlp->sictl_htable[x], si_intr,
509866f9d5cbSmlf 		    (caddr_t)si_ctlp, NULL) != DDI_SUCCESS) {
5099e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_C(SIDBG_ERRS, si_ctlp,
5100e57ece5bSPraveen Kumar Dasaraju Rama 			    "ddi_intr_add_handler() failed", NULL);
510166f9d5cbSmlf 
510266f9d5cbSmlf 			/* Free already allocated intr. */
510366f9d5cbSmlf 			for (y = 0; y < actual; y++) {
510466f9d5cbSmlf 				(void) ddi_intr_free(si_ctlp->sictl_htable[y]);
510566f9d5cbSmlf 			}
510666f9d5cbSmlf 
510766f9d5cbSmlf 			kmem_free(si_ctlp->sictl_htable,
510819397407SSherry Moore 			    si_ctlp->sictl_intr_size);
510966f9d5cbSmlf 			return (DDI_FAILURE);
511066f9d5cbSmlf 		}
511166f9d5cbSmlf 	}
511266f9d5cbSmlf 
511366f9d5cbSmlf 	(void) ddi_intr_get_cap(si_ctlp->sictl_htable[0],
511419397407SSherry Moore 	    &si_ctlp->sictl_intr_cap);
511566f9d5cbSmlf 
511666f9d5cbSmlf 	if (si_ctlp->sictl_intr_cap & DDI_INTR_FLAG_BLOCK) {
511766f9d5cbSmlf 		/* Call ddi_intr_block_enable() for MSI. */
511866f9d5cbSmlf 		(void) ddi_intr_block_enable(si_ctlp->sictl_htable,
511919397407SSherry Moore 		    si_ctlp->sictl_intr_cnt);
512066f9d5cbSmlf 	} else {
512166f9d5cbSmlf 		/* Call ddi_intr_enable() for MSI non block enable. */
512266f9d5cbSmlf 		for (x = 0; x < si_ctlp->sictl_intr_cnt; x++) {
512366f9d5cbSmlf 			(void) ddi_intr_enable(si_ctlp->sictl_htable[x]);
512466f9d5cbSmlf 		}
512566f9d5cbSmlf 	}
512666f9d5cbSmlf 
512766f9d5cbSmlf 	return (DDI_SUCCESS);
512866f9d5cbSmlf }
512966f9d5cbSmlf 
513066f9d5cbSmlf /*
513166f9d5cbSmlf  * Removes the registered interrupts irrespective of whether they
513266f9d5cbSmlf  * were legacy or MSI.
513366f9d5cbSmlf  */
513466f9d5cbSmlf static void
si_rem_intrs(si_ctl_state_t * si_ctlp)513566f9d5cbSmlf si_rem_intrs(si_ctl_state_t *si_ctlp)
513666f9d5cbSmlf {
513766f9d5cbSmlf 	int x;
513866f9d5cbSmlf 
5139e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_INIT, si_ctlp, "si_rem_intrs entered", NULL);
514066f9d5cbSmlf 
514166f9d5cbSmlf 	/* Disable all interrupts. */
514266f9d5cbSmlf 	if ((si_ctlp->sictl_intr_type == DDI_INTR_TYPE_MSI) &&
514319397407SSherry Moore 	    (si_ctlp->sictl_intr_cap & DDI_INTR_FLAG_BLOCK)) {
514466f9d5cbSmlf 		/* Call ddi_intr_block_disable(). */
514566f9d5cbSmlf 		(void) ddi_intr_block_disable(si_ctlp->sictl_htable,
514619397407SSherry Moore 		    si_ctlp->sictl_intr_cnt);
514766f9d5cbSmlf 	} else {
514866f9d5cbSmlf 		for (x = 0; x < si_ctlp->sictl_intr_cnt; x++) {
514966f9d5cbSmlf 			(void) ddi_intr_disable(si_ctlp->sictl_htable[x]);
515066f9d5cbSmlf 		}
515166f9d5cbSmlf 	}
515266f9d5cbSmlf 
515366f9d5cbSmlf 	/* Call ddi_intr_remove_handler(). */
515466f9d5cbSmlf 	for (x = 0; x < si_ctlp->sictl_intr_cnt; x++) {
515566f9d5cbSmlf 		(void) ddi_intr_remove_handler(si_ctlp->sictl_htable[x]);
515666f9d5cbSmlf 		(void) ddi_intr_free(si_ctlp->sictl_htable[x]);
515766f9d5cbSmlf 	}
515866f9d5cbSmlf 
515966f9d5cbSmlf 	kmem_free(si_ctlp->sictl_htable, si_ctlp->sictl_intr_size);
516066f9d5cbSmlf }
516166f9d5cbSmlf 
516266f9d5cbSmlf /*
516366f9d5cbSmlf  * Resets either the port or the device connected to the port based on
516466f9d5cbSmlf  * the flag variable.
516566f9d5cbSmlf  *
516666f9d5cbSmlf  * The reset effectively throws away all the pending commands. So, the caller
516766f9d5cbSmlf  * has to make provision to handle the pending commands.
516866f9d5cbSmlf  *
516966f9d5cbSmlf  * After the reset, we wait till the port is ready again.
517066f9d5cbSmlf  *
517166f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
517266f9d5cbSmlf  * before calling us.
517366f9d5cbSmlf  *
517466f9d5cbSmlf  * Note: Not port-mult aware.
517566f9d5cbSmlf  */
517666f9d5cbSmlf static int
si_reset_dport_wait_till_ready(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,int flag)517766f9d5cbSmlf si_reset_dport_wait_till_ready(
517866f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
517966f9d5cbSmlf 	si_port_state_t *si_portp,
518066f9d5cbSmlf 	int port,
518166f9d5cbSmlf 	int flag)
518266f9d5cbSmlf {
518366f9d5cbSmlf 	uint32_t port_status;
518466f9d5cbSmlf 	int loop_count = 0;
518566f9d5cbSmlf 	sata_device_t sdevice;
518666f9d5cbSmlf 	uint32_t SStatus;
518766f9d5cbSmlf 	uint32_t SControl;
5188a599d311SMartin Faltesek 	uint32_t port_intr_status;
518966f9d5cbSmlf 
519066f9d5cbSmlf 	_NOTE(ASSUMING_PROTECTED(si_portp))
519166f9d5cbSmlf 
519266f9d5cbSmlf 	if (flag == SI_PORT_RESET) {
519366f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
519419397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
519519397407SSherry Moore 		    PORT_CONTROL_SET_BITS_PORT_RESET);
519666f9d5cbSmlf 
519766f9d5cbSmlf 		/* Port reset is not self clearing. So clear it now. */
519866f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
519919397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
520019397407SSherry Moore 		    PORT_CONTROL_CLEAR_BITS_PORT_RESET);
520166f9d5cbSmlf 	} else {
520266f9d5cbSmlf 		/* Reset the device. */
520366f9d5cbSmlf 		ddi_put32(si_ctlp->sictl_port_acc_handle,
520419397407SSherry Moore 		    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
520519397407SSherry Moore 		    PORT_CONTROL_SET_BITS_DEV_RESET);
520666f9d5cbSmlf 
520766f9d5cbSmlf 		/*
520866f9d5cbSmlf 		 * tidbit: this bit is self clearing; so there is no need
520966f9d5cbSmlf 		 * for manual clear as we did for port reset.
521066f9d5cbSmlf 		 */
521166f9d5cbSmlf 	}
521266f9d5cbSmlf 
521366f9d5cbSmlf 	/* Set the reset in progress flag */
521466f9d5cbSmlf 	if (!(flag & SI_RESET_NO_EVENTS_UP)) {
521566f9d5cbSmlf 		si_portp->siport_reset_in_progress = 1;
521666f9d5cbSmlf 	}
521766f9d5cbSmlf 
521866f9d5cbSmlf 
521966f9d5cbSmlf 	/*
522066f9d5cbSmlf 	 * Every reset needs a PHY initialization.
522166f9d5cbSmlf 	 *
522266f9d5cbSmlf 	 * The way to initialize the PHY is to write a 1 and then
522366f9d5cbSmlf 	 * a 0 to DET field of SControl register.
522466f9d5cbSmlf 	 */
522566f9d5cbSmlf 
522666f9d5cbSmlf 	/* Fetch the current SControl before writing the DET part with 1. */
522766f9d5cbSmlf 	SControl = ddi_get32(si_ctlp->sictl_port_acc_handle,
522819397407SSherry Moore 	    (uint32_t *)PORT_SCONTROL(si_ctlp, port));
522966f9d5cbSmlf 	SCONTROL_SET_DET(SControl, SCONTROL_DET_COMRESET);
523066f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
523119397407SSherry Moore 	    (uint32_t *)(PORT_SCONTROL(si_ctlp, port)),
523219397407SSherry Moore 	    SControl);
523366f9d5cbSmlf #ifndef __lock_lint
523466f9d5cbSmlf 	delay(SI_10MS_TICKS); /* give time for COMRESET to percolate */
523566f9d5cbSmlf #endif /* __lock_lint */
523666f9d5cbSmlf 
523766f9d5cbSmlf 	/* Now fetch the SControl again and rewrite the DET part with 0 */
523866f9d5cbSmlf 	SControl = ddi_get32(si_ctlp->sictl_port_acc_handle,
523919397407SSherry Moore 	    (uint32_t *)PORT_SCONTROL(si_ctlp, port));
524066f9d5cbSmlf 	SCONTROL_SET_DET(SControl, SCONTROL_DET_NOACTION);
524166f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
524219397407SSherry Moore 	    (uint32_t *)(PORT_SCONTROL(si_ctlp, port)),
524319397407SSherry Moore 	    SControl);
524466f9d5cbSmlf 
524566f9d5cbSmlf 	/*
524666f9d5cbSmlf 	 * PHY may be initialized by now. Check the DET field of SStatus
524766f9d5cbSmlf 	 * to determine if there is a device present.
524866f9d5cbSmlf 	 *
524966f9d5cbSmlf 	 * The DET field is valid only if IPM field indicates that
525066f9d5cbSmlf 	 * the interface is in active state.
525166f9d5cbSmlf 	 */
525266f9d5cbSmlf 
525366f9d5cbSmlf 	loop_count = 0;
525466f9d5cbSmlf 	do {
525566f9d5cbSmlf 		SStatus = ddi_get32(si_ctlp->sictl_port_acc_handle,
525619397407SSherry Moore 		    (uint32_t *)PORT_SSTATUS(si_ctlp, port));
525766f9d5cbSmlf 
525866f9d5cbSmlf 		if (SSTATUS_GET_IPM(SStatus) !=
525919397407SSherry Moore 		    SSTATUS_IPM_INTERFACE_ACTIVE) {
526066f9d5cbSmlf 			/*
526166f9d5cbSmlf 			 * If the interface is not active, the DET field
526266f9d5cbSmlf 			 * is considered not accurate. So we want to
526366f9d5cbSmlf 			 * continue looping.
526466f9d5cbSmlf 			 */
526566f9d5cbSmlf 			SSTATUS_SET_DET(SStatus, SSTATUS_DET_NODEV_NOPHY);
526666f9d5cbSmlf 		}
526766f9d5cbSmlf 
526866f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_SSTATUS) {
526966f9d5cbSmlf 			/* We are effectively timing out after 0.1 sec. */
527066f9d5cbSmlf 			break;
527166f9d5cbSmlf 		}
527266f9d5cbSmlf 
527366f9d5cbSmlf 		/* Wait for 10 millisec */
527466f9d5cbSmlf #ifndef __lock_lint
527566f9d5cbSmlf 		delay(SI_10MS_TICKS);
527666f9d5cbSmlf #endif /* __lock_lint */
527766f9d5cbSmlf 
527866f9d5cbSmlf 	} while (SSTATUS_GET_DET(SStatus) != SSTATUS_DET_DEVPRESENT_PHYONLINE);
527966f9d5cbSmlf 
5280e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
528119397407SSherry Moore 	    "si_reset_dport_wait_till_ready: loop count: %d, \
528266f9d5cbSmlf 		SStatus: 0x%x",
528319397407SSherry Moore 	    loop_count,
528419397407SSherry Moore 	    SStatus);
528566f9d5cbSmlf 
528666f9d5cbSmlf 	/* Now check for port readiness. */
528766f9d5cbSmlf 	loop_count = 0;
528866f9d5cbSmlf 	do {
528966f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
529019397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
529166f9d5cbSmlf 
529266f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_PORTREADY) {
529366f9d5cbSmlf 			/* We are effectively timing out after 0.5 sec. */
529466f9d5cbSmlf 			break;
529566f9d5cbSmlf 		}
529666f9d5cbSmlf 
529766f9d5cbSmlf 		/* Wait for 10 millisec */
529866f9d5cbSmlf #ifndef __lock_lint
529966f9d5cbSmlf 		delay(SI_10MS_TICKS);
530066f9d5cbSmlf #endif /* __lock_lint */
530166f9d5cbSmlf 
530266f9d5cbSmlf 	} while (!(port_status & PORT_STATUS_BITS_PORT_READY));
530366f9d5cbSmlf 
5304e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
530519397407SSherry Moore 	    "si_reset_dport_wait_till_ready: loop count: %d, \
530666f9d5cbSmlf 		port_status: 0x%x, SStatus: 0x%x",
530719397407SSherry Moore 	    loop_count,
530819397407SSherry Moore 	    port_status,
530919397407SSherry Moore 	    SStatus);
531066f9d5cbSmlf 
531166f9d5cbSmlf 	/* Indicate to the framework that a reset has happened. */
531266f9d5cbSmlf 	if (!(flag & SI_RESET_NO_EVENTS_UP)) {
531366f9d5cbSmlf 
531466f9d5cbSmlf 		bzero((void *)&sdevice, sizeof (sata_device_t));
53150cfc6e4aSxun ni - Sun Microsystems - Beijing China 
53160cfc6e4aSxun ni - Sun Microsystems - Beijing China 		sdevice.satadev_addr.cport = (uint8_t)port;
531766f9d5cbSmlf 		sdevice.satadev_addr.pmport = PORTMULT_CONTROL_PORT;
531866f9d5cbSmlf 
531966f9d5cbSmlf 		if (si_portp->siport_port_type == PORT_TYPE_MULTIPLIER) {
532066f9d5cbSmlf 			sdevice.satadev_addr.qual = SATA_ADDR_DPMPORT;
532166f9d5cbSmlf 		} else {
532266f9d5cbSmlf 			sdevice.satadev_addr.qual = SATA_ADDR_DCPORT;
532366f9d5cbSmlf 		}
532466f9d5cbSmlf 		sdevice.satadev_state = SATA_DSTATE_RESET |
532519397407SSherry Moore 		    SATA_DSTATE_PWR_ACTIVE;
532666f9d5cbSmlf 		if (si_ctlp->sictl_sata_hba_tran) {
532766f9d5cbSmlf 			sata_hba_event_notify(
532819397407SSherry Moore 			    si_ctlp->sictl_sata_hba_tran->sata_tran_hba_dip,
532919397407SSherry Moore 			    &sdevice,
533019397407SSherry Moore 			    SATA_EVNT_DEVICE_RESET);
533166f9d5cbSmlf 		}
533266f9d5cbSmlf 
5333e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_EVENT, si_portp,
5334e57ece5bSPraveen Kumar Dasaraju Rama 		    "sending event up: SATA_EVNT_RESET", NULL);
533566f9d5cbSmlf 	}
533666f9d5cbSmlf 
533766f9d5cbSmlf 	if ((SSTATUS_GET_IPM(SStatus) == SSTATUS_IPM_INTERFACE_ACTIVE) &&
533819397407SSherry Moore 	    (SSTATUS_GET_DET(SStatus) ==
533919397407SSherry Moore 	    SSTATUS_DET_DEVPRESENT_PHYONLINE)) {
534066f9d5cbSmlf 		/* The interface is active and the device is present */
534166f9d5cbSmlf 		if (!(port_status & PORT_STATUS_BITS_PORT_READY)) {
534266f9d5cbSmlf 			/* But the port is is not ready for some reason */
5343e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_POLL_LOOP, si_portp,
5344e57ece5bSPraveen Kumar Dasaraju Rama 			    "si_reset_dport_wait_till_ready failed", NULL);
534566f9d5cbSmlf 			return (SI_FAILURE);
534666f9d5cbSmlf 		}
534766f9d5cbSmlf 	}
534866f9d5cbSmlf 
5349a599d311SMartin Faltesek 
5350a599d311SMartin Faltesek 	/*
5351a599d311SMartin Faltesek 	 * For some reason, we are losing the interrupt enablement after
5352a599d311SMartin Faltesek 	 * any reset condition. So restore them back now.
5353a599d311SMartin Faltesek 	 */
5354a599d311SMartin Faltesek 
5355e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_INIT, si_portp,
5356a599d311SMartin Faltesek 	    "current interrupt enable set: 0x%x",
5357a599d311SMartin Faltesek 	    ddi_get32(si_ctlp->sictl_port_acc_handle,
5358a599d311SMartin Faltesek 	    (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port)));
5359a599d311SMartin Faltesek 
5360a599d311SMartin Faltesek 	ddi_put32(si_ctlp->sictl_port_acc_handle,
5361a599d311SMartin Faltesek 	    (uint32_t *)PORT_INTERRUPT_ENABLE_SET(si_ctlp, port),
5362a599d311SMartin Faltesek 	    (INTR_COMMAND_COMPLETE |
5363a599d311SMartin Faltesek 	    INTR_COMMAND_ERROR |
5364a599d311SMartin Faltesek 	    INTR_PORT_READY |
5365a599d311SMartin Faltesek 	    INTR_POWER_CHANGE |
5366a599d311SMartin Faltesek 	    INTR_PHYRDY_CHANGE |
5367a599d311SMartin Faltesek 	    INTR_COMWAKE_RECEIVED |
5368a599d311SMartin Faltesek 	    INTR_UNRECOG_FIS |
5369a599d311SMartin Faltesek 	    INTR_DEV_XCHANGED |
5370a599d311SMartin Faltesek 	    INTR_SETDEVBITS_NOTIFY));
5371a599d311SMartin Faltesek 
5372a599d311SMartin Faltesek 	si_enable_port_interrupts(si_ctlp, port);
5373a599d311SMartin Faltesek 
5374a599d311SMartin Faltesek 	/*
5375a599d311SMartin Faltesek 	 * make sure interrupts are cleared
5376a599d311SMartin Faltesek 	 */
5377a599d311SMartin Faltesek 	port_intr_status = ddi_get32(si_ctlp->sictl_global_acc_handle,
5378a599d311SMartin Faltesek 	    (uint32_t *)PORT_INTERRUPT_STATUS(si_ctlp, port));
5379a599d311SMartin Faltesek 
5380a599d311SMartin Faltesek 	ddi_put32(si_ctlp->sictl_port_acc_handle,
5381a599d311SMartin Faltesek 	    (uint32_t *)(PORT_INTERRUPT_STATUS(si_ctlp,
5382a599d311SMartin Faltesek 	    port)),
5383a599d311SMartin Faltesek 	    port_intr_status & INTR_MASK);
5384a599d311SMartin Faltesek 
5385a599d311SMartin Faltesek 
5386e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
5387e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_reset_dport_wait_till_ready returning success", NULL);
538866f9d5cbSmlf 
538966f9d5cbSmlf 	return (SI_SUCCESS);
539066f9d5cbSmlf }
539166f9d5cbSmlf 
5392832d3fc2SMark Logan /*
5393832d3fc2SMark Logan  * Schedule an initialization of the port using a timeout to get it done
5394832d3fc2SMark Logan  * off an interrupt thread.
5395832d3fc2SMark Logan  *
5396832d3fc2SMark Logan  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
5397832d3fc2SMark Logan  * before calling us.
5398832d3fc2SMark Logan  */
5399832d3fc2SMark Logan static void
si_schedule_port_initialize(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port)5400832d3fc2SMark Logan si_schedule_port_initialize(
5401832d3fc2SMark Logan 	si_ctl_state_t *si_ctlp,
5402832d3fc2SMark Logan 	si_port_state_t *si_portp,
5403832d3fc2SMark Logan 	int port)
5404832d3fc2SMark Logan {
5405832d3fc2SMark Logan 	si_event_arg_t *args;
5406832d3fc2SMark Logan 
5407832d3fc2SMark Logan 	ASSERT(mutex_owned(&si_portp->siport_mutex));
5408832d3fc2SMark Logan 
5409832d3fc2SMark Logan 	args = si_portp->siport_event_args;
5410832d3fc2SMark Logan 	if (args->siea_ctlp != NULL) {
5411832d3fc2SMark Logan 		cmn_err(CE_WARN, "si_schedule_port_initialize: "
5412832d3fc2SMark Logan 		    "args->si_ctlp != NULL");
5413832d3fc2SMark Logan 		return;
5414832d3fc2SMark Logan 	}
5415832d3fc2SMark Logan 
5416832d3fc2SMark Logan 	args->siea_ctlp = si_ctlp;
5417832d3fc2SMark Logan 	args->siea_port = port;
5418832d3fc2SMark Logan 
54196d0510caSMark Logan 	(void) timeout(si_do_initialize_port, si_portp, 1);
5420832d3fc2SMark Logan }
5421832d3fc2SMark Logan 
5422832d3fc2SMark Logan /*
5423832d3fc2SMark Logan  * Called from timeout()
5424832d3fc2SMark Logan  * Unpack the arguments and call si_initialize_port_wait_till_ready()
5425832d3fc2SMark Logan  */
5426832d3fc2SMark Logan static void
si_do_initialize_port(void * arg)5427832d3fc2SMark Logan si_do_initialize_port(void *arg)
5428832d3fc2SMark Logan {
5429832d3fc2SMark Logan 	si_event_arg_t *args;
5430832d3fc2SMark Logan 	si_ctl_state_t *si_ctlp;
5431832d3fc2SMark Logan 	si_port_state_t *si_portp;
5432832d3fc2SMark Logan 	int port;
5433832d3fc2SMark Logan 
54346d0510caSMark Logan 	si_portp = arg;
54356d0510caSMark Logan 	mutex_enter(&si_portp->siport_mutex);
54366d0510caSMark Logan 
54376d0510caSMark Logan 	args = si_portp->siport_event_args;
5438832d3fc2SMark Logan 	si_ctlp = args->siea_ctlp;
5439832d3fc2SMark Logan 	port = args->siea_port;
5440832d3fc2SMark Logan 	args->siea_ctlp = NULL;	/* mark siport_event_args as free */
5441832d3fc2SMark Logan 	(void) si_initialize_port_wait_till_ready(si_ctlp, port);
54426d0510caSMark Logan 
5443832d3fc2SMark Logan 	mutex_exit(&si_portp->siport_mutex);
5444832d3fc2SMark Logan }
5445832d3fc2SMark Logan 
5446832d3fc2SMark Logan 
544766f9d5cbSmlf /*
544866f9d5cbSmlf  * Initializes the port.
544966f9d5cbSmlf  *
545066f9d5cbSmlf  * Initialization effectively throws away all the pending commands on
545166f9d5cbSmlf  * the port. So, the caller  has to make provision to handle the pending
545266f9d5cbSmlf  * commands.
545366f9d5cbSmlf  *
545466f9d5cbSmlf  * After the port initialization, we wait till the port is ready again.
545566f9d5cbSmlf  *
545666f9d5cbSmlf  * WARNING, WARNING: The caller is expected to obtain the siport_mutex
545766f9d5cbSmlf  * before calling us.
545866f9d5cbSmlf  */
545966f9d5cbSmlf static int
si_initialize_port_wait_till_ready(si_ctl_state_t * si_ctlp,int port)546066f9d5cbSmlf si_initialize_port_wait_till_ready(si_ctl_state_t *si_ctlp, int port)
546166f9d5cbSmlf {
546266f9d5cbSmlf 	uint32_t port_status;
546366f9d5cbSmlf 	int loop_count = 0;
546466f9d5cbSmlf 	uint32_t SStatus;
5465e57ece5bSPraveen Kumar Dasaraju Rama 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
546666f9d5cbSmlf 
546766f9d5cbSmlf 	/* Initialize the port. */
546866f9d5cbSmlf 	ddi_put32(si_ctlp->sictl_port_acc_handle,
546919397407SSherry Moore 	    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
547019397407SSherry Moore 	    PORT_CONTROL_SET_BITS_PORT_INITIALIZE);
547166f9d5cbSmlf 
547266f9d5cbSmlf 	/* Wait until Port Ready */
547366f9d5cbSmlf 	loop_count = 0;
547466f9d5cbSmlf 	do {
547566f9d5cbSmlf 		port_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
547619397407SSherry Moore 		    (uint32_t *)PORT_STATUS(si_ctlp, port));
547766f9d5cbSmlf 
547866f9d5cbSmlf 		if (loop_count++ > SI_POLLRATE_PORTREADY) {
5479e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INTR, si_portp,
548019397407SSherry Moore 			    "si_initialize_port_wait is timing out: "
548119397407SSherry Moore 			    "port_status: %x",
548219397407SSherry Moore 			    port_status);
548366f9d5cbSmlf 			/* We are effectively timing out after 0.5 sec. */
548466f9d5cbSmlf 			break;
548566f9d5cbSmlf 		}
548666f9d5cbSmlf 
548766f9d5cbSmlf 		/* Wait for 10 millisec */
548866f9d5cbSmlf #ifndef __lock_lint
548966f9d5cbSmlf 		delay(SI_10MS_TICKS);
549066f9d5cbSmlf #endif /* __lock_lint */
549166f9d5cbSmlf 
549266f9d5cbSmlf 	} while (!(port_status & PORT_STATUS_BITS_PORT_READY));
549366f9d5cbSmlf 
5494e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_POLL_LOOP, si_portp,
549519397407SSherry Moore 	    "si_initialize_port_wait_till_ready: loop count: %d",
549619397407SSherry Moore 	    loop_count);
549766f9d5cbSmlf 
549866f9d5cbSmlf 	SStatus = ddi_get32(si_ctlp->sictl_port_acc_handle,
549919397407SSherry Moore 	    (uint32_t *)PORT_SSTATUS(si_ctlp, port));
550066f9d5cbSmlf 
550166f9d5cbSmlf 	if ((SSTATUS_GET_IPM(SStatus) == SSTATUS_IPM_INTERFACE_ACTIVE) &&
550219397407SSherry Moore 	    (SSTATUS_GET_DET(SStatus) ==
550319397407SSherry Moore 	    SSTATUS_DET_DEVPRESENT_PHYONLINE)) {
550466f9d5cbSmlf 		/* The interface is active and the device is present */
550566f9d5cbSmlf 		if (!(port_status & PORT_STATUS_BITS_PORT_READY)) {
550666f9d5cbSmlf 			/* But the port is is not ready for some reason */
550766f9d5cbSmlf 			return (SI_FAILURE);
550866f9d5cbSmlf 		}
550966f9d5cbSmlf 	}
551066f9d5cbSmlf 
551166f9d5cbSmlf 	return (SI_SUCCESS);
551266f9d5cbSmlf }
551366f9d5cbSmlf 
551466f9d5cbSmlf 
551566f9d5cbSmlf /*
551666f9d5cbSmlf  * si_watchdog_handler() calls us if it detects that there are some
551766f9d5cbSmlf  * commands which timed out. We recalculate the timed out commands once
551866f9d5cbSmlf  * again since some of them may have finished recently.
551966f9d5cbSmlf  */
552066f9d5cbSmlf static void
si_timeout_pkts(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,int port,uint32_t timedout_tags)552166f9d5cbSmlf si_timeout_pkts(
552266f9d5cbSmlf 	si_ctl_state_t *si_ctlp,
552366f9d5cbSmlf 	si_port_state_t *si_portp,
552466f9d5cbSmlf 	int port,
552566f9d5cbSmlf 	uint32_t timedout_tags)
552666f9d5cbSmlf {
552766f9d5cbSmlf 	uint32_t slot_status;
552866f9d5cbSmlf 	uint32_t finished_tags;
552966f9d5cbSmlf 
5530e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_TIMEOUT, si_portp,
5531e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_timeout_pkts entry", NULL);
553266f9d5cbSmlf 
553366f9d5cbSmlf 	mutex_enter(&si_portp->siport_mutex);
553466f9d5cbSmlf 	slot_status = ddi_get32(si_ctlp->sictl_port_acc_handle,
553519397407SSherry Moore 	    (uint32_t *)(PORT_SLOT_STATUS(si_ctlp, port)));
553666f9d5cbSmlf 
5537cf6ed809SMark Logan 	si_portp->mopping_in_progress++;
5538cf6ed809SMark Logan 
553966f9d5cbSmlf 	/*
554066f9d5cbSmlf 	 * Initialize the controller. The only way to timeout the commands
554166f9d5cbSmlf 	 * is to reset or initialize the controller. We mop commands after
554266f9d5cbSmlf 	 * the initialization.
554366f9d5cbSmlf 	 */
554466f9d5cbSmlf 	(void) si_initialize_port_wait_till_ready(si_ctlp, port);
554566f9d5cbSmlf 
554666f9d5cbSmlf 	/*
554766f9d5cbSmlf 	 * Recompute the timedout tags since some of them may have finished
554866f9d5cbSmlf 	 * meanwhile.
554966f9d5cbSmlf 	 */
555066f9d5cbSmlf 	finished_tags =  si_portp->siport_pending_tags &
555119397407SSherry Moore 	    ~slot_status & SI_SLOT_MASK;
555266f9d5cbSmlf 	timedout_tags &= ~finished_tags;
555366f9d5cbSmlf 
5554e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_P(SIDBG_TIMEOUT, si_portp,
555519397407SSherry Moore 	    "si_timeout_pkts: finished: %x, timeout: %x",
555619397407SSherry Moore 	    finished_tags,
555719397407SSherry Moore 	    timedout_tags);
555866f9d5cbSmlf 
555966f9d5cbSmlf 	si_mop_commands(si_ctlp,
556019397407SSherry Moore 	    si_portp,
556119397407SSherry Moore 	    port,
556219397407SSherry Moore 	    slot_status,
556319397407SSherry Moore 	    0, /* failed_tags */
556419397407SSherry Moore 	    timedout_tags,
556519397407SSherry Moore 	    0, /* aborting_tags */
556619397407SSherry Moore 	    0);  /* reset_tags */
556766f9d5cbSmlf 
5568cf6ed809SMark Logan 	mutex_exit(&si_portp->siport_mutex);
556966f9d5cbSmlf }
557066f9d5cbSmlf 
557166f9d5cbSmlf 
557266f9d5cbSmlf 
557366f9d5cbSmlf /*
557466f9d5cbSmlf  * Watchdog handler kicks in every 5 seconds to timeout any commands pending
557566f9d5cbSmlf  * for long time.
557666f9d5cbSmlf  */
557766f9d5cbSmlf static void
si_watchdog_handler(si_ctl_state_t * si_ctlp)557866f9d5cbSmlf si_watchdog_handler(si_ctl_state_t *si_ctlp)
557966f9d5cbSmlf {
558066f9d5cbSmlf 	uint32_t pending_tags = 0;
558166f9d5cbSmlf 	uint32_t timedout_tags = 0;
558266f9d5cbSmlf 	si_port_state_t *si_portp;
558366f9d5cbSmlf 	int port;
558466f9d5cbSmlf 	int tmpslot;
558566f9d5cbSmlf 	sata_pkt_t *satapkt;
558666f9d5cbSmlf 
558766f9d5cbSmlf 	/* max number of cycles this packet should survive */
558866f9d5cbSmlf 	int max_life_cycles;
558966f9d5cbSmlf 
559066f9d5cbSmlf 	/* how many cycles this packet survived so far */
559166f9d5cbSmlf 	int watched_cycles;
559266f9d5cbSmlf 
559366f9d5cbSmlf 	mutex_enter(&si_ctlp->sictl_mutex);
5594e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_ENTRY, si_ctlp,
5595e57ece5bSPraveen Kumar Dasaraju Rama 	    "si_watchdog_handler entered", NULL);
559666f9d5cbSmlf 
559766f9d5cbSmlf 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
559866f9d5cbSmlf 
559966f9d5cbSmlf 		si_portp = si_ctlp->sictl_ports[port];
560066f9d5cbSmlf 		if (si_portp == NULL) {
560166f9d5cbSmlf 			continue;
560266f9d5cbSmlf 		}
560366f9d5cbSmlf 
560466f9d5cbSmlf 		mutex_enter(&si_portp->siport_mutex);
560566f9d5cbSmlf 
560666f9d5cbSmlf 		if (si_portp->siport_port_type == PORT_TYPE_NODEV) {
560766f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
560866f9d5cbSmlf 			continue;
560966f9d5cbSmlf 		}
561066f9d5cbSmlf 
5611cf6ed809SMark Logan 		/* Skip the check for those ports in error recovery */
5612cf6ed809SMark Logan 		if (si_portp->mopping_in_progress > 0) {
5613e57ece5bSPraveen Kumar Dasaraju Rama 			SIDBG_P(SIDBG_INFO, si_portp,
5614cf6ed809SMark Logan 			    "si_watchdog_handler: port %d mopping "
5615cf6ed809SMark Logan 			    "in progress, so just return", port);
5616cf6ed809SMark Logan 			mutex_exit(&si_portp->siport_mutex);
5617cf6ed809SMark Logan 			continue;
5618cf6ed809SMark Logan 		}
5619cf6ed809SMark Logan 
562066f9d5cbSmlf 		pending_tags =  si_portp->siport_pending_tags;
562166f9d5cbSmlf 		timedout_tags = 0;
562266f9d5cbSmlf 		while (pending_tags) {
562366f9d5cbSmlf 			tmpslot = ddi_ffs(pending_tags) - 1;
562466f9d5cbSmlf 			if (tmpslot == -1) {
562566f9d5cbSmlf 				break;
562666f9d5cbSmlf 			}
562766f9d5cbSmlf 			satapkt = si_portp->siport_slot_pkts[tmpslot];
562866f9d5cbSmlf 
562966f9d5cbSmlf 			if ((satapkt != NULL) && satapkt->satapkt_time) {
563066f9d5cbSmlf 
563166f9d5cbSmlf 				/*
563266f9d5cbSmlf 				 * We are overloading satapkt_hba_driver_private
563366f9d5cbSmlf 				 * with watched_cycle count.
563466f9d5cbSmlf 				 *
563566f9d5cbSmlf 				 * If a packet has survived for more than it's
563666f9d5cbSmlf 				 * max life cycles, it is a candidate for time
563766f9d5cbSmlf 				 * out.
563866f9d5cbSmlf 				 */
563966f9d5cbSmlf 				watched_cycles = (int)(intptr_t)
564019397407SSherry Moore 				    satapkt->satapkt_hba_driver_private;
564166f9d5cbSmlf 				watched_cycles++;
564266f9d5cbSmlf 				max_life_cycles = (satapkt->satapkt_time +
564319397407SSherry Moore 				    si_watchdog_timeout - 1) /
564419397407SSherry Moore 				    si_watchdog_timeout;
564566f9d5cbSmlf 				if (watched_cycles > max_life_cycles) {
564666f9d5cbSmlf 					timedout_tags |= (0x1 << tmpslot);
5647e57ece5bSPraveen Kumar Dasaraju Rama 					SIDBG_P(SIDBG_TIMEOUT,
5648e57ece5bSPraveen Kumar Dasaraju Rama 					    si_portp,
564919397407SSherry Moore 					    "watchdog: timedout_tags: 0x%x",
565019397407SSherry Moore 					    timedout_tags);
565166f9d5cbSmlf 				}
565266f9d5cbSmlf 				satapkt->satapkt_hba_driver_private =
565319397407SSherry Moore 				    (void *)(intptr_t)watched_cycles;
565466f9d5cbSmlf 			}
565566f9d5cbSmlf 
565666f9d5cbSmlf 			CLEAR_BIT(pending_tags, tmpslot);
565766f9d5cbSmlf 		}
565866f9d5cbSmlf 
565966f9d5cbSmlf 		if (timedout_tags) {
566066f9d5cbSmlf 			mutex_exit(&si_portp->siport_mutex);
566166f9d5cbSmlf 			mutex_exit(&si_ctlp->sictl_mutex);
566266f9d5cbSmlf 			si_timeout_pkts(si_ctlp, si_portp, port, timedout_tags);
566366f9d5cbSmlf 			mutex_enter(&si_ctlp->sictl_mutex);
566466f9d5cbSmlf 			mutex_enter(&si_portp->siport_mutex);
566566f9d5cbSmlf 		}
566666f9d5cbSmlf 
566766f9d5cbSmlf 		mutex_exit(&si_portp->siport_mutex);
566866f9d5cbSmlf 	}
566966f9d5cbSmlf 
567066f9d5cbSmlf 	/* Reinstall the watchdog timeout handler. */
567166f9d5cbSmlf 	if (!(si_ctlp->sictl_flags & SI_NO_TIMEOUTS)) {
567266f9d5cbSmlf 		si_ctlp->sictl_timeout_id =
567319397407SSherry Moore 		    timeout((void (*)(void *))si_watchdog_handler,
567419397407SSherry Moore 		    (caddr_t)si_ctlp, si_watchdog_tick);
567566f9d5cbSmlf 	}
567666f9d5cbSmlf 	mutex_exit(&si_ctlp->sictl_mutex);
567766f9d5cbSmlf }
567866f9d5cbSmlf 
5679ab0d082fSMark Logan /*
5680ab0d082fSMark Logan  * FMA Functions
5681ab0d082fSMark Logan  */
5682ab0d082fSMark Logan 
5683ab0d082fSMark Logan /*
5684ab0d082fSMark Logan  * The IO fault service error handling callback function
5685ab0d082fSMark Logan  */
5686ab0d082fSMark Logan /*ARGSUSED*/
5687ab0d082fSMark Logan static int
si_fm_error_cb(dev_info_t * dip,ddi_fm_error_t * err,const void * impl_data)5688ab0d082fSMark Logan si_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
5689ab0d082fSMark Logan {
5690ab0d082fSMark Logan 	/*
5691ab0d082fSMark Logan 	 * as the driver can always deal with an error in any dma or
5692ab0d082fSMark Logan 	 * access handle, we can just return the fme_status value.
5693ab0d082fSMark Logan 	 */
5694ab0d082fSMark Logan 	pci_ereport_post(dip, err, NULL);
5695ab0d082fSMark Logan 	return (err->fme_status);
5696ab0d082fSMark Logan }
5697ab0d082fSMark Logan 
5698ab0d082fSMark Logan /*
5699ab0d082fSMark Logan  * si_fm_init - initialize fma capabilities and register with IO
5700ab0d082fSMark Logan  *              fault services.
5701ab0d082fSMark Logan  */
5702ab0d082fSMark Logan static void
si_fm_init(si_ctl_state_t * si_ctlp)5703ab0d082fSMark Logan si_fm_init(si_ctl_state_t *si_ctlp)
5704ab0d082fSMark Logan {
5705ab0d082fSMark Logan 	/*
5706ab0d082fSMark Logan 	 * Need to change iblock to priority for new MSI intr
5707ab0d082fSMark Logan 	 */
5708ab0d082fSMark Logan 	ddi_iblock_cookie_t fm_ibc;
5709ab0d082fSMark Logan 
5710ab0d082fSMark Logan 	/* Only register with IO Fault Services if we have some capability */
5711ab0d082fSMark Logan 	if (si_ctlp->fm_capabilities) {
5712ab0d082fSMark Logan 		/* Adjust access and dma attributes for FMA */
5713ab0d082fSMark Logan 		accattr.devacc_attr_access = DDI_FLAGERR_ACC;
5714ab0d082fSMark Logan 		prb_sgt_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
5715ab0d082fSMark Logan 		buffer_dma_attr.dma_attr_flags |= DDI_DMA_FLAGERR;
5716ab0d082fSMark Logan 
5717ab0d082fSMark Logan 		/*
5718ab0d082fSMark Logan 		 * Register capabilities with IO Fault Services.
5719ab0d082fSMark Logan 		 * fm_capabilities will be updated to indicate
5720ab0d082fSMark Logan 		 * capabilities actually supported (not requested.)
5721ab0d082fSMark Logan 		 */
5722ab0d082fSMark Logan 		ddi_fm_init(si_ctlp->sictl_devinfop, &si_ctlp->fm_capabilities,
5723ab0d082fSMark Logan 		    &fm_ibc);
5724ab0d082fSMark Logan 
5725ab0d082fSMark Logan 		if (si_ctlp->fm_capabilities == DDI_FM_NOT_CAPABLE)
5726ab0d082fSMark Logan 			cmn_err(CE_WARN, "si_fm_init: ddi_fm_init fail");
5727ab0d082fSMark Logan 
5728ab0d082fSMark Logan 		/*
5729ab0d082fSMark Logan 		 * Initialize pci ereport capabilities if ereport
5730ab0d082fSMark Logan 		 * capable (should always be.)
5731ab0d082fSMark Logan 		 */
5732ab0d082fSMark Logan 		if (DDI_FM_EREPORT_CAP(si_ctlp->fm_capabilities) ||
5733ab0d082fSMark Logan 		    DDI_FM_ERRCB_CAP(si_ctlp->fm_capabilities)) {
5734ab0d082fSMark Logan 			pci_ereport_setup(si_ctlp->sictl_devinfop);
5735ab0d082fSMark Logan 		}
5736ab0d082fSMark Logan 
5737ab0d082fSMark Logan 		/*
5738ab0d082fSMark Logan 		 * Register error callback if error callback capable.
5739ab0d082fSMark Logan 		 */
5740ab0d082fSMark Logan 		if (DDI_FM_ERRCB_CAP(si_ctlp->fm_capabilities)) {
5741ab0d082fSMark Logan 			ddi_fm_handler_register(si_ctlp->sictl_devinfop,
5742ab0d082fSMark Logan 			    si_fm_error_cb, (void *) si_ctlp);
5743ab0d082fSMark Logan 		}
5744ab0d082fSMark Logan 	}
5745ab0d082fSMark Logan }
5746ab0d082fSMark Logan 
5747ab0d082fSMark Logan /*
5748ab0d082fSMark Logan  * si_fm_fini - Releases fma capabilities and un-registers with IO
5749ab0d082fSMark Logan  *              fault services.
5750ab0d082fSMark Logan  */
5751ab0d082fSMark Logan static void
si_fm_fini(si_ctl_state_t * si_ctlp)5752ab0d082fSMark Logan si_fm_fini(si_ctl_state_t *si_ctlp)
5753ab0d082fSMark Logan {
5754ab0d082fSMark Logan 	/* Only unregister FMA capabilities if registered */
5755ab0d082fSMark Logan 	if (si_ctlp->fm_capabilities) {
5756ab0d082fSMark Logan 		/*
5757ab0d082fSMark Logan 		 * Un-register error callback if error callback capable.
5758ab0d082fSMark Logan 		 */
5759ab0d082fSMark Logan 		if (DDI_FM_ERRCB_CAP(si_ctlp->fm_capabilities)) {
5760ab0d082fSMark Logan 			ddi_fm_handler_unregister(si_ctlp->sictl_devinfop);
5761ab0d082fSMark Logan 		}
5762ab0d082fSMark Logan 
5763ab0d082fSMark Logan 		/*
5764ab0d082fSMark Logan 		 * Release any resources allocated by pci_ereport_setup()
5765ab0d082fSMark Logan 		 */
5766ab0d082fSMark Logan 		if (DDI_FM_EREPORT_CAP(si_ctlp->fm_capabilities) ||
5767ab0d082fSMark Logan 		    DDI_FM_ERRCB_CAP(si_ctlp->fm_capabilities)) {
5768ab0d082fSMark Logan 			pci_ereport_teardown(si_ctlp->sictl_devinfop);
5769ab0d082fSMark Logan 		}
5770ab0d082fSMark Logan 
5771ab0d082fSMark Logan 		/* Unregister from IO Fault Services */
5772ab0d082fSMark Logan 		ddi_fm_fini(si_ctlp->sictl_devinfop);
5773ab0d082fSMark Logan 
5774ab0d082fSMark Logan 		/* Adjust access and dma attributes for FMA */
5775ab0d082fSMark Logan 		accattr.devacc_attr_access = DDI_DEFAULT_ACC;
5776ab0d082fSMark Logan 		prb_sgt_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
5777ab0d082fSMark Logan 		buffer_dma_attr.dma_attr_flags &= ~DDI_DMA_FLAGERR;
5778ab0d082fSMark Logan 	}
5779ab0d082fSMark Logan }
5780ab0d082fSMark Logan 
5781ab0d082fSMark Logan static int
si_check_acc_handle(ddi_acc_handle_t handle)5782ab0d082fSMark Logan si_check_acc_handle(ddi_acc_handle_t handle)
5783ab0d082fSMark Logan {
5784ab0d082fSMark Logan 	ddi_fm_error_t de;
5785ab0d082fSMark Logan 
5786ab0d082fSMark Logan 	ASSERT(handle != NULL);
5787ab0d082fSMark Logan 	ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
5788ab0d082fSMark Logan 	return (de.fme_status);
5789ab0d082fSMark Logan }
5790ab0d082fSMark Logan 
5791ab0d082fSMark Logan static int
si_check_dma_handle(ddi_dma_handle_t handle)5792ab0d082fSMark Logan si_check_dma_handle(ddi_dma_handle_t handle)
5793ab0d082fSMark Logan {
5794ab0d082fSMark Logan 	ddi_fm_error_t de;
5795ab0d082fSMark Logan 
5796ab0d082fSMark Logan 	ASSERT(handle != NULL);
5797ab0d082fSMark Logan 	ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
5798ab0d082fSMark Logan 	return (de.fme_status);
5799ab0d082fSMark Logan }
5800ab0d082fSMark Logan 
5801ab0d082fSMark Logan static int
si_check_ctl_handles(si_ctl_state_t * si_ctlp)5802ab0d082fSMark Logan si_check_ctl_handles(si_ctl_state_t *si_ctlp)
5803ab0d082fSMark Logan {
5804ab0d082fSMark Logan 	if ((si_check_acc_handle(si_ctlp->sictl_pci_conf_handle)
5805ab0d082fSMark Logan 	    != DDI_SUCCESS) ||
5806ab0d082fSMark Logan 	    (si_check_acc_handle(si_ctlp->sictl_global_acc_handle)
5807ab0d082fSMark Logan 	    != DDI_SUCCESS) ||
5808ab0d082fSMark Logan 	    (si_check_acc_handle(si_ctlp->sictl_port_acc_handle)
5809ab0d082fSMark Logan 	    != DDI_SUCCESS)) {
5810ab0d082fSMark Logan 		return (DDI_FAILURE);
5811ab0d082fSMark Logan 	}
5812ab0d082fSMark Logan 
5813ab0d082fSMark Logan 	return (DDI_SUCCESS);
5814ab0d082fSMark Logan }
5815ab0d082fSMark Logan 
5816ab0d082fSMark Logan /*
5817ab0d082fSMark Logan  * WARNING: The caller is expected to obtain the siport_mutex
5818ab0d082fSMark Logan  * before calling us.
5819ab0d082fSMark Logan  */
5820ab0d082fSMark Logan static int
si_check_port_handles(si_port_state_t * si_portp)5821ab0d082fSMark Logan si_check_port_handles(si_port_state_t *si_portp)
5822ab0d082fSMark Logan {
5823ab0d082fSMark Logan 	if ((si_check_dma_handle(si_portp->siport_prbpool_dma_handle)
5824ab0d082fSMark Logan 	    != DDI_SUCCESS) ||
5825ab0d082fSMark Logan 	    (si_check_acc_handle(si_portp->siport_prbpool_acc_handle)
5826ab0d082fSMark Logan 	    != DDI_SUCCESS) ||
5827ab0d082fSMark Logan 	    (si_check_dma_handle(si_portp->siport_sgbpool_dma_handle)
5828ab0d082fSMark Logan 	    != DDI_SUCCESS) ||
5829ab0d082fSMark Logan 	    (si_check_acc_handle(si_portp->siport_sgbpool_acc_handle)
5830ab0d082fSMark Logan 	    != DDI_SUCCESS)) {
5831ab0d082fSMark Logan 		return (DDI_FAILURE);
5832ab0d082fSMark Logan 	}
5833ab0d082fSMark Logan 
5834ab0d082fSMark Logan 	return (DDI_SUCCESS);
5835ab0d082fSMark Logan }
5836ab0d082fSMark Logan 
5837ab0d082fSMark Logan static void
si_fm_ereport(si_ctl_state_t * si_ctlp,char * detail,char * payload)5838ab0d082fSMark Logan si_fm_ereport(si_ctl_state_t *si_ctlp, char *detail, char *payload)
5839ab0d082fSMark Logan {
5840ab0d082fSMark Logan 	uint64_t ena;
5841ab0d082fSMark Logan 	char buf[FM_MAX_CLASS];
5842ab0d082fSMark Logan 
5843ab0d082fSMark Logan 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
5844ab0d082fSMark Logan 	ena = fm_ena_generate(0, FM_ENA_FMT1);
5845ab0d082fSMark Logan 
5846ab0d082fSMark Logan 	if (DDI_FM_EREPORT_CAP(si_ctlp->fm_capabilities)) {
5847ab0d082fSMark Logan 		ddi_fm_ereport_post(si_ctlp->sictl_devinfop, buf, ena,
5848ab0d082fSMark Logan 		    DDI_NOSLEEP,
5849ab0d082fSMark Logan 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERSION,
5850ab0d082fSMark Logan 		    "detailed_err_type", DATA_TYPE_STRING, payload,
5851ab0d082fSMark Logan 		    NULL);
5852ab0d082fSMark Logan 	}
5853ab0d082fSMark Logan }
5854ab0d082fSMark Logan 
585566f9d5cbSmlf /*
585666f9d5cbSmlf  * Logs the message.
585766f9d5cbSmlf  */
585866f9d5cbSmlf static void
si_log(si_ctl_state_t * si_ctlp,si_port_state_t * si_portp,char * fmt,...)5859e57ece5bSPraveen Kumar Dasaraju Rama si_log(si_ctl_state_t *si_ctlp, si_port_state_t *si_portp, char *fmt, ...)
586066f9d5cbSmlf {
586166f9d5cbSmlf 	va_list ap;
586266f9d5cbSmlf 
586366f9d5cbSmlf 	mutex_enter(&si_log_mutex);
586466f9d5cbSmlf 
586566f9d5cbSmlf 	va_start(ap, fmt);
5866e57ece5bSPraveen Kumar Dasaraju Rama 
5867e57ece5bSPraveen Kumar Dasaraju Rama 	if (si_portp == NULL && si_ctlp == NULL) {
5868e57ece5bSPraveen Kumar Dasaraju Rama 		sata_vtrace_debug(NULL, fmt, ap);
5869e57ece5bSPraveen Kumar Dasaraju Rama 		va_end(ap);
5870e57ece5bSPraveen Kumar Dasaraju Rama 		mutex_exit(&si_log_mutex);
5871e57ece5bSPraveen Kumar Dasaraju Rama 		return;
587266f9d5cbSmlf 	}
587366f9d5cbSmlf 
5874e57ece5bSPraveen Kumar Dasaraju Rama 	if (si_portp == NULL && si_ctlp != NULL) {
5875e57ece5bSPraveen Kumar Dasaraju Rama 		sata_vtrace_debug(si_ctlp->sictl_devinfop, fmt, ap);
5876e57ece5bSPraveen Kumar Dasaraju Rama 		va_end(ap);
5877e57ece5bSPraveen Kumar Dasaraju Rama 		mutex_exit(&si_log_mutex);
5878e57ece5bSPraveen Kumar Dasaraju Rama 		return;
5879e57ece5bSPraveen Kumar Dasaraju Rama 	}
5880e57ece5bSPraveen Kumar Dasaraju Rama 
5881e57ece5bSPraveen Kumar Dasaraju Rama 	/*
5882e57ece5bSPraveen Kumar Dasaraju Rama 	 * si_portp is not NULL, but si_ctlp might be.
5883e57ece5bSPraveen Kumar Dasaraju Rama 	 * Reference si_portp for both port and dip.
5884e57ece5bSPraveen Kumar Dasaraju Rama 	 */
5885e57ece5bSPraveen Kumar Dasaraju Rama 	(void) snprintf(si_log_buf, SI_LOGBUF_LEN, "port%d: %s",
5886e57ece5bSPraveen Kumar Dasaraju Rama 	    si_portp->siport_port_num, fmt);
5887e57ece5bSPraveen Kumar Dasaraju Rama 
5888e57ece5bSPraveen Kumar Dasaraju Rama 	if (si_portp->siport_ctlp == NULL) {
5889e57ece5bSPraveen Kumar Dasaraju Rama 		sata_vtrace_debug(NULL, si_log_buf, ap);
5890e57ece5bSPraveen Kumar Dasaraju Rama 		va_end(ap);
5891e57ece5bSPraveen Kumar Dasaraju Rama 		mutex_exit(&si_log_mutex);
5892e57ece5bSPraveen Kumar Dasaraju Rama 		return;
5893e57ece5bSPraveen Kumar Dasaraju Rama 	}
5894e57ece5bSPraveen Kumar Dasaraju Rama 
5895e57ece5bSPraveen Kumar Dasaraju Rama 	sata_vtrace_debug(si_portp->siport_ctlp->sictl_devinfop,
5896e57ece5bSPraveen Kumar Dasaraju Rama 	    si_log_buf, ap);
5897e57ece5bSPraveen Kumar Dasaraju Rama 
5898e57ece5bSPraveen Kumar Dasaraju Rama 	va_end(ap);
589966f9d5cbSmlf 
590066f9d5cbSmlf 	mutex_exit(&si_log_mutex);
590166f9d5cbSmlf 
590266f9d5cbSmlf }
5903c03acfcaSls 
5904c03acfcaSls static void
si_copy_out_regs(sata_cmd_t * scmd,si_ctl_state_t * si_ctlp,uint8_t port,uint8_t slot)5905a599d311SMartin Faltesek si_copy_out_regs(sata_cmd_t *scmd, si_ctl_state_t *si_ctlp, uint8_t port,
5906*83dba8e1SToomas Soome     uint8_t slot)
5907c03acfcaSls {
5908a599d311SMartin Faltesek 	uint32_t *fis_word_ptr;
5909a599d311SMartin Faltesek 	si_prb_t *prb;
5910a599d311SMartin Faltesek 	int i;
5911e57ece5bSPraveen Kumar Dasaraju Rama 	si_port_state_t *si_portp = si_ctlp->sictl_ports[port];
5912a599d311SMartin Faltesek 
5913a599d311SMartin Faltesek 	/*
5914a599d311SMartin Faltesek 	 * The LRAM contains the the modified FIS after command completion, so
5915a599d311SMartin Faltesek 	 * first copy it back to the in-core PRB pool.  To save read cycles,
5916a599d311SMartin Faltesek 	 * just copy over the FIS portion of the PRB pool.
5917a599d311SMartin Faltesek 	 */
5918a599d311SMartin Faltesek 	prb =  &si_ctlp->sictl_ports[port]->siport_prbpool[slot];
5919a599d311SMartin Faltesek 
5920a599d311SMartin Faltesek 	fis_word_ptr = (uint32_t *)(void *)(&prb->prb_fis);
5921a599d311SMartin Faltesek 
5922a599d311SMartin Faltesek 	for (i = 0; i < (sizeof (fis_reg_h2d_t)/4); i++) {
5923a599d311SMartin Faltesek 		fis_word_ptr[i] = ddi_get32(
5924a599d311SMartin Faltesek 		    si_ctlp->sictl_port_acc_handle,
5925a599d311SMartin Faltesek 		    (uint32_t *)(PORT_LRAM(si_ctlp, port,
5926a599d311SMartin Faltesek 		    slot) + i * 4 + 0x08));
5927a599d311SMartin Faltesek 	}
5928a599d311SMartin Faltesek 
5929a599d311SMartin Faltesek 	/*
5930a599d311SMartin Faltesek 	 * always get the status register
5931a599d311SMartin Faltesek 	 */
5932a599d311SMartin Faltesek 	scmd->satacmd_status_reg = GET_FIS_COMMAND(prb->prb_fis);
5933a599d311SMartin Faltesek 
5934a599d311SMartin Faltesek 	DTRACE_PROBE1(satacmd_status_reg, int, scmd->satacmd_status_reg);
5935a599d311SMartin Faltesek 
5936a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_sec_count_msb) {
5937a599d311SMartin Faltesek 		scmd->satacmd_sec_count_msb =
5938a599d311SMartin Faltesek 		    GET_FIS_SECTOR_COUNT_EXP(prb->prb_fis);
5939e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5940a599d311SMartin Faltesek 		    "copyout satacmd_sec_count_msb %x\n",
5941a599d311SMartin Faltesek 		    scmd->satacmd_sec_count_msb);
5942a599d311SMartin Faltesek 	}
5943a599d311SMartin Faltesek 
5944a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_low_msb) {
5945a599d311SMartin Faltesek 		scmd->satacmd_lba_low_msb = GET_FIS_SECTOR_EXP(prb->prb_fis);
5946e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5947e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_low_msb %x\n",
5948a599d311SMartin Faltesek 		    scmd->satacmd_lba_low_msb);
5949a599d311SMartin Faltesek 	}
5950a599d311SMartin Faltesek 
5951a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_mid_msb) {
5952a599d311SMartin Faltesek 		scmd->satacmd_lba_mid_msb = GET_FIS_CYL_LOW_EXP(prb->prb_fis);
5953e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5954e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_mid_msb %x\n",
5955a599d311SMartin Faltesek 		    scmd->satacmd_lba_mid_msb);
5956a599d311SMartin Faltesek 	}
5957a599d311SMartin Faltesek 
5958a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_high_msb) {
5959a599d311SMartin Faltesek 		scmd->satacmd_lba_high_msb = GET_FIS_CYL_HI_EXP(prb->prb_fis);
5960e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5961e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_high_msb %x\n",
5962a599d311SMartin Faltesek 		    scmd->satacmd_lba_high_msb);
5963a599d311SMartin Faltesek 	}
5964a599d311SMartin Faltesek 
5965a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_sec_count_lsb) {
5966a599d311SMartin Faltesek 		scmd->satacmd_sec_count_lsb =
5967a599d311SMartin Faltesek 		    GET_FIS_SECTOR_COUNT(prb->prb_fis);
5968e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5969a599d311SMartin Faltesek 		    "copyout satacmd_sec_count_lsb %x\n",
5970a599d311SMartin Faltesek 		    scmd->satacmd_sec_count_lsb);
5971a599d311SMartin Faltesek 	}
5972a599d311SMartin Faltesek 
5973a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_low_lsb) {
5974a599d311SMartin Faltesek 		scmd->satacmd_lba_low_lsb = GET_FIS_SECTOR(prb->prb_fis);
5975e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5976e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_low_lsb %x\n",
5977a599d311SMartin Faltesek 		    scmd->satacmd_lba_low_lsb);
5978a599d311SMartin Faltesek 	}
5979a599d311SMartin Faltesek 
5980a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_mid_lsb) {
5981a599d311SMartin Faltesek 		scmd->satacmd_lba_mid_lsb = GET_FIS_CYL_LOW(prb->prb_fis);
5982e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5983e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_mid_lsb %x\n",
5984a599d311SMartin Faltesek 		    scmd->satacmd_lba_mid_lsb);
5985a599d311SMartin Faltesek 	}
5986a599d311SMartin Faltesek 
5987a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_lba_high_lsb) {
5988a599d311SMartin Faltesek 		scmd->satacmd_lba_high_lsb = GET_FIS_CYL_HI(prb->prb_fis);
5989e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5990e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_lba_high_lsb %x\n",
5991a599d311SMartin Faltesek 		    scmd->satacmd_lba_high_lsb);
5992a599d311SMartin Faltesek 	}
5993a599d311SMartin Faltesek 
5994a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_device_reg) {
5995a599d311SMartin Faltesek 		scmd->satacmd_device_reg = GET_FIS_DEV_HEAD(prb->prb_fis);
5996e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
5997e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_device_reg %x\n",
5998a599d311SMartin Faltesek 		    scmd->satacmd_device_reg);
5999a599d311SMartin Faltesek 	}
6000a599d311SMartin Faltesek 
6001a599d311SMartin Faltesek 	if (scmd->satacmd_flags.sata_copy_out_error_reg) {
6002a599d311SMartin Faltesek 		scmd->satacmd_error_reg = GET_FIS_FEATURES(prb->prb_fis);
6003e57ece5bSPraveen Kumar Dasaraju Rama 		SIDBG_P(SIDBG_VERBOSE, si_portp,
6004e57ece5bSPraveen Kumar Dasaraju Rama 		    "copyout satacmd_error_reg %x\n",
6005a599d311SMartin Faltesek 		    scmd->satacmd_error_reg);
6006a599d311SMartin Faltesek 	}
6007c03acfcaSls }
60082d9382f4Sxun ni - Sun Microsystems - Beijing China 
60092d9382f4Sxun ni - Sun Microsystems - Beijing China /*
60102d9382f4Sxun ni - Sun Microsystems - Beijing China  * This function clear the special port by send the PORT RESET
60112d9382f4Sxun ni - Sun Microsystems - Beijing China  * After reset was sent, all commands running on the port
60122d9382f4Sxun ni - Sun Microsystems - Beijing China  * is aborted
60132d9382f4Sxun ni - Sun Microsystems - Beijing China  */
60142d9382f4Sxun ni - Sun Microsystems - Beijing China static int
si_clear_port(si_ctl_state_t * si_ctlp,int port)60152d9382f4Sxun ni - Sun Microsystems - Beijing China si_clear_port(si_ctl_state_t *si_ctlp, int port)
60162d9382f4Sxun ni - Sun Microsystems - Beijing China {
60172d9382f4Sxun ni - Sun Microsystems - Beijing China 
60182d9382f4Sxun ni - Sun Microsystems - Beijing China 	if (si_ctlp == NULL)
60192d9382f4Sxun ni - Sun Microsystems - Beijing China 		return (SI_FAILURE);
60202d9382f4Sxun ni - Sun Microsystems - Beijing China 	/*
60212d9382f4Sxun ni - Sun Microsystems - Beijing China 	 * reset this port so that all existing command
60222d9382f4Sxun ni - Sun Microsystems - Beijing China 	 * is clear
60232d9382f4Sxun ni - Sun Microsystems - Beijing China 	 */
60242d9382f4Sxun ni - Sun Microsystems - Beijing China 	ddi_put32(si_ctlp->sictl_port_acc_handle,
60252d9382f4Sxun ni - Sun Microsystems - Beijing China 	    (uint32_t *)PORT_CONTROL_SET(si_ctlp, port),
60262d9382f4Sxun ni - Sun Microsystems - Beijing China 	    PORT_CONTROL_SET_BITS_PORT_RESET);
60272d9382f4Sxun ni - Sun Microsystems - Beijing China 
60282d9382f4Sxun ni - Sun Microsystems - Beijing China 	/* Port reset is not self clearing. So clear it now. */
60292d9382f4Sxun ni - Sun Microsystems - Beijing China 	ddi_put32(si_ctlp->sictl_port_acc_handle,
60302d9382f4Sxun ni - Sun Microsystems - Beijing China 	    (uint32_t *)PORT_CONTROL_CLEAR(si_ctlp, port),
60312d9382f4Sxun ni - Sun Microsystems - Beijing China 	    PORT_CONTROL_CLEAR_BITS_PORT_RESET);
60322d9382f4Sxun ni - Sun Microsystems - Beijing China 	return (SI_SUCCESS);
60332d9382f4Sxun ni - Sun Microsystems - Beijing China }
60342d9382f4Sxun ni - Sun Microsystems - Beijing China 
60352d9382f4Sxun ni - Sun Microsystems - Beijing China /*
60362d9382f4Sxun ni - Sun Microsystems - Beijing China  * quiesce(9E) entry point.
60372d9382f4Sxun ni - Sun Microsystems - Beijing China  * This function is called when the system is single-threaded at high
60382d9382f4Sxun ni - Sun Microsystems - Beijing China  * PIL with preemption disabled. Therefore, this function must not be
60392d9382f4Sxun ni - Sun Microsystems - Beijing China  * blocked.
60402d9382f4Sxun ni - Sun Microsystems - Beijing China  *
60412d9382f4Sxun ni - Sun Microsystems - Beijing China  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
60422d9382f4Sxun ni - Sun Microsystems - Beijing China  * DDI_FAILURE indicates an error condition and should almost never happen.
60432d9382f4Sxun ni - Sun Microsystems - Beijing China  */
60442d9382f4Sxun ni - Sun Microsystems - Beijing China static int
si_quiesce(dev_info_t * dip)60452d9382f4Sxun ni - Sun Microsystems - Beijing China si_quiesce(dev_info_t *dip)
60462d9382f4Sxun ni - Sun Microsystems - Beijing China {
60472d9382f4Sxun ni - Sun Microsystems - Beijing China 	si_ctl_state_t *si_ctlp;
60482d9382f4Sxun ni - Sun Microsystems - Beijing China 	int instance;
60492d9382f4Sxun ni - Sun Microsystems - Beijing China 	int port;
60502d9382f4Sxun ni - Sun Microsystems - Beijing China 
60512d9382f4Sxun ni - Sun Microsystems - Beijing China 	instance = ddi_get_instance(dip);
60522d9382f4Sxun ni - Sun Microsystems - Beijing China 	si_ctlp = ddi_get_soft_state(si_statep, instance);
60532d9382f4Sxun ni - Sun Microsystems - Beijing China 	if (si_ctlp == NULL)
60542d9382f4Sxun ni - Sun Microsystems - Beijing China 		return (DDI_FAILURE);
60552d9382f4Sxun ni - Sun Microsystems - Beijing China 
6056e57ece5bSPraveen Kumar Dasaraju Rama 	SIDBG_C(SIDBG_ENTRY, si_ctlp, "si_quiesce enter", NULL);
60572d9382f4Sxun ni - Sun Microsystems - Beijing China 	/*
60582d9382f4Sxun ni - Sun Microsystems - Beijing China 	 * Disable all the interrupts before quiesce
60592d9382f4Sxun ni - Sun Microsystems - Beijing China 	 */
60602d9382f4Sxun ni - Sun Microsystems - Beijing China 
60612d9382f4Sxun ni - Sun Microsystems - Beijing China 	for (port = 0; port < si_ctlp->sictl_num_ports; port++) {
60622d9382f4Sxun ni - Sun Microsystems - Beijing China 		si_disable_port_interrupts(si_ctlp, port);
60632d9382f4Sxun ni - Sun Microsystems - Beijing China 		(void) si_clear_port(si_ctlp, port);
60642d9382f4Sxun ni - Sun Microsystems - Beijing China 	}
60652d9382f4Sxun ni - Sun Microsystems - Beijing China 
60662d9382f4Sxun ni - Sun Microsystems - Beijing China 	return (DDI_SUCCESS);
60672d9382f4Sxun ni - Sun Microsystems - Beijing China }
6068