17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5602ca9ecth * Common Development and Distribution License (the "License").
6602ca9ecth * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
217c478bdstevel@tonic-gate/*
22602ca9ecth * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bdstevel@tonic-gate * Use is subject to license terms.
2489b4368Bayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved.
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate
287c478bdstevel@tonic-gate/*
297c478bdstevel@tonic-gate * ISSUES
307c478bdstevel@tonic-gate *
317c478bdstevel@tonic-gate * - more consistent error messages
327c478bdstevel@tonic-gate * - report name of device on errors?
337c478bdstevel@tonic-gate * - if wide target renegotiates sync, back to narrow?
347c478bdstevel@tonic-gate * - last_msgout is not accurate ????
357c478bdstevel@tonic-gate * - resolve XXXX
367c478bdstevel@tonic-gate * - improve msg reject code (use special msg reject handler)
377c478bdstevel@tonic-gate * - better use of IDE message
387c478bdstevel@tonic-gate * - keep track if ATN remains asserted and target not going into
397c478bdstevel@tonic-gate *   a msg-out phase
407c478bdstevel@tonic-gate * - improve comments
417c478bdstevel@tonic-gate * - no slave accesses when start address is odd and dma hasn't started
427c478bdstevel@tonic-gate *   this affect asserting ATN
437c478bdstevel@tonic-gate */
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gate/*
467c478bdstevel@tonic-gate * fas - QLogic fas366 wide/fast SCSI Processor HBA driver with
477c478bdstevel@tonic-gate *	tagged and non-tagged queueing support
487c478bdstevel@tonic-gate */
497c478bdstevel@tonic-gate#if defined(lint) && !defined(DEBUG)
507c478bdstevel@tonic-gate#define	DEBUG	1
517c478bdstevel@tonic-gate#define	FASDEBUG
527c478bdstevel@tonic-gate#endif
537c478bdstevel@tonic-gate
547c478bdstevel@tonic-gate#define	DMA_REG_TRACING 	/* enable dma register access tracing */
557c478bdstevel@tonic-gate
567c478bdstevel@tonic-gate
577c478bdstevel@tonic-gate/*
587c478bdstevel@tonic-gate * standard header files
597c478bdstevel@tonic-gate */
607c478bdstevel@tonic-gate#include <sys/note.h>
617c478bdstevel@tonic-gate#include <sys/scsi/scsi.h>
627c478bdstevel@tonic-gate#include <sys/file.h>
637c478bdstevel@tonic-gate#include <sys/vtrace.h>
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate/*
667c478bdstevel@tonic-gate * private header files
677c478bdstevel@tonic-gate */
687c478bdstevel@tonic-gate#include <sys/scsi/adapters/fasdma.h>
697c478bdstevel@tonic-gate#include <sys/scsi/adapters/fasreg.h>
707c478bdstevel@tonic-gate#include <sys/scsi/adapters/fasvar.h>
717c478bdstevel@tonic-gate#include <sys/scsi/adapters/fascmd.h>
727c478bdstevel@tonic-gate#include <sys/scsi/impl/scsi_reset_notify.h>
737c478bdstevel@tonic-gate
747c478bdstevel@tonic-gate/*
757c478bdstevel@tonic-gate * tunables
767c478bdstevel@tonic-gate */
777c478bdstevel@tonic-gatestatic int		fas_selection_timeout = 250; /* 250 milliseconds */
787c478bdstevel@tonic-gatestatic uchar_t		fas_default_offset = DEFAULT_OFFSET;
797c478bdstevel@tonic-gate
807c478bdstevel@tonic-gate/*
817c478bdstevel@tonic-gate * needed for presto support, do not remove
827c478bdstevel@tonic-gate */
837c478bdstevel@tonic-gatestatic int		fas_enable_sbus64 = 1;
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate#ifdef	FASDEBUG
867c478bdstevel@tonic-gateint			fasdebug = 0;
877c478bdstevel@tonic-gateint			fasdebug_instance = -1; /* debug all instances */
887c478bdstevel@tonic-gatestatic int		fas_burstsizes_limit = -1;
897c478bdstevel@tonic-gatestatic int		fas_no_sync_wide_backoff = 0;
907c478bdstevel@tonic-gate#endif	/* FASDEBUG */
917c478bdstevel@tonic-gate
927c478bdstevel@tonic-gate/*
937c478bdstevel@tonic-gate * Local static data protected by global mutex
947c478bdstevel@tonic-gate */
957c478bdstevel@tonic-gatestatic kmutex_t 	fas_global_mutex; /* to allow concurrent attach */
967c478bdstevel@tonic-gate
977c478bdstevel@tonic-gatestatic int		fas_scsi_watchdog_tick; /* in seconds, for all	*/
987c478bdstevel@tonic-gate					/* instances			*/
997c478bdstevel@tonic-gatestatic clock_t		fas_tick;	/* fas_watch() interval in Hz	*/
1007c478bdstevel@tonic-gatestatic timeout_id_t	fas_reset_watch; /* timeout id for reset watch	*/
1017c478bdstevel@tonic-gatestatic timeout_id_t	fas_timeout_id = 0;
1027c478bdstevel@tonic-gatestatic int		fas_timeout_initted = 0;
1037c478bdstevel@tonic-gate
1047c478bdstevel@tonic-gatestatic krwlock_t	fas_global_rwlock;
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gatestatic void		*fas_state;	/* soft state ptr		*/
1077c478bdstevel@tonic-gatestatic struct fas	*fas_head;	/* link all softstate structures */
1087c478bdstevel@tonic-gatestatic struct fas	*fas_tail;	/* for fas_watch()		*/
1097c478bdstevel@tonic-gate
1107c478bdstevel@tonic-gatestatic kmutex_t		fas_log_mutex;
1117c478bdstevel@tonic-gatestatic char		fas_log_buf[256];
1127c478bdstevel@tonic-gate_NOTE(MUTEX_PROTECTS_DATA(fas_global_mutex, fas_reset_watch))
1137c478bdstevel@tonic-gate_NOTE(DATA_READABLE_WITHOUT_LOCK(fas_state fas_head fas_tail \
1147c478bdstevel@tonic-gate	fas_scsi_watchdog_tick fas_tick))
1157c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("safe sharing", fas::f_quiesce_timeid))
1167c478bdstevel@tonic-gate
1177c478bdstevel@tonic-gate/*
1187c478bdstevel@tonic-gate * dma attribute structure for scsi engine
1197c478bdstevel@tonic-gate */
1207c478bdstevel@tonic-gatestatic ddi_dma_attr_t dma_fasattr	= {
1217c478bdstevel@tonic-gate	DMA_ATTR_V0, (unsigned long long)0,
1227c478bdstevel@tonic-gate	(unsigned long long)0xffffffff, (unsigned long long)((1<<24)-1),
1237c478bdstevel@tonic-gate	1, DEFAULT_BURSTSIZE, 1,
1247c478bdstevel@tonic-gate	(unsigned long long)0xffffffff, (unsigned long long)0xffffffff,
1257c478bdstevel@tonic-gate	1, 512, 0
1267c478bdstevel@tonic-gate};
1277c478bdstevel@tonic-gate
1287c478bdstevel@tonic-gate/*
1297c478bdstevel@tonic-gate * optional torture test stuff
1307c478bdstevel@tonic-gate */
1317c478bdstevel@tonic-gate#ifdef	FASDEBUG
1327c478bdstevel@tonic-gate#define	FAS_TEST
1337c478bdstevel@tonic-gatestatic int fas_ptest_emsgin;
1347c478bdstevel@tonic-gatestatic int fas_ptest_msgin;
1357c478bdstevel@tonic-gatestatic int fas_ptest_msg = -1;
1367c478bdstevel@tonic-gatestatic int fas_ptest_status;
1377c478bdstevel@tonic-gatestatic int fas_ptest_data_in;
1387c478bdstevel@tonic-gatestatic int fas_atest;
1397c478bdstevel@tonic-gatestatic int fas_atest_disc;
1407c478bdstevel@tonic-gatestatic int fas_atest_reconn;
1417c478bdstevel@tonic-gatestatic void fas_test_abort(struct fas *fas, int slot);
1427c478bdstevel@tonic-gatestatic int fas_rtest;
1437c478bdstevel@tonic-gatestatic int fas_rtest_type;
1447c478bdstevel@tonic-gatestatic void fas_test_reset(struct fas *fas, int slot);
1457c478bdstevel@tonic-gatestatic int fas_force_timeout;
1467c478bdstevel@tonic-gatestatic int fas_btest;
1477c478bdstevel@tonic-gatestatic int fas_test_stop;
1487c478bdstevel@tonic-gatestatic int fas_transport_busy;
1497c478bdstevel@tonic-gatestatic int fas_transport_busy_rqs;
1507c478bdstevel@tonic-gatestatic int fas_transport_reject;
1517c478bdstevel@tonic-gatestatic int fas_arqs_failure;
1527c478bdstevel@tonic-gatestatic int fas_tran_err;
1537c478bdstevel@tonic-gatestatic int fas_test_untagged;
1547c478bdstevel@tonic-gatestatic int fas_enable_untagged;
1557c478bdstevel@tonic-gate#endif
1567c478bdstevel@tonic-gate
1577c478bdstevel@tonic-gate/*
1587c478bdstevel@tonic-gate * warlock directives
1597c478bdstevel@tonic-gate */
1607c478bdstevel@tonic-gate_NOTE(DATA_READABLE_WITHOUT_LOCK(dma fasdebug))
1617c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_busy))
1627c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_busy_rqs))
1637c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_reject))
1647c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_arqs_failure))
1657c478bdstevel@tonic-gate_NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_tran_err))
1667c478bdstevel@tonic-gate_NOTE(MUTEX_PROTECTS_DATA(fas_log_mutex, fas_log_buf))
1677c478bdstevel@tonic-gate_NOTE(MUTEX_PROTECTS_DATA(fas_global_mutex, fas_reset_watch))
1687c478bdstevel@tonic-gate_NOTE(DATA_READABLE_WITHOUT_LOCK(fas_state fas_head fas_tail \
1697c478bdstevel@tonic-gate	fas_scsi_watchdog_tick fas_tick))
1707c478bdstevel@tonic-gate
1717c478bdstevel@tonic-gate/*
1727c478bdstevel@tonic-gate * function prototypes
1737c478bdstevel@tonic-gate *
1747c478bdstevel@tonic-gate * scsa functions are exported by means of the transport table:
1757c478bdstevel@tonic-gate */
1767c478bdstevel@tonic-gatestatic int fas_scsi_tgt_probe(struct scsi_device *sd,
1777c478bdstevel@tonic-gate    int (*waitfunc)(void));
1787c478bdstevel@tonic-gatestatic int fas_scsi_tgt_init(dev_info_t *, dev_info_t *,
1797c478bdstevel@tonic-gate    scsi_hba_tran_t *, struct scsi_device *);
1807c478bdstevel@tonic-gatestatic int fas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt);
1817c478bdstevel@tonic-gatestatic int fas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
1827c478bdstevel@tonic-gatestatic int fas_scsi_reset(struct scsi_address *ap, int level);
1837c478bdstevel@tonic-gatestatic int fas_scsi_getcap(struct scsi_address *ap, char *cap, int whom);
1847c478bdstevel@tonic-gatestatic int fas_scsi_setcap(struct scsi_address *ap, char *cap, int value,
1857c478bdstevel@tonic-gate    int whom);
1867c478bdstevel@tonic-gatestatic struct scsi_pkt *fas_scsi_init_pkt(struct scsi_address *ap,
1877c478bdstevel@tonic-gate    struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen,
1887c478bdstevel@tonic-gate    int tgtlen, int flags, int (*callback)(), caddr_t arg);
1897c478bdstevel@tonic-gatestatic void fas_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt);
1907c478bdstevel@tonic-gatestatic void fas_scsi_dmafree(struct scsi_address *ap,
1917c478bdstevel@tonic-gate    struct scsi_pkt *pkt);
1927c478bdstevel@tonic-gatestatic void fas_scsi_sync_pkt(struct scsi_address *ap,
1937c478bdstevel@tonic-gate    struct scsi_pkt *pkt);
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gate/*
1967c478bdstevel@tonic-gate * internal functions:
1977c478bdstevel@tonic-gate */
1987c478bdstevel@tonic-gatestatic int fas_prepare_pkt(struct fas *fas, struct fas_cmd *sp);
1997c478bdstevel@tonic-gatestatic int fas_alloc_tag(struct fas *fas, struct fas_cmd *sp);
2007c478bdstevel@tonic-gatestatic int fas_accept_pkt(struct fas *fas, struct fas_cmd *sp, int flag);
2017c478bdstevel@tonic-gatestatic void fas_empty_waitQ(struct fas *fas);
2027c478bdstevel@tonic-gatestatic void fas_move_waitQ_to_readyQ(struct fas *fas);
2037c478bdstevel@tonic-gatestatic void fas_check_waitQ_and_mutex_exit(struct fas *fas);
2047c478bdstevel@tonic-gatestatic int fas_istart(struct fas *fas);
2057c478bdstevel@tonic-gatestatic int fas_ustart(struct fas *fas);
2067c478bdstevel@tonic-gatestatic int fas_startcmd(struct fas *fas, struct fas_cmd *sp);
2077c478bdstevel@tonic-gate
2087c478bdstevel@tonic-gatestatic int fas_pkt_alloc_extern(struct fas *fas, struct fas_cmd *sp,
2097c478bdstevel@tonic-gate    int cmdlen, int tgtlen, int statuslen, int kf);
2107c478bdstevel@tonic-gatestatic void fas_pkt_destroy_extern(struct fas *fas, struct fas_cmd *sp);
2117c478bdstevel@tonic-gatestatic int fas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags);
2127c478bdstevel@tonic-gatestatic void fas_kmem_cache_destructor(void *buf, void *cdrarg);
2137c478bdstevel@tonic-gate
2147c478bdstevel@tonic-gatestatic int fas_finish(struct fas *fas);
2157c478bdstevel@tonic-gatestatic void fas_handle_qfull(struct fas *fas, struct fas_cmd *sp);
2167c478bdstevel@tonic-gatestatic void fas_restart_cmd(void *);
2177c478bdstevel@tonic-gatestatic int fas_dopoll(struct fas *fas, int timeout);
2187c478bdstevel@tonic-gatestatic void fas_runpoll(struct fas *fas, short slot, struct fas_cmd *sp);
2197c478bdstevel@tonic-gatestatic uint_t fas_intr(caddr_t arg);
2207c478bdstevel@tonic-gatestatic int fas_intr_svc(struct	fas *fas);
2217c478bdstevel@tonic-gatestatic int fas_phasemanage(struct fas *fas);
2227c478bdstevel@tonic-gatestatic int fas_handle_unknown(struct fas *fas);
2237c478bdstevel@tonic-gatestatic int fas_handle_cmd_start(struct fas *fas);
2247c478bdstevel@tonic-gatestatic int fas_handle_cmd_done(struct fas *fas);
2257c478bdstevel@tonic-gatestatic int fas_handle_msg_out_start(struct fas *fas);
2267c478bdstevel@tonic-gatestatic int fas_handle_msg_out_done(struct fas *fas);
2277c478bdstevel@tonic-gatestatic int fas_handle_clearing(struct fas *fas);
2287c478bdstevel@tonic-gatestatic int fas_handle_data_start(struct fas *fas);
2297c478bdstevel@tonic-gatestatic int fas_handle_data_done(struct fas *fas);
2307c478bdstevel@tonic-gatestatic int fas_handle_c_cmplt(struct fas *fas);
2317c478bdstevel@tonic-gatestatic int fas_handle_msg_in_start(struct fas *fas);
2327c478bdstevel@tonic-gatestatic int fas_handle_more_msgin(struct fas *fas);
2337c478bdstevel@tonic-gatestatic int fas_handle_msg_in_done(struct fas *fas);
2347c478bdstevel@tonic-gatestatic int fas_onebyte_msg(struct fas *fas);
2357c478bdstevel@tonic-gatestatic int fas_twobyte_msg(struct fas *fas);
2367c478bdstevel@tonic-gatestatic int fas_multibyte_msg(struct fas *fas);
2377c478bdstevel@tonic-gatestatic void fas_revert_to_async(struct fas *fas, int tgt);
2387c478bdstevel@tonic-gatestatic int fas_finish_select(struct fas *fas);
2397c478bdstevel@tonic-gatestatic int fas_reselect_preempt(struct fas *fas);
2407c478bdstevel@tonic-gatestatic int fas_reconnect(struct fas *fas);
2417c478bdstevel@tonic-gatestatic int fas_handle_selection(struct fas *fas);
2427c478bdstevel@tonic-gatestatic void fas_head_of_readyQ(struct fas *fas, struct fas_cmd *sp);
2437c478bdstevel@tonic-gatestatic int fas_handle_gross_err(struct fas *fas);
2447c478bdstevel@tonic-gatestatic int fas_illegal_cmd_or_bus_reset(struct fas *fas);
2457c478bdstevel@tonic-gatestatic int fas_check_dma_error(struct fas *fas);
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gatestatic void fas_make_sdtr(struct fas *fas, int msgout_offset, int target);
2487c478bdstevel@tonic-gatestatic void fas_make_wdtr(struct fas *fas, int msgout_offset, int target,
2497c478bdstevel@tonic-gate    int width);
2507c478bdstevel@tonic-gatestatic void fas_update_props(struct fas *fas, int tgt);
2517c478bdstevel@tonic-gatestatic void fas_update_this_prop(struct fas *fas, char *property, int value);
2527c478bdstevel@tonic-gate
2537c478bdstevel@tonic-gatestatic int fas_commoncap(struct scsi_address *ap, char *cap, int val,
2547c478bdstevel@tonic-gate    int tgtonly, int doset);
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gatestatic void fas_watch(void *arg);
2577c478bdstevel@tonic-gatestatic void fas_watchsubr(struct fas *fas);
2587c478bdstevel@tonic-gatestatic void fas_cmd_timeout(struct fas *fas, int slot);
2597c478bdstevel@tonic-gatestatic void fas_sync_wide_backoff(struct fas *fas, struct fas_cmd *sp,
2607c478bdstevel@tonic-gate    int slot);
2617c478bdstevel@tonic-gatestatic void fas_reset_sync_wide(struct fas *fas);
2627c478bdstevel@tonic-gatestatic void fas_set_wide_conf3(struct fas *fas, int target, int width);
2637c478bdstevel@tonic-gatestatic void fas_force_renegotiation(struct fas *fas, int target);
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gatestatic int fas_set_new_window(struct fas *fas, struct fas_cmd *sp);
2667c478bdstevel@tonic-gatestatic int fas_restore_pointers(struct fas *fas, struct fas_cmd *sp);
2677c478bdstevel@tonic-gatestatic int fas_next_window(struct fas *fas, struct fas_cmd *sp, uint64_t end);
2687c478bdstevel@tonic-gate
2697c478bdstevel@tonic-gate/*PRINTFLIKE3*/
2707c478bdstevel@tonic-gatestatic void fas_log(struct fas *fas, int level, const char *fmt, ...);
2717c478bdstevel@tonic-gate/*PRINTFLIKE2*/
2727c478bdstevel@tonic-gatestatic void fas_printf(struct fas *fas, const char *fmt, ...);
2737c478bdstevel@tonic-gatestatic void fas_printstate(struct fas *fas, char *msg);
2747c478bdstevel@tonic-gatestatic void fas_dump_cmd(struct fas *fas, struct fas_cmd *sp);
2757c478bdstevel@tonic-gatestatic void fas_short_dump_cmd(struct fas *fas, struct fas_cmd *sp);
2767c478bdstevel@tonic-gatestatic char *fas_state_name(ushort_t state);
2777c478bdstevel@tonic-gate
2787c478bdstevel@tonic-gatestatic void fas_makeproxy_cmd(struct fas_cmd *sp,
2797c478bdstevel@tonic-gate    struct scsi_address *ap, struct scsi_pkt *pkt, int nmsg, ...);
2807c478bdstevel@tonic-gatestatic int fas_do_proxy_cmd(struct fas *fas, struct fas_cmd *sp,
2817c478bdstevel@tonic-gate    struct scsi_address *ap, char *what);
2827c478bdstevel@tonic-gate
2837c478bdstevel@tonic-gatestatic void fas_internal_reset(struct fas *fas, int reset_action);
2847c478bdstevel@tonic-gatestatic int fas_alloc_active_slots(struct fas *fas, int slot, int flag);
2857c478bdstevel@tonic-gate
2867c478bdstevel@tonic-gatestatic int fas_abort_curcmd(struct fas *fas);
2877c478bdstevel@tonic-gatestatic int fas_abort_cmd(struct fas *fas, struct fas_cmd *sp, int slot);
2887c478bdstevel@tonic-gatestatic int fas_do_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt);
2897c478bdstevel@tonic-gatestatic int fas_do_scsi_reset(struct scsi_address *ap, int level);
2907c478bdstevel@tonic-gatestatic int fas_remove_from_readyQ(struct fas *fas, struct fas_cmd *sp,
2917c478bdstevel@tonic-gate    int slot);
2927c478bdstevel@tonic-gatestatic void fas_flush_readyQ(struct fas *fas, int slot);
2937c478bdstevel@tonic-gatestatic void fas_flush_tagQ(struct fas *fas, int slot);
2947c478bdstevel@tonic-gatestatic void fas_flush_cmd(struct fas *fas, struct fas_cmd *sp,
2957c478bdstevel@tonic-gate    uchar_t reason, uint_t stat);
2967c478bdstevel@tonic-gatestatic int fas_abort_connected_cmd(struct fas *fas, struct fas_cmd *sp,
2977c478bdstevel@tonic-gate    uchar_t msg);
2987c478bdstevel@tonic-gatestatic int fas_abort_disconnected_cmd(struct fas *fas, struct scsi_address *ap,
2997c478bdstevel@tonic-gate    struct fas_cmd *sp, uchar_t msg, int slot);
3007c478bdstevel@tonic-gatestatic void fas_mark_packets(struct fas *fas, int slot, uchar_t reason,
3017c478bdstevel@tonic-gate    uint_t stat);
3027c478bdstevel@tonic-gatestatic void fas_set_pkt_reason(struct fas *fas, struct fas_cmd *sp,
3037c478bdstevel@tonic-gate    uchar_t reason, uint_t stat);
3047c478bdstevel@tonic-gate
3057c478bdstevel@tonic-gatestatic int fas_reset_bus(struct fas *fas);
3067c478bdstevel@tonic-gatestatic int fas_reset_recovery(struct fas *fas);
3077c478bdstevel@tonic-gatestatic int fas_reset_connected_cmd(struct fas *fas, struct scsi_address *ap);
3087c478bdstevel@tonic-gatestatic int fas_reset_disconnected_cmd(struct fas *fas, struct scsi_address *ap);
3097c478bdstevel@tonic-gatestatic void fas_start_watch_reset_delay(struct fas *);
3107c478bdstevel@tonic-gatestatic void fas_setup_reset_delay(struct fas *fas);
3117c478bdstevel@tonic-gatestatic void fas_watch_reset_delay(void *arg);
3127c478bdstevel@tonic-gatestatic int fas_watch_reset_delay_subr(struct fas *fas);
3137c478bdstevel@tonic-gatestatic void fas_reset_cleanup(struct fas *fas, int slot);
3147c478bdstevel@tonic-gatestatic int fas_scsi_reset_notify(struct scsi_address *ap, int flag,
3157c478bdstevel@tonic-gate    void (*callback)(caddr_t), caddr_t arg);
3167c478bdstevel@tonic-gatestatic int fas_scsi_quiesce(dev_info_t *hba_dip);
3177c478bdstevel@tonic-gatestatic int fas_scsi_unquiesce(dev_info_t *hba_dip);
3187c478bdstevel@tonic-gate
3197c478bdstevel@tonic-gatestatic void fas_set_throttles(struct fas *fas, int slot,
3207c478bdstevel@tonic-gate    int n, int what);
3217c478bdstevel@tonic-gatestatic void fas_set_all_lun_throttles(struct fas *fas, int slot, int what);
3227c478bdstevel@tonic-gatestatic void fas_full_throttle(struct fas *fas, int slot);
3237c478bdstevel@tonic-gatestatic void fas_remove_cmd(struct fas *fas, struct fas_cmd *sp, int timeout);
3247c478bdstevel@tonic-gatestatic void fas_decrement_ncmds(struct fas *fas, struct fas_cmd *sp);
3257c478bdstevel@tonic-gate
3267c478bdstevel@tonic-gatestatic int fas_quiesce_bus(struct fas *fas);
3277c478bdstevel@tonic-gatestatic int fas_unquiesce_bus(struct fas *fas);
3287c478bdstevel@tonic-gatestatic void fas_ncmds_checkdrain(void *arg);
3297c478bdstevel@tonic-gatestatic int fas_check_outstanding(struct fas *fas);
3307c478bdstevel@tonic-gate
3317c478bdstevel@tonic-gatestatic int fas_create_arq_pkt(struct fas *fas, struct scsi_address *ap);
3327c478bdstevel@tonic-gatestatic int fas_delete_arq_pkt(struct fas *fas, struct scsi_address *ap);
3337c478bdstevel@tonic-gatestatic int fas_handle_sts_chk(struct fas *fas, struct fas_cmd *sp);
3347c478bdstevel@tonic-gatevoid fas_complete_arq_pkt(struct scsi_pkt *pkt);
3357c478bdstevel@tonic-gate
3367c478bdstevel@tonic-gatevoid fas_call_pkt_comp(struct fas *fas, struct fas_cmd *sp);
3377c478bdstevel@tonic-gatevoid fas_empty_callbackQ(struct fas *fas);
3387c478bdstevel@tonic-gateint fas_init_callbacks(struct fas *fas);
3397c478bdstevel@tonic-gatevoid fas_destroy_callbacks(struct fas *fas);
3407c478bdstevel@tonic-gate
3417c478bdstevel@tonic-gatestatic int fas_check_dma_error(struct fas *fas);
3427c478bdstevel@tonic-gatestatic int fas_init_chip(struct fas *fas, uchar_t id);
3437c478bdstevel@tonic-gate
3447c478bdstevel@tonic-gatestatic void fas_read_fifo(struct fas *fas);
3457c478bdstevel@tonic-gatestatic void fas_write_fifo(struct fas *fas, uchar_t *buf, int length, int pad);
3467c478bdstevel@tonic-gate
3477c478bdstevel@tonic-gate#ifdef FASDEBUG
3487c478bdstevel@tonic-gatestatic void fas_reg_cmd_write(struct fas *fas, uint8_t cmd);
3497c478bdstevel@tonic-gatestatic void fas_reg_write(struct fas *fas, volatile uint8_t *p, uint8_t what);
3507c478bdstevel@tonic-gatestatic uint8_t fas_reg_read(struct fas *fas, volatile uint8_t *p);
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gatestatic void fas_dma_reg_write(struct fas *fas, volatile uint32_t *p,
3537c478bdstevel@tonic-gate    uint32_t what);
3547c478bdstevel@tonic-gatestatic uint32_t fas_dma_reg_read(struct fas *fas, volatile uint32_t *p);
3557c478bdstevel@tonic-gate#else
3567c478bdstevel@tonic-gate#define	fas_reg_cmd_write(fas, cmd) \
3577c478bdstevel@tonic-gate	fas->f_reg->fas_cmd = (cmd), fas->f_last_cmd = (cmd)
3587c478bdstevel@tonic-gate#define	fas_reg_write(fas, p, what)  *(p) = (what)
3597c478bdstevel@tonic-gate#define	fas_reg_read(fas, p) *(p)
3607c478bdstevel@tonic-gate#define	fas_dma_reg_write(fas, p, what)  *(p) = (what)
3617c478bdstevel@tonic-gate#define	fas_dma_reg_read(fas, p) *(p)
3627c478bdstevel@tonic-gate#endif
3637c478bdstevel@tonic-gate
3647c478bdstevel@tonic-gate/*
3657c478bdstevel@tonic-gate * autoconfiguration data and routines.
3667c478bdstevel@tonic-gate */
3677c478bdstevel@tonic-gatestatic int fas_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
3687c478bdstevel@tonic-gatestatic int fas_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
3697c478bdstevel@tonic-gatestatic int fas_dr_detach(dev_info_t *dev);
3707c478bdstevel@tonic-gate
3717c478bdstevel@tonic-gatestatic struct dev_ops fas_ops = {
3727c478bdstevel@tonic-gate	DEVO_REV,		/* devo_rev, */
3737c478bdstevel@tonic-gate	0,			/* refcnt  */
3747c478bdstevel@tonic-gate	ddi_no_info,		/* info */
3757c478bdstevel@tonic-gate	nulldev,		/* identify */
3767c478bdstevel@tonic-gate	nulldev,		/* probe */
3777c478bdstevel@tonic-gate	fas_attach,		/* attach */
3787c478bdstevel@tonic-gate	fas_detach,		/* detach */
3797c478bdstevel@tonic-gate	nodev,			/* reset */
3807c478bdstevel@tonic-gate	NULL,			/* driver operations */
3817c478bdstevel@tonic-gate	NULL,			/* bus operations */
3821939740Sherry Moore	NULL,			/* power */
3831939740Sherry Moore	ddi_quiesce_not_supported,	/* devo_quiesce */
3847c478bdstevel@tonic-gate};
3857c478bdstevel@tonic-gate
3867c478bdstevel@tonic-gatestatic struct modldrv modldrv = {
3877c478bdstevel@tonic-gate	&mod_driverops, /* Type of module. This one is a driver */
3881939740Sherry Moore	"FAS SCSI HBA Driver", /* Name of the module. */
3897c478bdstevel@tonic-gate	&fas_ops,	/* driver ops */
3907c478bdstevel@tonic-gate};
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gatestatic struct modlinkage modlinkage = {
3937c478bdstevel@tonic-gate	MODREV_1, (void *)&modldrv, NULL
3947c478bdstevel@tonic-gate};
3957c478bdstevel@tonic-gate
3967c478bdstevel@tonic-gateint
3977c478bdstevel@tonic-gate_init(void)
3987c478bdstevel@tonic-gate{
3997c478bdstevel@tonic-gate	int rval;
4007c478bdstevel@tonic-gate	/* CONSTCOND */
4017c478bdstevel@tonic-gate	ASSERT(NO_COMPETING_THREADS);
4027c478bdstevel@tonic-gate
4037c478bdstevel@tonic-gate	rval = ddi_soft_state_init(&fas_state, sizeof (struct fas),
4047c478bdstevel@tonic-gate	    FAS_INITIAL_SOFT_SPACE);
4057c478bdstevel@tonic-gate	if (rval != 0) {
4067c478bdstevel@tonic-gate		return (rval);
4077c478bdstevel@tonic-gate	}
4087c478bdstevel@tonic-gate
4097c478bdstevel@tonic-gate	if ((rval = scsi_hba_init(&modlinkage)) != 0) {
4107c478bdstevel@tonic-gate		ddi_soft_state_fini(&fas_state);
4117c478bdstevel@tonic-gate		return (rval);
4127c478bdstevel@tonic-gate	}
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate	mutex_init(&fas_global_mutex, NULL, MUTEX_DRIVER, NULL);
4157c478bdstevel@tonic-gate	rw_init(&fas_global_rwlock, NULL, RW_DRIVER, NULL);
4167c478bdstevel@tonic-gate
4177c478bdstevel@tonic-gate	mutex_init(&fas_log_mutex, NULL, MUTEX_DRIVER, NULL);
4187c478bdstevel@tonic-gate
4197c478bdstevel@tonic-gate	if ((rval = mod_install(&modlinkage)) != 0) {
4207c478bdstevel@tonic-gate		mutex_destroy(&fas_log_mutex);
4217c478bdstevel@tonic-gate		rw_destroy(&fas_global_rwlock);
4227c478bdstevel@tonic-gate		mutex_destroy(&fas_global_mutex);
4237c478bdstevel@tonic-gate		ddi_soft_state_fini(&fas_state);
4247c478bdstevel@tonic-gate		scsi_hba_fini(&modlinkage);
4257c478bdstevel@tonic-gate		return (rval);
4267c478bdstevel@tonic-gate	}
4277c478bdstevel@tonic-gate
4287c478bdstevel@tonic-gate	return (rval);
4297c478bdstevel@tonic-gate}
4307c478bdstevel@tonic-gate
4317c478bdstevel@tonic-gateint
4327c478bdstevel@tonic-gate_fini(void)
4337c478bdstevel@tonic-gate{
4347c478bdstevel@tonic-gate	int	rval;
4357c478bdstevel@tonic-gate	/* CONSTCOND */
4367c478bdstevel@tonic-gate	ASSERT(NO_COMPETING_THREADS);
4377c478bdstevel@tonic-gate
4387c478bdstevel@tonic-gate	if ((rval = mod_remove(&modlinkage)) == 0) {
4397c478bdstevel@tonic-gate		ddi_soft_state_fini(&fas_state);
4407c478bdstevel@tonic-gate		scsi_hba_fini(&modlinkage);
4417c478bdstevel@tonic-gate		mutex_destroy(&fas_log_mutex);
4427c478bdstevel@tonic-gate		rw_destroy(&fas_global_rwlock);
4437c478bdstevel@tonic-gate		mutex_destroy(&fas_global_mutex);
4447c478bdstevel@tonic-gate	}
4457c478bdstevel@tonic-gate	return (rval);
4467c478bdstevel@tonic-gate}
4477c478bdstevel@tonic-gate
4487c478bdstevel@tonic-gateint
4497c478bdstevel@tonic-gate_info(struct modinfo *modinfop)
4507c478bdstevel@tonic-gate{
4517c478bdstevel@tonic-gate	/* CONSTCOND */
4527c478bdstevel@tonic-gate	ASSERT(NO_COMPETING_THREADS);
4537c478bdstevel@tonic-gate
4547c478bdstevel@tonic-gate	return (mod_info(&modlinkage, modinfop));
4557c478bdstevel@tonic-gate}
4567c478bdstevel@tonic-gate
4577c478bdstevel@tonic-gatestatic int
4587c478bdstevel@tonic-gatefas_scsi_tgt_probe(struct scsi_device *sd,
4597c478bdstevel@tonic-gate    int (*waitfunc)(void))
4607c478bdstevel@tonic-gate{
4617c478bdstevel@tonic-gate	dev_info_t *dip = ddi_get_parent(sd->sd_dev);
4627c478bdstevel@tonic-gate	int rval = SCSIPROBE_FAILURE;
4637c478bdstevel@tonic-gate	scsi_hba_tran_t *tran;
4647c478bdstevel@tonic-gate	struct fas *fas;
4657c478bdstevel@tonic-gate	int tgt = sd->sd_address.a_target;
4667c478bdstevel@tonic-gate
4677c478bdstevel@tonic-gate	tran = ddi_get_driver_private(dip);
4687c478bdstevel@tonic-gate	ASSERT(tran != NULL);
4697c478bdstevel@tonic-gate	fas = TRAN2FAS(tran);
4707c478bdstevel@tonic-gate
4717c478bdstevel@tonic-gate	/*
4727c478bdstevel@tonic-gate	 * force renegotiation since inquiry cmds do not cause
4737c478bdstevel@tonic-gate	 * check conditions
4747c478bdstevel@tonic-gate	 */
4757c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
4767c478bdstevel@tonic-gate	fas_force_renegotiation(fas, tgt);
4777c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
4787c478bdstevel@tonic-gate	rval = scsi_hba_probe(sd, waitfunc);
4797c478bdstevel@tonic-gate
4807c478bdstevel@tonic-gate	/*
4817c478bdstevel@tonic-gate	 * the scsi-options precedence is:
4827c478bdstevel@tonic-gate	 *	target-scsi-options		highest
4837c478bdstevel@tonic-gate	 * 	device-type-scsi-options
4847c478bdstevel@tonic-gate	 *	per bus scsi-options
4857c478bdstevel@tonic-gate	 *	global scsi-options		lowest
4867c478bdstevel@tonic-gate	 */
4877c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
4887c478bdstevel@tonic-gate	if ((rval == SCSIPROBE_EXISTS) &&
4897c478bdstevel@tonic-gate	    ((fas->f_target_scsi_options_defined & (1 << tgt)) == 0)) {
4907c478bdstevel@tonic-gate		int options;
4917c478bdstevel@tonic-gate
4927c478bdstevel@tonic-gate		options = scsi_get_device_type_scsi_options(dip, sd, -1);
4937c478bdstevel@tonic-gate		if (options != -1) {
4947c478bdstevel@tonic-gate			fas->f_target_scsi_options[tgt] = options;
4957c478bdstevel@tonic-gate			fas_log(fas, CE_NOTE,
4961939740Sherry Moore			    "?target%x-scsi-options = 0x%x\n", tgt,
4971939740Sherry Moore			    fas->f_target_scsi_options[tgt]);
4987c478bdstevel@tonic-gate			fas_force_renegotiation(fas, tgt);
4997c478bdstevel@tonic-gate		}
5007c478bdstevel@tonic-gate	}
5017c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
5027c478bdstevel@tonic-gate
5037c478bdstevel@tonic-gate	IPRINTF2("target%x-scsi-options= 0x%x\n",
5041939740Sherry Moore	    tgt, fas->f_target_scsi_options[tgt]);
5057c478bdstevel@tonic-gate
5067c478bdstevel@tonic-gate	return (rval);
5077c478bdstevel@tonic-gate}
5087c478bdstevel@tonic-gate
5097c478bdstevel@tonic-gate
5107c478bdstevel@tonic-gate/*ARGSUSED*/
5117c478bdstevel@tonic-gatestatic int
5127c478bdstevel@tonic-gatefas_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip,
5137c478bdstevel@tonic-gate    scsi_hba_tran_t *hba_tran, struct scsi_device *sd)
5147c478bdstevel@tonic-gate{
5157c478bdstevel@tonic-gate	return (((sd->sd_address.a_target < NTARGETS_WIDE) &&
5167c478bdstevel@tonic-gate	    (sd->sd_address.a_lun < NLUNS_PER_TARGET)) ?
5171939740Sherry Moore	    DDI_SUCCESS : DDI_FAILURE);
5187c478bdstevel@tonic-gate}
5197c478bdstevel@tonic-gate
5207c478bdstevel@tonic-gate/*ARGSUSED*/
5217c478bdstevel@tonic-gatestatic int
5227c478bdstevel@tonic-gatefas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
5237c478bdstevel@tonic-gate{
5247c478bdstevel@tonic-gate	struct fas	*fas = NULL;
5257c478bdstevel@tonic-gate	volatile struct dma	*dmar = NULL;
5267c478bdstevel@tonic-gate	volatile struct fasreg	*fasreg;
5277c478bdstevel@tonic-gate	ddi_dma_attr_t		*fas_dma_attr;
5287c478bdstevel@tonic-gate	ddi_device_acc_attr_t	dev_attr;
5297c478bdstevel@tonic-gate
5307c478bdstevel@tonic-gate	int			instance, id, slot, i, hm_rev;
5317c478bdstevel@tonic-gate	size_t			rlen;
5327c478bdstevel@tonic-gate	uint_t			count;
5337c478bdstevel@tonic-gate	char			buf[64];
5347c478bdstevel@tonic-gate	scsi_hba_tran_t		*tran =	NULL;
5357c478bdstevel@tonic-gate	char			intr_added = 0;
5367c478bdstevel@tonic-gate	char			mutex_init_done = 0;
5377c478bdstevel@tonic-gate	char			hba_attached = 0;
5387c478bdstevel@tonic-gate	char			bound_handle = 0;
5397c478bdstevel@tonic-gate	char			*prop_template = "target%d-scsi-options";
5407c478bdstevel@tonic-gate	char			prop_str[32];
5417c478bdstevel@tonic-gate
5427c478bdstevel@tonic-gate	/* CONSTCOND */
5437c478bdstevel@tonic-gate	ASSERT(NO_COMPETING_THREADS);
5447c478bdstevel@tonic-gate
5457c478bdstevel@tonic-gate	switch (cmd) {
5467c478bdstevel@tonic-gate	case DDI_ATTACH:
5477c478bdstevel@tonic-gate		break;
5487c478bdstevel@tonic-gate
5497c478bdstevel@tonic-gate	case DDI_RESUME:
5507c478bdstevel@tonic-gate		if ((tran = ddi_get_driver_private(dip)) == NULL)
5517c478bdstevel@tonic-gate			return (DDI_FAILURE);
5527c478bdstevel@tonic-gate
5537c478bdstevel@tonic-gate		fas = TRAN2FAS(tran);
5547c478bdstevel@tonic-gate		if (!fas) {
5557c478bdstevel@tonic-gate			return (DDI_FAILURE);
5567c478bdstevel@tonic-gate		}
5577c478bdstevel@tonic-gate		/*
5587c478bdstevel@tonic-gate		 * Reset hardware and softc to "no outstanding commands"
5597c478bdstevel@tonic-gate		 * Note that a check condition can result on first command
5607c478bdstevel@tonic-gate		 * to a target.
5617c478bdstevel@tonic-gate		 */
5627c478bdstevel@tonic-gate		mutex_enter(FAS_MUTEX(fas));
5637c478bdstevel@tonic-gate		fas_internal_reset(fas,
5647c478bdstevel@tonic-gate		    FAS_RESET_SOFTC|FAS_RESET_FAS|FAS_RESET_DMA);
5657c478bdstevel@tonic-gate
5667c478bdstevel@tonic-gate		(void) fas_reset_bus(fas);
5677c478bdstevel@tonic-gate
5687c478bdstevel@tonic-gate		fas->f_suspended = 0;
5697c478bdstevel@tonic-gate
5707c478bdstevel@tonic-gate		/* make sure that things get started */
5717c478bdstevel@tonic-gate		(void) fas_istart(fas);
5727c478bdstevel@tonic-gate		fas_check_waitQ_and_mutex_exit(fas);
5737c478bdstevel@tonic-gate
5747c478bdstevel@tonic-gate		mutex_enter(&fas_global_mutex);
5757c478bdstevel@tonic-gate		if (fas_timeout_id == 0) {
5767c478bdstevel@tonic-gate			fas_timeout_id = timeout(fas_watch, NULL, fas_tick);
5777c478bdstevel@tonic-gate			fas_timeout_initted = 1;
5787c478bdstevel@tonic-gate		}
5797c478bdstevel@tonic-gate		mutex_exit(&fas_global_mutex);
5807c478bdstevel@tonic-gate
5817c478bdstevel@tonic-gate		return (DDI_SUCCESS);
5827c478bdstevel@tonic-gate
5837c478bdstevel@tonic-gate	default:
5847c478bdstevel@tonic-gate		return (DDI_FAILURE);
5857c478bdstevel@tonic-gate	}
5867c478bdstevel@tonic-gate
5877c478bdstevel@tonic-gate	instance = ddi_get_instance(dip);
5887c478bdstevel@tonic-gate
5897c478bdstevel@tonic-gate	/*
5907c478bdstevel@tonic-gate	 * Since we know that some instantiations of this device can
5917c478bdstevel@tonic-gate	 * be plugged into slave-only SBus slots, check to see whether
5927c478bdstevel@tonic-gate	 * this is one such.
5937c478bdstevel@tonic-gate	 */
5947c478bdstevel@tonic-gate	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
5957c478bdstevel@tonic-gate		cmn_err(CE_WARN,
5967c478bdstevel@tonic-gate		    "fas%d: device in slave-only slot", instance);
5977c478bdstevel@tonic-gate		return (DDI_FAILURE);
5987c478bdstevel@tonic-gate	}
5997c478bdstevel@tonic-gate
6007c478bdstevel@tonic-gate	if (ddi_intr_hilevel(dip, 0)) {
6017c478bdstevel@tonic-gate		/*
6027c478bdstevel@tonic-gate		 * Interrupt number '0' is a high-level interrupt.
6037c478bdstevel@tonic-gate		 * At this point you either add a special interrupt
6047c478bdstevel@tonic-gate		 * handler that triggers a soft interrupt at a lower level,
6057c478bdstevel@tonic-gate		 * or - more simply and appropriately here - you just
6067c478bdstevel@tonic-gate		 * fail the attach.
6077c478bdstevel@tonic-gate		 */
6087c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6097c478bdstevel@tonic-gate		    "fas%d: Device is using a hilevel intr", instance);
6107c478bdstevel@tonic-gate		return (DDI_FAILURE);
6117c478bdstevel@tonic-gate	}
6127c478bdstevel@tonic-gate
6137c478bdstevel@tonic-gate	/*
6147c478bdstevel@tonic-gate	 * Allocate softc information.
6157c478bdstevel@tonic-gate	 */
6167c478bdstevel@tonic-gate	if (ddi_soft_state_zalloc(fas_state, instance) != DDI_SUCCESS) {
6177c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6187c478bdstevel@tonic-gate		    "fas%d: cannot allocate soft state", instance);
6197c478bdstevel@tonic-gate		goto fail;
6207c478bdstevel@tonic-gate	}
6217c478bdstevel@tonic-gate
6227c478bdstevel@tonic-gate	fas = (struct fas *)ddi_get_soft_state(fas_state, instance);
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate	if (fas == NULL) {
6257c478bdstevel@tonic-gate		goto fail;
6267c478bdstevel@tonic-gate	}
6277c478bdstevel@tonic-gate
6287c478bdstevel@tonic-gate	/*
6297c478bdstevel@tonic-gate	 * map in device registers
6307c478bdstevel@tonic-gate	 */
6317c478bdstevel@tonic-gate	dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
6327c478bdstevel@tonic-gate	dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
6337c478bdstevel@tonic-gate	dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
6347c478bdstevel@tonic-gate
6357c478bdstevel@tonic-gate	if (ddi_regs_map_setup(dip, (uint_t)0, (caddr_t *)&dmar,
6367c478bdstevel@tonic-gate	    (off_t)0, (off_t)sizeof (struct dma),
6377c478bdstevel@tonic-gate	    &dev_attr, &fas->f_dmar_acc_handle) != DDI_SUCCESS) {
6387c478bdstevel@tonic-gate		cmn_err(CE_WARN, "fas%d: cannot map dma", instance);
6397c478bdstevel@tonic-gate		goto fail;
6407c478bdstevel@tonic-gate	}
6417c478bdstevel@tonic-gate
6427c478bdstevel@tonic-gate	if (ddi_regs_map_setup(dip, (uint_t)1, (caddr_t *)&fasreg,
6437c478bdstevel@tonic-gate	    (off_t)0, (off_t)sizeof (struct fasreg),
6447c478bdstevel@tonic-gate	    &dev_attr, &fas->f_regs_acc_handle) != DDI_SUCCESS) {
6457c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6467c478bdstevel@tonic-gate		    "fas%d: unable to map fas366 registers", instance);
6477c478bdstevel@tonic-gate		goto fail;
6487c478bdstevel@tonic-gate	}
6497c478bdstevel@tonic-gate
6507c478bdstevel@tonic-gate	fas_dma_attr = &dma_fasattr;
6517c478bdstevel@tonic-gate	if (ddi_dma_alloc_handle(dip, fas_dma_attr,
6527c478bdstevel@tonic-gate	    DDI_DMA_SLEEP, NULL, &fas->f_dmahandle) != DDI_SUCCESS) {
6537c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6547c478bdstevel@tonic-gate		    "fas%d: cannot alloc dma handle", instance);
6557c478bdstevel@tonic-gate		goto fail;
6567c478bdstevel@tonic-gate	}
6577c478bdstevel@tonic-gate
6587c478bdstevel@tonic-gate	/*
6597c478bdstevel@tonic-gate	 * allocate cmdarea and its dma handle
6607c478bdstevel@tonic-gate	 */
6617c478bdstevel@tonic-gate	if (ddi_dma_mem_alloc(fas->f_dmahandle,
6627c478bdstevel@tonic-gate	    (uint_t)2*FIFOSIZE,
6637c478bdstevel@tonic-gate	    &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
6647c478bdstevel@tonic-gate	    NULL, (caddr_t *)&fas->f_cmdarea, &rlen,
6651939740Sherry Moore	    &fas->f_cmdarea_acc_handle) != DDI_SUCCESS) {
6667c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6677c478bdstevel@tonic-gate		    "fas%d: cannot alloc cmd area", instance);
6687c478bdstevel@tonic-gate		goto fail;
6697c478bdstevel@tonic-gate	}
6707c478bdstevel@tonic-gate
6717c478bdstevel@tonic-gate	fas->f_reg = fasreg;
6727c478bdstevel@tonic-gate	fas->f_dma = dmar;
6737c478bdstevel@tonic-gate	fas->f_instance  = instance;
6747c478bdstevel@tonic-gate
6757c478bdstevel@tonic-gate	if (ddi_dma_addr_bind_handle(fas->f_dmahandle,
6767c478bdstevel@tonic-gate	    NULL, (caddr_t)fas->f_cmdarea,
6777c478bdstevel@tonic-gate	    rlen, DDI_DMA_RDWR|DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
6787c478bdstevel@tonic-gate	    &fas->f_dmacookie, &count) != DDI_DMA_MAPPED) {
6797c478bdstevel@tonic-gate		cmn_err(CE_WARN,
6807c478bdstevel@tonic-gate		    "fas%d: cannot bind cmdarea", instance);
6817c478bdstevel@tonic-gate		goto fail;
6827c478bdstevel@tonic-gate	}
6837c478bdstevel@tonic-gate	bound_handle++;
6847c478bdstevel@tonic-gate
6857c478bdstevel@tonic-gate	ASSERT(count == 1);
6867c478bdstevel@tonic-gate
6877c478bdstevel@tonic-gate	/*
6887c478bdstevel@tonic-gate	 * Allocate a transport structure
6897c478bdstevel@tonic-gate	 */
6907c478bdstevel@tonic-gate	tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP);
6917c478bdstevel@tonic-gate
692602ca9ecth	/* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
693602ca9ecth	scsi_size_clean(dip);		/* SCSI_SIZE_CLEAN_VERIFY ok */
694602ca9ecth
6957c478bdstevel@tonic-gate	/*
6967c478bdstevel@tonic-gate	 * initialize transport structure
6977c478bdstevel@tonic-gate	 */
6987c478bdstevel@tonic-gate	fas->f_tran			= tran;
6997c478bdstevel@tonic-gate	fas->f_dev			= dip;
7007c478bdstevel@tonic-gate	tran->tran_hba_private		= fas;
7017c478bdstevel@tonic-gate	tran->tran_tgt_private		= NULL;
7027c478bdstevel@tonic-gate	tran->tran_tgt_init		= fas_scsi_tgt_init;
7037c478bdstevel@tonic-gate	tran->tran_tgt_probe		= fas_scsi_tgt_probe;
7047c478bdstevel@tonic-gate	tran->tran_tgt_free		= NULL;
7057c478bdstevel@tonic-gate	tran->tran_start		= fas_scsi_start;
7067c478bdstevel@tonic-gate	tran->tran_abort		= fas_scsi_abort;
7077c478bdstevel@tonic-gate	tran->tran_reset		= fas_scsi_reset;
7087c478bdstevel@tonic-gate	tran->tran_getcap		= fas_scsi_getcap;
7097c478bdstevel@tonic-gate	tran->tran_setcap		= fas_scsi_setcap;
7107c478bdstevel@tonic-gate	tran->tran_init_pkt		= fas_scsi_init_pkt;
7117c478bdstevel@tonic-gate	tran->tran_destroy_pkt		= fas_scsi_destroy_pkt;
7127c478bdstevel@tonic-gate	tran->tran_dmafree		= fas_scsi_dmafree;
7137c478bdstevel@tonic-gate	tran->tran_sync_pkt		= fas_scsi_sync_pkt;
7147c478bdstevel@tonic-gate	tran->tran_reset_notify 	= fas_scsi_reset_notify;
7157c478bdstevel@tonic-gate	tran->tran_get_bus_addr		= NULL;
7167c478bdstevel@tonic-gate	tran->tran_get_name		= NULL;
7177c478bdstevel@tonic-gate	tran->tran_quiesce		= fas_scsi_quiesce;
7187c478bdstevel@tonic-gate	tran->tran_unquiesce		= fas_scsi_unquiesce;
7197c478bdstevel@tonic-gate	tran->tran_bus_reset		= NULL;
7207c478bdstevel@tonic-gate	tran->tran_add_eventcall	= NULL;
7217c478bdstevel@tonic-gate	tran->tran_get_eventcookie	= NULL;
7227c478bdstevel@tonic-gate	tran->tran_post_event		= NULL;
7237c478bdstevel@tonic-gate	tran->tran_remove_eventcall	= NULL;
7247c478bdstevel@tonic-gate
7257c478bdstevel@tonic-gate	fas->f_force_async = 0;
7267c478bdstevel@tonic-gate
7277c478bdstevel@tonic-gate	/*
7287c478bdstevel@tonic-gate	 * disable tagged queuing and wide for all targets
7297c478bdstevel@tonic-gate	 * (will be enabled by target driver if required)
7307c478bdstevel@tonic-gate	 * sync is enabled by default
7317c478bdstevel@tonic-gate	 */
7327c478bdstevel@tonic-gate	fas->f_nowide = fas->f_notag = ALL_TARGETS;
7337c478bdstevel@tonic-gate	fas->f_force_narrow = ALL_TARGETS;
7347c478bdstevel@tonic-gate
7357c478bdstevel@tonic-gate	/*
7367c478bdstevel@tonic-gate	 * By default we assume embedded devices and save time
7377c478bdstevel@tonic-gate	 * checking for timeouts in fas_watch() by skipping
7387c478bdstevel@tonic-gate	 * the rest of luns
7397c478bdstevel@tonic-gate	 * If we're talking to any non-embedded devices,
7407c478bdstevel@tonic-gate	 * we can't cheat and skip over non-zero luns anymore
7417c478bdstevel@tonic-gate	 * in fas_watch() and fas_ustart().
7427c478bdstevel@tonic-gate	 */
7437c478bdstevel@tonic-gate	fas->f_dslot = NLUNS_PER_TARGET;
7447c478bdstevel@tonic-gate
7457c478bdstevel@tonic-gate	/*
7467c478bdstevel@tonic-gate	 * f_active is used for saving disconnected cmds;
7477c478bdstevel@tonic-gate	 * For tagged targets, we need to increase the size later
7487c478bdstevel@tonic-gate	 * Only allocate for Lun == 0, if we probe a lun > 0 then
7497c478bdstevel@tonic-gate	 * we allocate an active structure
7507c478bdstevel@tonic-gate	 * If TQ gets enabled then we need to increase the size
7517c478bdstevel@tonic-gate	 * to hold 256 cmds
7527c478bdstevel@tonic-gate	 */
7537c478bdstevel@tonic-gate	for (slot = 0; slot < N_SLOTS; slot += NLUNS_PER_TARGET) {
7547c478bdstevel@tonic-gate		(void) fas_alloc_active_slots(fas, slot, KM_SLEEP);
7557c478bdstevel@tonic-gate	}
7567c478bdstevel@tonic-gate
7577c478bdstevel@tonic-gate	/*
7587c478bdstevel@tonic-gate	 * initialize the qfull retry counts
7597c478bdstevel@tonic-gate	 */
7607c478bdstevel@tonic-gate	for (i = 0; i < NTARGETS_WIDE; i++) {
7617c478bdstevel@tonic-gate		fas->f_qfull_retries[i] = QFULL_RETRIES;
7627c478bdstevel@tonic-gate		fas->f_qfull_retry_interval[i] =
7631939740Sherry Moore		    drv_usectohz(QFULL_RETRY_INTERVAL * 1000);
7647c478bdstevel@tonic-gate
7657c478bdstevel@tonic-gate	}
7667c478bdstevel@tonic-gate
7677c478bdstevel@tonic-gate	/*
7687c478bdstevel@tonic-gate	 * Initialize throttles.
7697c478bdstevel@tonic-gate	 */
7707c478bdstevel@tonic-gate	fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE);
7717c478bdstevel@tonic-gate
7727c478bdstevel@tonic-gate	/*
7737c478bdstevel@tonic-gate	 * Initialize mask of deferred property updates
7747c478bdstevel@tonic-gate	 */
7757c478bdstevel@tonic-gate	fas->f_props_update = 0;
7767c478bdstevel@tonic-gate
7777c478bdstevel@tonic-gate	/*
7787c478bdstevel@tonic-gate	 * set host ID
7797c478bdstevel@tonic-gate	 */
7807c478bdstevel@tonic-gate	fas->f_fasconf = DEFAULT_HOSTID;
7817c478bdstevel@tonic-gate	id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "initiator-id", -1);
7827c478bdstevel@tonic-gate	if (id == -1) {
7837c478bdstevel@tonic-gate		id = ddi_prop_get_int(DDI_DEV_T_ANY,	dip, 0,
7847c478bdstevel@tonic-gate		    "scsi-initiator-id", -1);
7857c478bdstevel@tonic-gate	}
7867c478bdstevel@tonic-gate	if (id != DEFAULT_HOSTID && id >= 0 && id < NTARGETS_WIDE) {
7877c478bdstevel@tonic-gate		fas_log(fas, CE_NOTE, "?initiator SCSI ID now %d\n", id);
7887c478bdstevel@tonic-gate		fas->f_fasconf = (uchar_t)id;
7897c478bdstevel@tonic-gate	}
7907c478bdstevel@tonic-gate
7917c478bdstevel@tonic-gate	/*
7927c478bdstevel@tonic-gate	 * find the burstsize and reduce ours if necessary
7937c478bdstevel@tonic-gate	 */
7947c478bdstevel@tonic-gate	fas->f_dma_attr = fas_dma_attr;
7957c478bdstevel@tonic-gate	fas->f_dma_attr->dma_attr_burstsizes &=
7967c478bdstevel@tonic-gate	    ddi_dma_burstsizes(fas->f_dmahandle);
7977c478bdstevel@tonic-gate
7987c478bdstevel@tonic-gate#ifdef FASDEBUG
7997c478bdstevel@tonic-gate	fas->f_dma_attr->dma_attr_burstsizes &= fas_burstsizes_limit;
8007c478bdstevel@tonic-gate	IPRINTF1("dma burstsize=%x\n", fas->f_dma_attr->dma_attr_burstsizes);
8017c478bdstevel@tonic-gate#endif
8027c478bdstevel@tonic-gate	/*
8037c478bdstevel@tonic-gate	 * Attach this instance of the hba
8047c478bdstevel@tonic-gate	 */
8057c478bdstevel@tonic-gate	if (scsi_hba_attach_setup(dip, fas->f_dma_attr, tran, 0) !=
8067c478bdstevel@tonic-gate	    DDI_SUCCESS) {
8077c478bdstevel@tonic-gate		fas_log(fas, CE_WARN, "scsi_hba_attach_setup failed");
8087c478bdstevel@tonic-gate		goto fail;
8097c478bdstevel@tonic-gate	}
8107c478bdstevel@tonic-gate	hba_attached++;
8117c478bdstevel@tonic-gate
8127c478bdstevel@tonic-gate	/*
8137c478bdstevel@tonic-gate	 * if scsi-options property exists, use it
8147c478bdstevel@tonic-gate	 */
8157c478bdstevel@tonic-gate	fas->f_scsi_options = ddi_prop_get_int(DDI_DEV_T_ANY,
8167c478bdstevel@tonic-gate	    dip, 0, "scsi-options", DEFAULT_SCSI_OPTIONS);
8177c478bdstevel@tonic-gate
8187c478bdstevel@tonic-gate	/*
8197c478bdstevel@tonic-gate	 * if scsi-selection-timeout property exists, use it
8207c478bdstevel@tonic-gate	 */
8217c478bdstevel@tonic-gate	fas_selection_timeout = ddi_prop_get_int(DDI_DEV_T_ANY,
8227c478bdstevel@tonic-gate	    dip, 0, "scsi-selection-timeout", SCSI_DEFAULT_SELECTION_TIMEOUT);
8237c478bdstevel@tonic-gate
8247c478bdstevel@tonic-gate	/*
8257c478bdstevel@tonic-gate	 * if hm-rev property doesn't exist, use old scheme for rev
8267c478bdstevel@tonic-gate	 */
8277c478bdstevel@tonic-gate	hm_rev = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
8287c478bdstevel@tonic-gate	    "hm-rev", -1);
8297c478bdstevel@tonic-gate
8307c478bdstevel@tonic-gate	if (hm_rev == 0xa0 || hm_rev == -1) {
8317c478bdstevel@tonic-gate		if (DMAREV(dmar) != 0) {
8327c478bdstevel@tonic-gate			fas->f_hm_rev = 0x20;
8337c478bdstevel@tonic-gate			fas_log(fas, CE_WARN,
8347c478bdstevel@tonic-gate			    "obsolete rev 2.0 FEPS chip, "
8357c478bdstevel@tonic-gate			    "possible data corruption");
8367c478bdstevel@tonic-gate		} else {
8377c478bdstevel@tonic-gate			fas->f_hm_rev = 0x10;
8387c478bdstevel@tonic-gate			fas_log(fas, CE_WARN,
8397c478bdstevel@tonic-gate			    "obsolete and unsupported rev 1.0 FEPS chip");
8407c478bdstevel@tonic-gate			goto fail;
8417c478bdstevel@tonic-gate		}
8427c478bdstevel@tonic-gate	} else if (hm_rev == 0x20) {
8437c478bdstevel@tonic-gate		fas->f_hm_rev = 0x21;
8447c478bdstevel@tonic-gate		fas_log(fas, CE_WARN, "obsolete rev 2.1 FEPS chip");
8457c478bdstevel@tonic-gate	} else {
8467c478bdstevel@tonic-gate		fas->f_hm_rev = (uchar_t)hm_rev;
8477c478bdstevel@tonic-gate		fas_log(fas, CE_NOTE, "?rev %x.%x FEPS chip\n",
8487c478bdstevel@tonic-gate		    (hm_rev >> 4) & 0xf, hm_rev & 0xf);
8497c478bdstevel@tonic-gate	}
8507c478bdstevel@tonic-gate
8517c478bdstevel@tonic-gate	if ((fas->f_scsi_options & SCSI_OPTIONS_SYNC) == 0) {
8527c478bdstevel@tonic-gate		fas->f_nosync = ALL_TARGETS;
8537c478bdstevel@tonic-gate	}
8547c478bdstevel@tonic-gate
8557c478bdstevel@tonic-gate	if ((fas->f_scsi_options & SCSI_OPTIONS_WIDE) == 0) {
8567c478bdstevel@tonic-gate		fas->f_nowide = ALL_TARGETS;
8577c478bdstevel@tonic-gate	}
8587c478bdstevel@tonic-gate
8597c478bdstevel@tonic-gate	/*
8607c478bdstevel@tonic-gate	 * if target<n>-scsi-options property exists, use it;
8617c478bdstevel@tonic-gate	 * otherwise use the f_scsi_options
8627c478bdstevel@tonic-gate	 */
8637c478bdstevel@tonic-gate	for (i = 0; i < NTARGETS_WIDE; i++) {
8647c478bdstevel@tonic-gate		(void) sprintf(prop_str, prop_template, i);
8657c478bdstevel@tonic-gate		fas->f_target_scsi_options[i] = ddi_prop_get_int(
8661939740Sherry Moore		    DDI_DEV_T_ANY, dip, 0, prop_str, -1);
8677c478bdstevel@tonic-gate
8687c478bdstevel@tonic-gate		if (fas->f_target_scsi_options[i] != -1) {
8697c478bdstevel@tonic-gate			fas_log(fas, CE_NOTE, "?target%x-scsi-options=0x%x\n",
8707c478bdstevel@tonic-gate			    i, fas->f_target_scsi_options[i]);
8717c478bdstevel@tonic-gate			fas->f_target_scsi_options_defined |= 1 << i;
8727c478bdstevel@tonic-gate		} else {
8737c478bdstevel@tonic-gate			fas->f_target_scsi_options[i] = fas->f_scsi_options;
8747c478bdstevel@tonic-gate		}
8757c478bdstevel@tonic-gate		if (((fas->f_target_scsi_options[i] &
8767c478bdstevel@tonic-gate		    SCSI_OPTIONS_DR) == 0) &&
8777c478bdstevel@tonic-gate		    (fas->f_target_scsi_options[i] & SCSI_OPTIONS_TAG)) {
8787c478bdstevel@tonic-gate			fas->f_target_scsi_options[i] &= ~SCSI_OPTIONS_TAG;
8797c478bdstevel@tonic-gate			fas_log(fas, CE_WARN,
8807c478bdstevel@tonic-gate			    "Disabled TQ since disconnects are disabled");
8817c478bdstevel@tonic-gate		}
8827c478bdstevel@tonic-gate	}
8837c478bdstevel@tonic-gate
8847c478bdstevel@tonic-gate	fas->f_scsi_tag_age_limit =
8857c478bdstevel@tonic-gate	    ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "scsi-tag-age-limit",
8861939740Sherry Moore	    DEFAULT_TAG_AGE_LIMIT);
8877c478bdstevel@tonic-gate
8887c478bdstevel@tonic-gate	fas->f_scsi_reset_delay = ddi_prop_get_int(DDI_DEV_T_ANY,
8897c478bdstevel@tonic-gate	    dip, 0, "scsi-reset-delay", SCSI_DEFAULT_RESET_DELAY);
8907c478bdstevel@tonic-gate	if (fas->f_scsi_reset_delay == 0) {
8917c478bdstevel@tonic-gate		fas_log(fas, CE_NOTE,
8921939740Sherry Moore		    "scsi_reset_delay of 0 is not recommended,"
8931939740Sherry Moore		    " resetting to SCSI_DEFAULT_RESET_DELAY\n");
8947c478bdstevel@tonic-gate		fas->f_scsi_reset_delay = SCSI_DEFAULT_RESET_DELAY;
8957c478bdstevel@tonic-gate	}
8967c478bdstevel@tonic-gate
8977c478bdstevel@tonic-gate	/*
8987c478bdstevel@tonic-gate	 * get iblock cookie and initialize mutexes
8997c478bdstevel@tonic-gate	 */
9007c478bdstevel@tonic-gate	if (ddi_get_iblock_cookie(dip, (uint_t)0, &fas->f_iblock)
9017c478bdstevel@tonic-gate	    != DDI_SUCCESS) {
9027c478bdstevel@tonic-gate		cmn_err(CE_WARN, "fas_attach: cannot get iblock cookie");
9037c478bdstevel@tonic-gate		goto fail;
9047c478bdstevel@tonic-gate	}
9057c478bdstevel@tonic-gate
9067c478bdstevel@tonic-gate	mutex_init(&fas->f_mutex, NULL, MUTEX_DRIVER, fas->f_iblock);
9077c478bdstevel@tonic-gate	cv_init(&fas->f_cv, NULL, CV_DRIVER, NULL);
9087c478bdstevel@tonic-gate
9097c478bdstevel@tonic-gate	/*
9107c478bdstevel@tonic-gate	 * initialize mutex for waitQ
9117c478bdstevel@tonic-gate	 */
9127c478bdstevel@tonic-gate	mutex_init(&fas->f_waitQ_mutex, NULL, MUTEX_DRIVER, fas->f_iblock);
9137c478bdstevel@tonic-gate	mutex_init_done++;
9147c478bdstevel@tonic-gate
9157c478bdstevel@tonic-gate	/*
9167c478bdstevel@tonic-gate	 * initialize callback mechanism (immediate callback)
9177c478bdstevel@tonic-gate	 */
9187c478bdstevel@tonic-gate	mutex_enter(&fas_global_mutex);
9197c478bdstevel@tonic-gate	if (fas_init_callbacks(fas)) {
9207c478bdstevel@tonic-gate		mutex_exit(&fas_global_mutex);
9217c478bdstevel@tonic-gate		goto fail;
9227c478bdstevel@tonic-gate	}
9237c478bdstevel@tonic-gate	mutex_exit(&fas_global_mutex);
9247c478bdstevel@tonic-gate
9257c478bdstevel@tonic-gate	/*
9267c478bdstevel@tonic-gate	 * kstat_intr support
9277c478bdstevel@tonic-gate	 */
9287c478bdstevel@tonic-gate	(void) sprintf(buf, "fas%d", instance);
9297c478bdstevel@tonic-gate	fas->f_intr_kstat = kstat_create("fas", instance, buf, "controller", \
9301939740Sherry Moore	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
9317c478bdstevel@tonic-gate	if (fas->f_intr_kstat)
9327c478bdstevel@tonic-gate		kstat_install(fas->f_intr_kstat);
9337c478bdstevel@tonic-gate
9347c478bdstevel@tonic-gate	/*
9357c478bdstevel@tonic-gate	 * install interrupt handler
9367c478bdstevel@tonic-gate	 */
9377c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
9387c478bdstevel@tonic-gate	if (ddi_add_intr(dip, (uint_t)0, &fas->f_iblock, NULL,
9397c478bdstevel@tonic-gate	    fas_intr, (caddr_t)fas)) {
9407c478bdstevel@tonic-gate		cmn_err(CE_WARN, "fas: cannot add intr");
9417c478bdstevel@tonic-gate		mutex_exit(FAS_MUTEX(fas));
9427c478bdstevel@tonic-gate		goto fail;
9437c478bdstevel@tonic-gate	}
9447c478bdstevel@tonic-gate	intr_added++;
9457c478bdstevel@tonic-gate
9467c478bdstevel@tonic-gate	/*
9477c478bdstevel@tonic-gate	 * initialize fas chip
9487c478bdstevel@tonic-gate	 */
9497c478bdstevel@tonic-gate	if (fas_init_chip(fas, id))	{
9507c478bdstevel@tonic-gate		cmn_err(CE_WARN, "fas: cannot initialize");
9517c478bdstevel@tonic-gate		mutex_exit(FAS_MUTEX(fas));
9527c478bdstevel@tonic-gate		goto fail;
9537c478bdstevel@tonic-gate	}
9547c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
9557c478bdstevel@tonic-gate
9567c478bdstevel@tonic-gate	/*
9577c478bdstevel@tonic-gate	 * create kmem cache for packets
9587c478bdstevel@tonic-gate	 */
9597c478bdstevel@tonic-gate	(void) sprintf(buf, "fas%d_cache", instance);
9607c478bdstevel@tonic-gate	fas->f_kmem_cache = kmem_cache_create(buf,
9611939740Sherry Moore	    EXTCMD_SIZE, 8,
9621939740Sherry Moore	    fas_kmem_cache_constructor, fas_kmem_cache_destructor,
9631939740Sherry Moore	    NULL, (void *)fas, NULL, 0);
9647c478bdstevel@tonic-gate	if (fas->f_kmem_cache == NULL) {
9657c478bdstevel@tonic-gate		cmn_err(CE_WARN, "fas: cannot create kmem_cache");
9667c478bdstevel@tonic-gate		goto fail;
9677c478bdstevel@tonic-gate	}
9687c478bdstevel@tonic-gate
9697c478bdstevel@tonic-gate	/*
9707c478bdstevel@tonic-gate	 * at this point, we are not going to fail the attach
9717c478bdstevel@tonic-gate	 * so there is no need to undo the rest:
9727c478bdstevel@tonic-gate	 *
9737c478bdstevel@tonic-gate	 * add this fas to the list, this makes debugging easier
9747c478bdstevel@tonic-gate	 * and fas_watch() needs it to walk thru all fas's
9757c478bdstevel@tonic-gate	 */
9767c478bdstevel@tonic-gate	rw_enter(&fas_global_rwlock, RW_WRITER);
9777c478bdstevel@tonic-gate	if (fas_head == NULL) {
9787c478bdstevel@tonic-gate		fas_head = fas;
9797c478bdstevel@tonic-gate	} else {
9807c478bdstevel@tonic-gate		fas_tail->f_next = fas;
9817c478bdstevel@tonic-gate	}
9827c478bdstevel@tonic-gate	fas_tail = fas; 	/* point to last fas in list */
9837c478bdstevel@tonic-gate	rw_exit(&fas_global_rwlock);
9847c478bdstevel@tonic-gate
9857c478bdstevel@tonic-gate	/*
9867c478bdstevel@tonic-gate	 * there is one watchdog handler for all driver instances.
9877c478bdstevel@tonic-gate	 * start the watchdog if it hasn't been done yet
9887c478bdstevel@tonic-gate	 */
9897c478bdstevel@tonic-gate	mutex_enter(&fas_global_mutex);
9907c478bdstevel@tonic-gate	if (fas_scsi_watchdog_tick == 0) {
9917c478bdstevel@tonic-gate		fas_scsi_watchdog_tick = ddi_prop_get_int(DDI_DEV_T_ANY,
9921939740Sherry Moore		    dip, 0, "scsi-watchdog-tick", DEFAULT_WD_TICK);
9937c478bdstevel@tonic-gate		if (fas_scsi_watchdog_tick != DEFAULT_WD_TICK) {
9947c478bdstevel@tonic-gate			fas_log(fas, CE_NOTE, "?scsi-watchdog-tick=%d\n",
9957c478bdstevel@tonic-gate			    fas_scsi_watchdog_tick);
9967c478bdstevel@tonic-gate		}
9977c478bdstevel@tonic-gate		fas_tick = drv_usectohz((clock_t)
9987c478bdstevel@tonic-gate		    fas_scsi_watchdog_tick * 1000000);
9997c478bdstevel@tonic-gate		IPRINTF2("fas scsi watchdog tick=%x, fas_tick=%lx\n",
10007c478bdstevel@tonic-gate		    fas_scsi_watchdog_tick, fas_tick);
10017c478bdstevel@tonic-gate		if (fas_timeout_id == 0) {
10027c478bdstevel@tonic-gate			fas_timeout_id = timeout(fas_watch, NULL, fas_tick);
10037c478bdstevel@tonic-gate			fas_timeout_initted = 1;
10047c478bdstevel@tonic-gate		}
10057c478bdstevel@tonic-gate	}
10067c478bdstevel@tonic-gate	mutex_exit(&fas_global_mutex);
10077c478bdstevel@tonic-gate
10087c478bdstevel@tonic-gate	ddi_report_dev(dip);
10097c478bdstevel@tonic-gate
10107c478bdstevel@tonic-gate	return (DDI_SUCCESS);
10117c478bdstevel@tonic-gate
10127c478bdstevel@tonic-gatefail:
10137c478bdstevel@tonic-gate	cmn_err(CE_WARN, "fas%d: cannot attach", instance);
10147c478bdstevel@tonic-gate	if (fas) {
10157c478bdstevel@tonic-gate		for (slot = 0; slot < N_SLOTS; slot++) {
10167c478bdstevel@tonic-gate			struct f_slots *active = fas->f_active[slot];
10177c478bdstevel@tonic-gate			if (active) {
10187c478bdstevel@tonic-gate				kmem_free(active, active->f_size);
10197c478bdstevel@tonic-gate				fas->f_active[slot] = NULL;
10207c478bdstevel@tonic-gate			}
10217c478bdstevel@tonic-gate		}
10227c478bdstevel@tonic-gate		if (mutex_init_done) {
10237c478bdstevel@tonic-gate			mutex_destroy(&fas->f_mutex);
10247c478bdstevel@tonic-gate			mutex_destroy(&fas->f_waitQ_mutex);
10257c478bdstevel@tonic-gate			cv_destroy(&fas->f_cv);
10267c478bdstevel@tonic-gate		}
10277c478bdstevel@tonic-gate		if (intr_added) {
10287c478bdstevel@tonic-gate			ddi_remove_intr(dip, (uint_t)0, fas->f_iblock);
10297c478bdstevel@tonic-gate		}
10307c478bdstevel@tonic-gate		/*
10317c478bdstevel@tonic-gate		 * kstat_intr support
10327c478bdstevel@tonic-gate		 */
10337c478bdstevel@tonic-gate		if (fas->f_intr_kstat) {
10347c478bdstevel@tonic-gate			kstat_delete(fas->f_intr_kstat);
10357c478bdstevel@tonic-gate		}
10367c478bdstevel@tonic-gate		if (hba_attached) {
10377c478bdstevel@tonic-gate			(void) scsi_hba_detach(dip);
10387c478bdstevel@tonic-gate		}
10397c478bdstevel@tonic-gate		if (tran) {
10407c478bdstevel@tonic-gate			scsi_hba_tran_free(tran);
10417c478bdstevel@tonic-gate		}
10427c478bdstevel@tonic-gate		if (fas->f_kmem_cache) {
10437c478bdstevel@tonic-gate			kmem_cache_destroy(fas->f_kmem_cache);
10447c478bdstevel@tonic-gate		}
10457c478bdstevel@tonic-gate		if (fas->f_cmdarea) {
10467c478bdstevel@tonic-gate			if (bound_handle) {
10477c478bdstevel@tonic-gate				(void) ddi_dma_unbind_handle(fas->f_dmahandle);
10487c478bdstevel@tonic-gate			}
10497c478bdstevel@tonic-gate			ddi_dma_mem_free(&fas->f_cmdarea_acc_handle);
10507c478bdstevel@tonic-gate		}
10517c478bdstevel@tonic-gate		if (fas->f_dmahandle) {
10527c478bdstevel@tonic-gate			ddi_dma_free_handle(&fas->f_dmahandle);
10537c478bdstevel@tonic-gate		}
10547c478bdstevel@tonic-gate		fas_destroy_callbacks(fas);
10557c478bdstevel@tonic-gate		if (fas->f_regs_acc_handle) {
10567c478bdstevel@tonic-gate			ddi_regs_map_free(&fas->f_regs_acc_handle);
10577c478bdstevel@tonic-gate		}
10587c478bdstevel@tonic-gate		if (fas->f_dmar_acc_handle) {
10597c478bdstevel@tonic-gate			ddi_regs_map_free(&fas->f_dmar_acc_handle);
10607c478bdstevel@tonic-gate		}
10617c478bdstevel@tonic-gate		ddi_soft_state_free(fas_state, instance);
10627c478bdstevel@tonic-gate
10637c478bdstevel@tonic-gate		ddi_remove_minor_node(dip, NULL);
10647c478bdstevel@tonic-gate	}
10657c478bdstevel@tonic-gate	return (DDI_FAILURE);
10667c478bdstevel@tonic-gate}
10677c478bdstevel@tonic-gate
10687c478bdstevel@tonic-gate/*ARGSUSED*/
10697c478bdstevel@tonic-gatestatic int
10707c478bdstevel@tonic-gatefas_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
10717c478bdstevel@tonic-gate{
10727c478bdstevel@tonic-gate	struct fas	*fas, *nfas;
10737c478bdstevel@tonic-gate	scsi_hba_tran_t 	*tran;
10747c478bdstevel@tonic-gate
10757c478bdstevel@tonic-gate	/* CONSTCOND */
10767c478bdstevel@tonic-gate	ASSERT(NO_COMPETING_THREADS);
10777c478bdstevel@tonic-gate
10787c478bdstevel@tonic-gate	switch (cmd) {
10797c478bdstevel@tonic-gate	case DDI_DETACH:
10807c478bdstevel@tonic-gate		return (fas_dr_detach(dip));
10817c478bdstevel@tonic-gate
10827c478bdstevel@tonic-gate	case DDI_SUSPEND:
10837c478bdstevel@tonic-gate		if ((tran = ddi_get_driver_private(dip)) == NULL)
10847c478bdstevel@tonic-gate			return (DDI_FAILURE);
10857c478bdstevel@tonic-gate
10867c478bdstevel@tonic-gate		fas = TRAN2FAS(tran);
10877c478bdstevel@tonic-gate		if (!fas) {
10887c478bdstevel@tonic-gate			return (DDI_FAILURE);
10897c478bdstevel@tonic-gate		}
10907c478bdstevel@tonic-gate
10917c478bdstevel@tonic-gate		mutex_enter(FAS_MUTEX(fas));
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gate		fas->f_suspended = 1;
10947c478bdstevel@tonic-gate
10957c478bdstevel@tonic-gate		if (fas->f_ncmds) {
10967c478bdstevel@tonic-gate			(void) fas_reset_bus(fas);
10977c478bdstevel@tonic-gate			(void) fas_dopoll(fas, SHORT_POLL_TIMEOUT);
10987c478bdstevel@tonic-gate		}
10997c478bdstevel@tonic-gate		/*
11007c478bdstevel@tonic-gate		 * disable dma and fas interrupt
11017c478bdstevel@tonic-gate		 */
11027c478bdstevel@tonic-gate		fas->f_dma_csr &= ~DMA_INTEN;
11037c478bdstevel@tonic-gate		fas->f_dma_csr &= ~DMA_ENDVMA;
11047c478bdstevel@tonic-gate		fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr);
11057c478bdstevel@tonic-gate
11067c478bdstevel@tonic-gate		mutex_exit(FAS_MUTEX(fas));
11077c478bdstevel@tonic-gate
11087c478bdstevel@tonic-gate		if (fas->f_quiesce_timeid) {
11097c478bdstevel@tonic-gate			(void) untimeout(fas->f_quiesce_timeid);
11107c478bdstevel@tonic-gate				fas->f_quiesce_timeid = 0;
11117c478bdstevel@tonic-gate		}
11127c478bdstevel@tonic-gate
11137c478bdstevel@tonic-gate		if (fas->f_restart_cmd_timeid) {
11147c478bdstevel@tonic-gate			(void) untimeout(fas->f_restart_cmd_timeid);
11157c478bdstevel@tonic-gate				fas->f_restart_cmd_timeid = 0;
11167c478bdstevel@tonic-gate		}
11177c478bdstevel@tonic-gate
11187c478bdstevel@tonic-gate		/* Last fas? */
11197c478bdstevel@tonic-gate		rw_enter(&fas_global_rwlock, RW_WRITER);
11207c478bdstevel@tonic-gate		for (nfas = fas_head; nfas; nfas = nfas->f_next) {
11217c478bdstevel@tonic-gate			if (!nfas->f_suspended) {
11227c478bdstevel@tonic-gate				rw_exit(&fas_global_rwlock);
11237c478bdstevel@tonic-gate				return (DDI_SUCCESS);
11247c478bdstevel@tonic-gate			}
11257c478bdstevel@tonic-gate		}
11267c478bdstevel@tonic-gate		rw_exit(&fas_global_rwlock);
11277c478bdstevel@tonic-gate
11287c478bdstevel@tonic-gate		mutex_enter(&fas_global_mutex);
11297c478bdstevel@tonic-gate		if (fas_timeout_id != 0) {
11307c478bdstevel@tonic-gate			timeout_id_t tid = fas_timeout_id;
11317c478bdstevel@tonic-gate			fas_timeout_id = 0;
11327c478bdstevel@tonic-gate			fas_timeout_initted = 0;
11337c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
11347c478bdstevel@tonic-gate			(void) untimeout(tid);
11357c478bdstevel@tonic-gate		} else {
11367c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
11377c478bdstevel@tonic-gate		}
11387c478bdstevel@tonic-gate
11397c478bdstevel@tonic-gate		mutex_enter(&fas_global_mutex);
11407c478bdstevel@tonic-gate		if (fas_reset_watch) {
11417c478bdstevel@tonic-gate			timeout_id_t tid = fas_reset_watch;
11427c478bdstevel@tonic-gate			fas_reset_watch = 0;
11437c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
11447c478bdstevel@tonic-gate			(void) untimeout(tid);
11457c478bdstevel@tonic-gate		} else {
11467c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
11477c478bdstevel@tonic-gate		}
11487c478bdstevel@tonic-gate
11497c478bdstevel@tonic-gate		return (DDI_SUCCESS);
11507c478bdstevel@tonic-gate
11517c478bdstevel@tonic-gate	default:
11527c478bdstevel@tonic-gate		return (DDI_FAILURE);
11537c478bdstevel@tonic-gate	}
11547c478bdstevel@tonic-gate	_NOTE(NOT_REACHED)
11557c478bdstevel@tonic-gate	/* NOTREACHED */
11567c478bdstevel@tonic-gate}
11577c478bdstevel@tonic-gate
11587c478bdstevel@tonic-gatestatic int
11597c478bdstevel@tonic-gatefas_dr_detach(dev_info_t *dip)
11607c478bdstevel@tonic-gate{
11617c478bdstevel@tonic-gate	struct fas 	*fas, *f;
11627c478bdstevel@tonic-gate	scsi_hba_tran_t		*tran;
11637c478bdstevel@tonic-gate	short		slot;
11647c478bdstevel@tonic-gate	int			i, j;
11657c478bdstevel@tonic-gate
11667c478bdstevel@tonic-gate	if ((tran = ddi_get_driver_private(dip)) == NULL)
11677c478bdstevel@tonic-gate		return (DDI_FAILURE);
11687c478bdstevel@tonic-gate
11697c478bdstevel@tonic-gate	fas = TRAN2FAS(tran);
11707c478bdstevel@tonic-gate	if (!fas) {
11717c478bdstevel@tonic-gate		return (DDI_FAILURE);
11727c478bdstevel@tonic-gate	}
11737c478bdstevel@tonic-gate
11747c478bdstevel@tonic-gate	/*
11757c478bdstevel@tonic-gate	 * disable interrupts
11767c478bdstevel@tonic-gate	 */
11777c478bdstevel@tonic-gate	fas->f_dma_csr &= ~DMA_INTEN;
11787c478bdstevel@tonic-gate	fas->f_dma->dma_csr = fas->f_dma_csr;
11797c478bdstevel@tonic-gate	ddi_remove_intr(dip, (uint_t)0, fas->f_iblock);
11807c478bdstevel@tonic-gate
11817c478bdstevel@tonic-gate	/*
11827c478bdstevel@tonic-gate	 * Remove device instance from the global linked list
11837c478bdstevel@tonic-gate	 */
11847c478bdstevel@tonic-gate	rw_enter(&fas_global_rwlock, RW_WRITER);
11857c478bdstevel@tonic-gate
11867c478bdstevel@tonic-gate	if (fas_head == fas) {
11877c478bdstevel@tonic-gate		f = fas_head = fas->f_next;
11887c478bdstevel@tonic-gate	} else {
11897c478bdstevel@tonic-gate		for (f = fas_head; f != (struct fas *)NULL; f = f->f_next) {
11907c478bdstevel@tonic-gate			if (f->f_next == fas) {
11917c478bdstevel@tonic-gate				f->f_next = fas->f_next;
11927c478bdstevel@tonic-gate				break;
11937c478bdstevel@tonic-gate			}
11947c478bdstevel@tonic-gate		}
11957c478bdstevel@tonic-gate
11967c478bdstevel@tonic-gate		/*
11977c478bdstevel@tonic-gate		 * Instance not in softc list. Since the
11987c478bdstevel@tonic-gate		 * instance is not there in softc list, don't
11997c478bdstevel@tonic-gate		 * enable interrupts, the instance is effectively
12007c478bdstevel@tonic-gate		 * unusable.
12017c478bdstevel@tonic-gate		 */
12027c478bdstevel@tonic-gate		if (f == (struct fas *)NULL) {
12037c478bdstevel@tonic-gate			cmn_err(CE_WARN, "fas_dr_detach: fas instance not"
12041939740Sherry Moore			    " in softc list!");
12057c478bdstevel@tonic-gate			rw_exit(&fas_global_rwlock);
12067c478bdstevel@tonic-gate			return (DDI_FAILURE);
12077c478bdstevel@tonic-gate		}
12087c478bdstevel@tonic-gate
12097c478bdstevel@tonic-gate
12107c478bdstevel@tonic-gate	}
12117c478bdstevel@tonic-gate
12127c478bdstevel@tonic-gate	if (fas_tail == fas)
12137c478bdstevel@tonic-gate		fas_tail = f;
12147c478bdstevel@tonic-gate
12157c478bdstevel@tonic-gate	rw_exit(&fas_global_rwlock);
12167c478bdstevel@tonic-gate
12177c478bdstevel@tonic-gate	if (fas->f_intr_kstat)
12187c478bdstevel@tonic-gate		kstat_delete(fas->f_intr_kstat);
12197c478bdstevel@tonic-gate
12207c478bdstevel@tonic-gate	fas_destroy_callbacks(fas);
12217c478bdstevel@tonic-gate
12227c478bdstevel@tonic-gate	scsi_hba_reset_notify_tear_down(fas->f_reset_notify_listf);
12237c478bdstevel@tonic-gate
12247c478bdstevel@tonic-gate	mutex_enter(&fas_global_mutex);
12257c478bdstevel@tonic-gate	/*
12267c478bdstevel@tonic-gate	 * destroy any outstanding tagged command info
12277c478bdstevel@tonic-gate	 */
12287c478bdstevel@tonic-gate	for (slot = 0; slot < N_SLOTS; slot++) {
12297c478bdstevel@tonic-gate		struct f_slots *active = fas->f_active[slot];
12307c478bdstevel@tonic-gate		if (active) {
12317c478bdstevel@tonic-gate			ushort_t	tag;
12327c478bdstevel@tonic-gate			for (tag = 0; tag < active->f_n_slots; tag++) {
12337c478bdstevel@tonic-gate				struct fas_cmd	*sp = active->f_slot[tag];
12347c478bdstevel@tonic-gate				if (sp) {
12357c478bdstevel@tonic-gate					struct scsi_pkt *pkt = sp->cmd_pkt;
12367c478bdstevel@tonic-gate					if (pkt) {
12377c478bdstevel@tonic-gate						(void) fas_scsi_destroy_pkt(
12387c478bdstevel@tonic-gate						    &pkt->pkt_address, pkt);
12397c478bdstevel@tonic-gate					}
12407c478bdstevel@tonic-gate					/* sp freed in fas_scsi_destroy_pkt */
12417c478bdstevel@tonic-gate					active->f_slot[tag] = NULL;
12427c478bdstevel@tonic-gate				}
12437c478bdstevel@tonic-gate			}
12447c478bdstevel@tonic-gate			kmem_free(active, active->f_size);
12457c478bdstevel@tonic-gate			fas->f_active[slot] = NULL;
12467c478bdstevel@tonic-gate		}
12477c478bdstevel@tonic-gate		ASSERT(fas->f_tcmds[slot] == 0);
12487c478bdstevel@tonic-gate	}
12497c478bdstevel@tonic-gate
12507c478bdstevel@tonic-gate	/*
12517c478bdstevel@tonic-gate	 * disallow timeout thread rescheduling
12527c478bdstevel@tonic-gate	 */
12537c478bdstevel@tonic-gate	fas->f_flags |= FAS_FLG_NOTIMEOUTS;
12547c478bdstevel@tonic-gate	mutex_exit(&fas_global_mutex);
12557c478bdstevel@tonic-gate
12567c478bdstevel@tonic-gate	if (fas->f_quiesce_timeid) {
12577c478bdstevel@tonic-gate		(void) untimeout(fas->f_quiesce_timeid);
12587c478bdstevel@tonic-gate	}
12597c478bdstevel@tonic-gate
12607c478bdstevel@tonic-gate	/*
12617c478bdstevel@tonic-gate	 * last fas? ... if active, CANCEL watch threads.
12627c478bdstevel@tonic-gate	 */
12637c478bdstevel@tonic-gate	mutex_enter(&fas_global_mutex);
12647c478bdstevel@tonic-gate	if (fas_head == (struct fas *)NULL) {
12657c478bdstevel@tonic-gate		if (fas_timeout_initted) {
12667c478bdstevel@tonic-gate			timeout_id_t tid = fas_timeout_id;
12677c478bdstevel@tonic-gate			fas_timeout_initted = 0;
12687c478bdstevel@tonic-gate			fas_timeout_id = 0;		/* don't resched */
12697c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
12707c478bdstevel@tonic-gate			(void) untimeout(tid);
12717c478bdstevel@tonic-gate			mutex_enter(&fas_global_mutex);
12727c478bdstevel@tonic-gate		}
12737c478bdstevel@tonic-gate
12747c478bdstevel@tonic-gate		if (fas_reset_watch) {
12757c478bdstevel@tonic-gate			mutex_exit(&fas_global_mutex);
12767c478bdstevel@tonic-gate			(void) untimeout(fas_reset_watch);
12777c478bdstevel@tonic-gate			mutex_enter(&fas_global_mutex);
12787c478bdstevel@tonic-gate			fas_reset_watch = 0;
12797c478bdstevel@tonic-gate		}
12807c478bdstevel@tonic-gate	}
12817c478bdstevel@tonic-gate	mutex_exit(&fas_global_mutex);
12827c478bdstevel@tonic-gate
12837c478bdstevel@tonic-gate	if (fas->f_restart_cmd_timeid) {
12847c478bdstevel@tonic-gate		(void) untimeout(fas->f_restart_cmd_timeid);
12857c478bdstevel@tonic-gate		fas->f_restart_cmd_timeid = 0;
12867c478bdstevel@tonic-gate	}
12877c478bdstevel@tonic-gate
12887c478bdstevel@tonic-gate	/*
12897c478bdstevel@tonic-gate	 * destroy outstanding ARQ pkts
12907c478bdstevel@tonic-gate	 */
12917c478bdstevel@tonic-gate	for (i = 0; i < NTARGETS_WIDE; i++) {
12927c478bdstevel@tonic-gate		for (j = 0; j < NLUNS_PER_TARGET; j++) {
12937c478bdstevel@tonic-gate			int slot = i * NLUNS_PER_TARGET | j;
12947c478bdstevel@tonic-gate			if (fas->f_arq_pkt[slot]) {
12957c478bdstevel@tonic-gate				struct scsi_address	sa;
12967c478bdstevel@tonic-gate				sa.a_hba_tran = NULL;		/* not used */
12977c478bdstevel@tonic-gate				sa.a_target = (ushort_t)i;
12987c478bdstevel@tonic-gate				sa.a_lun = (uchar_t)j;
12997c478bdstevel@tonic-gate				(void) fas_delete_arq_pkt(fas, &sa);
13007c478bdstevel@tonic-gate			}
13017c478bdstevel@tonic-gate		}
13027c478bdstevel@tonic-gate	}
13037c478bdstevel@tonic-gate
13047c478bdstevel@tonic-gate	/*
13057c478bdstevel@tonic-gate	 * Remove device MT locks and CV
13067c478bdstevel@tonic-gate	 */
13077c478bdstevel@tonic-gate	mutex_destroy(&fas->f_waitQ_mutex);
13087c478bdstevel@tonic-gate	mutex_destroy(&fas->f_mutex);
13097c478bdstevel@tonic-gate	cv_destroy(&fas->f_cv);
13107c478bdstevel@tonic-gate
13117c478bdstevel@tonic-gate	/*
13127c478bdstevel@tonic-gate	 * Release miscellaneous device resources
13137c478bdstevel@tonic-gate	 */
13147c478bdstevel@tonic-gate
13157c478bdstevel@tonic-gate	if (fas->f_kmem_cache) {
13167c478bdstevel@tonic-gate		kmem_cache_destroy(fas->f_kmem_cache);
13177c478bdstevel@tonic-gate	}
13187c478bdstevel@tonic-gate
13197c478bdstevel@tonic-gate	if (fas->f_cmdarea != (uchar_t *)NULL) {
13207c478bdstevel@tonic-gate		(void) ddi_dma_unbind_handle(fas->f_dmahandle);
13217c478bdstevel@tonic-gate		ddi_dma_mem_free(&fas->f_cmdarea_acc_handle);
13227c478bdstevel@tonic-gate	}
13237c478bdstevel@tonic-gate
13247c478bdstevel@tonic-gate	if (fas->f_dmahandle != (ddi_dma_handle_t)NULL) {
13257c478bdstevel@tonic-gate		ddi_dma_free_handle(&fas->f_dmahandle);
13267c478bdstevel@tonic-gate	}
13277c478bdstevel@tonic-gate
13287c478bdstevel@tonic-gate	if (fas->f_regs_acc_handle) {
13297c478bdstevel@tonic-gate		ddi_regs_map_free(&fas->f_regs_acc_handle);
13307c478bdstevel@tonic-gate	}
13317c478bdstevel@tonic-gate	if (fas->f_dmar_acc_handle) {
13327c478bdstevel@tonic-gate		ddi_regs_map_free(&fas->f_dmar_acc_handle);
13337c478bdstevel@tonic-gate	}
13347c478bdstevel@tonic-gate
13357c478bdstevel@tonic-gate	/*
13367c478bdstevel@tonic-gate	 * Remove properties created during attach()
13377c478bdstevel@tonic-gate	 */
13387c478bdstevel@tonic-gate	ddi_prop_remove_all(dip);
13397c478bdstevel@tonic-gate
13407c478bdstevel@tonic-gate	/*
13417c478bdstevel@tonic-gate	 * Delete the DMA limits, transport vectors and remove the device
13427c478bdstevel@tonic-gate	 * links to the scsi_transport layer.
13437c478bdstevel@tonic-gate	 *	-- ddi_set_driver_private(dip, NULL)
13447c478bdstevel@tonic-gate	 */
13457c478bdstevel@tonic-gate	(void) scsi_hba_detach(dip);
13467c478bdstevel@tonic-gate
13477c478bdstevel@tonic-gate	/*
13487c478bdstevel@tonic-gate	 * Free the scsi_transport structure for this device.
13497c478bdstevel@tonic-gate	 */
13507c478bdstevel@tonic-gate	scsi_hba_tran_free(tran);
13517c478bdstevel@tonic-gate
13527c478bdstevel@tonic-gate	ddi_soft_state_free(fas_state, ddi_get_instance(dip));
13537c478bdstevel@tonic-gate
13547c478bdstevel@tonic-gate	return (DDI_SUCCESS);
13557c478bdstevel@tonic-gate}
13567c478bdstevel@tonic-gate
13577c478bdstevel@tonic-gatestatic int
13587c478bdstevel@tonic-gatefas_quiesce_bus(struct fas *fas)
13597c478bdstevel@tonic-gate{
13607c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
13617c478bdstevel@tonic-gate	IPRINTF("fas_quiesce: QUIESCEing\n");
13627c478bdstevel@tonic-gate	IPRINTF3("fas_quiesce: ncmds (%d) ndisc (%d) state (%d)\n",
13631939740Sherry Moore	    fas->f_ncmds, fas->f_ndisc, fas->f_softstate);
13647c478bdstevel@tonic-gate	fas_set_throttles(fas, 0, N_SLOTS, HOLD_THROTTLE);
13657c478bdstevel@tonic-gate	if (fas_check_outstanding(fas)) {
13667c478bdstevel@tonic-gate		fas->f_softstate |= FAS_SS_DRAINING;
13677c478bdstevel@tonic-gate		fas->f_quiesce_timeid = timeout(fas_ncmds_checkdrain,
13687c478bdstevel@tonic-gate		    fas, (FAS_QUIESCE_TIMEOUT * drv_usectohz(1000000)));
13697c478bdstevel@tonic-gate		if (cv_wait_sig(FAS_CV(fas), FAS_MUTEX(fas)) == 0) {
13707c478bdstevel@tonic-gate			/*
13717c478bdstevel@tonic-gate			 * quiesce has been interrupted.
13727c478bdstevel@tonic-gate			 */
13737c478bdstevel@tonic-gate			IPRINTF("fas_quiesce: abort QUIESCE\n");
13747c478bdstevel@tonic-gate			fas->f_softstate &= ~FAS_SS_DRAINING;
13757c478bdstevel@tonic-gate			fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE);
13767c478bdstevel@tonic-gate			(void) fas_istart(fas);
13777c478bdstevel@tonic-gate			if (fas->f_quiesce_timeid != 0) {
13787c478bdstevel@tonic-gate				mutex_exit(FAS_MUTEX(fas));
13797c478bdstevel@tonic-gate#ifndef __lock_lint	/* warlock complains but there is a NOTE on this */
13807c478bdstevel@tonic-gate				(void) untimeout(fas->f_quiesce_timeid);
13817c478bdstevel@tonic-gate				fas->f_quiesce_timeid = 0;
13827c478bdstevel@tonic-gate#endif
13837c478bdstevel@tonic-gate				return (-1);
13847c478bdstevel@tonic-gate			}
13857c478bdstevel@tonic-gate			mutex_exit(FAS_MUTEX(fas));
13867c478bdstevel@tonic-gate			return (-1);
13877c478bdstevel@tonic-gate		} else {
13887c478bdstevel@tonic-gate			IPRINTF("fas_quiesce: bus is QUIESCED\n");
13897c478bdstevel@tonic-gate			ASSERT(fas->f_quiesce_timeid == 0);
13907c478bdstevel@tonic-gate			fas->f_softstate &= ~FAS_SS_DRAINING;
13917c478bdstevel@tonic-gate			fas->f_softstate |= FAS_SS_QUIESCED;
13927c478bdstevel@tonic-gate			mutex_exit(FAS_MUTEX(fas));
13937c478bdstevel@tonic-gate			return (0);
13947c478bdstevel@tonic-gate		}
13957c478bdstevel@tonic-gate	}
13967c478bdstevel@tonic-gate	IPRINTF("fas_quiesce: bus was not busy QUIESCED\n");
13977c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
13987c478bdstevel@tonic-gate	return (0);
13997c478bdstevel@tonic-gate}
14007c478bdstevel@tonic-gate
14017c478bdstevel@tonic-gatestatic int
14027c478bdstevel@tonic-gatefas_unquiesce_bus(struct fas *fas)
14037c478bdstevel@tonic-gate{
14047c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
14057c478bdstevel@tonic-gate	fas->f_softstate &= ~FAS_SS_QUIESCED;
14067c478bdstevel@tonic-gate	fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE);
14077c478bdstevel@tonic-gate	(void) fas_istart(fas);
14087c478bdstevel@tonic-gate	IPRINTF("fas_quiesce: bus has been UNQUIESCED\n");
14097c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
14107c478bdstevel@tonic-gate
14117c478bdstevel@tonic-gate	return (0);
14127c478bdstevel@tonic-gate}
14137c478bdstevel@tonic-gate
14147c478bdstevel@tonic-gate/*
14157c478bdstevel@tonic-gate * invoked from timeout() to check the number of outstanding commands
14167c478bdstevel@tonic-gate */
14177c478bdstevel@tonic-gatestatic void
14187c478bdstevel@tonic-gatefas_ncmds_checkdrain(void *arg)
14197c478bdstevel@tonic-gate{
14207c478bdstevel@tonic-gate	struct fas *fas = arg;
14217c478bdstevel@tonic-gate
14227c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
14237c478bdstevel@tonic-gate	IPRINTF3("fas_checkdrain: ncmds (%d) ndisc (%d) state (%d)\n",
14241939740Sherry Moore	    fas->f_ncmds, fas->f_ndisc, fas->f_softstate);
14257c478bdstevel@tonic-gate	if (fas->f_softstate & FAS_SS_DRAINING) {
14267c478bdstevel@tonic-gate		fas->f_quiesce_timeid = 0;
14277c478bdstevel@tonic-gate		if (fas_check_outstanding(fas) == 0) {
14287c478bdstevel@tonic-gate			IPRINTF("fas_drain: bus has drained\n");
14297c478bdstevel@tonic-gate			cv_signal(FAS_CV(fas));
14307c478bdstevel@tonic-gate		} else {
14317c478bdstevel@tonic-gate			/*
14327c478bdstevel@tonic-gate			 * throttle may have been reset by a bus reset
14337c478bdstevel@tonic-gate			 * or fas_runpoll()
14347c478bdstevel@tonic-gate			 * XXX shouldn't be necessary
14357c478bdstevel@tonic-gate			 */
14367c478bdstevel@tonic-gate			fas_set_throttles(fas, 0, N_SLOTS, HOLD_THROTTLE);
14377c478bdstevel@tonic-gate			IPRINTF("fas_drain: rescheduling timeout\n");
14387c478bdstevel@tonic-gate			fas->f_quiesce_timeid = timeout(fas_ncmds_checkdrain,
14397c478bdstevel@tonic-gate			    fas, (FAS_QUIESCE_TIMEOUT * drv_usectohz(1000000)));
14407c478bdstevel@tonic-gate		}
14417c478bdstevel@tonic-gate	}
14427c478bdstevel@tonic-gate	mutex_exit(FAS_MUTEX(fas));
14437c478bdstevel@tonic-gate}
14447c478bdstevel@tonic-gate
14457c478bdstevel@tonic-gatestatic int
14467c478bdstevel@tonic-gatefas_check_outstanding(struct fas *fas)
14477c478bdstevel@tonic-gate{
14487c478bdstevel@tonic-gate	uint_t slot;
14497c478bdstevel@tonic-gate	uint_t d = ((fas->f_dslot == 0)? 1 : fas->f_dslot);
14507c478bdstevel@tonic-gate	int ncmds = 0;
14517c478bdstevel@tonic-gate
14527c478bdstevel@tonic-gate	ASSERT(mutex_owned(FAS_MUTEX(fas)));
14537c478bdstevel@tonic-gate
14547c478bdstevel@tonic-gate	for (slot = 0; slot < N_SLOTS; slot += d)
14557c478bdstevel@tonic-gate		ncmds += fas->f_tcmds[slot];
14567c478bdstevel@tonic-gate
14577c478bdstevel@tonic-gate	return (ncmds);
14587c478bdstevel@tonic-gate}
14597c478bdstevel@tonic-gate
14607c478bdstevel@tonic-gate
14617c478bdstevel@tonic-gate#ifdef	FASDEBUG
14627c478bdstevel@tonic-gate/*
14637c478bdstevel@tonic-gate * fas register read/write functions with tracing
14647c478bdstevel@tonic-gate */
14657c478bdstevel@tonic-gatestatic void
14667c478bdstevel@tonic-gatefas_reg_tracing(struct fas *fas, int type, int regno, uint32_t what)
14677c478bdstevel@tonic-gate{
14687c478bdstevel@tonic-gate	fas->f_reg_trace[fas->f_reg_trace_index++] = type;
14697c478bdstevel@tonic-gate	fas->f_reg_trace[fas->f_reg_trace_index++] = regno;
14707c478bdstevel@tonic-gate	fas->f_reg_trace[fas->f_reg_trace_index++] = what;
14717c478bdstevel@tonic-gate	fas->f_reg_trace[fas->f_reg_trace_index++] = gethrtime();
14727c478bdstevel@tonic-gate	fas->f_reg_trace[fas->f_reg_trace_index] = 0xff;
14737c478bdstevel@tonic-gate	if (fas->f_reg_trace_index >= REG_TRACE_BUF_SIZE) {
14747c478bdstevel@tonic-gate		fas->f_reg_trace_index = 0;
14757c478bdstevel@tonic-gate	}
14767c478bdstevel@tonic-gate}
14777c478bdstevel@tonic-gate
14787c478bdstevel@tonic-gatestatic void
14797c478bdstevel@tonic-gatefas_reg_cmd_write(struct fas *fas, uint8_t cmd)
14807c478bdstevel@tonic-gate{
14817c478bdstevel@tonic-gate	volatile struct fasreg *fasreg = fas->f_reg;
14827c478bdstevel@tonic-gate	int regno = (uintptr_t)&fasreg->fas_cmd - (uintptr_t)fasreg;
14837c478bdstevel@tonic-gate
14847c478bdstevel@tonic-gate	fasreg->fas_cmd = cmd;
14857c478bdstevel@tonic-gate	fas->f_last_cmd = cmd;
14867c478bdstevel@tonic-gate
14877c478bdstevel@tonic-gate	EPRINTF1("issuing cmd %x\n", (uchar_t)cmd);
14887c478bdstevel@tonic-gate	fas_reg_tracing(fas, 0, regno, cmd);
14897c478bdstevel@tonic-gate
14907c478bdstevel@tonic-gate	fas->f_reg_cmds++;
14917c478bdstevel@tonic-gate}
14927c478bdstevel@tonic-gate
14937c478bdstevel@tonic-gatestatic void
14947c478bdstevel@tonic-gatefas_reg_write(struct fas *fas, volatile uint8_t *p, uint8_t what)
14957c478bdstevel@tonic-gate{
14967c478bdstevel@tonic-gate	int regno = (uintptr_t)p - (uintptr_t)fas->f_reg;
14977c478bdstevel@tonic-gate
14987c478bdstevel@tonic-gate	*p = what;
14997c478bdstevel@tonic-gate
15007c478bdstevel@tonic-gate	EPRINTF2("writing reg%x = %x\n", regno, what);
15017c478bdstevel@tonic-gate	fas_reg_tracing(fas, 1, regno, what);
15027c478bdstevel@tonic-gate
15037c478bdstevel@tonic-gate	fas->f_reg_writes++;
15047c478bdstevel@tonic-gate}
15057c478bdstevel@tonic-gate
15067c478bdstevel@tonic-gatestatic uint8_t
15077c478bdstevel@tonic-gatefas_reg_read(struct fas *fas, volatile uint8_t *p)
15087c478bdstevel@tonic-gate{
15097c478bdstevel@tonic-gate	uint8_t what;
15107c478bdstevel@tonic-gate	int regno = (uintptr_t)p - (uintptr_t)fas->f_reg;
15117c478bdstevel@tonic-gate
15127c478bdstevel@tonic-gate	what = *p;
15137c478bdstevel@tonic-gate
15147c478bdstevel@tonic-gate	EPRINTF2("reading reg%x => %x\n", regno, what);
15157c478bdstevel@tonic-gate	fas_reg_tracing(fas, 2, regno, what);
15167c478bdstevel@tonic-gate
15177c478bdstevel@tonic-gate	fas->f_reg_reads++;
15187c478bdstevel@tonic-gate
15197c478bdstevel@tonic-gate	return (what);
15207c478bdstevel@tonic-gate}
15217c478bdstevel@tonic-gate
15227c478bdstevel@tonic-gate/*
15237c478bdstevel@tonic-gate * dma register access routines
15247c478bdstevel@tonic-gate */
15257c478bdstevel@tonic-gatestatic void
15267c478bdstevel@tonic-gatefas_dma_reg_write(struct fas *fas, volatile uint32_t *p, uint32_t what)
15277c478bdstevel@tonic-gate{
15287c478bdstevel@tonic-gate	*p = what;
15297c478bdstevel@tonic-gate	fas->f_reg_dma_writes++;
15307c478bdstevel@tonic-gate
15317c478bdstevel@tonic-gate#ifdef DMA_REG_TRACING
15327c478bdstevel@tonic-gate{
15337c478bdstevel@tonic-gate	int regno = (uintptr_t)p - (uintptr_t)fas->f_dma;
15347c478bdstevel@tonic-gate	EPRINTF2("writing dma reg%x = %x\n", regno, what);
15357c478bdstevel@tonic-gate	fas_reg_tracing(fas, 3, regno, what);
15367c478bdstevel@tonic-gate}
15377c478bdstevel@tonic-gate#endif
15387c478bdstevel@tonic-gate}
15397c478bdstevel@tonic-gate
15407c478bdstevel@tonic-gatestatic uint32_t
15417c478bdstevel@tonic-gatefas_dma_reg_read(struct fas *fas, volatile uint32_t *p)
15427c478bdstevel@tonic-gate{
15437c478bdstevel@tonic-gate	uint32_t what = *p;
15447c478bdstevel@tonic-gate	fas->f_reg_dma_reads++;
15457c478bdstevel@tonic-gate
15467c478bdstevel@tonic-gate#ifdef DMA_REG_TRACING
15477c478bdstevel@tonic-gate{
15487c478bdstevel@tonic-gate	int regno = (uintptr_t)p - (uintptr_t)fas->f_dma;
15497c478bdstevel@tonic-gate	EPRINTF2("reading dma reg%x => %x\n", regno, what);
15507c478bdstevel@tonic-gate	fas_reg_tracing(fas, 4, regno, what);
15517c478bdstevel@tonic-gate}
15527c478bdstevel@tonic-gate#endif
15537c478bdstevel@tonic-gate	return (what);
15547c478bdstevel@tonic-gate}
15557c478bdstevel@tonic-gate#endif
15567c478bdstevel@tonic-gate
15577c478bdstevel@tonic-gate#define	FIFO_EMPTY(fas)  (fas_reg_read(fas, &fas->f_reg->fas_stat2) & \
15587c478bdstevel@tonic-gate		FAS_STAT2_EMPTY)
15597c478bdstevel@tonic-gate#define	FIFO_CNT(fas) \
15607c478bdstevel@tonic-gate	(fas_reg_read(fas, &fas->f_reg->fas_fifo_flag) & FIFO_CNT_MASK)
15617c478bdstevel@tonic-gate
15627c478bdstevel@tonic-gate#ifdef FASDEBUG
15637c478bdstevel@tonic-gatestatic void
15647c478bdstevel@tonic-gatefas_assert_atn(struct fas *fas)
15657c478bdstevel@tonic-gate{
15667c478bdstevel@tonic-gate	fas_reg_cmd_write(fas, CMD_SET_ATN);
15677c478bdstevel@tonic-gate#ifdef FAS_TEST
15687c478bdstevel@tonic-gate	if (fas_test_stop > 1)
15697c478bdstevel@tonic-gate		debug_enter("asserted atn");
15707c478bdstevel@tonic-gate#endif
15717c478bdstevel@tonic-gate}
15727c478bdstevel@tonic-gate#else
15737c478bdstevel@tonic-gate#define	fas_assert_atn(fas)  fas_reg_cmd_write(fas, CMD_SET_ATN)
15747c478bdstevel@tonic-gate#endif
15757c478bdstevel@tonic-gate
15767c478bdstevel@tonic-gate/*
15777c478bdstevel@tonic-gate * DMA macros; we use a shadow copy of the dma_csr to	save unnecessary
15787c478bdstevel@tonic-gate * reads
15797c478bdstevel@tonic-gate */
15807c478bdstevel@tonic-gate#define	FAS_DMA_WRITE(fas, count, base, cmd) { \
15817c478bdstevel@tonic-gate	volatile struct fasreg *fasreg = fas->f_reg; \
15827c478bdstevel@tonic-gate	volatile struct dma *dmar = fas->f_dma; \
15837c478bdstevel@tonic-gate	ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \
15847c478bdstevel@tonic-gate	SET_FAS_COUNT(fasreg, count); \
15857c478bdstevel@tonic-gate	fas_reg_cmd_write(fas, cmd); \
15867c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_count, count); \
15877c478bdstevel@tonic-gate	fas->f_dma_csr |= \
15887c478bdstevel@tonic-gate	    DMA_WRITE | DMA_ENDVMA | DMA_DSBL_DRAIN; \
15897c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \
15907c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_csr, fas->f_dma_csr); \
15917c478bdstevel@tonic-gate}
15927c478bdstevel@tonic-gate
15937c478bdstevel@tonic-gate#define	FAS_DMA_WRITE_SETUP(fas, count, base) { \
15947c478bdstevel@tonic-gate	volatile struct fasreg *fasreg = fas->f_reg; \
15957c478bdstevel@tonic-gate	volatile struct dma *dmar = fas->f_dma; \
15967c478bdstevel@tonic-gate	ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \
15977c478bdstevel@tonic-gate	SET_FAS_COUNT(fasreg, count); \
15987c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_count, count); \
15997c478bdstevel@tonic-gate	fas->f_dma_csr |= \
16007c478bdstevel@tonic-gate	    DMA_WRITE | DMA_ENDVMA | DMA_DSBL_DRAIN; \
16017c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \
16027c478bdstevel@tonic-gate}
16037c478bdstevel@tonic-gate
16047c478bdstevel@tonic-gate
16057c478bdstevel@tonic-gate#define	FAS_DMA_READ(fas, count, base, dmacount, cmd) { \
16067c478bdstevel@tonic-gate	volatile struct fasreg *fasreg = fas->f_reg; \
16077c478bdstevel@tonic-gate	volatile struct dma *dmar = fas->f_dma; \
16087c478bdstevel@tonic-gate	ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \
16097c478bdstevel@tonic-gate	SET_FAS_COUNT(fasreg, count); \
16107c478bdstevel@tonic-gate	fas_reg_cmd_write(fas, cmd); \
16117c478bdstevel@tonic-gate	fas->f_dma_csr |= \
16127c478bdstevel@tonic-gate	    (fas->f_dma_csr &	~DMA_WRITE) | DMA_ENDVMA | DMA_DSBL_DRAIN; \
16137c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_count, dmacount); \
16147c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \
16157c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &dmar->dma_csr, fas->f_dma_csr); \
16167c478bdstevel@tonic-gate}
16177c478bdstevel@tonic-gate
16187c478bdstevel@tonic-gatestatic void
16197c478bdstevel@tonic-gateFAS_FLUSH_DMA(struct fas *fas)
16207c478bdstevel@tonic-gate{
16217c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, DMA_RESET);
16227c478bdstevel@tonic-gate	fas->f_dma_csr |= (DMA_INTEN|DMA_TWO_CYCLE|DMA_DSBL_PARITY|
16231939740Sherry Moore	    DMA_DSBL_DRAIN);
16247c478bdstevel@tonic-gate	fas->f_dma_csr &= ~(DMA_ENDVMA | DMA_WRITE);
16257c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 0);
16267c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr);
16277c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_addr, 0);
16287c478bdstevel@tonic-gate}
16297c478bdstevel@tonic-gate
16307c478bdstevel@tonic-gate/*
16317c478bdstevel@tonic-gate * FAS_FLUSH_DMA_HARD checks on REQPEND before taking away the reset
16327c478bdstevel@tonic-gate */
16337c478bdstevel@tonic-gatestatic void
16347c478bdstevel@tonic-gateFAS_FLUSH_DMA_HARD(struct fas *fas)
16357c478bdstevel@tonic-gate{
16367c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, DMA_RESET);
16377c478bdstevel@tonic-gate	fas->f_dma_csr |= (DMA_INTEN|DMA_TWO_CYCLE|DMA_DSBL_PARITY|
16381939740Sherry Moore	    DMA_DSBL_DRAIN);
16397c478bdstevel@tonic-gate	fas->f_dma_csr &= ~(DMA_ENDVMA | DMA_WRITE);
1640602ca9ecth	while (fas_dma_reg_read(fas, &fas->f_dma->dma_csr) & DMA_REQPEND)
1641602ca9ecth		;
16427c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 0);
16437c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr);
16447c478bdstevel@tonic-gate	fas_dma_reg_write(fas, &fas->f_dma->dma_addr, 0);
16457c478bdstevel@tonic-gate}
16467c478bdstevel@tonic-gate
16477c478bdstevel@tonic-gate/*
16487c478bdstevel@tonic-gate * update period, conf3, offset reg, if necessary
16497c478bdstevel@tonic-gate */
16507c478bdstevel@tonic-gate#define	FAS_SET_PERIOD_OFFSET_CONF3_REGS(fas, target) \
16517c478bdstevel@tonic-gate{ \
16527c478bdstevel@tonic-gate	uchar_t period, offset, conf3; \
16537c478bdstevel@tonic-gate	period = fas->f_sync_period[target] & SYNC_PERIOD_MASK; \
16547c478bdstevel@tonic-gate	offset = fas->f_offset[target]; \
16557c478bdstevel@tonic-gate	conf3  = fas->f_fasconf3[target]; \
16567c478bdstevel@tonic-gate	if ((period != fas->f_period_reg_last) || \
16577c478bdstevel@tonic-gate	    (offset != fas->f_offset_reg_last) || \
16587c478bdstevel@tonic-gate	    (conf3 != fas->f_fasconf3_reg_last)) { \
16597c478bdstevel@tonic-gate		fas->f_period_reg_last = period; \
16607c478bdstevel@tonic-gate		fas->f_offset_reg_last = offset; \
16617c478bdstevel@tonic-gate		fas->f_fasconf3_reg_last = conf3; \
16627c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_sync_period, period); \
16637c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_sync_offset, offset); \
16647c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_conf3, conf3); \
16657c478bdstevel@tonic-gate	} \
16667c478bdstevel@tonic-gate}
16677c478bdstevel@tonic-gate
16687c478bdstevel@tonic-gate/*
16697c478bdstevel@tonic-gate * fifo read/write routines
16707c478bdstevel@tonic-gate * always read the fifo bytes before reading the interrupt register
16717c478bdstevel@tonic-gate */
16727c478bdstevel@tonic-gate
16737c478bdstevel@tonic-gatestatic void
16747c478bdstevel@tonic-gatefas_read_fifo(struct fas *fas)
16757c478bdstevel@tonic-gate{
16767c478bdstevel@tonic-gate	int stat = fas->f_stat;
16777c478bdstevel@tonic-gate	volatile struct fasreg	 *fasreg = fas->f_reg;
16787c478bdstevel@tonic-gate	int		 i;
16797c478bdstevel@tonic-gate
16807c478bdstevel@tonic-gate	i = fas_reg_read(fas, &fasreg->fas_fifo_flag) & FIFO_CNT_MASK;
16817c478bdstevel@tonic-gate	EPRINTF2("fas_read_fifo: fifo cnt=%x, stat=%x\n", i, stat);
16827c478bdstevel@tonic-gate	ASSERT(i <= FIFOSIZE);
16837c478bdstevel@tonic-gate
16847c478bdstevel@tonic-gate	fas->f_fifolen = 0;
16857c478bdstevel@tonic-gate	while (i-- > 0) {
16867c478bdstevel@tonic-gate		fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas,
16871939740Sherry Moore		    &fasreg->fas_fifo_data);
16887c478bdstevel@tonic-gate		fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas,
16891939740Sherry Moore		    &fasreg->fas_fifo_data);
16907c478bdstevel@tonic-gate	}
16917c478bdstevel@tonic-gate	if (fas->f_stat2 & FAS_STAT2_ISHUTTLE)	{
16927c478bdstevel@tonic-gate
16937c478bdstevel@tonic-gate		/* write pad byte */
16947c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_fifo_data, 0);
16957c478bdstevel@tonic-gate		fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas,
16961939740Sherry Moore		    &fasreg->fas_fifo_data);
16977c478bdstevel@tonic-gate		/* flush pad byte */
16987c478bdstevel@tonic-gate		fas_reg_cmd_write(fas, CMD_FLUSH);
16997c478bdstevel@tonic-gate	}
17007c478bdstevel@tonic-gate	EPRINTF2("fas_read_fifo: fifo len=%x, stat2=%x\n",
17011939740Sherry Moore	    fas->f_fifolen, stat);
17027c478bdstevel@tonic-gate} /* fas_read_fifo */
17037c478bdstevel@tonic-gate
17047c478bdstevel@tonic-gatestatic void
17057c478bdstevel@tonic-gatefas_write_fifo(struct fas *fas, uchar_t *buf, int length, int pad)
17067c478bdstevel@tonic-gate{
17077c478bdstevel@tonic-gate	int i;
17087c478bdstevel@tonic-gate	volatile struct fasreg	 *fasreg = fas->f_reg;
17097c478bdstevel@tonic-gate
17107c478bdstevel@tonic-gate	EPRINTF1("writing fifo %x bytes\n", length);
17117c478bdstevel@tonic-gate	ASSERT(length <= 15);
17127c478bdstevel@tonic-gate	fas_reg_cmd_write(fas, CMD_FLUSH);
17137c478bdstevel@tonic-gate	for (i = 0; i < length; i++) {
17147c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_fifo_data, buf[i]);
17157c478bdstevel@tonic-gate		if (pad) {
17167c478bdstevel@tonic-gate			fas_reg_write(fas, &fasreg->fas_fifo_data, 0);
17177c478bdstevel@tonic-gate		}
17187c478bdstevel@tonic-gate	}
17197c478bdstevel@tonic-gate}
17207c478bdstevel@tonic-gate
17217c478bdstevel@tonic-gate/*
17227c478bdstevel@tonic-gate * Hardware and Software internal reset routines
17237c478bdstevel@tonic-gate */
17247c478bdstevel@tonic-gatestatic int
17257c478bdstevel@tonic-gatefas_init_chip(struct fas *fas, uchar_t initiator_id)
17267c478bdstevel@tonic-gate{
17277c478bdstevel@tonic-gate	int		i;
17287c478bdstevel@tonic-gate	uchar_t		clock_conv;
17297c478bdstevel@tonic-gate	uchar_t		initial_conf3;
17307c478bdstevel@tonic-gate	uint_t		ticks;
17317c478bdstevel@tonic-gate	static char	*prop_cfreq = "clock-frequency";
17327c478bdstevel@tonic-gate
17337c478bdstevel@tonic-gate	/*
17347c478bdstevel@tonic-gate	 * Determine clock frequency of attached FAS chip.
17357c478bdstevel@tonic-gate	 */
17367c478bdstevel@tonic-gate	i = ddi_prop_get_int(DDI_DEV_T_ANY,
17371939740Sherry Moore	    fas->f_dev, DDI_PROP_DONTPASS, prop_cfreq, -1);
17387c478bdstevel@tonic-gate	clock_conv = (i + FIVE_MEG - 1) / FIVE_MEG;
17397c478bdstevel@tonic-gate	if (clock_conv != CLOCK_40MHZ) {
17407c478bdstevel@tonic-gate		fas_log(fas, CE_WARN, "Bad clock frequency");
17417c478bdstevel@tonic-gate		return (-1);
17427c478bdstevel@tonic-gate	}
17437c478bdstevel@tonic-gate
17447c478bdstevel@tonic-gate	fas->f_clock_conv = clock_conv;
17457c478bdstevel@tonic-gate	fas->f_clock_cycle = CLOCK_PERIOD(i);
17467c478bdstevel@tonic-gate	ticks = FAS_CLOCK_TICK(fas);
17477c478bdstevel@tonic-gate	fas->f_stval = FAS_CLOCK_TIMEOUT(ticks, fas_selection_timeout);
17487c478bdstevel@tonic-gate
17497c478bdstevel@tonic-gate	DPRINTF5("%d mhz, clock_conv %d, clock_cycle %d, ticks %d, stval %d\n",
17501939740Sherry Moore	    i, fas->f_clock_conv, fas->f_clock_cycle,
17511939740Sherry Moore	    ticks, fas->f_stval);
17527c478bdstevel@tonic-gate	/*
17537c478bdstevel@tonic-gate	 * set up conf registers
17547c478bdstevel@tonic-gate	 */
17557c478bdstevel@tonic-gate	fas->f_fasconf |= FAS_CONF_PAREN;
17567c478bdstevel@tonic-gate	fas->f_fasconf2 = (uchar_t)(FAS_CONF2_FENABLE | FAS_CONF2_XL32);
17577c478bdstevel@tonic-gate
17587c478bdstevel@tonic-gate	if (initiator_id < NTARGETS) {
17597c478bdstevel@tonic-gate		initial_conf3 = FAS_CONF3_FASTCLK | FAS_CONF3_ODDBYTE_AUTO;
17607c478bdstevel@tonic-gate	} else {
17617c478bdstevel@tonic-gate		initial_conf3 = FAS_CONF3_FASTCLK | FAS_CONF3_ODDBYTE_AUTO |
17627c478bdstevel@tonic-gate		    FAS_CONF3_IDBIT3;
17637c478bdstevel@tonic-gate	}
17647c478bdstevel@tonic-gate
17657c478bdstevel@tonic-gate	for (i = 0; i < NTARGETS_WIDE; i++) {
17667c478bdstevel@tonic-gate		fas->f_fasconf3[i] = initial_conf3;
17677c478bdstevel@tonic-gate	}
17687c478bdstevel@tonic-gate
17697c478bdstevel@tonic-gate	/*
17707c478bdstevel@tonic-gate	 * Avoid resetting the scsi bus since this causes a few seconds
17717c478bdstevel@tonic-gate	 * delay per fas in boot and also causes busy conditions in some
17727c478bdstevel@tonic-gate	 * tape devices.
17737c478bdstevel@tonic-gate	 */
17747c478bdstevel@tonic-gate	fas_internal_reset(fas, FAS_RESET_SOFTC|FAS_RESET_FAS|FAS_RESET_DMA);
17757c478bdstevel@tonic-gate
17767c478bdstevel@tonic-gate	/*
17777c478bdstevel@tonic-gate	 * initialize period and offset for each target
17787c478bdstevel@tonic-gate	 */
17797c478bdstevel@tonic-gate	for (i = 0; i < NTARGETS_WIDE; i++) {
17807c478bdstevel@tonic-gate		if (fas->f_target_scsi_options[i] & SCSI_OPTIONS_SYNC) {
17817c478bdstevel@tonic-gate			fas->f_offset[i] = fas_default_offset |
17821939740Sherry Moore			    fas->f_req_ack_delay;
17837c478bdstevel@tonic-gate		} else {
17847c478bdstevel@tonic-gate			fas->f_offset[i] = 0;
17857c478bdstevel@tonic-gate		}
17867c478bdstevel@tonic-gate		if (fas->f_target_scsi_options[i] & SCSI_OPTIONS_FAST) {
17877c478bdstevel@tonic-gate			fas->f_neg_period[i] =
17887c478bdstevel@tonic-gate			    (uchar_t)MIN_SYNC_PERIOD(fas);
17897c478bdstevel@tonic-gate		} else {
17907c478bdstevel@tonic-gate			fas->f_neg_period[i] =
17917c478bdstevel@tonic-gate			    (uchar_t)CONVERT_PERIOD(DEFAULT_SYNC_PERIOD);
17927c478bdstevel@tonic-gate		}
17937c478bdstevel@tonic-gate	}
17947c478bdstevel@tonic-gate	return (0);
17957c478bdstevel@tonic-gate}
17967c478bdstevel@tonic-gate
17977c478bdstevel@tonic-gate/*
17987c478bdstevel@tonic-gate * reset bus, chip, dma, or soft state
17997c478bdstevel@tonic-gate */
18007c478bdstevel@tonic-gatestatic void
18017c478bdstevel@tonic-gatefas_internal_reset(struct fas *fas, int reset_action)
18027c478bdstevel@tonic-gate{
18037c478bdstevel@tonic-gate	volatile struct fasreg *fasreg = fas->f_reg;
18047c478bdstevel@tonic-gate	volatile struct dma *dmar = fas->f_dma;
18057c478bdstevel@tonic-gate
18067c478bdstevel@tonic-gate	if (reset_action & FAS_RESET_SCSIBUS)	{
18077c478bdstevel@tonic-gate		fas_reg_cmd_write(fas, CMD_RESET_SCSI);
18087c478bdstevel@tonic-gate		fas_setup_reset_delay(fas);
18097c478bdstevel@tonic-gate	}
18107c478bdstevel@tonic-gate
18117c478bdstevel@tonic-gate	FAS_FLUSH_DMA_HARD(fas); /* resets and reinits the dma */
18127c478bdstevel@tonic-gate
18137c478bdstevel@tonic-gate	/*
18147c478bdstevel@tonic-gate	 * NOTE: if dma is aborted while active, indefinite hangs
18157c478bdstevel@tonic-gate	 * may occur; it is preferable to stop the target first before
18167c478bdstevel@tonic-gate	 * flushing the dma
18177c478bdstevel@tonic-gate	 */
18187c478bdstevel@tonic-gate	if (reset_action & FAS_RESET_DMA) {
18197c478bdstevel@tonic-gate		int burstsizes = fas->f_dma_attr->dma_attr_burstsizes;
18207c478bdstevel@tonic-gate		if (burstsizes & BURST64) {
18217c478bdstevel@tonic-gate			IPRINTF("64 byte burstsize\n");
18227c478bdstevel@tonic-gate			fas->f_dma_csr |= DMA_BURST64;
18237c478bdstevel@tonic-gate		} else if	(burstsizes & BURST32) {
18247c478bdstevel@tonic-gate			IPRINTF("32 byte burstsize\n");
18257c478bdstevel@tonic-gate			fas->f_dma_csr |= DMA_BURST32;
18267c478bdstevel@tonic-gate		} else {
18277c478bdstevel@tonic-gate			IPRINTF("16 byte burstsize\n");
18287c478bdstevel@tonic-gate		}
18297c478bdstevel@tonic-gate		if ((fas->f_hm_rev > 0x20) && (fas_enable_sbus64) &&
18307c478bdstevel@tonic-gate		    (ddi_dma_set_sbus64(fas->f_dmahandle, burstsizes) ==
18317c478bdstevel@tonic-gate		    DDI_SUCCESS)) {
18327c478bdstevel@tonic-gate			IPRINTF("enabled 64 bit sbus\n");
18337c478bdstevel@tonic-gate			fas->f_dma_csr |= DMA_WIDE_EN;
18347c478bdstevel@tonic-gate		}
18357c478bdstevel@tonic-gate	}
18367c478bdstevel@tonic-gate
18377c478bdstevel@tonic-gate	if (reset_action & FAS_RESET_FAS) {
18387c478bdstevel@tonic-gate		/*
18397c478bdstevel@tonic-gate		 * 2 NOPs with DMA are required here
18407c478bdstevel@tonic-gate		 * id_code is unreliable if we don't do this)
18417c478bdstevel@tonic-gate		 */
18427c478bdstevel@tonic-gate		uchar_t idcode, fcode;
18437c478bdstevel@tonic-gate		int dmarev;
18447c478bdstevel@tonic-gate
18457c478bdstevel@tonic-gate		fas_reg_cmd_write(fas, CMD_RESET_FAS);
18467c478bdstevel@tonic-gate		fas_reg_cmd_write(fas, CMD_NOP | CMD_DMA);
18477c478bdstevel@tonic-gate		fas_reg_cmd_write(fas, CMD_NOP | CMD_DMA);
18487c478bdstevel@tonic-gate
18497c478bdstevel@tonic-gate		/*
18507c478bdstevel@tonic-gate		 * Re-load chip configurations
18517c478bdstevel@tonic-gate		 * Only load registers which are not loaded in fas_startcmd()
18527c478bdstevel@tonic-gate		 */
18537c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_clock_conv,
18541939740Sherry Moore		    (fas->f_clock_conv & CLOCK_MASK));
18557c478bdstevel@tonic-gate
18567c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_timeout, fas->f_stval);
18577c478bdstevel@tonic-gate
18587c478bdstevel@tonic-gate		/*
18597c478bdstevel@tonic-gate		 * enable default configurations
18607c478bdstevel@tonic-gate		 */
18617c478bdstevel@tonic-gate		fas->f_idcode = idcode =
18621939740Sherry Moore		    fas_reg_read(fas, &fasreg->fas_id_code);
18637c478bdstevel@tonic-gate		fcode = (uchar_t)(idcode & FAS_FCODE_MASK) >> (uchar_t)3;
18647c478bdstevel@tonic-gate		fas->f_type = FAS366;
18657c478bdstevel@tonic-gate		IPRINTF2("Family code %d, revision %d\n",
18667c478bdstevel@tonic-gate		    fcode, (idcode & FAS_REV_MASK));
18677c478bdstevel@tonic-gate		dmarev = fas_dma_reg_read(fas, &dmar->dma_csr);
18687c478bdstevel@tonic-gate		dmarev = (dmarev >> 11) & 0xf;
18697c478bdstevel@tonic-gate		IPRINTF1("DMA channel revision %d\n", dmarev);
18707c478bdstevel@tonic-gate
18717c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_conf, fas->f_fasconf);
18727c478bdstevel@tonic-gate		fas_reg_write(fas, &fasreg->fas_conf2, fas->f_fasconf2);
18737c478bdstevel@tonic-gate
18747c478bdstevel@tonic-gate		fas->f_req_ack_delay = DEFAULT_REQ_ACK_DELAY;
18757c478bdstevel@tonic-gate
18767c478bdstevel@tonic-gate		/*
18777c478bdstevel@tonic-gate		 * Just in case... clear interrupt
18787c478bdstevel@tonic-gate		 */
18797c478bdstevel@tonic-gate		(void) fas_reg_read(fas, &fasreg->fas_intr);
18807c478bdstevel@tonic-gate	}
18817c478bdstevel@tonic-gate
18827c478bdstevel@tonic-gate	if (reset_action & FAS_RESET_SOFTC) {
18837c478bdstevel@tonic-gate		fas->f_wdtr_sent = fas->f_sdtr_sent = 0;
18847c478bdstevel@tonic-gate		fas->f_wide_known = fas->f_sync_known = 0;
18857c478bdstevel@tonic-gate		fas->f_wide_enabled = fas->f_sync_enabled = 0;
18867c478bdstevel@tonic-gate		fas->f_omsglen = 0;
18877c478bdstevel@tonic-gate		fas->f_cur_msgout[0] = fas->f_last_msgout =
18887c478bdstevel@tonic-gate		    fas->f_last_msgin = INVALID_MSG;
18897c478bdstevel@tonic-gate		fas->f_abort_msg_sent = fas->f_reset_msg_sent = 0;
18907c478bdstevel@tonic-gate		fas->f_next_slot = 0;
18917c478bdstevel@tonic-gate		fas->f_current_sp = NULL;
18927c478bdstevel@tonic-gate		fas->f_fifolen = 0;
18937c478bdstevel@tonic-gate		fas->f_fasconf3_reg_last = fas->f_offset_reg_last =
18941939740Sherry Moore		    fas->f_period_reg_last = 0xff;
18957c478bdstevel@tonic-gate
18967c478bdstevel@tonic-gate		New_state(fas, STATE_FREE);
18977c478bdstevel@tonic-gate	}
18987c478bdstevel@tonic-gate}
18997c478bdstevel@tonic-gate
19007c478bdstevel@tonic-gate
19017c478bdstevel@tonic-gate#ifdef FASDEBUG
19027c478bdstevel@tonic-gate/*
19037c478bdstevel@tonic-gate * check if ncmds still reflects the truth
19047c478bdstevel@tonic-gate * count all cmds for this driver instance and compare with ncmds
19057c478bdstevel@tonic-gate */
19067c478bdstevel@tonic-gatestatic void
19077c478bdstevel@tonic-gatefas_check_ncmds(struct fas *fas)
19087c478bdstevel@tonic-gate{
19097c478bdstevel@tonic-gate	int slot = 0;
19107c478bdstevel@tonic-gate	ushort_t tag, t;
19117c478bdstevel@tonic-gate	int n, total = 0;
19127c478bdstevel@tonic-gate
19137c478bdstevel@tonic-gate	do {
19147c478bdstevel@tonic-gate		if (fas->f_active[slot]) {
19157c478bdstevel@tonic-gate			struct fas_cmd *sp = fas->f_readyf[slot];
19167c478bdstevel@tonic-gate			t = fas->f_active[slot]->f_n_slots;
19177c478bdstevel@tonic-gate			while (sp != 0) {
19187c478bdstevel@tonic-gate				sp = sp->cmd_forw;
19197c478bdstevel@tonic-gate				total++;
19207c478bdstevel@tonic-gate			}
19217c478bdstevel@tonic-gate			for (n = tag = 0; tag < t; tag++) {
19227c478bdstevel@tonic-gate				if (fas->f_active[slot]->f_slot[tag] != 0) {
19237c478bdstevel@tonic-gate					n++;
19247c478bdstevel@tonic-gate					total++;
19257c478bdstevel@tonic-gate				}
19267c478bdstevel@tonic-gate			}
19277c478bdstevel@tonic-gate			ASSERT(n == fas->f_tcmds[slot]);
19287c478bdstevel@tonic-gate		}
19297c478bdstevel@tonic-gate		slot = NEXTSLOT(slot, fas->f_dslot);
19307c478bdstevel@tonic-gate	} while (slot != 0);
19317c478bdstevel@tonic-gate
19327c478bdstevel@tonic-gate	if (total != fas->f_ncmds) {
19337c478bdstevel@tonic-gate		IPRINTF2("fas_check_ncmds: total=%x, ncmds=%x\n",
19341939740Sherry Moore		    total, fas->f_ncmds);
19357c478bdstevel@tonic-gate	}
19367c478bdstevel@tonic-gate	ASSERT(fas->f_ncmds >= fas->f_ndisc);
19377c478bdstevel@tonic-gate}
19387c478bdstevel@tonic-gate#else
19397c478bdstevel@tonic-gate#define	fas_check_ncmds(fas)
19407c478bdstevel@tonic-gate#endif
19417c478bdstevel@tonic-gate
19427c478bdstevel@tonic-gate/*
19437c478bdstevel@tonic-gate * SCSA Interface functions
19447c478bdstevel@tonic-gate *
19457c478bdstevel@tonic-gate * Visible to the external world via the transport structure.
19467c478bdstevel@tonic-gate *
19477c478bdstevel@tonic-gate * fas_scsi_abort: abort a current cmd or all cmds for a target
19487c478bdstevel@tonic-gate */
19497c478bdstevel@tonic-gate/*ARGSUSED*/
19507c478bdstevel@tonic-gatestatic int
19517c478bdstevel@tonic-gatefas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
19527c478bdstevel@tonic-gate{
19537c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
19547c478bdstevel@tonic-gate	int rval;
19557c478bdstevel@tonic-gate
19567c478bdstevel@tonic-gate	IPRINTF2("fas_scsi_abort: target %d.%d\n", ap->a_target, ap->a_lun);
19577c478bdstevel@tonic-gate
19587c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
19597c478bdstevel@tonic-gate	rval =	fas_do_scsi_abort(ap, pkt);
19607c478bdstevel@tonic-gate	fas_check_waitQ_and_mutex_exit(fas);
19617c478bdstevel@tonic-gate	return (rval);
19627c478bdstevel@tonic-gate}
19637c478bdstevel@tonic-gate
19647c478bdstevel@tonic-gate/*
19657c478bdstevel@tonic-gate * reset handling: reset bus or target
19667c478bdstevel@tonic-gate */
19677c478bdstevel@tonic-gate/*ARGSUSED*/
19687c478bdstevel@tonic-gatestatic int
19697c478bdstevel@tonic-gatefas_scsi_reset(struct scsi_address *ap, int level)
19707c478bdstevel@tonic-gate{
19717c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
19727c478bdstevel@tonic-gate	int rval;
19737c478bdstevel@tonic-gate
19747c478bdstevel@tonic-gate	IPRINTF3("fas_scsi_reset: target %d.%d, level %d\n",
19751939740Sherry Moore	    ap->a_target, ap->a_lun, level);
19767c478bdstevel@tonic-gate
19777c478bdstevel@tonic-gate	mutex_enter(FAS_MUTEX(fas));
19787c478bdstevel@tonic-gate	rval = fas_do_scsi_reset(ap, level);
19797c478bdstevel@tonic-gate	fas_check_waitQ_and_mutex_exit(fas);
19807c478bdstevel@tonic-gate	return (rval);
19817c478bdstevel@tonic-gate}
19827c478bdstevel@tonic-gate
19837c478bdstevel@tonic-gate/*
19847c478bdstevel@tonic-gate * entry point for reset notification setup, to register or to cancel.
19857c478bdstevel@tonic-gate */
19867c478bdstevel@tonic-gatestatic int
19877c478bdstevel@tonic-gatefas_scsi_reset_notify(struct scsi_address *ap, int flag,
19887c478bdstevel@tonic-gate    void (*callback)(caddr_t), caddr_t arg)
19897c478bdstevel@tonic-gate{
19907c478bdstevel@tonic-gate	struct fas	*fas = ADDR2FAS(ap);
19917c478bdstevel@tonic-gate
19927c478bdstevel@tonic-gate	return (scsi_hba_reset_notify_setup(ap, flag, callback, arg,
19931939740Sherry Moore	    &fas->f_mutex, &fas->f_reset_notify_listf));
19947c478bdstevel@tonic-gate}
19957c478bdstevel@tonic-gate
19967c478bdstevel@tonic-gate/*
19977c478bdstevel@tonic-gate * capability interface
19987c478bdstevel@tonic-gate */
19997c478bdstevel@tonic-gate/*ARGSUSED*/
20007c478bdstevel@tonic-gatestatic int
20017c478bdstevel@tonic-gatefas_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
20027c478bdstevel@tonic-gate{
20037c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
20047c478bdstevel@tonic-gate	DPRINTF3("fas_scsi_getcap: tgt=%x, cap=%s, whom=%x\n",
20051939740Sherry Moore	    ap->a_target, cap, whom);
20067c478bdstevel@tonic-gate	return (fas_commoncap(ap, cap, 0, whom, 0));
20077c478bdstevel@tonic-gate}
20087c478bdstevel@tonic-gate
20097c478bdstevel@tonic-gate/*ARGSUSED*/
20107c478bdstevel@tonic-gatestatic int
20117c478bdstevel@tonic-gatefas_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
20127c478bdstevel@tonic-gate{
20137c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
20147c478bdstevel@tonic-gate	IPRINTF4("fas_scsi_setcap: tgt=%x, cap=%s, value=%x, whom=%x\n",
20151939740Sherry Moore	    ap->a_target, cap, value, whom);
20167c478bdstevel@tonic-gate	return (fas_commoncap(ap, cap, value, whom, 1));
20177c478bdstevel@tonic-gate}
20187c478bdstevel@tonic-gate
20197c478bdstevel@tonic-gate/*
20207c478bdstevel@tonic-gate * pkt and dma allocation and deallocation
20217c478bdstevel@tonic-gate */
20227c478bdstevel@tonic-gate/*ARGSUSED*/
20237c478bdstevel@tonic-gatestatic void
20247c478bdstevel@tonic-gatefas_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
20257c478bdstevel@tonic-gate{
20267c478bdstevel@tonic-gate	struct fas_cmd *cmd = PKT2CMD(pkt);
20277c478bdstevel@tonic-gate
20287c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_START,
20297c478bdstevel@tonic-gate	    "fas_scsi_dmafree_start");
20307c478bdstevel@tonic-gate
20317c478bdstevel@tonic-gate	if (cmd->cmd_flags & CFLAG_DMAVALID) {
20327c478bdstevel@tonic-gate		/*
20337c478bdstevel@tonic-gate		 * Free the mapping.
20347c478bdstevel@tonic-gate		 */
20357c478bdstevel@tonic-gate		(void) ddi_dma_unbind_handle(cmd->cmd_dmahandle);
20367c478bdstevel@tonic-gate		cmd->cmd_flags ^= CFLAG_DMAVALID;
20377c478bdstevel@tonic-gate	}
20387c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_END,
20397c478bdstevel@tonic-gate	    "fas_scsi_dmafree_end");
20407c478bdstevel@tonic-gate}
20417c478bdstevel@tonic-gate
20427c478bdstevel@tonic-gate/*ARGSUSED*/
20437c478bdstevel@tonic-gatestatic void
20447c478bdstevel@tonic-gatefas_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
20457c478bdstevel@tonic-gate{
20467c478bdstevel@tonic-gate	struct fas_cmd *sp = PKT2CMD(pkt);
20477c478bdstevel@tonic-gate
20487c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_DMAVALID) {
20497c478bdstevel@tonic-gate		if (ddi_dma_sync(sp->cmd_dmahandle, 0, 0,
20507c478bdstevel@tonic-gate		    (sp->cmd_flags & CFLAG_DMASEND) ?
20517c478bdstevel@tonic-gate		    DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU) !=
20527c478bdstevel@tonic-gate		    DDI_SUCCESS) {
20537c478bdstevel@tonic-gate			fas_log(ADDR2FAS(ap), CE_WARN,
20547c478bdstevel@tonic-gate			    "sync of pkt (%p) failed", (void *)pkt);
20557c478bdstevel@tonic-gate		}
20567c478bdstevel@tonic-gate	}
20577c478bdstevel@tonic-gate}
20587c478bdstevel@tonic-gate
20597c478bdstevel@tonic-gate/*
20607c478bdstevel@tonic-gate * initialize pkt and allocate DVMA resources
20617c478bdstevel@tonic-gate */
20627c478bdstevel@tonic-gatestatic struct scsi_pkt *
20637c478bdstevel@tonic-gatefas_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
20647c478bdstevel@tonic-gate	struct buf *bp, int cmdlen, int statuslen, int tgtlen,
20657c478bdstevel@tonic-gate	int flags, int (*callback)(), caddr_t arg)
20667c478bdstevel@tonic-gate{
20677c478bdstevel@tonic-gate	int kf;
20687c478bdstevel@tonic-gate	int failure = 1;
20697c478bdstevel@tonic-gate	struct fas_cmd *cmd;
20707c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
20717c478bdstevel@tonic-gate	struct fas_cmd *new_cmd;
20727c478bdstevel@tonic-gate	int rval;
20737c478bdstevel@tonic-gate
20747c478bdstevel@tonic-gate/* #define	FAS_TEST_EXTRN_ALLOC */
20757c478bdstevel@tonic-gate#ifdef FAS_TEST_EXTRN_ALLOC
20767c478bdstevel@tonic-gate	cmdlen *= 4; statuslen *= 4; tgtlen *= 4;
20777c478bdstevel@tonic-gate#endif
20787c478bdstevel@tonic-gate	/*
20797c478bdstevel@tonic-gate	 * if no pkt was passed then allocate a pkt first
20807c478bdstevel@tonic-gate	 */
20817c478bdstevel@tonic-gate	if (pkt == NULL) {
20827c478bdstevel@tonic-gate		TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTALLOC_START,
20837c478bdstevel@tonic-gate		    "fas_scsi_impl_pktalloc_start");
20847c478bdstevel@tonic-gate
20857c478bdstevel@tonic-gate		kf = (callback == SLEEP_FUNC)? KM_SLEEP: KM_NOSLEEP;
20867c478bdstevel@tonic-gate
20877c478bdstevel@tonic-gate		/*
20887c478bdstevel@tonic-gate		 * only one size of pkt (with arq).
20897c478bdstevel@tonic-gate		 */
20907c478bdstevel@tonic-gate		cmd = kmem_cache_alloc(fas->f_kmem_cache, kf);
20917c478bdstevel@tonic-gate
20927c478bdstevel@tonic-gate		if (cmd) {
20937c478bdstevel@tonic-gate
20947c478bdstevel@tonic-gate			ddi_dma_handle_t	save_dma_handle;
20957c478bdstevel@tonic-gate
20967c478bdstevel@tonic-gate			save_dma_handle = cmd->cmd_dmahandle;
20977c478bdstevel@tonic-gate			bzero(cmd, EXTCMD_SIZE);
20987c478bdstevel@tonic-gate			cmd->cmd_dmahandle = save_dma_handle;
20997c478bdstevel@tonic-gate
21007c478bdstevel@tonic-gate			pkt = (struct scsi_pkt *)((uchar_t *)cmd +
21017c478bdstevel@tonic-gate			    sizeof (struct fas_cmd));
21027c478bdstevel@tonic-gate			cmd->cmd_pkt		= pkt;
21037c478bdstevel@tonic-gate			pkt->pkt_ha_private	= (opaque_t)cmd;
21047c478bdstevel@tonic-gate			pkt->pkt_scbp	= (opaque_t)&cmd->cmd_scb;
21057c478bdstevel@tonic-gate			pkt->pkt_cdbp	= (opaque_t)&cmd->cmd_cdb;
21067c478bdstevel@tonic-gate			pkt->pkt_address	= *ap;
21077c478bdstevel@tonic-gate
21087c478bdstevel@tonic-gate			pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb;
21097c478bdstevel@tonic-gate			pkt->pkt_private = cmd->cmd_pkt_private;
21107c478bdstevel@tonic-gate
21117c478bdstevel@tonic-gate			cmd->cmd_cdblen 	= cmdlen;
21127c478bdstevel@tonic-gate			cmd->cmd_scblen 	= statuslen;
21137c478bdstevel@tonic-gate			cmd->cmd_privlen	= tgtlen;
21147c478bdstevel@tonic-gate			cmd->cmd_slot		=
21151939740Sherry Moore			    (Tgt(cmd) * NLUNS_PER_TARGET) | Lun(cmd);
21167c478bdstevel@tonic-gate			failure = 0;
21177c478bdstevel@tonic-gate		}
21187c478bdstevel@tonic-gate		if (failure || (cmdlen > sizeof (cmd->cmd_cdb)) ||
21197c478bdstevel@tonic-gate		    (tgtlen > PKT_PRIV_LEN) ||
21207c478bdstevel@tonic-gate		    (statuslen > EXTCMDS_STATUS_SIZE)) {
21217c478bdstevel@tonic-gate			if (failure == 0) {
21227c478bdstevel@tonic-gate				/*
21237c478bdstevel@tonic-gate				 * if extern alloc fails, all will be
21247c478bdstevel@tonic-gate				 * deallocated, including cmd
21257c478bdstevel@tonic-gate				 */
21267c478bdstevel@tonic-gate				failure = fas_pkt_alloc_extern(fas, cmd,
21277c478bdstevel@tonic-gate				    cmdlen, tgtlen, statuslen, kf);
21287c478bdstevel@tonic-gate			}
21297c478bdstevel@tonic-gate			if (failure) {
21307c478bdstevel@tonic-gate				/*
21317c478bdstevel@tonic-gate				 * nothing to deallocate so just return
21327c478bdstevel@tonic-gate				 */
21337c478bdstevel@tonic-gate				TRACE_0(TR_FAC_SCSI_FAS,
21341939740Sherry Moore				    TR_FAS_SCSI_IMPL_PKTALLOC_END,
21351939740Sherry Moore				    "fas_scsi_impl_pktalloc_end");
21367c478bdstevel@tonic-gate				return (NULL);
21377c478bdstevel@tonic-gate			}
21387c478bdstevel@tonic-gate		}
21397c478bdstevel@tonic-gate
21407c478bdstevel@tonic-gate		new_cmd = cmd;
21417c478bdstevel@tonic-gate
21427c478bdstevel@tonic-gate		TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTALLOC_END,
21431939740Sherry Moore		    "fas_scsi_impl_pktalloc_end");
21447c478bdstevel@tonic-gate	} else {
21457c478bdstevel@tonic-gate		cmd = PKT2CMD(pkt);
21467c478bdstevel@tonic-gate		new_cmd = NULL;
21477c478bdstevel@tonic-gate	}
21487c478bdstevel@tonic-gate
21497c478bdstevel@tonic-gate	/*
21507c478bdstevel@tonic-gate	 * Second step of fas_scsi_init_pkt:
21517c478bdstevel@tonic-gate	 * bind the buf to the handle
21527c478bdstevel@tonic-gate	 */
21537c478bdstevel@tonic-gate	if (bp && bp->b_bcount != 0 &&
21541939740Sherry Moore	    (cmd->cmd_flags & CFLAG_DMAVALID) == 0) {
21557c478bdstevel@tonic-gate
21567c478bdstevel@tonic-gate		int cmd_flags, dma_flags;
21577c478bdstevel@tonic-gate		uint_t dmacookie_count;
21587c478bdstevel@tonic-gate
21597c478bdstevel@tonic-gate		TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_START,
21607c478bdstevel@tonic-gate		    "fas_scsi_impl_dmaget_start");
21617c478bdstevel@tonic-gate
21627c478bdstevel@tonic-gate		cmd_flags = cmd->cmd_flags;
21637c478bdstevel@tonic-gate
21647c478bdstevel@tonic-gate		if (bp->b_flags & B_READ) {
21657c478bdstevel@tonic-gate			cmd_flags &= ~CFLAG_DMASEND;
21667c478bdstevel@tonic-gate			dma_flags = DDI_DMA_READ | DDI_DMA_PARTIAL;
21677c478bdstevel@tonic-gate		} else {
21687c478bdstevel@tonic-gate			cmd_flags |= CFLAG_DMASEND;
21697c478bdstevel@tonic-gate			dma_flags = DDI_DMA_WRITE | DDI_DMA_PARTIAL;
21707c478bdstevel@tonic-gate		}
21717c478bdstevel@tonic-gate		if (flags & PKT_CONSISTENT) {
21727c478bdstevel@tonic-gate			cmd_flags |= CFLAG_CMDIOPB;
21737c478bdstevel@tonic-gate			dma_flags |= DDI_DMA_CONSISTENT;
21747c478bdstevel@tonic-gate		}
21757c478bdstevel@tonic-gate
21767c478bdstevel@tonic-gate		/*
21777c478bdstevel@tonic-gate		 * bind the handle to the buf
21787c478bdstevel@tonic-gate		 */
21797c478bdstevel@tonic-gate		ASSERT(cmd->cmd_dmahandle != NULL);
21807c478bdstevel@tonic-gate		rval = ddi_dma_buf_bind_handle(cmd->cmd_dmahandle, bp,
21811939740Sherry Moore		    dma_flags, callback, arg, &cmd->cmd_dmacookie,
21821939740Sherry Moore		    &dmacookie_count);
21837c478bdstevel@tonic-gate
21847c478bdstevel@tonic-gate		if (rval && rval != DDI_DMA_PARTIAL_MAP) {
21857c478bdstevel@tonic-gate			switch (rval) {
21867c478bdstevel@tonic-gate			case DDI_DMA_NORESOURCES:
21877c478bdstevel@tonic-gate				bioerror(bp, 0);
21887c478bdstevel@tonic-gate				break;
21897c478bdstevel@tonic-gate			case DDI_DMA_BADATTR:
21907c478bdstevel@tonic-gate			case DDI_DMA_NOMAPPING:
21917c478bdstevel@tonic-gate				bioerror(bp, EFAULT);
21927c478bdstevel@tonic-gate				break;
21937c478bdstevel@tonic-gate			case DDI_DMA_TOOBIG:
21947c478bdstevel@tonic-gate			default:
21957c478bdstevel@tonic-gate				bioerror(bp, EINVAL);
21967c478bdstevel@tonic-gate				break;
21977c478bdstevel@tonic-gate			}
21987c478bdstevel@tonic-gate			cmd->cmd_flags = cmd_flags & ~CFLAG_DMAVALID;
21997c478bdstevel@tonic-gate			if (new_cmd) {
22007c478bdstevel@tonic-gate				fas_scsi_destroy_pkt(ap, pkt);
22017c478bdstevel@tonic-gate			}
22027c478bdstevel@tonic-gate			TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_END,
22031939740Sherry Moore			    "fas_scsi_impl_dmaget_end");
22047c478bdstevel@tonic-gate			return ((struct scsi_pkt *)NULL);
22057c478bdstevel@tonic-gate		}
22067c478bdstevel@tonic-gate		ASSERT(dmacookie_count == 1);
22077c478bdstevel@tonic-gate		cmd->cmd_dmacount = bp->b_bcount;
22087c478bdstevel@tonic-gate		cmd->cmd_flags = cmd_flags | CFLAG_DMAVALID;
22097c478bdstevel@tonic-gate
22107c478bdstevel@tonic-gate		ASSERT(cmd->cmd_dmahandle != NULL);
22117c478bdstevel@tonic-gate		TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_END,
22127c478bdstevel@tonic-gate		    "fas_scsi_impl_dmaget_end");
22137c478bdstevel@tonic-gate	}
22147c478bdstevel@tonic-gate
22157c478bdstevel@tonic-gate	return (pkt);
22167c478bdstevel@tonic-gate}
22177c478bdstevel@tonic-gate
22187c478bdstevel@tonic-gate/*
22197c478bdstevel@tonic-gate * unbind dma resources and deallocate the pkt
22207c478bdstevel@tonic-gate */
22217c478bdstevel@tonic-gatestatic void
22227c478bdstevel@tonic-gatefas_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
22237c478bdstevel@tonic-gate{
22247c478bdstevel@tonic-gate	struct fas_cmd *sp = PKT2CMD(pkt);
22257c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
22267c478bdstevel@tonic-gate
22277c478bdstevel@tonic-gate	/*
22287c478bdstevel@tonic-gate	 * fas_scsi_impl_dmafree inline to speed things up
22297c478bdstevel@tonic-gate	 */
22307c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_START,
22317c478bdstevel@tonic-gate	    "fas_scsi_impl_dmafree_start");
22327c478bdstevel@tonic-gate
22337c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_DMAVALID) {
22347c478bdstevel@tonic-gate		/*
22357c478bdstevel@tonic-gate		 * Free the mapping.
22367c478bdstevel@tonic-gate		 */
22377c478bdstevel@tonic-gate		(void) ddi_dma_unbind_handle(sp->cmd_dmahandle);
22387c478bdstevel@tonic-gate		sp->cmd_flags ^= CFLAG_DMAVALID;
22397c478bdstevel@tonic-gate	}
22407c478bdstevel@tonic-gate
22417c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_END,
22427c478bdstevel@tonic-gate	    "fas_scsi_impl_dmafree_end");
22437c478bdstevel@tonic-gate
22447c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTFREE_START,
22457c478bdstevel@tonic-gate	    "fas_scsi_impl_pktfree_start");
22467c478bdstevel@tonic-gate
22477c478bdstevel@tonic-gate	if ((sp->cmd_flags &
22487c478bdstevel@tonic-gate	    (CFLAG_FREE | CFLAG_CDBEXTERN | CFLAG_PRIVEXTERN |
22497c478bdstevel@tonic-gate	    CFLAG_SCBEXTERN)) == 0) {
22507c478bdstevel@tonic-gate		sp->cmd_flags = CFLAG_FREE;
22517c478bdstevel@tonic-gate		kmem_cache_free(fas->f_kmem_cache, (void *)sp);
22527c478bdstevel@tonic-gate	} else {
22537c478bdstevel@tonic-gate		fas_pkt_destroy_extern(fas, sp);
22547c478bdstevel@tonic-gate	}
22557c478bdstevel@tonic-gate
22567c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTFREE_END,
22577c478bdstevel@tonic-gate	    "fas_scsi_impl_pktfree_end");
22587c478bdstevel@tonic-gate}
22597c478bdstevel@tonic-gate
22607c478bdstevel@tonic-gate/*
22617c478bdstevel@tonic-gate * allocate and deallocate external pkt space (ie. not part of fas_cmd) for
22627c478bdstevel@tonic-gate * non-standard length cdb, pkt_private, status areas
22637c478bdstevel@tonic-gate * if allocation fails, then deallocate all external space and the pkt
22647c478bdstevel@tonic-gate */
22657c478bdstevel@tonic-gate/* ARGSUSED */
22667c478bdstevel@tonic-gatestatic int
22677c478bdstevel@tonic-gatefas_pkt_alloc_extern(struct fas *fas, struct fas_cmd *sp,
22687c478bdstevel@tonic-gate    int cmdlen, int tgtlen, int statuslen, int kf)
22697c478bdstevel@tonic-gate{
22707c478bdstevel@tonic-gate	caddr_t cdbp, scbp, tgt;
22717c478bdstevel@tonic-gate	int failure = 0;
22727c478bdstevel@tonic-gate
22737c478bdstevel@tonic-gate	tgt = cdbp = scbp = NULL;
22747c478bdstevel@tonic-gate	if (cmdlen > sizeof (sp->cmd_cdb)) {
22757c478bdstevel@tonic-gate		if ((cdbp = kmem_zalloc((size_t)cmdlen, kf)) == NULL) {
22767c478bdstevel@tonic-gate			failure++;
22777c478bdstevel@tonic-gate		} else {
22787c478bdstevel@tonic-gate			sp->cmd_pkt->pkt_cdbp = (opaque_t)cdbp;
22797c478bdstevel@tonic-gate			sp->cmd_flags |= CFLAG_CDBEXTERN;
22807c478bdstevel@tonic-gate		}
22817c478bdstevel@tonic-gate	}
22827c478bdstevel@tonic-gate	if (tgtlen > PKT_PRIV_LEN) {
22837c478bdstevel@tonic-gate		if ((tgt = kmem_zalloc(tgtlen, kf)) == NULL) {
22847c478bdstevel@tonic-gate			failure++;
22857c478bdstevel@tonic-gate		} else {
22867c478bdstevel@tonic-gate			sp->cmd_flags |= CFLAG_PRIVEXTERN;
22877c478bdstevel@tonic-gate			sp->cmd_pkt->pkt_private = tgt;
22887c478bdstevel@tonic-gate		}
22897c478bdstevel@tonic-gate	}
22907c478bdstevel@tonic-gate	if (statuslen > EXTCMDS_STATUS_SIZE) {
22917c478bdstevel@tonic-gate		if ((scbp = kmem_zalloc((size_t)statuslen, kf)) == NULL) {
22927c478bdstevel@tonic-gate			failure++;
22937c478bdstevel@tonic-gate		} else {
22947c478bdstevel@tonic-gate			sp->cmd_flags |= CFLAG_SCBEXTERN;
22957c478bdstevel@tonic-gate			sp->cmd_pkt->pkt_scbp = (opaque_t)scbp;
22967c478bdstevel@tonic-gate		}
22977c478bdstevel@tonic-gate	}
22987c478bdstevel@tonic-gate	if (failure) {
22997c478bdstevel@tonic-gate		fas_pkt_destroy_extern(fas, sp);
23007c478bdstevel@tonic-gate	}
23017c478bdstevel@tonic-gate	return (failure);
23027c478bdstevel@tonic-gate}
23037c478bdstevel@tonic-gate
23047c478bdstevel@tonic-gate/*
23057c478bdstevel@tonic-gate * deallocate external pkt space and deallocate the pkt
23067c478bdstevel@tonic-gate */
23077c478bdstevel@tonic-gatestatic void
23087c478bdstevel@tonic-gatefas_pkt_destroy_extern(struct fas *fas, struct fas_cmd *sp)
23097c478bdstevel@tonic-gate{
23107c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_FREE) {
23117c478bdstevel@tonic-gate		panic("fas_pkt_destroy_extern: freeing free packet");
23127c478bdstevel@tonic-gate		_NOTE(NOT_REACHED)
23137c478bdstevel@tonic-gate		/* NOTREACHED */
23147c478bdstevel@tonic-gate	}
23157c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_CDBEXTERN) {
23167c478bdstevel@tonic-gate		kmem_free((caddr_t)sp->cmd_pkt->pkt_cdbp,
23177c478bdstevel@tonic-gate		    (size_t)sp->cmd_cdblen);
23187c478bdstevel@tonic-gate	}
23197c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_SCBEXTERN) {
23207c478bdstevel@tonic-gate		kmem_free((caddr_t)sp->cmd_pkt->pkt_scbp,
23217c478bdstevel@tonic-gate		    (size_t)sp->cmd_scblen);
23227c478bdstevel@tonic-gate	}
23237c478bdstevel@tonic-gate	if (sp->cmd_flags & CFLAG_PRIVEXTERN) {
23247c478bdstevel@tonic-gate		kmem_free((caddr_t)sp->cmd_pkt->pkt_private,
23257c478bdstevel@tonic-gate		    (size_t)sp->cmd_privlen);
23267c478bdstevel@tonic-gate	}
23277c478bdstevel@tonic-gate	sp->cmd_flags = CFLAG_FREE;
23287c478bdstevel@tonic-gate	kmem_cache_free(fas->f_kmem_cache, (void *)sp);
23297c478bdstevel@tonic-gate}
23307c478bdstevel@tonic-gate
23317c478bdstevel@tonic-gate/*
23327c478bdstevel@tonic-gate * kmem cache constructor and destructor:
23337c478bdstevel@tonic-gate * When constructing, we bzero the cmd and allocate the dma handle
23347c478bdstevel@tonic-gate * When destructing, just free the dma handle
23357c478bdstevel@tonic-gate */
23367c478bdstevel@tonic-gatestatic int
23377c478bdstevel@tonic-gatefas_kmem_cache_constructor(void	*buf, void *cdrarg, int kmflags)
23387c478bdstevel@tonic-gate{
23397c478bdstevel@tonic-gate	struct fas_cmd *cmd = buf;
23407c478bdstevel@tonic-gate	struct fas *fas = cdrarg;
23417c478bdstevel@tonic-gate	int  (*callback)(caddr_t) = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP:
23421939740Sherry Moore	    DDI_DMA_DONTWAIT;
23437c478bdstevel@tonic-gate
23447c478bdstevel@tonic-gate	bzero(buf, EXTCMD_SIZE);
23457c478bdstevel@tonic-gate
23467c478bdstevel@tonic-gate	/*
23477c478bdstevel@tonic-gate	 * allocate a dma handle
23487c478bdstevel@tonic-gate	 */
23497c478bdstevel@tonic-gate	if ((ddi_dma_alloc_handle(fas->f_dev, fas->f_dma_attr, callback,
23507c478bdstevel@tonic-gate	    NULL, &cmd->cmd_dmahandle)) != DDI_SUCCESS) {
23517c478bdstevel@tonic-gate		return (-1);
23527c478bdstevel@tonic-gate	}
23537c478bdstevel@tonic-gate	return (0);
23547c478bdstevel@tonic-gate}
23557c478bdstevel@tonic-gate
23567c478bdstevel@tonic-gate/*ARGSUSED*/
23577c478bdstevel@tonic-gatestatic void
23587c478bdstevel@tonic-gatefas_kmem_cache_destructor(void *buf, void *cdrarg)
23597c478bdstevel@tonic-gate{
23607c478bdstevel@tonic-gate	struct fas_cmd *cmd = buf;
23617c478bdstevel@tonic-gate	if (cmd->cmd_dmahandle) {
23627c478bdstevel@tonic-gate		ddi_dma_free_handle(&cmd->cmd_dmahandle);
23637c478bdstevel@tonic-gate	}
23647c478bdstevel@tonic-gate}
23657c478bdstevel@tonic-gate
23667c478bdstevel@tonic-gate/*
23677c478bdstevel@tonic-gate * fas_scsi_start - Accept commands for transport
23687c478bdstevel@tonic-gate */
23697c478bdstevel@tonic-gatestatic int
23707c478bdstevel@tonic-gatefas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
23717c478bdstevel@tonic-gate{
23727c478bdstevel@tonic-gate	struct fas_cmd *sp = PKT2CMD(pkt);
23737c478bdstevel@tonic-gate	struct fas *fas = ADDR2FAS(ap);
23747c478bdstevel@tonic-gate	int rval;
23757c478bdstevel@tonic-gate	int intr = 0;
23767c478bdstevel@tonic-gate
23777c478bdstevel@tonic-gate	TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_START_START, "fas_scsi_start_start");
23787c478bdstevel@tonic-gate
23797c478bdstevel@tonic-gate#ifdef FAS_TEST
23807c478bdstevel@tonic-gate	if (fas_transport_busy > 0) {
23817c478bdstevel@tonic-gate		fas_transport_busy--;
23827c478bdstevel@tonic-gate		return (TRAN_BUSY);
23837c478bdstevel@tonic-gate	}
23847c478bdstevel@tonic-gate	if ((fas_transport_busy_rqs > 0) &&
23857c478bdstevel@tonic-gate	    (*(sp->cmd_pkt->pkt_cdbp) == SCMD_REQUEST_SENSE)) {
23867c478bdstevel@tonic-gate		fas_transport_busy_rqs--;
23877c478bdstevel@tonic-gate		return (TRAN_BUSY);
23887c478bdstevel@tonic-gate	}
23897c478bdstevel@tonic-gate	if (fas_transport_reject > 0) {
23907c478bdstevel@tonic-gate		fas_transport_reject--;
23917c478bdstevel@tonic-gate		return (TRAN_BADPKT);
23927c478bdstevel@tonic-gate	}
23937c478bdstevel@tonic-gate#endif
23947c478bdstevel@tonic-gate	/*
23957c478bdstevel@tonic-gate	 * prepare packet before taking the mutex
23967c478bdstevel@tonic-gate	 */
23977c478bdstevel@tonic-gate	rval = fas_prepare_pkt(fas, sp);
23987c478bdstevel@tonic-gate	if (rval != TRAN_ACCEPT) {
23997c478bdstevel@tonic-gate		TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_START_PREPARE_PKT_END,
24007c478bdstevel@tonic-gate		    "fas_scsi_start_end (prepare_pkt)");
24017c478bdstevel@tonic-gate		return (rval);
24027c478bdstevel@tonic-gate	}
24037c478bdstevel@tonic-gate
24047c478bdstevel@tonic-gate	/*
24057c478bdstevel@tonic-gate	 * fas mutex can be held for a long time; therefore, if the mutex is
24067c478bdstevel@tonic-gate	 * held, we queue the packet in a waitQ; we now should check
24077c478bdstevel@tonic-gate	 * the waitQ on every mutex_exit(FAS_MUTEX(fas)) but we really only
24087c478bdstevel@tonic-gate	 * need to do this when the bus is free
24097c478bdstevel@tonic-gate	 * don't put NOINTR cmds including proxy cmds in waitQ! These
24107c478bdstevel@tonic-gate	 * cmds are handled by fas_runpoll()
24117c478bdstevel@tonic-gate	 * if the waitQ is non-empty, queue the pkt anyway to preserve
24127c478bdstevel@tonic-gate	 * order
24137c478bdstevel@tonic-gate	 * the goal is to queue in waitQ as much as possible so at
24147c478bdstevel@tonic-gate	 * interrupt time, we can move the packets to readyQ or start
24157c478bdstevel@tonic-gate	 * a packet immediately. It helps to do this at interrupt
24167c478bdstevel@tonic-gate	 * time because we can then field more interrupts
24177c478bdstevel@tonic-gate	 */
24187c478bdstevel@tonic-gate	if ((sp->cmd_pkt_flags & FLAG_NOINTR) == 0) {
24197c478bdstevel@tonic-gate
24207c478bdstevel@tonic-gate		/*
24217c478bdstevel@tonic-gate		 * if the bus is not free, we will get an interrupt shortly
24227c478bdstevel@tonic-gate		 * so we don't want to take the fas mutex but queue up
24237c478bdstevel@tonic-gate		 * the packet in the waitQ
24247c478bdstevel@tonic-gate		 * also, if the waitQ is non-empty or there is an interrupt
24257c478bdstevel@tonic-gate		 * pending then queue up the packet in the waitQ and let the
24267c478bdstevel@tonic-gate		 * interrupt handler empty the waitQ
24277c478bdstevel@tonic-gate		 */
24287c478bdstevel@tonic-gate		mutex_enter(&fas->f_waitQ_mutex);
24297c478bdstevel@tonic-gate
24307c478bdstevel@tonic-gate		if ((fas->