17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5602ca9eaScth * Common Development and Distribution License (the "License"). 6602ca9eaScth * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22602ca9eaScth * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 24*89b43686SBayard Bell * Copyright (c) 2011 Bayard G. Bell. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * ISSUES 307c478bd9Sstevel@tonic-gate * 317c478bd9Sstevel@tonic-gate * - more consistent error messages 327c478bd9Sstevel@tonic-gate * - report name of device on errors? 337c478bd9Sstevel@tonic-gate * - if wide target renegotiates sync, back to narrow? 347c478bd9Sstevel@tonic-gate * - last_msgout is not accurate ???? 357c478bd9Sstevel@tonic-gate * - resolve XXXX 367c478bd9Sstevel@tonic-gate * - improve msg reject code (use special msg reject handler) 377c478bd9Sstevel@tonic-gate * - better use of IDE message 387c478bd9Sstevel@tonic-gate * - keep track if ATN remains asserted and target not going into 397c478bd9Sstevel@tonic-gate * a msg-out phase 407c478bd9Sstevel@tonic-gate * - improve comments 417c478bd9Sstevel@tonic-gate * - no slave accesses when start address is odd and dma hasn't started 427c478bd9Sstevel@tonic-gate * this affect asserting ATN 437c478bd9Sstevel@tonic-gate */ 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * fas - QLogic fas366 wide/fast SCSI Processor HBA driver with 477c478bd9Sstevel@tonic-gate * tagged and non-tagged queueing support 487c478bd9Sstevel@tonic-gate */ 497c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG) 507c478bd9Sstevel@tonic-gate #define DEBUG 1 517c478bd9Sstevel@tonic-gate #define FASDEBUG 527c478bd9Sstevel@tonic-gate #endif 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #define DMA_REG_TRACING /* enable dma register access tracing */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * standard header files 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate #include <sys/note.h> 617c478bd9Sstevel@tonic-gate #include <sys/scsi/scsi.h> 627c478bd9Sstevel@tonic-gate #include <sys/file.h> 637c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * private header files 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/fasdma.h> 697c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/fasreg.h> 707c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/fasvar.h> 717c478bd9Sstevel@tonic-gate #include <sys/scsi/adapters/fascmd.h> 727c478bd9Sstevel@tonic-gate #include <sys/scsi/impl/scsi_reset_notify.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate /* 757c478bd9Sstevel@tonic-gate * tunables 767c478bd9Sstevel@tonic-gate */ 777c478bd9Sstevel@tonic-gate static int fas_selection_timeout = 250; /* 250 milliseconds */ 787c478bd9Sstevel@tonic-gate static uchar_t fas_default_offset = DEFAULT_OFFSET; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * needed for presto support, do not remove 827c478bd9Sstevel@tonic-gate */ 837c478bd9Sstevel@tonic-gate static int fas_enable_sbus64 = 1; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 867c478bd9Sstevel@tonic-gate int fasdebug = 0; 877c478bd9Sstevel@tonic-gate int fasdebug_instance = -1; /* debug all instances */ 887c478bd9Sstevel@tonic-gate static int fas_burstsizes_limit = -1; 897c478bd9Sstevel@tonic-gate static int fas_no_sync_wide_backoff = 0; 907c478bd9Sstevel@tonic-gate #endif /* FASDEBUG */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * Local static data protected by global mutex 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate static kmutex_t fas_global_mutex; /* to allow concurrent attach */ 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static int fas_scsi_watchdog_tick; /* in seconds, for all */ 987c478bd9Sstevel@tonic-gate /* instances */ 997c478bd9Sstevel@tonic-gate static clock_t fas_tick; /* fas_watch() interval in Hz */ 1007c478bd9Sstevel@tonic-gate static timeout_id_t fas_reset_watch; /* timeout id for reset watch */ 1017c478bd9Sstevel@tonic-gate static timeout_id_t fas_timeout_id = 0; 1027c478bd9Sstevel@tonic-gate static int fas_timeout_initted = 0; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static krwlock_t fas_global_rwlock; 1057c478bd9Sstevel@tonic-gate 1067c478bd9Sstevel@tonic-gate static void *fas_state; /* soft state ptr */ 1077c478bd9Sstevel@tonic-gate static struct fas *fas_head; /* link all softstate structures */ 1087c478bd9Sstevel@tonic-gate static struct fas *fas_tail; /* for fas_watch() */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate static kmutex_t fas_log_mutex; 1117c478bd9Sstevel@tonic-gate static char fas_log_buf[256]; 1127c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(fas_global_mutex, fas_reset_watch)) 1137c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(fas_state fas_head fas_tail \ 1147c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick fas_tick)) 1157c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("safe sharing", fas::f_quiesce_timeid)) 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * dma attribute structure for scsi engine 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_fasattr = { 1217c478bd9Sstevel@tonic-gate DMA_ATTR_V0, (unsigned long long)0, 1227c478bd9Sstevel@tonic-gate (unsigned long long)0xffffffff, (unsigned long long)((1<<24)-1), 1237c478bd9Sstevel@tonic-gate 1, DEFAULT_BURSTSIZE, 1, 1247c478bd9Sstevel@tonic-gate (unsigned long long)0xffffffff, (unsigned long long)0xffffffff, 1257c478bd9Sstevel@tonic-gate 1, 512, 0 1267c478bd9Sstevel@tonic-gate }; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 1297c478bd9Sstevel@tonic-gate * optional torture test stuff 1307c478bd9Sstevel@tonic-gate */ 1317c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 1327c478bd9Sstevel@tonic-gate #define FAS_TEST 1337c478bd9Sstevel@tonic-gate static int fas_ptest_emsgin; 1347c478bd9Sstevel@tonic-gate static int fas_ptest_msgin; 1357c478bd9Sstevel@tonic-gate static int fas_ptest_msg = -1; 1367c478bd9Sstevel@tonic-gate static int fas_ptest_status; 1377c478bd9Sstevel@tonic-gate static int fas_ptest_data_in; 1387c478bd9Sstevel@tonic-gate static int fas_atest; 1397c478bd9Sstevel@tonic-gate static int fas_atest_disc; 1407c478bd9Sstevel@tonic-gate static int fas_atest_reconn; 1417c478bd9Sstevel@tonic-gate static void fas_test_abort(struct fas *fas, int slot); 1427c478bd9Sstevel@tonic-gate static int fas_rtest; 1437c478bd9Sstevel@tonic-gate static int fas_rtest_type; 1447c478bd9Sstevel@tonic-gate static void fas_test_reset(struct fas *fas, int slot); 1457c478bd9Sstevel@tonic-gate static int fas_force_timeout; 1467c478bd9Sstevel@tonic-gate static int fas_btest; 1477c478bd9Sstevel@tonic-gate static int fas_test_stop; 1487c478bd9Sstevel@tonic-gate static int fas_transport_busy; 1497c478bd9Sstevel@tonic-gate static int fas_transport_busy_rqs; 1507c478bd9Sstevel@tonic-gate static int fas_transport_reject; 1517c478bd9Sstevel@tonic-gate static int fas_arqs_failure; 1527c478bd9Sstevel@tonic-gate static int fas_tran_err; 1537c478bd9Sstevel@tonic-gate static int fas_test_untagged; 1547c478bd9Sstevel@tonic-gate static int fas_enable_untagged; 1557c478bd9Sstevel@tonic-gate #endif 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * warlock directives 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(dma fasdebug)) 1617c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_busy)) 1627c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_busy_rqs)) 1637c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_transport_reject)) 1647c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_arqs_failure)) 1657c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("just test variables", fas_tran_err)) 1667c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(fas_log_mutex, fas_log_buf)) 1677c478bd9Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(fas_global_mutex, fas_reset_watch)) 1687c478bd9Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(fas_state fas_head fas_tail \ 1697c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick fas_tick)) 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate /* 1727c478bd9Sstevel@tonic-gate * function prototypes 1737c478bd9Sstevel@tonic-gate * 1747c478bd9Sstevel@tonic-gate * scsa functions are exported by means of the transport table: 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate static int fas_scsi_tgt_probe(struct scsi_device *sd, 1777c478bd9Sstevel@tonic-gate int (*waitfunc)(void)); 1787c478bd9Sstevel@tonic-gate static int fas_scsi_tgt_init(dev_info_t *, dev_info_t *, 1797c478bd9Sstevel@tonic-gate scsi_hba_tran_t *, struct scsi_device *); 1807c478bd9Sstevel@tonic-gate static int fas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt); 1817c478bd9Sstevel@tonic-gate static int fas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt); 1827c478bd9Sstevel@tonic-gate static int fas_scsi_reset(struct scsi_address *ap, int level); 1837c478bd9Sstevel@tonic-gate static int fas_scsi_getcap(struct scsi_address *ap, char *cap, int whom); 1847c478bd9Sstevel@tonic-gate static int fas_scsi_setcap(struct scsi_address *ap, char *cap, int value, 1857c478bd9Sstevel@tonic-gate int whom); 1867c478bd9Sstevel@tonic-gate static struct scsi_pkt *fas_scsi_init_pkt(struct scsi_address *ap, 1877c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt, struct buf *bp, int cmdlen, int statuslen, 1887c478bd9Sstevel@tonic-gate int tgtlen, int flags, int (*callback)(), caddr_t arg); 1897c478bd9Sstevel@tonic-gate static void fas_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt); 1907c478bd9Sstevel@tonic-gate static void fas_scsi_dmafree(struct scsi_address *ap, 1917c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt); 1927c478bd9Sstevel@tonic-gate static void fas_scsi_sync_pkt(struct scsi_address *ap, 1937c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * internal functions: 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate static int fas_prepare_pkt(struct fas *fas, struct fas_cmd *sp); 1997c478bd9Sstevel@tonic-gate static int fas_alloc_tag(struct fas *fas, struct fas_cmd *sp); 2007c478bd9Sstevel@tonic-gate static int fas_accept_pkt(struct fas *fas, struct fas_cmd *sp, int flag); 2017c478bd9Sstevel@tonic-gate static void fas_empty_waitQ(struct fas *fas); 2027c478bd9Sstevel@tonic-gate static void fas_move_waitQ_to_readyQ(struct fas *fas); 2037c478bd9Sstevel@tonic-gate static void fas_check_waitQ_and_mutex_exit(struct fas *fas); 2047c478bd9Sstevel@tonic-gate static int fas_istart(struct fas *fas); 2057c478bd9Sstevel@tonic-gate static int fas_ustart(struct fas *fas); 2067c478bd9Sstevel@tonic-gate static int fas_startcmd(struct fas *fas, struct fas_cmd *sp); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate static int fas_pkt_alloc_extern(struct fas *fas, struct fas_cmd *sp, 2097c478bd9Sstevel@tonic-gate int cmdlen, int tgtlen, int statuslen, int kf); 2107c478bd9Sstevel@tonic-gate static void fas_pkt_destroy_extern(struct fas *fas, struct fas_cmd *sp); 2117c478bd9Sstevel@tonic-gate static int fas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags); 2127c478bd9Sstevel@tonic-gate static void fas_kmem_cache_destructor(void *buf, void *cdrarg); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate static int fas_finish(struct fas *fas); 2157c478bd9Sstevel@tonic-gate static void fas_handle_qfull(struct fas *fas, struct fas_cmd *sp); 2167c478bd9Sstevel@tonic-gate static void fas_restart_cmd(void *); 2177c478bd9Sstevel@tonic-gate static int fas_dopoll(struct fas *fas, int timeout); 2187c478bd9Sstevel@tonic-gate static void fas_runpoll(struct fas *fas, short slot, struct fas_cmd *sp); 2197c478bd9Sstevel@tonic-gate static uint_t fas_intr(caddr_t arg); 2207c478bd9Sstevel@tonic-gate static int fas_intr_svc(struct fas *fas); 2217c478bd9Sstevel@tonic-gate static int fas_phasemanage(struct fas *fas); 2227c478bd9Sstevel@tonic-gate static int fas_handle_unknown(struct fas *fas); 2237c478bd9Sstevel@tonic-gate static int fas_handle_cmd_start(struct fas *fas); 2247c478bd9Sstevel@tonic-gate static int fas_handle_cmd_done(struct fas *fas); 2257c478bd9Sstevel@tonic-gate static int fas_handle_msg_out_start(struct fas *fas); 2267c478bd9Sstevel@tonic-gate static int fas_handle_msg_out_done(struct fas *fas); 2277c478bd9Sstevel@tonic-gate static int fas_handle_clearing(struct fas *fas); 2287c478bd9Sstevel@tonic-gate static int fas_handle_data_start(struct fas *fas); 2297c478bd9Sstevel@tonic-gate static int fas_handle_data_done(struct fas *fas); 2307c478bd9Sstevel@tonic-gate static int fas_handle_c_cmplt(struct fas *fas); 2317c478bd9Sstevel@tonic-gate static int fas_handle_msg_in_start(struct fas *fas); 2327c478bd9Sstevel@tonic-gate static int fas_handle_more_msgin(struct fas *fas); 2337c478bd9Sstevel@tonic-gate static int fas_handle_msg_in_done(struct fas *fas); 2347c478bd9Sstevel@tonic-gate static int fas_onebyte_msg(struct fas *fas); 2357c478bd9Sstevel@tonic-gate static int fas_twobyte_msg(struct fas *fas); 2367c478bd9Sstevel@tonic-gate static int fas_multibyte_msg(struct fas *fas); 2377c478bd9Sstevel@tonic-gate static void fas_revert_to_async(struct fas *fas, int tgt); 2387c478bd9Sstevel@tonic-gate static int fas_finish_select(struct fas *fas); 2397c478bd9Sstevel@tonic-gate static int fas_reselect_preempt(struct fas *fas); 2407c478bd9Sstevel@tonic-gate static int fas_reconnect(struct fas *fas); 2417c478bd9Sstevel@tonic-gate static int fas_handle_selection(struct fas *fas); 2427c478bd9Sstevel@tonic-gate static void fas_head_of_readyQ(struct fas *fas, struct fas_cmd *sp); 2437c478bd9Sstevel@tonic-gate static int fas_handle_gross_err(struct fas *fas); 2447c478bd9Sstevel@tonic-gate static int fas_illegal_cmd_or_bus_reset(struct fas *fas); 2457c478bd9Sstevel@tonic-gate static int fas_check_dma_error(struct fas *fas); 2467c478bd9Sstevel@tonic-gate 2477c478bd9Sstevel@tonic-gate static void fas_make_sdtr(struct fas *fas, int msgout_offset, int target); 2487c478bd9Sstevel@tonic-gate static void fas_make_wdtr(struct fas *fas, int msgout_offset, int target, 2497c478bd9Sstevel@tonic-gate int width); 2507c478bd9Sstevel@tonic-gate static void fas_update_props(struct fas *fas, int tgt); 2517c478bd9Sstevel@tonic-gate static void fas_update_this_prop(struct fas *fas, char *property, int value); 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate static int fas_commoncap(struct scsi_address *ap, char *cap, int val, 2547c478bd9Sstevel@tonic-gate int tgtonly, int doset); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate static void fas_watch(void *arg); 2577c478bd9Sstevel@tonic-gate static void fas_watchsubr(struct fas *fas); 2587c478bd9Sstevel@tonic-gate static void fas_cmd_timeout(struct fas *fas, int slot); 2597c478bd9Sstevel@tonic-gate static void fas_sync_wide_backoff(struct fas *fas, struct fas_cmd *sp, 2607c478bd9Sstevel@tonic-gate int slot); 2617c478bd9Sstevel@tonic-gate static void fas_reset_sync_wide(struct fas *fas); 2627c478bd9Sstevel@tonic-gate static void fas_set_wide_conf3(struct fas *fas, int target, int width); 2637c478bd9Sstevel@tonic-gate static void fas_force_renegotiation(struct fas *fas, int target); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate static int fas_set_new_window(struct fas *fas, struct fas_cmd *sp); 2667c478bd9Sstevel@tonic-gate static int fas_restore_pointers(struct fas *fas, struct fas_cmd *sp); 2677c478bd9Sstevel@tonic-gate static int fas_next_window(struct fas *fas, struct fas_cmd *sp, uint64_t end); 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 2707c478bd9Sstevel@tonic-gate static void fas_log(struct fas *fas, int level, const char *fmt, ...); 2717c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 2727c478bd9Sstevel@tonic-gate static void fas_printf(struct fas *fas, const char *fmt, ...); 2737c478bd9Sstevel@tonic-gate static void fas_printstate(struct fas *fas, char *msg); 2747c478bd9Sstevel@tonic-gate static void fas_dump_cmd(struct fas *fas, struct fas_cmd *sp); 2757c478bd9Sstevel@tonic-gate static void fas_short_dump_cmd(struct fas *fas, struct fas_cmd *sp); 2767c478bd9Sstevel@tonic-gate static char *fas_state_name(ushort_t state); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate static void fas_makeproxy_cmd(struct fas_cmd *sp, 2797c478bd9Sstevel@tonic-gate struct scsi_address *ap, struct scsi_pkt *pkt, int nmsg, ...); 2807c478bd9Sstevel@tonic-gate static int fas_do_proxy_cmd(struct fas *fas, struct fas_cmd *sp, 2817c478bd9Sstevel@tonic-gate struct scsi_address *ap, char *what); 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate static void fas_internal_reset(struct fas *fas, int reset_action); 2847c478bd9Sstevel@tonic-gate static int fas_alloc_active_slots(struct fas *fas, int slot, int flag); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate static int fas_abort_curcmd(struct fas *fas); 2877c478bd9Sstevel@tonic-gate static int fas_abort_cmd(struct fas *fas, struct fas_cmd *sp, int slot); 2887c478bd9Sstevel@tonic-gate static int fas_do_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt); 2897c478bd9Sstevel@tonic-gate static int fas_do_scsi_reset(struct scsi_address *ap, int level); 2907c478bd9Sstevel@tonic-gate static int fas_remove_from_readyQ(struct fas *fas, struct fas_cmd *sp, 2917c478bd9Sstevel@tonic-gate int slot); 2927c478bd9Sstevel@tonic-gate static void fas_flush_readyQ(struct fas *fas, int slot); 2937c478bd9Sstevel@tonic-gate static void fas_flush_tagQ(struct fas *fas, int slot); 2947c478bd9Sstevel@tonic-gate static void fas_flush_cmd(struct fas *fas, struct fas_cmd *sp, 2957c478bd9Sstevel@tonic-gate uchar_t reason, uint_t stat); 2967c478bd9Sstevel@tonic-gate static int fas_abort_connected_cmd(struct fas *fas, struct fas_cmd *sp, 2977c478bd9Sstevel@tonic-gate uchar_t msg); 2987c478bd9Sstevel@tonic-gate static int fas_abort_disconnected_cmd(struct fas *fas, struct scsi_address *ap, 2997c478bd9Sstevel@tonic-gate struct fas_cmd *sp, uchar_t msg, int slot); 3007c478bd9Sstevel@tonic-gate static void fas_mark_packets(struct fas *fas, int slot, uchar_t reason, 3017c478bd9Sstevel@tonic-gate uint_t stat); 3027c478bd9Sstevel@tonic-gate static void fas_set_pkt_reason(struct fas *fas, struct fas_cmd *sp, 3037c478bd9Sstevel@tonic-gate uchar_t reason, uint_t stat); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate static int fas_reset_bus(struct fas *fas); 3067c478bd9Sstevel@tonic-gate static int fas_reset_recovery(struct fas *fas); 3077c478bd9Sstevel@tonic-gate static int fas_reset_connected_cmd(struct fas *fas, struct scsi_address *ap); 3087c478bd9Sstevel@tonic-gate static int fas_reset_disconnected_cmd(struct fas *fas, struct scsi_address *ap); 3097c478bd9Sstevel@tonic-gate static void fas_start_watch_reset_delay(struct fas *); 3107c478bd9Sstevel@tonic-gate static void fas_setup_reset_delay(struct fas *fas); 3117c478bd9Sstevel@tonic-gate static void fas_watch_reset_delay(void *arg); 3127c478bd9Sstevel@tonic-gate static int fas_watch_reset_delay_subr(struct fas *fas); 3137c478bd9Sstevel@tonic-gate static void fas_reset_cleanup(struct fas *fas, int slot); 3147c478bd9Sstevel@tonic-gate static int fas_scsi_reset_notify(struct scsi_address *ap, int flag, 3157c478bd9Sstevel@tonic-gate void (*callback)(caddr_t), caddr_t arg); 3167c478bd9Sstevel@tonic-gate static int fas_scsi_quiesce(dev_info_t *hba_dip); 3177c478bd9Sstevel@tonic-gate static int fas_scsi_unquiesce(dev_info_t *hba_dip); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate static void fas_set_throttles(struct fas *fas, int slot, 3207c478bd9Sstevel@tonic-gate int n, int what); 3217c478bd9Sstevel@tonic-gate static void fas_set_all_lun_throttles(struct fas *fas, int slot, int what); 3227c478bd9Sstevel@tonic-gate static void fas_full_throttle(struct fas *fas, int slot); 3237c478bd9Sstevel@tonic-gate static void fas_remove_cmd(struct fas *fas, struct fas_cmd *sp, int timeout); 3247c478bd9Sstevel@tonic-gate static void fas_decrement_ncmds(struct fas *fas, struct fas_cmd *sp); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate static int fas_quiesce_bus(struct fas *fas); 3277c478bd9Sstevel@tonic-gate static int fas_unquiesce_bus(struct fas *fas); 3287c478bd9Sstevel@tonic-gate static void fas_ncmds_checkdrain(void *arg); 3297c478bd9Sstevel@tonic-gate static int fas_check_outstanding(struct fas *fas); 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate static int fas_create_arq_pkt(struct fas *fas, struct scsi_address *ap); 3327c478bd9Sstevel@tonic-gate static int fas_delete_arq_pkt(struct fas *fas, struct scsi_address *ap); 3337c478bd9Sstevel@tonic-gate static int fas_handle_sts_chk(struct fas *fas, struct fas_cmd *sp); 3347c478bd9Sstevel@tonic-gate void fas_complete_arq_pkt(struct scsi_pkt *pkt); 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate void fas_call_pkt_comp(struct fas *fas, struct fas_cmd *sp); 3377c478bd9Sstevel@tonic-gate void fas_empty_callbackQ(struct fas *fas); 3387c478bd9Sstevel@tonic-gate int fas_init_callbacks(struct fas *fas); 3397c478bd9Sstevel@tonic-gate void fas_destroy_callbacks(struct fas *fas); 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate static int fas_check_dma_error(struct fas *fas); 3427c478bd9Sstevel@tonic-gate static int fas_init_chip(struct fas *fas, uchar_t id); 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate static void fas_read_fifo(struct fas *fas); 3457c478bd9Sstevel@tonic-gate static void fas_write_fifo(struct fas *fas, uchar_t *buf, int length, int pad); 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 3487c478bd9Sstevel@tonic-gate static void fas_reg_cmd_write(struct fas *fas, uint8_t cmd); 3497c478bd9Sstevel@tonic-gate static void fas_reg_write(struct fas *fas, volatile uint8_t *p, uint8_t what); 3507c478bd9Sstevel@tonic-gate static uint8_t fas_reg_read(struct fas *fas, volatile uint8_t *p); 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate static void fas_dma_reg_write(struct fas *fas, volatile uint32_t *p, 3537c478bd9Sstevel@tonic-gate uint32_t what); 3547c478bd9Sstevel@tonic-gate static uint32_t fas_dma_reg_read(struct fas *fas, volatile uint32_t *p); 3557c478bd9Sstevel@tonic-gate #else 3567c478bd9Sstevel@tonic-gate #define fas_reg_cmd_write(fas, cmd) \ 3577c478bd9Sstevel@tonic-gate fas->f_reg->fas_cmd = (cmd), fas->f_last_cmd = (cmd) 3587c478bd9Sstevel@tonic-gate #define fas_reg_write(fas, p, what) *(p) = (what) 3597c478bd9Sstevel@tonic-gate #define fas_reg_read(fas, p) *(p) 3607c478bd9Sstevel@tonic-gate #define fas_dma_reg_write(fas, p, what) *(p) = (what) 3617c478bd9Sstevel@tonic-gate #define fas_dma_reg_read(fas, p) *(p) 3627c478bd9Sstevel@tonic-gate #endif 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* 3657c478bd9Sstevel@tonic-gate * autoconfiguration data and routines. 3667c478bd9Sstevel@tonic-gate */ 3677c478bd9Sstevel@tonic-gate static int fas_attach(dev_info_t *dev, ddi_attach_cmd_t cmd); 3687c478bd9Sstevel@tonic-gate static int fas_detach(dev_info_t *dev, ddi_detach_cmd_t cmd); 3697c478bd9Sstevel@tonic-gate static int fas_dr_detach(dev_info_t *dev); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate static struct dev_ops fas_ops = { 3727c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 3737c478bd9Sstevel@tonic-gate 0, /* refcnt */ 3747c478bd9Sstevel@tonic-gate ddi_no_info, /* info */ 3757c478bd9Sstevel@tonic-gate nulldev, /* identify */ 3767c478bd9Sstevel@tonic-gate nulldev, /* probe */ 3777c478bd9Sstevel@tonic-gate fas_attach, /* attach */ 3787c478bd9Sstevel@tonic-gate fas_detach, /* detach */ 3797c478bd9Sstevel@tonic-gate nodev, /* reset */ 3807c478bd9Sstevel@tonic-gate NULL, /* driver operations */ 3817c478bd9Sstevel@tonic-gate NULL, /* bus operations */ 38219397407SSherry Moore NULL, /* power */ 38319397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 3847c478bd9Sstevel@tonic-gate }; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 3877c478bd9Sstevel@tonic-gate &mod_driverops, /* Type of module. This one is a driver */ 38819397407SSherry Moore "FAS SCSI HBA Driver", /* Name of the module. */ 3897c478bd9Sstevel@tonic-gate &fas_ops, /* driver ops */ 3907c478bd9Sstevel@tonic-gate }; 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3937c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modldrv, NULL 3947c478bd9Sstevel@tonic-gate }; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate int 3977c478bd9Sstevel@tonic-gate _init(void) 3987c478bd9Sstevel@tonic-gate { 3997c478bd9Sstevel@tonic-gate int rval; 4007c478bd9Sstevel@tonic-gate /* CONSTCOND */ 4017c478bd9Sstevel@tonic-gate ASSERT(NO_COMPETING_THREADS); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate rval = ddi_soft_state_init(&fas_state, sizeof (struct fas), 4047c478bd9Sstevel@tonic-gate FAS_INITIAL_SOFT_SPACE); 4057c478bd9Sstevel@tonic-gate if (rval != 0) { 4067c478bd9Sstevel@tonic-gate return (rval); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate if ((rval = scsi_hba_init(&modlinkage)) != 0) { 4107c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&fas_state); 4117c478bd9Sstevel@tonic-gate return (rval); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate mutex_init(&fas_global_mutex, NULL, MUTEX_DRIVER, NULL); 4157c478bd9Sstevel@tonic-gate rw_init(&fas_global_rwlock, NULL, RW_DRIVER, NULL); 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate mutex_init(&fas_log_mutex, NULL, MUTEX_DRIVER, NULL); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate if ((rval = mod_install(&modlinkage)) != 0) { 4207c478bd9Sstevel@tonic-gate mutex_destroy(&fas_log_mutex); 4217c478bd9Sstevel@tonic-gate rw_destroy(&fas_global_rwlock); 4227c478bd9Sstevel@tonic-gate mutex_destroy(&fas_global_mutex); 4237c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&fas_state); 4247c478bd9Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 4257c478bd9Sstevel@tonic-gate return (rval); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate return (rval); 4297c478bd9Sstevel@tonic-gate } 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate int 4327c478bd9Sstevel@tonic-gate _fini(void) 4337c478bd9Sstevel@tonic-gate { 4347c478bd9Sstevel@tonic-gate int rval; 4357c478bd9Sstevel@tonic-gate /* CONSTCOND */ 4367c478bd9Sstevel@tonic-gate ASSERT(NO_COMPETING_THREADS); 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate if ((rval = mod_remove(&modlinkage)) == 0) { 4397c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&fas_state); 4407c478bd9Sstevel@tonic-gate scsi_hba_fini(&modlinkage); 4417c478bd9Sstevel@tonic-gate mutex_destroy(&fas_log_mutex); 4427c478bd9Sstevel@tonic-gate rw_destroy(&fas_global_rwlock); 4437c478bd9Sstevel@tonic-gate mutex_destroy(&fas_global_mutex); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate return (rval); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate int 4497c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 4507c478bd9Sstevel@tonic-gate { 4517c478bd9Sstevel@tonic-gate /* CONSTCOND */ 4527c478bd9Sstevel@tonic-gate ASSERT(NO_COMPETING_THREADS); 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate static int 4587c478bd9Sstevel@tonic-gate fas_scsi_tgt_probe(struct scsi_device *sd, 4597c478bd9Sstevel@tonic-gate int (*waitfunc)(void)) 4607c478bd9Sstevel@tonic-gate { 4617c478bd9Sstevel@tonic-gate dev_info_t *dip = ddi_get_parent(sd->sd_dev); 4627c478bd9Sstevel@tonic-gate int rval = SCSIPROBE_FAILURE; 4637c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran; 4647c478bd9Sstevel@tonic-gate struct fas *fas; 4657c478bd9Sstevel@tonic-gate int tgt = sd->sd_address.a_target; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate tran = ddi_get_driver_private(dip); 4687c478bd9Sstevel@tonic-gate ASSERT(tran != NULL); 4697c478bd9Sstevel@tonic-gate fas = TRAN2FAS(tran); 4707c478bd9Sstevel@tonic-gate 4717c478bd9Sstevel@tonic-gate /* 4727c478bd9Sstevel@tonic-gate * force renegotiation since inquiry cmds do not cause 4737c478bd9Sstevel@tonic-gate * check conditions 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 4767c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, tgt); 4777c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 4787c478bd9Sstevel@tonic-gate rval = scsi_hba_probe(sd, waitfunc); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * the scsi-options precedence is: 4827c478bd9Sstevel@tonic-gate * target-scsi-options highest 4837c478bd9Sstevel@tonic-gate * device-type-scsi-options 4847c478bd9Sstevel@tonic-gate * per bus scsi-options 4857c478bd9Sstevel@tonic-gate * global scsi-options lowest 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 4887c478bd9Sstevel@tonic-gate if ((rval == SCSIPROBE_EXISTS) && 4897c478bd9Sstevel@tonic-gate ((fas->f_target_scsi_options_defined & (1 << tgt)) == 0)) { 4907c478bd9Sstevel@tonic-gate int options; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate options = scsi_get_device_type_scsi_options(dip, sd, -1); 4937c478bd9Sstevel@tonic-gate if (options != -1) { 4947c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[tgt] = options; 4957c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, 4967c478bd9Sstevel@tonic-gate "?target%x-scsi-options = 0x%x\n", tgt, 4977c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[tgt]); 4987c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, tgt); 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate IPRINTF2("target%x-scsi-options= 0x%x\n", 5047c478bd9Sstevel@tonic-gate tgt, fas->f_target_scsi_options[tgt]); 5057c478bd9Sstevel@tonic-gate 5067c478bd9Sstevel@tonic-gate return (rval); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5117c478bd9Sstevel@tonic-gate static int 5127c478bd9Sstevel@tonic-gate fas_scsi_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, 5137c478bd9Sstevel@tonic-gate scsi_hba_tran_t *hba_tran, struct scsi_device *sd) 5147c478bd9Sstevel@tonic-gate { 5157c478bd9Sstevel@tonic-gate return (((sd->sd_address.a_target < NTARGETS_WIDE) && 5167c478bd9Sstevel@tonic-gate (sd->sd_address.a_lun < NLUNS_PER_TARGET)) ? 5177c478bd9Sstevel@tonic-gate DDI_SUCCESS : DDI_FAILURE); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5217c478bd9Sstevel@tonic-gate static int 5227c478bd9Sstevel@tonic-gate fas_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 5237c478bd9Sstevel@tonic-gate { 5247c478bd9Sstevel@tonic-gate struct fas *fas = NULL; 5257c478bd9Sstevel@tonic-gate volatile struct dma *dmar = NULL; 5267c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg; 5277c478bd9Sstevel@tonic-gate ddi_dma_attr_t *fas_dma_attr; 5287c478bd9Sstevel@tonic-gate ddi_device_acc_attr_t dev_attr; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate int instance, id, slot, i, hm_rev; 5317c478bd9Sstevel@tonic-gate size_t rlen; 5327c478bd9Sstevel@tonic-gate uint_t count; 5337c478bd9Sstevel@tonic-gate char buf[64]; 5347c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran = NULL; 5357c478bd9Sstevel@tonic-gate char intr_added = 0; 5367c478bd9Sstevel@tonic-gate char mutex_init_done = 0; 5377c478bd9Sstevel@tonic-gate char hba_attached = 0; 5387c478bd9Sstevel@tonic-gate char bound_handle = 0; 5397c478bd9Sstevel@tonic-gate char *prop_template = "target%d-scsi-options"; 5407c478bd9Sstevel@tonic-gate char prop_str[32]; 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate /* CONSTCOND */ 5437c478bd9Sstevel@tonic-gate ASSERT(NO_COMPETING_THREADS); 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate switch (cmd) { 5467c478bd9Sstevel@tonic-gate case DDI_ATTACH: 5477c478bd9Sstevel@tonic-gate break; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate case DDI_RESUME: 5507c478bd9Sstevel@tonic-gate if ((tran = ddi_get_driver_private(dip)) == NULL) 5517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate fas = TRAN2FAS(tran); 5547c478bd9Sstevel@tonic-gate if (!fas) { 5557c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Reset hardware and softc to "no outstanding commands" 5597c478bd9Sstevel@tonic-gate * Note that a check condition can result on first command 5607c478bd9Sstevel@tonic-gate * to a target. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 5637c478bd9Sstevel@tonic-gate fas_internal_reset(fas, 5647c478bd9Sstevel@tonic-gate FAS_RESET_SOFTC|FAS_RESET_FAS|FAS_RESET_DMA); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate fas->f_suspended = 0; 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate /* make sure that things get started */ 5717c478bd9Sstevel@tonic-gate (void) fas_istart(fas); 5727c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 5757c478bd9Sstevel@tonic-gate if (fas_timeout_id == 0) { 5767c478bd9Sstevel@tonic-gate fas_timeout_id = timeout(fas_watch, NULL, fas_tick); 5777c478bd9Sstevel@tonic-gate fas_timeout_initted = 1; 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate default: 5847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * Since we know that some instantiations of this device can 5917c478bd9Sstevel@tonic-gate * be plugged into slave-only SBus slots, check to see whether 5927c478bd9Sstevel@tonic-gate * this is one such. 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate if (ddi_slaveonly(dip) == DDI_SUCCESS) { 5957c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5967c478bd9Sstevel@tonic-gate "fas%d: device in slave-only slot", instance); 5977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate if (ddi_intr_hilevel(dip, 0)) { 6017c478bd9Sstevel@tonic-gate /* 6027c478bd9Sstevel@tonic-gate * Interrupt number '0' is a high-level interrupt. 6037c478bd9Sstevel@tonic-gate * At this point you either add a special interrupt 6047c478bd9Sstevel@tonic-gate * handler that triggers a soft interrupt at a lower level, 6057c478bd9Sstevel@tonic-gate * or - more simply and appropriately here - you just 6067c478bd9Sstevel@tonic-gate * fail the attach. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6097c478bd9Sstevel@tonic-gate "fas%d: Device is using a hilevel intr", instance); 6107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6117c478bd9Sstevel@tonic-gate } 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate /* 6147c478bd9Sstevel@tonic-gate * Allocate softc information. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(fas_state, instance) != DDI_SUCCESS) { 6177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6187c478bd9Sstevel@tonic-gate "fas%d: cannot allocate soft state", instance); 6197c478bd9Sstevel@tonic-gate goto fail; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate 6227c478bd9Sstevel@tonic-gate fas = (struct fas *)ddi_get_soft_state(fas_state, instance); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate if (fas == NULL) { 6257c478bd9Sstevel@tonic-gate goto fail; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * map in device registers 6307c478bd9Sstevel@tonic-gate */ 6317c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 6327c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 6337c478bd9Sstevel@tonic-gate dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, (uint_t)0, (caddr_t *)&dmar, 6367c478bd9Sstevel@tonic-gate (off_t)0, (off_t)sizeof (struct dma), 6377c478bd9Sstevel@tonic-gate &dev_attr, &fas->f_dmar_acc_handle) != DDI_SUCCESS) { 6387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas%d: cannot map dma", instance); 6397c478bd9Sstevel@tonic-gate goto fail; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate if (ddi_regs_map_setup(dip, (uint_t)1, (caddr_t *)&fasreg, 6437c478bd9Sstevel@tonic-gate (off_t)0, (off_t)sizeof (struct fasreg), 6447c478bd9Sstevel@tonic-gate &dev_attr, &fas->f_regs_acc_handle) != DDI_SUCCESS) { 6457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6467c478bd9Sstevel@tonic-gate "fas%d: unable to map fas366 registers", instance); 6477c478bd9Sstevel@tonic-gate goto fail; 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate fas_dma_attr = &dma_fasattr; 6517c478bd9Sstevel@tonic-gate if (ddi_dma_alloc_handle(dip, fas_dma_attr, 6527c478bd9Sstevel@tonic-gate DDI_DMA_SLEEP, NULL, &fas->f_dmahandle) != DDI_SUCCESS) { 6537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6547c478bd9Sstevel@tonic-gate "fas%d: cannot alloc dma handle", instance); 6557c478bd9Sstevel@tonic-gate goto fail; 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* 6597c478bd9Sstevel@tonic-gate * allocate cmdarea and its dma handle 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate if (ddi_dma_mem_alloc(fas->f_dmahandle, 6627c478bd9Sstevel@tonic-gate (uint_t)2*FIFOSIZE, 6637c478bd9Sstevel@tonic-gate &dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 6647c478bd9Sstevel@tonic-gate NULL, (caddr_t *)&fas->f_cmdarea, &rlen, 6657c478bd9Sstevel@tonic-gate &fas->f_cmdarea_acc_handle) != DDI_SUCCESS) { 6667c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6677c478bd9Sstevel@tonic-gate "fas%d: cannot alloc cmd area", instance); 6687c478bd9Sstevel@tonic-gate goto fail; 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate fas->f_reg = fasreg; 6727c478bd9Sstevel@tonic-gate fas->f_dma = dmar; 6737c478bd9Sstevel@tonic-gate fas->f_instance = instance; 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate if (ddi_dma_addr_bind_handle(fas->f_dmahandle, 6767c478bd9Sstevel@tonic-gate NULL, (caddr_t)fas->f_cmdarea, 6777c478bd9Sstevel@tonic-gate rlen, DDI_DMA_RDWR|DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 6787c478bd9Sstevel@tonic-gate &fas->f_dmacookie, &count) != DDI_DMA_MAPPED) { 6797c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 6807c478bd9Sstevel@tonic-gate "fas%d: cannot bind cmdarea", instance); 6817c478bd9Sstevel@tonic-gate goto fail; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate bound_handle++; 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate ASSERT(count == 1); 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * Allocate a transport structure 6897c478bd9Sstevel@tonic-gate */ 6907c478bd9Sstevel@tonic-gate tran = scsi_hba_tran_alloc(dip, SCSI_HBA_CANSLEEP); 6917c478bd9Sstevel@tonic-gate 692602ca9eaScth /* Indicate that we are 'sizeof (scsi_*(9S))' clean. */ 693602ca9eaScth scsi_size_clean(dip); /* SCSI_SIZE_CLEAN_VERIFY ok */ 694602ca9eaScth 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * initialize transport structure 6977c478bd9Sstevel@tonic-gate */ 6987c478bd9Sstevel@tonic-gate fas->f_tran = tran; 6997c478bd9Sstevel@tonic-gate fas->f_dev = dip; 7007c478bd9Sstevel@tonic-gate tran->tran_hba_private = fas; 7017c478bd9Sstevel@tonic-gate tran->tran_tgt_private = NULL; 7027c478bd9Sstevel@tonic-gate tran->tran_tgt_init = fas_scsi_tgt_init; 7037c478bd9Sstevel@tonic-gate tran->tran_tgt_probe = fas_scsi_tgt_probe; 7047c478bd9Sstevel@tonic-gate tran->tran_tgt_free = NULL; 7057c478bd9Sstevel@tonic-gate tran->tran_start = fas_scsi_start; 7067c478bd9Sstevel@tonic-gate tran->tran_abort = fas_scsi_abort; 7077c478bd9Sstevel@tonic-gate tran->tran_reset = fas_scsi_reset; 7087c478bd9Sstevel@tonic-gate tran->tran_getcap = fas_scsi_getcap; 7097c478bd9Sstevel@tonic-gate tran->tran_setcap = fas_scsi_setcap; 7107c478bd9Sstevel@tonic-gate tran->tran_init_pkt = fas_scsi_init_pkt; 7117c478bd9Sstevel@tonic-gate tran->tran_destroy_pkt = fas_scsi_destroy_pkt; 7127c478bd9Sstevel@tonic-gate tran->tran_dmafree = fas_scsi_dmafree; 7137c478bd9Sstevel@tonic-gate tran->tran_sync_pkt = fas_scsi_sync_pkt; 7147c478bd9Sstevel@tonic-gate tran->tran_reset_notify = fas_scsi_reset_notify; 7157c478bd9Sstevel@tonic-gate tran->tran_get_bus_addr = NULL; 7167c478bd9Sstevel@tonic-gate tran->tran_get_name = NULL; 7177c478bd9Sstevel@tonic-gate tran->tran_quiesce = fas_scsi_quiesce; 7187c478bd9Sstevel@tonic-gate tran->tran_unquiesce = fas_scsi_unquiesce; 7197c478bd9Sstevel@tonic-gate tran->tran_bus_reset = NULL; 7207c478bd9Sstevel@tonic-gate tran->tran_add_eventcall = NULL; 7217c478bd9Sstevel@tonic-gate tran->tran_get_eventcookie = NULL; 7227c478bd9Sstevel@tonic-gate tran->tran_post_event = NULL; 7237c478bd9Sstevel@tonic-gate tran->tran_remove_eventcall = NULL; 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate fas->f_force_async = 0; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* 7287c478bd9Sstevel@tonic-gate * disable tagged queuing and wide for all targets 7297c478bd9Sstevel@tonic-gate * (will be enabled by target driver if required) 7307c478bd9Sstevel@tonic-gate * sync is enabled by default 7317c478bd9Sstevel@tonic-gate */ 7327c478bd9Sstevel@tonic-gate fas->f_nowide = fas->f_notag = ALL_TARGETS; 7337c478bd9Sstevel@tonic-gate fas->f_force_narrow = ALL_TARGETS; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 7367c478bd9Sstevel@tonic-gate * By default we assume embedded devices and save time 7377c478bd9Sstevel@tonic-gate * checking for timeouts in fas_watch() by skipping 7387c478bd9Sstevel@tonic-gate * the rest of luns 7397c478bd9Sstevel@tonic-gate * If we're talking to any non-embedded devices, 7407c478bd9Sstevel@tonic-gate * we can't cheat and skip over non-zero luns anymore 7417c478bd9Sstevel@tonic-gate * in fas_watch() and fas_ustart(). 7427c478bd9Sstevel@tonic-gate */ 7437c478bd9Sstevel@tonic-gate fas->f_dslot = NLUNS_PER_TARGET; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate /* 7467c478bd9Sstevel@tonic-gate * f_active is used for saving disconnected cmds; 7477c478bd9Sstevel@tonic-gate * For tagged targets, we need to increase the size later 7487c478bd9Sstevel@tonic-gate * Only allocate for Lun == 0, if we probe a lun > 0 then 7497c478bd9Sstevel@tonic-gate * we allocate an active structure 7507c478bd9Sstevel@tonic-gate * If TQ gets enabled then we need to increase the size 7517c478bd9Sstevel@tonic-gate * to hold 256 cmds 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot += NLUNS_PER_TARGET) { 7547c478bd9Sstevel@tonic-gate (void) fas_alloc_active_slots(fas, slot, KM_SLEEP); 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate /* 7587c478bd9Sstevel@tonic-gate * initialize the qfull retry counts 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 7617c478bd9Sstevel@tonic-gate fas->f_qfull_retries[i] = QFULL_RETRIES; 7627c478bd9Sstevel@tonic-gate fas->f_qfull_retry_interval[i] = 7637c478bd9Sstevel@tonic-gate drv_usectohz(QFULL_RETRY_INTERVAL * 1000); 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * Initialize throttles. 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE); 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * Initialize mask of deferred property updates 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate fas->f_props_update = 0; 7767c478bd9Sstevel@tonic-gate 7777c478bd9Sstevel@tonic-gate /* 7787c478bd9Sstevel@tonic-gate * set host ID 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate fas->f_fasconf = DEFAULT_HOSTID; 7817c478bd9Sstevel@tonic-gate id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "initiator-id", -1); 7827c478bd9Sstevel@tonic-gate if (id == -1) { 7837c478bd9Sstevel@tonic-gate id = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 7847c478bd9Sstevel@tonic-gate "scsi-initiator-id", -1); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate if (id != DEFAULT_HOSTID && id >= 0 && id < NTARGETS_WIDE) { 7877c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, "?initiator SCSI ID now %d\n", id); 7887c478bd9Sstevel@tonic-gate fas->f_fasconf = (uchar_t)id; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate /* 7927c478bd9Sstevel@tonic-gate * find the burstsize and reduce ours if necessary 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate fas->f_dma_attr = fas_dma_attr; 7957c478bd9Sstevel@tonic-gate fas->f_dma_attr->dma_attr_burstsizes &= 7967c478bd9Sstevel@tonic-gate ddi_dma_burstsizes(fas->f_dmahandle); 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 7997c478bd9Sstevel@tonic-gate fas->f_dma_attr->dma_attr_burstsizes &= fas_burstsizes_limit; 8007c478bd9Sstevel@tonic-gate IPRINTF1("dma burstsize=%x\n", fas->f_dma_attr->dma_attr_burstsizes); 8017c478bd9Sstevel@tonic-gate #endif 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * Attach this instance of the hba 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate if (scsi_hba_attach_setup(dip, fas->f_dma_attr, tran, 0) != 8067c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 8077c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "scsi_hba_attach_setup failed"); 8087c478bd9Sstevel@tonic-gate goto fail; 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate hba_attached++; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate /* 8137c478bd9Sstevel@tonic-gate * if scsi-options property exists, use it 8147c478bd9Sstevel@tonic-gate */ 8157c478bd9Sstevel@tonic-gate fas->f_scsi_options = ddi_prop_get_int(DDI_DEV_T_ANY, 8167c478bd9Sstevel@tonic-gate dip, 0, "scsi-options", DEFAULT_SCSI_OPTIONS); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate /* 8197c478bd9Sstevel@tonic-gate * if scsi-selection-timeout property exists, use it 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate fas_selection_timeout = ddi_prop_get_int(DDI_DEV_T_ANY, 8227c478bd9Sstevel@tonic-gate dip, 0, "scsi-selection-timeout", SCSI_DEFAULT_SELECTION_TIMEOUT); 8237c478bd9Sstevel@tonic-gate 8247c478bd9Sstevel@tonic-gate /* 8257c478bd9Sstevel@tonic-gate * if hm-rev property doesn't exist, use old scheme for rev 8267c478bd9Sstevel@tonic-gate */ 8277c478bd9Sstevel@tonic-gate hm_rev = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, 8287c478bd9Sstevel@tonic-gate "hm-rev", -1); 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate if (hm_rev == 0xa0 || hm_rev == -1) { 8317c478bd9Sstevel@tonic-gate if (DMAREV(dmar) != 0) { 8327c478bd9Sstevel@tonic-gate fas->f_hm_rev = 0x20; 8337c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 8347c478bd9Sstevel@tonic-gate "obsolete rev 2.0 FEPS chip, " 8357c478bd9Sstevel@tonic-gate "possible data corruption"); 8367c478bd9Sstevel@tonic-gate } else { 8377c478bd9Sstevel@tonic-gate fas->f_hm_rev = 0x10; 8387c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 8397c478bd9Sstevel@tonic-gate "obsolete and unsupported rev 1.0 FEPS chip"); 8407c478bd9Sstevel@tonic-gate goto fail; 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate } else if (hm_rev == 0x20) { 8437c478bd9Sstevel@tonic-gate fas->f_hm_rev = 0x21; 8447c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "obsolete rev 2.1 FEPS chip"); 8457c478bd9Sstevel@tonic-gate } else { 8467c478bd9Sstevel@tonic-gate fas->f_hm_rev = (uchar_t)hm_rev; 8477c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, "?rev %x.%x FEPS chip\n", 8487c478bd9Sstevel@tonic-gate (hm_rev >> 4) & 0xf, hm_rev & 0xf); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate if ((fas->f_scsi_options & SCSI_OPTIONS_SYNC) == 0) { 8527c478bd9Sstevel@tonic-gate fas->f_nosync = ALL_TARGETS; 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate if ((fas->f_scsi_options & SCSI_OPTIONS_WIDE) == 0) { 8567c478bd9Sstevel@tonic-gate fas->f_nowide = ALL_TARGETS; 8577c478bd9Sstevel@tonic-gate } 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* 8607c478bd9Sstevel@tonic-gate * if target<n>-scsi-options property exists, use it; 8617c478bd9Sstevel@tonic-gate * otherwise use the f_scsi_options 8627c478bd9Sstevel@tonic-gate */ 8637c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 8647c478bd9Sstevel@tonic-gate (void) sprintf(prop_str, prop_template, i); 8657c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[i] = ddi_prop_get_int( 8667c478bd9Sstevel@tonic-gate DDI_DEV_T_ANY, dip, 0, prop_str, -1); 8677c478bd9Sstevel@tonic-gate 8687c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[i] != -1) { 8697c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, "?target%x-scsi-options=0x%x\n", 8707c478bd9Sstevel@tonic-gate i, fas->f_target_scsi_options[i]); 8717c478bd9Sstevel@tonic-gate fas->f_target_scsi_options_defined |= 1 << i; 8727c478bd9Sstevel@tonic-gate } else { 8737c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[i] = fas->f_scsi_options; 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate if (((fas->f_target_scsi_options[i] & 8767c478bd9Sstevel@tonic-gate SCSI_OPTIONS_DR) == 0) && 8777c478bd9Sstevel@tonic-gate (fas->f_target_scsi_options[i] & SCSI_OPTIONS_TAG)) { 8787c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[i] &= ~SCSI_OPTIONS_TAG; 8797c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 8807c478bd9Sstevel@tonic-gate "Disabled TQ since disconnects are disabled"); 8817c478bd9Sstevel@tonic-gate } 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate fas->f_scsi_tag_age_limit = 8857c478bd9Sstevel@tonic-gate ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "scsi-tag-age-limit", 8867c478bd9Sstevel@tonic-gate DEFAULT_TAG_AGE_LIMIT); 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate fas->f_scsi_reset_delay = ddi_prop_get_int(DDI_DEV_T_ANY, 8897c478bd9Sstevel@tonic-gate dip, 0, "scsi-reset-delay", SCSI_DEFAULT_RESET_DELAY); 8907c478bd9Sstevel@tonic-gate if (fas->f_scsi_reset_delay == 0) { 8917c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, 8927c478bd9Sstevel@tonic-gate "scsi_reset_delay of 0 is not recommended," 8937c478bd9Sstevel@tonic-gate " resetting to SCSI_DEFAULT_RESET_DELAY\n"); 8947c478bd9Sstevel@tonic-gate fas->f_scsi_reset_delay = SCSI_DEFAULT_RESET_DELAY; 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * get iblock cookie and initialize mutexes 8997c478bd9Sstevel@tonic-gate */ 9007c478bd9Sstevel@tonic-gate if (ddi_get_iblock_cookie(dip, (uint_t)0, &fas->f_iblock) 9017c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 9027c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas_attach: cannot get iblock cookie"); 9037c478bd9Sstevel@tonic-gate goto fail; 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate mutex_init(&fas->f_mutex, NULL, MUTEX_DRIVER, fas->f_iblock); 9077c478bd9Sstevel@tonic-gate cv_init(&fas->f_cv, NULL, CV_DRIVER, NULL); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* 9107c478bd9Sstevel@tonic-gate * initialize mutex for waitQ 9117c478bd9Sstevel@tonic-gate */ 9127c478bd9Sstevel@tonic-gate mutex_init(&fas->f_waitQ_mutex, NULL, MUTEX_DRIVER, fas->f_iblock); 9137c478bd9Sstevel@tonic-gate mutex_init_done++; 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate /* 9167c478bd9Sstevel@tonic-gate * initialize callback mechanism (immediate callback) 9177c478bd9Sstevel@tonic-gate */ 9187c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 9197c478bd9Sstevel@tonic-gate if (fas_init_callbacks(fas)) { 9207c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 9217c478bd9Sstevel@tonic-gate goto fail; 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * kstat_intr support 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate (void) sprintf(buf, "fas%d", instance); 9297c478bd9Sstevel@tonic-gate fas->f_intr_kstat = kstat_create("fas", instance, buf, "controller", \ 9307c478bd9Sstevel@tonic-gate KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT); 9317c478bd9Sstevel@tonic-gate if (fas->f_intr_kstat) 9327c478bd9Sstevel@tonic-gate kstat_install(fas->f_intr_kstat); 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * install interrupt handler 9367c478bd9Sstevel@tonic-gate */ 9377c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 9387c478bd9Sstevel@tonic-gate if (ddi_add_intr(dip, (uint_t)0, &fas->f_iblock, NULL, 9397c478bd9Sstevel@tonic-gate fas_intr, (caddr_t)fas)) { 9407c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas: cannot add intr"); 9417c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 9427c478bd9Sstevel@tonic-gate goto fail; 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate intr_added++; 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * initialize fas chip 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate if (fas_init_chip(fas, id)) { 9507c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas: cannot initialize"); 9517c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 9527c478bd9Sstevel@tonic-gate goto fail; 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 9557c478bd9Sstevel@tonic-gate 9567c478bd9Sstevel@tonic-gate /* 9577c478bd9Sstevel@tonic-gate * create kmem cache for packets 9587c478bd9Sstevel@tonic-gate */ 9597c478bd9Sstevel@tonic-gate (void) sprintf(buf, "fas%d_cache", instance); 9607c478bd9Sstevel@tonic-gate fas->f_kmem_cache = kmem_cache_create(buf, 9617c478bd9Sstevel@tonic-gate EXTCMD_SIZE, 8, 9627c478bd9Sstevel@tonic-gate fas_kmem_cache_constructor, fas_kmem_cache_destructor, 9637c478bd9Sstevel@tonic-gate NULL, (void *)fas, NULL, 0); 9647c478bd9Sstevel@tonic-gate if (fas->f_kmem_cache == NULL) { 9657c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas: cannot create kmem_cache"); 9667c478bd9Sstevel@tonic-gate goto fail; 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate /* 9707c478bd9Sstevel@tonic-gate * at this point, we are not going to fail the attach 9717c478bd9Sstevel@tonic-gate * so there is no need to undo the rest: 9727c478bd9Sstevel@tonic-gate * 9737c478bd9Sstevel@tonic-gate * add this fas to the list, this makes debugging easier 9747c478bd9Sstevel@tonic-gate * and fas_watch() needs it to walk thru all fas's 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate rw_enter(&fas_global_rwlock, RW_WRITER); 9777c478bd9Sstevel@tonic-gate if (fas_head == NULL) { 9787c478bd9Sstevel@tonic-gate fas_head = fas; 9797c478bd9Sstevel@tonic-gate } else { 9807c478bd9Sstevel@tonic-gate fas_tail->f_next = fas; 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate fas_tail = fas; /* point to last fas in list */ 9837c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * there is one watchdog handler for all driver instances. 9877c478bd9Sstevel@tonic-gate * start the watchdog if it hasn't been done yet 9887c478bd9Sstevel@tonic-gate */ 9897c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 9907c478bd9Sstevel@tonic-gate if (fas_scsi_watchdog_tick == 0) { 9917c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick = ddi_prop_get_int(DDI_DEV_T_ANY, 9927c478bd9Sstevel@tonic-gate dip, 0, "scsi-watchdog-tick", DEFAULT_WD_TICK); 9937c478bd9Sstevel@tonic-gate if (fas_scsi_watchdog_tick != DEFAULT_WD_TICK) { 9947c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, "?scsi-watchdog-tick=%d\n", 9957c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate fas_tick = drv_usectohz((clock_t) 9987c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick * 1000000); 9997c478bd9Sstevel@tonic-gate IPRINTF2("fas scsi watchdog tick=%x, fas_tick=%lx\n", 10007c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick, fas_tick); 10017c478bd9Sstevel@tonic-gate if (fas_timeout_id == 0) { 10027c478bd9Sstevel@tonic-gate fas_timeout_id = timeout(fas_watch, NULL, fas_tick); 10037c478bd9Sstevel@tonic-gate fas_timeout_initted = 1; 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate ddi_report_dev(dip); 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10117c478bd9Sstevel@tonic-gate 10127c478bd9Sstevel@tonic-gate fail: 10137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas%d: cannot attach", instance); 10147c478bd9Sstevel@tonic-gate if (fas) { 10157c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot++) { 10167c478bd9Sstevel@tonic-gate struct f_slots *active = fas->f_active[slot]; 10177c478bd9Sstevel@tonic-gate if (active) { 10187c478bd9Sstevel@tonic-gate kmem_free(active, active->f_size); 10197c478bd9Sstevel@tonic-gate fas->f_active[slot] = NULL; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate } 10227c478bd9Sstevel@tonic-gate if (mutex_init_done) { 10237c478bd9Sstevel@tonic-gate mutex_destroy(&fas->f_mutex); 10247c478bd9Sstevel@tonic-gate mutex_destroy(&fas->f_waitQ_mutex); 10257c478bd9Sstevel@tonic-gate cv_destroy(&fas->f_cv); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate if (intr_added) { 10287c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, (uint_t)0, fas->f_iblock); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * kstat_intr support 10327c478bd9Sstevel@tonic-gate */ 10337c478bd9Sstevel@tonic-gate if (fas->f_intr_kstat) { 10347c478bd9Sstevel@tonic-gate kstat_delete(fas->f_intr_kstat); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate if (hba_attached) { 10377c478bd9Sstevel@tonic-gate (void) scsi_hba_detach(dip); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate if (tran) { 10407c478bd9Sstevel@tonic-gate scsi_hba_tran_free(tran); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate if (fas->f_kmem_cache) { 10437c478bd9Sstevel@tonic-gate kmem_cache_destroy(fas->f_kmem_cache); 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate if (fas->f_cmdarea) { 10467c478bd9Sstevel@tonic-gate if (bound_handle) { 10477c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(fas->f_dmahandle); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&fas->f_cmdarea_acc_handle); 10507c478bd9Sstevel@tonic-gate } 10517c478bd9Sstevel@tonic-gate if (fas->f_dmahandle) { 10527c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&fas->f_dmahandle); 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate fas_destroy_callbacks(fas); 10557c478bd9Sstevel@tonic-gate if (fas->f_regs_acc_handle) { 10567c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fas->f_regs_acc_handle); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate if (fas->f_dmar_acc_handle) { 10597c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fas->f_dmar_acc_handle); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate ddi_soft_state_free(fas_state, instance); 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 10647c478bd9Sstevel@tonic-gate } 10657c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10667c478bd9Sstevel@tonic-gate } 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10697c478bd9Sstevel@tonic-gate static int 10707c478bd9Sstevel@tonic-gate fas_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 10717c478bd9Sstevel@tonic-gate { 10727c478bd9Sstevel@tonic-gate struct fas *fas, *nfas; 10737c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* CONSTCOND */ 10767c478bd9Sstevel@tonic-gate ASSERT(NO_COMPETING_THREADS); 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate switch (cmd) { 10797c478bd9Sstevel@tonic-gate case DDI_DETACH: 10807c478bd9Sstevel@tonic-gate return (fas_dr_detach(dip)); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 10837c478bd9Sstevel@tonic-gate if ((tran = ddi_get_driver_private(dip)) == NULL) 10847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate fas = TRAN2FAS(tran); 10877c478bd9Sstevel@tonic-gate if (!fas) { 10887c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate fas->f_suspended = 1; 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate if (fas->f_ncmds) { 10967c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 10977c478bd9Sstevel@tonic-gate (void) fas_dopoll(fas, SHORT_POLL_TIMEOUT); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate /* 11007c478bd9Sstevel@tonic-gate * disable dma and fas interrupt 11017c478bd9Sstevel@tonic-gate */ 11027c478bd9Sstevel@tonic-gate fas->f_dma_csr &= ~DMA_INTEN; 11037c478bd9Sstevel@tonic-gate fas->f_dma_csr &= ~DMA_ENDVMA; 11047c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate if (fas->f_quiesce_timeid) { 11097c478bd9Sstevel@tonic-gate (void) untimeout(fas->f_quiesce_timeid); 11107c478bd9Sstevel@tonic-gate fas->f_quiesce_timeid = 0; 11117c478bd9Sstevel@tonic-gate } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate if (fas->f_restart_cmd_timeid) { 11147c478bd9Sstevel@tonic-gate (void) untimeout(fas->f_restart_cmd_timeid); 11157c478bd9Sstevel@tonic-gate fas->f_restart_cmd_timeid = 0; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate /* Last fas? */ 11197c478bd9Sstevel@tonic-gate rw_enter(&fas_global_rwlock, RW_WRITER); 11207c478bd9Sstevel@tonic-gate for (nfas = fas_head; nfas; nfas = nfas->f_next) { 11217c478bd9Sstevel@tonic-gate if (!nfas->f_suspended) { 11227c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 11237c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 11297c478bd9Sstevel@tonic-gate if (fas_timeout_id != 0) { 11307c478bd9Sstevel@tonic-gate timeout_id_t tid = fas_timeout_id; 11317c478bd9Sstevel@tonic-gate fas_timeout_id = 0; 11327c478bd9Sstevel@tonic-gate fas_timeout_initted = 0; 11337c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 11347c478bd9Sstevel@tonic-gate (void) untimeout(tid); 11357c478bd9Sstevel@tonic-gate } else { 11367c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 11407c478bd9Sstevel@tonic-gate if (fas_reset_watch) { 11417c478bd9Sstevel@tonic-gate timeout_id_t tid = fas_reset_watch; 11427c478bd9Sstevel@tonic-gate fas_reset_watch = 0; 11437c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 11447c478bd9Sstevel@tonic-gate (void) untimeout(tid); 11457c478bd9Sstevel@tonic-gate } else { 11467c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate default: 11527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11537c478bd9Sstevel@tonic-gate } 11547c478bd9Sstevel@tonic-gate _NOTE(NOT_REACHED) 11557c478bd9Sstevel@tonic-gate /* NOTREACHED */ 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate static int 11597c478bd9Sstevel@tonic-gate fas_dr_detach(dev_info_t *dip) 11607c478bd9Sstevel@tonic-gate { 11617c478bd9Sstevel@tonic-gate struct fas *fas, *f; 11627c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran; 11637c478bd9Sstevel@tonic-gate short slot; 11647c478bd9Sstevel@tonic-gate int i, j; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate if ((tran = ddi_get_driver_private(dip)) == NULL) 11677c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate fas = TRAN2FAS(tran); 11707c478bd9Sstevel@tonic-gate if (!fas) { 11717c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate /* 11757c478bd9Sstevel@tonic-gate * disable interrupts 11767c478bd9Sstevel@tonic-gate */ 11777c478bd9Sstevel@tonic-gate fas->f_dma_csr &= ~DMA_INTEN; 11787c478bd9Sstevel@tonic-gate fas->f_dma->dma_csr = fas->f_dma_csr; 11797c478bd9Sstevel@tonic-gate ddi_remove_intr(dip, (uint_t)0, fas->f_iblock); 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* 11827c478bd9Sstevel@tonic-gate * Remove device instance from the global linked list 11837c478bd9Sstevel@tonic-gate */ 11847c478bd9Sstevel@tonic-gate rw_enter(&fas_global_rwlock, RW_WRITER); 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate if (fas_head == fas) { 11877c478bd9Sstevel@tonic-gate f = fas_head = fas->f_next; 11887c478bd9Sstevel@tonic-gate } else { 11897c478bd9Sstevel@tonic-gate for (f = fas_head; f != (struct fas *)NULL; f = f->f_next) { 11907c478bd9Sstevel@tonic-gate if (f->f_next == fas) { 11917c478bd9Sstevel@tonic-gate f->f_next = fas->f_next; 11927c478bd9Sstevel@tonic-gate break; 11937c478bd9Sstevel@tonic-gate } 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 11977c478bd9Sstevel@tonic-gate * Instance not in softc list. Since the 11987c478bd9Sstevel@tonic-gate * instance is not there in softc list, don't 11997c478bd9Sstevel@tonic-gate * enable interrupts, the instance is effectively 12007c478bd9Sstevel@tonic-gate * unusable. 12017c478bd9Sstevel@tonic-gate */ 12027c478bd9Sstevel@tonic-gate if (f == (struct fas *)NULL) { 12037c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "fas_dr_detach: fas instance not" 12047c478bd9Sstevel@tonic-gate " in softc list!"); 12057c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 12067c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate } 12117c478bd9Sstevel@tonic-gate 12127c478bd9Sstevel@tonic-gate if (fas_tail == fas) 12137c478bd9Sstevel@tonic-gate fas_tail = f; 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate if (fas->f_intr_kstat) 12187c478bd9Sstevel@tonic-gate kstat_delete(fas->f_intr_kstat); 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate fas_destroy_callbacks(fas); 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate scsi_hba_reset_notify_tear_down(fas->f_reset_notify_listf); 12237c478bd9Sstevel@tonic-gate 12247c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 12257c478bd9Sstevel@tonic-gate /* 12267c478bd9Sstevel@tonic-gate * destroy any outstanding tagged command info 12277c478bd9Sstevel@tonic-gate */ 12287c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot++) { 12297c478bd9Sstevel@tonic-gate struct f_slots *active = fas->f_active[slot]; 12307c478bd9Sstevel@tonic-gate if (active) { 12317c478bd9Sstevel@tonic-gate ushort_t tag; 12327c478bd9Sstevel@tonic-gate for (tag = 0; tag < active->f_n_slots; tag++) { 12337c478bd9Sstevel@tonic-gate struct fas_cmd *sp = active->f_slot[tag]; 12347c478bd9Sstevel@tonic-gate if (sp) { 12357c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt = sp->cmd_pkt; 12367c478bd9Sstevel@tonic-gate if (pkt) { 12377c478bd9Sstevel@tonic-gate (void) fas_scsi_destroy_pkt( 12387c478bd9Sstevel@tonic-gate &pkt->pkt_address, pkt); 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate /* sp freed in fas_scsi_destroy_pkt */ 12417c478bd9Sstevel@tonic-gate active->f_slot[tag] = NULL; 12427c478bd9Sstevel@tonic-gate } 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate kmem_free(active, active->f_size); 12457c478bd9Sstevel@tonic-gate fas->f_active[slot] = NULL; 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] == 0); 12487c478bd9Sstevel@tonic-gate } 12497c478bd9Sstevel@tonic-gate 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * disallow timeout thread rescheduling 12527c478bd9Sstevel@tonic-gate */ 12537c478bd9Sstevel@tonic-gate fas->f_flags |= FAS_FLG_NOTIMEOUTS; 12547c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 12557c478bd9Sstevel@tonic-gate 12567c478bd9Sstevel@tonic-gate if (fas->f_quiesce_timeid) { 12577c478bd9Sstevel@tonic-gate (void) untimeout(fas->f_quiesce_timeid); 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate /* 12617c478bd9Sstevel@tonic-gate * last fas? ... if active, CANCEL watch threads. 12627c478bd9Sstevel@tonic-gate */ 12637c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 12647c478bd9Sstevel@tonic-gate if (fas_head == (struct fas *)NULL) { 12657c478bd9Sstevel@tonic-gate if (fas_timeout_initted) { 12667c478bd9Sstevel@tonic-gate timeout_id_t tid = fas_timeout_id; 12677c478bd9Sstevel@tonic-gate fas_timeout_initted = 0; 12687c478bd9Sstevel@tonic-gate fas_timeout_id = 0; /* don't resched */ 12697c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 12707c478bd9Sstevel@tonic-gate (void) untimeout(tid); 12717c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 12727c478bd9Sstevel@tonic-gate } 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate if (fas_reset_watch) { 12757c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 12767c478bd9Sstevel@tonic-gate (void) untimeout(fas_reset_watch); 12777c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 12787c478bd9Sstevel@tonic-gate fas_reset_watch = 0; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate } 12817c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate if (fas->f_restart_cmd_timeid) { 12847c478bd9Sstevel@tonic-gate (void) untimeout(fas->f_restart_cmd_timeid); 12857c478bd9Sstevel@tonic-gate fas->f_restart_cmd_timeid = 0; 12867c478bd9Sstevel@tonic-gate } 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate /* 12897c478bd9Sstevel@tonic-gate * destroy outstanding ARQ pkts 12907c478bd9Sstevel@tonic-gate */ 12917c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 12927c478bd9Sstevel@tonic-gate for (j = 0; j < NLUNS_PER_TARGET; j++) { 12937c478bd9Sstevel@tonic-gate int slot = i * NLUNS_PER_TARGET | j; 12947c478bd9Sstevel@tonic-gate if (fas->f_arq_pkt[slot]) { 12957c478bd9Sstevel@tonic-gate struct scsi_address sa; 12967c478bd9Sstevel@tonic-gate sa.a_hba_tran = NULL; /* not used */ 12977c478bd9Sstevel@tonic-gate sa.a_target = (ushort_t)i; 12987c478bd9Sstevel@tonic-gate sa.a_lun = (uchar_t)j; 12997c478bd9Sstevel@tonic-gate (void) fas_delete_arq_pkt(fas, &sa); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate } 13037c478bd9Sstevel@tonic-gate 13047c478bd9Sstevel@tonic-gate /* 13057c478bd9Sstevel@tonic-gate * Remove device MT locks and CV 13067c478bd9Sstevel@tonic-gate */ 13077c478bd9Sstevel@tonic-gate mutex_destroy(&fas->f_waitQ_mutex); 13087c478bd9Sstevel@tonic-gate mutex_destroy(&fas->f_mutex); 13097c478bd9Sstevel@tonic-gate cv_destroy(&fas->f_cv); 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate /* 13127c478bd9Sstevel@tonic-gate * Release miscellaneous device resources 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate 13157c478bd9Sstevel@tonic-gate if (fas->f_kmem_cache) { 13167c478bd9Sstevel@tonic-gate kmem_cache_destroy(fas->f_kmem_cache); 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate 13197c478bd9Sstevel@tonic-gate if (fas->f_cmdarea != (uchar_t *)NULL) { 13207c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(fas->f_dmahandle); 13217c478bd9Sstevel@tonic-gate ddi_dma_mem_free(&fas->f_cmdarea_acc_handle); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 13247c478bd9Sstevel@tonic-gate if (fas->f_dmahandle != (ddi_dma_handle_t)NULL) { 13257c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&fas->f_dmahandle); 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate if (fas->f_regs_acc_handle) { 13297c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fas->f_regs_acc_handle); 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate if (fas->f_dmar_acc_handle) { 13327c478bd9Sstevel@tonic-gate ddi_regs_map_free(&fas->f_dmar_acc_handle); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* 13367c478bd9Sstevel@tonic-gate * Remove properties created during attach() 13377c478bd9Sstevel@tonic-gate */ 13387c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dip); 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * Delete the DMA limits, transport vectors and remove the device 13427c478bd9Sstevel@tonic-gate * links to the scsi_transport layer. 13437c478bd9Sstevel@tonic-gate * -- ddi_set_driver_private(dip, NULL) 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate (void) scsi_hba_detach(dip); 13467c478bd9Sstevel@tonic-gate 13477c478bd9Sstevel@tonic-gate /* 13487c478bd9Sstevel@tonic-gate * Free the scsi_transport structure for this device. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate scsi_hba_tran_free(tran); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate ddi_soft_state_free(fas_state, ddi_get_instance(dip)); 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate 13577c478bd9Sstevel@tonic-gate static int 13587c478bd9Sstevel@tonic-gate fas_quiesce_bus(struct fas *fas) 13597c478bd9Sstevel@tonic-gate { 13607c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 13617c478bd9Sstevel@tonic-gate IPRINTF("fas_quiesce: QUIESCEing\n"); 13627c478bd9Sstevel@tonic-gate IPRINTF3("fas_quiesce: ncmds (%d) ndisc (%d) state (%d)\n", 13637c478bd9Sstevel@tonic-gate fas->f_ncmds, fas->f_ndisc, fas->f_softstate); 13647c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, HOLD_THROTTLE); 13657c478bd9Sstevel@tonic-gate if (fas_check_outstanding(fas)) { 13667c478bd9Sstevel@tonic-gate fas->f_softstate |= FAS_SS_DRAINING; 13677c478bd9Sstevel@tonic-gate fas->f_quiesce_timeid = timeout(fas_ncmds_checkdrain, 13687c478bd9Sstevel@tonic-gate fas, (FAS_QUIESCE_TIMEOUT * drv_usectohz(1000000))); 13697c478bd9Sstevel@tonic-gate if (cv_wait_sig(FAS_CV(fas), FAS_MUTEX(fas)) == 0) { 13707c478bd9Sstevel@tonic-gate /* 13717c478bd9Sstevel@tonic-gate * quiesce has been interrupted. 13727c478bd9Sstevel@tonic-gate */ 13737c478bd9Sstevel@tonic-gate IPRINTF("fas_quiesce: abort QUIESCE\n"); 13747c478bd9Sstevel@tonic-gate fas->f_softstate &= ~FAS_SS_DRAINING; 13757c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE); 13767c478bd9Sstevel@tonic-gate (void) fas_istart(fas); 13777c478bd9Sstevel@tonic-gate if (fas->f_quiesce_timeid != 0) { 13787c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 13797c478bd9Sstevel@tonic-gate #ifndef __lock_lint /* warlock complains but there is a NOTE on this */ 13807c478bd9Sstevel@tonic-gate (void) untimeout(fas->f_quiesce_timeid); 13817c478bd9Sstevel@tonic-gate fas->f_quiesce_timeid = 0; 13827c478bd9Sstevel@tonic-gate #endif 13837c478bd9Sstevel@tonic-gate return (-1); 13847c478bd9Sstevel@tonic-gate } 13857c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 13867c478bd9Sstevel@tonic-gate return (-1); 13877c478bd9Sstevel@tonic-gate } else { 13887c478bd9Sstevel@tonic-gate IPRINTF("fas_quiesce: bus is QUIESCED\n"); 13897c478bd9Sstevel@tonic-gate ASSERT(fas->f_quiesce_timeid == 0); 13907c478bd9Sstevel@tonic-gate fas->f_softstate &= ~FAS_SS_DRAINING; 13917c478bd9Sstevel@tonic-gate fas->f_softstate |= FAS_SS_QUIESCED; 13927c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 13937c478bd9Sstevel@tonic-gate return (0); 13947c478bd9Sstevel@tonic-gate } 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate IPRINTF("fas_quiesce: bus was not busy QUIESCED\n"); 13977c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 13987c478bd9Sstevel@tonic-gate return (0); 13997c478bd9Sstevel@tonic-gate } 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate static int 14027c478bd9Sstevel@tonic-gate fas_unquiesce_bus(struct fas *fas) 14037c478bd9Sstevel@tonic-gate { 14047c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 14057c478bd9Sstevel@tonic-gate fas->f_softstate &= ~FAS_SS_QUIESCED; 14067c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, MAX_THROTTLE); 14077c478bd9Sstevel@tonic-gate (void) fas_istart(fas); 14087c478bd9Sstevel@tonic-gate IPRINTF("fas_quiesce: bus has been UNQUIESCED\n"); 14097c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate return (0); 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * invoked from timeout() to check the number of outstanding commands 14167c478bd9Sstevel@tonic-gate */ 14177c478bd9Sstevel@tonic-gate static void 14187c478bd9Sstevel@tonic-gate fas_ncmds_checkdrain(void *arg) 14197c478bd9Sstevel@tonic-gate { 14207c478bd9Sstevel@tonic-gate struct fas *fas = arg; 14217c478bd9Sstevel@tonic-gate 14227c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 14237c478bd9Sstevel@tonic-gate IPRINTF3("fas_checkdrain: ncmds (%d) ndisc (%d) state (%d)\n", 14247c478bd9Sstevel@tonic-gate fas->f_ncmds, fas->f_ndisc, fas->f_softstate); 14257c478bd9Sstevel@tonic-gate if (fas->f_softstate & FAS_SS_DRAINING) { 14267c478bd9Sstevel@tonic-gate fas->f_quiesce_timeid = 0; 14277c478bd9Sstevel@tonic-gate if (fas_check_outstanding(fas) == 0) { 14287c478bd9Sstevel@tonic-gate IPRINTF("fas_drain: bus has drained\n"); 14297c478bd9Sstevel@tonic-gate cv_signal(FAS_CV(fas)); 14307c478bd9Sstevel@tonic-gate } else { 14317c478bd9Sstevel@tonic-gate /* 14327c478bd9Sstevel@tonic-gate * throttle may have been reset by a bus reset 14337c478bd9Sstevel@tonic-gate * or fas_runpoll() 14347c478bd9Sstevel@tonic-gate * XXX shouldn't be necessary 14357c478bd9Sstevel@tonic-gate */ 14367c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, HOLD_THROTTLE); 14377c478bd9Sstevel@tonic-gate IPRINTF("fas_drain: rescheduling timeout\n"); 14387c478bd9Sstevel@tonic-gate fas->f_quiesce_timeid = timeout(fas_ncmds_checkdrain, 14397c478bd9Sstevel@tonic-gate fas, (FAS_QUIESCE_TIMEOUT * drv_usectohz(1000000))); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 14437c478bd9Sstevel@tonic-gate } 14447c478bd9Sstevel@tonic-gate 14457c478bd9Sstevel@tonic-gate static int 14467c478bd9Sstevel@tonic-gate fas_check_outstanding(struct fas *fas) 14477c478bd9Sstevel@tonic-gate { 14487c478bd9Sstevel@tonic-gate uint_t slot; 14497c478bd9Sstevel@tonic-gate uint_t d = ((fas->f_dslot == 0)? 1 : fas->f_dslot); 14507c478bd9Sstevel@tonic-gate int ncmds = 0; 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot += d) 14557c478bd9Sstevel@tonic-gate ncmds += fas->f_tcmds[slot]; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate return (ncmds); 14587c478bd9Sstevel@tonic-gate } 14597c478bd9Sstevel@tonic-gate 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 14627c478bd9Sstevel@tonic-gate /* 14637c478bd9Sstevel@tonic-gate * fas register read/write functions with tracing 14647c478bd9Sstevel@tonic-gate */ 14657c478bd9Sstevel@tonic-gate static void 14667c478bd9Sstevel@tonic-gate fas_reg_tracing(struct fas *fas, int type, int regno, uint32_t what) 14677c478bd9Sstevel@tonic-gate { 14687c478bd9Sstevel@tonic-gate fas->f_reg_trace[fas->f_reg_trace_index++] = type; 14697c478bd9Sstevel@tonic-gate fas->f_reg_trace[fas->f_reg_trace_index++] = regno; 14707c478bd9Sstevel@tonic-gate fas->f_reg_trace[fas->f_reg_trace_index++] = what; 14717c478bd9Sstevel@tonic-gate fas->f_reg_trace[fas->f_reg_trace_index++] = gethrtime(); 14727c478bd9Sstevel@tonic-gate fas->f_reg_trace[fas->f_reg_trace_index] = 0xff; 14737c478bd9Sstevel@tonic-gate if (fas->f_reg_trace_index >= REG_TRACE_BUF_SIZE) { 14747c478bd9Sstevel@tonic-gate fas->f_reg_trace_index = 0; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate static void 14797c478bd9Sstevel@tonic-gate fas_reg_cmd_write(struct fas *fas, uint8_t cmd) 14807c478bd9Sstevel@tonic-gate { 14817c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 14827c478bd9Sstevel@tonic-gate int regno = (uintptr_t)&fasreg->fas_cmd - (uintptr_t)fasreg; 14837c478bd9Sstevel@tonic-gate 14847c478bd9Sstevel@tonic-gate fasreg->fas_cmd = cmd; 14857c478bd9Sstevel@tonic-gate fas->f_last_cmd = cmd; 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate EPRINTF1("issuing cmd %x\n", (uchar_t)cmd); 14887c478bd9Sstevel@tonic-gate fas_reg_tracing(fas, 0, regno, cmd); 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate fas->f_reg_cmds++; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate static void 14947c478bd9Sstevel@tonic-gate fas_reg_write(struct fas *fas, volatile uint8_t *p, uint8_t what) 14957c478bd9Sstevel@tonic-gate { 14967c478bd9Sstevel@tonic-gate int regno = (uintptr_t)p - (uintptr_t)fas->f_reg; 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate *p = what; 14997c478bd9Sstevel@tonic-gate 15007c478bd9Sstevel@tonic-gate EPRINTF2("writing reg%x = %x\n", regno, what); 15017c478bd9Sstevel@tonic-gate fas_reg_tracing(fas, 1, regno, what); 15027c478bd9Sstevel@tonic-gate 15037c478bd9Sstevel@tonic-gate fas->f_reg_writes++; 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate static uint8_t 15077c478bd9Sstevel@tonic-gate fas_reg_read(struct fas *fas, volatile uint8_t *p) 15087c478bd9Sstevel@tonic-gate { 15097c478bd9Sstevel@tonic-gate uint8_t what; 15107c478bd9Sstevel@tonic-gate int regno = (uintptr_t)p - (uintptr_t)fas->f_reg; 15117c478bd9Sstevel@tonic-gate 15127c478bd9Sstevel@tonic-gate what = *p; 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate EPRINTF2("reading reg%x => %x\n", regno, what); 15157c478bd9Sstevel@tonic-gate fas_reg_tracing(fas, 2, regno, what); 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate fas->f_reg_reads++; 15187c478bd9Sstevel@tonic-gate 15197c478bd9Sstevel@tonic-gate return (what); 15207c478bd9Sstevel@tonic-gate } 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * dma register access routines 15247c478bd9Sstevel@tonic-gate */ 15257c478bd9Sstevel@tonic-gate static void 15267c478bd9Sstevel@tonic-gate fas_dma_reg_write(struct fas *fas, volatile uint32_t *p, uint32_t what) 15277c478bd9Sstevel@tonic-gate { 15287c478bd9Sstevel@tonic-gate *p = what; 15297c478bd9Sstevel@tonic-gate fas->f_reg_dma_writes++; 15307c478bd9Sstevel@tonic-gate 15317c478bd9Sstevel@tonic-gate #ifdef DMA_REG_TRACING 15327c478bd9Sstevel@tonic-gate { 15337c478bd9Sstevel@tonic-gate int regno = (uintptr_t)p - (uintptr_t)fas->f_dma; 15347c478bd9Sstevel@tonic-gate EPRINTF2("writing dma reg%x = %x\n", regno, what); 15357c478bd9Sstevel@tonic-gate fas_reg_tracing(fas, 3, regno, what); 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate #endif 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate static uint32_t 15417c478bd9Sstevel@tonic-gate fas_dma_reg_read(struct fas *fas, volatile uint32_t *p) 15427c478bd9Sstevel@tonic-gate { 15437c478bd9Sstevel@tonic-gate uint32_t what = *p; 15447c478bd9Sstevel@tonic-gate fas->f_reg_dma_reads++; 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate #ifdef DMA_REG_TRACING 15477c478bd9Sstevel@tonic-gate { 15487c478bd9Sstevel@tonic-gate int regno = (uintptr_t)p - (uintptr_t)fas->f_dma; 15497c478bd9Sstevel@tonic-gate EPRINTF2("reading dma reg%x => %x\n", regno, what); 15507c478bd9Sstevel@tonic-gate fas_reg_tracing(fas, 4, regno, what); 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate #endif 15537c478bd9Sstevel@tonic-gate return (what); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate #endif 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate #define FIFO_EMPTY(fas) (fas_reg_read(fas, &fas->f_reg->fas_stat2) & \ 15587c478bd9Sstevel@tonic-gate FAS_STAT2_EMPTY) 15597c478bd9Sstevel@tonic-gate #define FIFO_CNT(fas) \ 15607c478bd9Sstevel@tonic-gate (fas_reg_read(fas, &fas->f_reg->fas_fifo_flag) & FIFO_CNT_MASK) 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 15637c478bd9Sstevel@tonic-gate static void 15647c478bd9Sstevel@tonic-gate fas_assert_atn(struct fas *fas) 15657c478bd9Sstevel@tonic-gate { 15667c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_SET_ATN); 15677c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 15687c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) 15697c478bd9Sstevel@tonic-gate debug_enter("asserted atn"); 15707c478bd9Sstevel@tonic-gate #endif 15717c478bd9Sstevel@tonic-gate } 15727c478bd9Sstevel@tonic-gate #else 15737c478bd9Sstevel@tonic-gate #define fas_assert_atn(fas) fas_reg_cmd_write(fas, CMD_SET_ATN) 15747c478bd9Sstevel@tonic-gate #endif 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * DMA macros; we use a shadow copy of the dma_csr to save unnecessary 15787c478bd9Sstevel@tonic-gate * reads 15797c478bd9Sstevel@tonic-gate */ 15807c478bd9Sstevel@tonic-gate #define FAS_DMA_WRITE(fas, count, base, cmd) { \ 15817c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; \ 15827c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; \ 15837c478bd9Sstevel@tonic-gate ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \ 15847c478bd9Sstevel@tonic-gate SET_FAS_COUNT(fasreg, count); \ 15857c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, cmd); \ 15867c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_count, count); \ 15877c478bd9Sstevel@tonic-gate fas->f_dma_csr |= \ 15887c478bd9Sstevel@tonic-gate DMA_WRITE | DMA_ENDVMA | DMA_DSBL_DRAIN; \ 15897c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \ 15907c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_csr, fas->f_dma_csr); \ 15917c478bd9Sstevel@tonic-gate } 15927c478bd9Sstevel@tonic-gate 15937c478bd9Sstevel@tonic-gate #define FAS_DMA_WRITE_SETUP(fas, count, base) { \ 15947c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; \ 15957c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; \ 15967c478bd9Sstevel@tonic-gate ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \ 15977c478bd9Sstevel@tonic-gate SET_FAS_COUNT(fasreg, count); \ 15987c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_count, count); \ 15997c478bd9Sstevel@tonic-gate fas->f_dma_csr |= \ 16007c478bd9Sstevel@tonic-gate DMA_WRITE | DMA_ENDVMA | DMA_DSBL_DRAIN; \ 16017c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \ 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate #define FAS_DMA_READ(fas, count, base, dmacount, cmd) { \ 16067c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; \ 16077c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; \ 16087c478bd9Sstevel@tonic-gate ASSERT((fas_dma_reg_read(fas, &dmar->dma_csr) & DMA_ENDVMA) == 0); \ 16097c478bd9Sstevel@tonic-gate SET_FAS_COUNT(fasreg, count); \ 16107c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, cmd); \ 16117c478bd9Sstevel@tonic-gate fas->f_dma_csr |= \ 16127c478bd9Sstevel@tonic-gate (fas->f_dma_csr & ~DMA_WRITE) | DMA_ENDVMA | DMA_DSBL_DRAIN; \ 16137c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_count, dmacount); \ 16147c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_addr, (fas->f_lastdma = base)); \ 16157c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &dmar->dma_csr, fas->f_dma_csr); \ 16167c478bd9Sstevel@tonic-gate } 16177c478bd9Sstevel@tonic-gate 16187c478bd9Sstevel@tonic-gate static void 16197c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(struct fas *fas) 16207c478bd9Sstevel@tonic-gate { 16217c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, DMA_RESET); 16227c478bd9Sstevel@tonic-gate fas->f_dma_csr |= (DMA_INTEN|DMA_TWO_CYCLE|DMA_DSBL_PARITY| 16237c478bd9Sstevel@tonic-gate DMA_DSBL_DRAIN); 16247c478bd9Sstevel@tonic-gate fas->f_dma_csr &= ~(DMA_ENDVMA | DMA_WRITE); 16257c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 0); 16267c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr); 16277c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_addr, 0); 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate /* 16317c478bd9Sstevel@tonic-gate * FAS_FLUSH_DMA_HARD checks on REQPEND before taking away the reset 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate static void 16347c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA_HARD(struct fas *fas) 16357c478bd9Sstevel@tonic-gate { 16367c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, DMA_RESET); 16377c478bd9Sstevel@tonic-gate fas->f_dma_csr |= (DMA_INTEN|DMA_TWO_CYCLE|DMA_DSBL_PARITY| 16387c478bd9Sstevel@tonic-gate DMA_DSBL_DRAIN); 16397c478bd9Sstevel@tonic-gate fas->f_dma_csr &= ~(DMA_ENDVMA | DMA_WRITE); 1640602ca9eaScth while (fas_dma_reg_read(fas, &fas->f_dma->dma_csr) & DMA_REQPEND) 1641602ca9eaScth ; 16427c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 0); 16437c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, fas->f_dma_csr); 16447c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_addr, 0); 16457c478bd9Sstevel@tonic-gate } 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * update period, conf3, offset reg, if necessary 16497c478bd9Sstevel@tonic-gate */ 16507c478bd9Sstevel@tonic-gate #define FAS_SET_PERIOD_OFFSET_CONF3_REGS(fas, target) \ 16517c478bd9Sstevel@tonic-gate { \ 16527c478bd9Sstevel@tonic-gate uchar_t period, offset, conf3; \ 16537c478bd9Sstevel@tonic-gate period = fas->f_sync_period[target] & SYNC_PERIOD_MASK; \ 16547c478bd9Sstevel@tonic-gate offset = fas->f_offset[target]; \ 16557c478bd9Sstevel@tonic-gate conf3 = fas->f_fasconf3[target]; \ 16567c478bd9Sstevel@tonic-gate if ((period != fas->f_period_reg_last) || \ 16577c478bd9Sstevel@tonic-gate (offset != fas->f_offset_reg_last) || \ 16587c478bd9Sstevel@tonic-gate (conf3 != fas->f_fasconf3_reg_last)) { \ 16597c478bd9Sstevel@tonic-gate fas->f_period_reg_last = period; \ 16607c478bd9Sstevel@tonic-gate fas->f_offset_reg_last = offset; \ 16617c478bd9Sstevel@tonic-gate fas->f_fasconf3_reg_last = conf3; \ 16627c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_sync_period, period); \ 16637c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_sync_offset, offset); \ 16647c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_conf3, conf3); \ 16657c478bd9Sstevel@tonic-gate } \ 16667c478bd9Sstevel@tonic-gate } 16677c478bd9Sstevel@tonic-gate 16687c478bd9Sstevel@tonic-gate /* 16697c478bd9Sstevel@tonic-gate * fifo read/write routines 16707c478bd9Sstevel@tonic-gate * always read the fifo bytes before reading the interrupt register 16717c478bd9Sstevel@tonic-gate */ 16727c478bd9Sstevel@tonic-gate 16737c478bd9Sstevel@tonic-gate static void 16747c478bd9Sstevel@tonic-gate fas_read_fifo(struct fas *fas) 16757c478bd9Sstevel@tonic-gate { 16767c478bd9Sstevel@tonic-gate int stat = fas->f_stat; 16777c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 16787c478bd9Sstevel@tonic-gate int i; 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate i = fas_reg_read(fas, &fasreg->fas_fifo_flag) & FIFO_CNT_MASK; 16817c478bd9Sstevel@tonic-gate EPRINTF2("fas_read_fifo: fifo cnt=%x, stat=%x\n", i, stat); 16827c478bd9Sstevel@tonic-gate ASSERT(i <= FIFOSIZE); 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate fas->f_fifolen = 0; 16857c478bd9Sstevel@tonic-gate while (i-- > 0) { 16867c478bd9Sstevel@tonic-gate fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas, 16877c478bd9Sstevel@tonic-gate &fasreg->fas_fifo_data); 16887c478bd9Sstevel@tonic-gate fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas, 16897c478bd9Sstevel@tonic-gate &fasreg->fas_fifo_data); 16907c478bd9Sstevel@tonic-gate } 16917c478bd9Sstevel@tonic-gate if (fas->f_stat2 & FAS_STAT2_ISHUTTLE) { 16927c478bd9Sstevel@tonic-gate 16937c478bd9Sstevel@tonic-gate /* write pad byte */ 16947c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_fifo_data, 0); 16957c478bd9Sstevel@tonic-gate fas->f_fifo[fas->f_fifolen++] = fas_reg_read(fas, 16967c478bd9Sstevel@tonic-gate &fasreg->fas_fifo_data); 16977c478bd9Sstevel@tonic-gate /* flush pad byte */ 16987c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate EPRINTF2("fas_read_fifo: fifo len=%x, stat2=%x\n", 17017c478bd9Sstevel@tonic-gate fas->f_fifolen, stat); 17027c478bd9Sstevel@tonic-gate } /* fas_read_fifo */ 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate static void 17057c478bd9Sstevel@tonic-gate fas_write_fifo(struct fas *fas, uchar_t *buf, int length, int pad) 17067c478bd9Sstevel@tonic-gate { 17077c478bd9Sstevel@tonic-gate int i; 17087c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate EPRINTF1("writing fifo %x bytes\n", length); 17117c478bd9Sstevel@tonic-gate ASSERT(length <= 15); 17127c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 17137c478bd9Sstevel@tonic-gate for (i = 0; i < length; i++) { 17147c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_fifo_data, buf[i]); 17157c478bd9Sstevel@tonic-gate if (pad) { 17167c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_fifo_data, 0); 17177c478bd9Sstevel@tonic-gate } 17187c478bd9Sstevel@tonic-gate } 17197c478bd9Sstevel@tonic-gate } 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate /* 17227c478bd9Sstevel@tonic-gate * Hardware and Software internal reset routines 17237c478bd9Sstevel@tonic-gate */ 17247c478bd9Sstevel@tonic-gate static int 17257c478bd9Sstevel@tonic-gate fas_init_chip(struct fas *fas, uchar_t initiator_id) 17267c478bd9Sstevel@tonic-gate { 17277c478bd9Sstevel@tonic-gate int i; 17287c478bd9Sstevel@tonic-gate uchar_t clock_conv; 17297c478bd9Sstevel@tonic-gate uchar_t initial_conf3; 17307c478bd9Sstevel@tonic-gate uint_t ticks; 17317c478bd9Sstevel@tonic-gate static char *prop_cfreq = "clock-frequency"; 17327c478bd9Sstevel@tonic-gate 17337c478bd9Sstevel@tonic-gate /* 17347c478bd9Sstevel@tonic-gate * Determine clock frequency of attached FAS chip. 17357c478bd9Sstevel@tonic-gate */ 17367c478bd9Sstevel@tonic-gate i = ddi_prop_get_int(DDI_DEV_T_ANY, 17377c478bd9Sstevel@tonic-gate fas->f_dev, DDI_PROP_DONTPASS, prop_cfreq, -1); 17387c478bd9Sstevel@tonic-gate clock_conv = (i + FIVE_MEG - 1) / FIVE_MEG; 17397c478bd9Sstevel@tonic-gate if (clock_conv != CLOCK_40MHZ) { 17407c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "Bad clock frequency"); 17417c478bd9Sstevel@tonic-gate return (-1); 17427c478bd9Sstevel@tonic-gate } 17437c478bd9Sstevel@tonic-gate 17447c478bd9Sstevel@tonic-gate fas->f_clock_conv = clock_conv; 17457c478bd9Sstevel@tonic-gate fas->f_clock_cycle = CLOCK_PERIOD(i); 17467c478bd9Sstevel@tonic-gate ticks = FAS_CLOCK_TICK(fas); 17477c478bd9Sstevel@tonic-gate fas->f_stval = FAS_CLOCK_TIMEOUT(ticks, fas_selection_timeout); 17487c478bd9Sstevel@tonic-gate 17497c478bd9Sstevel@tonic-gate DPRINTF5("%d mhz, clock_conv %d, clock_cycle %d, ticks %d, stval %d\n", 17507c478bd9Sstevel@tonic-gate i, fas->f_clock_conv, fas->f_clock_cycle, 17517c478bd9Sstevel@tonic-gate ticks, fas->f_stval); 17527c478bd9Sstevel@tonic-gate /* 17537c478bd9Sstevel@tonic-gate * set up conf registers 17547c478bd9Sstevel@tonic-gate */ 17557c478bd9Sstevel@tonic-gate fas->f_fasconf |= FAS_CONF_PAREN; 17567c478bd9Sstevel@tonic-gate fas->f_fasconf2 = (uchar_t)(FAS_CONF2_FENABLE | FAS_CONF2_XL32); 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate if (initiator_id < NTARGETS) { 17597c478bd9Sstevel@tonic-gate initial_conf3 = FAS_CONF3_FASTCLK | FAS_CONF3_ODDBYTE_AUTO; 17607c478bd9Sstevel@tonic-gate } else { 17617c478bd9Sstevel@tonic-gate initial_conf3 = FAS_CONF3_FASTCLK | FAS_CONF3_ODDBYTE_AUTO | 17627c478bd9Sstevel@tonic-gate FAS_CONF3_IDBIT3; 17637c478bd9Sstevel@tonic-gate } 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 17667c478bd9Sstevel@tonic-gate fas->f_fasconf3[i] = initial_conf3; 17677c478bd9Sstevel@tonic-gate } 17687c478bd9Sstevel@tonic-gate 17697c478bd9Sstevel@tonic-gate /* 17707c478bd9Sstevel@tonic-gate * Avoid resetting the scsi bus since this causes a few seconds 17717c478bd9Sstevel@tonic-gate * delay per fas in boot and also causes busy conditions in some 17727c478bd9Sstevel@tonic-gate * tape devices. 17737c478bd9Sstevel@tonic-gate */ 17747c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_SOFTC|FAS_RESET_FAS|FAS_RESET_DMA); 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate /* 17777c478bd9Sstevel@tonic-gate * initialize period and offset for each target 17787c478bd9Sstevel@tonic-gate */ 17797c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 17807c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[i] & SCSI_OPTIONS_SYNC) { 17817c478bd9Sstevel@tonic-gate fas->f_offset[i] = fas_default_offset | 17827c478bd9Sstevel@tonic-gate fas->f_req_ack_delay; 17837c478bd9Sstevel@tonic-gate } else { 17847c478bd9Sstevel@tonic-gate fas->f_offset[i] = 0; 17857c478bd9Sstevel@tonic-gate } 17867c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[i] & SCSI_OPTIONS_FAST) { 17877c478bd9Sstevel@tonic-gate fas->f_neg_period[i] = 17887c478bd9Sstevel@tonic-gate (uchar_t)MIN_SYNC_PERIOD(fas); 17897c478bd9Sstevel@tonic-gate } else { 17907c478bd9Sstevel@tonic-gate fas->f_neg_period[i] = 17917c478bd9Sstevel@tonic-gate (uchar_t)CONVERT_PERIOD(DEFAULT_SYNC_PERIOD); 17927c478bd9Sstevel@tonic-gate } 17937c478bd9Sstevel@tonic-gate } 17947c478bd9Sstevel@tonic-gate return (0); 17957c478bd9Sstevel@tonic-gate } 17967c478bd9Sstevel@tonic-gate 17977c478bd9Sstevel@tonic-gate /* 17987c478bd9Sstevel@tonic-gate * reset bus, chip, dma, or soft state 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate static void 18017c478bd9Sstevel@tonic-gate fas_internal_reset(struct fas *fas, int reset_action) 18027c478bd9Sstevel@tonic-gate { 18037c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 18047c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate if (reset_action & FAS_RESET_SCSIBUS) { 18077c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_RESET_SCSI); 18087c478bd9Sstevel@tonic-gate fas_setup_reset_delay(fas); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA_HARD(fas); /* resets and reinits the dma */ 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /* 18147c478bd9Sstevel@tonic-gate * NOTE: if dma is aborted while active, indefinite hangs 18157c478bd9Sstevel@tonic-gate * may occur; it is preferable to stop the target first before 18167c478bd9Sstevel@tonic-gate * flushing the dma 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate if (reset_action & FAS_RESET_DMA) { 18197c478bd9Sstevel@tonic-gate int burstsizes = fas->f_dma_attr->dma_attr_burstsizes; 18207c478bd9Sstevel@tonic-gate if (burstsizes & BURST64) { 18217c478bd9Sstevel@tonic-gate IPRINTF("64 byte burstsize\n"); 18227c478bd9Sstevel@tonic-gate fas->f_dma_csr |= DMA_BURST64; 18237c478bd9Sstevel@tonic-gate } else if (burstsizes & BURST32) { 18247c478bd9Sstevel@tonic-gate IPRINTF("32 byte burstsize\n"); 18257c478bd9Sstevel@tonic-gate fas->f_dma_csr |= DMA_BURST32; 18267c478bd9Sstevel@tonic-gate } else { 18277c478bd9Sstevel@tonic-gate IPRINTF("16 byte burstsize\n"); 18287c478bd9Sstevel@tonic-gate } 18297c478bd9Sstevel@tonic-gate if ((fas->f_hm_rev > 0x20) && (fas_enable_sbus64) && 18307c478bd9Sstevel@tonic-gate (ddi_dma_set_sbus64(fas->f_dmahandle, burstsizes) == 18317c478bd9Sstevel@tonic-gate DDI_SUCCESS)) { 18327c478bd9Sstevel@tonic-gate IPRINTF("enabled 64 bit sbus\n"); 18337c478bd9Sstevel@tonic-gate fas->f_dma_csr |= DMA_WIDE_EN; 18347c478bd9Sstevel@tonic-gate } 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate if (reset_action & FAS_RESET_FAS) { 18387c478bd9Sstevel@tonic-gate /* 18397c478bd9Sstevel@tonic-gate * 2 NOPs with DMA are required here 18407c478bd9Sstevel@tonic-gate * id_code is unreliable if we don't do this) 18417c478bd9Sstevel@tonic-gate */ 18427c478bd9Sstevel@tonic-gate uchar_t idcode, fcode; 18437c478bd9Sstevel@tonic-gate int dmarev; 18447c478bd9Sstevel@tonic-gate 18457c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_RESET_FAS); 18467c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_NOP | CMD_DMA); 18477c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_NOP | CMD_DMA); 18487c478bd9Sstevel@tonic-gate 18497c478bd9Sstevel@tonic-gate /* 18507c478bd9Sstevel@tonic-gate * Re-load chip configurations 18517c478bd9Sstevel@tonic-gate * Only load registers which are not loaded in fas_startcmd() 18527c478bd9Sstevel@tonic-gate */ 18537c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_clock_conv, 18547c478bd9Sstevel@tonic-gate (fas->f_clock_conv & CLOCK_MASK)); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_timeout, fas->f_stval); 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * enable default configurations 18607c478bd9Sstevel@tonic-gate */ 18617c478bd9Sstevel@tonic-gate fas->f_idcode = idcode = 18627c478bd9Sstevel@tonic-gate fas_reg_read(fas, &fasreg->fas_id_code); 18637c478bd9Sstevel@tonic-gate fcode = (uchar_t)(idcode & FAS_FCODE_MASK) >> (uchar_t)3; 18647c478bd9Sstevel@tonic-gate fas->f_type = FAS366; 18657c478bd9Sstevel@tonic-gate IPRINTF2("Family code %d, revision %d\n", 18667c478bd9Sstevel@tonic-gate fcode, (idcode & FAS_REV_MASK)); 18677c478bd9Sstevel@tonic-gate dmarev = fas_dma_reg_read(fas, &dmar->dma_csr); 18687c478bd9Sstevel@tonic-gate dmarev = (dmarev >> 11) & 0xf; 18697c478bd9Sstevel@tonic-gate IPRINTF1("DMA channel revision %d\n", dmarev); 18707c478bd9Sstevel@tonic-gate 18717c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_conf, fas->f_fasconf); 18727c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_conf2, fas->f_fasconf2); 18737c478bd9Sstevel@tonic-gate 18747c478bd9Sstevel@tonic-gate fas->f_req_ack_delay = DEFAULT_REQ_ACK_DELAY; 18757c478bd9Sstevel@tonic-gate 18767c478bd9Sstevel@tonic-gate /* 18777c478bd9Sstevel@tonic-gate * Just in case... clear interrupt 18787c478bd9Sstevel@tonic-gate */ 18797c478bd9Sstevel@tonic-gate (void) fas_reg_read(fas, &fasreg->fas_intr); 18807c478bd9Sstevel@tonic-gate } 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate if (reset_action & FAS_RESET_SOFTC) { 18837c478bd9Sstevel@tonic-gate fas->f_wdtr_sent = fas->f_sdtr_sent = 0; 18847c478bd9Sstevel@tonic-gate fas->f_wide_known = fas->f_sync_known = 0; 18857c478bd9Sstevel@tonic-gate fas->f_wide_enabled = fas->f_sync_enabled = 0; 18867c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 18877c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = fas->f_last_msgout = 18887c478bd9Sstevel@tonic-gate fas->f_last_msgin = INVALID_MSG; 18897c478bd9Sstevel@tonic-gate fas->f_abort_msg_sent = fas->f_reset_msg_sent = 0; 18907c478bd9Sstevel@tonic-gate fas->f_next_slot = 0; 18917c478bd9Sstevel@tonic-gate fas->f_current_sp = NULL; 18927c478bd9Sstevel@tonic-gate fas->f_fifolen = 0; 18937c478bd9Sstevel@tonic-gate fas->f_fasconf3_reg_last = fas->f_offset_reg_last = 18947c478bd9Sstevel@tonic-gate fas->f_period_reg_last = 0xff; 18957c478bd9Sstevel@tonic-gate 18967c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 19027c478bd9Sstevel@tonic-gate /* 19037c478bd9Sstevel@tonic-gate * check if ncmds still reflects the truth 19047c478bd9Sstevel@tonic-gate * count all cmds for this driver instance and compare with ncmds 19057c478bd9Sstevel@tonic-gate */ 19067c478bd9Sstevel@tonic-gate static void 19077c478bd9Sstevel@tonic-gate fas_check_ncmds(struct fas *fas) 19087c478bd9Sstevel@tonic-gate { 19097c478bd9Sstevel@tonic-gate int slot = 0; 19107c478bd9Sstevel@tonic-gate ushort_t tag, t; 19117c478bd9Sstevel@tonic-gate int n, total = 0; 19127c478bd9Sstevel@tonic-gate 19137c478bd9Sstevel@tonic-gate do { 19147c478bd9Sstevel@tonic-gate if (fas->f_active[slot]) { 19157c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_readyf[slot]; 19167c478bd9Sstevel@tonic-gate t = fas->f_active[slot]->f_n_slots; 19177c478bd9Sstevel@tonic-gate while (sp != 0) { 19187c478bd9Sstevel@tonic-gate sp = sp->cmd_forw; 19197c478bd9Sstevel@tonic-gate total++; 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate for (n = tag = 0; tag < t; tag++) { 19227c478bd9Sstevel@tonic-gate if (fas->f_active[slot]->f_slot[tag] != 0) { 19237c478bd9Sstevel@tonic-gate n++; 19247c478bd9Sstevel@tonic-gate total++; 19257c478bd9Sstevel@tonic-gate } 19267c478bd9Sstevel@tonic-gate } 19277c478bd9Sstevel@tonic-gate ASSERT(n == fas->f_tcmds[slot]); 19287c478bd9Sstevel@tonic-gate } 19297c478bd9Sstevel@tonic-gate slot = NEXTSLOT(slot, fas->f_dslot); 19307c478bd9Sstevel@tonic-gate } while (slot != 0); 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate if (total != fas->f_ncmds) { 19337c478bd9Sstevel@tonic-gate IPRINTF2("fas_check_ncmds: total=%x, ncmds=%x\n", 19347c478bd9Sstevel@tonic-gate total, fas->f_ncmds); 19357c478bd9Sstevel@tonic-gate } 19367c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 19377c478bd9Sstevel@tonic-gate } 19387c478bd9Sstevel@tonic-gate #else 19397c478bd9Sstevel@tonic-gate #define fas_check_ncmds(fas) 19407c478bd9Sstevel@tonic-gate #endif 19417c478bd9Sstevel@tonic-gate 19427c478bd9Sstevel@tonic-gate /* 19437c478bd9Sstevel@tonic-gate * SCSA Interface functions 19447c478bd9Sstevel@tonic-gate * 19457c478bd9Sstevel@tonic-gate * Visible to the external world via the transport structure. 19467c478bd9Sstevel@tonic-gate * 19477c478bd9Sstevel@tonic-gate * fas_scsi_abort: abort a current cmd or all cmds for a target 19487c478bd9Sstevel@tonic-gate */ 19497c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19507c478bd9Sstevel@tonic-gate static int 19517c478bd9Sstevel@tonic-gate fas_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt) 19527c478bd9Sstevel@tonic-gate { 19537c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 19547c478bd9Sstevel@tonic-gate int rval; 19557c478bd9Sstevel@tonic-gate 19567c478bd9Sstevel@tonic-gate IPRINTF2("fas_scsi_abort: target %d.%d\n", ap->a_target, ap->a_lun); 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 19597c478bd9Sstevel@tonic-gate rval = fas_do_scsi_abort(ap, pkt); 19607c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 19617c478bd9Sstevel@tonic-gate return (rval); 19627c478bd9Sstevel@tonic-gate } 19637c478bd9Sstevel@tonic-gate 19647c478bd9Sstevel@tonic-gate /* 19657c478bd9Sstevel@tonic-gate * reset handling: reset bus or target 19667c478bd9Sstevel@tonic-gate */ 19677c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 19687c478bd9Sstevel@tonic-gate static int 19697c478bd9Sstevel@tonic-gate fas_scsi_reset(struct scsi_address *ap, int level) 19707c478bd9Sstevel@tonic-gate { 19717c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 19727c478bd9Sstevel@tonic-gate int rval; 19737c478bd9Sstevel@tonic-gate 19747c478bd9Sstevel@tonic-gate IPRINTF3("fas_scsi_reset: target %d.%d, level %d\n", 19757c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun, level); 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 19787c478bd9Sstevel@tonic-gate rval = fas_do_scsi_reset(ap, level); 19797c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 19807c478bd9Sstevel@tonic-gate return (rval); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate /* 19847c478bd9Sstevel@tonic-gate * entry point for reset notification setup, to register or to cancel. 19857c478bd9Sstevel@tonic-gate */ 19867c478bd9Sstevel@tonic-gate static int 19877c478bd9Sstevel@tonic-gate fas_scsi_reset_notify(struct scsi_address *ap, int flag, 19887c478bd9Sstevel@tonic-gate void (*callback)(caddr_t), caddr_t arg) 19897c478bd9Sstevel@tonic-gate { 19907c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 19917c478bd9Sstevel@tonic-gate 19927c478bd9Sstevel@tonic-gate return (scsi_hba_reset_notify_setup(ap, flag, callback, arg, 19937c478bd9Sstevel@tonic-gate &fas->f_mutex, &fas->f_reset_notify_listf)); 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate 19967c478bd9Sstevel@tonic-gate /* 19977c478bd9Sstevel@tonic-gate * capability interface 19987c478bd9Sstevel@tonic-gate */ 19997c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20007c478bd9Sstevel@tonic-gate static int 20017c478bd9Sstevel@tonic-gate fas_scsi_getcap(struct scsi_address *ap, char *cap, int whom) 20027c478bd9Sstevel@tonic-gate { 20037c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 20047c478bd9Sstevel@tonic-gate DPRINTF3("fas_scsi_getcap: tgt=%x, cap=%s, whom=%x\n", 20057c478bd9Sstevel@tonic-gate ap->a_target, cap, whom); 20067c478bd9Sstevel@tonic-gate return (fas_commoncap(ap, cap, 0, whom, 0)); 20077c478bd9Sstevel@tonic-gate } 20087c478bd9Sstevel@tonic-gate 20097c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20107c478bd9Sstevel@tonic-gate static int 20117c478bd9Sstevel@tonic-gate fas_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom) 20127c478bd9Sstevel@tonic-gate { 20137c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 20147c478bd9Sstevel@tonic-gate IPRINTF4("fas_scsi_setcap: tgt=%x, cap=%s, value=%x, whom=%x\n", 20157c478bd9Sstevel@tonic-gate ap->a_target, cap, value, whom); 20167c478bd9Sstevel@tonic-gate return (fas_commoncap(ap, cap, value, whom, 1)); 20177c478bd9Sstevel@tonic-gate } 20187c478bd9Sstevel@tonic-gate 20197c478bd9Sstevel@tonic-gate /* 20207c478bd9Sstevel@tonic-gate * pkt and dma allocation and deallocation 20217c478bd9Sstevel@tonic-gate */ 20227c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20237c478bd9Sstevel@tonic-gate static void 20247c478bd9Sstevel@tonic-gate fas_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt) 20257c478bd9Sstevel@tonic-gate { 20267c478bd9Sstevel@tonic-gate struct fas_cmd *cmd = PKT2CMD(pkt); 20277c478bd9Sstevel@tonic-gate 20287c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_START, 20297c478bd9Sstevel@tonic-gate "fas_scsi_dmafree_start"); 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate if (cmd->cmd_flags & CFLAG_DMAVALID) { 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * Free the mapping. 20347c478bd9Sstevel@tonic-gate */ 20357c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(cmd->cmd_dmahandle); 20367c478bd9Sstevel@tonic-gate cmd->cmd_flags ^= CFLAG_DMAVALID; 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_END, 20397c478bd9Sstevel@tonic-gate "fas_scsi_dmafree_end"); 20407c478bd9Sstevel@tonic-gate } 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 20437c478bd9Sstevel@tonic-gate static void 20447c478bd9Sstevel@tonic-gate fas_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 20457c478bd9Sstevel@tonic-gate { 20467c478bd9Sstevel@tonic-gate struct fas_cmd *sp = PKT2CMD(pkt); 20477c478bd9Sstevel@tonic-gate 20487c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_DMAVALID) { 20497c478bd9Sstevel@tonic-gate if (ddi_dma_sync(sp->cmd_dmahandle, 0, 0, 20507c478bd9Sstevel@tonic-gate (sp->cmd_flags & CFLAG_DMASEND) ? 20517c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV : DDI_DMA_SYNC_FORCPU) != 20527c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 20537c478bd9Sstevel@tonic-gate fas_log(ADDR2FAS(ap), CE_WARN, 20547c478bd9Sstevel@tonic-gate "sync of pkt (%p) failed", (void *)pkt); 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate } 20577c478bd9Sstevel@tonic-gate } 20587c478bd9Sstevel@tonic-gate 20597c478bd9Sstevel@tonic-gate /* 20607c478bd9Sstevel@tonic-gate * initialize pkt and allocate DVMA resources 20617c478bd9Sstevel@tonic-gate */ 20627c478bd9Sstevel@tonic-gate static struct scsi_pkt * 20637c478bd9Sstevel@tonic-gate fas_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt, 20647c478bd9Sstevel@tonic-gate struct buf *bp, int cmdlen, int statuslen, int tgtlen, 20657c478bd9Sstevel@tonic-gate int flags, int (*callback)(), caddr_t arg) 20667c478bd9Sstevel@tonic-gate { 20677c478bd9Sstevel@tonic-gate int kf; 20687c478bd9Sstevel@tonic-gate int failure = 1; 20697c478bd9Sstevel@tonic-gate struct fas_cmd *cmd; 20707c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 20717c478bd9Sstevel@tonic-gate struct fas_cmd *new_cmd; 20727c478bd9Sstevel@tonic-gate int rval; 20737c478bd9Sstevel@tonic-gate 20747c478bd9Sstevel@tonic-gate /* #define FAS_TEST_EXTRN_ALLOC */ 20757c478bd9Sstevel@tonic-gate #ifdef FAS_TEST_EXTRN_ALLOC 20767c478bd9Sstevel@tonic-gate cmdlen *= 4; statuslen *= 4; tgtlen *= 4; 20777c478bd9Sstevel@tonic-gate #endif 20787c478bd9Sstevel@tonic-gate /* 20797c478bd9Sstevel@tonic-gate * if no pkt was passed then allocate a pkt first 20807c478bd9Sstevel@tonic-gate */ 20817c478bd9Sstevel@tonic-gate if (pkt == NULL) { 20827c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTALLOC_START, 20837c478bd9Sstevel@tonic-gate "fas_scsi_impl_pktalloc_start"); 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate kf = (callback == SLEEP_FUNC)? KM_SLEEP: KM_NOSLEEP; 20867c478bd9Sstevel@tonic-gate 20877c478bd9Sstevel@tonic-gate /* 20887c478bd9Sstevel@tonic-gate * only one size of pkt (with arq). 20897c478bd9Sstevel@tonic-gate */ 20907c478bd9Sstevel@tonic-gate cmd = kmem_cache_alloc(fas->f_kmem_cache, kf); 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate if (cmd) { 20937c478bd9Sstevel@tonic-gate 20947c478bd9Sstevel@tonic-gate ddi_dma_handle_t save_dma_handle; 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate save_dma_handle = cmd->cmd_dmahandle; 20977c478bd9Sstevel@tonic-gate bzero(cmd, EXTCMD_SIZE); 20987c478bd9Sstevel@tonic-gate cmd->cmd_dmahandle = save_dma_handle; 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate pkt = (struct scsi_pkt *)((uchar_t *)cmd + 21017c478bd9Sstevel@tonic-gate sizeof (struct fas_cmd)); 21027c478bd9Sstevel@tonic-gate cmd->cmd_pkt = pkt; 21037c478bd9Sstevel@tonic-gate pkt->pkt_ha_private = (opaque_t)cmd; 21047c478bd9Sstevel@tonic-gate pkt->pkt_scbp = (opaque_t)&cmd->cmd_scb; 21057c478bd9Sstevel@tonic-gate pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb; 21067c478bd9Sstevel@tonic-gate pkt->pkt_address = *ap; 21077c478bd9Sstevel@tonic-gate 21087c478bd9Sstevel@tonic-gate pkt->pkt_cdbp = (opaque_t)&cmd->cmd_cdb; 21097c478bd9Sstevel@tonic-gate pkt->pkt_private = cmd->cmd_pkt_private; 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate cmd->cmd_cdblen = cmdlen; 21127c478bd9Sstevel@tonic-gate cmd->cmd_scblen = statuslen; 21137c478bd9Sstevel@tonic-gate cmd->cmd_privlen = tgtlen; 21147c478bd9Sstevel@tonic-gate cmd->cmd_slot = 21157c478bd9Sstevel@tonic-gate (Tgt(cmd) * NLUNS_PER_TARGET) | Lun(cmd); 21167c478bd9Sstevel@tonic-gate failure = 0; 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate if (failure || (cmdlen > sizeof (cmd->cmd_cdb)) || 21197c478bd9Sstevel@tonic-gate (tgtlen > PKT_PRIV_LEN) || 21207c478bd9Sstevel@tonic-gate (statuslen > EXTCMDS_STATUS_SIZE)) { 21217c478bd9Sstevel@tonic-gate if (failure == 0) { 21227c478bd9Sstevel@tonic-gate /* 21237c478bd9Sstevel@tonic-gate * if extern alloc fails, all will be 21247c478bd9Sstevel@tonic-gate * deallocated, including cmd 21257c478bd9Sstevel@tonic-gate */ 21267c478bd9Sstevel@tonic-gate failure = fas_pkt_alloc_extern(fas, cmd, 21277c478bd9Sstevel@tonic-gate cmdlen, tgtlen, statuslen, kf); 21287c478bd9Sstevel@tonic-gate } 21297c478bd9Sstevel@tonic-gate if (failure) { 21307c478bd9Sstevel@tonic-gate /* 21317c478bd9Sstevel@tonic-gate * nothing to deallocate so just return 21327c478bd9Sstevel@tonic-gate */ 21337c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 21347c478bd9Sstevel@tonic-gate TR_FAS_SCSI_IMPL_PKTALLOC_END, 21357c478bd9Sstevel@tonic-gate "fas_scsi_impl_pktalloc_end"); 21367c478bd9Sstevel@tonic-gate return (NULL); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate } 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate new_cmd = cmd; 21417c478bd9Sstevel@tonic-gate 21427c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTALLOC_END, 21437c478bd9Sstevel@tonic-gate "fas_scsi_impl_pktalloc_end"); 21447c478bd9Sstevel@tonic-gate } else { 21457c478bd9Sstevel@tonic-gate cmd = PKT2CMD(pkt); 21467c478bd9Sstevel@tonic-gate new_cmd = NULL; 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate 21497c478bd9Sstevel@tonic-gate /* 21507c478bd9Sstevel@tonic-gate * Second step of fas_scsi_init_pkt: 21517c478bd9Sstevel@tonic-gate * bind the buf to the handle 21527c478bd9Sstevel@tonic-gate */ 21537c478bd9Sstevel@tonic-gate if (bp && bp->b_bcount != 0 && 21547c478bd9Sstevel@tonic-gate (cmd->cmd_flags & CFLAG_DMAVALID) == 0) { 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate int cmd_flags, dma_flags; 21577c478bd9Sstevel@tonic-gate uint_t dmacookie_count; 21587c478bd9Sstevel@tonic-gate 21597c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_START, 21607c478bd9Sstevel@tonic-gate "fas_scsi_impl_dmaget_start"); 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate cmd_flags = cmd->cmd_flags; 21637c478bd9Sstevel@tonic-gate 21647c478bd9Sstevel@tonic-gate if (bp->b_flags & B_READ) { 21657c478bd9Sstevel@tonic-gate cmd_flags &= ~CFLAG_DMASEND; 21667c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_READ | DDI_DMA_PARTIAL; 21677c478bd9Sstevel@tonic-gate } else { 21687c478bd9Sstevel@tonic-gate cmd_flags |= CFLAG_DMASEND; 21697c478bd9Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE | DDI_DMA_PARTIAL; 21707c478bd9Sstevel@tonic-gate } 21717c478bd9Sstevel@tonic-gate if (flags & PKT_CONSISTENT) { 21727c478bd9Sstevel@tonic-gate cmd_flags |= CFLAG_CMDIOPB; 21737c478bd9Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT; 21747c478bd9Sstevel@tonic-gate } 21757c478bd9Sstevel@tonic-gate 21767c478bd9Sstevel@tonic-gate /* 21777c478bd9Sstevel@tonic-gate * bind the handle to the buf 21787c478bd9Sstevel@tonic-gate */ 21797c478bd9Sstevel@tonic-gate ASSERT(cmd->cmd_dmahandle != NULL); 21807c478bd9Sstevel@tonic-gate rval = ddi_dma_buf_bind_handle(cmd->cmd_dmahandle, bp, 21817c478bd9Sstevel@tonic-gate dma_flags, callback, arg, &cmd->cmd_dmacookie, 21827c478bd9Sstevel@tonic-gate &dmacookie_count); 21837c478bd9Sstevel@tonic-gate 21847c478bd9Sstevel@tonic-gate if (rval && rval != DDI_DMA_PARTIAL_MAP) { 21857c478bd9Sstevel@tonic-gate switch (rval) { 21867c478bd9Sstevel@tonic-gate case DDI_DMA_NORESOURCES: 21877c478bd9Sstevel@tonic-gate bioerror(bp, 0); 21887c478bd9Sstevel@tonic-gate break; 21897c478bd9Sstevel@tonic-gate case DDI_DMA_BADATTR: 21907c478bd9Sstevel@tonic-gate case DDI_DMA_NOMAPPING: 21917c478bd9Sstevel@tonic-gate bioerror(bp, EFAULT); 21927c478bd9Sstevel@tonic-gate break; 21937c478bd9Sstevel@tonic-gate case DDI_DMA_TOOBIG: 21947c478bd9Sstevel@tonic-gate default: 21957c478bd9Sstevel@tonic-gate bioerror(bp, EINVAL); 21967c478bd9Sstevel@tonic-gate break; 21977c478bd9Sstevel@tonic-gate } 21987c478bd9Sstevel@tonic-gate cmd->cmd_flags = cmd_flags & ~CFLAG_DMAVALID; 21997c478bd9Sstevel@tonic-gate if (new_cmd) { 22007c478bd9Sstevel@tonic-gate fas_scsi_destroy_pkt(ap, pkt); 22017c478bd9Sstevel@tonic-gate } 22027c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_END, 22037c478bd9Sstevel@tonic-gate "fas_scsi_impl_dmaget_end"); 22047c478bd9Sstevel@tonic-gate return ((struct scsi_pkt *)NULL); 22057c478bd9Sstevel@tonic-gate } 22067c478bd9Sstevel@tonic-gate ASSERT(dmacookie_count == 1); 22077c478bd9Sstevel@tonic-gate cmd->cmd_dmacount = bp->b_bcount; 22087c478bd9Sstevel@tonic-gate cmd->cmd_flags = cmd_flags | CFLAG_DMAVALID; 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate ASSERT(cmd->cmd_dmahandle != NULL); 22117c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAGET_END, 22127c478bd9Sstevel@tonic-gate "fas_scsi_impl_dmaget_end"); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate return (pkt); 22167c478bd9Sstevel@tonic-gate } 22177c478bd9Sstevel@tonic-gate 22187c478bd9Sstevel@tonic-gate /* 22197c478bd9Sstevel@tonic-gate * unbind dma resources and deallocate the pkt 22207c478bd9Sstevel@tonic-gate */ 22217c478bd9Sstevel@tonic-gate static void 22227c478bd9Sstevel@tonic-gate fas_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt) 22237c478bd9Sstevel@tonic-gate { 22247c478bd9Sstevel@tonic-gate struct fas_cmd *sp = PKT2CMD(pkt); 22257c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 22267c478bd9Sstevel@tonic-gate 22277c478bd9Sstevel@tonic-gate /* 22287c478bd9Sstevel@tonic-gate * fas_scsi_impl_dmafree inline to speed things up 22297c478bd9Sstevel@tonic-gate */ 22307c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_START, 22317c478bd9Sstevel@tonic-gate "fas_scsi_impl_dmafree_start"); 22327c478bd9Sstevel@tonic-gate 22337c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_DMAVALID) { 22347c478bd9Sstevel@tonic-gate /* 22357c478bd9Sstevel@tonic-gate * Free the mapping. 22367c478bd9Sstevel@tonic-gate */ 22377c478bd9Sstevel@tonic-gate (void) ddi_dma_unbind_handle(sp->cmd_dmahandle); 22387c478bd9Sstevel@tonic-gate sp->cmd_flags ^= CFLAG_DMAVALID; 22397c478bd9Sstevel@tonic-gate } 22407c478bd9Sstevel@tonic-gate 22417c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_DMAFREE_END, 22427c478bd9Sstevel@tonic-gate "fas_scsi_impl_dmafree_end"); 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTFREE_START, 22457c478bd9Sstevel@tonic-gate "fas_scsi_impl_pktfree_start"); 22467c478bd9Sstevel@tonic-gate 22477c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & 22487c478bd9Sstevel@tonic-gate (CFLAG_FREE | CFLAG_CDBEXTERN | CFLAG_PRIVEXTERN | 22497c478bd9Sstevel@tonic-gate CFLAG_SCBEXTERN)) == 0) { 22507c478bd9Sstevel@tonic-gate sp->cmd_flags = CFLAG_FREE; 22517c478bd9Sstevel@tonic-gate kmem_cache_free(fas->f_kmem_cache, (void *)sp); 22527c478bd9Sstevel@tonic-gate } else { 22537c478bd9Sstevel@tonic-gate fas_pkt_destroy_extern(fas, sp); 22547c478bd9Sstevel@tonic-gate } 22557c478bd9Sstevel@tonic-gate 22567c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_SCSI_IMPL_PKTFREE_END, 22577c478bd9Sstevel@tonic-gate "fas_scsi_impl_pktfree_end"); 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate /* 22617c478bd9Sstevel@tonic-gate * allocate and deallocate external pkt space (ie. not part of fas_cmd) for 22627c478bd9Sstevel@tonic-gate * non-standard length cdb, pkt_private, status areas 22637c478bd9Sstevel@tonic-gate * if allocation fails, then deallocate all external space and the pkt 22647c478bd9Sstevel@tonic-gate */ 22657c478bd9Sstevel@tonic-gate /* ARGSUSED */ 22667c478bd9Sstevel@tonic-gate static int 22677c478bd9Sstevel@tonic-gate fas_pkt_alloc_extern(struct fas *fas, struct fas_cmd *sp, 22687c478bd9Sstevel@tonic-gate int cmdlen, int tgtlen, int statuslen, int kf) 22697c478bd9Sstevel@tonic-gate { 22707c478bd9Sstevel@tonic-gate caddr_t cdbp, scbp, tgt; 22717c478bd9Sstevel@tonic-gate int failure = 0; 22727c478bd9Sstevel@tonic-gate 22737c478bd9Sstevel@tonic-gate tgt = cdbp = scbp = NULL; 22747c478bd9Sstevel@tonic-gate if (cmdlen > sizeof (sp->cmd_cdb)) { 22757c478bd9Sstevel@tonic-gate if ((cdbp = kmem_zalloc((size_t)cmdlen, kf)) == NULL) { 22767c478bd9Sstevel@tonic-gate failure++; 22777c478bd9Sstevel@tonic-gate } else { 22787c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_cdbp = (opaque_t)cdbp; 22797c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_CDBEXTERN; 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate } 22827c478bd9Sstevel@tonic-gate if (tgtlen > PKT_PRIV_LEN) { 22837c478bd9Sstevel@tonic-gate if ((tgt = kmem_zalloc(tgtlen, kf)) == NULL) { 22847c478bd9Sstevel@tonic-gate failure++; 22857c478bd9Sstevel@tonic-gate } else { 22867c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_PRIVEXTERN; 22877c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_private = tgt; 22887c478bd9Sstevel@tonic-gate } 22897c478bd9Sstevel@tonic-gate } 22907c478bd9Sstevel@tonic-gate if (statuslen > EXTCMDS_STATUS_SIZE) { 22917c478bd9Sstevel@tonic-gate if ((scbp = kmem_zalloc((size_t)statuslen, kf)) == NULL) { 22927c478bd9Sstevel@tonic-gate failure++; 22937c478bd9Sstevel@tonic-gate } else { 22947c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_SCBEXTERN; 22957c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_scbp = (opaque_t)scbp; 22967c478bd9Sstevel@tonic-gate } 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate if (failure) { 22997c478bd9Sstevel@tonic-gate fas_pkt_destroy_extern(fas, sp); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate return (failure); 23027c478bd9Sstevel@tonic-gate } 23037c478bd9Sstevel@tonic-gate 23047c478bd9Sstevel@tonic-gate /* 23057c478bd9Sstevel@tonic-gate * deallocate external pkt space and deallocate the pkt 23067c478bd9Sstevel@tonic-gate */ 23077c478bd9Sstevel@tonic-gate static void 23087c478bd9Sstevel@tonic-gate fas_pkt_destroy_extern(struct fas *fas, struct fas_cmd *sp) 23097c478bd9Sstevel@tonic-gate { 23107c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_FREE) { 23117c478bd9Sstevel@tonic-gate panic("fas_pkt_destroy_extern: freeing free packet"); 23127c478bd9Sstevel@tonic-gate _NOTE(NOT_REACHED) 23137c478bd9Sstevel@tonic-gate /* NOTREACHED */ 23147c478bd9Sstevel@tonic-gate } 23157c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CDBEXTERN) { 23167c478bd9Sstevel@tonic-gate kmem_free((caddr_t)sp->cmd_pkt->pkt_cdbp, 23177c478bd9Sstevel@tonic-gate (size_t)sp->cmd_cdblen); 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_SCBEXTERN) { 23207c478bd9Sstevel@tonic-gate kmem_free((caddr_t)sp->cmd_pkt->pkt_scbp, 23217c478bd9Sstevel@tonic-gate (size_t)sp->cmd_scblen); 23227c478bd9Sstevel@tonic-gate } 23237c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_PRIVEXTERN) { 23247c478bd9Sstevel@tonic-gate kmem_free((caddr_t)sp->cmd_pkt->pkt_private, 23257c478bd9Sstevel@tonic-gate (size_t)sp->cmd_privlen); 23267c478bd9Sstevel@tonic-gate } 23277c478bd9Sstevel@tonic-gate sp->cmd_flags = CFLAG_FREE; 23287c478bd9Sstevel@tonic-gate kmem_cache_free(fas->f_kmem_cache, (void *)sp); 23297c478bd9Sstevel@tonic-gate } 23307c478bd9Sstevel@tonic-gate 23317c478bd9Sstevel@tonic-gate /* 23327c478bd9Sstevel@tonic-gate * kmem cache constructor and destructor: 23337c478bd9Sstevel@tonic-gate * When constructing, we bzero the cmd and allocate the dma handle 23347c478bd9Sstevel@tonic-gate * When destructing, just free the dma handle 23357c478bd9Sstevel@tonic-gate */ 23367c478bd9Sstevel@tonic-gate static int 23377c478bd9Sstevel@tonic-gate fas_kmem_cache_constructor(void *buf, void *cdrarg, int kmflags) 23387c478bd9Sstevel@tonic-gate { 23397c478bd9Sstevel@tonic-gate struct fas_cmd *cmd = buf; 23407c478bd9Sstevel@tonic-gate struct fas *fas = cdrarg; 23417c478bd9Sstevel@tonic-gate int (*callback)(caddr_t) = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: 23427c478bd9Sstevel@tonic-gate DDI_DMA_DONTWAIT; 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate bzero(buf, EXTCMD_SIZE); 23457c478bd9Sstevel@tonic-gate 23467c478bd9Sstevel@tonic-gate /* 23477c478bd9Sstevel@tonic-gate * allocate a dma handle 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate if ((ddi_dma_alloc_handle(fas->f_dev, fas->f_dma_attr, callback, 23507c478bd9Sstevel@tonic-gate NULL, &cmd->cmd_dmahandle)) != DDI_SUCCESS) { 23517c478bd9Sstevel@tonic-gate return (-1); 23527c478bd9Sstevel@tonic-gate } 23537c478bd9Sstevel@tonic-gate return (0); 23547c478bd9Sstevel@tonic-gate } 23557c478bd9Sstevel@tonic-gate 23567c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 23577c478bd9Sstevel@tonic-gate static void 23587c478bd9Sstevel@tonic-gate fas_kmem_cache_destructor(void *buf, void *cdrarg) 23597c478bd9Sstevel@tonic-gate { 23607c478bd9Sstevel@tonic-gate struct fas_cmd *cmd = buf; 23617c478bd9Sstevel@tonic-gate if (cmd->cmd_dmahandle) { 23627c478bd9Sstevel@tonic-gate ddi_dma_free_handle(&cmd->cmd_dmahandle); 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate } 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate /* 23677c478bd9Sstevel@tonic-gate * fas_scsi_start - Accept commands for transport 23687c478bd9Sstevel@tonic-gate */ 23697c478bd9Sstevel@tonic-gate static int 23707c478bd9Sstevel@tonic-gate fas_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt) 23717c478bd9Sstevel@tonic-gate { 23727c478bd9Sstevel@tonic-gate struct fas_cmd *sp = PKT2CMD(pkt); 23737c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 23747c478bd9Sstevel@tonic-gate int rval; 23757c478bd9Sstevel@tonic-gate int intr = 0; 23767c478bd9Sstevel@tonic-gate 23777c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_START_START, "fas_scsi_start_start"); 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 23807c478bd9Sstevel@tonic-gate if (fas_transport_busy > 0) { 23817c478bd9Sstevel@tonic-gate fas_transport_busy--; 23827c478bd9Sstevel@tonic-gate return (TRAN_BUSY); 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate if ((fas_transport_busy_rqs > 0) && 23857c478bd9Sstevel@tonic-gate (*(sp->cmd_pkt->pkt_cdbp) == SCMD_REQUEST_SENSE)) { 23867c478bd9Sstevel@tonic-gate fas_transport_busy_rqs--; 23877c478bd9Sstevel@tonic-gate return (TRAN_BUSY); 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate if (fas_transport_reject > 0) { 23907c478bd9Sstevel@tonic-gate fas_transport_reject--; 23917c478bd9Sstevel@tonic-gate return (TRAN_BADPKT); 23927c478bd9Sstevel@tonic-gate } 23937c478bd9Sstevel@tonic-gate #endif 23947c478bd9Sstevel@tonic-gate /* 23957c478bd9Sstevel@tonic-gate * prepare packet before taking the mutex 23967c478bd9Sstevel@tonic-gate */ 23977c478bd9Sstevel@tonic-gate rval = fas_prepare_pkt(fas, sp); 23987c478bd9Sstevel@tonic-gate if (rval != TRAN_ACCEPT) { 23997c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_START_PREPARE_PKT_END, 24007c478bd9Sstevel@tonic-gate "fas_scsi_start_end (prepare_pkt)"); 24017c478bd9Sstevel@tonic-gate return (rval); 24027c478bd9Sstevel@tonic-gate } 24037c478bd9Sstevel@tonic-gate 24047c478bd9Sstevel@tonic-gate /* 24057c478bd9Sstevel@tonic-gate * fas mutex can be held for a long time; therefore, if the mutex is 24067c478bd9Sstevel@tonic-gate * held, we queue the packet in a waitQ; we now should check 24077c478bd9Sstevel@tonic-gate * the waitQ on every mutex_exit(FAS_MUTEX(fas)) but we really only 24087c478bd9Sstevel@tonic-gate * need to do this when the bus is free 24097c478bd9Sstevel@tonic-gate * don't put NOINTR cmds including proxy cmds in waitQ! These 24107c478bd9Sstevel@tonic-gate * cmds are handled by fas_runpoll() 24117c478bd9Sstevel@tonic-gate * if the waitQ is non-empty, queue the pkt anyway to preserve 24127c478bd9Sstevel@tonic-gate * order 24137c478bd9Sstevel@tonic-gate * the goal is to queue in waitQ as much as possible so at 24147c478bd9Sstevel@tonic-gate * interrupt time, we can move the packets to readyQ or start 24157c478bd9Sstevel@tonic-gate * a packet immediately. It helps to do this at interrupt 24167c478bd9Sstevel@tonic-gate * time because we can then field more interrupts 24177c478bd9Sstevel@tonic-gate */ 24187c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_NOINTR) == 0) { 24197c478bd9Sstevel@tonic-gate 24207c478bd9Sstevel@tonic-gate /* 24217c478bd9Sstevel@tonic-gate * if the bus is not free, we will get an interrupt shortly 24227c478bd9Sstevel@tonic-gate * so we don't want to take the fas mutex but queue up 24237c478bd9Sstevel@tonic-gate * the packet in the waitQ 24247c478bd9Sstevel@tonic-gate * also, if the waitQ is non-empty or there is an interrupt 24257c478bd9Sstevel@tonic-gate * pending then queue up the packet in the waitQ and let the 24267c478bd9Sstevel@tonic-gate * interrupt handler empty the waitQ 24277c478bd9Sstevel@tonic-gate */ 24287c478bd9Sstevel@tonic-gate mutex_enter(&fas->f_waitQ_mutex); 24297c478bd9Sstevel@tonic-gate 24307c478bd9Sstevel@tonic-gate if ((fas->f_state != STATE_FREE) || 24317c478bd9Sstevel@tonic-gate fas->f_waitf || (intr = INTPENDING(fas))) { 24327c478bd9Sstevel@tonic-gate goto queue_in_waitQ; 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate /* 24367c478bd9Sstevel@tonic-gate * we didn't queue up in the waitQ, so now try to accept 24377c478bd9Sstevel@tonic-gate * the packet. if we fail to get the fas mutex, go back to 24387c478bd9Sstevel@tonic-gate * the waitQ again 24397c478bd9Sstevel@tonic-gate * do not release the waitQ mutex yet because that 24407c478bd9Sstevel@tonic-gate * leaves a window where the interrupt handler has 24417c478bd9Sstevel@tonic-gate * emptied the waitQ but not released the fas mutex yet 24427c478bd9Sstevel@tonic-gate * 24437c478bd9Sstevel@tonic-gate * the interrupt handler gets the locks in opposite order 24447c478bd9Sstevel@tonic-gate * but because we do a tryenter, there is no deadlock 24457c478bd9Sstevel@tonic-gate * 24467c478bd9Sstevel@tonic-gate * if another thread has the fas mutex then either this 24477c478bd9Sstevel@tonic-gate * thread or the other may find the bus free and 24487c478bd9Sstevel@tonic-gate * empty the waitQ 24497c478bd9Sstevel@tonic-gate */ 24507c478bd9Sstevel@tonic-gate if (mutex_tryenter(FAS_MUTEX(fas))) { 24517c478bd9Sstevel@tonic-gate mutex_exit(&fas->f_waitQ_mutex); 24527c478bd9Sstevel@tonic-gate rval = fas_accept_pkt(fas, sp, TRAN_BUSY_OK); 24537c478bd9Sstevel@tonic-gate } else { 24547c478bd9Sstevel@tonic-gate /* 24557c478bd9Sstevel@tonic-gate * we didn't get the fas mutex so 24567c478bd9Sstevel@tonic-gate * the packet has to go in the waitQ now 24577c478bd9Sstevel@tonic-gate */ 24587c478bd9Sstevel@tonic-gate goto queue_in_waitQ; 24597c478bd9Sstevel@tonic-gate } 24607c478bd9Sstevel@tonic-gate } else { 24617c478bd9Sstevel@tonic-gate /* 24627c478bd9Sstevel@tonic-gate * for polled cmds, we have to take the mutex and 24637c478bd9Sstevel@tonic-gate * start the packet using fas_runpoll() 24647c478bd9Sstevel@tonic-gate */ 24657c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 24667c478bd9Sstevel@tonic-gate rval = fas_accept_pkt(fas, sp, TRAN_BUSY_OK); 24677c478bd9Sstevel@tonic-gate } 24687c478bd9Sstevel@tonic-gate 24697c478bd9Sstevel@tonic-gate /* 24707c478bd9Sstevel@tonic-gate * if the bus is free then empty waitQ and release the mutex 24717c478bd9Sstevel@tonic-gate * (this should be unlikely that the bus is still free after 24727c478bd9Sstevel@tonic-gate * accepting the packet. it may be the relatively unusual case 24737c478bd9Sstevel@tonic-gate * that we are throttling) 24747c478bd9Sstevel@tonic-gate */ 24757c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) { 24767c478bd9Sstevel@tonic-gate FAS_CHECK_WAITQ_AND_FAS_MUTEX_EXIT(fas); 24777c478bd9Sstevel@tonic-gate } else { 24787c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 24797c478bd9Sstevel@tonic-gate } 24807c478bd9Sstevel@tonic-gate 24817c478bd9Sstevel@tonic-gate done: 24827c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_SCSI_FAS, TR_FAS_START_END, 24837c478bd9Sstevel@tonic-gate "fas_scsi_start_end: fas 0x%p", fas); 24847c478bd9Sstevel@tonic-gate return (rval); 24857c478bd9Sstevel@tonic-gate 24867c478bd9Sstevel@tonic-gate queue_in_waitQ: 24877c478bd9Sstevel@tonic-gate if (fas->f_waitf == NULL) { 24887c478bd9Sstevel@tonic-gate fas->f_waitb = fas->f_waitf = sp; 24897c478bd9Sstevel@tonic-gate sp->cmd_forw = NULL; 24907c478bd9Sstevel@tonic-gate } else { 24917c478bd9Sstevel@tonic-gate struct fas_cmd *dp = fas->f_waitb; 24927c478bd9Sstevel@tonic-gate dp->cmd_forw = fas->f_waitb = sp; 24937c478bd9Sstevel@tonic-gate sp->cmd_forw = NULL; 24947c478bd9Sstevel@tonic-gate } 24957c478bd9Sstevel@tonic-gate 24967c478bd9Sstevel@tonic-gate /* 24977c478bd9Sstevel@tonic-gate * check again the fas mutex 24987c478bd9Sstevel@tonic-gate * if there was an interrupt then the interrupt 24997c478bd9Sstevel@tonic-gate * handler will eventually empty the waitQ 25007c478bd9Sstevel@tonic-gate */ 25017c478bd9Sstevel@tonic-gate if ((intr == 0) && (fas->f_state == STATE_FREE) && 25027c478bd9Sstevel@tonic-gate mutex_tryenter(FAS_MUTEX(fas))) { 25037c478bd9Sstevel@tonic-gate /* 25047c478bd9Sstevel@tonic-gate * double check if the bus is still free 25057c478bd9Sstevel@tonic-gate * (this actually reduced mutex contention a bit) 25067c478bd9Sstevel@tonic-gate */ 25077c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) { 25087c478bd9Sstevel@tonic-gate fas_empty_waitQ(fas); 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 25117c478bd9Sstevel@tonic-gate } 25127c478bd9Sstevel@tonic-gate mutex_exit(&fas->f_waitQ_mutex); 25137c478bd9Sstevel@tonic-gate 25147c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_SCSI_FAS, TR_FAS_START_END, 25157c478bd9Sstevel@tonic-gate "fas_scsi_start_end: fas 0x%p", fas); 25167c478bd9Sstevel@tonic-gate return (rval); 25177c478bd9Sstevel@tonic-gate } 25187c478bd9Sstevel@tonic-gate 25197c478bd9Sstevel@tonic-gate /* 25207c478bd9Sstevel@tonic-gate * prepare the pkt: 25217c478bd9Sstevel@tonic-gate * the pkt may have been resubmitted or just reused so 25227c478bd9Sstevel@tonic-gate * initialize some fields, reset the dma window, and do some checks 25237c478bd9Sstevel@tonic-gate */ 25247c478bd9Sstevel@tonic-gate static int 25257c478bd9Sstevel@tonic-gate fas_prepare_pkt(struct fas *fas, struct fas_cmd *sp) 25267c478bd9Sstevel@tonic-gate { 25277c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(sp); 25287c478bd9Sstevel@tonic-gate 25297c478bd9Sstevel@tonic-gate /* 25307c478bd9Sstevel@tonic-gate * Reinitialize some fields that need it; the packet may 25317c478bd9Sstevel@tonic-gate * have been resubmitted 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT; 25347c478bd9Sstevel@tonic-gate pkt->pkt_state = 0; 25357c478bd9Sstevel@tonic-gate pkt->pkt_statistics = 0; 25367c478bd9Sstevel@tonic-gate pkt->pkt_resid = 0; 25377c478bd9Sstevel@tonic-gate sp->cmd_age = 0; 25387c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags = pkt->pkt_flags; 25397c478bd9Sstevel@tonic-gate 25407c478bd9Sstevel@tonic-gate /* 25417c478bd9Sstevel@tonic-gate * Copy the cdb pointer to the pkt wrapper area as we 25427c478bd9Sstevel@tonic-gate * might modify this pointer. Zero status byte 25437c478bd9Sstevel@tonic-gate */ 25447c478bd9Sstevel@tonic-gate sp->cmd_cdbp = pkt->pkt_cdbp; 25457c478bd9Sstevel@tonic-gate *(pkt->pkt_scbp) = 0; 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_DMAVALID) { 25487c478bd9Sstevel@tonic-gate pkt->pkt_resid = sp->cmd_dmacount; 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate /* 25517c478bd9Sstevel@tonic-gate * if the pkt was resubmitted then the 25527c478bd9Sstevel@tonic-gate * windows may be at the wrong number 25537c478bd9Sstevel@tonic-gate */ 25547c478bd9Sstevel@tonic-gate if (sp->cmd_cur_win) { 25557c478bd9Sstevel@tonic-gate sp->cmd_cur_win = 0; 25567c478bd9Sstevel@tonic-gate if (fas_set_new_window(fas, sp)) { 25577c478bd9Sstevel@tonic-gate IPRINTF("cannot reset window\n"); 25587c478bd9Sstevel@tonic-gate return (TRAN_BADPKT); 25597c478bd9Sstevel@tonic-gate } 25607c478bd9Sstevel@tonic-gate } 25617c478bd9Sstevel@tonic-gate sp->cmd_saved_cur_addr = 25627c478bd9Sstevel@tonic-gate sp->cmd_cur_addr = sp->cmd_dmacookie.dmac_address; 25637c478bd9Sstevel@tonic-gate 25647c478bd9Sstevel@tonic-gate /* 25657c478bd9Sstevel@tonic-gate * the common case is just one window, we worry 25667c478bd9Sstevel@tonic-gate * about multiple windows when we run out of the 25677c478bd9Sstevel@tonic-gate * current window 25687c478bd9Sstevel@tonic-gate */ 25697c478bd9Sstevel@tonic-gate sp->cmd_nwin = sp->cmd_saved_win = 0; 25707c478bd9Sstevel@tonic-gate sp->cmd_data_count = sp->cmd_saved_data_count = 0; 25717c478bd9Sstevel@tonic-gate 25727c478bd9Sstevel@tonic-gate /* 25737c478bd9Sstevel@tonic-gate * consistent packets need to be sync'ed first 25747c478bd9Sstevel@tonic-gate * (only for data going out) 25757c478bd9Sstevel@tonic-gate */ 25767c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & (CFLAG_CMDIOPB | CFLAG_DMASEND)) == 25777c478bd9Sstevel@tonic-gate (CFLAG_CMDIOPB | CFLAG_DMASEND)) { 25787c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(sp->cmd_dmahandle, 0, (uint_t)0, 25797c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORDEV); 25807c478bd9Sstevel@tonic-gate } 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate 25837c478bd9Sstevel@tonic-gate sp->cmd_actual_cdblen = sp->cmd_cdblen; 25847c478bd9Sstevel@tonic-gate 25857c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 25867c478bd9Sstevel@tonic-gate #ifndef __lock_lint 25877c478bd9Sstevel@tonic-gate if (fas_test_untagged > 0) { 25887c478bd9Sstevel@tonic-gate if (TAGGED(Tgt(sp))) { 25897c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 25907c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags &= ~FLAG_TAGMASK; 25917c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags &= ~FLAG_NODISCON; 25927c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags |= 0x80000000; 25937c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, 25947c478bd9Sstevel@tonic-gate "starting untagged cmd, target=%d," 25957c478bd9Sstevel@tonic-gate " tcmds=%d, sp=0x%p, throttle=%d\n", 25967c478bd9Sstevel@tonic-gate Tgt(sp), fas->f_tcmds[slot], (void *)sp, 25977c478bd9Sstevel@tonic-gate fas->f_throttle[slot]); 25987c478bd9Sstevel@tonic-gate fas_test_untagged = -10; 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate } 26017c478bd9Sstevel@tonic-gate #endif 26027c478bd9Sstevel@tonic-gate #endif 26037c478bd9Sstevel@tonic-gate 26047c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 26057c478bd9Sstevel@tonic-gate if (NOTAG(Tgt(sp)) && (pkt->pkt_flags & FLAG_TAGMASK)) { 26067c478bd9Sstevel@tonic-gate IPRINTF2("tagged packet for non-tagged target %d.%d\n", 26077c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp)); 26087c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_PREPARE_PKT_TRAN_BADPKT_END, 26097c478bd9Sstevel@tonic-gate "fas_prepare_pkt_end (tran_badpkt)"); 26107c478bd9Sstevel@tonic-gate return (TRAN_BADPKT); 26117c478bd9Sstevel@tonic-gate } 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate /* 26147c478bd9Sstevel@tonic-gate * the SCSA spec states that it is an error to have no 26157c478bd9Sstevel@tonic-gate * completion function when FLAG_NOINTR is not set 26167c478bd9Sstevel@tonic-gate */ 26177c478bd9Sstevel@tonic-gate if ((pkt->pkt_comp == NULL) && 26187c478bd9Sstevel@tonic-gate ((pkt->pkt_flags & FLAG_NOINTR) == 0)) { 26197c478bd9Sstevel@tonic-gate IPRINTF("intr packet with pkt_comp == 0\n"); 26207c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_PREPARE_PKT_TRAN_BADPKT_END, 26217c478bd9Sstevel@tonic-gate "fas_prepare_pkt_end (tran_badpkt)"); 26227c478bd9Sstevel@tonic-gate return (TRAN_BADPKT); 26237c478bd9Sstevel@tonic-gate } 26247c478bd9Sstevel@tonic-gate #endif /* FASDEBUG */ 26257c478bd9Sstevel@tonic-gate 26267c478bd9Sstevel@tonic-gate if ((fas->f_target_scsi_options[Tgt(sp)] & SCSI_OPTIONS_DR) == 0) { 26277c478bd9Sstevel@tonic-gate /* 26287c478bd9Sstevel@tonic-gate * no need to reset tag bits since tag queueing will 26297c478bd9Sstevel@tonic-gate * not be enabled if disconnects are disabled 26307c478bd9Sstevel@tonic-gate */ 26317c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags |= FLAG_NODISCON; 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate 26347c478bd9Sstevel@tonic-gate sp->cmd_flags = (sp->cmd_flags & ~CFLAG_TRANFLAG) | 26357c478bd9Sstevel@tonic-gate CFLAG_PREPARED | CFLAG_IN_TRANSPORT; 26367c478bd9Sstevel@tonic-gate 26377c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_PREPARE_PKT_TRAN_ACCEPT_END, 26387c478bd9Sstevel@tonic-gate "fas_prepare_pkt_end (tran_accept)"); 26397c478bd9Sstevel@tonic-gate return (TRAN_ACCEPT); 26407c478bd9Sstevel@tonic-gate } 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate /* 26437c478bd9Sstevel@tonic-gate * emptying the waitQ just before releasing FAS_MUTEX is a bit 26447c478bd9Sstevel@tonic-gate * tricky; if we release the waitQ mutex and then the FAS_MUTEX, 26457c478bd9Sstevel@tonic-gate * another thread could queue a cmd in the waitQ, just before 26467c478bd9Sstevel@tonic-gate * the FAS_MUTEX is released. This cmd is then stuck in the waitQ unless 26477c478bd9Sstevel@tonic-gate * another cmd comes in or fas_intr() or fas_watch() checks the waitQ. 26487c478bd9Sstevel@tonic-gate * Therefore, by releasing the FAS_MUTEX before releasing the waitQ mutex, 26497c478bd9Sstevel@tonic-gate * we prevent fas_scsi_start() filling the waitQ 26507c478bd9Sstevel@tonic-gate * 26517c478bd9Sstevel@tonic-gate * By setting NO_TRAN_BUSY, we force fas_accept_pkt() to queue up 26527c478bd9Sstevel@tonic-gate * the waitQ pkts in the readyQ. 26537c478bd9Sstevel@tonic-gate * If a QFull condition occurs, the target driver may set its throttle 26547c478bd9Sstevel@tonic-gate * too high because of the requests queued up in the readyQ but this 26557c478bd9Sstevel@tonic-gate * is not a big problem. The throttle should be periodically reset anyway. 26567c478bd9Sstevel@tonic-gate */ 26577c478bd9Sstevel@tonic-gate static void 26587c478bd9Sstevel@tonic-gate fas_empty_waitQ(struct fas *fas) 26597c478bd9Sstevel@tonic-gate { 26607c478bd9Sstevel@tonic-gate struct fas_cmd *sp; 26617c478bd9Sstevel@tonic-gate int rval; 26627c478bd9Sstevel@tonic-gate struct fas_cmd *waitf, *waitb; 26637c478bd9Sstevel@tonic-gate 26647c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&fas->f_waitQ_mutex)); 26657c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_EMPTY_WAITQ_START, 26667c478bd9Sstevel@tonic-gate "fas_empty_waitQ_start"); 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate while (fas->f_waitf) { 26697c478bd9Sstevel@tonic-gate 26707c478bd9Sstevel@tonic-gate /* copy waitQ, zero the waitQ and release the mutex */ 26717c478bd9Sstevel@tonic-gate waitf = fas->f_waitf; 26727c478bd9Sstevel@tonic-gate waitb = fas->f_waitb; 26737c478bd9Sstevel@tonic-gate fas->f_waitf = fas->f_waitb = NULL; 26747c478bd9Sstevel@tonic-gate mutex_exit(&fas->f_waitQ_mutex); 26757c478bd9Sstevel@tonic-gate 26767c478bd9Sstevel@tonic-gate do { 26777c478bd9Sstevel@tonic-gate sp = waitf; 26787c478bd9Sstevel@tonic-gate waitf = sp->cmd_forw; 26797c478bd9Sstevel@tonic-gate if (waitb == sp) { 26807c478bd9Sstevel@tonic-gate waitb = NULL; 26817c478bd9Sstevel@tonic-gate } 26827c478bd9Sstevel@tonic-gate 26837c478bd9Sstevel@tonic-gate rval = fas_accept_pkt(fas, sp, NO_TRAN_BUSY); 26847c478bd9Sstevel@tonic-gate 26857c478bd9Sstevel@tonic-gate /* 26867c478bd9Sstevel@tonic-gate * If the packet was rejected for other reasons then 26877c478bd9Sstevel@tonic-gate * complete it here 26887c478bd9Sstevel@tonic-gate */ 26897c478bd9Sstevel@tonic-gate if (rval != TRAN_ACCEPT) { 26907c478bd9Sstevel@tonic-gate ASSERT(rval != TRAN_BUSY); 26917c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 26927c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_comp) { 26937c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_FINISHED; 26947c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 26957c478bd9Sstevel@tonic-gate } 26967c478bd9Sstevel@tonic-gate } 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 26997c478bd9Sstevel@tonic-gate /* 27007c478bd9Sstevel@tonic-gate * stop processing the waitQ and put back 27017c478bd9Sstevel@tonic-gate * the remaining packets on the waitQ 27027c478bd9Sstevel@tonic-gate */ 27037c478bd9Sstevel@tonic-gate mutex_enter(&fas->f_waitQ_mutex); 27047c478bd9Sstevel@tonic-gate if (waitf) { 27057c478bd9Sstevel@tonic-gate ASSERT(waitb != NULL); 27067c478bd9Sstevel@tonic-gate waitb->cmd_forw = fas->f_waitf; 27077c478bd9Sstevel@tonic-gate fas->f_waitf = waitf; 27087c478bd9Sstevel@tonic-gate if (fas->f_waitb == NULL) { 27097c478bd9Sstevel@tonic-gate fas->f_waitb = waitb; 27107c478bd9Sstevel@tonic-gate } 27117c478bd9Sstevel@tonic-gate } 27127c478bd9Sstevel@tonic-gate return; 27137c478bd9Sstevel@tonic-gate } 27147c478bd9Sstevel@tonic-gate } while (waitf); 27157c478bd9Sstevel@tonic-gate 27167c478bd9Sstevel@tonic-gate mutex_enter(&fas->f_waitQ_mutex); 27177c478bd9Sstevel@tonic-gate } 27187c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_EMPTY_WAITQ_END, 27197c478bd9Sstevel@tonic-gate "fas_empty_waitQ_end"); 27207c478bd9Sstevel@tonic-gate } 27217c478bd9Sstevel@tonic-gate 27227c478bd9Sstevel@tonic-gate static void 27237c478bd9Sstevel@tonic-gate fas_move_waitQ_to_readyQ(struct fas *fas) 27247c478bd9Sstevel@tonic-gate { 27257c478bd9Sstevel@tonic-gate /* 27267c478bd9Sstevel@tonic-gate * this may actually start cmds but it is most likely 27277c478bd9Sstevel@tonic-gate * that if waitQ is not empty that the bus is not free 27287c478bd9Sstevel@tonic-gate */ 27297c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 27307c478bd9Sstevel@tonic-gate mutex_enter(&fas->f_waitQ_mutex); 27317c478bd9Sstevel@tonic-gate fas_empty_waitQ(fas); 27327c478bd9Sstevel@tonic-gate mutex_exit(&fas->f_waitQ_mutex); 27337c478bd9Sstevel@tonic-gate } 27347c478bd9Sstevel@tonic-gate 27357c478bd9Sstevel@tonic-gate 27367c478bd9Sstevel@tonic-gate /* 27377c478bd9Sstevel@tonic-gate * function wrapper for two frequently used macros. for the non-critical 27387c478bd9Sstevel@tonic-gate * path we use the function 27397c478bd9Sstevel@tonic-gate */ 27407c478bd9Sstevel@tonic-gate static void 27417c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(struct fas *fas) 27427c478bd9Sstevel@tonic-gate { 27437c478bd9Sstevel@tonic-gate _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(fas->f_mutex)) 27447c478bd9Sstevel@tonic-gate FAS_CHECK_WAITQ_AND_FAS_MUTEX_EXIT(fas); 27457c478bd9Sstevel@tonic-gate FAS_EMPTY_CALLBACKQ(fas); 27467c478bd9Sstevel@tonic-gate } 27477c478bd9Sstevel@tonic-gate 27487c478bd9Sstevel@tonic-gate /* 27497c478bd9Sstevel@tonic-gate * fas_accept_pkt(): 27507c478bd9Sstevel@tonic-gate * the flag argument is to force fas_accept_pkt to accept the pkt; 27517c478bd9Sstevel@tonic-gate * the caller cannot take the pkt back and it has to be queued up in 27527c478bd9Sstevel@tonic-gate * the readyQ 27537c478bd9Sstevel@tonic-gate */ 27547c478bd9Sstevel@tonic-gate static int 27557c478bd9Sstevel@tonic-gate fas_accept_pkt(struct fas *fas, struct fas_cmd *sp, int flag) 27567c478bd9Sstevel@tonic-gate { 27577c478bd9Sstevel@tonic-gate short slot = sp->cmd_slot; 27587c478bd9Sstevel@tonic-gate int rval = TRAN_ACCEPT; 27597c478bd9Sstevel@tonic-gate 27607c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR__FAS_START_START, "fas_accept_pkt_start"); 27617c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 27627c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= 0 && fas->f_ndisc >= 0); 27637c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 27647c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] >= 0); 27657c478bd9Sstevel@tonic-gate 27667c478bd9Sstevel@tonic-gate /* 27677c478bd9Sstevel@tonic-gate * prepare packet for transport if this hasn't been done yet and 27687c478bd9Sstevel@tonic-gate * do some checks 27697c478bd9Sstevel@tonic-gate */ 27707c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_PREPARED) == 0) { 27717c478bd9Sstevel@tonic-gate rval = fas_prepare_pkt(fas, sp); 27727c478bd9Sstevel@tonic-gate if (rval != TRAN_ACCEPT) { 27737c478bd9Sstevel@tonic-gate IPRINTF1("prepare pkt failed, slot=%x\n", slot); 27747c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_TRANFLAG; 27757c478bd9Sstevel@tonic-gate goto done; 27767c478bd9Sstevel@tonic-gate } 27777c478bd9Sstevel@tonic-gate } 27787c478bd9Sstevel@tonic-gate 27797c478bd9Sstevel@tonic-gate if (Lun(sp)) { 27807c478bd9Sstevel@tonic-gate EPRINTF("fas_accept_pkt: switching target and lun slot scan\n"); 27817c478bd9Sstevel@tonic-gate fas->f_dslot = 1; 27827c478bd9Sstevel@tonic-gate 27837c478bd9Sstevel@tonic-gate if ((fas->f_active[slot] == NULL) || 27847c478bd9Sstevel@tonic-gate ((fas->f_active[slot]->f_n_slots != NTAGS) && 27857c478bd9Sstevel@tonic-gate TAGGED(Tgt(sp)))) { 27867c478bd9Sstevel@tonic-gate (void) fas_alloc_active_slots(fas, slot, KM_NOSLEEP); 27877c478bd9Sstevel@tonic-gate } 27887c478bd9Sstevel@tonic-gate if ((fas->f_active[slot] == NULL) || 27897c478bd9Sstevel@tonic-gate (NOTAG(Tgt(sp)) && (sp->cmd_pkt_flags & FLAG_TAGMASK))) { 27907c478bd9Sstevel@tonic-gate IPRINTF("fatal error on non-zero lun pkt\n"); 27917c478bd9Sstevel@tonic-gate return (TRAN_FATAL_ERROR); 27927c478bd9Sstevel@tonic-gate } 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate 27957c478bd9Sstevel@tonic-gate /* 27967c478bd9Sstevel@tonic-gate * we accepted the command; increment the count 27977c478bd9Sstevel@tonic-gate * (we may still reject later if TRAN_BUSY_OK) 27987c478bd9Sstevel@tonic-gate */ 27997c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 28007c478bd9Sstevel@tonic-gate fas->f_ncmds++; 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate /* 28037c478bd9Sstevel@tonic-gate * if it is a nointr packet, start it now 28047c478bd9Sstevel@tonic-gate * (NO_INTR pkts are not queued in the waitQ) 28057c478bd9Sstevel@tonic-gate */ 28067c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_NOINTR) { 28077c478bd9Sstevel@tonic-gate EPRINTF("starting a nointr cmd\n"); 28087c478bd9Sstevel@tonic-gate fas_runpoll(fas, slot, sp); 28097c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_TRANFLAG; 28107c478bd9Sstevel@tonic-gate goto done; 28117c478bd9Sstevel@tonic-gate } 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* 28147c478bd9Sstevel@tonic-gate * reset the throttle if we were draining 28157c478bd9Sstevel@tonic-gate */ 28167c478bd9Sstevel@tonic-gate if ((fas->f_tcmds[slot] == 0) && 28177c478bd9Sstevel@tonic-gate (fas->f_throttle[slot] == DRAIN_THROTTLE)) { 28187c478bd9Sstevel@tonic-gate DPRINTF("reset throttle\n"); 28197c478bd9Sstevel@tonic-gate ASSERT(fas->f_reset_delay[Tgt(sp)] == 0); 28207c478bd9Sstevel@tonic-gate fas_full_throttle(fas, slot); 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate /* 28247c478bd9Sstevel@tonic-gate * accept the command: 28257c478bd9Sstevel@tonic-gate * If no readyQ and no bus free, and throttle is OK, 28267c478bd9Sstevel@tonic-gate * run cmd immediately. 28277c478bd9Sstevel@tonic-gate */ 28287c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 28297c478bd9Sstevel@tonic-gate fas->f_total_cmds++; 28307c478bd9Sstevel@tonic-gate #endif 28317c478bd9Sstevel@tonic-gate 28327c478bd9Sstevel@tonic-gate if ((fas->f_readyf[slot] == NULL) && (fas->f_state == STATE_FREE) && 28337c478bd9Sstevel@tonic-gate (fas->f_throttle[slot] > fas->f_tcmds[slot])) { 28347c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp == 0); 28357c478bd9Sstevel@tonic-gate (void) fas_startcmd(fas, sp); 28367c478bd9Sstevel@tonic-gate goto exit; 28377c478bd9Sstevel@tonic-gate } else { 28387c478bd9Sstevel@tonic-gate /* 28397c478bd9Sstevel@tonic-gate * If FLAG_HEAD is set, run cmd if target and bus are 28407c478bd9Sstevel@tonic-gate * available. if first cmd in ready Q is request sense 28417c478bd9Sstevel@tonic-gate * then insert after this command, there shouldn't be more 28427c478bd9Sstevel@tonic-gate * than one request sense. 28437c478bd9Sstevel@tonic-gate */ 28447c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_HEAD) { 28457c478bd9Sstevel@tonic-gate struct fas_cmd *ssp = fas->f_readyf[slot]; 28467c478bd9Sstevel@tonic-gate EPRINTF("que head\n"); 28477c478bd9Sstevel@tonic-gate if (ssp && 28487c478bd9Sstevel@tonic-gate *(ssp->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE) { 28497c478bd9Sstevel@tonic-gate fas_head_of_readyQ(fas, sp); 28507c478bd9Sstevel@tonic-gate } else if (ssp) { 28517c478bd9Sstevel@tonic-gate struct fas_cmd *dp = ssp->cmd_forw; 28527c478bd9Sstevel@tonic-gate ssp->cmd_forw = sp; 28537c478bd9Sstevel@tonic-gate sp->cmd_forw = dp; 28547c478bd9Sstevel@tonic-gate if (fas->f_readyb[slot] == ssp) { 28557c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = sp; 28567c478bd9Sstevel@tonic-gate } 28577c478bd9Sstevel@tonic-gate } else { 28587c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = fas->f_readyb[slot] = sp; 28597c478bd9Sstevel@tonic-gate sp->cmd_forw = NULL; 28607c478bd9Sstevel@tonic-gate } 28617c478bd9Sstevel@tonic-gate 28627c478bd9Sstevel@tonic-gate /* 28637c478bd9Sstevel@tonic-gate * for tagged targets, check for qfull condition and 28647c478bd9Sstevel@tonic-gate * return TRAN_BUSY (if permitted), if throttle has been 28657c478bd9Sstevel@tonic-gate * exceeded 28667c478bd9Sstevel@tonic-gate */ 28677c478bd9Sstevel@tonic-gate } else if (TAGGED(Tgt(sp)) && 28687c478bd9Sstevel@tonic-gate (fas->f_tcmds[slot] >= fas->f_throttle[slot]) && 28697c478bd9Sstevel@tonic-gate (fas->f_throttle[slot] > HOLD_THROTTLE) && 28707c478bd9Sstevel@tonic-gate (flag == TRAN_BUSY_OK)) { 28717c478bd9Sstevel@tonic-gate IPRINTF2( 28727c478bd9Sstevel@tonic-gate "transport busy, slot=%x, ncmds=%x\n", 28737c478bd9Sstevel@tonic-gate slot, fas->f_ncmds); 28747c478bd9Sstevel@tonic-gate rval = TRAN_BUSY; 28757c478bd9Sstevel@tonic-gate fas->f_ncmds--; 28767c478bd9Sstevel@tonic-gate sp->cmd_flags &= 28777c478bd9Sstevel@tonic-gate ~(CFLAG_PREPARED | CFLAG_IN_TRANSPORT); 28787c478bd9Sstevel@tonic-gate goto done; 28797c478bd9Sstevel@tonic-gate /* 28807c478bd9Sstevel@tonic-gate * append to readyQ or start a new readyQ 28817c478bd9Sstevel@tonic-gate */ 28827c478bd9Sstevel@tonic-gate } else if (fas->f_readyf[slot]) { 28837c478bd9Sstevel@tonic-gate struct fas_cmd *dp = fas->f_readyb[slot]; 28847c478bd9Sstevel@tonic-gate ASSERT(dp != 0); 28857c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = sp; 28867c478bd9Sstevel@tonic-gate sp->cmd_forw = NULL; 28877c478bd9Sstevel@tonic-gate dp->cmd_forw = sp; 28887c478bd9Sstevel@tonic-gate } else { 28897c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = fas->f_readyb[slot] = sp; 28907c478bd9Sstevel@tonic-gate sp->cmd_forw = NULL; 28917c478bd9Sstevel@tonic-gate } 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate } 28947c478bd9Sstevel@tonic-gate 28957c478bd9Sstevel@tonic-gate done: 28967c478bd9Sstevel@tonic-gate /* 28977c478bd9Sstevel@tonic-gate * just in case that the bus is free and we haven't 28987c478bd9Sstevel@tonic-gate * been able to restart for some reason 28997c478bd9Sstevel@tonic-gate */ 29007c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) { 29017c478bd9Sstevel@tonic-gate (void) fas_istart(fas); 29027c478bd9Sstevel@tonic-gate } 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate exit: 29057c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 29067c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 29077c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR__FAS_START_END, "fas_accept_pkt_end"); 29087c478bd9Sstevel@tonic-gate return (rval); 29097c478bd9Sstevel@tonic-gate } 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate /* 29127c478bd9Sstevel@tonic-gate * allocate a tag byte and check for tag aging 29137c478bd9Sstevel@tonic-gate */ 29147c478bd9Sstevel@tonic-gate static char fas_tag_lookup[] = 29157c478bd9Sstevel@tonic-gate {0, MSG_HEAD_QTAG, MSG_ORDERED_QTAG, 0, MSG_SIMPLE_QTAG}; 29167c478bd9Sstevel@tonic-gate 29177c478bd9Sstevel@tonic-gate static int 29187c478bd9Sstevel@tonic-gate fas_alloc_tag(struct fas *fas, struct fas_cmd *sp) 29197c478bd9Sstevel@tonic-gate { 29207c478bd9Sstevel@tonic-gate struct f_slots *tag_slots; 29217c478bd9Sstevel@tonic-gate int tag; 29227c478bd9Sstevel@tonic-gate short slot = sp->cmd_slot; 29237c478bd9Sstevel@tonic-gate 29247c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_ALLOC_TAG_START, "fas_alloc_tag_start"); 29257c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 29267c478bd9Sstevel@tonic-gate 29277c478bd9Sstevel@tonic-gate tag_slots = fas->f_active[slot]; 29287c478bd9Sstevel@tonic-gate ASSERT(tag_slots->f_n_slots == NTAGS); 29297c478bd9Sstevel@tonic-gate 29307c478bd9Sstevel@tonic-gate alloc_tag: 29317c478bd9Sstevel@tonic-gate tag = (fas->f_active[slot]->f_tags)++; 29327c478bd9Sstevel@tonic-gate if (fas->f_active[slot]->f_tags >= NTAGS) { 29337c478bd9Sstevel@tonic-gate /* 29347c478bd9Sstevel@tonic-gate * we reserve tag 0 for non-tagged cmds 29357c478bd9Sstevel@tonic-gate */ 29367c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_tags = 1; 29377c478bd9Sstevel@tonic-gate } 29387c478bd9Sstevel@tonic-gate EPRINTF1("tagged cmd, tag = %d\n", tag); 29397c478bd9Sstevel@tonic-gate 29407c478bd9Sstevel@tonic-gate /* Validate tag, should never fail. */ 29417c478bd9Sstevel@tonic-gate if (tag_slots->f_slot[tag] == 0) { 29427c478bd9Sstevel@tonic-gate /* 29437c478bd9Sstevel@tonic-gate * Store assigned tag and tag queue type. 29447c478bd9Sstevel@tonic-gate * Note, in case of multiple choice, default to simple queue. 29457c478bd9Sstevel@tonic-gate */ 29467c478bd9Sstevel@tonic-gate ASSERT(tag < NTAGS); 29477c478bd9Sstevel@tonic-gate sp->cmd_tag[1] = (uchar_t)tag; 29487c478bd9Sstevel@tonic-gate sp->cmd_tag[0] = fas_tag_lookup[((sp->cmd_pkt_flags & 29497c478bd9Sstevel@tonic-gate FLAG_TAGMASK) >> 12)]; 29507c478bd9Sstevel@tonic-gate EPRINTF1("tag= %d\n", tag); 29517c478bd9Sstevel@tonic-gate tag_slots->f_slot[tag] = sp; 29527c478bd9Sstevel@tonic-gate (fas->f_tcmds[slot])++; 29537c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 29547c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_ALLOC_TAG_END, 29557c478bd9Sstevel@tonic-gate "fas_alloc_tag_end"); 29567c478bd9Sstevel@tonic-gate return (0); 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate } else { 29597c478bd9Sstevel@tonic-gate int age, i; 29607c478bd9Sstevel@tonic-gate 29617c478bd9Sstevel@tonic-gate /* 29627c478bd9Sstevel@tonic-gate * Check tag age. If timeouts enabled and 29637c478bd9Sstevel@tonic-gate * tag age greater than 1, print warning msg. 29647c478bd9Sstevel@tonic-gate * If timeouts enabled and tag age greater than 29657c478bd9Sstevel@tonic-gate * age limit, begin draining tag que to check for 29667c478bd9Sstevel@tonic-gate * lost tag cmd. 29677c478bd9Sstevel@tonic-gate */ 29687c478bd9Sstevel@tonic-gate age = tag_slots->f_slot[tag]->cmd_age++; 29697c478bd9Sstevel@tonic-gate if (age >= fas->f_scsi_tag_age_limit && 29707c478bd9Sstevel@tonic-gate tag_slots->f_slot[tag]->cmd_pkt->pkt_time) { 29717c478bd9Sstevel@tonic-gate IPRINTF2("tag %d in use, age= %d\n", tag, age); 29727c478bd9Sstevel@tonic-gate DPRINTF("draining tag queue\n"); 29737c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[Tgt(sp)] == 0) { 29747c478bd9Sstevel@tonic-gate fas->f_throttle[slot] = DRAIN_THROTTLE; 29757c478bd9Sstevel@tonic-gate } 29767c478bd9Sstevel@tonic-gate } 29777c478bd9Sstevel@tonic-gate 29787c478bd9Sstevel@tonic-gate /* If tag in use, scan until a free one is found. */ 29797c478bd9Sstevel@tonic-gate for (i = 1; i < NTAGS; i++) { 29807c478bd9Sstevel@tonic-gate tag = fas->f_active[slot]->f_tags; 29817c478bd9Sstevel@tonic-gate if (!tag_slots->f_slot[tag]) { 29827c478bd9Sstevel@tonic-gate EPRINTF1("found free tag %d\n", tag); 29837c478bd9Sstevel@tonic-gate break; 29847c478bd9Sstevel@tonic-gate } 29857c478bd9Sstevel@tonic-gate if (++(fas->f_active[slot]->f_tags) >= NTAGS) { 29867c478bd9Sstevel@tonic-gate /* 29877c478bd9Sstevel@tonic-gate * we reserve tag 0 for non-tagged cmds 29887c478bd9Sstevel@tonic-gate */ 29897c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_tags = 1; 29907c478bd9Sstevel@tonic-gate } 29917c478bd9Sstevel@tonic-gate EPRINTF1("found in use tag %d\n", tag); 29927c478bd9Sstevel@tonic-gate } 29937c478bd9Sstevel@tonic-gate 29947c478bd9Sstevel@tonic-gate /* 29957c478bd9Sstevel@tonic-gate * If no free tags, we're in serious trouble. 29967c478bd9Sstevel@tonic-gate * the target driver submitted more than 255 29977c478bd9Sstevel@tonic-gate * requests 29987c478bd9Sstevel@tonic-gate */ 29997c478bd9Sstevel@tonic-gate if (tag_slots->f_slot[tag]) { 30007c478bd9Sstevel@tonic-gate IPRINTF1("slot %x: All tags in use!!!\n", slot); 30017c478bd9Sstevel@tonic-gate goto fail; 30027c478bd9Sstevel@tonic-gate } 30037c478bd9Sstevel@tonic-gate goto alloc_tag; 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate 30067c478bd9Sstevel@tonic-gate fail: 30077c478bd9Sstevel@tonic-gate fas_head_of_readyQ(fas, sp); 30087c478bd9Sstevel@tonic-gate 30097c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_ALLOC_TAG_END, 30107c478bd9Sstevel@tonic-gate "fas_alloc_tag_end"); 30117c478bd9Sstevel@tonic-gate return (-1); 30127c478bd9Sstevel@tonic-gate } 30137c478bd9Sstevel@tonic-gate 30147c478bd9Sstevel@tonic-gate /* 30157c478bd9Sstevel@tonic-gate * Internal Search Routine. 30167c478bd9Sstevel@tonic-gate * 30177c478bd9Sstevel@tonic-gate * Search for a command to start. 30187c478bd9Sstevel@tonic-gate */ 30197c478bd9Sstevel@tonic-gate static int 30207c478bd9Sstevel@tonic-gate fas_istart(struct fas *fas) 30217c478bd9Sstevel@tonic-gate { 30227c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_ISTART_START, 30237c478bd9Sstevel@tonic-gate "fas_istart_start"); 30247c478bd9Sstevel@tonic-gate EPRINTF("fas_istart:\n"); 30257c478bd9Sstevel@tonic-gate 30267c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE && fas->f_ncmds > fas->f_ndisc) { 30277c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 30287c478bd9Sstevel@tonic-gate } 30297c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_ISTART_END, 30307c478bd9Sstevel@tonic-gate "fas_istart_end"); 30317c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 30327c478bd9Sstevel@tonic-gate } 30337c478bd9Sstevel@tonic-gate 30347c478bd9Sstevel@tonic-gate static int 30357c478bd9Sstevel@tonic-gate fas_ustart(struct fas *fas) 30367c478bd9Sstevel@tonic-gate { 30377c478bd9Sstevel@tonic-gate struct fas_cmd *sp; 30387c478bd9Sstevel@tonic-gate short slot = fas->f_next_slot; 30397c478bd9Sstevel@tonic-gate short start_slot = slot; 30407c478bd9Sstevel@tonic-gate short dslot = fas->f_dslot; 30417c478bd9Sstevel@tonic-gate 30427c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_USTART_START, "fas_ustart_start"); 30437c478bd9Sstevel@tonic-gate EPRINTF1("fas_ustart: start_slot=%x\n", fas->f_next_slot); 30447c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp == NULL); 30457c478bd9Sstevel@tonic-gate ASSERT(dslot != 0); 30467c478bd9Sstevel@tonic-gate if (dslot == NLUNS_PER_TARGET) { 30477c478bd9Sstevel@tonic-gate ASSERT((slot % NLUNS_PER_TARGET) == 0); 30487c478bd9Sstevel@tonic-gate } 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate /* 30517c478bd9Sstevel@tonic-gate * if readyQ not empty and we are not draining, then we 30527c478bd9Sstevel@tonic-gate * can start another cmd 30537c478bd9Sstevel@tonic-gate */ 30547c478bd9Sstevel@tonic-gate do { 30557c478bd9Sstevel@tonic-gate /* 30567c478bd9Sstevel@tonic-gate * If all cmds drained from tag Q, back to full throttle and 30577c478bd9Sstevel@tonic-gate * start queueing up new cmds again. 30587c478bd9Sstevel@tonic-gate */ 30597c478bd9Sstevel@tonic-gate if (fas->f_throttle[slot] == DRAIN_THROTTLE && 30607c478bd9Sstevel@tonic-gate fas->f_tcmds[slot] == 0) { 30617c478bd9Sstevel@tonic-gate fas_full_throttle(fas, slot); 30627c478bd9Sstevel@tonic-gate } 30637c478bd9Sstevel@tonic-gate 30647c478bd9Sstevel@tonic-gate if (fas->f_readyf[slot] && 30657c478bd9Sstevel@tonic-gate (fas->f_throttle[slot] > fas->f_tcmds[slot])) { 30667c478bd9Sstevel@tonic-gate sp = fas->f_readyf[slot]; 30677c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = sp->cmd_forw; 30687c478bd9Sstevel@tonic-gate if (sp->cmd_forw == NULL) { 30697c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = NULL; 30707c478bd9Sstevel@tonic-gate } 30717c478bd9Sstevel@tonic-gate fas->f_next_slot = NEXTSLOT(slot, dslot); 30727c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_pkt_flags & FLAG_NOINTR) == 0); 30737c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_USTART_END, 30747c478bd9Sstevel@tonic-gate "fas_ustart_end"); 30757c478bd9Sstevel@tonic-gate return (fas_startcmd(fas, sp)); 30767c478bd9Sstevel@tonic-gate } else { 30777c478bd9Sstevel@tonic-gate slot = NEXTSLOT(slot, dslot); 30787c478bd9Sstevel@tonic-gate } 30797c478bd9Sstevel@tonic-gate } while (slot != start_slot); 30807c478bd9Sstevel@tonic-gate 30817c478bd9Sstevel@tonic-gate EPRINTF("fas_ustart: no cmds to start\n"); 30827c478bd9Sstevel@tonic-gate fas->f_next_slot = NEXTSLOT(slot, dslot); 30837c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_USTART_NOT_FOUND_END, 30847c478bd9Sstevel@tonic-gate "fas_ustart_end (not_found)"); 30857c478bd9Sstevel@tonic-gate return (FALSE); 30867c478bd9Sstevel@tonic-gate } 30877c478bd9Sstevel@tonic-gate 30887c478bd9Sstevel@tonic-gate /* 30897c478bd9Sstevel@tonic-gate * Start a command off 30907c478bd9Sstevel@tonic-gate */ 30917c478bd9Sstevel@tonic-gate static int 30927c478bd9Sstevel@tonic-gate fas_startcmd(struct fas *fas, struct fas_cmd *sp) 30937c478bd9Sstevel@tonic-gate { 30947c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 30957c478bd9Sstevel@tonic-gate ushort_t nstate; 30967c478bd9Sstevel@tonic-gate uchar_t cmd, target, lun; 30977c478bd9Sstevel@tonic-gate ushort_t tshift; 30987c478bd9Sstevel@tonic-gate volatile uchar_t *tp = fas->f_cmdarea; 30997c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(sp); 31007c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 31017c478bd9Sstevel@tonic-gate struct f_slots *slots = fas->f_active[slot]; 31027c478bd9Sstevel@tonic-gate int i, cdb_len; 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate #define LOAD_CMDP *(tp++) 31057c478bd9Sstevel@tonic-gate 31067c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_STARTCMD_START, "fas_startcmd_start"); 31077c478bd9Sstevel@tonic-gate 31087c478bd9Sstevel@tonic-gate EPRINTF2("fas_startcmd: sp=0x%p flags=%x\n", 31097c478bd9Sstevel@tonic-gate (void *)sp, sp->cmd_pkt_flags); 31107c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); 31117c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0); 31127c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp == NULL && fas->f_state == STATE_FREE); 31137c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_NOINTR) == 0) { 31147c478bd9Sstevel@tonic-gate ASSERT(fas->f_throttle[slot] > 0); 31157c478bd9Sstevel@tonic-gate ASSERT(fas->f_reset_delay[Tgt(sp)] == 0); 31167c478bd9Sstevel@tonic-gate } 31177c478bd9Sstevel@tonic-gate 31187c478bd9Sstevel@tonic-gate target = Tgt(sp); 31197c478bd9Sstevel@tonic-gate lun = Lun(sp); 31207c478bd9Sstevel@tonic-gate 31217c478bd9Sstevel@tonic-gate /* 31227c478bd9Sstevel@tonic-gate * if a non-tagged cmd is submitted to an active tagged target 31237c478bd9Sstevel@tonic-gate * then drain before submitting this cmd; SCSI-2 allows RQSENSE 31247c478bd9Sstevel@tonic-gate * to be untagged 31257c478bd9Sstevel@tonic-gate */ 31267c478bd9Sstevel@tonic-gate if (((sp->cmd_pkt_flags & FLAG_TAGMASK) == 0) && 31277c478bd9Sstevel@tonic-gate TAGGED(target) && fas->f_tcmds[slot] && 31287c478bd9Sstevel@tonic-gate ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) && 31297c478bd9Sstevel@tonic-gate (*(sp->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE)) { 31307c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_NOINTR) == 0) { 31317c478bd9Sstevel@tonic-gate struct fas_cmd *dp; 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate IPRINTF("untagged cmd, start draining\n"); 31347c478bd9Sstevel@tonic-gate 31357c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[Tgt(sp)] == 0) { 31367c478bd9Sstevel@tonic-gate fas->f_throttle[slot] = DRAIN_THROTTLE; 31377c478bd9Sstevel@tonic-gate } 31387c478bd9Sstevel@tonic-gate dp = fas->f_readyf[slot]; 31397c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = sp; 31407c478bd9Sstevel@tonic-gate sp->cmd_forw = dp; 31417c478bd9Sstevel@tonic-gate if (fas->f_readyb[slot] == NULL) { 31427c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = sp; 31437c478bd9Sstevel@tonic-gate } 31447c478bd9Sstevel@tonic-gate } 31457c478bd9Sstevel@tonic-gate return (FALSE); 31467c478bd9Sstevel@tonic-gate } 31477c478bd9Sstevel@tonic-gate 31487c478bd9Sstevel@tonic-gate /* 31497c478bd9Sstevel@tonic-gate * allocate a tag; if no tag available then put request back 31507c478bd9Sstevel@tonic-gate * on the ready queue and return; eventually a cmd returns and we 31517c478bd9Sstevel@tonic-gate * get going again or we timeout 31527c478bd9Sstevel@tonic-gate */ 31537c478bd9Sstevel@tonic-gate if (TAGGED(target) && (sp->cmd_pkt_flags & FLAG_TAGMASK)) { 31547c478bd9Sstevel@tonic-gate if (fas_alloc_tag(fas, sp)) { 31557c478bd9Sstevel@tonic-gate return (FALSE); 31567c478bd9Sstevel@tonic-gate } 31577c478bd9Sstevel@tonic-gate } else { 31587c478bd9Sstevel@tonic-gate /* 31597c478bd9Sstevel@tonic-gate * tag slot 0 is reserved for non-tagged cmds 31607c478bd9Sstevel@tonic-gate * and should be empty because we have drained 31617c478bd9Sstevel@tonic-gate */ 31627c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 31637c478bd9Sstevel@tonic-gate ASSERT(fas->f_active[slot]->f_slot[0] == NULL); 31647c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_slot[0] = sp; 31657c478bd9Sstevel@tonic-gate sp->cmd_tag[1] = 0; 31667c478bd9Sstevel@tonic-gate if (*(sp->cmd_pkt->pkt_cdbp) != SCMD_REQUEST_SENSE) { 31677c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] == 0); 31687c478bd9Sstevel@tonic-gate /* 31697c478bd9Sstevel@tonic-gate * don't start any other cmd until this 31707c478bd9Sstevel@tonic-gate * one is finished. The throttle is reset 31717c478bd9Sstevel@tonic-gate * later in fas_watch() 31727c478bd9Sstevel@tonic-gate */ 31737c478bd9Sstevel@tonic-gate fas->f_throttle[slot] = 1; 31747c478bd9Sstevel@tonic-gate } 31757c478bd9Sstevel@tonic-gate (fas->f_tcmds[slot])++; 31767c478bd9Sstevel@tonic-gate 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate } 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate fas->f_current_sp = sp; 31817c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 31827c478bd9Sstevel@tonic-gate tshift = 1<<target; 31837c478bd9Sstevel@tonic-gate fas->f_sdtr_sent = fas->f_wdtr_sent = 0; 31847c478bd9Sstevel@tonic-gate cdb_len = sp->cmd_actual_cdblen; 31857c478bd9Sstevel@tonic-gate 31867c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_RENEGOTIATE_WIDE_SYNC) { 31877c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, Tgt(sp)); 31887c478bd9Sstevel@tonic-gate } 31897c478bd9Sstevel@tonic-gate 31907c478bd9Sstevel@tonic-gate /* 31917c478bd9Sstevel@tonic-gate * first send identify message, with or without disconnect priv. 31927c478bd9Sstevel@tonic-gate */ 31937c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_NODISCON) { 31947c478bd9Sstevel@tonic-gate LOAD_CMDP = fas->f_last_msgout = MSG_IDENTIFY | lun; 31957c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_pkt_flags & FLAG_TAGMASK) == 0); 31967c478bd9Sstevel@tonic-gate } else { 31977c478bd9Sstevel@tonic-gate LOAD_CMDP = fas->f_last_msgout = MSG_DR_IDENTIFY | lun; 31987c478bd9Sstevel@tonic-gate } 31997c478bd9Sstevel@tonic-gate 32007c478bd9Sstevel@tonic-gate /* 32017c478bd9Sstevel@tonic-gate * normal case, tagQ and we have negotiated wide and sync 32027c478bd9Sstevel@tonic-gate * or we don't need to renegotiate because wide and sync 32037c478bd9Sstevel@tonic-gate * have been disabled 32047c478bd9Sstevel@tonic-gate * (proxy msg's don't have tag flag set) 32057c478bd9Sstevel@tonic-gate */ 32067c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_TAGMASK) && 32077c478bd9Sstevel@tonic-gate ((fas->f_wide_known | fas->f_nowide) & 32087c478bd9Sstevel@tonic-gate (fas->f_sync_known | fas->f_nosync) & tshift)) { 32097c478bd9Sstevel@tonic-gate 32107c478bd9Sstevel@tonic-gate EPRINTF("tag cmd\n"); 32117c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_pkt_flags & FLAG_NODISCON) == 0); 32127c478bd9Sstevel@tonic-gate 32137c478bd9Sstevel@tonic-gate fas->f_last_msgout = LOAD_CMDP = sp->cmd_tag[0]; 32147c478bd9Sstevel@tonic-gate LOAD_CMDP = sp->cmd_tag[1]; 32157c478bd9Sstevel@tonic-gate 32167c478bd9Sstevel@tonic-gate nstate = STATE_SELECT_NORMAL; 32177c478bd9Sstevel@tonic-gate cmd = CMD_SEL_ATN3 | CMD_DMA; 32187c478bd9Sstevel@tonic-gate 32197c478bd9Sstevel@tonic-gate /* 32207c478bd9Sstevel@tonic-gate * is this a proxy message 32217c478bd9Sstevel@tonic-gate */ 32227c478bd9Sstevel@tonic-gate } else if (sp->cmd_flags & CFLAG_CMDPROXY) { 32237c478bd9Sstevel@tonic-gate 32247c478bd9Sstevel@tonic-gate IPRINTF2("proxy cmd, len=%x, msg=%x\n", 32257c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA], 32267c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA+1]); 32277c478bd9Sstevel@tonic-gate /* 32287c478bd9Sstevel@tonic-gate * This is a proxy command. It will have 32297c478bd9Sstevel@tonic-gate * a message to send as part of post-selection 32307c478bd9Sstevel@tonic-gate * (e.g, MSG_ABORT or MSG_DEVICE_RESET) 32317c478bd9Sstevel@tonic-gate */ 32327c478bd9Sstevel@tonic-gate fas->f_omsglen = sp->cmd_cdb[FAS_PROXY_DATA]; 32337c478bd9Sstevel@tonic-gate for (i = 0; i < (uint_t)fas->f_omsglen; i++) { 32347c478bd9Sstevel@tonic-gate fas->f_cur_msgout[i] = 32357c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA+1+i]; 32367c478bd9Sstevel@tonic-gate } 32377c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] = FALSE; 32387c478bd9Sstevel@tonic-gate cdb_len = 0; 32397c478bd9Sstevel@tonic-gate cmd = CMD_SEL_STOP | CMD_DMA; 32407c478bd9Sstevel@tonic-gate nstate = STATE_SELECT_N_SENDMSG; 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate /* 32437c478bd9Sstevel@tonic-gate * always negotiate wide first and sync after wide 32447c478bd9Sstevel@tonic-gate */ 32457c478bd9Sstevel@tonic-gate } else if (((fas->f_wide_known | fas->f_nowide) & tshift) == 0) { 32467c478bd9Sstevel@tonic-gate int i = 0; 32477c478bd9Sstevel@tonic-gate 32487c478bd9Sstevel@tonic-gate /* First the tag message bytes */ 32497c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_TAGMASK) { 32507c478bd9Sstevel@tonic-gate fas->f_cur_msgout[i++] = sp->cmd_tag[0]; 32517c478bd9Sstevel@tonic-gate fas->f_cur_msgout[i++] = sp->cmd_tag[1]; 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate /* 32557c478bd9Sstevel@tonic-gate * Set up to send wide negotiating message. This is getting 32567c478bd9Sstevel@tonic-gate * a bit tricky as we dma out the identify message and 32577c478bd9Sstevel@tonic-gate * send the other messages via the fifo buffer. 32587c478bd9Sstevel@tonic-gate */ 32597c478bd9Sstevel@tonic-gate EPRINTF1("cmd with wdtr msg, tag=%x\n", sp->cmd_tag[1]); 32607c478bd9Sstevel@tonic-gate 32617c478bd9Sstevel@tonic-gate fas_make_wdtr(fas, i, target, FAS_XFER_WIDTH); 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate cdb_len = 0; 32647c478bd9Sstevel@tonic-gate nstate = STATE_SELECT_N_SENDMSG; 32657c478bd9Sstevel@tonic-gate cmd = CMD_SEL_STOP | CMD_DMA; 32667c478bd9Sstevel@tonic-gate 32677c478bd9Sstevel@tonic-gate /* 32687c478bd9Sstevel@tonic-gate * negotiate sync xfer rate 32697c478bd9Sstevel@tonic-gate */ 32707c478bd9Sstevel@tonic-gate } else if (((fas->f_sync_known | fas->f_nosync) & tshift) == 0) { 32717c478bd9Sstevel@tonic-gate int i = 0; 32727c478bd9Sstevel@tonic-gate /* 32737c478bd9Sstevel@tonic-gate * Set up to send sync negotiating message. This is getting 32747c478bd9Sstevel@tonic-gate * a bit tricky as we dma out the identify message and 32757c478bd9Sstevel@tonic-gate * send the other messages via the fifo buffer. 32767c478bd9Sstevel@tonic-gate */ 32777c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_TAGMASK) { 32787c478bd9Sstevel@tonic-gate fas->f_cur_msgout[i++] = sp->cmd_tag[0]; 32797c478bd9Sstevel@tonic-gate fas->f_cur_msgout[i++] = sp->cmd_tag[1]; 32807c478bd9Sstevel@tonic-gate } 32817c478bd9Sstevel@tonic-gate 32827c478bd9Sstevel@tonic-gate fas_make_sdtr(fas, i, target); 32837c478bd9Sstevel@tonic-gate 32847c478bd9Sstevel@tonic-gate cdb_len = 0; 32857c478bd9Sstevel@tonic-gate cmd = CMD_SEL_STOP | CMD_DMA; 32867c478bd9Sstevel@tonic-gate nstate = STATE_SELECT_N_SENDMSG; 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate /* 32897c478bd9Sstevel@tonic-gate * normal cmds, no negotiations and not a proxy and no TQ 32907c478bd9Sstevel@tonic-gate */ 32917c478bd9Sstevel@tonic-gate } else { 32927c478bd9Sstevel@tonic-gate 32937c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_pkt_flags & FLAG_TAGMASK) == 0); 32947c478bd9Sstevel@tonic-gate EPRINTF("std. cmd\n"); 32957c478bd9Sstevel@tonic-gate 32967c478bd9Sstevel@tonic-gate nstate = STATE_SELECT_NORMAL; 32977c478bd9Sstevel@tonic-gate cmd = CMD_SEL_ATN | CMD_DMA; 32987c478bd9Sstevel@tonic-gate } 32997c478bd9Sstevel@tonic-gate 33007c478bd9Sstevel@tonic-gate /* 33017c478bd9Sstevel@tonic-gate * Now load cdb (if any) 33027c478bd9Sstevel@tonic-gate */ 33037c478bd9Sstevel@tonic-gate for (i = 0; i < cdb_len; i++) { 33047c478bd9Sstevel@tonic-gate LOAD_CMDP = sp->cmd_cdbp[i]; 33057c478bd9Sstevel@tonic-gate } 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate /* 33087c478bd9Sstevel@tonic-gate * calculate total dma amount: 33097c478bd9Sstevel@tonic-gate */ 33107c478bd9Sstevel@tonic-gate fas->f_lastcount = (uintptr_t)tp - (uintptr_t)fas->f_cmdarea; 33117c478bd9Sstevel@tonic-gate 33127c478bd9Sstevel@tonic-gate /* 33137c478bd9Sstevel@tonic-gate * load target id and enable bus id encoding and 32 bit counter 33147c478bd9Sstevel@tonic-gate */ 33157c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_busid, 33167c478bd9Sstevel@tonic-gate (target & 0xf) | FAS_BUSID_ENCODID | FAS_BUSID_32BIT_COUNTER); 33177c478bd9Sstevel@tonic-gate 33187c478bd9Sstevel@tonic-gate FAS_SET_PERIOD_OFFSET_CONF3_REGS(fas, target); 33197c478bd9Sstevel@tonic-gate 33207c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 33217c478bd9Sstevel@tonic-gate 33227c478bd9Sstevel@tonic-gate FAS_DMA_READ(fas, fas->f_lastcount, 33237c478bd9Sstevel@tonic-gate fas->f_dmacookie.dmac_address, 16, cmd); 33247c478bd9Sstevel@tonic-gate 33257c478bd9Sstevel@tonic-gate New_state(fas, (int)nstate); 33267c478bd9Sstevel@tonic-gate 33277c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 33287c478bd9Sstevel@tonic-gate if (DDEBUGGING) { 33297c478bd9Sstevel@tonic-gate fas_dump_cmd(fas, sp); 33307c478bd9Sstevel@tonic-gate } 33317c478bd9Sstevel@tonic-gate #endif /* FASDEBUG */ 33327c478bd9Sstevel@tonic-gate 33337c478bd9Sstevel@tonic-gate /* 33347c478bd9Sstevel@tonic-gate * if timeout == 0, then it has no effect on the timeout 33357c478bd9Sstevel@tonic-gate * handling; we deal with this when an actual timeout occurs. 33367c478bd9Sstevel@tonic-gate */ 33377c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 33387c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] >= 1); 33397c478bd9Sstevel@tonic-gate } 33407c478bd9Sstevel@tonic-gate i = pkt->pkt_time - slots->f_timebase; 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate if (i == 0) { 33437c478bd9Sstevel@tonic-gate EPRINTF("dup timeout\n"); 33447c478bd9Sstevel@tonic-gate (slots->f_dups)++; 33457c478bd9Sstevel@tonic-gate slots->f_timeout = slots->f_timebase; 33467c478bd9Sstevel@tonic-gate } else if (i > 0) { 33477c478bd9Sstevel@tonic-gate EPRINTF("new timeout\n"); 33487c478bd9Sstevel@tonic-gate slots->f_timeout = slots->f_timebase = pkt->pkt_time; 33497c478bd9Sstevel@tonic-gate slots->f_dups = 1; 33507c478bd9Sstevel@tonic-gate } 33517c478bd9Sstevel@tonic-gate 33527c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 33537c478bd9Sstevel@tonic-gate 33547c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_STARTCMD_END, "fas_startcmd_end"); 33557c478bd9Sstevel@tonic-gate 33567c478bd9Sstevel@tonic-gate return (TRUE); 33577c478bd9Sstevel@tonic-gate } 33587c478bd9Sstevel@tonic-gate 33597c478bd9Sstevel@tonic-gate /* 33607c478bd9Sstevel@tonic-gate * Interrupt Entry Point. 33617c478bd9Sstevel@tonic-gate * Poll interrupts until they go away 33627c478bd9Sstevel@tonic-gate */ 33637c478bd9Sstevel@tonic-gate static uint_t 33647c478bd9Sstevel@tonic-gate fas_intr(caddr_t arg) 33657c478bd9Sstevel@tonic-gate { 33667c478bd9Sstevel@tonic-gate struct fas *fas = (struct fas *)arg; 33677c478bd9Sstevel@tonic-gate int rval = DDI_INTR_UNCLAIMED; 33687c478bd9Sstevel@tonic-gate int kstat_updated = 0; 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_POLL_START, "fas_intr_start"); 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate do { 33737c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 33747c478bd9Sstevel@tonic-gate 33757c478bd9Sstevel@tonic-gate do { 33767c478bd9Sstevel@tonic-gate if (fas_intr_svc(fas)) { 33777c478bd9Sstevel@tonic-gate /* 33787c478bd9Sstevel@tonic-gate * do not return immediately here because 33797c478bd9Sstevel@tonic-gate * we have to guarantee to always empty 33807c478bd9Sstevel@tonic-gate * the waitQ and callbackQ in the interrupt 33817c478bd9Sstevel@tonic-gate * handler 33827c478bd9Sstevel@tonic-gate */ 33837c478bd9Sstevel@tonic-gate if (fas->f_polled_intr) { 33847c478bd9Sstevel@tonic-gate rval = DDI_INTR_CLAIMED; 33857c478bd9Sstevel@tonic-gate fas->f_polled_intr = 0; 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate } else { 33887c478bd9Sstevel@tonic-gate rval = DDI_INTR_CLAIMED; 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate } while (INTPENDING(fas)); 33917c478bd9Sstevel@tonic-gate 33927c478bd9Sstevel@tonic-gate if (!kstat_updated && fas->f_intr_kstat && 33937c478bd9Sstevel@tonic-gate rval == DDI_INTR_CLAIMED) { 33947c478bd9Sstevel@tonic-gate FAS_KSTAT_INTR(fas); 33957c478bd9Sstevel@tonic-gate kstat_updated++; 33967c478bd9Sstevel@tonic-gate } 33977c478bd9Sstevel@tonic-gate 33987c478bd9Sstevel@tonic-gate /* 33997c478bd9Sstevel@tonic-gate * check and empty the waitQ and the callbackQ 34007c478bd9Sstevel@tonic-gate */ 34017c478bd9Sstevel@tonic-gate FAS_CHECK_WAITQ_AND_FAS_MUTEX_EXIT(fas); 34027c478bd9Sstevel@tonic-gate FAS_EMPTY_CALLBACKQ(fas); 34037c478bd9Sstevel@tonic-gate 34047c478bd9Sstevel@tonic-gate } while (INTPENDING(fas)); 34057c478bd9Sstevel@tonic-gate 34067c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_POLL_END, "fas_intr_end"); 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate return (rval); 34097c478bd9Sstevel@tonic-gate } 34107c478bd9Sstevel@tonic-gate 34117c478bd9Sstevel@tonic-gate /* 34127c478bd9Sstevel@tonic-gate * General interrupt service routine. 34137c478bd9Sstevel@tonic-gate */ 34147c478bd9Sstevel@tonic-gate static char *dma_bits = DMA_BITS; 34157c478bd9Sstevel@tonic-gate 34167c478bd9Sstevel@tonic-gate static int 34177c478bd9Sstevel@tonic-gate fas_intr_svc(struct fas *fas) 34187c478bd9Sstevel@tonic-gate { 34197c478bd9Sstevel@tonic-gate static int (*evec[])(struct fas *fas) = { 34207c478bd9Sstevel@tonic-gate fas_finish_select, 34217c478bd9Sstevel@tonic-gate fas_reconnect, 34227c478bd9Sstevel@tonic-gate fas_phasemanage, 34237c478bd9Sstevel@tonic-gate fas_finish, 34247c478bd9Sstevel@tonic-gate fas_reset_recovery, 34257c478bd9Sstevel@tonic-gate fas_istart, 34267c478bd9Sstevel@tonic-gate fas_abort_curcmd, 34277c478bd9Sstevel@tonic-gate fas_reset_bus, 34287c478bd9Sstevel@tonic-gate fas_reset_bus, 34297c478bd9Sstevel@tonic-gate fas_handle_selection 34307c478bd9Sstevel@tonic-gate }; 34317c478bd9Sstevel@tonic-gate int action; 34327c478bd9Sstevel@tonic-gate uchar_t intr, stat; 34337c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 34347c478bd9Sstevel@tonic-gate int i = 0; 34357c478bd9Sstevel@tonic-gate 34367c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FASSVC_START, "fas_intr_svc_start"); 34377c478bd9Sstevel@tonic-gate 34387c478bd9Sstevel@tonic-gate /* 34397c478bd9Sstevel@tonic-gate * A read of FAS interrupt register clears interrupt, 34407c478bd9Sstevel@tonic-gate * so any other volatile information needs to be latched 34417c478bd9Sstevel@tonic-gate * up prior to reading the interrupt register. 34427c478bd9Sstevel@tonic-gate */ 34437c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, &fasreg->fas_stat); 34447c478bd9Sstevel@tonic-gate 34457c478bd9Sstevel@tonic-gate EPRINTF2("fas_intr_svc: state=%x stat=%x\n", fas->f_state, 34467c478bd9Sstevel@tonic-gate fas->f_stat); 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate /* 34497c478bd9Sstevel@tonic-gate * this wasn't our interrupt? 34507c478bd9Sstevel@tonic-gate */ 34517c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_STAT_IPEND) == 0) { 34527c478bd9Sstevel@tonic-gate if (fas_check_dma_error(fas)) { 34537c478bd9Sstevel@tonic-gate action = ACTION_RESET; 34547c478bd9Sstevel@tonic-gate goto start_action; 34557c478bd9Sstevel@tonic-gate } 34567c478bd9Sstevel@tonic-gate return (-1); 34577c478bd9Sstevel@tonic-gate } 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate /* 34607c478bd9Sstevel@tonic-gate * if we are reset state, handle this first 34617c478bd9Sstevel@tonic-gate */ 34627c478bd9Sstevel@tonic-gate if (fas->f_state == ACTS_RESET) { 34637c478bd9Sstevel@tonic-gate action = ACTION_FINRST; 34647c478bd9Sstevel@tonic-gate goto start_action; 34657c478bd9Sstevel@tonic-gate } 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate /* 34687c478bd9Sstevel@tonic-gate * check for gross error. fas366 hardware seems to register 34697c478bd9Sstevel@tonic-gate * the gross error bit when a parity error is found. Make sure 34707c478bd9Sstevel@tonic-gate * to ignore the gross error bit when a parity error is detected. 34717c478bd9Sstevel@tonic-gate */ 34727c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_STAT_GERR) && 34737c478bd9Sstevel@tonic-gate (fas->f_stat & FAS_STAT_PERR) == 0) { 34747c478bd9Sstevel@tonic-gate action = fas_handle_gross_err(fas); 34757c478bd9Sstevel@tonic-gate goto start_action; 34767c478bd9Sstevel@tonic-gate } 34777c478bd9Sstevel@tonic-gate 34787c478bd9Sstevel@tonic-gate /* 34797c478bd9Sstevel@tonic-gate * now it is finally safe to read the interrupt register 34807c478bd9Sstevel@tonic-gate * if we haven't done so yet 34817c478bd9Sstevel@tonic-gate * Note: we don't read step register here but only in 34827c478bd9Sstevel@tonic-gate * fas_finish_select(). It is not entirely safe but saves 34837c478bd9Sstevel@tonic-gate * redundant PIOs or extra code in this critical path 34847c478bd9Sstevel@tonic-gate */ 34857c478bd9Sstevel@tonic-gate fas->f_intr = 34867c478bd9Sstevel@tonic-gate intr = fas_reg_read(fas, (uchar_t *)&fasreg->fas_intr); 34877c478bd9Sstevel@tonic-gate 34887c478bd9Sstevel@tonic-gate /* 34897c478bd9Sstevel@tonic-gate * read the fifo if there is something there or still in the 34907c478bd9Sstevel@tonic-gate * input shuttle 34917c478bd9Sstevel@tonic-gate */ 34927c478bd9Sstevel@tonic-gate stat = fas->f_stat & FAS_PHASE_MASK; 34937c478bd9Sstevel@tonic-gate 34947c478bd9Sstevel@tonic-gate if ((intr & FAS_INT_RESEL) || 34957c478bd9Sstevel@tonic-gate ((stat != FAS_PHASE_DATA_IN) && (stat != FAS_PHASE_DATA_OUT) && 34967c478bd9Sstevel@tonic-gate ((fas->f_state & STATE_SELECTING) == 0) && 34977c478bd9Sstevel@tonic-gate (fas->f_state != ACTS_DATA_DONE) && 34987c478bd9Sstevel@tonic-gate (fas->f_state != ACTS_C_CMPLT))) { 34997c478bd9Sstevel@tonic-gate 35007c478bd9Sstevel@tonic-gate fas->f_stat2 = fas_reg_read(fas, &fasreg->fas_stat2); 35017c478bd9Sstevel@tonic-gate 35027c478bd9Sstevel@tonic-gate if (((fas->f_stat2 & FAS_STAT2_EMPTY) == 0) || 35037c478bd9Sstevel@tonic-gate (fas->f_stat2 & FAS_STAT2_ISHUTTLE)) { 35047c478bd9Sstevel@tonic-gate fas_read_fifo(fas); 35057c478bd9Sstevel@tonic-gate } 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate 35087c478bd9Sstevel@tonic-gate EPRINTF2("fas_intr_svc: intr=%x, stat=%x\n", fas->f_intr, fas->f_stat); 35097c478bd9Sstevel@tonic-gate EPRINTF2("dmacsr=%b\n", fas->f_dma->dma_csr, dma_bits); 35107c478bd9Sstevel@tonic-gate 35117c478bd9Sstevel@tonic-gate /* 35127c478bd9Sstevel@tonic-gate * Based upon the current state of the host adapter driver 35137c478bd9Sstevel@tonic-gate * we should be able to figure out what to do with an interrupt. 35147c478bd9Sstevel@tonic-gate * 35157c478bd9Sstevel@tonic-gate * The FAS asserts an interrupt with one or more of 8 possible 35167c478bd9Sstevel@tonic-gate * bits set in its interrupt register. These conditions are 35177c478bd9Sstevel@tonic-gate * SCSI bus reset detected, an illegal command fed to the FAS, 35187c478bd9Sstevel@tonic-gate * one of DISCONNECT, BUS SERVICE, FUNCTION COMPLETE conditions 35197c478bd9Sstevel@tonic-gate * for the FAS, a Reselection interrupt, or one of Selection 35207c478bd9Sstevel@tonic-gate * or Selection with Attention. 35217c478bd9Sstevel@tonic-gate * 35227c478bd9Sstevel@tonic-gate * Of these possible interrupts, we can deal with some right 35237c478bd9Sstevel@tonic-gate * here and now, irrespective of the current state of the driver. 35247c478bd9Sstevel@tonic-gate * 35257c478bd9Sstevel@tonic-gate * take care of the most likely interrupts first and call the action 35267c478bd9Sstevel@tonic-gate * immediately 35277c478bd9Sstevel@tonic-gate */ 35287c478bd9Sstevel@tonic-gate if ((intr & (FAS_INT_RESET|FAS_INT_ILLEGAL|FAS_INT_SEL|FAS_INT_SELATN| 35297c478bd9Sstevel@tonic-gate FAS_INT_RESEL)) == 0) { 35307c478bd9Sstevel@tonic-gate /* 35317c478bd9Sstevel@tonic-gate * The rest of the reasons for an interrupt can 35327c478bd9Sstevel@tonic-gate * be handled based purely on the state that the driver 35337c478bd9Sstevel@tonic-gate * is currently in now. 35347c478bd9Sstevel@tonic-gate */ 35357c478bd9Sstevel@tonic-gate if (fas->f_state & STATE_SELECTING) { 35367c478bd9Sstevel@tonic-gate action = fas_finish_select(fas); 35377c478bd9Sstevel@tonic-gate 35387c478bd9Sstevel@tonic-gate } else if (fas->f_state & STATE_ITPHASES) { 35397c478bd9Sstevel@tonic-gate action = fas_phasemanage(fas); 35407c478bd9Sstevel@tonic-gate 35417c478bd9Sstevel@tonic-gate } else { 35427c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "spurious interrupt"); 35437c478bd9Sstevel@tonic-gate action = ACTION_RETURN; 35447c478bd9Sstevel@tonic-gate } 35457c478bd9Sstevel@tonic-gate 35467c478bd9Sstevel@tonic-gate } else if ((intr & FAS_INT_RESEL) && ((intr & 35477c478bd9Sstevel@tonic-gate (FAS_INT_RESET|FAS_INT_ILLEGAL|FAS_INT_SEL|FAS_INT_SELATN)) == 0)) { 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate if ((fas->f_state & STATE_SELECTING) == 0) { 35507c478bd9Sstevel@tonic-gate ASSERT(fas->f_state == STATE_FREE); 35517c478bd9Sstevel@tonic-gate action = fas_reconnect(fas); 35527c478bd9Sstevel@tonic-gate } else { 35537c478bd9Sstevel@tonic-gate action = fas_reselect_preempt(fas); 35547c478bd9Sstevel@tonic-gate } 35557c478bd9Sstevel@tonic-gate 35567c478bd9Sstevel@tonic-gate } else if (intr & (FAS_INT_RESET | FAS_INT_ILLEGAL)) { 35577c478bd9Sstevel@tonic-gate action = fas_illegal_cmd_or_bus_reset(fas); 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate } else if (intr & (FAS_INT_SEL|FAS_INT_SELATN)) { 35607c478bd9Sstevel@tonic-gate action = ACTION_SELECT; 35617c478bd9Sstevel@tonic-gate } 35627c478bd9Sstevel@tonic-gate 35637c478bd9Sstevel@tonic-gate start_action: 35647c478bd9Sstevel@tonic-gate while (action != ACTION_RETURN) { 35657c478bd9Sstevel@tonic-gate ASSERT((action >= 0) && (action <= ACTION_SELECT)); 35667c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_SCSI_FAS, TR_FASSVC_ACTION_CALL, 35677c478bd9Sstevel@tonic-gate "fas_intr_svc call: fas 0x%p, action %d (%d)", 35687c478bd9Sstevel@tonic-gate fas, action, i); 35697c478bd9Sstevel@tonic-gate i++; 35707c478bd9Sstevel@tonic-gate action = (*evec[action])(fas); 35717c478bd9Sstevel@tonic-gate } 35727c478bd9Sstevel@tonic-gate exit: 35737c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FASSVC_END, "fas_intr_svc_end"); 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate return (0); 35767c478bd9Sstevel@tonic-gate } 35777c478bd9Sstevel@tonic-gate 35787c478bd9Sstevel@tonic-gate /* 35797c478bd9Sstevel@tonic-gate * Manage phase transitions. 35807c478bd9Sstevel@tonic-gate */ 35817c478bd9Sstevel@tonic-gate static int 35827c478bd9Sstevel@tonic-gate fas_phasemanage(struct fas *fas) 35837c478bd9Sstevel@tonic-gate { 35847c478bd9Sstevel@tonic-gate ushort_t state; 35857c478bd9Sstevel@tonic-gate int action; 35867c478bd9Sstevel@tonic-gate static int (*pvecs[])(struct fas *fas) = { 35877c478bd9Sstevel@tonic-gate fas_handle_cmd_start, 35887c478bd9Sstevel@tonic-gate fas_handle_cmd_done, 35897c478bd9Sstevel@tonic-gate fas_handle_msg_out_start, 35907c478bd9Sstevel@tonic-gate fas_handle_msg_out_done, 35917c478bd9Sstevel@tonic-gate fas_handle_msg_in_start, 35927c478bd9Sstevel@tonic-gate fas_handle_more_msgin, 35937c478bd9Sstevel@tonic-gate fas_handle_msg_in_done, 35947c478bd9Sstevel@tonic-gate fas_handle_clearing, 35957c478bd9Sstevel@tonic-gate fas_handle_data_start, 35967c478bd9Sstevel@tonic-gate fas_handle_data_done, 35977c478bd9Sstevel@tonic-gate fas_handle_c_cmplt, 35987c478bd9Sstevel@tonic-gate fas_reconnect, 35997c478bd9Sstevel@tonic-gate fas_handle_unknown, 36007c478bd9Sstevel@tonic-gate fas_reset_recovery 36017c478bd9Sstevel@tonic-gate }; 36027c478bd9Sstevel@tonic-gate int i = 0; 36037c478bd9Sstevel@tonic-gate 36047c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_PHASEMANAGE_START, 36057c478bd9Sstevel@tonic-gate "fas_phasemanage_start"); 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate do { 36087c478bd9Sstevel@tonic-gate EPRINTF1("fas_phasemanage: %s\n", 36097c478bd9Sstevel@tonic-gate fas_state_name(fas->f_state & STATE_ITPHASES)); 36107c478bd9Sstevel@tonic-gate 36117c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_SCSI_FAS, TR_FAS_PHASEMANAGE_CALL, 36127c478bd9Sstevel@tonic-gate "fas_phasemanage_call: fas 0x%p (%d)", fas, i++); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate state = fas->f_state; 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate if (!(state == STATE_FREE || state > ACTS_ENDVEC)) { 36177c478bd9Sstevel@tonic-gate ASSERT(pvecs[state-1] != NULL); 36187c478bd9Sstevel@tonic-gate action = (*pvecs[state-1]) (fas); 36197c478bd9Sstevel@tonic-gate } else { 36207c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "lost state in phasemanage"); 36217c478bd9Sstevel@tonic-gate action = ACTION_ABORT_ALLCMDS; 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate } while (action == ACTION_PHASEMANAGE); 36257c478bd9Sstevel@tonic-gate 36267c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_PHASEMANAGE_END, 36277c478bd9Sstevel@tonic-gate "fas_phasemanage_end"); 36287c478bd9Sstevel@tonic-gate return (action); 36297c478bd9Sstevel@tonic-gate } 36307c478bd9Sstevel@tonic-gate 36317c478bd9Sstevel@tonic-gate /* 36327c478bd9Sstevel@tonic-gate * remove a cmd from active list and if timeout flag is set, then 36337c478bd9Sstevel@tonic-gate * adjust timeouts; if a the same cmd will be resubmitted soon, don't 36347c478bd9Sstevel@tonic-gate * bother to adjust timeouts (ie. don't set this flag) 36357c478bd9Sstevel@tonic-gate */ 36367c478bd9Sstevel@tonic-gate static void 36377c478bd9Sstevel@tonic-gate fas_remove_cmd(struct fas *fas, struct fas_cmd *sp, int new_timeout_flag) 36387c478bd9Sstevel@tonic-gate { 36397c478bd9Sstevel@tonic-gate int tag = sp->cmd_tag[1]; 36407c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 36417c478bd9Sstevel@tonic-gate struct f_slots *tag_slots = fas->f_active[slot]; 36427c478bd9Sstevel@tonic-gate 36437c478bd9Sstevel@tonic-gate ASSERT(sp != NULL); 36447c478bd9Sstevel@tonic-gate EPRINTF4("remove tag %d slot %d for target %d.%d\n", 36457c478bd9Sstevel@tonic-gate tag, slot, Tgt(sp), Lun(sp)); 36467c478bd9Sstevel@tonic-gate 36477c478bd9Sstevel@tonic-gate if (sp == tag_slots->f_slot[tag]) { 36487c478bd9Sstevel@tonic-gate tag_slots->f_slot[tag] = NULL; 36497c478bd9Sstevel@tonic-gate fas->f_tcmds[slot]--; 36507c478bd9Sstevel@tonic-gate } 36517c478bd9Sstevel@tonic-gate if (fas->f_current_sp == sp) { 36527c478bd9Sstevel@tonic-gate fas->f_current_sp = NULL; 36537c478bd9Sstevel@tonic-gate } 36547c478bd9Sstevel@tonic-gate 36557c478bd9Sstevel@tonic-gate ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]); 36567c478bd9Sstevel@tonic-gate 36577c478bd9Sstevel@tonic-gate if (new_timeout_flag != NEW_TIMEOUT) { 36587c478bd9Sstevel@tonic-gate return; 36597c478bd9Sstevel@tonic-gate } 36607c478bd9Sstevel@tonic-gate 36617c478bd9Sstevel@tonic-gate /* 36627c478bd9Sstevel@tonic-gate * Figure out what to set tag Q timeout for... 36637c478bd9Sstevel@tonic-gate * 36647c478bd9Sstevel@tonic-gate * Optimize: If we have duplicate's of same timeout 36657c478bd9Sstevel@tonic-gate * we're using, then we'll use it again until we run 36667c478bd9Sstevel@tonic-gate * out of duplicates. This should be the normal case 36677c478bd9Sstevel@tonic-gate * for block and raw I/O. 36687c478bd9Sstevel@tonic-gate * If no duplicates, we have to scan through tag que and 36697c478bd9Sstevel@tonic-gate * find the longest timeout value and use it. This is 36707c478bd9Sstevel@tonic-gate * going to take a while... 36717c478bd9Sstevel@tonic-gate */ 36727c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_time == tag_slots->f_timebase) { 36737c478bd9Sstevel@tonic-gate if (--(tag_slots->f_dups) <= 0) { 36747c478bd9Sstevel@tonic-gate if (fas->f_tcmds[slot]) { 36757c478bd9Sstevel@tonic-gate struct fas_cmd *ssp; 36767c478bd9Sstevel@tonic-gate uint_t n = 0; 36777c478bd9Sstevel@tonic-gate ushort_t t = tag_slots->f_n_slots; 36787c478bd9Sstevel@tonic-gate ushort_t i; 36797c478bd9Sstevel@tonic-gate /* 36807c478bd9Sstevel@tonic-gate * This crude check assumes we don't do 36817c478bd9Sstevel@tonic-gate * this too often which seems reasonable 36827c478bd9Sstevel@tonic-gate * for block and raw I/O. 36837c478bd9Sstevel@tonic-gate */ 36847c478bd9Sstevel@tonic-gate for (i = 0; i < t; i++) { 36857c478bd9Sstevel@tonic-gate ssp = tag_slots->f_slot[i]; 36867c478bd9Sstevel@tonic-gate if (ssp && 36877c478bd9Sstevel@tonic-gate (ssp->cmd_pkt->pkt_time > n)) { 36887c478bd9Sstevel@tonic-gate n = ssp->cmd_pkt->pkt_time; 36897c478bd9Sstevel@tonic-gate tag_slots->f_dups = 1; 36907c478bd9Sstevel@tonic-gate } else if (ssp && 36917c478bd9Sstevel@tonic-gate (ssp->cmd_pkt->pkt_time == n)) { 36927c478bd9Sstevel@tonic-gate tag_slots->f_dups++; 36937c478bd9Sstevel@tonic-gate } 36947c478bd9Sstevel@tonic-gate } 36957c478bd9Sstevel@tonic-gate tag_slots->f_timebase = n; 36967c478bd9Sstevel@tonic-gate EPRINTF1("searching, new_timeout= %d\n", n); 36977c478bd9Sstevel@tonic-gate } else { 36987c478bd9Sstevel@tonic-gate tag_slots->f_dups = 0; 36997c478bd9Sstevel@tonic-gate tag_slots->f_timebase = 0; 37007c478bd9Sstevel@tonic-gate } 37017c478bd9Sstevel@tonic-gate } 37027c478bd9Sstevel@tonic-gate } 37037c478bd9Sstevel@tonic-gate tag_slots->f_timeout = tag_slots->f_timebase; 37047c478bd9Sstevel@tonic-gate 37057c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 37067c478bd9Sstevel@tonic-gate } 37077c478bd9Sstevel@tonic-gate 37087c478bd9Sstevel@tonic-gate /* 37097c478bd9Sstevel@tonic-gate * decrement f_ncmds and f_ndisc for this cmd before completing 37107c478bd9Sstevel@tonic-gate */ 37117c478bd9Sstevel@tonic-gate static void 37127c478bd9Sstevel@tonic-gate fas_decrement_ncmds(struct fas *fas, struct fas_cmd *sp) 37137c478bd9Sstevel@tonic-gate { 37147c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); 37157c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_FINISHED) == 0) { 37167c478bd9Sstevel@tonic-gate fas->f_ncmds--; 37177c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CMDDISC) { 37187c478bd9Sstevel@tonic-gate fas->f_ndisc--; 37197c478bd9Sstevel@tonic-gate } 37207c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_FINISHED; 37217c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_CMDDISC; 37227c478bd9Sstevel@tonic-gate } 37237c478bd9Sstevel@tonic-gate ASSERT((fas->f_ncmds >= 0) && (fas->f_ndisc >= 0)); 37247c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 37257c478bd9Sstevel@tonic-gate } 37267c478bd9Sstevel@tonic-gate 37277c478bd9Sstevel@tonic-gate /* 37287c478bd9Sstevel@tonic-gate * Most commonly called phase handlers: 37297c478bd9Sstevel@tonic-gate * 37307c478bd9Sstevel@tonic-gate * Finish routines 37317c478bd9Sstevel@tonic-gate */ 37327c478bd9Sstevel@tonic-gate static int 37337c478bd9Sstevel@tonic-gate fas_finish(struct fas *fas) 37347c478bd9Sstevel@tonic-gate { 37357c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 37367c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(sp); 37377c478bd9Sstevel@tonic-gate int action = ACTION_SEARCH; 37387c478bd9Sstevel@tonic-gate struct scsi_status *status = 37397c478bd9Sstevel@tonic-gate (struct scsi_status *)sp->cmd_pkt->pkt_scbp; 37407c478bd9Sstevel@tonic-gate 37417c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_START, 37427c478bd9Sstevel@tonic-gate "fas_finish_start"); 37437c478bd9Sstevel@tonic-gate EPRINTF("fas_finish\n"); 37447c478bd9Sstevel@tonic-gate 37457c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 37467c478bd9Sstevel@tonic-gate if (fas_test_stop && (sp->cmd_pkt_flags & 0x80000000)) { 37477c478bd9Sstevel@tonic-gate debug_enter("untagged cmd completed"); 37487c478bd9Sstevel@tonic-gate } 37497c478bd9Sstevel@tonic-gate #endif 37507c478bd9Sstevel@tonic-gate 37517c478bd9Sstevel@tonic-gate /* 37527c478bd9Sstevel@tonic-gate * immediately enable reselects 37537c478bd9Sstevel@tonic-gate */ 37547c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_EN_RESEL); 37557c478bd9Sstevel@tonic-gate if (status->sts_chk) { 37567c478bd9Sstevel@tonic-gate /* 37577c478bd9Sstevel@tonic-gate * In the case that we are getting a check condition 37587c478bd9Sstevel@tonic-gate * clear our knowledge of synchronous capabilities. 37597c478bd9Sstevel@tonic-gate * This will unambiguously force a renegotiation 37607c478bd9Sstevel@tonic-gate * prior to any possible data transfer (we hope), 37617c478bd9Sstevel@tonic-gate * including the data transfer for a UNIT ATTENTION 37627c478bd9Sstevel@tonic-gate * condition generated by somebody powering on and 37637c478bd9Sstevel@tonic-gate * off a target. 37647c478bd9Sstevel@tonic-gate */ 37657c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, Tgt(sp)); 37667c478bd9Sstevel@tonic-gate } 37677c478bd9Sstevel@tonic-gate 37687c478bd9Sstevel@tonic-gate /* 37697c478bd9Sstevel@tonic-gate * backoff sync/wide if there were parity errors 37707c478bd9Sstevel@tonic-gate */ 37717c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_statistics & STAT_PERR) { 37727c478bd9Sstevel@tonic-gate fas_sync_wide_backoff(fas, sp, sp->cmd_slot); 37737c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 37747c478bd9Sstevel@tonic-gate if (fas_test_stop) { 37757c478bd9Sstevel@tonic-gate debug_enter("parity error"); 37767c478bd9Sstevel@tonic-gate } 37777c478bd9Sstevel@tonic-gate #endif 37787c478bd9Sstevel@tonic-gate } 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate /* 37817c478bd9Sstevel@tonic-gate * Free from active list and update counts 37827c478bd9Sstevel@tonic-gate * We need to clean up this cmd now, just in case fas_ustart() 37837c478bd9Sstevel@tonic-gate * hits a reset or other fatal transport error 37847c478bd9Sstevel@tonic-gate */ 37857c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 37867c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 37877c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 37887c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 37897c478bd9Sstevel@tonic-gate 37907c478bd9Sstevel@tonic-gate /* 37917c478bd9Sstevel@tonic-gate * go to state free and try to start a new cmd now 37927c478bd9Sstevel@tonic-gate */ 37937c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 37947c478bd9Sstevel@tonic-gate 37957c478bd9Sstevel@tonic-gate if ((fas->f_ncmds > fas->f_ndisc) && (*((char *)status) == 0) && 37967c478bd9Sstevel@tonic-gate (INTPENDING(fas) == 0)) { 37977c478bd9Sstevel@tonic-gate if (fas_ustart(fas)) { 37987c478bd9Sstevel@tonic-gate action = ACTION_RETURN; 37997c478bd9Sstevel@tonic-gate } 38007c478bd9Sstevel@tonic-gate } 38017c478bd9Sstevel@tonic-gate 38027c478bd9Sstevel@tonic-gate /* 38037c478bd9Sstevel@tonic-gate * if there was a data xfer then calculate residue and 38047c478bd9Sstevel@tonic-gate * sync data for consistent memory xfers 38057c478bd9Sstevel@tonic-gate */ 38067c478bd9Sstevel@tonic-gate if (pkt->pkt_state & STATE_XFERRED_DATA) { 38077c478bd9Sstevel@tonic-gate pkt->pkt_resid = sp->cmd_dmacount - sp->cmd_data_count; 38087c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CMDIOPB) { 38097c478bd9Sstevel@tonic-gate (void) ddi_dma_sync(sp->cmd_dmahandle, 0, (uint_t)0, 38107c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORCPU); 38117c478bd9Sstevel@tonic-gate } 38127c478bd9Sstevel@tonic-gate if (pkt->pkt_resid) { 38137c478bd9Sstevel@tonic-gate IPRINTF3("%d.%d finishes with %ld resid\n", 38147c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp), pkt->pkt_resid); 38157c478bd9Sstevel@tonic-gate } 38167c478bd9Sstevel@tonic-gate } 38177c478bd9Sstevel@tonic-gate 38187c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_NOINTR) { 38197c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 38207c478bd9Sstevel@tonic-gate action = ACTION_RETURN; 38217c478bd9Sstevel@tonic-gate } else { 38227c478bd9Sstevel@tonic-gate /* 38237c478bd9Sstevel@tonic-gate * start an autorequest sense if there was a check condition. 38247c478bd9Sstevel@tonic-gate * if arq has not been enabled, fas_handle_sts_chk will do 38257c478bd9Sstevel@tonic-gate * do the callback 38267c478bd9Sstevel@tonic-gate */ 38277c478bd9Sstevel@tonic-gate if (status->sts_chk) { 38287c478bd9Sstevel@tonic-gate if (fas_handle_sts_chk(fas, sp)) { 38297c478bd9Sstevel@tonic-gate /* 38307c478bd9Sstevel@tonic-gate * we can't start an arq because one is 38317c478bd9Sstevel@tonic-gate * already in progress. the target is 38327c478bd9Sstevel@tonic-gate * probably confused 38337c478bd9Sstevel@tonic-gate */ 38347c478bd9Sstevel@tonic-gate action = ACTION_ABORT_CURCMD; 38357c478bd9Sstevel@tonic-gate } 38367c478bd9Sstevel@tonic-gate } else if ((*((char *)status) & STATUS_MASK) == 38377c478bd9Sstevel@tonic-gate STATUS_QFULL) { 38387c478bd9Sstevel@tonic-gate fas_handle_qfull(fas, sp); 38397c478bd9Sstevel@tonic-gate } else { 38407c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 38417c478bd9Sstevel@tonic-gate if (fas_arqs_failure && (status->sts_chk == 0)) { 38427c478bd9Sstevel@tonic-gate struct scsi_arq_status *arqstat; 38437c478bd9Sstevel@tonic-gate status->sts_chk = 1; 38447c478bd9Sstevel@tonic-gate arqstat = (struct scsi_arq_status *) 38457c478bd9Sstevel@tonic-gate (sp->cmd_pkt->pkt_scbp); 38467c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_reason = CMD_TRAN_ERR; 38477c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_ARQ_DONE; 38487c478bd9Sstevel@tonic-gate fas_arqs_failure = 0; 38497c478bd9Sstevel@tonic-gate } 38507c478bd9Sstevel@tonic-gate if (fas_tran_err) { 38517c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason = CMD_TRAN_ERR; 38527c478bd9Sstevel@tonic-gate fas_tran_err = 0; 38537c478bd9Sstevel@tonic-gate } 38547c478bd9Sstevel@tonic-gate #endif 38557c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 38567c478bd9Sstevel@tonic-gate } 38577c478bd9Sstevel@tonic-gate } 38587c478bd9Sstevel@tonic-gate 38597c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_END, "fas_finish_end"); 38607c478bd9Sstevel@tonic-gate return (action); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate 38637c478bd9Sstevel@tonic-gate /* 38647c478bd9Sstevel@tonic-gate * Complete the process of selecting a target 38657c478bd9Sstevel@tonic-gate */ 38667c478bd9Sstevel@tonic-gate static int 38677c478bd9Sstevel@tonic-gate fas_finish_select(struct fas *fas) 38687c478bd9Sstevel@tonic-gate { 38697c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; 38707c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 38717c478bd9Sstevel@tonic-gate uchar_t intr = fas->f_intr; 38727c478bd9Sstevel@tonic-gate uchar_t step; 38737c478bd9Sstevel@tonic-gate 38747c478bd9Sstevel@tonic-gate step = fas_reg_read(fas, &fas->f_reg->fas_step) & FAS_STEP_MASK; 38757c478bd9Sstevel@tonic-gate 38767c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_SELECT_START, 38777c478bd9Sstevel@tonic-gate "fas_finish_select_start"); 38787c478bd9Sstevel@tonic-gate EPRINTF("fas_finish_select:\n"); 38797c478bd9Sstevel@tonic-gate ASSERT(sp != 0); 38807c478bd9Sstevel@tonic-gate 38817c478bd9Sstevel@tonic-gate /* 38827c478bd9Sstevel@tonic-gate * Check for DMA gate array errors 38837c478bd9Sstevel@tonic-gate */ 38847c478bd9Sstevel@tonic-gate if ((fas->f_dma_csr = fas_dma_reg_read(fas, &dmar->dma_csr)) 38857c478bd9Sstevel@tonic-gate & DMA_ERRPEND) { 38867c478bd9Sstevel@tonic-gate /* 38877c478bd9Sstevel@tonic-gate * It would be desirable to set the ATN* line and attempt to 38887c478bd9Sstevel@tonic-gate * do the whole schmear of INITIATOR DETECTED ERROR here, 38897c478bd9Sstevel@tonic-gate * but that is too hard to do at present. 38907c478bd9Sstevel@tonic-gate */ 38917c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 38927c478bd9Sstevel@tonic-gate "Unrecoverable DMA error during selection"); 38937c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 38947c478bd9Sstevel@tonic-gate 38957c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_SELECT_RESET1_END, 38967c478bd9Sstevel@tonic-gate "fas_finish_select_end (ACTION_RESET1)"); 38977c478bd9Sstevel@tonic-gate return (ACTION_RESET); 38987c478bd9Sstevel@tonic-gate } 38997c478bd9Sstevel@tonic-gate 39007c478bd9Sstevel@tonic-gate /* 39017c478bd9Sstevel@tonic-gate * Shut off DMA gate array 39027c478bd9Sstevel@tonic-gate */ 39037c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(fas); 39047c478bd9Sstevel@tonic-gate 39057c478bd9Sstevel@tonic-gate /* 39067c478bd9Sstevel@tonic-gate * Did something respond to selection? 39077c478bd9Sstevel@tonic-gate */ 39087c478bd9Sstevel@tonic-gate if (intr == (FAS_INT_BUS|FAS_INT_FCMP)) { 39097c478bd9Sstevel@tonic-gate /* 39107c478bd9Sstevel@tonic-gate * We succesfully selected a target (we think). 39117c478bd9Sstevel@tonic-gate * Now we figure out how botched things are 39127c478bd9Sstevel@tonic-gate * based upon the kind of selection we were 39137c478bd9Sstevel@tonic-gate * doing and the state of the step register. 39147c478bd9Sstevel@tonic-gate */ 39157c478bd9Sstevel@tonic-gate switch (step) { 39167c478bd9Sstevel@tonic-gate case FAS_STEP_ARBSEL: 39177c478bd9Sstevel@tonic-gate /* 39187c478bd9Sstevel@tonic-gate * In this case, we selected the target, but went 39197c478bd9Sstevel@tonic-gate * neither into MESSAGE OUT nor COMMAND phase. 39207c478bd9Sstevel@tonic-gate * However, this isn't a fatal error, so we just 39217c478bd9Sstevel@tonic-gate * drive on. 39227c478bd9Sstevel@tonic-gate * 39237c478bd9Sstevel@tonic-gate * This might be a good point to note that we have 39247c478bd9Sstevel@tonic-gate * a target that appears to not accomodate 39257c478bd9Sstevel@tonic-gate * disconnecting, 39267c478bd9Sstevel@tonic-gate * but it really isn't worth the effort to distinguish 39277c478bd9Sstevel@tonic-gate * such targets fasecially from others. 39287c478bd9Sstevel@tonic-gate */ 39297c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 39307c478bd9Sstevel@tonic-gate 39317c478bd9Sstevel@tonic-gate case FAS_STEP_SENTID: 39327c478bd9Sstevel@tonic-gate /* 39337c478bd9Sstevel@tonic-gate * In this case, we selected the target and sent 39347c478bd9Sstevel@tonic-gate * message byte and have stopped with ATN* still on. 39357c478bd9Sstevel@tonic-gate * This case should only occur if we use the SELECT 39367c478bd9Sstevel@tonic-gate * AND STOP command. 39377c478bd9Sstevel@tonic-gate */ 39387c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 39397c478bd9Sstevel@tonic-gate 39407c478bd9Sstevel@tonic-gate case FAS_STEP_NOTCMD: 39417c478bd9Sstevel@tonic-gate /* 39427c478bd9Sstevel@tonic-gate * In this case, we either didn't transition to command 39437c478bd9Sstevel@tonic-gate * phase, or, 39447c478bd9Sstevel@tonic-gate * if we were using the SELECT WITH ATN3 command, 39457c478bd9Sstevel@tonic-gate * we possibly didn't send all message bytes. 39467c478bd9Sstevel@tonic-gate */ 39477c478bd9Sstevel@tonic-gate break; 39487c478bd9Sstevel@tonic-gate 39497c478bd9Sstevel@tonic-gate case FAS_STEP_PCMD: 39507c478bd9Sstevel@tonic-gate /* 39517c478bd9Sstevel@tonic-gate * In this case, not all command bytes transferred. 39527c478bd9Sstevel@tonic-gate */ 39537c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 39547c478bd9Sstevel@tonic-gate 39557c478bd9Sstevel@tonic-gate case FAS_STEP_DONE: 39567c478bd9Sstevel@tonic-gate /* 39577c478bd9Sstevel@tonic-gate * This is the usual 'good' completion point. 39587c478bd9Sstevel@tonic-gate * If we we sent message byte(s), we subtract 39597c478bd9Sstevel@tonic-gate * off the number of message bytes that were 39607c478bd9Sstevel@tonic-gate * ahead of the command. 39617c478bd9Sstevel@tonic-gate */ 39627c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_SENT_CMD; 39637c478bd9Sstevel@tonic-gate break; 39647c478bd9Sstevel@tonic-gate 39657c478bd9Sstevel@tonic-gate default: 39667c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 39677c478bd9Sstevel@tonic-gate "bad sequence step (0x%x) in selection", step); 39687c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 39697c478bd9Sstevel@tonic-gate TR_FAS_FINISH_SELECT_RESET3_END, 39707c478bd9Sstevel@tonic-gate "fas_finish_select_end (ACTION_RESET3)"); 39717c478bd9Sstevel@tonic-gate return (ACTION_RESET); 39727c478bd9Sstevel@tonic-gate } 39737c478bd9Sstevel@tonic-gate 39747c478bd9Sstevel@tonic-gate /* 39757c478bd9Sstevel@tonic-gate * OR in common state... 39767c478bd9Sstevel@tonic-gate */ 39777c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= (STATE_GOT_BUS|STATE_GOT_TARGET); 39787c478bd9Sstevel@tonic-gate 39797c478bd9Sstevel@tonic-gate /* 39807c478bd9Sstevel@tonic-gate * data pointer initialization has already been done 39817c478bd9Sstevel@tonic-gate */ 39827c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 39837c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_SELECT_ACTION3_END, 39847c478bd9Sstevel@tonic-gate "fas_finish_select_end (action3)"); 39857c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 39867c478bd9Sstevel@tonic-gate 39877c478bd9Sstevel@tonic-gate } else if (intr == FAS_INT_DISCON) { 39887c478bd9Sstevel@tonic-gate /* 39897c478bd9Sstevel@tonic-gate * make sure we negotiate when this target comes 39907c478bd9Sstevel@tonic-gate * on line later on 39917c478bd9Sstevel@tonic-gate */ 39927c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, Tgt(sp)); 39937c478bd9Sstevel@tonic-gate 39947c478bd9Sstevel@tonic-gate fas->f_sdtr_sent = fas->f_wdtr_sent = 0; 39957c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_GOT_BUS; 39967c478bd9Sstevel@tonic-gate 39977c478bd9Sstevel@tonic-gate /* 39987c478bd9Sstevel@tonic-gate * Set the throttle to DRAIN_THROTTLE to make 39997c478bd9Sstevel@tonic-gate * sure any disconnected commands will get timed out 40007c478bd9Sstevel@tonic-gate * incase the drive dies 40017c478bd9Sstevel@tonic-gate */ 40027c478bd9Sstevel@tonic-gate 40037c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[Tgt(sp)] == 0) { 40047c478bd9Sstevel@tonic-gate fas->f_throttle[sp->cmd_slot] = DRAIN_THROTTLE; 40057c478bd9Sstevel@tonic-gate } 40067c478bd9Sstevel@tonic-gate 40077c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_INCOMPLETE, 0); 40087c478bd9Sstevel@tonic-gate 40097c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_SELECT_FINISH_END, 40107c478bd9Sstevel@tonic-gate "fas_finish_select_end (ACTION_FINISH)"); 40117c478bd9Sstevel@tonic-gate return (ACTION_FINISH); 40127c478bd9Sstevel@tonic-gate } else { 40137c478bd9Sstevel@tonic-gate fas_printstate(fas, "undetermined selection failure"); 40147c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_FINISH_SELECT_RESET2_END, 40157c478bd9Sstevel@tonic-gate "fas_finish_select_end (ACTION_RESET2)"); 40167c478bd9Sstevel@tonic-gate return (ACTION_RESET); 40177c478bd9Sstevel@tonic-gate } 40187c478bd9Sstevel@tonic-gate _NOTE(NOT_REACHED) 40197c478bd9Sstevel@tonic-gate /* NOTREACHED */ 40207c478bd9Sstevel@tonic-gate } 40217c478bd9Sstevel@tonic-gate 40227c478bd9Sstevel@tonic-gate /* 40237c478bd9Sstevel@tonic-gate * a selection got preempted by a reselection; shut down dma 40247c478bd9Sstevel@tonic-gate * and put back cmd in the ready queue unless NOINTR 40257c478bd9Sstevel@tonic-gate */ 40267c478bd9Sstevel@tonic-gate static int 40277c478bd9Sstevel@tonic-gate fas_reselect_preempt(struct fas *fas) 40287c478bd9Sstevel@tonic-gate { 40297c478bd9Sstevel@tonic-gate int rval; 40307c478bd9Sstevel@tonic-gate 40317c478bd9Sstevel@tonic-gate /* 40327c478bd9Sstevel@tonic-gate * A reselection attempt glotzed our selection attempt. 40337c478bd9Sstevel@tonic-gate * we put request back in the ready queue 40347c478bd9Sstevel@tonic-gate */ 40357c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 40367c478bd9Sstevel@tonic-gate 40377c478bd9Sstevel@tonic-gate /* 40387c478bd9Sstevel@tonic-gate * Shut off DMA gate array 40397c478bd9Sstevel@tonic-gate */ 40407c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(fas); 40417c478bd9Sstevel@tonic-gate 40427c478bd9Sstevel@tonic-gate /* 40437c478bd9Sstevel@tonic-gate * service the reconnect now and clean up later 40447c478bd9Sstevel@tonic-gate */ 40457c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 40467c478bd9Sstevel@tonic-gate rval = fas_reconnect(fas); 40477c478bd9Sstevel@tonic-gate 40487c478bd9Sstevel@tonic-gate /* 40497c478bd9Sstevel@tonic-gate * If selection for a non-tagged command is preempted, the 40507c478bd9Sstevel@tonic-gate * command could be stuck because throttle was set to DRAIN, 40517c478bd9Sstevel@tonic-gate * and a disconnected command timeout follows. 40527c478bd9Sstevel@tonic-gate */ 40537c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_TAGMASK) == 0) 40547c478bd9Sstevel@tonic-gate fas->f_throttle[sp->cmd_slot] = 1; 40557c478bd9Sstevel@tonic-gate 40567c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 40577c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 40587c478bd9Sstevel@tonic-gate } 40597c478bd9Sstevel@tonic-gate 40607c478bd9Sstevel@tonic-gate /* 40617c478bd9Sstevel@tonic-gate * if we attempted to renegotiate on this cmd, undo this now 40627c478bd9Sstevel@tonic-gate */ 40637c478bd9Sstevel@tonic-gate if (fas->f_wdtr_sent) { 40647c478bd9Sstevel@tonic-gate fas->f_wide_known &= ~(1<<Tgt(sp)); 40657c478bd9Sstevel@tonic-gate fas->f_wdtr_sent = 0; 40667c478bd9Sstevel@tonic-gate } 40677c478bd9Sstevel@tonic-gate if (fas->f_sdtr_sent) { 40687c478bd9Sstevel@tonic-gate fas->f_sync_known &= ~(1<<Tgt(sp)); 40697c478bd9Sstevel@tonic-gate fas->f_sdtr_sent = 0; 40707c478bd9Sstevel@tonic-gate } 40717c478bd9Sstevel@tonic-gate 40727c478bd9Sstevel@tonic-gate fas_head_of_readyQ(fas, sp); 40737c478bd9Sstevel@tonic-gate 40747c478bd9Sstevel@tonic-gate return (rval); 40757c478bd9Sstevel@tonic-gate } 40767c478bd9Sstevel@tonic-gate 40777c478bd9Sstevel@tonic-gate /* 40787c478bd9Sstevel@tonic-gate * Handle the reconnection of a target 40797c478bd9Sstevel@tonic-gate */ 40807c478bd9Sstevel@tonic-gate static int 40817c478bd9Sstevel@tonic-gate fas_reconnect(struct fas *fas) 40827c478bd9Sstevel@tonic-gate { 40837c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 40847c478bd9Sstevel@tonic-gate struct fas_cmd *sp = NULL; 40857c478bd9Sstevel@tonic-gate uchar_t target, lun; 40867c478bd9Sstevel@tonic-gate uchar_t tmp; 40877c478bd9Sstevel@tonic-gate uchar_t slot; 40887c478bd9Sstevel@tonic-gate char *bad_reselect = NULL; 40897c478bd9Sstevel@tonic-gate 40907c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_RECONNECT_START, 40917c478bd9Sstevel@tonic-gate "fas_reconnect_start"); 40927c478bd9Sstevel@tonic-gate EPRINTF("fas_reconnect:\n"); 40937c478bd9Sstevel@tonic-gate 40947c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 40957c478bd9Sstevel@tonic-gate 40967c478bd9Sstevel@tonic-gate switch (fas->f_state) { 40977c478bd9Sstevel@tonic-gate default: 40987c478bd9Sstevel@tonic-gate /* 40997c478bd9Sstevel@tonic-gate * Pick up target id from fifo 41007c478bd9Sstevel@tonic-gate * 41017c478bd9Sstevel@tonic-gate * There should only be the reselecting target's id 41027c478bd9Sstevel@tonic-gate * and an identify message in the fifo. 41037c478bd9Sstevel@tonic-gate */ 41047c478bd9Sstevel@tonic-gate target = fas->f_fifo[0]; 41057c478bd9Sstevel@tonic-gate 41067c478bd9Sstevel@tonic-gate /* 41077c478bd9Sstevel@tonic-gate * we know the target so update period, conf3, 41087c478bd9Sstevel@tonic-gate * offset reg, if necessary, and accept the msg 41097c478bd9Sstevel@tonic-gate */ 41107c478bd9Sstevel@tonic-gate FAS_SET_PERIOD_OFFSET_CONF3_REGS(fas, target); 41117c478bd9Sstevel@tonic-gate 41127c478bd9Sstevel@tonic-gate /* 41137c478bd9Sstevel@tonic-gate * now we can accept the message. an untagged 41147c478bd9Sstevel@tonic-gate * target will go immediately into data phase so 41157c478bd9Sstevel@tonic-gate * the period/offset/conf3 registers need to be 41167c478bd9Sstevel@tonic-gate * updated before accepting the message 41177c478bd9Sstevel@tonic-gate */ 41187c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_MSG_ACPT); 41197c478bd9Sstevel@tonic-gate 41207c478bd9Sstevel@tonic-gate if (fas->f_fifolen != 2) { 41217c478bd9Sstevel@tonic-gate bad_reselect = "bad reselect bytes"; 41227c478bd9Sstevel@tonic-gate break; 41237c478bd9Sstevel@tonic-gate } 41247c478bd9Sstevel@tonic-gate 41257c478bd9Sstevel@tonic-gate /* 41267c478bd9Sstevel@tonic-gate * normal initial reconnect; we get another interrupt later 41277c478bd9Sstevel@tonic-gate * for the tag 41287c478bd9Sstevel@tonic-gate */ 41297c478bd9Sstevel@tonic-gate New_state(fas, ACTS_RESEL); 41307c478bd9Sstevel@tonic-gate 41317c478bd9Sstevel@tonic-gate if (fas->f_stat & FAS_STAT_PERR) { 41327c478bd9Sstevel@tonic-gate break; 41337c478bd9Sstevel@tonic-gate } 41347c478bd9Sstevel@tonic-gate 41357c478bd9Sstevel@tonic-gate /* 41367c478bd9Sstevel@tonic-gate * Check sanity of message. 41377c478bd9Sstevel@tonic-gate */ 41387c478bd9Sstevel@tonic-gate tmp = fas->f_fifo[1]; 41397c478bd9Sstevel@tonic-gate fas->f_last_msgin = tmp; 41407c478bd9Sstevel@tonic-gate 41417c478bd9Sstevel@tonic-gate if (!(IS_IDENTIFY_MSG(tmp)) || (tmp & INI_CAN_DISCON)) { 41427c478bd9Sstevel@tonic-gate bad_reselect = "bad identify msg"; 41437c478bd9Sstevel@tonic-gate break; 41447c478bd9Sstevel@tonic-gate } 41457c478bd9Sstevel@tonic-gate 41467c478bd9Sstevel@tonic-gate lun = tmp & (NLUNS_PER_TARGET-1); 41477c478bd9Sstevel@tonic-gate 41487c478bd9Sstevel@tonic-gate EPRINTF2("fas_reconnect: target=%x, idmsg=%x\n", 41497c478bd9Sstevel@tonic-gate target, tmp); 41507c478bd9Sstevel@tonic-gate 41517c478bd9Sstevel@tonic-gate fas->f_resel_slot = slot = (target * NLUNS_PER_TARGET) | lun; 41527c478bd9Sstevel@tonic-gate 41537c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_busid, 41547c478bd9Sstevel@tonic-gate (target & 0xf) | FAS_BUSID_ENCODID | 41557c478bd9Sstevel@tonic-gate FAS_BUSID_32BIT_COUNTER); 41567c478bd9Sstevel@tonic-gate 41577c478bd9Sstevel@tonic-gate /* 41587c478bd9Sstevel@tonic-gate * If tag queueing in use, DMA in tag. 41597c478bd9Sstevel@tonic-gate * Otherwise, we're ready to go. 41607c478bd9Sstevel@tonic-gate * if tag 0 slot is non-empty, a non-tagged cmd is 41617c478bd9Sstevel@tonic-gate * reconnecting 41627c478bd9Sstevel@tonic-gate */ 41637c478bd9Sstevel@tonic-gate if (TAGGED(target) && fas->f_tcmds[slot] && 41647c478bd9Sstevel@tonic-gate (fas->f_active[slot]->f_slot[0] == NULL)) { 41657c478bd9Sstevel@tonic-gate volatile uchar_t *c = 41667c478bd9Sstevel@tonic-gate (uchar_t *)fas->f_cmdarea; 41677c478bd9Sstevel@tonic-gate 41687c478bd9Sstevel@tonic-gate /* 41697c478bd9Sstevel@tonic-gate * If we've been doing tagged queueing and this 41707c478bd9Sstevel@tonic-gate * request doesn't do it, 41717c478bd9Sstevel@tonic-gate * maybe it was disabled for this one. This is rather 41727c478bd9Sstevel@tonic-gate * dangerous as it blows all pending tagged cmds away. 41737c478bd9Sstevel@tonic-gate * But if target is confused, then we'll blow up 41747c478bd9Sstevel@tonic-gate * shortly. 41757c478bd9Sstevel@tonic-gate */ 41767c478bd9Sstevel@tonic-gate *c++ = INVALID_MSG; 41777c478bd9Sstevel@tonic-gate *c = INVALID_MSG; 41787c478bd9Sstevel@tonic-gate 41797c478bd9Sstevel@tonic-gate FAS_DMA_WRITE_SETUP(fas, 2, 41807c478bd9Sstevel@tonic-gate fas->f_dmacookie.dmac_address); 41817c478bd9Sstevel@tonic-gate 41827c478bd9Sstevel@tonic-gate /* 41837c478bd9Sstevel@tonic-gate * For tagged queuing, we should still be in msgin 41847c478bd9Sstevel@tonic-gate * phase. 41857c478bd9Sstevel@tonic-gate * If not, then either we aren't running tagged 41867c478bd9Sstevel@tonic-gate * queueing like we thought or the target died. 41877c478bd9Sstevel@tonic-gate */ 41887c478bd9Sstevel@tonic-gate if (INTPENDING(fas) == 0) { 41897c478bd9Sstevel@tonic-gate EPRINTF1("slow reconnect, slot=%x\n", slot); 41907c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 41917c478bd9Sstevel@tonic-gate TR_FAS_RECONNECT_RETURN1_END, 41927c478bd9Sstevel@tonic-gate "fas_reconnect_end (_RETURN1)"); 41937c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 41947c478bd9Sstevel@tonic-gate } 41957c478bd9Sstevel@tonic-gate 41967c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, &fasreg->fas_stat); 41977c478bd9Sstevel@tonic-gate fas->f_intr = fas_reg_read(fas, &fasreg->fas_intr); 41987c478bd9Sstevel@tonic-gate if (fas->f_intr & (FAS_INT_ILLEGAL | FAS_INT_RESET)) { 41997c478bd9Sstevel@tonic-gate return (fas_illegal_cmd_or_bus_reset(fas)); 42007c478bd9Sstevel@tonic-gate } 42017c478bd9Sstevel@tonic-gate 42027c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_PHASE_MASK) != 42037c478bd9Sstevel@tonic-gate FAS_PHASE_MSG_IN) { 42047c478bd9Sstevel@tonic-gate bad_reselect = "not in msgin phase"; 42057c478bd9Sstevel@tonic-gate break; 42067c478bd9Sstevel@tonic-gate } 42077c478bd9Sstevel@tonic-gate 42087c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_DISCON) { 42097c478bd9Sstevel@tonic-gate bad_reselect = "unexpected bus free"; 42107c478bd9Sstevel@tonic-gate break; 42117c478bd9Sstevel@tonic-gate } 42127c478bd9Sstevel@tonic-gate } else { 42137c478bd9Sstevel@tonic-gate fas->f_current_sp = sp = fas->f_active[slot]->f_slot[0]; 42147c478bd9Sstevel@tonic-gate break; 42157c478bd9Sstevel@tonic-gate } 42167c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 42177c478bd9Sstevel@tonic-gate 42187c478bd9Sstevel@tonic-gate case ACTS_RESEL: 42197c478bd9Sstevel@tonic-gate { 42207c478bd9Sstevel@tonic-gate volatile uchar_t *c = 42217c478bd9Sstevel@tonic-gate (uchar_t *)fas->f_cmdarea; 42227c478bd9Sstevel@tonic-gate struct f_slots *tag_slots; 42237c478bd9Sstevel@tonic-gate int id, tag; 42247c478bd9Sstevel@tonic-gate uint_t i; 42257c478bd9Sstevel@tonic-gate 42267c478bd9Sstevel@tonic-gate slot = fas->f_resel_slot; 42277c478bd9Sstevel@tonic-gate target = slot/NLUNS_PER_TARGET; 42287c478bd9Sstevel@tonic-gate 42297c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_PHASE_MASK) != 42307c478bd9Sstevel@tonic-gate FAS_PHASE_MSG_IN) { 42317c478bd9Sstevel@tonic-gate IPRINTF1("no tag for slot %x\n", slot); 42327c478bd9Sstevel@tonic-gate if (fas->f_intr & ~(FAS_INT_BUS | 42337c478bd9Sstevel@tonic-gate FAS_INT_FCMP)) { 42347c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 42357c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 42367c478bd9Sstevel@tonic-gate TR_FAS_RECONNECT_PHASEMANAGE_END, 42377c478bd9Sstevel@tonic-gate "fas_reconnect_end (_PHASEMANAGE)"); 42387c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 42397c478bd9Sstevel@tonic-gate } else { 42407c478bd9Sstevel@tonic-gate bad_reselect = "not in msgin phase"; 42417c478bd9Sstevel@tonic-gate break; 42427c478bd9Sstevel@tonic-gate } 42437c478bd9Sstevel@tonic-gate } 42447c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_TRAN_INFO|CMD_DMA); 42457c478bd9Sstevel@tonic-gate fas_dma_reg_write(fas, &fas->f_dma->dma_csr, 42467c478bd9Sstevel@tonic-gate fas->f_dma_csr); 42477c478bd9Sstevel@tonic-gate 42487c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_MSG_ACPT); 42497c478bd9Sstevel@tonic-gate 42507c478bd9Sstevel@tonic-gate for (i = 0; i < (uint_t)RECONNECT_TAG_RCV_TIMEOUT; 42517c478bd9Sstevel@tonic-gate i++) { 42527c478bd9Sstevel@tonic-gate /* 42537c478bd9Sstevel@tonic-gate * timeout is not very accurate but this 42547c478bd9Sstevel@tonic-gate * should take no time at all 42557c478bd9Sstevel@tonic-gate */ 42567c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 42577c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, 42587c478bd9Sstevel@tonic-gate (uchar_t *)&fas->f_reg->fas_stat); 42597c478bd9Sstevel@tonic-gate fas->f_intr = fas_reg_read(fas, 42607c478bd9Sstevel@tonic-gate (uchar_t *)&fas->f_reg->fas_intr); 42617c478bd9Sstevel@tonic-gate if (fas->f_intr & (FAS_INT_RESET | 42627c478bd9Sstevel@tonic-gate FAS_INT_ILLEGAL)) { 42637c478bd9Sstevel@tonic-gate return ( 426419397407SSherry Moore fas_illegal_cmd_or_bus_reset 426519397407SSherry Moore (fas)); 42667c478bd9Sstevel@tonic-gate } 42677c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_FCMP) { 42687c478bd9Sstevel@tonic-gate break; 42697c478bd9Sstevel@tonic-gate } 42707c478bd9Sstevel@tonic-gate } 42717c478bd9Sstevel@tonic-gate } 42727c478bd9Sstevel@tonic-gate 42737c478bd9Sstevel@tonic-gate if (i == (uint_t)RECONNECT_TAG_RCV_TIMEOUT) { 42747c478bd9Sstevel@tonic-gate bad_reselect = "timeout on receiving tag msg"; 42757c478bd9Sstevel@tonic-gate break; 42767c478bd9Sstevel@tonic-gate } 42777c478bd9Sstevel@tonic-gate 42787c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(fas); 42797c478bd9Sstevel@tonic-gate 42807c478bd9Sstevel@tonic-gate /* 42817c478bd9Sstevel@tonic-gate * we should really do a sync here but that 42827c478bd9Sstevel@tonic-gate * hurts performance too much; we'll just hang 42837c478bd9Sstevel@tonic-gate * around till the tag byte flips 42847c478bd9Sstevel@tonic-gate * This is necessary on any system with an 42857c478bd9Sstevel@tonic-gate * XBox 42867c478bd9Sstevel@tonic-gate */ 42877c478bd9Sstevel@tonic-gate if (*c == INVALID_MSG) { 42887c478bd9Sstevel@tonic-gate EPRINTF( 42897c478bd9Sstevel@tonic-gate "fas_reconnect: invalid msg, polling\n"); 42907c478bd9Sstevel@tonic-gate for (i = 0; i < 1000000; i++) { 42917c478bd9Sstevel@tonic-gate if (*c != INVALID_MSG) 42927c478bd9Sstevel@tonic-gate break; 42937c478bd9Sstevel@tonic-gate } 42947c478bd9Sstevel@tonic-gate } 42957c478bd9Sstevel@tonic-gate 42967c478bd9Sstevel@tonic-gate if (fas->f_stat & FAS_STAT_PERR) { 42977c478bd9Sstevel@tonic-gate break; 42987c478bd9Sstevel@tonic-gate } 42997c478bd9Sstevel@tonic-gate 43007c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_STAT_XZERO) == 0 || 43017c478bd9Sstevel@tonic-gate (id = *c++) < MSG_SIMPLE_QTAG || 43027c478bd9Sstevel@tonic-gate id > MSG_ORDERED_QTAG) { 43037c478bd9Sstevel@tonic-gate /* 43047c478bd9Sstevel@tonic-gate * Target agreed to do tagged queueing 43057c478bd9Sstevel@tonic-gate * and lied! 43067c478bd9Sstevel@tonic-gate * This problem implies the drive firmware is 43077c478bd9Sstevel@tonic-gate * broken. 43087c478bd9Sstevel@tonic-gate */ 43097c478bd9Sstevel@tonic-gate bad_reselect = "botched tag"; 43107c478bd9Sstevel@tonic-gate break; 43117c478bd9Sstevel@tonic-gate } 43127c478bd9Sstevel@tonic-gate tag = *c; 43137c478bd9Sstevel@tonic-gate 43147c478bd9Sstevel@tonic-gate /* Set ptr to reconnecting scsi pkt */ 43157c478bd9Sstevel@tonic-gate tag_slots = fas->f_active[slot]; 43167c478bd9Sstevel@tonic-gate if (tag_slots != NULL) { 43177c478bd9Sstevel@tonic-gate sp = tag_slots->f_slot[tag]; 43187c478bd9Sstevel@tonic-gate } else { 43197c478bd9Sstevel@tonic-gate bad_reselect = "Invalid tag"; 43207c478bd9Sstevel@tonic-gate break; 43217c478bd9Sstevel@tonic-gate } 43227c478bd9Sstevel@tonic-gate 43237c478bd9Sstevel@tonic-gate fas->f_current_sp = sp; 43247c478bd9Sstevel@tonic-gate } 43257c478bd9Sstevel@tonic-gate } 43267c478bd9Sstevel@tonic-gate 43277c478bd9Sstevel@tonic-gate if (fas->f_stat & FAS_STAT_PERR) { 43287c478bd9Sstevel@tonic-gate sp = NULL; 43297c478bd9Sstevel@tonic-gate bad_reselect = "Parity error in reconnect msg's"; 43307c478bd9Sstevel@tonic-gate } 43317c478bd9Sstevel@tonic-gate 43327c478bd9Sstevel@tonic-gate if ((sp == NULL || 43337c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 43347c478bd9Sstevel@tonic-gate (fas_atest_reconn & (1<<Tgt(sp))) || 43357c478bd9Sstevel@tonic-gate #endif 43367c478bd9Sstevel@tonic-gate (sp->cmd_flags & (CFLAG_CMDDISC|CFLAG_CMDPROXY)) == 0)) { 43377c478bd9Sstevel@tonic-gate /* 43387c478bd9Sstevel@tonic-gate * this shouldn't really happen, so it is better 43397c478bd9Sstevel@tonic-gate * to reset the bus; some disks accept the abort 43407c478bd9Sstevel@tonic-gate * and then still reconnect 43417c478bd9Sstevel@tonic-gate */ 43427c478bd9Sstevel@tonic-gate if (bad_reselect == NULL) { 43437c478bd9Sstevel@tonic-gate bad_reselect = "no command"; 43447c478bd9Sstevel@tonic-gate } 43457c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 43467c478bd9Sstevel@tonic-gate if (sp && !(fas_atest_reconn & (1<<Tgt(sp))) && 43477c478bd9Sstevel@tonic-gate fas_test_stop) { 43487c478bd9Sstevel@tonic-gate debug_enter("bad reconnect"); 43497c478bd9Sstevel@tonic-gate } else { 43507c478bd9Sstevel@tonic-gate fas_atest_reconn = 0; 43517c478bd9Sstevel@tonic-gate } 43527c478bd9Sstevel@tonic-gate #endif 43537c478bd9Sstevel@tonic-gate goto bad; 43547c478bd9Sstevel@tonic-gate 43557c478bd9Sstevel@tonic-gate /* 43567c478bd9Sstevel@tonic-gate * XXX remove this case or make it an ASSERT 43577c478bd9Sstevel@tonic-gate */ 43587c478bd9Sstevel@tonic-gate } else if (sp->cmd_flags & CFLAG_CMDPROXY) { 43597c478bd9Sstevel@tonic-gate /* 43607c478bd9Sstevel@tonic-gate * If we got here, we were already attempting to 43617c478bd9Sstevel@tonic-gate * run a polled proxy command for this target. 43627c478bd9Sstevel@tonic-gate * Set ATN and, copy in the message, and drive 43637c478bd9Sstevel@tonic-gate * on (ignoring any parity error on the identify). 43647c478bd9Sstevel@tonic-gate */ 43657c478bd9Sstevel@tonic-gate IPRINTF1("fas_reconnect: fielding proxy cmd for %d\n", 43667c478bd9Sstevel@tonic-gate target); 43677c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 43687c478bd9Sstevel@tonic-gate fas->f_omsglen = sp->cmd_cdb[FAS_PROXY_DATA]; 43697c478bd9Sstevel@tonic-gate tmp = 0; 43707c478bd9Sstevel@tonic-gate while (tmp < fas->f_omsglen) { 43717c478bd9Sstevel@tonic-gate fas->f_cur_msgout[tmp] = 43727c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA+1+tmp]; 43737c478bd9Sstevel@tonic-gate tmp++; 43747c478bd9Sstevel@tonic-gate } 43757c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] = FALSE; 43767c478bd9Sstevel@tonic-gate 43777c478bd9Sstevel@tonic-gate /* 43787c478bd9Sstevel@tonic-gate * pretend that the disconnected cmd is still disconnected 43797c478bd9Sstevel@tonic-gate * (this prevents ndisc from going negative) 43807c478bd9Sstevel@tonic-gate */ 43817c478bd9Sstevel@tonic-gate fas->f_ndisc++; 43827c478bd9Sstevel@tonic-gate ASSERT((fas->f_ncmds >= 0) && (fas->f_ndisc >= 0)); 43837c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 43847c478bd9Sstevel@tonic-gate } 43857c478bd9Sstevel@tonic-gate 43867c478bd9Sstevel@tonic-gate ASSERT(fas->f_resel_slot == slot); 43877c478bd9Sstevel@tonic-gate ASSERT(fas->f_ndisc > 0); 43887c478bd9Sstevel@tonic-gate fas->f_ndisc--; 43897c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_CMDDISC; 43907c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 43917c478bd9Sstevel@tonic-gate 43927c478bd9Sstevel@tonic-gate /* 43937c478bd9Sstevel@tonic-gate * A reconnect may imply a restore pointers operation 43947c478bd9Sstevel@tonic-gate * Note that some older disks (Micropolis in Pbox) do not 43957c478bd9Sstevel@tonic-gate * send a save data ptr on disconnect if all data has been 43967c478bd9Sstevel@tonic-gate * xferred. So, we cannot restore ptrs yet here. 43977c478bd9Sstevel@tonic-gate */ 43987c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_DMAVALID) && 43997c478bd9Sstevel@tonic-gate (sp->cmd_data_count != sp->cmd_saved_data_count)) { 44007c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_RESTORE_PTRS; 44017c478bd9Sstevel@tonic-gate } 44027c478bd9Sstevel@tonic-gate 44037c478bd9Sstevel@tonic-gate /* 44047c478bd9Sstevel@tonic-gate * Return to await the FUNCTION COMPLETE interrupt we 44057c478bd9Sstevel@tonic-gate * should get out of accepting the IDENTIFY message. 44067c478bd9Sstevel@tonic-gate */ 44077c478bd9Sstevel@tonic-gate EPRINTF2("Reconnecting %d.%d\n", target, slot % NLUNS_PER_TARGET); 44087c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_RECONNECT_RETURN2_END, 44097c478bd9Sstevel@tonic-gate "fas_reconnect_end (_RETURN2)"); 44107c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate bad: 44137c478bd9Sstevel@tonic-gate if (sp && (fas->f_stat & FAS_STAT_PERR)) { 44147c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 44157c478bd9Sstevel@tonic-gate } 44167c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "target %x: failed reselection (%s)", 44177c478bd9Sstevel@tonic-gate target, bad_reselect); 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 44207c478bd9Sstevel@tonic-gate fas_printstate(fas, "failed reselection"); 44217c478bd9Sstevel@tonic-gate #endif 44227c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_RECONNECT_RESET5_END, 44237c478bd9Sstevel@tonic-gate "fas_reconnect_end (_RESET5)"); 44247c478bd9Sstevel@tonic-gate return (ACTION_RESET); 44257c478bd9Sstevel@tonic-gate } 44267c478bd9Sstevel@tonic-gate 44277c478bd9Sstevel@tonic-gate /* 44287c478bd9Sstevel@tonic-gate * handle unknown bus phase 44297c478bd9Sstevel@tonic-gate * we don't know what to expect so check status register for current 44307c478bd9Sstevel@tonic-gate * phase 44317c478bd9Sstevel@tonic-gate */ 44327c478bd9Sstevel@tonic-gate int 44337c478bd9Sstevel@tonic-gate fas_handle_unknown(struct fas *fas) 44347c478bd9Sstevel@tonic-gate { 44357c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_UNKNOWN_START, 44367c478bd9Sstevel@tonic-gate "fas_handle_unknown_start: fas 0x%p", fas); 44377c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_unknown:\n"); 44387c478bd9Sstevel@tonic-gate 44397c478bd9Sstevel@tonic-gate if ((fas->f_intr & FAS_INT_DISCON) == 0) { 44407c478bd9Sstevel@tonic-gate /* 44417c478bd9Sstevel@tonic-gate * we call actions here rather than returning to phasemanage 44427c478bd9Sstevel@tonic-gate * (this is the most frequently called action) 44437c478bd9Sstevel@tonic-gate */ 44447c478bd9Sstevel@tonic-gate switch (fas->f_stat & FAS_PHASE_MASK) { 44457c478bd9Sstevel@tonic-gate case FAS_PHASE_DATA_IN: 44467c478bd9Sstevel@tonic-gate case FAS_PHASE_DATA_OUT: 44477c478bd9Sstevel@tonic-gate New_state(fas, ACTS_DATA); 44487c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 44497c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_PHASE_DATA_END, 44507c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (phase_data)"); 44517c478bd9Sstevel@tonic-gate return (fas_handle_data_start(fas)); 44527c478bd9Sstevel@tonic-gate 44537c478bd9Sstevel@tonic-gate case FAS_PHASE_MSG_OUT: 44547c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_OUT); 44557c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 44567c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_PHASE_MSG_OUT_END, 44577c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (phase_msg_out)"); 44587c478bd9Sstevel@tonic-gate return (fas_handle_msg_out_start(fas)); 44597c478bd9Sstevel@tonic-gate 44607c478bd9Sstevel@tonic-gate case FAS_PHASE_MSG_IN: 44617c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN); 44627c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 44637c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_PHASE_MSG_IN_END, 44647c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (phase_msg_in)"); 44657c478bd9Sstevel@tonic-gate return (fas_handle_msg_in_start(fas)); 44667c478bd9Sstevel@tonic-gate 44677c478bd9Sstevel@tonic-gate case FAS_PHASE_STATUS: 44687c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 44697c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 44707c478bd9Sstevel@tonic-gate if (fas_ptest_status & (1<<Tgt(fas->f_current_sp))) { 44717c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 44727c478bd9Sstevel@tonic-gate } 44737c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 44747c478bd9Sstevel@tonic-gate 44757c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_COMP_SEQ); 44767c478bd9Sstevel@tonic-gate New_state(fas, ACTS_C_CMPLT); 44777c478bd9Sstevel@tonic-gate 44787c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 44797c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_PHASE_STATUS_END, 44807c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (phase_status)"); 44817c478bd9Sstevel@tonic-gate return (fas_handle_c_cmplt(fas)); 44827c478bd9Sstevel@tonic-gate 44837c478bd9Sstevel@tonic-gate case FAS_PHASE_COMMAND: 44847c478bd9Sstevel@tonic-gate New_state(fas, ACTS_CMD_START); 44857c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 44867c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_PHASE_CMD_END, 44877c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (phase_cmd)"); 44887c478bd9Sstevel@tonic-gate return (fas_handle_cmd_start(fas)); 44897c478bd9Sstevel@tonic-gate } 44907c478bd9Sstevel@tonic-gate 44917c478bd9Sstevel@tonic-gate fas_printstate(fas, "Unknown bus phase"); 44927c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_UNKNOWN_RESET_END, 44937c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (reset)"); 44947c478bd9Sstevel@tonic-gate return (ACTION_RESET); 44957c478bd9Sstevel@tonic-gate 44967c478bd9Sstevel@tonic-gate } else { 44977c478bd9Sstevel@tonic-gate /* 44987c478bd9Sstevel@tonic-gate * Okay. What to do now? Let's try (for the time being) 44997c478bd9Sstevel@tonic-gate * assuming that the target went south and dropped busy, 45007c478bd9Sstevel@tonic-gate * as a disconnect implies that either we received 45017c478bd9Sstevel@tonic-gate * a completion or a disconnect message, or that we 45027c478bd9Sstevel@tonic-gate * had sent an ABORT OPERATION or BUS DEVICE RESET 45037c478bd9Sstevel@tonic-gate * message. In either case, we expected the disconnect 45047c478bd9Sstevel@tonic-gate * and should have fielded it elsewhere. 45057c478bd9Sstevel@tonic-gate * 45067c478bd9Sstevel@tonic-gate * If we see a chip disconnect here, this is an unexpected 45077c478bd9Sstevel@tonic-gate * loss of BSY*. Clean up the state of the chip and return. 45087c478bd9Sstevel@tonic-gate * 45097c478bd9Sstevel@tonic-gate */ 45107c478bd9Sstevel@tonic-gate int msgout = fas->f_cur_msgout[0]; 45117c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 45127c478bd9Sstevel@tonic-gate int target = Tgt(sp); 45137c478bd9Sstevel@tonic-gate 45147c478bd9Sstevel@tonic-gate if (msgout == MSG_HEAD_QTAG || msgout == MSG_SIMPLE_QTAG) { 45157c478bd9Sstevel@tonic-gate msgout = fas->f_cur_msgout[2]; 45167c478bd9Sstevel@tonic-gate } 45177c478bd9Sstevel@tonic-gate EPRINTF4("msgout: %x %x %x, last_msgout=%x\n", 45187c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0], fas->f_cur_msgout[1], 45197c478bd9Sstevel@tonic-gate fas->f_cur_msgout[2], fas->f_last_msgout); 45207c478bd9Sstevel@tonic-gate 45217c478bd9Sstevel@tonic-gate if (msgout == MSG_ABORT || msgout == MSG_ABORT_TAG || 45227c478bd9Sstevel@tonic-gate msgout == MSG_DEVICE_RESET) { 45237c478bd9Sstevel@tonic-gate IPRINTF2("Successful %s message to target %d\n", 45247c478bd9Sstevel@tonic-gate scsi_mname(msgout), Tgt(sp)); 45257c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CMDPROXY) { 45267c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] = TRUE; 45277c478bd9Sstevel@tonic-gate } 45287c478bd9Sstevel@tonic-gate if (msgout == MSG_ABORT || msgout == MSG_ABORT_TAG) { 45297c478bd9Sstevel@tonic-gate fas->f_abort_msg_sent++; 45307c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 45317c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, 45327c478bd9Sstevel@tonic-gate CMD_ABORTED, STAT_ABORTED); 45337c478bd9Sstevel@tonic-gate } 45347c478bd9Sstevel@tonic-gate } else if (msgout == MSG_DEVICE_RESET) { 45357c478bd9Sstevel@tonic-gate fas->f_reset_msg_sent++; 45367c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 45377c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, 45387c478bd9Sstevel@tonic-gate CMD_RESET, STAT_DEV_RESET); 45397c478bd9Sstevel@tonic-gate } 45407c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, target); 45417c478bd9Sstevel@tonic-gate } 45427c478bd9Sstevel@tonic-gate } else { 45437c478bd9Sstevel@tonic-gate if ((fas->f_last_msgout == MSG_EXTENDED) && 45447c478bd9Sstevel@tonic-gate (fas->f_last_msgin == MSG_REJECT)) { 45457c478bd9Sstevel@tonic-gate /* 45467c478bd9Sstevel@tonic-gate * the target rejected the negotiations, 45477c478bd9Sstevel@tonic-gate * so resubmit again (no_sync/no_wide 45487c478bd9Sstevel@tonic-gate * is now set) 45497c478bd9Sstevel@tonic-gate */ 45507c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 45517c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_EN_RESEL); 45527c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 45537c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 45547c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 45557c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_TRANFLAG; 45567c478bd9Sstevel@tonic-gate (void) fas_accept_pkt(fas, sp, NO_TRAN_BUSY); 45577c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 45587c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 45597c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_UNKNOWN_INT_DISCON_END, 45607c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (int_discon)"); 45617c478bd9Sstevel@tonic-gate return (ACTION_SEARCH); 45627c478bd9Sstevel@tonic-gate 45637c478bd9Sstevel@tonic-gate } else if (fas->f_last_msgout == MSG_EXTENDED) { 45647c478bd9Sstevel@tonic-gate /* 45657c478bd9Sstevel@tonic-gate * target dropped off the bus during 45667c478bd9Sstevel@tonic-gate * negotiations 45677c478bd9Sstevel@tonic-gate */ 45687c478bd9Sstevel@tonic-gate fas_reset_sync_wide(fas); 45697c478bd9Sstevel@tonic-gate fas->f_sdtr_sent = fas->f_wdtr_sent = 0; 45707c478bd9Sstevel@tonic-gate } 45717c478bd9Sstevel@tonic-gate 45727c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_UNX_BUS_FREE, 0); 45737c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 45747c478bd9Sstevel@tonic-gate fas_printstate(fas, "unexpected bus free"); 45757c478bd9Sstevel@tonic-gate #endif 45767c478bd9Sstevel@tonic-gate } 45777c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_UNKNOWN_INT_DISCON_END, 45787c478bd9Sstevel@tonic-gate "fas_handle_unknown_end (int_discon)"); 45797c478bd9Sstevel@tonic-gate return (ACTION_FINISH); 45807c478bd9Sstevel@tonic-gate } 45817c478bd9Sstevel@tonic-gate _NOTE(NOT_REACHED) 45827c478bd9Sstevel@tonic-gate /* NOTREACHED */ 45837c478bd9Sstevel@tonic-gate } 45847c478bd9Sstevel@tonic-gate 45857c478bd9Sstevel@tonic-gate /* 45867c478bd9Sstevel@tonic-gate * handle target disconnecting 45877c478bd9Sstevel@tonic-gate */ 45887c478bd9Sstevel@tonic-gate static int 45897c478bd9Sstevel@tonic-gate fas_handle_clearing(struct fas *fas) 45907c478bd9Sstevel@tonic-gate { 45917c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 45927c478bd9Sstevel@tonic-gate 45937c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CLEARING_START, 45947c478bd9Sstevel@tonic-gate "fas_handle_clearing_start"); 45957c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_clearing:\n"); 45967c478bd9Sstevel@tonic-gate 45977c478bd9Sstevel@tonic-gate if (fas->f_laststate == ACTS_C_CMPLT || 45987c478bd9Sstevel@tonic-gate fas->f_laststate == ACTS_MSG_IN_DONE) { 45997c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 46007c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 46017c478bd9Sstevel@tonic-gate 46027c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, 46037c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_stat); 46047c478bd9Sstevel@tonic-gate fas->f_intr = fas_reg_read(fas, 46057c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_intr); 46067c478bd9Sstevel@tonic-gate if (fas->f_intr & (FAS_INT_RESET | FAS_INT_ILLEGAL)) { 46077c478bd9Sstevel@tonic-gate return (fas_illegal_cmd_or_bus_reset(fas)); 46087c478bd9Sstevel@tonic-gate } 46097c478bd9Sstevel@tonic-gate } else { 46107c478bd9Sstevel@tonic-gate /* 46117c478bd9Sstevel@tonic-gate * change e_laststate for the next time around 46127c478bd9Sstevel@tonic-gate */ 46137c478bd9Sstevel@tonic-gate fas->f_laststate = ACTS_CLEARING; 46147c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 46157c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_CLEARING_RETURN1_END, 46167c478bd9Sstevel@tonic-gate "fas_handle_clearing_end (ACTION_RETURN1)"); 46177c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 46187c478bd9Sstevel@tonic-gate } 46197c478bd9Sstevel@tonic-gate } 46207c478bd9Sstevel@tonic-gate 46217c478bd9Sstevel@tonic-gate if (fas->f_intr == FAS_INT_DISCON) { 46227c478bd9Sstevel@tonic-gate /* 46237c478bd9Sstevel@tonic-gate * At this point the FAS chip has disconnected. The bus should 46247c478bd9Sstevel@tonic-gate * be either quiet or someone may be attempting a reselection 46257c478bd9Sstevel@tonic-gate * of us (or somebody else). Call the routine that sets the 46267c478bd9Sstevel@tonic-gate * chip back to a correct and known state. 46277c478bd9Sstevel@tonic-gate * If the last message in was a disconnect, search 46287c478bd9Sstevel@tonic-gate * for new work to do, else return to call fas_finish() 46297c478bd9Sstevel@tonic-gate */ 46307c478bd9Sstevel@tonic-gate fas->f_last_msgout = 0xff; 46317c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 46327c478bd9Sstevel@tonic-gate if (fas->f_last_msgin == MSG_DISCONNECT) { 46337c478bd9Sstevel@tonic-gate 46347c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_EN_RESEL); 46357c478bd9Sstevel@tonic-gate 46367c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 46377c478bd9Sstevel@tonic-gate 46387c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp != NULL); 46397c478bd9Sstevel@tonic-gate EPRINTF2("disconnecting %d.%d\n", Tgt(sp), Lun(sp)); 46407c478bd9Sstevel@tonic-gate 46417c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_DISCON; 46427c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_CMDDISC; 46437c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 46447c478bd9Sstevel@tonic-gate fas->f_ndisc++; 46457c478bd9Sstevel@tonic-gate } 46467c478bd9Sstevel@tonic-gate ASSERT((fas->f_ncmds >= 0) && (fas->f_ndisc >= 0)); 46477c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 46487c478bd9Sstevel@tonic-gate 46497c478bd9Sstevel@tonic-gate fas->f_current_sp = NULL; 46507c478bd9Sstevel@tonic-gate 46517c478bd9Sstevel@tonic-gate /* 46527c478bd9Sstevel@tonic-gate * start a cmd here to save time 46537c478bd9Sstevel@tonic-gate */ 46547c478bd9Sstevel@tonic-gate if ((fas->f_ncmds > fas->f_ndisc) && fas_ustart(fas)) { 46557c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 46567c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_CLEARING_RETURN2_END, 46577c478bd9Sstevel@tonic-gate "fas_handle_clearing_end (ACTION_RETURN2)"); 46587c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 46597c478bd9Sstevel@tonic-gate } 46607c478bd9Sstevel@tonic-gate 46617c478bd9Sstevel@tonic-gate 46627c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 46637c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_CLEARING_RETURN3_END, 46647c478bd9Sstevel@tonic-gate "fas_handle_clearing_end (ACTION_RETURN3)"); 46657c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 46667c478bd9Sstevel@tonic-gate } else { 46677c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CLEARING_END, 46687c478bd9Sstevel@tonic-gate "fas_handle_clearing_end"); 46697c478bd9Sstevel@tonic-gate return (fas_finish(fas)); 46707c478bd9Sstevel@tonic-gate } 46717c478bd9Sstevel@tonic-gate } else { 46727c478bd9Sstevel@tonic-gate /* 46737c478bd9Sstevel@tonic-gate * If the target didn't disconnect from the 46747c478bd9Sstevel@tonic-gate * bus, that is a gross fatal error. 46757c478bd9Sstevel@tonic-gate * XXX this can be caused by asserting ATN 46767c478bd9Sstevel@tonic-gate * XXX check bus phase and if msgout, send a message 46777c478bd9Sstevel@tonic-gate */ 46787c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 46797c478bd9Sstevel@tonic-gate "Target %d didn't disconnect after sending %s", 46807c478bd9Sstevel@tonic-gate Tgt(sp), scsi_mname(fas->f_last_msgin)); 46817c478bd9Sstevel@tonic-gate 46827c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 46837c478bd9Sstevel@tonic-gate 46847c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 46857c478bd9Sstevel@tonic-gate IPRINTF4("msgout: %x %x %x, last_msgout=%x\n", 46867c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0], fas->f_cur_msgout[1], 46877c478bd9Sstevel@tonic-gate fas->f_cur_msgout[2], fas->f_last_msgout); 46887c478bd9Sstevel@tonic-gate IPRINTF1("last msgin=%x\n", fas->f_last_msgin); 46897c478bd9Sstevel@tonic-gate #endif 46907c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CLEARING_ABORT_END, 46917c478bd9Sstevel@tonic-gate "fas_handle_clearing_end (ACTION_ABORT_CURCMD)"); 46927c478bd9Sstevel@tonic-gate return (ACTION_ABORT_ALLCMDS); 46937c478bd9Sstevel@tonic-gate } 46947c478bd9Sstevel@tonic-gate } 46957c478bd9Sstevel@tonic-gate 46967c478bd9Sstevel@tonic-gate /* 46977c478bd9Sstevel@tonic-gate * handle data phase start 46987c478bd9Sstevel@tonic-gate */ 46997c478bd9Sstevel@tonic-gate static int 47007c478bd9Sstevel@tonic-gate fas_handle_data_start(struct fas *fas) 47017c478bd9Sstevel@tonic-gate { 47027c478bd9Sstevel@tonic-gate uint64_t end; 47037c478bd9Sstevel@tonic-gate uint32_t amt; 47047c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 47057c478bd9Sstevel@tonic-gate int sending, phase; 47067c478bd9Sstevel@tonic-gate 47077c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_START, 47087c478bd9Sstevel@tonic-gate "fas_handle_data_start"); 47097c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_data_start:\n"); 47107c478bd9Sstevel@tonic-gate 47117c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_DMAVALID) == 0) { 47127c478bd9Sstevel@tonic-gate fas_printstate(fas, "unexpected data phase"); 47137c478bd9Sstevel@tonic-gate bad: 47147c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 47157c478bd9Sstevel@tonic-gate 47167c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_ABORT1_END, 47177c478bd9Sstevel@tonic-gate "fas_handle_data_end (ACTION_ABORT_CURCMD1)"); 47187c478bd9Sstevel@tonic-gate return (ACTION_ABORT_CURCMD); 47197c478bd9Sstevel@tonic-gate } else { 47207c478bd9Sstevel@tonic-gate sending = (sp->cmd_flags & CFLAG_DMASEND)? 1 : 0; 47217c478bd9Sstevel@tonic-gate } 47227c478bd9Sstevel@tonic-gate 47237c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_RESTORE_PTRS) { 47247c478bd9Sstevel@tonic-gate if (fas_restore_pointers(fas, sp)) { 47257c478bd9Sstevel@tonic-gate return (ACTION_ABORT_CURCMD); 47267c478bd9Sstevel@tonic-gate } 47277c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_RESTORE_PTRS; 47287c478bd9Sstevel@tonic-gate } 47297c478bd9Sstevel@tonic-gate 47307c478bd9Sstevel@tonic-gate /* 47317c478bd9Sstevel@tonic-gate * And make sure our DMA pointers are in good shape. 47327c478bd9Sstevel@tonic-gate * 47337c478bd9Sstevel@tonic-gate * Because SCSI is SCSI, the current DMA pointer has got to be 47347c478bd9Sstevel@tonic-gate * greater than or equal to our DMA base address. All other cases 47357c478bd9Sstevel@tonic-gate * that might have affected this always set curaddr to be >= 47367c478bd9Sstevel@tonic-gate * to the DMA base address. 47377c478bd9Sstevel@tonic-gate */ 47387c478bd9Sstevel@tonic-gate ASSERT(sp->cmd_cur_addr >= sp->cmd_dmacookie.dmac_address); 47397c478bd9Sstevel@tonic-gate end = (uint64_t)sp->cmd_dmacookie.dmac_address + 47407c478bd9Sstevel@tonic-gate (uint64_t)sp->cmd_dmacookie.dmac_size; 47417c478bd9Sstevel@tonic-gate 47427c478bd9Sstevel@tonic-gate DPRINTF5( 47437c478bd9Sstevel@tonic-gate "cmd_data_count=%x, dmacount=%x, curaddr=%x, end=%" 47447c478bd9Sstevel@tonic-gate PRIx64 ", nwin=%x\n", 47457c478bd9Sstevel@tonic-gate sp->cmd_data_count, sp->cmd_dmacount, sp->cmd_cur_addr, end, 47467c478bd9Sstevel@tonic-gate sp->cmd_nwin); 47477c478bd9Sstevel@tonic-gate DPRINTF2("dmac_address = %x, dmac_size=%lx\n", 47487c478bd9Sstevel@tonic-gate sp->cmd_dmacookie.dmac_address, sp->cmd_dmacookie.dmac_size); 47497c478bd9Sstevel@tonic-gate 47507c478bd9Sstevel@tonic-gate if (sp->cmd_cur_addr >= end) { 47517c478bd9Sstevel@tonic-gate if (fas_next_window(fas, sp, end)) { 47527c478bd9Sstevel@tonic-gate goto bad; 47537c478bd9Sstevel@tonic-gate } 47547c478bd9Sstevel@tonic-gate end = (uint64_t)sp->cmd_dmacookie.dmac_address + 47557c478bd9Sstevel@tonic-gate (uint64_t)sp->cmd_dmacookie.dmac_size; 47567c478bd9Sstevel@tonic-gate DPRINTF2("dmac_address=%x, dmac_size=%lx\n", 47577c478bd9Sstevel@tonic-gate sp->cmd_dmacookie.dmac_address, 47587c478bd9Sstevel@tonic-gate sp->cmd_dmacookie.dmac_size); 47597c478bd9Sstevel@tonic-gate } 47607c478bd9Sstevel@tonic-gate 47617c478bd9Sstevel@tonic-gate amt = end - sp->cmd_cur_addr; 47627c478bd9Sstevel@tonic-gate if (fas->f_dma_attr->dma_attr_count_max < amt) { 47637c478bd9Sstevel@tonic-gate amt = fas->f_dma_attr->dma_attr_count_max; 47647c478bd9Sstevel@tonic-gate } 47657c478bd9Sstevel@tonic-gate DPRINTF3("amt=%x, end=%lx, cur_addr=%x\n", amt, end, sp->cmd_cur_addr); 47667c478bd9Sstevel@tonic-gate 47677c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 47687c478bd9Sstevel@tonic-gate /* 47697c478bd9Sstevel@tonic-gate * Make sure that we don't cross a boundary we can't handle 47707c478bd9Sstevel@tonic-gate */ 47717c478bd9Sstevel@tonic-gate end = (uint64_t)sp->cmd_cur_addr + (uint64_t)amt - 1; 47727c478bd9Sstevel@tonic-gate if ((end & ~fas->f_dma_attr->dma_attr_seg) != 47737c478bd9Sstevel@tonic-gate (sp->cmd_cur_addr & ~fas->f_dma_attr->dma_attr_seg)) { 47747c478bd9Sstevel@tonic-gate EPRINTF3("curaddr %x curaddr+amt %" PRIx64 47757c478bd9Sstevel@tonic-gate " cntr_max %" PRIx64 "\n", 47767c478bd9Sstevel@tonic-gate sp->cmd_cur_addr, end, fas->f_dma_attr->dma_attr_seg); 47777c478bd9Sstevel@tonic-gate amt = (end & ~fas->f_dma_attr->dma_attr_seg) - sp->cmd_cur_addr; 47787c478bd9Sstevel@tonic-gate if (amt == 0 || amt > fas->f_dma_attr->dma_attr_count_max) { 47797c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "illegal dma boundary? %x", amt); 47807c478bd9Sstevel@tonic-gate goto bad; 47817c478bd9Sstevel@tonic-gate } 47827c478bd9Sstevel@tonic-gate } 47837c478bd9Sstevel@tonic-gate #endif 47847c478bd9Sstevel@tonic-gate 47857c478bd9Sstevel@tonic-gate end = (uint64_t)sp->cmd_dmacookie.dmac_address + 47867c478bd9Sstevel@tonic-gate (uint64_t)sp->cmd_dmacookie.dmac_size - 47877c478bd9Sstevel@tonic-gate (uint64_t)sp->cmd_cur_addr; 47887c478bd9Sstevel@tonic-gate if (amt > end) { 47897c478bd9Sstevel@tonic-gate EPRINTF4("ovflow amt %x s.b. %" PRIx64 " curaddr %x count %x\n", 47907c478bd9Sstevel@tonic-gate amt, end, sp->cmd_cur_addr, sp->cmd_dmacount); 47917c478bd9Sstevel@tonic-gate amt = (uint32_t)end; 47927c478bd9Sstevel@tonic-gate } 47937c478bd9Sstevel@tonic-gate 47947c478bd9Sstevel@tonic-gate fas->f_lastcount = amt; 47957c478bd9Sstevel@tonic-gate 47967c478bd9Sstevel@tonic-gate EPRINTF4("%d.%d cmd 0x%x to xfer %x\n", Tgt(sp), Lun(sp), 47977c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_cdbp[0], amt); 47987c478bd9Sstevel@tonic-gate 47997c478bd9Sstevel@tonic-gate phase = fas->f_stat & FAS_PHASE_MASK; 48007c478bd9Sstevel@tonic-gate 48017c478bd9Sstevel@tonic-gate if ((phase == FAS_PHASE_DATA_IN) && !sending) { 48027c478bd9Sstevel@tonic-gate FAS_DMA_WRITE(fas, amt, sp->cmd_cur_addr, 48037c478bd9Sstevel@tonic-gate CMD_TRAN_INFO|CMD_DMA); 48047c478bd9Sstevel@tonic-gate } else if ((phase == FAS_PHASE_DATA_OUT) && sending) { 48057c478bd9Sstevel@tonic-gate FAS_DMA_READ(fas, amt, sp->cmd_cur_addr, amt, 48067c478bd9Sstevel@tonic-gate CMD_TRAN_INFO|CMD_DMA); 48077c478bd9Sstevel@tonic-gate } else { 48087c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 48097c478bd9Sstevel@tonic-gate "unwanted data xfer direction for Target %d", Tgt(sp)); 48107c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_DMA_DERR, 0); 48117c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_ABORT2_END, 48127c478bd9Sstevel@tonic-gate "fas_handle_data_end (ACTION_ABORT_CURCMD2)"); 48137c478bd9Sstevel@tonic-gate return (ACTION_ABORT_CURCMD); 48147c478bd9Sstevel@tonic-gate } 48157c478bd9Sstevel@tonic-gate 48167c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 48177c478bd9Sstevel@tonic-gate if (!sending && (fas_ptest_data_in & (1<<Tgt(sp)))) { 48187c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 48197c478bd9Sstevel@tonic-gate } 48207c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 48217c478bd9Sstevel@tonic-gate 48227c478bd9Sstevel@tonic-gate New_state(fas, ACTS_DATA_DONE); 48237c478bd9Sstevel@tonic-gate 48247c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_END, 48257c478bd9Sstevel@tonic-gate "fas_handle_data_end (ACTION_RETURN)"); 48267c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 48277c478bd9Sstevel@tonic-gate } 48287c478bd9Sstevel@tonic-gate 48297c478bd9Sstevel@tonic-gate static int 48307c478bd9Sstevel@tonic-gate fas_handle_data_done(struct fas *fas) 48317c478bd9Sstevel@tonic-gate { 48327c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 48337c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; 48347c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 48357c478bd9Sstevel@tonic-gate uint32_t xfer_amt; 48367c478bd9Sstevel@tonic-gate char was_sending; 48377c478bd9Sstevel@tonic-gate uchar_t stat, fifoamt, tgt; 48387c478bd9Sstevel@tonic-gate 48397c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_DONE_START, 48407c478bd9Sstevel@tonic-gate "fas_handle_data_done_start"); 48417c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_data_done\n"); 48427c478bd9Sstevel@tonic-gate 48437c478bd9Sstevel@tonic-gate tgt = Tgt(sp); 48447c478bd9Sstevel@tonic-gate stat = fas->f_stat; 48457c478bd9Sstevel@tonic-gate was_sending = (sp->cmd_flags & CFLAG_DMASEND) ? 1 : 0; 48467c478bd9Sstevel@tonic-gate 48477c478bd9Sstevel@tonic-gate /* 48487c478bd9Sstevel@tonic-gate * Check for DMA errors (parity or memory fault) 48497c478bd9Sstevel@tonic-gate */ 48507c478bd9Sstevel@tonic-gate if ((fas->f_dma_csr = fas_dma_reg_read(fas, &dmar->dma_csr)) & 48517c478bd9Sstevel@tonic-gate DMA_ERRPEND) { 48527c478bd9Sstevel@tonic-gate /* 48537c478bd9Sstevel@tonic-gate * It would be desirable to set the ATN* line and attempt to 48547c478bd9Sstevel@tonic-gate * do the whole schmear of INITIATOR DETECTED ERROR here, 48557c478bd9Sstevel@tonic-gate * but that is too hard to do at present. 48567c478bd9Sstevel@tonic-gate */ 48577c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "Unrecoverable DMA error on dma %s", 48587c478bd9Sstevel@tonic-gate (was_sending) ? "send" : "receive"); 48597c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 48607c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_DONE_RESET_END, 48617c478bd9Sstevel@tonic-gate "fas_handle_data_done_end (ACTION_RESET)"); 48627c478bd9Sstevel@tonic-gate return (ACTION_RESET); 48637c478bd9Sstevel@tonic-gate } 48647c478bd9Sstevel@tonic-gate 48657c478bd9Sstevel@tonic-gate /* 48667c478bd9Sstevel@tonic-gate * Data Receive conditions: 48677c478bd9Sstevel@tonic-gate * 48687c478bd9Sstevel@tonic-gate * Check for parity errors. If we have a parity error upon 48697c478bd9Sstevel@tonic-gate * receive, the FAS chip has asserted ATN* for us already. 48707c478bd9Sstevel@tonic-gate */ 48717c478bd9Sstevel@tonic-gate if (!was_sending) { 48727c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 48737c478bd9Sstevel@tonic-gate if (fas_ptest_data_in & (1<<tgt)) { 48747c478bd9Sstevel@tonic-gate fas_ptest_data_in = 0; 48757c478bd9Sstevel@tonic-gate stat |= FAS_STAT_PERR; 48767c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) { 48777c478bd9Sstevel@tonic-gate debug_enter("ptest_data_in"); 48787c478bd9Sstevel@tonic-gate } 48797c478bd9Sstevel@tonic-gate } 48807c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 48817c478bd9Sstevel@tonic-gate if (stat & FAS_STAT_PERR) { 48827c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 48837c478bd9Sstevel@tonic-gate "SCSI bus DATA IN phase parity error"); 48847c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = MSG_INITIATOR_ERROR; 48857c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 48867c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 48877c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason = CMD_TRAN_ERR; 48887c478bd9Sstevel@tonic-gate } 48897c478bd9Sstevel@tonic-gate } 48907c478bd9Sstevel@tonic-gate 48917c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(fas); 48927c478bd9Sstevel@tonic-gate 48937c478bd9Sstevel@tonic-gate /* 48947c478bd9Sstevel@tonic-gate * Check to make sure we're still connected to the target. 48957c478bd9Sstevel@tonic-gate * If the target dropped the bus, that is a fatal error. 48967c478bd9Sstevel@tonic-gate * We don't even attempt to count what we were transferring 48977c478bd9Sstevel@tonic-gate * here. Let fas_handle_unknown clean up for us. 48987c478bd9Sstevel@tonic-gate */ 48997c478bd9Sstevel@tonic-gate if (fas->f_intr != FAS_INT_BUS) { 49007c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 49017c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 49027c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_DATA_DONE_PHASEMANAGE_END, 49037c478bd9Sstevel@tonic-gate "fas_handle_data_done_end (ACTION_PHASEMANAGE)"); 49047c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 49057c478bd9Sstevel@tonic-gate } 49067c478bd9Sstevel@tonic-gate 49077c478bd9Sstevel@tonic-gate /* 49087c478bd9Sstevel@tonic-gate * Figure out how far we got. 49097c478bd9Sstevel@tonic-gate * Latch up fifo amount first and double if wide has been enabled 49107c478bd9Sstevel@tonic-gate */ 49117c478bd9Sstevel@tonic-gate fifoamt = FIFO_CNT(fas); 49127c478bd9Sstevel@tonic-gate if (fas->f_wide_enabled & (1<<tgt)) { 49137c478bd9Sstevel@tonic-gate fifoamt = fifoamt << 1; 49147c478bd9Sstevel@tonic-gate } 49157c478bd9Sstevel@tonic-gate 49167c478bd9Sstevel@tonic-gate if (stat & FAS_STAT_XZERO) { 49177c478bd9Sstevel@tonic-gate xfer_amt = fas->f_lastcount; 49187c478bd9Sstevel@tonic-gate } else { 49197c478bd9Sstevel@tonic-gate GET_FAS_COUNT(fasreg, xfer_amt); 49207c478bd9Sstevel@tonic-gate xfer_amt = fas->f_lastcount - xfer_amt; 49217c478bd9Sstevel@tonic-gate } 49227c478bd9Sstevel@tonic-gate DPRINTF4("fifoamt=%x, xfer_amt=%x, lastcount=%x, stat=%x\n", 49237c478bd9Sstevel@tonic-gate fifoamt, xfer_amt, fas->f_lastcount, stat); 49247c478bd9Sstevel@tonic-gate 49257c478bd9Sstevel@tonic-gate 49267c478bd9Sstevel@tonic-gate /* 49277c478bd9Sstevel@tonic-gate * Unconditionally knock off by the amount left 49287c478bd9Sstevel@tonic-gate * in the fifo if we were sending out the SCSI bus. 49297c478bd9Sstevel@tonic-gate * 49307c478bd9Sstevel@tonic-gate * If we were receiving from the SCSI bus, believe 49317c478bd9Sstevel@tonic-gate * what the chip told us (either XZERO or by the 49327c478bd9Sstevel@tonic-gate * value calculated from the counter register). 49337c478bd9Sstevel@tonic-gate * The reason we don't look at the fifo for 49347c478bd9Sstevel@tonic-gate * incoming data is that in synchronous mode 49357c478bd9Sstevel@tonic-gate * the fifo may have further data bytes, and 49367c478bd9Sstevel@tonic-gate * for async mode we assume that all data in 49377c478bd9Sstevel@tonic-gate * the fifo will have been transferred before 49387c478bd9Sstevel@tonic-gate * the fas asserts an interrupt. 49397c478bd9Sstevel@tonic-gate */ 49407c478bd9Sstevel@tonic-gate if (was_sending) { 49417c478bd9Sstevel@tonic-gate xfer_amt -= fifoamt; 49427c478bd9Sstevel@tonic-gate } 49437c478bd9Sstevel@tonic-gate 49447c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 49457c478bd9Sstevel@tonic-gate { 49467c478bd9Sstevel@tonic-gate int phase = stat & FAS_PHASE_MASK; 49477c478bd9Sstevel@tonic-gate fas->f_stat2 = fas_reg_read(fas, 49487c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_stat2); 49497c478bd9Sstevel@tonic-gate 49507c478bd9Sstevel@tonic-gate if (((fas->f_stat & FAS_STAT_XZERO) == 0) && 49517c478bd9Sstevel@tonic-gate (phase != FAS_PHASE_DATA_IN) && 49527c478bd9Sstevel@tonic-gate (phase != FAS_PHASE_DATA_OUT) && 49537c478bd9Sstevel@tonic-gate (fas->f_stat2 & FAS_STAT2_ISHUTTLE)) { 49547c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 49557c478bd9Sstevel@tonic-gate "input shuttle not empty at end of data phase"); 49567c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 49577c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_DONE_RESET_END, 49587c478bd9Sstevel@tonic-gate "fas_handle_data_done_end (ACTION_RESET)"); 49597c478bd9Sstevel@tonic-gate return (ACTION_RESET); 49607c478bd9Sstevel@tonic-gate } 49617c478bd9Sstevel@tonic-gate } 49627c478bd9Sstevel@tonic-gate #endif /* FASDEBUG */ 49637c478bd9Sstevel@tonic-gate 49647c478bd9Sstevel@tonic-gate /* 49657c478bd9Sstevel@tonic-gate * If this was a synchronous transfer, flag it. 49667c478bd9Sstevel@tonic-gate * Also check for the errata condition of long 49677c478bd9Sstevel@tonic-gate * last REQ/ pulse for some synchronous targets 49687c478bd9Sstevel@tonic-gate */ 49697c478bd9Sstevel@tonic-gate if (fas->f_offset[tgt]) { 49707c478bd9Sstevel@tonic-gate /* 49717c478bd9Sstevel@tonic-gate * flag that a synchronous data xfer took place 49727c478bd9Sstevel@tonic-gate */ 49737c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_SYNC; 49747c478bd9Sstevel@tonic-gate 49757c478bd9Sstevel@tonic-gate if (was_sending) 49767c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 49777c478bd9Sstevel@tonic-gate } else { 49787c478bd9Sstevel@tonic-gate /* 49797c478bd9Sstevel@tonic-gate * If we aren't doing Synchronous Data Transfers, 49807c478bd9Sstevel@tonic-gate * definitely offload the fifo. 49817c478bd9Sstevel@tonic-gate */ 49827c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 49837c478bd9Sstevel@tonic-gate } 49847c478bd9Sstevel@tonic-gate 49857c478bd9Sstevel@tonic-gate /* 49867c478bd9Sstevel@tonic-gate * adjust pointers... 49877c478bd9Sstevel@tonic-gate */ 49887c478bd9Sstevel@tonic-gate DPRINTF3("before:cmd_data_count=%x, cmd_cur_addr=%x, xfer_amt=%x\n", 49897c478bd9Sstevel@tonic-gate sp->cmd_data_count, sp->cmd_cur_addr, xfer_amt); 49907c478bd9Sstevel@tonic-gate sp->cmd_data_count += xfer_amt; 49917c478bd9Sstevel@tonic-gate sp->cmd_cur_addr += xfer_amt; 49927c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_XFERRED_DATA; 49937c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 49947c478bd9Sstevel@tonic-gate DPRINTF3("after:cmd_data_count=%x, cmd_cur_addr=%x, xfer_amt=%x\n", 49957c478bd9Sstevel@tonic-gate sp->cmd_data_count, sp->cmd_cur_addr, xfer_amt); 49967c478bd9Sstevel@tonic-gate 49977c478bd9Sstevel@tonic-gate stat &= FAS_PHASE_MASK; 49987c478bd9Sstevel@tonic-gate if (stat == FAS_PHASE_DATA_IN || stat == FAS_PHASE_DATA_OUT) { 49997c478bd9Sstevel@tonic-gate fas->f_state = ACTS_DATA; 50007c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 50017c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_DATA_DONE_ACTION1_END, 50027c478bd9Sstevel@tonic-gate "fas_handle_data_done_end (action1)"); 50037c478bd9Sstevel@tonic-gate return (fas_handle_data_start(fas)); 50047c478bd9Sstevel@tonic-gate } 50057c478bd9Sstevel@tonic-gate 50067c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_DATA_DONE_ACTION2_END, 50077c478bd9Sstevel@tonic-gate "fas_handle_data_done_end (action2)"); 50087c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 50097c478bd9Sstevel@tonic-gate } 50107c478bd9Sstevel@tonic-gate 50117c478bd9Sstevel@tonic-gate static char msginperr[] = "SCSI bus MESSAGE IN phase parity error"; 50127c478bd9Sstevel@tonic-gate 50137c478bd9Sstevel@tonic-gate static int 50147c478bd9Sstevel@tonic-gate fas_handle_c_cmplt(struct fas *fas) 50157c478bd9Sstevel@tonic-gate { 50167c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 50177c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 50187c478bd9Sstevel@tonic-gate uchar_t sts, msg, intr, perr; 50197c478bd9Sstevel@tonic-gate 50207c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_C_CMPLT_START, 50217c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_start"); 50227c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_c_cmplt:\n"); 50237c478bd9Sstevel@tonic-gate 50247c478bd9Sstevel@tonic-gate 50257c478bd9Sstevel@tonic-gate /* 50267c478bd9Sstevel@tonic-gate * if target is fast, we can get cmd. completion by the time we get 50277c478bd9Sstevel@tonic-gate * here. Otherwise, we'll have to taken an interrupt. 50287c478bd9Sstevel@tonic-gate */ 50297c478bd9Sstevel@tonic-gate if (fas->f_laststate == ACTS_UNKNOWN) { 50307c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 50317c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, 50327c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_stat); 50337c478bd9Sstevel@tonic-gate intr = fas_reg_read(fas, (uchar_t *)&fasreg->fas_intr); 50347c478bd9Sstevel@tonic-gate fas->f_intr = intr; 50357c478bd9Sstevel@tonic-gate if (fas->f_intr & (FAS_INT_RESET | FAS_INT_ILLEGAL)) { 50367c478bd9Sstevel@tonic-gate return (fas_illegal_cmd_or_bus_reset(fas)); 50377c478bd9Sstevel@tonic-gate } 50387c478bd9Sstevel@tonic-gate } else { 50397c478bd9Sstevel@tonic-gate /* 50407c478bd9Sstevel@tonic-gate * change f_laststate for the next time around 50417c478bd9Sstevel@tonic-gate */ 50427c478bd9Sstevel@tonic-gate fas->f_laststate = ACTS_C_CMPLT; 50437c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 50447c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_C_CMPLT_RETURN1_END, 50457c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (ACTION_RETURN1)"); 50467c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 50477c478bd9Sstevel@tonic-gate } 50487c478bd9Sstevel@tonic-gate } else { 50497c478bd9Sstevel@tonic-gate intr = fas->f_intr; 50507c478bd9Sstevel@tonic-gate } 50517c478bd9Sstevel@tonic-gate 50527c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 50537c478bd9Sstevel@tonic-gate if (fas_ptest_status & (1<<Tgt(sp))) { 50547c478bd9Sstevel@tonic-gate fas_ptest_status = 0; 50557c478bd9Sstevel@tonic-gate fas->f_stat |= FAS_STAT_PERR; 50567c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) { 50577c478bd9Sstevel@tonic-gate debug_enter("ptest_status"); 50587c478bd9Sstevel@tonic-gate } 50597c478bd9Sstevel@tonic-gate } else if ((fas_ptest_msgin & (1<<Tgt(sp))) && fas_ptest_msg == 0) { 50607c478bd9Sstevel@tonic-gate fas_ptest_msgin = 0; 50617c478bd9Sstevel@tonic-gate fas_ptest_msg = -1; 50627c478bd9Sstevel@tonic-gate fas->f_stat |= FAS_STAT_PERR; 50637c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) { 50647c478bd9Sstevel@tonic-gate debug_enter("ptest_completion"); 50657c478bd9Sstevel@tonic-gate } 50667c478bd9Sstevel@tonic-gate } 50677c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 50687c478bd9Sstevel@tonic-gate 50697c478bd9Sstevel@tonic-gate if (intr == FAS_INT_DISCON) { 50707c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 50717c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_C_CMPLT_ACTION1_END, 50727c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action1)"); 50737c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 50747c478bd9Sstevel@tonic-gate } 50757c478bd9Sstevel@tonic-gate 50767c478bd9Sstevel@tonic-gate if ((perr = (fas->f_stat & FAS_STAT_PERR)) != 0) { 50777c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 50787c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 50797c478bd9Sstevel@tonic-gate } 50807c478bd9Sstevel@tonic-gate 50817c478bd9Sstevel@tonic-gate /* 50827c478bd9Sstevel@tonic-gate * do a msg accept now and read the fifo data 50837c478bd9Sstevel@tonic-gate */ 50847c478bd9Sstevel@tonic-gate if (intr & FAS_INT_FCMP) { 50857c478bd9Sstevel@tonic-gate /* 50867c478bd9Sstevel@tonic-gate * The FAS manuals state that this sequence completes 50877c478bd9Sstevel@tonic-gate * with a BUS SERVICE interrupt if just the status 50887c478bd9Sstevel@tonic-gate * byte was received, else a FUNCTION COMPLETE interrupt 50897c478bd9Sstevel@tonic-gate * if both status and a message was received. 50907c478bd9Sstevel@tonic-gate * 50917c478bd9Sstevel@tonic-gate * if we give the MSG_ACT before reading the msg byte 50927c478bd9Sstevel@tonic-gate * we get the status byte again and if the status is zero 50937c478bd9Sstevel@tonic-gate * then we won't detect a failure 50947c478bd9Sstevel@tonic-gate */ 50957c478bd9Sstevel@tonic-gate *(sp->cmd_pkt->pkt_scbp) = 50967c478bd9Sstevel@tonic-gate sts = fas_reg_read(fas, (uchar_t *)&fasreg->fas_fifo_data); 50977c478bd9Sstevel@tonic-gate fas->f_last_msgin = fas->f_imsgarea[0] = 50987c478bd9Sstevel@tonic-gate msg = fas_reg_read(fas, (uchar_t *)&fasreg->fas_fifo_data); 50997c478bd9Sstevel@tonic-gate 51007c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_MSG_ACPT); 51017c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_GOT_STATUS; 51027c478bd9Sstevel@tonic-gate 51037c478bd9Sstevel@tonic-gate /* 51047c478bd9Sstevel@tonic-gate * The manuals also state that ATN* is asserted if 51057c478bd9Sstevel@tonic-gate * bad parity is detected. 51067c478bd9Sstevel@tonic-gate * 51077c478bd9Sstevel@tonic-gate * The one case that we cannot handle is where we detect 51087c478bd9Sstevel@tonic-gate * bad parity for the status byte, but the target refuses 51097c478bd9Sstevel@tonic-gate * to go to MESSAGE OUT phase right away. This means that 51107c478bd9Sstevel@tonic-gate * if that happens, we will misconstrue the parity error 51117c478bd9Sstevel@tonic-gate * to be for the completion message, not the status byte. 51127c478bd9Sstevel@tonic-gate */ 51137c478bd9Sstevel@tonic-gate if (perr) { 51147c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, msginperr); 51157c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 51167c478bd9Sstevel@tonic-gate 51177c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = MSG_MSG_PARITY; 51187c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 51197c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 51207c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 51217c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_C_CMPLT_ACTION5_END, 51227c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action5)"); 51237c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 51247c478bd9Sstevel@tonic-gate } 51257c478bd9Sstevel@tonic-gate 51267c478bd9Sstevel@tonic-gate } else if (intr == FAS_INT_BUS) { 51277c478bd9Sstevel@tonic-gate /* 51287c478bd9Sstevel@tonic-gate * We only got the status byte. 51297c478bd9Sstevel@tonic-gate */ 51307c478bd9Sstevel@tonic-gate sts = fas_reg_read(fas, (uchar_t *)&fasreg->fas_fifo_data); 51317c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_GOT_STATUS; 51327c478bd9Sstevel@tonic-gate *(sp->cmd_pkt->pkt_scbp) = sts; 51337c478bd9Sstevel@tonic-gate msg = INVALID_MSG; 51347c478bd9Sstevel@tonic-gate 51357c478bd9Sstevel@tonic-gate IPRINTF1("fas_handle_cmd_cmplt: sts=%x, no msg byte\n", sts); 51367c478bd9Sstevel@tonic-gate 51377c478bd9Sstevel@tonic-gate if (perr) { 51387c478bd9Sstevel@tonic-gate /* 51397c478bd9Sstevel@tonic-gate * If we get a parity error on a status byte 51407c478bd9Sstevel@tonic-gate * assume that it was a CHECK CONDITION 51417c478bd9Sstevel@tonic-gate */ 51427c478bd9Sstevel@tonic-gate sts = STATUS_CHECK; 51437c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 51447c478bd9Sstevel@tonic-gate "SCSI bus STATUS phase parity error"); 51457c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = MSG_INITIATOR_ERROR; 51467c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 51477c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 51487c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 51497c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_C_CMPLT_ACTION5_END, 51507c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action5)"); 51517c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 51527c478bd9Sstevel@tonic-gate } 51537c478bd9Sstevel@tonic-gate 51547c478bd9Sstevel@tonic-gate } else { 51557c478bd9Sstevel@tonic-gate msg = sts = INVALID_MSG; 51567c478bd9Sstevel@tonic-gate IPRINTF("fas_handle_cmd_cmplt: unexpected intr\n"); 51577c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 51587c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_C_CMPLT_ACTION2_END, 51597c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action2)"); 51607c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 51617c478bd9Sstevel@tonic-gate } 51627c478bd9Sstevel@tonic-gate 51637c478bd9Sstevel@tonic-gate EPRINTF2("fas_handle_c_cmplt: status=%x, msg=%x\n", sts, msg); 51647c478bd9Sstevel@tonic-gate 51657c478bd9Sstevel@tonic-gate EPRINTF1("Completion Message=%s\n", scsi_mname(msg)); 51667c478bd9Sstevel@tonic-gate if (msg == MSG_COMMAND_COMPLETE) { 51677c478bd9Sstevel@tonic-gate /* 51687c478bd9Sstevel@tonic-gate * Actually, if the message was a 'linked command 51697c478bd9Sstevel@tonic-gate * complete' message, the target isn't going to be 51707c478bd9Sstevel@tonic-gate * clearing the bus. 51717c478bd9Sstevel@tonic-gate */ 51727c478bd9Sstevel@tonic-gate New_state(fas, ACTS_CLEARING); 51737c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 51747c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_C_CMPLT_ACTION4_END, 51757c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action4)"); 51767c478bd9Sstevel@tonic-gate return (fas_handle_clearing(fas)); 51777c478bd9Sstevel@tonic-gate } else { 51787c478bd9Sstevel@tonic-gate fas->f_imsglen = 1; 51797c478bd9Sstevel@tonic-gate fas->f_imsgindex = 1; 51807c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_DONE); 51817c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 51827c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_C_CMPLT_ACTION3_END, 51837c478bd9Sstevel@tonic-gate "fas_handle_c_cmplt_end (action3)"); 51847c478bd9Sstevel@tonic-gate return (fas_handle_msg_in_done(fas)); 51857c478bd9Sstevel@tonic-gate } 51867c478bd9Sstevel@tonic-gate } 51877c478bd9Sstevel@tonic-gate 51887c478bd9Sstevel@tonic-gate /* 51897c478bd9Sstevel@tonic-gate * prepare for accepting a message byte from the fifo 51907c478bd9Sstevel@tonic-gate */ 51917c478bd9Sstevel@tonic-gate static int 51927c478bd9Sstevel@tonic-gate fas_handle_msg_in_start(struct fas *fas) 51937c478bd9Sstevel@tonic-gate { 51947c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_START, 51957c478bd9Sstevel@tonic-gate "fas_handle_msg_in_start"); 51967c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_msg_in_start\n"); 51977c478bd9Sstevel@tonic-gate 51987c478bd9Sstevel@tonic-gate /* 51997c478bd9Sstevel@tonic-gate * Pick up a message byte. 52007c478bd9Sstevel@tonic-gate * Clear the FIFO so we 52017c478bd9Sstevel@tonic-gate * don't get confused. 52027c478bd9Sstevel@tonic-gate */ 52037c478bd9Sstevel@tonic-gate if (!FIFO_EMPTY(fas)) { 52047c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 52057c478bd9Sstevel@tonic-gate } 52067c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_TRAN_INFO); 52077c478bd9Sstevel@tonic-gate fas->f_imsglen = 1; 52087c478bd9Sstevel@tonic-gate fas->f_imsgindex = 0; 52097c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_DONE); 52107c478bd9Sstevel@tonic-gate 52117c478bd9Sstevel@tonic-gate /* 52127c478bd9Sstevel@tonic-gate * give a little extra time by returning to phasemanage 52137c478bd9Sstevel@tonic-gate */ 52147c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_END, 52157c478bd9Sstevel@tonic-gate "fas_handle_msg_in_end (ACTION_PHASEMANAGE)"); 52167c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 52177c478bd9Sstevel@tonic-gate } 52187c478bd9Sstevel@tonic-gate 52197c478bd9Sstevel@tonic-gate /* 52207c478bd9Sstevel@tonic-gate * We come here after issuing a MSG_ACCEPT 52217c478bd9Sstevel@tonic-gate * command and are expecting more message bytes. 52227c478bd9Sstevel@tonic-gate * The FAS should be asserting a BUS SERVICE 52237c478bd9Sstevel@tonic-gate * interrupt status, but may have asserted 52247c478bd9Sstevel@tonic-gate * a different interrupt in the case that 52257c478bd9Sstevel@tonic-gate * the target disconnected and dropped BSY*. 52267c478bd9Sstevel@tonic-gate * 52277c478bd9Sstevel@tonic-gate * In the case that we are eating up message 52287c478bd9Sstevel@tonic-gate * bytes (and throwing them away unread) because 52297c478bd9Sstevel@tonic-gate * we have ATN* asserted (we are trying to send 52307c478bd9Sstevel@tonic-gate * a message), we do not consider it an error 52317c478bd9Sstevel@tonic-gate * if the phase has changed out of MESSAGE IN. 52327c478bd9Sstevel@tonic-gate */ 52337c478bd9Sstevel@tonic-gate static int 52347c478bd9Sstevel@tonic-gate fas_handle_more_msgin(struct fas *fas) 52357c478bd9Sstevel@tonic-gate { 52367c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MORE_MSGIN_START, 52377c478bd9Sstevel@tonic-gate "fas_handle_more_msgin_start"); 52387c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_more_msgin\n"); 52397c478bd9Sstevel@tonic-gate 52407c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_BUS) { 52417c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_PHASE_MASK) == FAS_PHASE_MSG_IN) { 52427c478bd9Sstevel@tonic-gate /* 52437c478bd9Sstevel@tonic-gate * Fetch another byte of a message in. 52447c478bd9Sstevel@tonic-gate */ 52457c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_TRAN_INFO); 52467c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_DONE); 52477c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 52487c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MORE_MSGIN_RETURN1_END, 52497c478bd9Sstevel@tonic-gate "fas_handle_more_msgin_end (ACTION_RETURN)"); 52507c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 52517c478bd9Sstevel@tonic-gate } 52527c478bd9Sstevel@tonic-gate 52537c478bd9Sstevel@tonic-gate /* 52547c478bd9Sstevel@tonic-gate * If we were gobbling up a message and we have 52557c478bd9Sstevel@tonic-gate * changed phases, handle this silently, else 52567c478bd9Sstevel@tonic-gate * complain. In either case, we return to let 52577c478bd9Sstevel@tonic-gate * fas_phasemanage() handle things. 52587c478bd9Sstevel@tonic-gate * 52597c478bd9Sstevel@tonic-gate * If it wasn't a BUS SERVICE interrupt, 52607c478bd9Sstevel@tonic-gate * let fas_phasemanage() find out if the 52617c478bd9Sstevel@tonic-gate * chip disconnected. 52627c478bd9Sstevel@tonic-gate */ 52637c478bd9Sstevel@tonic-gate if (fas->f_imsglen != 0) { 52647c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 52657c478bd9Sstevel@tonic-gate "Premature end of extended message"); 52667c478bd9Sstevel@tonic-gate } 52677c478bd9Sstevel@tonic-gate } 52687c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 52697c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MORE_MSGIN_RETURN2_END, 52707c478bd9Sstevel@tonic-gate "fas_handle_more_msgin_end (action)"); 52717c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 52727c478bd9Sstevel@tonic-gate } 52737c478bd9Sstevel@tonic-gate 52747c478bd9Sstevel@tonic-gate static int 52757c478bd9Sstevel@tonic-gate fas_handle_msg_in_done(struct fas *fas) 52767c478bd9Sstevel@tonic-gate { 52777c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 52787c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 52797c478bd9Sstevel@tonic-gate int sndmsg = 0; 52807c478bd9Sstevel@tonic-gate uchar_t msgin; 52817c478bd9Sstevel@tonic-gate 52827c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_DONE_START, 52837c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_start"); 52847c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_msg_in_done:\n"); 52857c478bd9Sstevel@tonic-gate if (fas->f_laststate == ACTS_MSG_IN) { 52867c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 52877c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, 52887c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_stat); 52897c478bd9Sstevel@tonic-gate fas->f_stat2 = fas_reg_read(fas, 52907c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_stat2); 52917c478bd9Sstevel@tonic-gate 52927c478bd9Sstevel@tonic-gate fas_read_fifo(fas); 52937c478bd9Sstevel@tonic-gate 52947c478bd9Sstevel@tonic-gate fas->f_intr = fas_reg_read(fas, 52957c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_intr); 52967c478bd9Sstevel@tonic-gate if (fas->f_intr & (FAS_INT_RESET | FAS_INT_ILLEGAL)) { 52977c478bd9Sstevel@tonic-gate return (fas_illegal_cmd_or_bus_reset(fas)); 52987c478bd9Sstevel@tonic-gate } 52997c478bd9Sstevel@tonic-gate } else { 53007c478bd9Sstevel@tonic-gate /* 53017c478bd9Sstevel@tonic-gate * change f_laststate for the next time around 53027c478bd9Sstevel@tonic-gate */ 53037c478bd9Sstevel@tonic-gate fas->f_laststate = ACTS_MSG_IN_DONE; 53047c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 53057c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MSG_IN_DONE_RETURN1_END, 53067c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (ACTION_RETURN1)"); 53077c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 53087c478bd9Sstevel@tonic-gate } 53097c478bd9Sstevel@tonic-gate } 53107c478bd9Sstevel@tonic-gate 53117c478bd9Sstevel@tonic-gate /* 53127c478bd9Sstevel@tonic-gate * the most common case is a disconnect message. we do 53137c478bd9Sstevel@tonic-gate * a fast path for this condition and if it fails then 53147c478bd9Sstevel@tonic-gate * we go for the detailed error handling 53157c478bd9Sstevel@tonic-gate */ 53167c478bd9Sstevel@tonic-gate #ifndef FAS_TEST 53177c478bd9Sstevel@tonic-gate if (((fas->f_laststate == ACTS_MSG_IN) || 53187c478bd9Sstevel@tonic-gate (fas->f_laststate == ACTS_MSG_IN_DONE)) && 53197c478bd9Sstevel@tonic-gate ((fas->f_intr & FAS_INT_DISCON) == 0) && 53207c478bd9Sstevel@tonic-gate ((fas->f_stat & FAS_STAT_PERR) == 0) && 53217c478bd9Sstevel@tonic-gate ((sp->cmd_pkt_flags & FLAG_NODISCON) == 0)) { 53227c478bd9Sstevel@tonic-gate 53237c478bd9Sstevel@tonic-gate if ((fas->f_fifolen == 1) && 53247c478bd9Sstevel@tonic-gate (fas->f_imsglen == 1) && 53257c478bd9Sstevel@tonic-gate (fas->f_fifo[0] == MSG_DISCONNECT)) { 53267c478bd9Sstevel@tonic-gate 53277c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_MSG_ACPT); 53287c478bd9Sstevel@tonic-gate fas->f_imsgarea[fas->f_imsgindex++] = fas->f_fifo[0]; 53297c478bd9Sstevel@tonic-gate fas->f_last_msgin = MSG_DISCONNECT; 53307c478bd9Sstevel@tonic-gate New_state(fas, ACTS_CLEARING); 53317c478bd9Sstevel@tonic-gate 53327c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 53337c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MSG_IN_DONE_ACTION_END, 53347c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (action)"); 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate return (fas_handle_clearing(fas)); 53377c478bd9Sstevel@tonic-gate } 53387c478bd9Sstevel@tonic-gate } 53397c478bd9Sstevel@tonic-gate #endif /* not FAS_TEST */ 53407c478bd9Sstevel@tonic-gate 53417c478bd9Sstevel@tonic-gate /* 53427c478bd9Sstevel@tonic-gate * We can be called here for both the case where 53437c478bd9Sstevel@tonic-gate * we had requested the FAS chip to fetch a message 53447c478bd9Sstevel@tonic-gate * byte from the target (at the target's request). 53457c478bd9Sstevel@tonic-gate * We can also be called in the case where we had 53467c478bd9Sstevel@tonic-gate * been using the CMD_COMP_SEQ command to pick up 53477c478bd9Sstevel@tonic-gate * both a status byte and a completion message from 53487c478bd9Sstevel@tonic-gate * a target, but where the message wasn't one of 53497c478bd9Sstevel@tonic-gate * COMMAND COMPLETE, LINKED COMMAND COMPLETE, or 53507c478bd9Sstevel@tonic-gate * LINKED COMMAND COMPLETE (with flag). This is a 53517c478bd9Sstevel@tonic-gate * legal (albeit extremely unusual) SCSI bus trans- 53527c478bd9Sstevel@tonic-gate * -ition, so we have to handle it. 53537c478bd9Sstevel@tonic-gate */ 53547c478bd9Sstevel@tonic-gate if (fas->f_laststate != ACTS_C_CMPLT) { 53557c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 53567c478bd9Sstevel@tonic-gate reloop: 53577c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 53587c478bd9Sstevel@tonic-gate 53597c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_DISCON) { 53607c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 53617c478bd9Sstevel@tonic-gate "premature end of input message"); 53627c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 53637c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 53647c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MSG_IN_DONE_PHASEMANAGE_END, 53657c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (ACTION_PHASEMANAGE)"); 53667c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 53677c478bd9Sstevel@tonic-gate } 53687c478bd9Sstevel@tonic-gate 53697c478bd9Sstevel@tonic-gate /* 53707c478bd9Sstevel@tonic-gate * Note that if f_imsglen is zero, then we are skipping 53717c478bd9Sstevel@tonic-gate * input message bytes, so there is no reason to look for 53727c478bd9Sstevel@tonic-gate * parity errors. 53737c478bd9Sstevel@tonic-gate */ 53747c478bd9Sstevel@tonic-gate if (fas->f_imsglen != 0 && (fas->f_stat & FAS_STAT_PERR)) { 53757c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, msginperr); 53767c478bd9Sstevel@tonic-gate sndmsg = MSG_MSG_PARITY; 53777c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 53787c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 53797c478bd9Sstevel@tonic-gate 53807c478bd9Sstevel@tonic-gate } else if ((msgin = fas->f_fifolen) != 1) { 53817c478bd9Sstevel@tonic-gate 53827c478bd9Sstevel@tonic-gate /* 53837c478bd9Sstevel@tonic-gate * If we have got more than one or 0 bytes in the fifo, 53847c478bd9Sstevel@tonic-gate * that is a gross screwup, and we should let the 53857c478bd9Sstevel@tonic-gate * target know that we have completely fouled up. 53867c478bd9Sstevel@tonic-gate */ 53877c478bd9Sstevel@tonic-gate fas_printf(fas, "fifocount=%x", msgin); 53887c478bd9Sstevel@tonic-gate fas_printstate(fas, "input message botch"); 53897c478bd9Sstevel@tonic-gate sndmsg = MSG_INITIATOR_ERROR; 53907c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 53917c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "input message botch"); 53927c478bd9Sstevel@tonic-gate 53937c478bd9Sstevel@tonic-gate } else if (fas->f_imsglen == 0) { 53947c478bd9Sstevel@tonic-gate /* 53957c478bd9Sstevel@tonic-gate * If we are in the middle of gobbling up and throwing 53967c478bd9Sstevel@tonic-gate * away a message (due to a previous message input 53977c478bd9Sstevel@tonic-gate * error), drive on. 53987c478bd9Sstevel@tonic-gate */ 53997c478bd9Sstevel@tonic-gate msgin = fas_reg_read(fas, 54007c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_fifo_data); 54017c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_MORE); 54027c478bd9Sstevel@tonic-gate 54037c478bd9Sstevel@tonic-gate } else { 54047c478bd9Sstevel@tonic-gate msgin = fas->f_fifo[0]; 54057c478bd9Sstevel@tonic-gate fas->f_imsgarea[fas->f_imsgindex++] = msgin; 54067c478bd9Sstevel@tonic-gate } 54077c478bd9Sstevel@tonic-gate 54087c478bd9Sstevel@tonic-gate } else { 54097c478bd9Sstevel@tonic-gate /* 54107c478bd9Sstevel@tonic-gate * In this case, we have been called (from 54117c478bd9Sstevel@tonic-gate * fas_handle_c_cmplt()) with the message 54127c478bd9Sstevel@tonic-gate * already stored in the message array. 54137c478bd9Sstevel@tonic-gate */ 54147c478bd9Sstevel@tonic-gate msgin = fas->f_imsgarea[0]; 54157c478bd9Sstevel@tonic-gate } 54167c478bd9Sstevel@tonic-gate 54177c478bd9Sstevel@tonic-gate /* 54187c478bd9Sstevel@tonic-gate * Process this message byte (but not if we are 54197c478bd9Sstevel@tonic-gate * going to be trying to send back some error 54207c478bd9Sstevel@tonic-gate * anyway) 54217c478bd9Sstevel@tonic-gate */ 54227c478bd9Sstevel@tonic-gate if (sndmsg == 0 && fas->f_imsglen != 0) { 54237c478bd9Sstevel@tonic-gate 54247c478bd9Sstevel@tonic-gate if (fas->f_imsgindex < fas->f_imsglen) { 54257c478bd9Sstevel@tonic-gate 54267c478bd9Sstevel@tonic-gate EPRINTF2("message byte %d: 0x%x\n", 54277c478bd9Sstevel@tonic-gate fas->f_imsgindex-1, 54287c478bd9Sstevel@tonic-gate fas->f_imsgarea[fas->f_imsgindex-1]); 54297c478bd9Sstevel@tonic-gate 54307c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_MORE); 54317c478bd9Sstevel@tonic-gate 54327c478bd9Sstevel@tonic-gate } else if (fas->f_imsglen == 1) { 54337c478bd9Sstevel@tonic-gate 54347c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 54357c478bd9Sstevel@tonic-gate if ((fas_ptest_msgin & (1<<Tgt(sp))) && 54367c478bd9Sstevel@tonic-gate fas_ptest_msg == msgin) { 54377c478bd9Sstevel@tonic-gate fas_ptest_msgin = 0; 54387c478bd9Sstevel@tonic-gate fas_ptest_msg = -1; 54397c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 54407c478bd9Sstevel@tonic-gate fas->f_stat |= FAS_STAT_PERR; 54417c478bd9Sstevel@tonic-gate fas->f_imsgindex -= 1; 54427c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) { 54437c478bd9Sstevel@tonic-gate debug_enter("ptest msgin"); 54447c478bd9Sstevel@tonic-gate } 54457c478bd9Sstevel@tonic-gate goto reloop; 54467c478bd9Sstevel@tonic-gate } 54477c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 54487c478bd9Sstevel@tonic-gate 54497c478bd9Sstevel@tonic-gate sndmsg = fas_onebyte_msg(fas); 54507c478bd9Sstevel@tonic-gate 54517c478bd9Sstevel@tonic-gate } else if (fas->f_imsglen == 2) { 54527c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 54537c478bd9Sstevel@tonic-gate if (fas_ptest_emsgin & (1<<Tgt(sp))) { 54547c478bd9Sstevel@tonic-gate fas_ptest_emsgin = 0; 54557c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 54567c478bd9Sstevel@tonic-gate fas->f_stat |= FAS_STAT_PERR; 54577c478bd9Sstevel@tonic-gate fas->f_imsgindex -= 1; 54587c478bd9Sstevel@tonic-gate if (fas_test_stop > 1) { 54597c478bd9Sstevel@tonic-gate debug_enter("ptest emsgin"); 54607c478bd9Sstevel@tonic-gate } 54617c478bd9Sstevel@tonic-gate goto reloop; 54627c478bd9Sstevel@tonic-gate } 54637c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 54647c478bd9Sstevel@tonic-gate 54657c478bd9Sstevel@tonic-gate if (fas->f_imsgarea[0] == MSG_EXTENDED) { 54667c478bd9Sstevel@tonic-gate static char *tool = 54677c478bd9Sstevel@tonic-gate "Extended message 0x%x is too long"; 54687c478bd9Sstevel@tonic-gate 54697c478bd9Sstevel@tonic-gate /* 54707c478bd9Sstevel@tonic-gate * Is the incoming message too long 54717c478bd9Sstevel@tonic-gate * to be stored in our local array? 54727c478bd9Sstevel@tonic-gate */ 54737c478bd9Sstevel@tonic-gate if ((int)(msgin+2) > IMSGSIZE) { 54747c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 54757c478bd9Sstevel@tonic-gate tool, fas->f_imsgarea[0]); 54767c478bd9Sstevel@tonic-gate sndmsg = MSG_REJECT; 54777c478bd9Sstevel@tonic-gate } else { 54787c478bd9Sstevel@tonic-gate fas->f_imsglen = msgin + 2; 54797c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_MORE); 54807c478bd9Sstevel@tonic-gate } 54817c478bd9Sstevel@tonic-gate } else { 54827c478bd9Sstevel@tonic-gate sndmsg = fas_twobyte_msg(fas); 54837c478bd9Sstevel@tonic-gate } 54847c478bd9Sstevel@tonic-gate 54857c478bd9Sstevel@tonic-gate } else { 54867c478bd9Sstevel@tonic-gate sndmsg = fas_multibyte_msg(fas); 54877c478bd9Sstevel@tonic-gate } 54887c478bd9Sstevel@tonic-gate } 54897c478bd9Sstevel@tonic-gate 54907c478bd9Sstevel@tonic-gate if (sndmsg < 0) { 54917c478bd9Sstevel@tonic-gate /* 54927c478bd9Sstevel@tonic-gate * If sndmsg is less than zero, one of the subsidiary 54937c478bd9Sstevel@tonic-gate * routines needs to return some other state than 54947c478bd9Sstevel@tonic-gate * ACTION_RETURN. 54957c478bd9Sstevel@tonic-gate */ 54967c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_DONE_SNDMSG_END, 54977c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (-sndmsg)"); 54987c478bd9Sstevel@tonic-gate return (-sndmsg); 54997c478bd9Sstevel@tonic-gate 55007c478bd9Sstevel@tonic-gate } else if (sndmsg > 0) { 55017c478bd9Sstevel@tonic-gate if (IS_1BYTE_MSG(sndmsg)) { 55027c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 55037c478bd9Sstevel@tonic-gate } 55047c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = (uchar_t)sndmsg; 55057c478bd9Sstevel@tonic-gate 55067c478bd9Sstevel@tonic-gate /* 55077c478bd9Sstevel@tonic-gate * The target is not guaranteed to go to message out 55087c478bd9Sstevel@tonic-gate * phase, period. Moreover, until the entire incoming 55097c478bd9Sstevel@tonic-gate * message is transferred, the target may (and likely 55107c478bd9Sstevel@tonic-gate * will) continue to transfer message bytes (which 55117c478bd9Sstevel@tonic-gate * we will have to ignore). 55127c478bd9Sstevel@tonic-gate * 55137c478bd9Sstevel@tonic-gate * In order to do this, we'll go to 'infinite' 55147c478bd9Sstevel@tonic-gate * message in handling by setting the current input 55157c478bd9Sstevel@tonic-gate * message length to a sentinel of zero. 55167c478bd9Sstevel@tonic-gate * 55177c478bd9Sstevel@tonic-gate * This works regardless of the message we are trying 55187c478bd9Sstevel@tonic-gate * to send out. At the point in time which we want 55197c478bd9Sstevel@tonic-gate * to send a message in response to an incoming message 55207c478bd9Sstevel@tonic-gate * we do not care any more about the incoming message. 55217c478bd9Sstevel@tonic-gate * 55227c478bd9Sstevel@tonic-gate * If we are sending a message in response to detecting 55237c478bd9Sstevel@tonic-gate * a parity error on input, the FAS chip has already 55247c478bd9Sstevel@tonic-gate * set ATN* for us, but it doesn't hurt to set it here 55257c478bd9Sstevel@tonic-gate * again anyhow. 55267c478bd9Sstevel@tonic-gate */ 55277c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 55287c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_MORE); 55297c478bd9Sstevel@tonic-gate fas->f_imsglen = 0; 55307c478bd9Sstevel@tonic-gate } 55317c478bd9Sstevel@tonic-gate 55327c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 55337c478bd9Sstevel@tonic-gate 55347c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_MSG_ACPT); 55357c478bd9Sstevel@tonic-gate 55367c478bd9Sstevel@tonic-gate if ((fas->f_laststate == ACTS_MSG_IN_DONE) && 55377c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_CLEARING)) { 55387c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_DONE_ACTION_END, 55397c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (action)"); 55407c478bd9Sstevel@tonic-gate return (fas_handle_clearing(fas)); 55417c478bd9Sstevel@tonic-gate } 55427c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_IN_DONE_RETURN2_END, 55437c478bd9Sstevel@tonic-gate "fas_handle_msg_in_done_end (ACTION_RETURN2)"); 55447c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 55457c478bd9Sstevel@tonic-gate } 55467c478bd9Sstevel@tonic-gate 55477c478bd9Sstevel@tonic-gate static int 55487c478bd9Sstevel@tonic-gate fas_onebyte_msg(struct fas *fas) 55497c478bd9Sstevel@tonic-gate { 55507c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 55517c478bd9Sstevel@tonic-gate int msgout = 0; 55527c478bd9Sstevel@tonic-gate uchar_t msgin = fas->f_last_msgin = fas->f_imsgarea[0]; 55537c478bd9Sstevel@tonic-gate int tgt = Tgt(sp); 55547c478bd9Sstevel@tonic-gate 55557c478bd9Sstevel@tonic-gate EPRINTF("fas_onebyte_msg\n"); 55567c478bd9Sstevel@tonic-gate 55577c478bd9Sstevel@tonic-gate if (msgin & MSG_IDENTIFY) { 55587c478bd9Sstevel@tonic-gate /* 55597c478bd9Sstevel@tonic-gate * How did we get here? We should only see identify 55607c478bd9Sstevel@tonic-gate * messages on a reconnection, but we'll handle this 55617c478bd9Sstevel@tonic-gate * fine here (just in case we get this) as long as 55627c478bd9Sstevel@tonic-gate * we believe that this is a valid identify message. 55637c478bd9Sstevel@tonic-gate * 55647c478bd9Sstevel@tonic-gate * For this to be a valid incoming message, 55657c478bd9Sstevel@tonic-gate * bits 6-4 must must be zero. Also, the 55667c478bd9Sstevel@tonic-gate * bit that says that I'm an initiator and 55677c478bd9Sstevel@tonic-gate * can support disconnection cannot possibly 55687c478bd9Sstevel@tonic-gate * be set here. 55697c478bd9Sstevel@tonic-gate */ 55707c478bd9Sstevel@tonic-gate 55717c478bd9Sstevel@tonic-gate char garbled = ((msgin & (BAD_IDENTIFY|INI_CAN_DISCON)) != 0); 55727c478bd9Sstevel@tonic-gate 55737c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "%s message 0x%x from Target %d", 55747c478bd9Sstevel@tonic-gate garbled ? "Garbled" : "Identify", msgin, tgt); 55757c478bd9Sstevel@tonic-gate 55767c478bd9Sstevel@tonic-gate if (garbled) { 55777c478bd9Sstevel@tonic-gate /* 55787c478bd9Sstevel@tonic-gate * If it's a garbled message, 55797c478bd9Sstevel@tonic-gate * try and tell the target... 55807c478bd9Sstevel@tonic-gate */ 55817c478bd9Sstevel@tonic-gate msgout = MSG_INITIATOR_ERROR; 55827c478bd9Sstevel@tonic-gate } else { 55837c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 55847c478bd9Sstevel@tonic-gate } 55857c478bd9Sstevel@tonic-gate return (msgout); 55867c478bd9Sstevel@tonic-gate 55877c478bd9Sstevel@tonic-gate } else if (IS_2BYTE_MSG(msgin) || IS_EXTENDED_MSG(msgin)) { 55887c478bd9Sstevel@tonic-gate fas->f_imsglen = 2; 55897c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_IN_MORE); 55907c478bd9Sstevel@tonic-gate return (0); 55917c478bd9Sstevel@tonic-gate } 55927c478bd9Sstevel@tonic-gate 55937c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 55947c478bd9Sstevel@tonic-gate 55957c478bd9Sstevel@tonic-gate switch (msgin) { 55967c478bd9Sstevel@tonic-gate case MSG_DISCONNECT: 55977c478bd9Sstevel@tonic-gate /* 55987c478bd9Sstevel@tonic-gate * If we 'cannot' disconnect- reject this message. 55997c478bd9Sstevel@tonic-gate * Note that we only key off of the pkt_flags here- 56007c478bd9Sstevel@tonic-gate * the FLAG_NODISCON was set in fas_accept_pkt() if 56017c478bd9Sstevel@tonic-gate * no disconnect was enabled in scsi_options 56027c478bd9Sstevel@tonic-gate */ 56037c478bd9Sstevel@tonic-gate if (sp->cmd_pkt_flags & FLAG_NODISCON) { 56047c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 56057c478bd9Sstevel@tonic-gate break; 56067c478bd9Sstevel@tonic-gate } 56077c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 56087c478bd9Sstevel@tonic-gate case MSG_COMMAND_COMPLETE: 56097c478bd9Sstevel@tonic-gate fas->f_state = ACTS_CLEARING; 56107c478bd9Sstevel@tonic-gate break; 56117c478bd9Sstevel@tonic-gate 56127c478bd9Sstevel@tonic-gate case MSG_NOP: 56137c478bd9Sstevel@tonic-gate break; 56147c478bd9Sstevel@tonic-gate 56157c478bd9Sstevel@tonic-gate /* XXX Make it a MSG_REJECT handler */ 56167c478bd9Sstevel@tonic-gate case MSG_REJECT: 56177c478bd9Sstevel@tonic-gate { 56187c478bd9Sstevel@tonic-gate uchar_t reason = 0; 56197c478bd9Sstevel@tonic-gate uchar_t lastmsg = fas->f_last_msgout; 56207c478bd9Sstevel@tonic-gate /* 56217c478bd9Sstevel@tonic-gate * The target is rejecting the last message we sent. 56227c478bd9Sstevel@tonic-gate * 56237c478bd9Sstevel@tonic-gate * If the last message we attempted to send out was an 56247c478bd9Sstevel@tonic-gate * extended message, we were trying to negotiate sync 56257c478bd9Sstevel@tonic-gate * xfers- and we're okay. 56267c478bd9Sstevel@tonic-gate * 56277c478bd9Sstevel@tonic-gate * Otherwise, a target has rejected a message that 56287c478bd9Sstevel@tonic-gate * it should have handled. We will abort the operation 56297c478bd9Sstevel@tonic-gate * in progress and set the pkt_reason value here to 56307c478bd9Sstevel@tonic-gate * show why we have completed. The process of aborting 56317c478bd9Sstevel@tonic-gate * may be via a message or may be via a bus reset (as 56327c478bd9Sstevel@tonic-gate * a last resort). 56337c478bd9Sstevel@tonic-gate */ 56347c478bd9Sstevel@tonic-gate msgout = (TAGGED(tgt)? MSG_ABORT_TAG : MSG_ABORT); 56357c478bd9Sstevel@tonic-gate 56367c478bd9Sstevel@tonic-gate switch (lastmsg) { 56377c478bd9Sstevel@tonic-gate case MSG_EXTENDED: 56387c478bd9Sstevel@tonic-gate if (fas->f_wdtr_sent) { 56397c478bd9Sstevel@tonic-gate /* 56407c478bd9Sstevel@tonic-gate * Disable wide, Target rejected 56417c478bd9Sstevel@tonic-gate * out WDTR message 56427c478bd9Sstevel@tonic-gate */ 56437c478bd9Sstevel@tonic-gate fas_set_wide_conf3(fas, tgt, 0); 56447c478bd9Sstevel@tonic-gate fas->f_nowide |= (1<<tgt); 56457c478bd9Sstevel@tonic-gate fas->f_wdtr_sent = 0; 56467c478bd9Sstevel@tonic-gate /* 56477c478bd9Sstevel@tonic-gate * we still want to negotiate sync 56487c478bd9Sstevel@tonic-gate */ 56497c478bd9Sstevel@tonic-gate if ((fas->f_nosync & (1<<tgt)) == 0) { 56507c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 56517c478bd9Sstevel@tonic-gate fas_make_sdtr(fas, 0, tgt); 56527c478bd9Sstevel@tonic-gate } 56537c478bd9Sstevel@tonic-gate } else if (fas->f_sdtr_sent) { 56547c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_CLR_ATN); 56557c478bd9Sstevel@tonic-gate fas_revert_to_async(fas, tgt); 56567c478bd9Sstevel@tonic-gate fas->f_nosync |= (1<<tgt); 56577c478bd9Sstevel@tonic-gate fas->f_sdtr_sent = 0; 56587c478bd9Sstevel@tonic-gate } 56597c478bd9Sstevel@tonic-gate msgout = 0; 56607c478bd9Sstevel@tonic-gate break; 56617c478bd9Sstevel@tonic-gate case MSG_NOP: 56627c478bd9Sstevel@tonic-gate reason = CMD_NOP_FAIL; 56637c478bd9Sstevel@tonic-gate break; 56647c478bd9Sstevel@tonic-gate case MSG_INITIATOR_ERROR: 56657c478bd9Sstevel@tonic-gate reason = CMD_IDE_FAIL; 56667c478bd9Sstevel@tonic-gate break; 56677c478bd9Sstevel@tonic-gate case MSG_MSG_PARITY: 56687c478bd9Sstevel@tonic-gate reason = CMD_PER_FAIL; 56697c478bd9Sstevel@tonic-gate break; 56707c478bd9Sstevel@tonic-gate case MSG_REJECT: 56717c478bd9Sstevel@tonic-gate reason = CMD_REJECT_FAIL; 56727c478bd9Sstevel@tonic-gate break; 56737c478bd9Sstevel@tonic-gate /* XXX - abort not good, queue full handling or drain (?) */ 56747c478bd9Sstevel@tonic-gate case MSG_SIMPLE_QTAG: 56757c478bd9Sstevel@tonic-gate case MSG_ORDERED_QTAG: 56767c478bd9Sstevel@tonic-gate case MSG_HEAD_QTAG: 56777c478bd9Sstevel@tonic-gate msgout = MSG_ABORT; 56787c478bd9Sstevel@tonic-gate reason = CMD_TAG_REJECT; 56797c478bd9Sstevel@tonic-gate break; 56807c478bd9Sstevel@tonic-gate case MSG_DEVICE_RESET: 56817c478bd9Sstevel@tonic-gate reason = CMD_BDR_FAIL; 56827c478bd9Sstevel@tonic-gate msgout = -ACTION_ABORT_CURCMD; 56837c478bd9Sstevel@tonic-gate break; 56847c478bd9Sstevel@tonic-gate case MSG_ABORT: 56857c478bd9Sstevel@tonic-gate case MSG_ABORT_TAG: 56867c478bd9Sstevel@tonic-gate /* 56877c478bd9Sstevel@tonic-gate * If an RESET/ABORT OPERATION message is rejected 56887c478bd9Sstevel@tonic-gate * it is time to yank the chain on the bus... 56897c478bd9Sstevel@tonic-gate */ 56907c478bd9Sstevel@tonic-gate reason = CMD_ABORT_FAIL; 56917c478bd9Sstevel@tonic-gate msgout = -ACTION_ABORT_CURCMD; 56927c478bd9Sstevel@tonic-gate break; 56937c478bd9Sstevel@tonic-gate default: 56947c478bd9Sstevel@tonic-gate if (IS_IDENTIFY_MSG(lastmsg)) { 56957c478bd9Sstevel@tonic-gate if (TAGGED(tgt)) { 56967c478bd9Sstevel@tonic-gate /* 56977c478bd9Sstevel@tonic-gate * this often happens when the 56987c478bd9Sstevel@tonic-gate * target rejected our tag 56997c478bd9Sstevel@tonic-gate */ 57007c478bd9Sstevel@tonic-gate reason = CMD_TAG_REJECT; 57017c478bd9Sstevel@tonic-gate } else { 57027c478bd9Sstevel@tonic-gate reason = CMD_ID_FAIL; 57037c478bd9Sstevel@tonic-gate } 57047c478bd9Sstevel@tonic-gate } else { 57057c478bd9Sstevel@tonic-gate reason = CMD_TRAN_ERR; 57067c478bd9Sstevel@tonic-gate msgout = -ACTION_ABORT_CURCMD; 57077c478bd9Sstevel@tonic-gate } 57087c478bd9Sstevel@tonic-gate 57097c478bd9Sstevel@tonic-gate break; 57107c478bd9Sstevel@tonic-gate } 57117c478bd9Sstevel@tonic-gate 57127c478bd9Sstevel@tonic-gate if (msgout) { 57137c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 57147c478bd9Sstevel@tonic-gate "Target %d rejects our message '%s'", 57157c478bd9Sstevel@tonic-gate tgt, scsi_mname(lastmsg)); 57167c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, reason, 0); 57177c478bd9Sstevel@tonic-gate } 57187c478bd9Sstevel@tonic-gate 57197c478bd9Sstevel@tonic-gate break; 57207c478bd9Sstevel@tonic-gate } 57217c478bd9Sstevel@tonic-gate case MSG_RESTORE_PTRS: 57227c478bd9Sstevel@tonic-gate sp->cmd_cdbp = sp->cmd_pkt->pkt_cdbp; 57237c478bd9Sstevel@tonic-gate if (sp->cmd_data_count != sp->cmd_saved_data_count) { 57247c478bd9Sstevel@tonic-gate if (fas_restore_pointers(fas, sp)) { 57257c478bd9Sstevel@tonic-gate msgout = -ACTION_ABORT_CURCMD; 57267c478bd9Sstevel@tonic-gate } else if ((sp->cmd_pkt->pkt_reason & CMD_TRAN_ERR) && 57277c478bd9Sstevel@tonic-gate (sp->cmd_pkt->pkt_statistics & STAT_PERR) && 57287c478bd9Sstevel@tonic-gate (sp->cmd_cur_win == 0) && 57297c478bd9Sstevel@tonic-gate (sp->cmd_data_count == 0)) { 57307c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason &= ~CMD_TRAN_ERR; 57317c478bd9Sstevel@tonic-gate } 57327c478bd9Sstevel@tonic-gate } 57337c478bd9Sstevel@tonic-gate break; 57347c478bd9Sstevel@tonic-gate 57357c478bd9Sstevel@tonic-gate case MSG_SAVE_DATA_PTR: 57367c478bd9Sstevel@tonic-gate sp->cmd_saved_data_count = sp->cmd_data_count; 57377c478bd9Sstevel@tonic-gate sp->cmd_saved_win = sp->cmd_cur_win; 57387c478bd9Sstevel@tonic-gate sp->cmd_saved_cur_addr = sp->cmd_cur_addr; 57397c478bd9Sstevel@tonic-gate break; 57407c478bd9Sstevel@tonic-gate 57417c478bd9Sstevel@tonic-gate /* These don't make sense for us, and */ 57427c478bd9Sstevel@tonic-gate /* will be rejected */ 57437c478bd9Sstevel@tonic-gate /* case MSG_INITIATOR_ERROR */ 57447c478bd9Sstevel@tonic-gate /* case MSG_ABORT */ 57457c478bd9Sstevel@tonic-gate /* case MSG_MSG_PARITY */ 57467c478bd9Sstevel@tonic-gate /* case MSG_DEVICE_RESET */ 57477c478bd9Sstevel@tonic-gate default: 57487c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 57497c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 57507c478bd9Sstevel@tonic-gate "Rejecting message '%s' from Target %d", 57517c478bd9Sstevel@tonic-gate scsi_mname(msgin), tgt); 57527c478bd9Sstevel@tonic-gate break; 57537c478bd9Sstevel@tonic-gate } 57547c478bd9Sstevel@tonic-gate 57557c478bd9Sstevel@tonic-gate EPRINTF1("Message in: %s\n", scsi_mname(msgin)); 57567c478bd9Sstevel@tonic-gate 57577c478bd9Sstevel@tonic-gate return (msgout); 57587c478bd9Sstevel@tonic-gate } 57597c478bd9Sstevel@tonic-gate 57607c478bd9Sstevel@tonic-gate /* 57617c478bd9Sstevel@tonic-gate * phase handlers that are rarely used 57627c478bd9Sstevel@tonic-gate */ 57637c478bd9Sstevel@tonic-gate static int 57647c478bd9Sstevel@tonic-gate fas_handle_cmd_start(struct fas *fas) 57657c478bd9Sstevel@tonic-gate { 57667c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 57677c478bd9Sstevel@tonic-gate volatile uchar_t *tp = fas->f_cmdarea; 57687c478bd9Sstevel@tonic-gate int i; 57697c478bd9Sstevel@tonic-gate int amt = sp->cmd_cdblen; 57707c478bd9Sstevel@tonic-gate 57717c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CMD_START_START, 57727c478bd9Sstevel@tonic-gate "fas_handle_cmd_start_start"); 57737c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_cmd: send cmd\n"); 57747c478bd9Sstevel@tonic-gate 57757c478bd9Sstevel@tonic-gate for (i = 0; i < amt; i++) { 57767c478bd9Sstevel@tonic-gate *tp++ = sp->cmd_cdbp[i]; 57777c478bd9Sstevel@tonic-gate } 57787c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 57797c478bd9Sstevel@tonic-gate 57807c478bd9Sstevel@tonic-gate FAS_DMA_READ(fas, amt, fas->f_dmacookie.dmac_address, amt, 57817c478bd9Sstevel@tonic-gate CMD_TRAN_INFO|CMD_DMA); 57827c478bd9Sstevel@tonic-gate fas->f_lastcount = amt; 57837c478bd9Sstevel@tonic-gate 57847c478bd9Sstevel@tonic-gate New_state(fas, ACTS_CMD_DONE); 57857c478bd9Sstevel@tonic-gate 57867c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CMD_START_END, 57877c478bd9Sstevel@tonic-gate "fas_handle_cmd_start_end"); 57887c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 57897c478bd9Sstevel@tonic-gate } 57907c478bd9Sstevel@tonic-gate 57917c478bd9Sstevel@tonic-gate static int 57927c478bd9Sstevel@tonic-gate fas_handle_cmd_done(struct fas *fas) 57937c478bd9Sstevel@tonic-gate { 57947c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 57957c478bd9Sstevel@tonic-gate uchar_t intr = fas->f_intr; 57967c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; 57977c478bd9Sstevel@tonic-gate 57987c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CMD_DONE_START, 57997c478bd9Sstevel@tonic-gate "fas_handle_cmd_done_start"); 58007c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_cmd_done\n"); 58017c478bd9Sstevel@tonic-gate 58027c478bd9Sstevel@tonic-gate /* 58037c478bd9Sstevel@tonic-gate * We should have gotten a BUS SERVICE interrupt. 58047c478bd9Sstevel@tonic-gate * If it isn't that, and it isn't a DISCONNECT 58057c478bd9Sstevel@tonic-gate * interrupt, we have a "cannot happen" situation. 58067c478bd9Sstevel@tonic-gate */ 58077c478bd9Sstevel@tonic-gate if ((intr & FAS_INT_BUS) == 0) { 58087c478bd9Sstevel@tonic-gate if ((intr & FAS_INT_DISCON) == 0) { 58097c478bd9Sstevel@tonic-gate fas_printstate(fas, "cmd transmission error"); 58107c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 58117c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_CMD_DONE_ABORT1_END, 58127c478bd9Sstevel@tonic-gate "fas_handle_cmd_done_end (abort1)"); 58137c478bd9Sstevel@tonic-gate return (ACTION_ABORT_CURCMD); 58147c478bd9Sstevel@tonic-gate } 58157c478bd9Sstevel@tonic-gate } else { 58167c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state |= STATE_SENT_CMD; 58177c478bd9Sstevel@tonic-gate } 58187c478bd9Sstevel@tonic-gate 58197c478bd9Sstevel@tonic-gate fas->f_dma_csr = fas_dma_reg_read(fas, &dmar->dma_csr); 58207c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA(fas); 58217c478bd9Sstevel@tonic-gate 58227c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 58237c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_CMD_DONE_END, 58247c478bd9Sstevel@tonic-gate "fas_handle_cmd_done_end"); 58257c478bd9Sstevel@tonic-gate return (fas_handle_unknown(fas)); 58267c478bd9Sstevel@tonic-gate } 58277c478bd9Sstevel@tonic-gate 58287c478bd9Sstevel@tonic-gate /* 58297c478bd9Sstevel@tonic-gate * Begin to send a message out 58307c478bd9Sstevel@tonic-gate */ 58317c478bd9Sstevel@tonic-gate static int 58327c478bd9Sstevel@tonic-gate fas_handle_msg_out_start(struct fas *fas) 58337c478bd9Sstevel@tonic-gate { 58347c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 58357c478bd9Sstevel@tonic-gate uchar_t *msgout = fas->f_cur_msgout; 58367c478bd9Sstevel@tonic-gate uchar_t amt = fas->f_omsglen; 58377c478bd9Sstevel@tonic-gate 58387c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_OUT_START, 58397c478bd9Sstevel@tonic-gate "fas_handle_msg_out_start"); 58407c478bd9Sstevel@tonic-gate EPRINTF("fas_handle_msg_out_start\n"); 58417c478bd9Sstevel@tonic-gate 58427c478bd9Sstevel@tonic-gate /* 58437c478bd9Sstevel@tonic-gate * Check to make *sure* that we are really 58447c478bd9Sstevel@tonic-gate * in MESSAGE OUT phase. If the last state 58457c478bd9Sstevel@tonic-gate * was ACTS_MSG_OUT_DONE, then we are trying 58467c478bd9Sstevel@tonic-gate * to resend a message that the target stated 58477c478bd9Sstevel@tonic-gate * had a parity error in it. 58487c478bd9Sstevel@tonic-gate * 58497c478bd9Sstevel@tonic-gate * If this is the case, and mark completion reason as CMD_NOMSGOUT. 58507c478bd9Sstevel@tonic-gate * XXX: Right now, we just *drive* on. Should we abort the command? 58517c478bd9Sstevel@tonic-gate */ 58527c478bd9Sstevel@tonic-gate if ((fas->f_stat & FAS_PHASE_MASK) != FAS_PHASE_MSG_OUT && 58537c478bd9Sstevel@tonic-gate fas->f_laststate == ACTS_MSG_OUT_DONE) { 58547c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 58557c478bd9Sstevel@tonic-gate "Target %d refused message resend", Tgt(sp)); 58567c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_NOMSGOUT, 0); 58577c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 58587c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_OUT_PHASEMANAGE_END, 58597c478bd9Sstevel@tonic-gate "fas_handle_msg_out_end (ACTION_PHASEMANAGE)"); 58607c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 58617c478bd9Sstevel@tonic-gate } 58627c478bd9Sstevel@tonic-gate 58637c478bd9Sstevel@tonic-gate /* 58647c478bd9Sstevel@tonic-gate * Clean the fifo. 58657c478bd9Sstevel@tonic-gate */ 58667c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 58677c478bd9Sstevel@tonic-gate 58687c478bd9Sstevel@tonic-gate if (amt == 0) { 58697c478bd9Sstevel@tonic-gate /* 58707c478bd9Sstevel@tonic-gate * no msg to send 58717c478bd9Sstevel@tonic-gate */ 58727c478bd9Sstevel@tonic-gate *msgout = MSG_NOP; 58737c478bd9Sstevel@tonic-gate amt = fas->f_omsglen = 1; 58747c478bd9Sstevel@tonic-gate } 58757c478bd9Sstevel@tonic-gate 58767c478bd9Sstevel@tonic-gate /* 58777c478bd9Sstevel@tonic-gate * If msg only 1 byte, just dump it in the fifo and go. For 58787c478bd9Sstevel@tonic-gate * multi-byte msgs, dma them to save time. If we have no 58797c478bd9Sstevel@tonic-gate * msg to send and we're in msg out phase, send a NOP. 58807c478bd9Sstevel@tonic-gate */ 58817c478bd9Sstevel@tonic-gate fas->f_last_msgout = *msgout; 58827c478bd9Sstevel@tonic-gate 58837c478bd9Sstevel@tonic-gate /* 58847c478bd9Sstevel@tonic-gate * There is a bug in the fas366 that occasionaly 58857c478bd9Sstevel@tonic-gate * deasserts the ATN signal prematurely when we send 58867c478bd9Sstevel@tonic-gate * the sync/wide negotiation bytes out using DMA. The 58877c478bd9Sstevel@tonic-gate * workaround here is to send the negotiation bytes out 58887c478bd9Sstevel@tonic-gate * using PIO 58897c478bd9Sstevel@tonic-gate */ 58907c478bd9Sstevel@tonic-gate fas_write_fifo(fas, msgout, fas->f_omsglen, 1); 58917c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_TRAN_INFO); 58927c478bd9Sstevel@tonic-gate 58937c478bd9Sstevel@tonic-gate EPRINTF2("amt=%x, last_msgout=%x\n", amt, fas->f_last_msgout); 58947c478bd9Sstevel@tonic-gate 58957c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_OUT_DONE); 58967c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_OUT_END, 58977c478bd9Sstevel@tonic-gate "fas_handle_msg_out_end"); 58987c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 58997c478bd9Sstevel@tonic-gate } 59007c478bd9Sstevel@tonic-gate 59017c478bd9Sstevel@tonic-gate static int 59027c478bd9Sstevel@tonic-gate fas_handle_msg_out_done(struct fas *fas) 59037c478bd9Sstevel@tonic-gate { 59047c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 59057c478bd9Sstevel@tonic-gate uchar_t msgout, phase; 59067c478bd9Sstevel@tonic-gate int target = Tgt(sp); 59077c478bd9Sstevel@tonic-gate int amt = fas->f_omsglen; 59087c478bd9Sstevel@tonic-gate int action; 59097c478bd9Sstevel@tonic-gate 59107c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_OUT_DONE_START, 59117c478bd9Sstevel@tonic-gate "fas_handle_msg_out_done_start"); 59127c478bd9Sstevel@tonic-gate msgout = fas->f_cur_msgout[0]; 59137c478bd9Sstevel@tonic-gate if ((msgout == MSG_HEAD_QTAG) || (msgout == MSG_SIMPLE_QTAG)) { 59147c478bd9Sstevel@tonic-gate msgout = fas->f_cur_msgout[2]; 59157c478bd9Sstevel@tonic-gate } 59167c478bd9Sstevel@tonic-gate EPRINTF4("msgout: %x %x %x, last_msgout=%x\n", 59177c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0], fas->f_cur_msgout[1], 59187c478bd9Sstevel@tonic-gate fas->f_cur_msgout[2], fas->f_last_msgout); 59197c478bd9Sstevel@tonic-gate 59207c478bd9Sstevel@tonic-gate EPRINTF1("fas_handle_msgout_done: msgout=%x\n", msgout); 59217c478bd9Sstevel@tonic-gate 59227c478bd9Sstevel@tonic-gate /* 59237c478bd9Sstevel@tonic-gate * flush fifo, just in case some bytes were not sent 59247c478bd9Sstevel@tonic-gate */ 59257c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 59267c478bd9Sstevel@tonic-gate 59277c478bd9Sstevel@tonic-gate /* 59287c478bd9Sstevel@tonic-gate * If the FAS disconnected, then the message we sent caused 59297c478bd9Sstevel@tonic-gate * the target to decide to drop BSY* and clear the bus. 59307c478bd9Sstevel@tonic-gate */ 59317c478bd9Sstevel@tonic-gate if (fas->f_intr == FAS_INT_DISCON) { 59327c478bd9Sstevel@tonic-gate if (msgout == MSG_DEVICE_RESET || msgout == MSG_ABORT || 59337c478bd9Sstevel@tonic-gate msgout == MSG_ABORT_TAG) { 59347c478bd9Sstevel@tonic-gate /* 59357c478bd9Sstevel@tonic-gate * If we sent a device reset msg, then we need to do 59367c478bd9Sstevel@tonic-gate * a synch negotiate again unless we have already 59377c478bd9Sstevel@tonic-gate * inhibited synch. 59387c478bd9Sstevel@tonic-gate */ 59397c478bd9Sstevel@tonic-gate if (msgout == MSG_ABORT || msgout == MSG_ABORT_TAG) { 59407c478bd9Sstevel@tonic-gate fas->f_abort_msg_sent++; 59417c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 59427c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, 59437c478bd9Sstevel@tonic-gate CMD_ABORTED, STAT_ABORTED); 59447c478bd9Sstevel@tonic-gate } 59457c478bd9Sstevel@tonic-gate } else if (msgout == MSG_DEVICE_RESET) { 59467c478bd9Sstevel@tonic-gate fas->f_reset_msg_sent++; 59477c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 59487c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, 59497c478bd9Sstevel@tonic-gate CMD_RESET, STAT_DEV_RESET); 59507c478bd9Sstevel@tonic-gate } 59517c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, Tgt(sp)); 59527c478bd9Sstevel@tonic-gate } 59537c478bd9Sstevel@tonic-gate EPRINTF2("Successful %s message to target %d\n", 59547c478bd9Sstevel@tonic-gate scsi_mname(msgout), target); 59557c478bd9Sstevel@tonic-gate 59567c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CMDPROXY) { 59577c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] = TRUE; 59587c478bd9Sstevel@tonic-gate } 59597c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 59607c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MSG_OUT_DONE_FINISH_END, 59617c478bd9Sstevel@tonic-gate "fas_handle_msg_out_done_end (ACTION_FINISH)"); 59627c478bd9Sstevel@tonic-gate return (ACTION_FINISH); 59637c478bd9Sstevel@tonic-gate } 59647c478bd9Sstevel@tonic-gate /* 59657c478bd9Sstevel@tonic-gate * If the target dropped busy on any other message, it 59667c478bd9Sstevel@tonic-gate * wasn't expected. We will let the code in fas_phasemanage() 59677c478bd9Sstevel@tonic-gate * handle this unexpected bus free event. 59687c478bd9Sstevel@tonic-gate */ 59697c478bd9Sstevel@tonic-gate goto out; 59707c478bd9Sstevel@tonic-gate } 59717c478bd9Sstevel@tonic-gate 59727c478bd9Sstevel@tonic-gate /* 59737c478bd9Sstevel@tonic-gate * What phase have we transitioned to? 59747c478bd9Sstevel@tonic-gate */ 59757c478bd9Sstevel@tonic-gate phase = fas->f_stat & FAS_PHASE_MASK; 59767c478bd9Sstevel@tonic-gate 59777c478bd9Sstevel@tonic-gate /* 59787c478bd9Sstevel@tonic-gate * If we finish sending a message out, and we are 59797c478bd9Sstevel@tonic-gate * still in message out phase, then the target has 59807c478bd9Sstevel@tonic-gate * detected one or more parity errors in the message 59817c478bd9Sstevel@tonic-gate * we just sent and it is asking us to resend the 59827c478bd9Sstevel@tonic-gate * previous message. 59837c478bd9Sstevel@tonic-gate */ 59847c478bd9Sstevel@tonic-gate if ((fas->f_intr & FAS_INT_BUS) && phase == FAS_PHASE_MSG_OUT) { 59857c478bd9Sstevel@tonic-gate /* 59867c478bd9Sstevel@tonic-gate * As per SCSI-2 specification, if the message to 59877c478bd9Sstevel@tonic-gate * be re-sent is greater than one byte, then we 59887c478bd9Sstevel@tonic-gate * have to set ATN*. 59897c478bd9Sstevel@tonic-gate */ 59907c478bd9Sstevel@tonic-gate if (amt > 1) { 59917c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 59927c478bd9Sstevel@tonic-gate } 59937c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 59947c478bd9Sstevel@tonic-gate "SCSI bus MESSAGE OUT phase parity error"); 59957c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= STAT_PERR; 59967c478bd9Sstevel@tonic-gate New_state(fas, ACTS_MSG_OUT); 59977c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, 59987c478bd9Sstevel@tonic-gate TR_FAS_HANDLE_MSG_OUT_DONE_PHASEMANAGE_END, 59997c478bd9Sstevel@tonic-gate "fas_handle_msg_out_done_end (ACTION_PHASEMANAGE)"); 60007c478bd9Sstevel@tonic-gate return (ACTION_PHASEMANAGE); 60017c478bd9Sstevel@tonic-gate } 60027c478bd9Sstevel@tonic-gate 60037c478bd9Sstevel@tonic-gate 60047c478bd9Sstevel@tonic-gate out: 60057c478bd9Sstevel@tonic-gate fas->f_last_msgout = msgout; 60067c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 60077c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 60087c478bd9Sstevel@tonic-gate action = fas_handle_unknown(fas); 60097c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_HANDLE_MSG_OUT_DONE_END, 60107c478bd9Sstevel@tonic-gate "fas_handle_msg_out_done_end"); 60117c478bd9Sstevel@tonic-gate return (action); 60127c478bd9Sstevel@tonic-gate } 60137c478bd9Sstevel@tonic-gate 60147c478bd9Sstevel@tonic-gate static int 60157c478bd9Sstevel@tonic-gate fas_twobyte_msg(struct fas *fas) 60167c478bd9Sstevel@tonic-gate { 60177c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 60187c478bd9Sstevel@tonic-gate 60197c478bd9Sstevel@tonic-gate if ((fas->f_imsgarea[0] == MSG_IGNORE_WIDE_RESID) && 60207c478bd9Sstevel@tonic-gate (fas->f_imsgarea[1] == 1)) { 60217c478bd9Sstevel@tonic-gate int xfer_amt; 60227c478bd9Sstevel@tonic-gate 60237c478bd9Sstevel@tonic-gate /* 60247c478bd9Sstevel@tonic-gate * Knock off one byte if there 60257c478bd9Sstevel@tonic-gate * is a last transfer and is even number of bytes 60267c478bd9Sstevel@tonic-gate */ 60277c478bd9Sstevel@tonic-gate xfer_amt = sp->cmd_data_count - sp->cmd_saved_data_count; 60287c478bd9Sstevel@tonic-gate if (xfer_amt && (!(xfer_amt & 1))) { 60297c478bd9Sstevel@tonic-gate ASSERT(sp->cmd_data_count > 0); 60307c478bd9Sstevel@tonic-gate sp->cmd_data_count--; 60317c478bd9Sstevel@tonic-gate sp->cmd_cur_addr--; 60327c478bd9Sstevel@tonic-gate } 60337c478bd9Sstevel@tonic-gate IPRINTF1("ignore wide resid %d\n", fas->f_imsgarea[1]); 60347c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 60357c478bd9Sstevel@tonic-gate return (0); 60367c478bd9Sstevel@tonic-gate } 60377c478bd9Sstevel@tonic-gate 60387c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 60397c478bd9Sstevel@tonic-gate "Two byte message '%s' 0x%x rejected", 60407c478bd9Sstevel@tonic-gate scsi_mname(fas->f_imsgarea[0]), fas->f_imsgarea[1]); 60417c478bd9Sstevel@tonic-gate return (MSG_REJECT); 60427c478bd9Sstevel@tonic-gate } 60437c478bd9Sstevel@tonic-gate 60447c478bd9Sstevel@tonic-gate /* 60457c478bd9Sstevel@tonic-gate * handle receiving extended messages 60467c478bd9Sstevel@tonic-gate */ 60477c478bd9Sstevel@tonic-gate static int 60487c478bd9Sstevel@tonic-gate fas_multibyte_msg(struct fas *fas) 60497c478bd9Sstevel@tonic-gate { 60507c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 60517c478bd9Sstevel@tonic-gate static char *mbs = 60527c478bd9Sstevel@tonic-gate "Target %d now Synchronous at %d.%d MB/s max transmit rate\n"; 60537c478bd9Sstevel@tonic-gate static char *mbs1 = 60547c478bd9Sstevel@tonic-gate "Target %d now Synchronous at %d.0%d MB/s max transmit rate\n"; 60557c478bd9Sstevel@tonic-gate static char *mbs2 = 60567c478bd9Sstevel@tonic-gate "Target %d now Synchronous at %d.00%d MB/s max transmit rate\n"; 60577c478bd9Sstevel@tonic-gate #endif 60587c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 60597c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 60607c478bd9Sstevel@tonic-gate uchar_t emsg = fas->f_imsgarea[2]; 60617c478bd9Sstevel@tonic-gate int tgt = Tgt(sp); 60627c478bd9Sstevel@tonic-gate int msgout = 0; 60637c478bd9Sstevel@tonic-gate 60647c478bd9Sstevel@tonic-gate EPRINTF("fas_multibyte_msg:\n"); 60657c478bd9Sstevel@tonic-gate 60667c478bd9Sstevel@tonic-gate if (emsg == MSG_SYNCHRONOUS) { 60677c478bd9Sstevel@tonic-gate uint_t period, offset, regval; 60687c478bd9Sstevel@tonic-gate uint_t minsync, maxsync, clockval; 60697c478bd9Sstevel@tonic-gate uint_t xfer_freq, xfer_div, xfer_mod, xfer_rate; 60707c478bd9Sstevel@tonic-gate 60717c478bd9Sstevel@tonic-gate period = fas->f_imsgarea[3] & 0xff; 60727c478bd9Sstevel@tonic-gate offset = fas->f_imsgarea[4] & 0xff; 60737c478bd9Sstevel@tonic-gate minsync = MIN_SYNC_PERIOD(fas); 60747c478bd9Sstevel@tonic-gate maxsync = MAX_SYNC_PERIOD(fas); 60757c478bd9Sstevel@tonic-gate DPRINTF5("sync msg received: %x %x %x %x %x\n", 60767c478bd9Sstevel@tonic-gate fas->f_imsgarea[0], fas->f_imsgarea[1], 60777c478bd9Sstevel@tonic-gate fas->f_imsgarea[2], fas->f_imsgarea[3], 60787c478bd9Sstevel@tonic-gate fas->f_imsgarea[4]); 60797c478bd9Sstevel@tonic-gate DPRINTF3("received period %d offset %d from tgt %d\n", 60807c478bd9Sstevel@tonic-gate period, offset, tgt); 60817c478bd9Sstevel@tonic-gate DPRINTF3("calculated minsync %d, maxsync %d for tgt %d\n", 60827c478bd9Sstevel@tonic-gate minsync, maxsync, tgt); 60837c478bd9Sstevel@tonic-gate DPRINTF2("sync period %d, neg period %d\n", 60847c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt], fas->f_neg_period[tgt]); 60857c478bd9Sstevel@tonic-gate 60867c478bd9Sstevel@tonic-gate if ((++(fas->f_sdtr_sent)) & 1) { 60877c478bd9Sstevel@tonic-gate /* 60887c478bd9Sstevel@tonic-gate * In cases where the target negotiates synchronous 60897c478bd9Sstevel@tonic-gate * mode before we do, and we either have sync mode 60907c478bd9Sstevel@tonic-gate * disabled, or this target is known to be a weak 60917c478bd9Sstevel@tonic-gate * signal target, we send back a message indicating 60927c478bd9Sstevel@tonic-gate * a desire to stay in asynchronous mode (the SCSI-2 60937c478bd9Sstevel@tonic-gate * spec states that if we have synchronous capability 60947c478bd9Sstevel@tonic-gate * then we cannot reject a SYNCHRONOUS DATA TRANSFER 60957c478bd9Sstevel@tonic-gate * REQUEST message). 60967c478bd9Sstevel@tonic-gate */ 60977c478bd9Sstevel@tonic-gate IPRINTF1("SYNC negotiation initiated by target %d\n", 60987c478bd9Sstevel@tonic-gate tgt); 60997c478bd9Sstevel@tonic-gate 61007c478bd9Sstevel@tonic-gate msgout = MSG_EXTENDED; 61017c478bd9Sstevel@tonic-gate 61027c478bd9Sstevel@tonic-gate period = 61037c478bd9Sstevel@tonic-gate period ? max(period, MIN_SYNC_PERIOD(fas)) : 0; 61047c478bd9Sstevel@tonic-gate 61057c478bd9Sstevel@tonic-gate if (fas->f_backoff & (1<<tgt)) { 61067c478bd9Sstevel@tonic-gate period = period ? 61077c478bd9Sstevel@tonic-gate max(period, fas->f_neg_period[tgt]) : 0; 61087c478bd9Sstevel@tonic-gate } 61097c478bd9Sstevel@tonic-gate offset = min(offset, fas_default_offset); 61107c478bd9Sstevel@tonic-gate } 61117c478bd9Sstevel@tonic-gate xfer_freq = regval = 0; 61127c478bd9Sstevel@tonic-gate 61137c478bd9Sstevel@tonic-gate /* 61147c478bd9Sstevel@tonic-gate * If the target's offset is bigger than ours, 61157c478bd9Sstevel@tonic-gate * the target has violated the scsi protocol. 61167c478bd9Sstevel@tonic-gate */ 61177c478bd9Sstevel@tonic-gate if (offset > fas_default_offset) { 61187c478bd9Sstevel@tonic-gate period = offset = 0; 61197c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 61207c478bd9Sstevel@tonic-gate } 61217c478bd9Sstevel@tonic-gate 61227c478bd9Sstevel@tonic-gate if (offset && (period > maxsync)) { 61237c478bd9Sstevel@tonic-gate /* 61247c478bd9Sstevel@tonic-gate * We cannot transmit data in synchronous 61257c478bd9Sstevel@tonic-gate * mode this slow, so convert to asynchronous 61267c478bd9Sstevel@tonic-gate * mode. 61277c478bd9Sstevel@tonic-gate */ 61287c478bd9Sstevel@tonic-gate msgout = MSG_EXTENDED; 61297c478bd9Sstevel@tonic-gate period = offset = 0; 61307c478bd9Sstevel@tonic-gate 61317c478bd9Sstevel@tonic-gate } else if (offset && (period < minsync)) { 61327c478bd9Sstevel@tonic-gate /* 61337c478bd9Sstevel@tonic-gate * If the target's period is less than ours, 61347c478bd9Sstevel@tonic-gate * the target has violated the scsi protocol. 61357c478bd9Sstevel@tonic-gate */ 61367c478bd9Sstevel@tonic-gate period = offset = 0; 61377c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 61387c478bd9Sstevel@tonic-gate 61397c478bd9Sstevel@tonic-gate } else if (offset) { 61407c478bd9Sstevel@tonic-gate /* 61417c478bd9Sstevel@tonic-gate * Conversion method for received PERIOD value 61427c478bd9Sstevel@tonic-gate * to the number of input clock ticks to the FAS. 61437c478bd9Sstevel@tonic-gate * 61447c478bd9Sstevel@tonic-gate * We adjust the input period value such that 61457c478bd9Sstevel@tonic-gate * we always will transmit data *not* faster 61467c478bd9Sstevel@tonic-gate * than the period value received. 61477c478bd9Sstevel@tonic-gate */ 61487c478bd9Sstevel@tonic-gate 61497c478bd9Sstevel@tonic-gate clockval = fas->f_clock_cycle / 1000; 61507c478bd9Sstevel@tonic-gate regval = (((period << 2) + clockval - 1) / clockval); 61517c478bd9Sstevel@tonic-gate 61527c478bd9Sstevel@tonic-gate /* 61537c478bd9Sstevel@tonic-gate * correction if xfer rate <= 5MB/sec 61547c478bd9Sstevel@tonic-gate * XXX do we need this? 61557c478bd9Sstevel@tonic-gate */ 61567c478bd9Sstevel@tonic-gate if (regval && (period >= FASTSCSI_THRESHOLD)) { 61577c478bd9Sstevel@tonic-gate regval--; 61587c478bd9Sstevel@tonic-gate } 61597c478bd9Sstevel@tonic-gate } 61607c478bd9Sstevel@tonic-gate 61617c478bd9Sstevel@tonic-gate fas->f_offset[tgt] = offset; 61627c478bd9Sstevel@tonic-gate fas->f_neg_period[tgt] = period; 61637c478bd9Sstevel@tonic-gate 61647c478bd9Sstevel@tonic-gate /* 61657c478bd9Sstevel@tonic-gate * Is is now safe to produce a responce to a target 61667c478bd9Sstevel@tonic-gate * initiated sdtr. period and offset have been checked. 61677c478bd9Sstevel@tonic-gate */ 61687c478bd9Sstevel@tonic-gate if (msgout == MSG_EXTENDED) { 61697c478bd9Sstevel@tonic-gate fas_make_sdtr(fas, 0, tgt); 61707c478bd9Sstevel@tonic-gate period = fas->f_neg_period[tgt]; 61717c478bd9Sstevel@tonic-gate offset = (fas->f_offset[tgt] & 0xf); 61727c478bd9Sstevel@tonic-gate } 61737c478bd9Sstevel@tonic-gate 61747c478bd9Sstevel@tonic-gate if (offset) { 61757c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt] = regval & SYNC_PERIOD_MASK; 61767c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_sync_period, 61777c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt]); 61787c478bd9Sstevel@tonic-gate 61797c478bd9Sstevel@tonic-gate fas->f_offset[tgt] = offset | fas->f_req_ack_delay; 61807c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_sync_offset, 61817c478bd9Sstevel@tonic-gate fas->f_offset[tgt]); 61827c478bd9Sstevel@tonic-gate 61837c478bd9Sstevel@tonic-gate /* 61847c478bd9Sstevel@tonic-gate * if transferring > 5 MB/sec then enable 61857c478bd9Sstevel@tonic-gate * fastscsi in conf3 61867c478bd9Sstevel@tonic-gate */ 61877c478bd9Sstevel@tonic-gate if (period < FASTSCSI_THRESHOLD) { 61887c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt] |= FAS_CONF3_FASTSCSI; 61897c478bd9Sstevel@tonic-gate } else { 61907c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt] &= ~FAS_CONF3_FASTSCSI; 61917c478bd9Sstevel@tonic-gate } 61927c478bd9Sstevel@tonic-gate 61937c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_conf3, 61947c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt]); 61957c478bd9Sstevel@tonic-gate 61967c478bd9Sstevel@tonic-gate DPRINTF4("period %d (%d), offset %d to tgt %d\n", 61977c478bd9Sstevel@tonic-gate period, 61987c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt] & SYNC_PERIOD_MASK, 61997c478bd9Sstevel@tonic-gate fas->f_offset[tgt] & 0xf, tgt); 62007c478bd9Sstevel@tonic-gate DPRINTF1("req/ack delay = %x\n", fas->f_req_ack_delay); 62017c478bd9Sstevel@tonic-gate DPRINTF1("conf3 = %x\n", fas->f_fasconf3[tgt]); 62027c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 62037c478bd9Sstevel@tonic-gate /* 62047c478bd9Sstevel@tonic-gate * Convert input clock cycle per 62057c478bd9Sstevel@tonic-gate * byte to nanoseconds per byte. 62067c478bd9Sstevel@tonic-gate * (ns/b), and convert that to 62077c478bd9Sstevel@tonic-gate * k-bytes/second. 62087c478bd9Sstevel@tonic-gate */ 62097c478bd9Sstevel@tonic-gate xfer_freq = FAS_SYNC_KBPS((regval * 62107c478bd9Sstevel@tonic-gate fas->f_clock_cycle) / 1000); 62117c478bd9Sstevel@tonic-gate xfer_rate = ((fas->f_nowide & (1<<tgt))? 1 : 2) * 62127c478bd9Sstevel@tonic-gate xfer_freq; 62137c478bd9Sstevel@tonic-gate xfer_div = xfer_rate / 1000; 62147c478bd9Sstevel@tonic-gate xfer_mod = xfer_rate % 1000; 62157c478bd9Sstevel@tonic-gate 62167c478bd9Sstevel@tonic-gate 62177c478bd9Sstevel@tonic-gate if (xfer_mod > 99) { 62187c478bd9Sstevel@tonic-gate IPRINTF3(mbs, tgt, xfer_div, xfer_mod); 62197c478bd9Sstevel@tonic-gate } else if (xfer_mod > 9) { 62207c478bd9Sstevel@tonic-gate IPRINTF3(mbs1, tgt, xfer_div, xfer_mod); 62217c478bd9Sstevel@tonic-gate } else { 62227c478bd9Sstevel@tonic-gate IPRINTF3(mbs2, tgt, xfer_div, xfer_mod); 62237c478bd9Sstevel@tonic-gate } 62247c478bd9Sstevel@tonic-gate #endif 62257c478bd9Sstevel@tonic-gate fas->f_sync_enabled |= (1<<tgt); 62267c478bd9Sstevel@tonic-gate 62277c478bd9Sstevel@tonic-gate } else { 62287c478bd9Sstevel@tonic-gate /* 62297c478bd9Sstevel@tonic-gate * We are converting back to async mode. 62307c478bd9Sstevel@tonic-gate */ 62317c478bd9Sstevel@tonic-gate fas_revert_to_async(fas, tgt); 62327c478bd9Sstevel@tonic-gate } 62337c478bd9Sstevel@tonic-gate 62347c478bd9Sstevel@tonic-gate /* 62357c478bd9Sstevel@tonic-gate * If this target violated the scsi spec, reject the 62367c478bd9Sstevel@tonic-gate * sdtr msg and don't negotiate sdtr again. 62377c478bd9Sstevel@tonic-gate */ 62387c478bd9Sstevel@tonic-gate if (msgout == MSG_REJECT) { 62397c478bd9Sstevel@tonic-gate fas->f_nosync |= (1<<tgt); 62407c478bd9Sstevel@tonic-gate } 62417c478bd9Sstevel@tonic-gate 62427c478bd9Sstevel@tonic-gate fas->f_props_update |= (1<<tgt); 62437c478bd9Sstevel@tonic-gate 62447c478bd9Sstevel@tonic-gate } else if (emsg == MSG_WIDE_DATA_XFER) { 62457c478bd9Sstevel@tonic-gate uchar_t width = fas->f_imsgarea[3] & 0xff; 62467c478bd9Sstevel@tonic-gate 62477c478bd9Sstevel@tonic-gate DPRINTF4("wide msg received: %x %x %x %x\n", 62487c478bd9Sstevel@tonic-gate fas->f_imsgarea[0], fas->f_imsgarea[1], 62497c478bd9Sstevel@tonic-gate fas->f_imsgarea[2], fas->f_imsgarea[3]); 62507c478bd9Sstevel@tonic-gate 62517c478bd9Sstevel@tonic-gate /* always renegotiate sync after wide */ 62527c478bd9Sstevel@tonic-gate msgout = MSG_EXTENDED; 62537c478bd9Sstevel@tonic-gate 62547c478bd9Sstevel@tonic-gate if ((++(fas->f_wdtr_sent)) & 1) { 62557c478bd9Sstevel@tonic-gate IPRINTF1("Wide negotiation initiated by target %d\n", 62567c478bd9Sstevel@tonic-gate tgt); 62577c478bd9Sstevel@tonic-gate /* 62587c478bd9Sstevel@tonic-gate * allow wide neg even if the target driver hasn't 62597c478bd9Sstevel@tonic-gate * enabled wide yet. 62607c478bd9Sstevel@tonic-gate */ 62617c478bd9Sstevel@tonic-gate fas->f_nowide &= ~(1<<tgt); 62627c478bd9Sstevel@tonic-gate fas_make_wdtr(fas, 0, tgt, width); 62637c478bd9Sstevel@tonic-gate IPRINTF1("sending wide sync %d back\n", width); 62647c478bd9Sstevel@tonic-gate /* 62657c478bd9Sstevel@tonic-gate * Let us go back to async mode(SCSI spec) 62667c478bd9Sstevel@tonic-gate * and depend on target to do sync 62677c478bd9Sstevel@tonic-gate * after wide negotiations. 62687c478bd9Sstevel@tonic-gate * If target does not do a sync neg and enters 62697c478bd9Sstevel@tonic-gate * async mode we will negotiate sync on next command 62707c478bd9Sstevel@tonic-gate */ 62717c478bd9Sstevel@tonic-gate fas_revert_to_async(fas, tgt); 62727c478bd9Sstevel@tonic-gate fas->f_sync_known &= ~(1<<tgt); 62737c478bd9Sstevel@tonic-gate } else { 62747c478bd9Sstevel@tonic-gate /* 62757c478bd9Sstevel@tonic-gate * renegotiate sync after wide 62767c478bd9Sstevel@tonic-gate */ 62777c478bd9Sstevel@tonic-gate fas_set_wide_conf3(fas, tgt, width); 62787c478bd9Sstevel@tonic-gate ASSERT(width <= 1); 62797c478bd9Sstevel@tonic-gate fas->f_wdtr_sent = 0; 62807c478bd9Sstevel@tonic-gate if ((fas->f_nosync & (1<<tgt)) == 0) { 62817c478bd9Sstevel@tonic-gate fas_make_sdtr(fas, 0, tgt); 62827c478bd9Sstevel@tonic-gate } else { 62837c478bd9Sstevel@tonic-gate msgout = 0; 62847c478bd9Sstevel@tonic-gate } 62857c478bd9Sstevel@tonic-gate } 62867c478bd9Sstevel@tonic-gate 62877c478bd9Sstevel@tonic-gate fas->f_props_update |= (1<<tgt); 62887c478bd9Sstevel@tonic-gate 62897c478bd9Sstevel@tonic-gate } else if (emsg == MSG_MODIFY_DATA_PTR) { 62907c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 62917c478bd9Sstevel@tonic-gate } else { 62927c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 62937c478bd9Sstevel@tonic-gate "Rejecting message %s 0x%x from Target %d", 62947c478bd9Sstevel@tonic-gate scsi_mname(MSG_EXTENDED), emsg, tgt); 62957c478bd9Sstevel@tonic-gate msgout = MSG_REJECT; 62967c478bd9Sstevel@tonic-gate } 62977c478bd9Sstevel@tonic-gate out: 62987c478bd9Sstevel@tonic-gate New_state(fas, ACTS_UNKNOWN); 62997c478bd9Sstevel@tonic-gate return (msgout); 63007c478bd9Sstevel@tonic-gate } 63017c478bd9Sstevel@tonic-gate 63027c478bd9Sstevel@tonic-gate /* 63037c478bd9Sstevel@tonic-gate * Back off sync negotiation 63047c478bd9Sstevel@tonic-gate * and got to async mode 63057c478bd9Sstevel@tonic-gate */ 63067c478bd9Sstevel@tonic-gate static void 63077c478bd9Sstevel@tonic-gate fas_revert_to_async(struct fas *fas, int tgt) 63087c478bd9Sstevel@tonic-gate { 63097c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 63107c478bd9Sstevel@tonic-gate 63117c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt] = 0; 63127c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_sync_period, 0); 63137c478bd9Sstevel@tonic-gate fas->f_offset[tgt] = 0; 63147c478bd9Sstevel@tonic-gate fas_reg_write(fas, (uchar_t *)&fasreg->fas_sync_offset, 0); 63157c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt] &= ~FAS_CONF3_FASTSCSI; 63167c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_conf3, fas->f_fasconf3[tgt]); 63177c478bd9Sstevel@tonic-gate fas->f_sync_enabled &= ~(1<<tgt); 63187c478bd9Sstevel@tonic-gate } 63197c478bd9Sstevel@tonic-gate 63207c478bd9Sstevel@tonic-gate /* 63217c478bd9Sstevel@tonic-gate * handle an unexpected selection attempt 63227c478bd9Sstevel@tonic-gate * XXX look for better way: msg reject, drop off the bus 63237c478bd9Sstevel@tonic-gate */ 63247c478bd9Sstevel@tonic-gate static int 63257c478bd9Sstevel@tonic-gate fas_handle_selection(struct fas *fas) 63267c478bd9Sstevel@tonic-gate { 63277c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_DISCONNECT); 63287c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 63297c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_EN_RESEL); 63307c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 63317c478bd9Sstevel@tonic-gate } 63327c478bd9Sstevel@tonic-gate 63337c478bd9Sstevel@tonic-gate /* 63347c478bd9Sstevel@tonic-gate * dma window handling 63357c478bd9Sstevel@tonic-gate */ 63367c478bd9Sstevel@tonic-gate static int 63377c478bd9Sstevel@tonic-gate fas_restore_pointers(struct fas *fas, struct fas_cmd *sp) 63387c478bd9Sstevel@tonic-gate { 63397c478bd9Sstevel@tonic-gate if (sp->cmd_data_count != sp->cmd_saved_data_count) { 63407c478bd9Sstevel@tonic-gate sp->cmd_data_count = sp->cmd_saved_data_count; 63417c478bd9Sstevel@tonic-gate sp->cmd_cur_addr = sp->cmd_saved_cur_addr; 63427c478bd9Sstevel@tonic-gate 63437c478bd9Sstevel@tonic-gate if (sp->cmd_cur_win != sp->cmd_saved_win) { 63447c478bd9Sstevel@tonic-gate sp->cmd_cur_win = sp->cmd_saved_win; 63457c478bd9Sstevel@tonic-gate if (fas_set_new_window(fas, sp)) { 63467c478bd9Sstevel@tonic-gate return (-1); 63477c478bd9Sstevel@tonic-gate } 63487c478bd9Sstevel@tonic-gate } 63497c478bd9Sstevel@tonic-gate DPRINTF1("curaddr=%x\n", sp->cmd_cur_addr); 63507c478bd9Sstevel@tonic-gate } 63517c478bd9Sstevel@tonic-gate return (0); 63527c478bd9Sstevel@tonic-gate } 63537c478bd9Sstevel@tonic-gate 63547c478bd9Sstevel@tonic-gate static int 63557c478bd9Sstevel@tonic-gate fas_set_new_window(struct fas *fas, struct fas_cmd *sp) 63567c478bd9Sstevel@tonic-gate { 63577c478bd9Sstevel@tonic-gate off_t offset; 63587c478bd9Sstevel@tonic-gate size_t len; 63597c478bd9Sstevel@tonic-gate uint_t count; 63607c478bd9Sstevel@tonic-gate 63617c478bd9Sstevel@tonic-gate if (ddi_dma_getwin(sp->cmd_dmahandle, sp->cmd_cur_win, 63627c478bd9Sstevel@tonic-gate &offset, &len, &sp->cmd_dmacookie, &count) != DDI_SUCCESS) { 63637c478bd9Sstevel@tonic-gate return (-1); 63647c478bd9Sstevel@tonic-gate } 63657c478bd9Sstevel@tonic-gate 63667c478bd9Sstevel@tonic-gate DPRINTF4("new window %x: off=%lx, len=%lx, count=%x\n", 63677c478bd9Sstevel@tonic-gate sp->cmd_cur_win, offset, len, count); 63687c478bd9Sstevel@tonic-gate 63697c478bd9Sstevel@tonic-gate ASSERT(count == 1); 63707c478bd9Sstevel@tonic-gate return (0); 63717c478bd9Sstevel@tonic-gate } 63727c478bd9Sstevel@tonic-gate 63737c478bd9Sstevel@tonic-gate static int 63747c478bd9Sstevel@tonic-gate fas_next_window(struct fas *fas, struct fas_cmd *sp, uint64_t end) 63757c478bd9Sstevel@tonic-gate { 63767c478bd9Sstevel@tonic-gate 63777c478bd9Sstevel@tonic-gate /* are there more windows? */ 63787c478bd9Sstevel@tonic-gate if (sp->cmd_nwin == 0) { 63797c478bd9Sstevel@tonic-gate uint_t nwin = 0; 63807c478bd9Sstevel@tonic-gate (void) ddi_dma_numwin(sp->cmd_dmahandle, &nwin); 63817c478bd9Sstevel@tonic-gate sp->cmd_nwin = (uchar_t)nwin; 63827c478bd9Sstevel@tonic-gate } 63837c478bd9Sstevel@tonic-gate 63847c478bd9Sstevel@tonic-gate DPRINTF5( 63857c478bd9Sstevel@tonic-gate "cmd_data_count=%x, dmacount=%x, curaddr=%x, end=%lx, nwin=%x\n", 63867c478bd9Sstevel@tonic-gate sp->cmd_data_count, sp->cmd_dmacount, sp->cmd_cur_addr, end, 63877c478bd9Sstevel@tonic-gate sp->cmd_nwin); 63887c478bd9Sstevel@tonic-gate 63897c478bd9Sstevel@tonic-gate if (sp->cmd_cur_win < sp->cmd_nwin) { 63907c478bd9Sstevel@tonic-gate sp->cmd_cur_win++; 63917c478bd9Sstevel@tonic-gate if (fas_set_new_window(fas, sp)) { 63927c478bd9Sstevel@tonic-gate fas_printstate(fas, "cannot set new window"); 63937c478bd9Sstevel@tonic-gate sp->cmd_cur_win--; 63947c478bd9Sstevel@tonic-gate return (-1); 63957c478bd9Sstevel@tonic-gate } 63967c478bd9Sstevel@tonic-gate /* 63977c478bd9Sstevel@tonic-gate * if there are no more windows, we have a data overrun condition 63987c478bd9Sstevel@tonic-gate */ 63997c478bd9Sstevel@tonic-gate } else { 64007c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 64017c478bd9Sstevel@tonic-gate 64027c478bd9Sstevel@tonic-gate fas_printstate(fas, "data transfer overrun"); 64037c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_DATA_OVR, 0); 64047c478bd9Sstevel@tonic-gate 64057c478bd9Sstevel@tonic-gate /* 64067c478bd9Sstevel@tonic-gate * if we get data transfer overruns, assume we have 64077c478bd9Sstevel@tonic-gate * a weak scsi bus. Note that this won't catch consistent 64087c478bd9Sstevel@tonic-gate * underruns or other noise related syndromes. 64097c478bd9Sstevel@tonic-gate */ 64107c478bd9Sstevel@tonic-gate fas_sync_wide_backoff(fas, sp, slot); 64117c478bd9Sstevel@tonic-gate return (-1); 64127c478bd9Sstevel@tonic-gate } 64137c478bd9Sstevel@tonic-gate sp->cmd_cur_addr = sp->cmd_dmacookie.dmac_address; 64147c478bd9Sstevel@tonic-gate DPRINTF1("cur_addr=%x\n", sp->cmd_cur_addr); 64157c478bd9Sstevel@tonic-gate return (0); 64167c478bd9Sstevel@tonic-gate } 64177c478bd9Sstevel@tonic-gate 64187c478bd9Sstevel@tonic-gate /* 64197c478bd9Sstevel@tonic-gate * dma error handler 64207c478bd9Sstevel@tonic-gate */ 64217c478bd9Sstevel@tonic-gate static int 64227c478bd9Sstevel@tonic-gate fas_check_dma_error(struct fas *fas) 64237c478bd9Sstevel@tonic-gate { 64247c478bd9Sstevel@tonic-gate /* 64257c478bd9Sstevel@tonic-gate * was there a dma error that caused fas_intr_svc() to be called? 64267c478bd9Sstevel@tonic-gate */ 64277c478bd9Sstevel@tonic-gate if (fas->f_dma->dma_csr & DMA_ERRPEND) { 64287c478bd9Sstevel@tonic-gate /* 64297c478bd9Sstevel@tonic-gate * It would be desirable to set the ATN* line and attempt to 64307c478bd9Sstevel@tonic-gate * do the whole schmear of INITIATOR DETECTED ERROR here, 64317c478bd9Sstevel@tonic-gate * but that is too hard to do at present. 64327c478bd9Sstevel@tonic-gate */ 64337c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "Unrecoverable DMA error"); 64347c478bd9Sstevel@tonic-gate fas_printstate(fas, "dma error"); 64357c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, fas->f_current_sp, CMD_TRAN_ERR, 0); 64367c478bd9Sstevel@tonic-gate return (-1); 64377c478bd9Sstevel@tonic-gate } 64387c478bd9Sstevel@tonic-gate return (0); 64397c478bd9Sstevel@tonic-gate } 64407c478bd9Sstevel@tonic-gate 64417c478bd9Sstevel@tonic-gate /* 64427c478bd9Sstevel@tonic-gate * check for gross error or spurious interrupt 64437c478bd9Sstevel@tonic-gate */ 64447c478bd9Sstevel@tonic-gate static int 64457c478bd9Sstevel@tonic-gate fas_handle_gross_err(struct fas *fas) 64467c478bd9Sstevel@tonic-gate { 64477c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 64487c478bd9Sstevel@tonic-gate 64497c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 64507c478bd9Sstevel@tonic-gate "gross error in fas status (%x)", fas->f_stat); 64517c478bd9Sstevel@tonic-gate 64527c478bd9Sstevel@tonic-gate IPRINTF5("fas_cmd=%x, stat=%x, intr=%x, step=%x, fifoflag=%x\n", 64537c478bd9Sstevel@tonic-gate fasreg->fas_cmd, fas->f_stat, fas->f_intr, fasreg->fas_step, 64547c478bd9Sstevel@tonic-gate fasreg->fas_fifo_flag); 64557c478bd9Sstevel@tonic-gate 64567c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, fas->f_current_sp, CMD_TRAN_ERR, 0); 64577c478bd9Sstevel@tonic-gate 64587c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_FAS); 64597c478bd9Sstevel@tonic-gate return (ACTION_RESET); 64607c478bd9Sstevel@tonic-gate } 64617c478bd9Sstevel@tonic-gate 64627c478bd9Sstevel@tonic-gate 64637c478bd9Sstevel@tonic-gate /* 64647c478bd9Sstevel@tonic-gate * handle illegal cmd interrupt or (external) bus reset cleanup 64657c478bd9Sstevel@tonic-gate */ 64667c478bd9Sstevel@tonic-gate static int 64677c478bd9Sstevel@tonic-gate fas_illegal_cmd_or_bus_reset(struct fas *fas) 64687c478bd9Sstevel@tonic-gate { 64697c478bd9Sstevel@tonic-gate /* 64707c478bd9Sstevel@tonic-gate * If we detect a SCSI reset, we blow away the current 64717c478bd9Sstevel@tonic-gate * command (if there is one) and all disconnected commands 64727c478bd9Sstevel@tonic-gate * because we now don't know the state of them at all. 64737c478bd9Sstevel@tonic-gate */ 64747c478bd9Sstevel@tonic-gate ASSERT(fas->f_intr & (FAS_INT_ILLEGAL | FAS_INT_RESET)); 64757c478bd9Sstevel@tonic-gate 64767c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_RESET) { 64777c478bd9Sstevel@tonic-gate return (ACTION_FINRST); 64787c478bd9Sstevel@tonic-gate } 64797c478bd9Sstevel@tonic-gate 64807c478bd9Sstevel@tonic-gate /* 64817c478bd9Sstevel@tonic-gate * Illegal cmd to fas: 64827c478bd9Sstevel@tonic-gate * This should not happen. The one situation where 64837c478bd9Sstevel@tonic-gate * we can get an ILLEGAL COMMAND interrupt is due to 64847c478bd9Sstevel@tonic-gate * a bug in the FAS366 during reselection which we 64857c478bd9Sstevel@tonic-gate * should be handling in fas_reconnect(). 64867c478bd9Sstevel@tonic-gate */ 64877c478bd9Sstevel@tonic-gate if (fas->f_intr & FAS_INT_ILLEGAL) { 64887c478bd9Sstevel@tonic-gate IPRINTF1("lastcmd=%x\n", fas->f_reg->fas_cmd); 64897c478bd9Sstevel@tonic-gate fas_printstate(fas, "ILLEGAL bit set"); 64907c478bd9Sstevel@tonic-gate return (ACTION_RESET); 64917c478bd9Sstevel@tonic-gate } 64927c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 6493360e6f5eSmathue return (ACTION_RETURN); 64947c478bd9Sstevel@tonic-gate } 64957c478bd9Sstevel@tonic-gate 64967c478bd9Sstevel@tonic-gate /* 64977c478bd9Sstevel@tonic-gate * set throttles for all luns of this target 64987c478bd9Sstevel@tonic-gate */ 64997c478bd9Sstevel@tonic-gate static void 65007c478bd9Sstevel@tonic-gate fas_set_throttles(struct fas *fas, int slot, int n, int what) 65017c478bd9Sstevel@tonic-gate { 65027c478bd9Sstevel@tonic-gate int i; 65037c478bd9Sstevel@tonic-gate 65047c478bd9Sstevel@tonic-gate /* 65057c478bd9Sstevel@tonic-gate * if the bus is draining/quiesced, no changes to the throttles 65067c478bd9Sstevel@tonic-gate * are allowed. Not allowing change of throttles during draining 65077c478bd9Sstevel@tonic-gate * limits error recovery but will reduce draining time 65087c478bd9Sstevel@tonic-gate * 65097c478bd9Sstevel@tonic-gate * all throttles should have been set to HOLD_THROTTLE 65107c478bd9Sstevel@tonic-gate */ 65117c478bd9Sstevel@tonic-gate if (fas->f_softstate & (FAS_SS_QUIESCED | FAS_SS_DRAINING)) { 65127c478bd9Sstevel@tonic-gate return; 65137c478bd9Sstevel@tonic-gate } 65147c478bd9Sstevel@tonic-gate 65157c478bd9Sstevel@tonic-gate ASSERT((n == 1) || (n == N_SLOTS) || (n == NLUNS_PER_TARGET)); 65167c478bd9Sstevel@tonic-gate ASSERT((slot + n) <= N_SLOTS); 65177c478bd9Sstevel@tonic-gate if (n == NLUNS_PER_TARGET) { 65187c478bd9Sstevel@tonic-gate slot &= ~(NLUNS_PER_TARGET - 1); 65197c478bd9Sstevel@tonic-gate } 65207c478bd9Sstevel@tonic-gate 65217c478bd9Sstevel@tonic-gate for (i = slot; i < (slot + n); i++) { 65227c478bd9Sstevel@tonic-gate if (what == HOLD_THROTTLE) { 65237c478bd9Sstevel@tonic-gate fas->f_throttle[i] = HOLD_THROTTLE; 65247c478bd9Sstevel@tonic-gate } else if ((fas->f_reset_delay[i/NLUNS_PER_TARGET]) == 0) { 65257c478bd9Sstevel@tonic-gate if (what == MAX_THROTTLE) { 65267c478bd9Sstevel@tonic-gate int tshift = 1 << (i/NLUNS_PER_TARGET); 65277c478bd9Sstevel@tonic-gate fas->f_throttle[i] = (short) 65287c478bd9Sstevel@tonic-gate ((fas->f_notag & tshift)? 1 : what); 65297c478bd9Sstevel@tonic-gate } else { 65307c478bd9Sstevel@tonic-gate fas->f_throttle[i] = what; 65317c478bd9Sstevel@tonic-gate } 65327c478bd9Sstevel@tonic-gate } 65337c478bd9Sstevel@tonic-gate } 65347c478bd9Sstevel@tonic-gate } 65357c478bd9Sstevel@tonic-gate 65367c478bd9Sstevel@tonic-gate static void 65377c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(struct fas *fas, int slot, int what) 65387c478bd9Sstevel@tonic-gate { 65397c478bd9Sstevel@tonic-gate /* 65407c478bd9Sstevel@tonic-gate * fas_set_throttle will adjust slot to starting at LUN 0 65417c478bd9Sstevel@tonic-gate */ 65427c478bd9Sstevel@tonic-gate fas_set_throttles(fas, slot, NLUNS_PER_TARGET, what); 65437c478bd9Sstevel@tonic-gate } 65447c478bd9Sstevel@tonic-gate 65457c478bd9Sstevel@tonic-gate static void 65467c478bd9Sstevel@tonic-gate fas_full_throttle(struct fas *fas, int slot) 65477c478bd9Sstevel@tonic-gate { 65487c478bd9Sstevel@tonic-gate fas_set_throttles(fas, slot, 1, MAX_THROTTLE); 65497c478bd9Sstevel@tonic-gate } 65507c478bd9Sstevel@tonic-gate 65517c478bd9Sstevel@tonic-gate /* 65527c478bd9Sstevel@tonic-gate * run a polled cmd 65537c478bd9Sstevel@tonic-gate */ 65547c478bd9Sstevel@tonic-gate static void 65557c478bd9Sstevel@tonic-gate fas_runpoll(struct fas *fas, short slot, struct fas_cmd *sp) 65567c478bd9Sstevel@tonic-gate { 65577c478bd9Sstevel@tonic-gate int limit, i, n; 65587c478bd9Sstevel@tonic-gate int timeout = 0; 65597c478bd9Sstevel@tonic-gate 65607c478bd9Sstevel@tonic-gate DPRINTF4("runpoll: slot=%x, cmd=%x, current_sp=0x%p, tcmds=%x\n", 65617c478bd9Sstevel@tonic-gate slot, *((uchar_t *)sp->cmd_pkt->pkt_cdbp), 65627c478bd9Sstevel@tonic-gate (void *)fas->f_current_sp, fas->f_tcmds[slot]); 65637c478bd9Sstevel@tonic-gate 65647c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_RUNPOLL_START, "fas_runpoll_start"); 65657c478bd9Sstevel@tonic-gate 65667c478bd9Sstevel@tonic-gate /* 65677c478bd9Sstevel@tonic-gate * wait for cmd to complete 65687c478bd9Sstevel@tonic-gate * don't start new cmds so set throttles to HOLD_THROTTLE 65697c478bd9Sstevel@tonic-gate */ 65707c478bd9Sstevel@tonic-gate while ((sp->cmd_flags & CFLAG_COMPLETED) == 0) { 65717c478bd9Sstevel@tonic-gate if (!(sp->cmd_flags & CFLAG_CMDPROXY)) { 65727c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, HOLD_THROTTLE); 65737c478bd9Sstevel@tonic-gate } 65747c478bd9Sstevel@tonic-gate if ((fas->f_state != STATE_FREE) || INTPENDING(fas)) { 65757c478bd9Sstevel@tonic-gate if (fas_dopoll(fas, POLL_TIMEOUT) <= 0) { 65767c478bd9Sstevel@tonic-gate IPRINTF("runpoll: timeout on draining\n"); 65777c478bd9Sstevel@tonic-gate goto bad; 65787c478bd9Sstevel@tonic-gate } 65797c478bd9Sstevel@tonic-gate } 65807c478bd9Sstevel@tonic-gate 65817c478bd9Sstevel@tonic-gate ASSERT(fas->f_state == STATE_FREE); 65827c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp == NULL); 65837c478bd9Sstevel@tonic-gate 65847c478bd9Sstevel@tonic-gate /* 65857c478bd9Sstevel@tonic-gate * if this is not a proxy cmd, don't start the cmd 65867c478bd9Sstevel@tonic-gate * without draining the active cmd(s) 65877c478bd9Sstevel@tonic-gate * for proxy cmds, we zap the active cmd and assume 65887c478bd9Sstevel@tonic-gate * that the caller will take care of this 65897c478bd9Sstevel@tonic-gate * For tagged cmds, wait with submitting a non-tagged 65907c478bd9Sstevel@tonic-gate * cmd until the queue has been drained 65917c478bd9Sstevel@tonic-gate * If the cmd is a request sense, then draining won't 65927c478bd9Sstevel@tonic-gate * help since we are in contingence allegiance condition 65937c478bd9Sstevel@tonic-gate */ 65947c478bd9Sstevel@tonic-gate if (!(sp->cmd_flags & CFLAG_CMDPROXY)) { 65957c478bd9Sstevel@tonic-gate uchar_t *cmdp = (uchar_t *)sp->cmd_pkt->pkt_cdbp; 65967c478bd9Sstevel@tonic-gate 65977c478bd9Sstevel@tonic-gate if ((fas->f_tcmds[slot]) && 65987c478bd9Sstevel@tonic-gate (NOTAG(Tgt(sp)) || 65997c478bd9Sstevel@tonic-gate (((sp->cmd_pkt_flags & FLAG_TAGMASK) == 0) && 66007c478bd9Sstevel@tonic-gate (*cmdp != SCMD_REQUEST_SENSE)))) { 66017c478bd9Sstevel@tonic-gate if (timeout < POLL_TIMEOUT) { 66027c478bd9Sstevel@tonic-gate timeout += 100; 66037c478bd9Sstevel@tonic-gate drv_usecwait(100); 66047c478bd9Sstevel@tonic-gate continue; 66057c478bd9Sstevel@tonic-gate } else { 66067c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 66077c478bd9Sstevel@tonic-gate "polled cmd failed (target busy)"); 66087c478bd9Sstevel@tonic-gate goto cleanup; 66097c478bd9Sstevel@tonic-gate } 66107c478bd9Sstevel@tonic-gate } 66117c478bd9Sstevel@tonic-gate } 66127c478bd9Sstevel@tonic-gate 66137c478bd9Sstevel@tonic-gate /* 66147c478bd9Sstevel@tonic-gate * If the draining of active commands killed the 66157c478bd9Sstevel@tonic-gate * the current polled command, we're done.. 66167c478bd9Sstevel@tonic-gate */ 66177c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_COMPLETED) { 66187c478bd9Sstevel@tonic-gate break; 66197c478bd9Sstevel@tonic-gate } 66207c478bd9Sstevel@tonic-gate 66217c478bd9Sstevel@tonic-gate /* 66227c478bd9Sstevel@tonic-gate * ensure we are not accessing a target too quickly 66237c478bd9Sstevel@tonic-gate * after a reset. the throttles get set back later 66247c478bd9Sstevel@tonic-gate * by the reset delay watch; hopefully, we don't go 66257c478bd9Sstevel@tonic-gate * thru this loop more than once 66267c478bd9Sstevel@tonic-gate */ 66277c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[slot/NLUNS_PER_TARGET]) { 66287c478bd9Sstevel@tonic-gate IPRINTF1("reset delay set for slot %x\n", slot); 66297c478bd9Sstevel@tonic-gate drv_usecwait(fas->f_scsi_reset_delay * 1000); 66307c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 66317c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[i]) { 66327c478bd9Sstevel@tonic-gate int s = i * NLUNS_PER_TARGET; 66337c478bd9Sstevel@tonic-gate int e = s + NLUNS_PER_TARGET; 66347c478bd9Sstevel@tonic-gate fas->f_reset_delay[i] = 0; 66357c478bd9Sstevel@tonic-gate for (; s < e; s++) { 66367c478bd9Sstevel@tonic-gate fas_full_throttle(fas, s); 66377c478bd9Sstevel@tonic-gate } 66387c478bd9Sstevel@tonic-gate } 66397c478bd9Sstevel@tonic-gate } 66407c478bd9Sstevel@tonic-gate } 66417c478bd9Sstevel@tonic-gate 66427c478bd9Sstevel@tonic-gate /* 66437c478bd9Sstevel@tonic-gate * fas_startcmd() will return false if preempted 66447c478bd9Sstevel@tonic-gate * or draining 66457c478bd9Sstevel@tonic-gate */ 66467c478bd9Sstevel@tonic-gate if (fas_startcmd(fas, sp) != TRUE) { 66477c478bd9Sstevel@tonic-gate IPRINTF("runpoll: cannot start new cmds\n"); 66487c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp != sp); 66497c478bd9Sstevel@tonic-gate continue; 66507c478bd9Sstevel@tonic-gate } 66517c478bd9Sstevel@tonic-gate 66527c478bd9Sstevel@tonic-gate /* 66537c478bd9Sstevel@tonic-gate * We're now 'running' this command. 66547c478bd9Sstevel@tonic-gate * 66557c478bd9Sstevel@tonic-gate * fas_dopoll will always return when 66567c478bd9Sstevel@tonic-gate * fas->f_state is STATE_FREE, and 66577c478bd9Sstevel@tonic-gate */ 66587c478bd9Sstevel@tonic-gate limit = sp->cmd_pkt->pkt_time * 1000000; 66597c478bd9Sstevel@tonic-gate if (limit == 0) { 66607c478bd9Sstevel@tonic-gate limit = POLL_TIMEOUT; 66617c478bd9Sstevel@tonic-gate } 66627c478bd9Sstevel@tonic-gate 66637c478bd9Sstevel@tonic-gate /* 66647c478bd9Sstevel@tonic-gate * if the cmd disconnected, the first call to fas_dopoll 66657c478bd9Sstevel@tonic-gate * will return with bus free; we go thru the loop one more 66667c478bd9Sstevel@tonic-gate * time and wait limit usec for the target to reconnect 66677c478bd9Sstevel@tonic-gate */ 66687c478bd9Sstevel@tonic-gate for (i = 0; i <= POLL_TIMEOUT; i += 100) { 66697c478bd9Sstevel@tonic-gate 66707c478bd9Sstevel@tonic-gate if ((n = fas_dopoll(fas, limit)) <= 0) { 66717c478bd9Sstevel@tonic-gate IPRINTF("runpoll: timeout on polling\n"); 66727c478bd9Sstevel@tonic-gate goto bad; 66737c478bd9Sstevel@tonic-gate } 66747c478bd9Sstevel@tonic-gate 66757c478bd9Sstevel@tonic-gate /* 66767c478bd9Sstevel@tonic-gate * If a preemption occurred that caused this 66777c478bd9Sstevel@tonic-gate * command to actually not start, go around 66787c478bd9Sstevel@tonic-gate * the loop again. If CFLAG_COMPLETED is set, the 66797c478bd9Sstevel@tonic-gate * command completed 66807c478bd9Sstevel@tonic-gate */ 66817c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_COMPLETED) || 66827c478bd9Sstevel@tonic-gate (sp->cmd_pkt->pkt_state == 0)) { 66837c478bd9Sstevel@tonic-gate break; 66847c478bd9Sstevel@tonic-gate } 66857c478bd9Sstevel@tonic-gate 66867c478bd9Sstevel@tonic-gate /* 66877c478bd9Sstevel@tonic-gate * the bus may have gone free because the target 66887c478bd9Sstevel@tonic-gate * disconnected; go thru the loop again 66897c478bd9Sstevel@tonic-gate */ 66907c478bd9Sstevel@tonic-gate ASSERT(fas->f_state == STATE_FREE); 66917c478bd9Sstevel@tonic-gate if (n == 0) { 66927c478bd9Sstevel@tonic-gate /* 66937c478bd9Sstevel@tonic-gate * bump i, we have waited limit usecs in 66947c478bd9Sstevel@tonic-gate * fas_dopoll 66957c478bd9Sstevel@tonic-gate */ 66967c478bd9Sstevel@tonic-gate i += limit - 100; 66977c478bd9Sstevel@tonic-gate } 66987c478bd9Sstevel@tonic-gate } 66997c478bd9Sstevel@tonic-gate 67007c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_COMPLETED) == 0) { 67017c478bd9Sstevel@tonic-gate 67027c478bd9Sstevel@tonic-gate if (i > POLL_TIMEOUT) { 67037c478bd9Sstevel@tonic-gate IPRINTF("polled timeout on disc. cmd\n"); 67047c478bd9Sstevel@tonic-gate goto bad; 67057c478bd9Sstevel@tonic-gate } 67067c478bd9Sstevel@tonic-gate 67077c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_state) { 67087c478bd9Sstevel@tonic-gate /* 67097c478bd9Sstevel@tonic-gate * don't go thru the loop again; the cmd 67107c478bd9Sstevel@tonic-gate * was already started 67117c478bd9Sstevel@tonic-gate */ 67127c478bd9Sstevel@tonic-gate IPRINTF("fas_runpoll: cmd started??\n"); 67137c478bd9Sstevel@tonic-gate goto bad; 67147c478bd9Sstevel@tonic-gate } 67157c478bd9Sstevel@tonic-gate } 67167c478bd9Sstevel@tonic-gate } 67177c478bd9Sstevel@tonic-gate 67187c478bd9Sstevel@tonic-gate /* 67197c478bd9Sstevel@tonic-gate * blindly restore throttles which is preferable over 67207c478bd9Sstevel@tonic-gate * leaving throttle hanging at 0 and noone to clear it 67217c478bd9Sstevel@tonic-gate */ 67227c478bd9Sstevel@tonic-gate if (!(sp->cmd_flags & CFLAG_CMDPROXY)) { 67237c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, MAX_THROTTLE); 67247c478bd9Sstevel@tonic-gate } 67257c478bd9Sstevel@tonic-gate 67267c478bd9Sstevel@tonic-gate /* 67277c478bd9Sstevel@tonic-gate * ensure that the cmd is completely removed 67287c478bd9Sstevel@tonic-gate */ 67297c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, 0); 67307c478bd9Sstevel@tonic-gate 67317c478bd9Sstevel@tonic-gate /* 67327c478bd9Sstevel@tonic-gate * If we stored up commands to do, start them off now. 67337c478bd9Sstevel@tonic-gate */ 67347c478bd9Sstevel@tonic-gate if ((fas->f_state == STATE_FREE) && 67357c478bd9Sstevel@tonic-gate (!(sp->cmd_flags & CFLAG_CMDPROXY))) { 67367c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 67377c478bd9Sstevel@tonic-gate } 67387c478bd9Sstevel@tonic-gate exit: 67397c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_RUNPOLL_END, "fas_runpoll_end"); 67407c478bd9Sstevel@tonic-gate return; 67417c478bd9Sstevel@tonic-gate 67427c478bd9Sstevel@tonic-gate bad: 67437c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "Polled cmd failed"); 67447c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 67457c478bd9Sstevel@tonic-gate fas_printstate(fas, "fas_runpoll: polled cmd failed"); 67467c478bd9Sstevel@tonic-gate #endif /* FASDEBUG */ 67477c478bd9Sstevel@tonic-gate 67487c478bd9Sstevel@tonic-gate cleanup: 67497c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, MAX_THROTTLE); 67507c478bd9Sstevel@tonic-gate 67517c478bd9Sstevel@tonic-gate /* 67527c478bd9Sstevel@tonic-gate * clean up all traces of this sp because fas_runpoll will return 67537c478bd9Sstevel@tonic-gate * before fas_reset_recovery() cleans up 67547c478bd9Sstevel@tonic-gate */ 67557c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 67567c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 67577c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 67587c478bd9Sstevel@tonic-gate 67597c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_CMDPROXY) == 0) { 67607c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 67617c478bd9Sstevel@tonic-gate } 67627c478bd9Sstevel@tonic-gate goto exit; 67637c478bd9Sstevel@tonic-gate } 67647c478bd9Sstevel@tonic-gate 67657c478bd9Sstevel@tonic-gate /* 67667c478bd9Sstevel@tonic-gate * Poll for command completion (i.e., no interrupts) 67677c478bd9Sstevel@tonic-gate * limit is in usec (and will not be very accurate) 67687c478bd9Sstevel@tonic-gate * 67697c478bd9Sstevel@tonic-gate * the assumption is that we only run polled cmds in interrupt context 67707c478bd9Sstevel@tonic-gate * as scsi_transport will filter out FLAG_NOINTR 67717c478bd9Sstevel@tonic-gate */ 67727c478bd9Sstevel@tonic-gate static int 67737c478bd9Sstevel@tonic-gate fas_dopoll(struct fas *fas, int limit) 67747c478bd9Sstevel@tonic-gate { 67757c478bd9Sstevel@tonic-gate int i, n; 67767c478bd9Sstevel@tonic-gate 67777c478bd9Sstevel@tonic-gate /* 67787c478bd9Sstevel@tonic-gate * timeout is not very accurate since we don't know how 67797c478bd9Sstevel@tonic-gate * long the poll takes 67807c478bd9Sstevel@tonic-gate * also if the packet gets started fairly late, we may 67817c478bd9Sstevel@tonic-gate * timeout prematurely 67827c478bd9Sstevel@tonic-gate * fas_dopoll always returns if e_state transitions to STATE_FREE 67837c478bd9Sstevel@tonic-gate */ 67847c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_DOPOLL_START, "fas_dopoll_start"); 67857c478bd9Sstevel@tonic-gate 67867c478bd9Sstevel@tonic-gate if (limit == 0) { 67877c478bd9Sstevel@tonic-gate limit = POLL_TIMEOUT; 67887c478bd9Sstevel@tonic-gate } 67897c478bd9Sstevel@tonic-gate 67907c478bd9Sstevel@tonic-gate for (n = i = 0; i < limit; i += 100) { 67917c478bd9Sstevel@tonic-gate if (INTPENDING(fas)) { 67927c478bd9Sstevel@tonic-gate fas->f_polled_intr = 1; 67937c478bd9Sstevel@tonic-gate n++; 67947c478bd9Sstevel@tonic-gate (void) fas_intr_svc(fas); 67957c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) 67967c478bd9Sstevel@tonic-gate break; 67977c478bd9Sstevel@tonic-gate } 67987c478bd9Sstevel@tonic-gate drv_usecwait(100); 67997c478bd9Sstevel@tonic-gate } 68007c478bd9Sstevel@tonic-gate 68017c478bd9Sstevel@tonic-gate if (i >= limit && fas->f_state != STATE_FREE) { 68027c478bd9Sstevel@tonic-gate fas_printstate(fas, "polled command timeout"); 68037c478bd9Sstevel@tonic-gate n = -1; 68047c478bd9Sstevel@tonic-gate } 68057c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_SCSI_FAS, TR_FAS_DOPOLL_END, 68067c478bd9Sstevel@tonic-gate "fas_dopoll_end: rval %x", n); 68077c478bd9Sstevel@tonic-gate return (n); 68087c478bd9Sstevel@tonic-gate } 68097c478bd9Sstevel@tonic-gate 68107c478bd9Sstevel@tonic-gate /* 68117c478bd9Sstevel@tonic-gate * prepare a sync negotiation message 68127c478bd9Sstevel@tonic-gate */ 68137c478bd9Sstevel@tonic-gate static void 68147c478bd9Sstevel@tonic-gate fas_make_sdtr(struct fas *fas, int msgout_offset, int target) 68157c478bd9Sstevel@tonic-gate { 68167c478bd9Sstevel@tonic-gate uchar_t *p = fas->f_cur_msgout + msgout_offset; 68177c478bd9Sstevel@tonic-gate ushort_t tshift = 1<<target; 68187c478bd9Sstevel@tonic-gate uchar_t period = MIN_SYNC_PERIOD(fas); 68197c478bd9Sstevel@tonic-gate uchar_t offset = fas_default_offset; 68207c478bd9Sstevel@tonic-gate 68217c478bd9Sstevel@tonic-gate /* 68227c478bd9Sstevel@tonic-gate * If this target experienced a sync backoff use the 68237c478bd9Sstevel@tonic-gate * target's sync speed that was adjusted in 68247c478bd9Sstevel@tonic-gate * fas_sync_wide_backoff. For second sync backoff, 68257c478bd9Sstevel@tonic-gate * offset will be ajusted below in sanity checks. 68267c478bd9Sstevel@tonic-gate */ 68277c478bd9Sstevel@tonic-gate if (fas->f_backoff & tshift) { 68287c478bd9Sstevel@tonic-gate period = fas->f_neg_period[target]; 68297c478bd9Sstevel@tonic-gate } 68307c478bd9Sstevel@tonic-gate 68317c478bd9Sstevel@tonic-gate /* 68327c478bd9Sstevel@tonic-gate * If this is a responce to a target initiated sdtr, 68337c478bd9Sstevel@tonic-gate * use the agreed upon values. 68347c478bd9Sstevel@tonic-gate */ 68357c478bd9Sstevel@tonic-gate if (fas->f_sdtr_sent & 1) { 68367c478bd9Sstevel@tonic-gate period = fas->f_neg_period[target]; 68377c478bd9Sstevel@tonic-gate offset = fas->f_offset[target]; 68387c478bd9Sstevel@tonic-gate } 68397c478bd9Sstevel@tonic-gate 68407c478bd9Sstevel@tonic-gate /* 68417c478bd9Sstevel@tonic-gate * If the target driver disabled 68427c478bd9Sstevel@tonic-gate * sync then make offset = 0 68437c478bd9Sstevel@tonic-gate */ 68447c478bd9Sstevel@tonic-gate if (fas->f_force_async & tshift) { 68457c478bd9Sstevel@tonic-gate offset = 0; 68467c478bd9Sstevel@tonic-gate } 68477c478bd9Sstevel@tonic-gate 68487c478bd9Sstevel@tonic-gate /* 68497c478bd9Sstevel@tonic-gate * sanity check of period and offset 68507c478bd9Sstevel@tonic-gate */ 68517c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[target] & SCSI_OPTIONS_FAST) { 68527c478bd9Sstevel@tonic-gate if (period < (uchar_t)(DEFAULT_FASTSYNC_PERIOD/4)) { 68537c478bd9Sstevel@tonic-gate period = (uchar_t)(DEFAULT_FASTSYNC_PERIOD/4); 68547c478bd9Sstevel@tonic-gate } 68557c478bd9Sstevel@tonic-gate } else if (fas->f_target_scsi_options[target] & SCSI_OPTIONS_SYNC) { 68567c478bd9Sstevel@tonic-gate if (period < (uchar_t)(DEFAULT_SYNC_PERIOD/4)) { 68577c478bd9Sstevel@tonic-gate period = (uchar_t)(DEFAULT_SYNC_PERIOD/4); 68587c478bd9Sstevel@tonic-gate } 68597c478bd9Sstevel@tonic-gate } else { 68607c478bd9Sstevel@tonic-gate fas->f_nosync |= tshift; 68617c478bd9Sstevel@tonic-gate } 68627c478bd9Sstevel@tonic-gate 68637c478bd9Sstevel@tonic-gate if (fas->f_nosync & tshift) { 68647c478bd9Sstevel@tonic-gate offset = 0; 68657c478bd9Sstevel@tonic-gate } 68667c478bd9Sstevel@tonic-gate 68677c478bd9Sstevel@tonic-gate if ((uchar_t)(offset & 0xf) > fas_default_offset) { 68687c478bd9Sstevel@tonic-gate offset = fas_default_offset | fas->f_req_ack_delay; 68697c478bd9Sstevel@tonic-gate } 68707c478bd9Sstevel@tonic-gate 68717c478bd9Sstevel@tonic-gate fas->f_neg_period[target] = (uchar_t)period; 68727c478bd9Sstevel@tonic-gate fas->f_offset[target] = (uchar_t)offset; 68737c478bd9Sstevel@tonic-gate 68747c478bd9Sstevel@tonic-gate *p++ = (uchar_t)MSG_EXTENDED; 68757c478bd9Sstevel@tonic-gate *p++ = (uchar_t)3; 68767c478bd9Sstevel@tonic-gate *p++ = (uchar_t)MSG_SYNCHRONOUS; 68777c478bd9Sstevel@tonic-gate *p++ = period; 68787c478bd9Sstevel@tonic-gate *p++ = offset & 0xf; 68797c478bd9Sstevel@tonic-gate fas->f_omsglen = 5 + msgout_offset; 68807c478bd9Sstevel@tonic-gate 68817c478bd9Sstevel@tonic-gate IPRINTF2("fas_make_sdtr: period = %x, offset = %x\n", 68827c478bd9Sstevel@tonic-gate period, offset); 68837c478bd9Sstevel@tonic-gate /* 68847c478bd9Sstevel@tonic-gate * increment sdtr flag, odd value indicates that we initiated 68857c478bd9Sstevel@tonic-gate * the negotiation 68867c478bd9Sstevel@tonic-gate */ 68877c478bd9Sstevel@tonic-gate fas->f_sdtr_sent++; 68887c478bd9Sstevel@tonic-gate 68897c478bd9Sstevel@tonic-gate /* 68907c478bd9Sstevel@tonic-gate * the target may reject the optional sync message so 68917c478bd9Sstevel@tonic-gate * to avoid negotiating on every cmd, set sync known here 68927c478bd9Sstevel@tonic-gate * we should not negotiate wide after sync again 68937c478bd9Sstevel@tonic-gate */ 68947c478bd9Sstevel@tonic-gate fas->f_sync_known |= 1<<target; 68957c478bd9Sstevel@tonic-gate fas->f_wide_known |= 1<<target; 68967c478bd9Sstevel@tonic-gate } 68977c478bd9Sstevel@tonic-gate 68987c478bd9Sstevel@tonic-gate /* 68997c478bd9Sstevel@tonic-gate * prepare a wide negotiation message 69007c478bd9Sstevel@tonic-gate */ 69017c478bd9Sstevel@tonic-gate static void 69027c478bd9Sstevel@tonic-gate fas_make_wdtr(struct fas *fas, int msgout_offset, int target, int width) 69037c478bd9Sstevel@tonic-gate { 69047c478bd9Sstevel@tonic-gate uchar_t *p = fas->f_cur_msgout + msgout_offset; 69057c478bd9Sstevel@tonic-gate 69067c478bd9Sstevel@tonic-gate if (((fas->f_target_scsi_options[target] & SCSI_OPTIONS_WIDE) == 0) || 69077c478bd9Sstevel@tonic-gate (fas->f_nowide & (1<<target))) { 69087c478bd9Sstevel@tonic-gate fas->f_nowide |= 1<<target; 69097c478bd9Sstevel@tonic-gate width = 0; 69107c478bd9Sstevel@tonic-gate } 69117c478bd9Sstevel@tonic-gate if (fas->f_force_narrow & (1<<target)) { 69127c478bd9Sstevel@tonic-gate width = 0; 69137c478bd9Sstevel@tonic-gate } 69147c478bd9Sstevel@tonic-gate width = min(FAS_XFER_WIDTH, width); 69157c478bd9Sstevel@tonic-gate 69167c478bd9Sstevel@tonic-gate *p++ = (uchar_t)MSG_EXTENDED; 69177c478bd9Sstevel@tonic-gate *p++ = (uchar_t)2; 69187c478bd9Sstevel@tonic-gate *p++ = (uchar_t)MSG_WIDE_DATA_XFER; 69197c478bd9Sstevel@tonic-gate *p++ = (uchar_t)width; 69207c478bd9Sstevel@tonic-gate fas->f_omsglen = 4 + msgout_offset; 69217c478bd9Sstevel@tonic-gate IPRINTF1("fas_make_wdtr: width=%x\n", width); 69227c478bd9Sstevel@tonic-gate 69237c478bd9Sstevel@tonic-gate /* 69247c478bd9Sstevel@tonic-gate * increment wdtr flag, odd value indicates that we initiated 69257c478bd9Sstevel@tonic-gate * the negotiation 69267c478bd9Sstevel@tonic-gate */ 69277c478bd9Sstevel@tonic-gate fas->f_wdtr_sent++; 69287c478bd9Sstevel@tonic-gate 69297c478bd9Sstevel@tonic-gate /* 69307c478bd9Sstevel@tonic-gate * the target may reject the optional wide message so 69317c478bd9Sstevel@tonic-gate * to avoid negotiating on every cmd, set wide known here 69327c478bd9Sstevel@tonic-gate */ 69337c478bd9Sstevel@tonic-gate fas->f_wide_known |= 1<<target; 69347c478bd9Sstevel@tonic-gate 69357c478bd9Sstevel@tonic-gate fas_set_wide_conf3(fas, target, width); 69367c478bd9Sstevel@tonic-gate } 69377c478bd9Sstevel@tonic-gate 69387c478bd9Sstevel@tonic-gate /* 69397c478bd9Sstevel@tonic-gate * auto request sense support 69407c478bd9Sstevel@tonic-gate * create or destroy an auto request sense packet 69417c478bd9Sstevel@tonic-gate */ 69427c478bd9Sstevel@tonic-gate static int 69437c478bd9Sstevel@tonic-gate fas_create_arq_pkt(struct fas *fas, struct scsi_address *ap) 69447c478bd9Sstevel@tonic-gate { 69457c478bd9Sstevel@tonic-gate /* 69467c478bd9Sstevel@tonic-gate * Allocate a request sense packet using get_pktiopb 69477c478bd9Sstevel@tonic-gate */ 69487c478bd9Sstevel@tonic-gate struct fas_cmd *rqpktp; 69497c478bd9Sstevel@tonic-gate uchar_t slot = ap->a_target * NLUNS_PER_TARGET | ap->a_lun; 69507c478bd9Sstevel@tonic-gate struct buf *bp; 69517c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data; 69527c478bd9Sstevel@tonic-gate 69537c478bd9Sstevel@tonic-gate /* 69547c478bd9Sstevel@tonic-gate * if one exists, don't create another 69557c478bd9Sstevel@tonic-gate */ 69567c478bd9Sstevel@tonic-gate if (fas->f_arq_pkt[slot] != 0) { 69577c478bd9Sstevel@tonic-gate return (0); 69587c478bd9Sstevel@tonic-gate } 69597c478bd9Sstevel@tonic-gate 69607c478bd9Sstevel@tonic-gate /* 69617c478bd9Sstevel@tonic-gate * it would be nicer if we could allow the target driver 69627c478bd9Sstevel@tonic-gate * to specify the size but this is easier and OK for most 69637c478bd9Sstevel@tonic-gate * drivers to use SENSE_LENGTH 69647c478bd9Sstevel@tonic-gate * Allocate a request sense packet. 69657c478bd9Sstevel@tonic-gate */ 69667c478bd9Sstevel@tonic-gate bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL, 69677c478bd9Sstevel@tonic-gate SENSE_LENGTH, B_READ, SLEEP_FUNC, NULL); 69687c478bd9Sstevel@tonic-gate rqpktp = PKT2CMD(scsi_init_pkt(ap, 69697c478bd9Sstevel@tonic-gate NULL, bp, CDB_GROUP0, 1, PKT_PRIV_LEN, 69707c478bd9Sstevel@tonic-gate PKT_CONSISTENT, SLEEP_FUNC, NULL)); 69717c478bd9Sstevel@tonic-gate arq_data = 69727c478bd9Sstevel@tonic-gate (struct arq_private_data *)(rqpktp->cmd_pkt->pkt_private); 69737c478bd9Sstevel@tonic-gate arq_data->arq_save_bp = bp; 69747c478bd9Sstevel@tonic-gate 69757c478bd9Sstevel@tonic-gate RQ_MAKECOM_G0((CMD2PKT(rqpktp)), 69767c478bd9Sstevel@tonic-gate FLAG_SENSING | FLAG_HEAD | FLAG_NODISCON, 69777c478bd9Sstevel@tonic-gate (char)SCMD_REQUEST_SENSE, 0, (char)SENSE_LENGTH); 69787c478bd9Sstevel@tonic-gate rqpktp->cmd_flags |= CFLAG_CMDARQ; 69797c478bd9Sstevel@tonic-gate rqpktp->cmd_slot = slot; 69807c478bd9Sstevel@tonic-gate rqpktp->cmd_pkt->pkt_ha_private = rqpktp; 69817c478bd9Sstevel@tonic-gate fas->f_arq_pkt[slot] = rqpktp; 69827c478bd9Sstevel@tonic-gate 69837c478bd9Sstevel@tonic-gate /* 69847c478bd9Sstevel@tonic-gate * we need a function ptr here so abort/reset can 69857c478bd9Sstevel@tonic-gate * defer callbacks; fas_call_pkt_comp() calls 69867c478bd9Sstevel@tonic-gate * fas_complete_arq_pkt() directly without releasing the lock 69877c478bd9Sstevel@tonic-gate * However, since we are not calling back directly thru 69887c478bd9Sstevel@tonic-gate * pkt_comp, don't check this with warlock 69897c478bd9Sstevel@tonic-gate */ 69907c478bd9Sstevel@tonic-gate #ifndef __lock_lint 69917c478bd9Sstevel@tonic-gate rqpktp->cmd_pkt->pkt_comp = 69927c478bd9Sstevel@tonic-gate (void (*)(struct scsi_pkt *))fas_complete_arq_pkt; 69937c478bd9Sstevel@tonic-gate #endif 69947c478bd9Sstevel@tonic-gate return (0); 69957c478bd9Sstevel@tonic-gate } 69967c478bd9Sstevel@tonic-gate 69977c478bd9Sstevel@tonic-gate static int 69987c478bd9Sstevel@tonic-gate fas_delete_arq_pkt(struct fas *fas, struct scsi_address *ap) 69997c478bd9Sstevel@tonic-gate { 70007c478bd9Sstevel@tonic-gate struct fas_cmd *rqpktp; 70017c478bd9Sstevel@tonic-gate int slot = ap->a_target * NLUNS_PER_TARGET | ap->a_lun; 70027c478bd9Sstevel@tonic-gate 70037c478bd9Sstevel@tonic-gate /* 70047c478bd9Sstevel@tonic-gate * if there is still a pkt saved or no rqpkt 70057c478bd9Sstevel@tonic-gate * then we cannot deallocate or there is nothing to do 70067c478bd9Sstevel@tonic-gate */ 70077c478bd9Sstevel@tonic-gate if ((rqpktp = fas->f_arq_pkt[slot]) != NULL) { 70087c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data = 70097c478bd9Sstevel@tonic-gate (struct arq_private_data *)(rqpktp->cmd_pkt->pkt_private); 70107c478bd9Sstevel@tonic-gate struct buf *bp = arq_data->arq_save_bp; 70117c478bd9Sstevel@tonic-gate /* 70127c478bd9Sstevel@tonic-gate * is arq pkt in use? 70137c478bd9Sstevel@tonic-gate */ 70147c478bd9Sstevel@tonic-gate if (arq_data->arq_save_sp) { 70157c478bd9Sstevel@tonic-gate return (-1); 70167c478bd9Sstevel@tonic-gate } 70177c478bd9Sstevel@tonic-gate 70187c478bd9Sstevel@tonic-gate scsi_destroy_pkt(CMD2PKT(rqpktp)); 70197c478bd9Sstevel@tonic-gate scsi_free_consistent_buf(bp); 70207c478bd9Sstevel@tonic-gate fas->f_arq_pkt[slot] = 0; 70217c478bd9Sstevel@tonic-gate } 70227c478bd9Sstevel@tonic-gate return (0); 70237c478bd9Sstevel@tonic-gate } 70247c478bd9Sstevel@tonic-gate 70257c478bd9Sstevel@tonic-gate /* 70267c478bd9Sstevel@tonic-gate * complete an arq packet by copying over transport info and the actual 70277c478bd9Sstevel@tonic-gate * request sense data; called with mutex held from fas_call_pkt_comp() 70287c478bd9Sstevel@tonic-gate */ 70297c478bd9Sstevel@tonic-gate void 70307c478bd9Sstevel@tonic-gate fas_complete_arq_pkt(struct scsi_pkt *pkt) 70317c478bd9Sstevel@tonic-gate { 70327c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(&pkt->pkt_address); 70337c478bd9Sstevel@tonic-gate struct fas_cmd *sp = pkt->pkt_ha_private; 70347c478bd9Sstevel@tonic-gate struct scsi_arq_status *arqstat; 70357c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data = 70367c478bd9Sstevel@tonic-gate (struct arq_private_data *)sp->cmd_pkt->pkt_private; 70377c478bd9Sstevel@tonic-gate struct fas_cmd *ssp = arq_data->arq_save_sp; 70387c478bd9Sstevel@tonic-gate struct buf *bp = arq_data->arq_save_bp; 70397c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 70407c478bd9Sstevel@tonic-gate 70417c478bd9Sstevel@tonic-gate DPRINTF1("completing arq pkt sp=0x%p\n", (void *)sp); 70427c478bd9Sstevel@tonic-gate ASSERT(sp == fas->f_arq_pkt[slot]); 70437c478bd9Sstevel@tonic-gate ASSERT(arq_data->arq_save_sp != NULL); 70447c478bd9Sstevel@tonic-gate ASSERT(ssp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]); 70457c478bd9Sstevel@tonic-gate 70467c478bd9Sstevel@tonic-gate arqstat = (struct scsi_arq_status *)(ssp->cmd_pkt->pkt_scbp); 70477c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_status = *((struct scsi_status *) 70487c478bd9Sstevel@tonic-gate (sp->cmd_pkt->pkt_scbp)); 70497c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_reason = sp->cmd_pkt->pkt_reason; 70507c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_state = sp->cmd_pkt->pkt_state; 70517c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_statistics = sp->cmd_pkt->pkt_statistics; 70527c478bd9Sstevel@tonic-gate arqstat->sts_rqpkt_resid = sp->cmd_pkt->pkt_resid; 70537c478bd9Sstevel@tonic-gate arqstat->sts_sensedata = 70547c478bd9Sstevel@tonic-gate *((struct scsi_extended_sense *)bp->b_un.b_addr); 70557c478bd9Sstevel@tonic-gate ssp->cmd_pkt->pkt_state |= STATE_ARQ_DONE; 70567c478bd9Sstevel@tonic-gate arq_data->arq_save_sp = NULL; 70577c478bd9Sstevel@tonic-gate 70587c478bd9Sstevel@tonic-gate /* 70597c478bd9Sstevel@tonic-gate * ASC=0x47 is parity error 70607c478bd9Sstevel@tonic-gate */ 70617c478bd9Sstevel@tonic-gate if (arqstat->sts_sensedata.es_key == KEY_ABORTED_COMMAND && 70627c478bd9Sstevel@tonic-gate arqstat->sts_sensedata.es_add_code == 0x47) { 70637c478bd9Sstevel@tonic-gate fas_sync_wide_backoff(fas, sp, slot); 70647c478bd9Sstevel@tonic-gate } 70657c478bd9Sstevel@tonic-gate 70667c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, ssp); 70677c478bd9Sstevel@tonic-gate } 70687c478bd9Sstevel@tonic-gate 70697c478bd9Sstevel@tonic-gate /* 70707c478bd9Sstevel@tonic-gate * handle check condition and start an arq packet 70717c478bd9Sstevel@tonic-gate */ 70727c478bd9Sstevel@tonic-gate static int 70737c478bd9Sstevel@tonic-gate fas_handle_sts_chk(struct fas *fas, struct fas_cmd *sp) 70747c478bd9Sstevel@tonic-gate { 70757c478bd9Sstevel@tonic-gate struct fas_cmd *arqsp = fas->f_arq_pkt[sp->cmd_slot]; 70767c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data; 70777c478bd9Sstevel@tonic-gate struct buf *bp; 70787c478bd9Sstevel@tonic-gate 70797c478bd9Sstevel@tonic-gate if ((arqsp == NULL) || (arqsp == sp) || 70807c478bd9Sstevel@tonic-gate (sp->cmd_scblen < sizeof (struct scsi_arq_status))) { 70817c478bd9Sstevel@tonic-gate IPRINTF("no arq packet or cannot arq on arq pkt\n"); 70827c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 70837c478bd9Sstevel@tonic-gate return (0); 70847c478bd9Sstevel@tonic-gate } 70857c478bd9Sstevel@tonic-gate 70867c478bd9Sstevel@tonic-gate arq_data = (struct arq_private_data *)arqsp->cmd_pkt->pkt_private; 70877c478bd9Sstevel@tonic-gate bp = arq_data->arq_save_bp; 70887c478bd9Sstevel@tonic-gate 70897c478bd9Sstevel@tonic-gate ASSERT(sp->cmd_flags & CFLAG_FINISHED); 70907c478bd9Sstevel@tonic-gate ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]); 70917c478bd9Sstevel@tonic-gate DPRINTF3("start arq for slot=%x, arqsp=0x%p, rqpkt=0x%p\n", 70927c478bd9Sstevel@tonic-gate sp->cmd_slot, (void *)arqsp, (void *)fas->f_arq_pkt[sp->cmd_slot]); 70937c478bd9Sstevel@tonic-gate if (arq_data->arq_save_sp != NULL) { 70947c478bd9Sstevel@tonic-gate IPRINTF("auto request sense already in progress\n"); 70957c478bd9Sstevel@tonic-gate goto fail; 70967c478bd9Sstevel@tonic-gate } 70977c478bd9Sstevel@tonic-gate 70987c478bd9Sstevel@tonic-gate arq_data->arq_save_sp = sp; 70997c478bd9Sstevel@tonic-gate 71007c478bd9Sstevel@tonic-gate bzero(bp->b_un.b_addr, sizeof (struct scsi_extended_sense)); 71017c478bd9Sstevel@tonic-gate 71027c478bd9Sstevel@tonic-gate /* 71037c478bd9Sstevel@tonic-gate * copy the timeout from the original packet by lack of a better 71047c478bd9Sstevel@tonic-gate * value 71057c478bd9Sstevel@tonic-gate * we could take the residue of the timeout but that could cause 71067c478bd9Sstevel@tonic-gate * premature timeouts perhaps 71077c478bd9Sstevel@tonic-gate */ 71087c478bd9Sstevel@tonic-gate arqsp->cmd_pkt->pkt_time = sp->cmd_pkt->pkt_time; 71097c478bd9Sstevel@tonic-gate arqsp->cmd_flags &= ~CFLAG_TRANFLAG; 71107c478bd9Sstevel@tonic-gate ASSERT(arqsp->cmd_pkt->pkt_comp != NULL); 71117c478bd9Sstevel@tonic-gate 71127c478bd9Sstevel@tonic-gate /* 71137c478bd9Sstevel@tonic-gate * make sure that auto request sense always goes out 71147c478bd9Sstevel@tonic-gate * after queue full and after throttle was set to draining 71157c478bd9Sstevel@tonic-gate */ 71167c478bd9Sstevel@tonic-gate fas_full_throttle(fas, sp->cmd_slot); 71177c478bd9Sstevel@tonic-gate (void) fas_accept_pkt(fas, arqsp, NO_TRAN_BUSY); 71187c478bd9Sstevel@tonic-gate return (0); 71197c478bd9Sstevel@tonic-gate 71207c478bd9Sstevel@tonic-gate fail: 71217c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_TRAN_ERR, 0); 71227c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "auto request sense failed\n"); 71237c478bd9Sstevel@tonic-gate fas_dump_cmd(fas, sp); 71247c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 71257c478bd9Sstevel@tonic-gate return (-1); 71267c478bd9Sstevel@tonic-gate } 71277c478bd9Sstevel@tonic-gate 71287c478bd9Sstevel@tonic-gate 71297c478bd9Sstevel@tonic-gate /* 71307c478bd9Sstevel@tonic-gate * handle qfull condition 71317c478bd9Sstevel@tonic-gate */ 71327c478bd9Sstevel@tonic-gate static void 71337c478bd9Sstevel@tonic-gate fas_handle_qfull(struct fas *fas, struct fas_cmd *sp) 71347c478bd9Sstevel@tonic-gate { 71357c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 71367c478bd9Sstevel@tonic-gate 71377c478bd9Sstevel@tonic-gate if ((++sp->cmd_qfull_retries > fas->f_qfull_retries[Tgt(sp)]) || 71387c478bd9Sstevel@tonic-gate (fas->f_qfull_retries[Tgt(sp)] == 0)) { 71397c478bd9Sstevel@tonic-gate /* 71407c478bd9Sstevel@tonic-gate * We have exhausted the retries on QFULL, or, 71417c478bd9Sstevel@tonic-gate * the target driver has indicated that it 71427c478bd9Sstevel@tonic-gate * wants to handle QFULL itself by setting 71437c478bd9Sstevel@tonic-gate * qfull-retries capability to 0. In either case 71447c478bd9Sstevel@tonic-gate * we want the target driver's QFULL handling 71457c478bd9Sstevel@tonic-gate * to kick in. We do this by having pkt_reason 71467c478bd9Sstevel@tonic-gate * as CMD_CMPLT and pkt_scbp as STATUS_QFULL. 71477c478bd9Sstevel@tonic-gate */ 71487c478bd9Sstevel@tonic-gate IPRINTF2("%d.%d: status queue full, retries over\n", 71497c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp)); 71507c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, DRAIN_THROTTLE); 71517c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 71527c478bd9Sstevel@tonic-gate } else { 71537c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[Tgt(sp)] == 0) { 71547c478bd9Sstevel@tonic-gate fas->f_throttle[slot] = 71557c478bd9Sstevel@tonic-gate max((fas->f_tcmds[slot] - 2), 0); 71567c478bd9Sstevel@tonic-gate } 71577c478bd9Sstevel@tonic-gate IPRINTF3("%d.%d: status queue full, new throttle = %d, " 71587c478bd9Sstevel@tonic-gate "retrying\n", Tgt(sp), Lun(sp), fas->f_throttle[slot]); 71597c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_flags |= FLAG_HEAD; 71607c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_TRANFLAG; 71617c478bd9Sstevel@tonic-gate (void) fas_accept_pkt(fas, sp, NO_TRAN_BUSY); 71627c478bd9Sstevel@tonic-gate 71637c478bd9Sstevel@tonic-gate /* 71647c478bd9Sstevel@tonic-gate * when target gives queue full status with no commands 71657c478bd9Sstevel@tonic-gate * outstanding (f_tcmds[] == 0), throttle is set to 0 71667c478bd9Sstevel@tonic-gate * (HOLD_THROTTLE), and the queue full handling starts 71677c478bd9Sstevel@tonic-gate * (see psarc/1994/313); if there are commands outstanding, 71687c478bd9Sstevel@tonic-gate * the throttle is set to (f_tcmds[] - 2) 71697c478bd9Sstevel@tonic-gate */ 71707c478bd9Sstevel@tonic-gate if (fas->f_throttle[slot] == HOLD_THROTTLE) { 71717c478bd9Sstevel@tonic-gate /* 71727c478bd9Sstevel@tonic-gate * By setting throttle to QFULL_THROTTLE, we 71737c478bd9Sstevel@tonic-gate * avoid submitting new commands and in 71747c478bd9Sstevel@tonic-gate * fas_restart_cmd find out slots which need 71757c478bd9Sstevel@tonic-gate * their throttles to be cleared. 71767c478bd9Sstevel@tonic-gate */ 71777c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, QFULL_THROTTLE); 71787c478bd9Sstevel@tonic-gate if (fas->f_restart_cmd_timeid == 0) { 71797c478bd9Sstevel@tonic-gate fas->f_restart_cmd_timeid = 71807c478bd9Sstevel@tonic-gate timeout(fas_restart_cmd, fas, 71817c478bd9Sstevel@tonic-gate fas->f_qfull_retry_interval[Tgt(sp)]); 71827c478bd9Sstevel@tonic-gate } 71837c478bd9Sstevel@tonic-gate } 71847c478bd9Sstevel@tonic-gate } 71857c478bd9Sstevel@tonic-gate } 71867c478bd9Sstevel@tonic-gate 71877c478bd9Sstevel@tonic-gate /* 71887c478bd9Sstevel@tonic-gate * invoked from timeout() to restart qfull cmds with throttle == 0 71897c478bd9Sstevel@tonic-gate */ 71907c478bd9Sstevel@tonic-gate static void 71917c478bd9Sstevel@tonic-gate fas_restart_cmd(void *fas_arg) 71927c478bd9Sstevel@tonic-gate { 71937c478bd9Sstevel@tonic-gate struct fas *fas = fas_arg; 71947c478bd9Sstevel@tonic-gate int i; 71957c478bd9Sstevel@tonic-gate 71967c478bd9Sstevel@tonic-gate IPRINTF("fas_restart_cmd:\n"); 71977c478bd9Sstevel@tonic-gate 71987c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 71997c478bd9Sstevel@tonic-gate fas->f_restart_cmd_timeid = 0; 72007c478bd9Sstevel@tonic-gate 72017c478bd9Sstevel@tonic-gate for (i = 0; i < N_SLOTS; i += NLUNS_PER_TARGET) { 72027c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[i/NLUNS_PER_TARGET] == 0) { 72037c478bd9Sstevel@tonic-gate if (fas->f_throttle[i] == QFULL_THROTTLE) { 72047c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, 72057c478bd9Sstevel@tonic-gate i, MAX_THROTTLE); 72067c478bd9Sstevel@tonic-gate } 72077c478bd9Sstevel@tonic-gate } 72087c478bd9Sstevel@tonic-gate } 72097c478bd9Sstevel@tonic-gate 72107c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 72117c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 72127c478bd9Sstevel@tonic-gate } 72137c478bd9Sstevel@tonic-gate 72147c478bd9Sstevel@tonic-gate /* 72157c478bd9Sstevel@tonic-gate * Timeout handling: 72167c478bd9Sstevel@tonic-gate * Command watchdog routines 72177c478bd9Sstevel@tonic-gate */ 72187c478bd9Sstevel@tonic-gate 72197c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 72207c478bd9Sstevel@tonic-gate static void 72217c478bd9Sstevel@tonic-gate fas_watch(void *arg) 72227c478bd9Sstevel@tonic-gate { 72237c478bd9Sstevel@tonic-gate struct fas *fas; 72247c478bd9Sstevel@tonic-gate ushort_t props_update = 0; 72257c478bd9Sstevel@tonic-gate 72267c478bd9Sstevel@tonic-gate rw_enter(&fas_global_rwlock, RW_READER); 72277c478bd9Sstevel@tonic-gate 72287c478bd9Sstevel@tonic-gate for (fas = fas_head; fas != (struct fas *)NULL; fas = fas->f_next) { 72297c478bd9Sstevel@tonic-gate 72307c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 72317c478bd9Sstevel@tonic-gate IPRINTF2("ncmds=%x, ndisc=%x\n", fas->f_ncmds, fas->f_ndisc); 72327c478bd9Sstevel@tonic-gate 72337c478bd9Sstevel@tonic-gate #ifdef FAS_PIO_COUNTS 72347c478bd9Sstevel@tonic-gate if (fas->f_total_cmds) { 72357c478bd9Sstevel@tonic-gate int n = fas->f_total_cmds; 72367c478bd9Sstevel@tonic-gate 72377c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, 72387c478bd9Sstevel@tonic-gate "total=%d, cmds=%d fas-rd=%d, fas-wrt=%d, dma-rd=%d, dma-wrt=%d\n", 72397c478bd9Sstevel@tonic-gate fas->f_total_cmds, 72407c478bd9Sstevel@tonic-gate fas->f_reg_cmds/n, 72417c478bd9Sstevel@tonic-gate fas->f_reg_reads/n, fas->f_reg_writes/n, 72427c478bd9Sstevel@tonic-gate fas->f_reg_dma_reads/n, fas->f_reg_dma_writes/n); 72437c478bd9Sstevel@tonic-gate 72447c478bd9Sstevel@tonic-gate fas->f_reg_reads = fas->f_reg_writes = 72457c478bd9Sstevel@tonic-gate fas->f_reg_dma_reads = fas->f_reg_dma_writes = 72467c478bd9Sstevel@tonic-gate fas->f_reg_cmds = fas->f_total_cmds = 0; 72477c478bd9Sstevel@tonic-gate } 72487c478bd9Sstevel@tonic-gate #endif 72497c478bd9Sstevel@tonic-gate if (fas->f_ncmds) { 72507c478bd9Sstevel@tonic-gate int i; 72517c478bd9Sstevel@tonic-gate fas_watchsubr(fas); 72527c478bd9Sstevel@tonic-gate 72537c478bd9Sstevel@tonic-gate /* 72547c478bd9Sstevel@tonic-gate * reset throttle. the throttle may have been 72557c478bd9Sstevel@tonic-gate * too low if queue full was caused by 72567c478bd9Sstevel@tonic-gate * another initiator 72577c478bd9Sstevel@tonic-gate * Only reset throttle if no cmd active in slot 0 72587c478bd9Sstevel@tonic-gate * (untagged cmd) 72597c478bd9Sstevel@tonic-gate */ 72607c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 72617c478bd9Sstevel@tonic-gate if (fas_enable_untagged) { 72627c478bd9Sstevel@tonic-gate fas_test_untagged++; 72637c478bd9Sstevel@tonic-gate } 72647c478bd9Sstevel@tonic-gate #endif 72657c478bd9Sstevel@tonic-gate for (i = 0; i < N_SLOTS; i++) { 72667c478bd9Sstevel@tonic-gate if ((fas->f_throttle[i] > HOLD_THROTTLE) && 72677c478bd9Sstevel@tonic-gate (fas->f_active[i] && 72687c478bd9Sstevel@tonic-gate (fas->f_active[i]->f_slot[0] == NULL))) { 72697c478bd9Sstevel@tonic-gate fas_full_throttle(fas, i); 72707c478bd9Sstevel@tonic-gate } 72717c478bd9Sstevel@tonic-gate } 72727c478bd9Sstevel@tonic-gate } 72737c478bd9Sstevel@tonic-gate 72747c478bd9Sstevel@tonic-gate if (fas->f_props_update) { 72757c478bd9Sstevel@tonic-gate int i; 72767c478bd9Sstevel@tonic-gate /* 72777c478bd9Sstevel@tonic-gate * f_mutex will be released and reentered in 72787c478bd9Sstevel@tonic-gate * fas_props_update(). 72797c478bd9Sstevel@tonic-gate * Hence we save the fas->f_props_update now and 72807c478bd9Sstevel@tonic-gate * set to 0 indicating that property has been 72817c478bd9Sstevel@tonic-gate * updated. This will avoid a race condition with 72827c478bd9Sstevel@tonic-gate * any thread that runs in interrupt context that 72837c478bd9Sstevel@tonic-gate * attempts to set the f_props_update to non-zero value 72847c478bd9Sstevel@tonic-gate */ 72857c478bd9Sstevel@tonic-gate props_update = fas->f_props_update; 72867c478bd9Sstevel@tonic-gate fas->f_props_update = 0; 72877c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 72887c478bd9Sstevel@tonic-gate if (props_update & (1<<i)) { 72897c478bd9Sstevel@tonic-gate fas_update_props(fas, i); 72907c478bd9Sstevel@tonic-gate } 72917c478bd9Sstevel@tonic-gate } 72927c478bd9Sstevel@tonic-gate } 72937c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 72947c478bd9Sstevel@tonic-gate 72957c478bd9Sstevel@tonic-gate } 72967c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 72977c478bd9Sstevel@tonic-gate 72987c478bd9Sstevel@tonic-gate again: 72997c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 73007c478bd9Sstevel@tonic-gate if (fas_timeout_initted && fas_timeout_id) { 73017c478bd9Sstevel@tonic-gate fas_timeout_id = timeout(fas_watch, NULL, fas_tick); 73027c478bd9Sstevel@tonic-gate } 73037c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 73047c478bd9Sstevel@tonic-gate TRACE_0(TR_FAC_SCSI_FAS, TR_FAS_WATCH_END, "fas_watch_end"); 73057c478bd9Sstevel@tonic-gate } 73067c478bd9Sstevel@tonic-gate 73077c478bd9Sstevel@tonic-gate static void 73087c478bd9Sstevel@tonic-gate fas_watchsubr(struct fas *fas) 73097c478bd9Sstevel@tonic-gate { 73107c478bd9Sstevel@tonic-gate short slot; 73117c478bd9Sstevel@tonic-gate int d = ((fas->f_dslot == 0)? 1 : fas->f_dslot); 73127c478bd9Sstevel@tonic-gate struct f_slots *tag_slots; 73137c478bd9Sstevel@tonic-gate 73147c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot += d) { 73157c478bd9Sstevel@tonic-gate 73167c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 73177c478bd9Sstevel@tonic-gate if (fas_btest) { 73187c478bd9Sstevel@tonic-gate fas_btest = 0; 73197c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 73207c478bd9Sstevel@tonic-gate return; 73217c478bd9Sstevel@tonic-gate } 73227c478bd9Sstevel@tonic-gate if (fas_force_timeout && fas->f_tcmds[slot]) { 73237c478bd9Sstevel@tonic-gate fas_cmd_timeout(fas, slot); 73247c478bd9Sstevel@tonic-gate fas_force_timeout = 0; 73257c478bd9Sstevel@tonic-gate return; 73267c478bd9Sstevel@tonic-gate } 73277c478bd9Sstevel@tonic-gate fas_test_reset(fas, slot); 73287c478bd9Sstevel@tonic-gate fas_test_abort(fas, slot); 73297c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 73307c478bd9Sstevel@tonic-gate 73317c478bd9Sstevel@tonic-gate /* 73327c478bd9Sstevel@tonic-gate * check tagged cmds first 73337c478bd9Sstevel@tonic-gate */ 73347c478bd9Sstevel@tonic-gate tag_slots = fas->f_active[slot]; 73357c478bd9Sstevel@tonic-gate DPRINTF3( 73367c478bd9Sstevel@tonic-gate "fas_watchsubr: slot %x: tcmds=%x, timeout=%x\n", 73377c478bd9Sstevel@tonic-gate slot, fas->f_tcmds[slot], tag_slots->f_timeout); 73387c478bd9Sstevel@tonic-gate 73397c478bd9Sstevel@tonic-gate if ((fas->f_tcmds[slot] > 0) && (tag_slots->f_timebase)) { 73407c478bd9Sstevel@tonic-gate 73417c478bd9Sstevel@tonic-gate if (tag_slots->f_timebase <= 73427c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick) { 73437c478bd9Sstevel@tonic-gate tag_slots->f_timebase += 73447c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick; 73457c478bd9Sstevel@tonic-gate continue; 73467c478bd9Sstevel@tonic-gate } 73477c478bd9Sstevel@tonic-gate 73487c478bd9Sstevel@tonic-gate tag_slots->f_timeout -= fas_scsi_watchdog_tick; 73497c478bd9Sstevel@tonic-gate 73507c478bd9Sstevel@tonic-gate if (tag_slots->f_timeout < 0) { 73517c478bd9Sstevel@tonic-gate fas_cmd_timeout(fas, slot); 73527c478bd9Sstevel@tonic-gate return; 73537c478bd9Sstevel@tonic-gate } 73547c478bd9Sstevel@tonic-gate if ((tag_slots->f_timeout) <= 73557c478bd9Sstevel@tonic-gate fas_scsi_watchdog_tick) { 73567c478bd9Sstevel@tonic-gate IPRINTF1("pending timeout on slot=%x\n", 73577c478bd9Sstevel@tonic-gate slot); 73587c478bd9Sstevel@tonic-gate IPRINTF("draining all queues\n"); 73597c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, 73607c478bd9Sstevel@tonic-gate DRAIN_THROTTLE); 73617c478bd9Sstevel@tonic-gate } 73627c478bd9Sstevel@tonic-gate } 73637c478bd9Sstevel@tonic-gate } 73647c478bd9Sstevel@tonic-gate } 73657c478bd9Sstevel@tonic-gate 73667c478bd9Sstevel@tonic-gate /* 73677c478bd9Sstevel@tonic-gate * timeout recovery 73687c478bd9Sstevel@tonic-gate */ 73697c478bd9Sstevel@tonic-gate static void 73707c478bd9Sstevel@tonic-gate fas_cmd_timeout(struct fas *fas, int slot) 73717c478bd9Sstevel@tonic-gate { 73727c478bd9Sstevel@tonic-gate int d = ((fas->f_dslot == 0)? 1 : fas->f_dslot); 73737c478bd9Sstevel@tonic-gate int target, lun, i, n, tag, ncmds; 73747c478bd9Sstevel@tonic-gate struct fas_cmd *sp = NULL; 73757c478bd9Sstevel@tonic-gate struct fas_cmd *ssp; 73767c478bd9Sstevel@tonic-gate 73777c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot]); 73787c478bd9Sstevel@tonic-gate 73797c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 73807c478bd9Sstevel@tonic-gate if (fas_test_stop) { 73817c478bd9Sstevel@tonic-gate debug_enter("timeout"); 73827c478bd9Sstevel@tonic-gate } 73837c478bd9Sstevel@tonic-gate #endif 73847c478bd9Sstevel@tonic-gate 73857c478bd9Sstevel@tonic-gate /* 73867c478bd9Sstevel@tonic-gate * set throttle back; no more draining necessary 73877c478bd9Sstevel@tonic-gate */ 73887c478bd9Sstevel@tonic-gate for (i = 0; i < N_SLOTS; i += d) { 73897c478bd9Sstevel@tonic-gate if (fas->f_throttle[i] == DRAIN_THROTTLE) { 73907c478bd9Sstevel@tonic-gate fas_full_throttle(fas, i); 73917c478bd9Sstevel@tonic-gate } 73927c478bd9Sstevel@tonic-gate } 73937c478bd9Sstevel@tonic-gate 73947c478bd9Sstevel@tonic-gate if (NOTAG(slot/NLUNS_PER_TARGET)) { 73957c478bd9Sstevel@tonic-gate sp = fas->f_active[slot]->f_slot[0]; 73967c478bd9Sstevel@tonic-gate } 73977c478bd9Sstevel@tonic-gate 73987c478bd9Sstevel@tonic-gate /* 73997c478bd9Sstevel@tonic-gate * if no interrupt pending for next second then the current 74007c478bd9Sstevel@tonic-gate * cmd must be stuck; switch slot and sp to current slot and cmd 74017c478bd9Sstevel@tonic-gate */ 74027c478bd9Sstevel@tonic-gate if (fas->f_current_sp && fas->f_state != STATE_FREE) { 74037c478bd9Sstevel@tonic-gate for (i = 0; (i < 10000) && (INTPENDING(fas) == 0); i++) { 74047c478bd9Sstevel@tonic-gate drv_usecwait(100); 74057c478bd9Sstevel@tonic-gate } 74067c478bd9Sstevel@tonic-gate if (INTPENDING(fas) == 0) { 74077c478bd9Sstevel@tonic-gate slot = fas->f_current_sp->cmd_slot; 74087c478bd9Sstevel@tonic-gate sp = fas->f_current_sp; 74097c478bd9Sstevel@tonic-gate } 74107c478bd9Sstevel@tonic-gate } 74117c478bd9Sstevel@tonic-gate 74127c478bd9Sstevel@tonic-gate target = slot / NLUNS_PER_TARGET; 74137c478bd9Sstevel@tonic-gate lun = slot % NLUNS_PER_TARGET; 74147c478bd9Sstevel@tonic-gate 74157c478bd9Sstevel@tonic-gate /* 74167c478bd9Sstevel@tonic-gate * update all outstanding pkts for this slot 74177c478bd9Sstevel@tonic-gate */ 74187c478bd9Sstevel@tonic-gate n = fas->f_active[slot]->f_n_slots; 74197c478bd9Sstevel@tonic-gate for (ncmds = tag = 0; tag < n; tag++) { 74207c478bd9Sstevel@tonic-gate ssp = fas->f_active[slot]->f_slot[tag]; 74217c478bd9Sstevel@tonic-gate if (ssp && ssp->cmd_pkt->pkt_time) { 74227c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, ssp, CMD_TIMEOUT, 74237c478bd9Sstevel@tonic-gate STAT_TIMEOUT | STAT_ABORTED); 74247c478bd9Sstevel@tonic-gate fas_short_dump_cmd(fas, ssp); 74257c478bd9Sstevel@tonic-gate ncmds++; 74267c478bd9Sstevel@tonic-gate } 74277c478bd9Sstevel@tonic-gate } 74287c478bd9Sstevel@tonic-gate 74297c478bd9Sstevel@tonic-gate /* 74307c478bd9Sstevel@tonic-gate * no timed-out cmds here? 74317c478bd9Sstevel@tonic-gate */ 74327c478bd9Sstevel@tonic-gate if (ncmds == 0) { 74337c478bd9Sstevel@tonic-gate return; 74347c478bd9Sstevel@tonic-gate } 74357c478bd9Sstevel@tonic-gate 74367c478bd9Sstevel@tonic-gate /* 74377c478bd9Sstevel@tonic-gate * dump all we know about this timeout 74387c478bd9Sstevel@tonic-gate */ 74397c478bd9Sstevel@tonic-gate if (sp) { 74407c478bd9Sstevel@tonic-gate if (sp->cmd_flags & CFLAG_CMDDISC) { 74417c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 74427c478bd9Sstevel@tonic-gate "Disconnected command timeout for Target %d.%d", 74437c478bd9Sstevel@tonic-gate target, lun); 74447c478bd9Sstevel@tonic-gate } else { 74457c478bd9Sstevel@tonic-gate ASSERT(sp == fas->f_current_sp); 74467c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 74477c478bd9Sstevel@tonic-gate "Connected command timeout for Target %d.%d", 74487c478bd9Sstevel@tonic-gate target, lun); 74497c478bd9Sstevel@tonic-gate /* 74507c478bd9Sstevel@tonic-gate * Current command timeout appears to relate often 74517c478bd9Sstevel@tonic-gate * to noisy SCSI in synchronous mode. 74527c478bd9Sstevel@tonic-gate */ 74537c478bd9Sstevel@tonic-gate if (fas->f_state == ACTS_DATA_DONE) { 74547c478bd9Sstevel@tonic-gate fas_sync_wide_backoff(fas, sp, slot); 74557c478bd9Sstevel@tonic-gate } 74567c478bd9Sstevel@tonic-gate } 74577c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 74587c478bd9Sstevel@tonic-gate fas_printstate(fas, "timeout"); 74597c478bd9Sstevel@tonic-gate #endif 74607c478bd9Sstevel@tonic-gate } else { 74617c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 74627c478bd9Sstevel@tonic-gate "Disconnected tagged cmd(s) (%d) timeout for Target %d.%d", 74637c478bd9Sstevel@tonic-gate fas->f_tcmds[slot], target, lun); 74647c478bd9Sstevel@tonic-gate } 74657c478bd9Sstevel@tonic-gate 74667c478bd9Sstevel@tonic-gate if (fas_abort_cmd(fas, sp, slot) == ACTION_SEARCH) { 74677c478bd9Sstevel@tonic-gate (void) fas_istart(fas); 74687c478bd9Sstevel@tonic-gate } 74697c478bd9Sstevel@tonic-gate } 74707c478bd9Sstevel@tonic-gate 74717c478bd9Sstevel@tonic-gate /* 74727c478bd9Sstevel@tonic-gate * fas_sync_wide_backoff() increases sync period and enables slow 74737c478bd9Sstevel@tonic-gate * cable mode. 74747c478bd9Sstevel@tonic-gate * the second time, we revert back to narrow/async 74757c478bd9Sstevel@tonic-gate * we count on a bus reset to disable wide in the target and will 74767c478bd9Sstevel@tonic-gate * never renegotiate wide again 74777c478bd9Sstevel@tonic-gate */ 74787c478bd9Sstevel@tonic-gate static void 74797c478bd9Sstevel@tonic-gate fas_sync_wide_backoff(struct fas *fas, struct fas_cmd *sp, 74807c478bd9Sstevel@tonic-gate int slot) 74817c478bd9Sstevel@tonic-gate { 74827c478bd9Sstevel@tonic-gate char phase; 74837c478bd9Sstevel@tonic-gate ushort_t state = fas->f_state; 74847c478bd9Sstevel@tonic-gate uchar_t tgt = slot / NLUNS_PER_TARGET; 74857c478bd9Sstevel@tonic-gate uint_t tshift = 1 << tgt; 74867c478bd9Sstevel@tonic-gate 74877c478bd9Sstevel@tonic-gate phase = fas_reg_read(fas, &fas->f_reg->fas_stat); 74887c478bd9Sstevel@tonic-gate phase &= FAS_PHASE_MASK; 74897c478bd9Sstevel@tonic-gate 74907c478bd9Sstevel@tonic-gate IPRINTF4( 74917c478bd9Sstevel@tonic-gate "fas_sync_wide_backoff: target %d: state=%x, phase=%x, sp=0x%p\n", 74927c478bd9Sstevel@tonic-gate tgt, state, phase, (void *)sp); 74937c478bd9Sstevel@tonic-gate 74947c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 74957c478bd9Sstevel@tonic-gate if (fas_no_sync_wide_backoff) { 74967c478bd9Sstevel@tonic-gate return; 74977c478bd9Sstevel@tonic-gate } 74987c478bd9Sstevel@tonic-gate #endif 74997c478bd9Sstevel@tonic-gate 75007c478bd9Sstevel@tonic-gate /* 75017c478bd9Sstevel@tonic-gate * if this not the first time or sync is disabled 75027c478bd9Sstevel@tonic-gate * thru scsi_options then disable wide 75037c478bd9Sstevel@tonic-gate */ 75047c478bd9Sstevel@tonic-gate if ((fas->f_backoff & tshift) || 75057c478bd9Sstevel@tonic-gate (fas->f_nosync & tshift)) { 75067c478bd9Sstevel@tonic-gate /* 75077c478bd9Sstevel@tonic-gate * disable wide for just this target 75087c478bd9Sstevel@tonic-gate */ 75097c478bd9Sstevel@tonic-gate if ((fas->f_nowide & tshift) == 0) { 75107c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 75117c478bd9Sstevel@tonic-gate "Target %d disabled wide SCSI mode", tgt); 75127c478bd9Sstevel@tonic-gate } 75137c478bd9Sstevel@tonic-gate /* 75147c478bd9Sstevel@tonic-gate * do not reset the bit in f_nowide because that 75157c478bd9Sstevel@tonic-gate * would not force a renegotiation of wide 75167c478bd9Sstevel@tonic-gate * and do not change any register value yet because 75177c478bd9Sstevel@tonic-gate * we may have reconnects before the renegotiations 75187c478bd9Sstevel@tonic-gate */ 75197c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[tgt] &= ~SCSI_OPTIONS_WIDE; 75207c478bd9Sstevel@tonic-gate } 75217c478bd9Sstevel@tonic-gate 75227c478bd9Sstevel@tonic-gate /* 75237c478bd9Sstevel@tonic-gate * reduce xfer rate. if this is the first time, reduce by 75247c478bd9Sstevel@tonic-gate * 100%. second time, disable sync and wide. 75257c478bd9Sstevel@tonic-gate */ 75267c478bd9Sstevel@tonic-gate if (fas->f_offset[tgt] != 0) { 75277c478bd9Sstevel@tonic-gate /* 75287c478bd9Sstevel@tonic-gate * do not reset the bit in f_nosync because that 75297c478bd9Sstevel@tonic-gate * would not force a renegotiation of sync 75307c478bd9Sstevel@tonic-gate */ 75317c478bd9Sstevel@tonic-gate if (fas->f_backoff & tshift) { 75327c478bd9Sstevel@tonic-gate if ((fas->f_nosync & tshift) == 0) { 75337c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 75347c478bd9Sstevel@tonic-gate "Target %d reverting to async. mode", 75357c478bd9Sstevel@tonic-gate tgt); 75367c478bd9Sstevel@tonic-gate } 75377c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[tgt] &= 75387c478bd9Sstevel@tonic-gate ~(SCSI_OPTIONS_SYNC | SCSI_OPTIONS_FAST); 75397c478bd9Sstevel@tonic-gate } else { 75407c478bd9Sstevel@tonic-gate /* increase period by 100% */ 75417c478bd9Sstevel@tonic-gate fas->f_neg_period[tgt] *= 2; 75427c478bd9Sstevel@tonic-gate 75437c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, 75447c478bd9Sstevel@tonic-gate "Target %d reducing sync. transfer rate", tgt); 75457c478bd9Sstevel@tonic-gate } 75467c478bd9Sstevel@tonic-gate } 75477c478bd9Sstevel@tonic-gate fas->f_backoff |= tshift; 75487c478bd9Sstevel@tonic-gate 75497c478bd9Sstevel@tonic-gate /* 75507c478bd9Sstevel@tonic-gate * always enable slow cable mode, if not already enabled 75517c478bd9Sstevel@tonic-gate */ 75527c478bd9Sstevel@tonic-gate if ((fas->f_fasconf & FAS_CONF_SLOWMODE) == 0) { 75537c478bd9Sstevel@tonic-gate fas->f_fasconf |= FAS_CONF_SLOWMODE; 75547c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fas->f_reg->fas_conf, fas->f_fasconf); 75557c478bd9Sstevel@tonic-gate IPRINTF("Reverting to slow SCSI cable mode\n"); 75567c478bd9Sstevel@tonic-gate } 75577c478bd9Sstevel@tonic-gate 75587c478bd9Sstevel@tonic-gate /* 75597c478bd9Sstevel@tonic-gate * Force sync renegotiation and update properties 75607c478bd9Sstevel@tonic-gate */ 75617c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, tgt); 75627c478bd9Sstevel@tonic-gate fas->f_props_update |= (1<<tgt); 75637c478bd9Sstevel@tonic-gate } 75647c478bd9Sstevel@tonic-gate 75657c478bd9Sstevel@tonic-gate /* 75667c478bd9Sstevel@tonic-gate * handle failed negotiations (either reject or bus free condition) 75677c478bd9Sstevel@tonic-gate */ 75687c478bd9Sstevel@tonic-gate static void 75697c478bd9Sstevel@tonic-gate fas_reset_sync_wide(struct fas *fas) 75707c478bd9Sstevel@tonic-gate { 75717c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 75727c478bd9Sstevel@tonic-gate int tgt = Tgt(sp); 75737c478bd9Sstevel@tonic-gate 75747c478bd9Sstevel@tonic-gate if (fas->f_wdtr_sent) { 75757c478bd9Sstevel@tonic-gate IPRINTF("wide neg message rejected or bus free\n"); 75767c478bd9Sstevel@tonic-gate fas->f_nowide |= (1<<tgt); 75777c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt] &= ~FAS_CONF3_WIDE; 75787c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fas->f_reg->fas_conf3, 75797c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt]); 75807c478bd9Sstevel@tonic-gate /* 75817c478bd9Sstevel@tonic-gate * clear offset just in case it goes to 75827c478bd9Sstevel@tonic-gate * data phase 75837c478bd9Sstevel@tonic-gate */ 75847c478bd9Sstevel@tonic-gate fas_reg_write(fas, 75857c478bd9Sstevel@tonic-gate (uchar_t *)&fas->f_reg->fas_sync_offset, 0); 75867c478bd9Sstevel@tonic-gate } else if (fas->f_sdtr_sent) { 75877c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = 75887c478bd9Sstevel@tonic-gate fas->f_reg; 75897c478bd9Sstevel@tonic-gate IPRINTF("sync neg message rejected or bus free\n"); 75907c478bd9Sstevel@tonic-gate fas->f_nosync |= (1<<tgt); 75917c478bd9Sstevel@tonic-gate fas->f_offset[tgt] = 0; 75927c478bd9Sstevel@tonic-gate fas->f_sync_period[tgt] = 0; 75937c478bd9Sstevel@tonic-gate fas_reg_write(fas, 75947c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_sync_period, 0); 75957c478bd9Sstevel@tonic-gate fas_reg_write(fas, 75967c478bd9Sstevel@tonic-gate (uchar_t *)&fasreg->fas_sync_offset, 0); 75977c478bd9Sstevel@tonic-gate fas->f_offset[tgt] = 0; 75987c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt] &= ~FAS_CONF3_FASTSCSI; 75997c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fasreg->fas_conf3, 76007c478bd9Sstevel@tonic-gate fas->f_fasconf3[tgt]); 76017c478bd9Sstevel@tonic-gate } 76027c478bd9Sstevel@tonic-gate 76037c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, tgt); 76047c478bd9Sstevel@tonic-gate } 76057c478bd9Sstevel@tonic-gate 76067c478bd9Sstevel@tonic-gate /* 76077c478bd9Sstevel@tonic-gate * force wide and sync renegotiation 76087c478bd9Sstevel@tonic-gate */ 76097c478bd9Sstevel@tonic-gate static void 76107c478bd9Sstevel@tonic-gate fas_force_renegotiation(struct fas *fas, int target) 76117c478bd9Sstevel@tonic-gate { 76127c478bd9Sstevel@tonic-gate ushort_t tshift = 1<<target; 76137c478bd9Sstevel@tonic-gate fas->f_sync_known &= ~tshift; 76147c478bd9Sstevel@tonic-gate fas->f_sync_enabled &= ~tshift; 76157c478bd9Sstevel@tonic-gate fas->f_wide_known &= ~tshift; 76167c478bd9Sstevel@tonic-gate fas->f_wide_enabled &= ~tshift; 76177c478bd9Sstevel@tonic-gate } 76187c478bd9Sstevel@tonic-gate 76197c478bd9Sstevel@tonic-gate /* 76207c478bd9Sstevel@tonic-gate * update conf3 register for wide negotiation 76217c478bd9Sstevel@tonic-gate */ 76227c478bd9Sstevel@tonic-gate static void 76237c478bd9Sstevel@tonic-gate fas_set_wide_conf3(struct fas *fas, int target, int width) 76247c478bd9Sstevel@tonic-gate { 76257c478bd9Sstevel@tonic-gate ASSERT(width <= 1); 76267c478bd9Sstevel@tonic-gate switch (width) { 76277c478bd9Sstevel@tonic-gate case 0: 76287c478bd9Sstevel@tonic-gate fas->f_fasconf3[target] &= ~FAS_CONF3_WIDE; 76297c478bd9Sstevel@tonic-gate break; 76307c478bd9Sstevel@tonic-gate case 1: 76317c478bd9Sstevel@tonic-gate fas->f_fasconf3[target] |= FAS_CONF3_WIDE; 76327c478bd9Sstevel@tonic-gate fas->f_wide_enabled |= (1<<target); 76337c478bd9Sstevel@tonic-gate break; 76347c478bd9Sstevel@tonic-gate } 76357c478bd9Sstevel@tonic-gate 76367c478bd9Sstevel@tonic-gate fas_reg_write(fas, &fas->f_reg->fas_conf3, fas->f_fasconf3[target]); 76377c478bd9Sstevel@tonic-gate fas->f_fasconf3_reg_last = fas->f_fasconf3[target]; 76387c478bd9Sstevel@tonic-gate } 76397c478bd9Sstevel@tonic-gate 76407c478bd9Sstevel@tonic-gate /* 76417c478bd9Sstevel@tonic-gate * Abort command handling 76427c478bd9Sstevel@tonic-gate * 76437c478bd9Sstevel@tonic-gate * abort current cmd, either by device reset or immediately with bus reset 76447c478bd9Sstevel@tonic-gate * (usually an abort msg doesn't completely solve the problem, therefore 76457c478bd9Sstevel@tonic-gate * a device or bus reset is recommended) 76467c478bd9Sstevel@tonic-gate */ 76477c478bd9Sstevel@tonic-gate static int 76487c478bd9Sstevel@tonic-gate fas_abort_curcmd(struct fas *fas) 76497c478bd9Sstevel@tonic-gate { 76507c478bd9Sstevel@tonic-gate if (fas->f_current_sp) { 76517c478bd9Sstevel@tonic-gate return (fas_abort_cmd(fas, fas->f_current_sp, 76527c478bd9Sstevel@tonic-gate fas->f_current_sp->cmd_slot)); 76537c478bd9Sstevel@tonic-gate } else { 76547c478bd9Sstevel@tonic-gate return (fas_reset_bus(fas)); 76557c478bd9Sstevel@tonic-gate } 76567c478bd9Sstevel@tonic-gate } 76577c478bd9Sstevel@tonic-gate 76587c478bd9Sstevel@tonic-gate static int 76597c478bd9Sstevel@tonic-gate fas_abort_cmd(struct fas *fas, struct fas_cmd *sp, int slot) 76607c478bd9Sstevel@tonic-gate { 76617c478bd9Sstevel@tonic-gate struct scsi_address ap; 76627c478bd9Sstevel@tonic-gate 76637c478bd9Sstevel@tonic-gate ap.a_hba_tran = fas->f_tran; 76647c478bd9Sstevel@tonic-gate ap.a_target = slot / NLUNS_PER_TARGET; 76657c478bd9Sstevel@tonic-gate ap.a_lun = slot % NLUNS_PER_TARGET; 76667c478bd9Sstevel@tonic-gate 76677c478bd9Sstevel@tonic-gate IPRINTF1("abort cmd 0x%p\n", (void *)sp); 76687c478bd9Sstevel@tonic-gate 76697c478bd9Sstevel@tonic-gate /* 76707c478bd9Sstevel@tonic-gate * attempting to abort a connected cmd is usually fruitless, so 76717c478bd9Sstevel@tonic-gate * only try disconnected cmds 76727c478bd9Sstevel@tonic-gate * a reset is preferable over an abort (see 1161701) 76737c478bd9Sstevel@tonic-gate */ 76747c478bd9Sstevel@tonic-gate if ((fas->f_current_sp && (fas->f_current_sp->cmd_slot != slot)) || 76757c478bd9Sstevel@tonic-gate (fas->f_state == STATE_FREE)) { 76767c478bd9Sstevel@tonic-gate IPRINTF2("attempting to reset target %d.%d\n", 76777c478bd9Sstevel@tonic-gate ap.a_target, ap.a_lun); 76787c478bd9Sstevel@tonic-gate if (fas_do_scsi_reset(&ap, RESET_TARGET)) { 76797c478bd9Sstevel@tonic-gate return (ACTION_SEARCH); 76807c478bd9Sstevel@tonic-gate } 76817c478bd9Sstevel@tonic-gate } 76827c478bd9Sstevel@tonic-gate 76837c478bd9Sstevel@tonic-gate /* 76847c478bd9Sstevel@tonic-gate * if the target won't listen, then a retry is useless 76857c478bd9Sstevel@tonic-gate * there is also the possibility that the cmd still completed while 76867c478bd9Sstevel@tonic-gate * we were trying to reset and the target driver may have done a 76877c478bd9Sstevel@tonic-gate * device reset which has blown away this sp. 76887c478bd9Sstevel@tonic-gate * well, we've tried, now pull the chain 76897c478bd9Sstevel@tonic-gate */ 76907c478bd9Sstevel@tonic-gate IPRINTF("aborting all cmds by bus reset\n"); 76917c478bd9Sstevel@tonic-gate return (fas_reset_bus(fas)); 76927c478bd9Sstevel@tonic-gate } 76937c478bd9Sstevel@tonic-gate 76947c478bd9Sstevel@tonic-gate /* 76957c478bd9Sstevel@tonic-gate * fas_do_scsi_abort() assumes that we already have the mutex. 76967c478bd9Sstevel@tonic-gate * during the abort, we hold the mutex and prevent callbacks by setting 76977c478bd9Sstevel@tonic-gate * completion pointer to NULL. this will also avoid that a target driver 76987c478bd9Sstevel@tonic-gate * attempts to do a scsi_abort/reset while we are aborting. 76997c478bd9Sstevel@tonic-gate * because the completion pointer is NULL we can still update the 77007c478bd9Sstevel@tonic-gate * packet after completion 77017c478bd9Sstevel@tonic-gate * the throttle for this slot is cleared either by fas_abort_connected_cmd 77027c478bd9Sstevel@tonic-gate * or fas_runpoll which prevents new cmds from starting while aborting 77037c478bd9Sstevel@tonic-gate */ 77047c478bd9Sstevel@tonic-gate static int 77057c478bd9Sstevel@tonic-gate fas_do_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt) 77067c478bd9Sstevel@tonic-gate { 77077c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 77087c478bd9Sstevel@tonic-gate struct fas_cmd *sp; 77097c478bd9Sstevel@tonic-gate int rval = FALSE; 77107c478bd9Sstevel@tonic-gate short slot; 77117c478bd9Sstevel@tonic-gate struct fas_cmd *cur_sp = fas->f_current_sp; 77127c478bd9Sstevel@tonic-gate void (*cur_savec)(), (*sp_savec)(); 77137c478bd9Sstevel@tonic-gate int sp_tagged_flag, abort_msg; 77147c478bd9Sstevel@tonic-gate 77157c478bd9Sstevel@tonic-gate if (pkt) { 77167c478bd9Sstevel@tonic-gate sp = PKT2CMD(pkt); 77177c478bd9Sstevel@tonic-gate slot = sp->cmd_slot; 77187c478bd9Sstevel@tonic-gate ASSERT(slot == ((ap->a_target * NLUNS_PER_TARGET) | ap->a_lun)); 77197c478bd9Sstevel@tonic-gate } else { 77207c478bd9Sstevel@tonic-gate sp = NULL; 77217c478bd9Sstevel@tonic-gate slot = (ap->a_target * NLUNS_PER_TARGET) | ap->a_lun; 77227c478bd9Sstevel@tonic-gate } 77237c478bd9Sstevel@tonic-gate 77247c478bd9Sstevel@tonic-gate fas_move_waitQ_to_readyQ(fas); 77257c478bd9Sstevel@tonic-gate 77267c478bd9Sstevel@tonic-gate /* 77277c478bd9Sstevel@tonic-gate * If no specific command was passed, all cmds here will be aborted 77287c478bd9Sstevel@tonic-gate * If a specific command was passed as an argument (to be aborted) 77297c478bd9Sstevel@tonic-gate * only the specified command will be aborted 77307c478bd9Sstevel@tonic-gate */ 77317c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 77327c478bd9Sstevel@tonic-gate IPRINTF4("fas_scsi_abort for slot %x, " 77337c478bd9Sstevel@tonic-gate "sp=0x%p, pkt_flags=%x, cur_sp=0x%p\n", 77347c478bd9Sstevel@tonic-gate slot, (void *)sp, (sp? sp->cmd_pkt_flags : 0), (void *)cur_sp); 77357c478bd9Sstevel@tonic-gate 77367c478bd9Sstevel@tonic-gate /* 77377c478bd9Sstevel@tonic-gate * first check if the cmd is in the ready queue or 77387c478bd9Sstevel@tonic-gate * in the active queue 77397c478bd9Sstevel@tonic-gate */ 77407c478bd9Sstevel@tonic-gate if (sp) { 77417c478bd9Sstevel@tonic-gate IPRINTF3("aborting one command 0x%p for %d.%d\n", 77427c478bd9Sstevel@tonic-gate (void *)sp, ap->a_target, ap->a_lun); 77437c478bd9Sstevel@tonic-gate rval = fas_remove_from_readyQ(fas, sp, slot); 77447c478bd9Sstevel@tonic-gate if (rval) { 77457c478bd9Sstevel@tonic-gate IPRINTF("aborted one ready cmd\n"); 77467c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_ABORTED, STAT_ABORTED); 77477c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 77487c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 77497c478bd9Sstevel@tonic-gate goto exit; 77507c478bd9Sstevel@tonic-gate 77517c478bd9Sstevel@tonic-gate } else if ((sp != 77527c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_slot[sp->cmd_tag[1]])) { 77537c478bd9Sstevel@tonic-gate IPRINTF("cmd doesn't exist here\n"); 77547c478bd9Sstevel@tonic-gate rval = TRUE; 77557c478bd9Sstevel@tonic-gate goto exit; 77567c478bd9Sstevel@tonic-gate } 77577c478bd9Sstevel@tonic-gate } 77587c478bd9Sstevel@tonic-gate 77597c478bd9Sstevel@tonic-gate /* 77607c478bd9Sstevel@tonic-gate * hold off any new commands while attempting to abort 77617c478bd9Sstevel@tonic-gate * an active cmd 77627c478bd9Sstevel@tonic-gate */ 77637c478bd9Sstevel@tonic-gate fas_set_throttles(fas, slot, 1, HOLD_THROTTLE); 77647c478bd9Sstevel@tonic-gate 77657c478bd9Sstevel@tonic-gate if (cur_sp) { 77667c478bd9Sstevel@tonic-gate /* 77677c478bd9Sstevel@tonic-gate * prevent completion on current cmd 77687c478bd9Sstevel@tonic-gate */ 77697c478bd9Sstevel@tonic-gate cur_savec = cur_sp->cmd_pkt->pkt_comp; 77707c478bd9Sstevel@tonic-gate cur_sp->cmd_pkt->pkt_comp = NULL; 77717c478bd9Sstevel@tonic-gate } 77727c478bd9Sstevel@tonic-gate 77737c478bd9Sstevel@tonic-gate if (sp) { 77747c478bd9Sstevel@tonic-gate /* 77757c478bd9Sstevel@tonic-gate * the cmd exists here. is it connected or disconnected? 77767c478bd9Sstevel@tonic-gate * if connected but still selecting then can't abort now. 77777c478bd9Sstevel@tonic-gate * prevent completion on this cmd 77787c478bd9Sstevel@tonic-gate */ 77797c478bd9Sstevel@tonic-gate sp_tagged_flag = (sp->cmd_pkt_flags & FLAG_TAGMASK); 77807c478bd9Sstevel@tonic-gate abort_msg = (sp_tagged_flag? MSG_ABORT_TAG : MSG_ABORT); 77817c478bd9Sstevel@tonic-gate sp_savec = sp->cmd_pkt->pkt_comp; 77827c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_comp = NULL; 77837c478bd9Sstevel@tonic-gate 77847c478bd9Sstevel@tonic-gate /* connected but not selecting? */ 77857c478bd9Sstevel@tonic-gate if ((sp == cur_sp) && (fas->f_state != STATE_FREE) && 77867c478bd9Sstevel@tonic-gate (sp->cmd_pkt->pkt_state)) { 77877c478bd9Sstevel@tonic-gate rval = fas_abort_connected_cmd(fas, sp, abort_msg); 77887c478bd9Sstevel@tonic-gate } 77897c478bd9Sstevel@tonic-gate 77907c478bd9Sstevel@tonic-gate /* if abort connected cmd failed, try abort disconnected */ 77917c478bd9Sstevel@tonic-gate if ((rval == 0) && 77927c478bd9Sstevel@tonic-gate (sp->cmd_flags & CFLAG_CMDDISC) && 77937c478bd9Sstevel@tonic-gate ((sp->cmd_flags & CFLAG_COMPLETED) == 0)) { 77947c478bd9Sstevel@tonic-gate rval = fas_abort_disconnected_cmd(fas, ap, sp, 77957c478bd9Sstevel@tonic-gate abort_msg, slot); 77967c478bd9Sstevel@tonic-gate } 77977c478bd9Sstevel@tonic-gate 77987c478bd9Sstevel@tonic-gate if (rval) { 77997c478bd9Sstevel@tonic-gate sp->cmd_flags |= CFLAG_COMPLETED; 78007c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, CMD_ABORTED, STAT_ABORTED); 78017c478bd9Sstevel@tonic-gate } 78027c478bd9Sstevel@tonic-gate 78037c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_comp = sp_savec; 78047c478bd9Sstevel@tonic-gate 78057c478bd9Sstevel@tonic-gate } else { 78067c478bd9Sstevel@tonic-gate IPRINTF2("aborting all commands for %d.%d\n", 78077c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun); 78087c478bd9Sstevel@tonic-gate abort_msg = MSG_ABORT; 78097c478bd9Sstevel@tonic-gate 78107c478bd9Sstevel@tonic-gate /* active and not selecting ? */ 78117c478bd9Sstevel@tonic-gate if (cur_sp && (fas->f_state != STATE_FREE) && 78127c478bd9Sstevel@tonic-gate (cur_sp->cmd_slot == slot) && 78137c478bd9Sstevel@tonic-gate cur_sp->cmd_pkt->pkt_state) { 78147c478bd9Sstevel@tonic-gate rval = fas_abort_connected_cmd(fas, cur_sp, 78157c478bd9Sstevel@tonic-gate abort_msg); 78167c478bd9Sstevel@tonic-gate } 78177c478bd9Sstevel@tonic-gate if (rval == 0) { 78187c478bd9Sstevel@tonic-gate rval = fas_abort_disconnected_cmd(fas, ap, 78197c478bd9Sstevel@tonic-gate NULL, abort_msg, slot); 78207c478bd9Sstevel@tonic-gate } 78217c478bd9Sstevel@tonic-gate } 78227c478bd9Sstevel@tonic-gate 78237c478bd9Sstevel@tonic-gate done: 78247c478bd9Sstevel@tonic-gate /* complete the current sp */ 78257c478bd9Sstevel@tonic-gate if (cur_sp) { 78267c478bd9Sstevel@tonic-gate cur_sp->cmd_pkt->pkt_comp = cur_savec; 78277c478bd9Sstevel@tonic-gate if (cur_sp->cmd_flags & CFLAG_COMPLETED) { 78287c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, cur_sp, NEW_TIMEOUT); 78297c478bd9Sstevel@tonic-gate cur_sp->cmd_flags &= ~CFLAG_COMPLETED; 78307c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, cur_sp); 78317c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, cur_sp); 78327c478bd9Sstevel@tonic-gate } 78337c478bd9Sstevel@tonic-gate } 78347c478bd9Sstevel@tonic-gate 78357c478bd9Sstevel@tonic-gate /* complete the sp passed as 2nd arg */ 78367c478bd9Sstevel@tonic-gate if (sp && (sp != cur_sp) && (sp->cmd_flags & CFLAG_COMPLETED)) { 78377c478bd9Sstevel@tonic-gate sp->cmd_flags &= ~CFLAG_COMPLETED; 78387c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 78397c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 78407c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 78417c478bd9Sstevel@tonic-gate } 78427c478bd9Sstevel@tonic-gate 78437c478bd9Sstevel@tonic-gate /* clean up all cmds for this slot */ 78447c478bd9Sstevel@tonic-gate if (rval && (abort_msg == MSG_ABORT)) { 78457c478bd9Sstevel@tonic-gate /* 78467c478bd9Sstevel@tonic-gate * mark all commands here as aborted 78477c478bd9Sstevel@tonic-gate * abort msg has been accepted, now cleanup queues; 78487c478bd9Sstevel@tonic-gate */ 78497c478bd9Sstevel@tonic-gate fas_mark_packets(fas, slot, CMD_ABORTED, STAT_ABORTED); 78507c478bd9Sstevel@tonic-gate fas_flush_tagQ(fas, slot); 78517c478bd9Sstevel@tonic-gate fas_flush_readyQ(fas, slot); 78527c478bd9Sstevel@tonic-gate } 78537c478bd9Sstevel@tonic-gate fas_set_throttles(fas, slot, 1, MAX_THROTTLE); 78547c478bd9Sstevel@tonic-gate 78557c478bd9Sstevel@tonic-gate exit: 78567c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) { 78577c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 78587c478bd9Sstevel@tonic-gate } 78597c478bd9Sstevel@tonic-gate 78607c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 78617c478bd9Sstevel@tonic-gate 78627c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 78637c478bd9Sstevel@tonic-gate if (rval && fas_test_stop) { 78647c478bd9Sstevel@tonic-gate debug_enter("abort succeeded"); 78657c478bd9Sstevel@tonic-gate } 78667c478bd9Sstevel@tonic-gate #endif 78677c478bd9Sstevel@tonic-gate return (rval); 78687c478bd9Sstevel@tonic-gate } 78697c478bd9Sstevel@tonic-gate 78707c478bd9Sstevel@tonic-gate /* 78717c478bd9Sstevel@tonic-gate * mark all packets with new reason and update statistics 78727c478bd9Sstevel@tonic-gate */ 78737c478bd9Sstevel@tonic-gate static void 78747c478bd9Sstevel@tonic-gate fas_mark_packets(struct fas *fas, int slot, uchar_t reason, uint_t stat) 78757c478bd9Sstevel@tonic-gate { 78767c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_readyf[slot]; 78777c478bd9Sstevel@tonic-gate 78787c478bd9Sstevel@tonic-gate while (sp != 0) { 78797c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, reason, STAT_ABORTED); 78807c478bd9Sstevel@tonic-gate sp = sp->cmd_forw; 78817c478bd9Sstevel@tonic-gate } 78827c478bd9Sstevel@tonic-gate if (fas->f_tcmds[slot]) { 78837c478bd9Sstevel@tonic-gate int n = 0; 78847c478bd9Sstevel@tonic-gate ushort_t tag; 78857c478bd9Sstevel@tonic-gate 78867c478bd9Sstevel@tonic-gate for (tag = 0; tag < fas->f_active[slot]->f_n_slots; tag++) { 78877c478bd9Sstevel@tonic-gate if ((sp = fas->f_active[slot]->f_slot[tag]) != 0) { 78887c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, reason, stat); 78897c478bd9Sstevel@tonic-gate n++; 78907c478bd9Sstevel@tonic-gate } 78917c478bd9Sstevel@tonic-gate } 78927c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] == n); 78937c478bd9Sstevel@tonic-gate } 78947c478bd9Sstevel@tonic-gate } 78957c478bd9Sstevel@tonic-gate 78967c478bd9Sstevel@tonic-gate /* 78977c478bd9Sstevel@tonic-gate * set pkt_reason and OR in pkt_statistics flag 78987c478bd9Sstevel@tonic-gate */ 78997c478bd9Sstevel@tonic-gate static void 79007c478bd9Sstevel@tonic-gate fas_set_pkt_reason(struct fas *fas, struct fas_cmd *sp, uchar_t reason, 79017c478bd9Sstevel@tonic-gate uint_t stat) 79027c478bd9Sstevel@tonic-gate { 79037c478bd9Sstevel@tonic-gate if (sp) { 79047c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_reason == CMD_CMPLT) { 79057c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason = reason; 79067c478bd9Sstevel@tonic-gate } 79077c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics |= stat; 79087c478bd9Sstevel@tonic-gate IPRINTF3("sp=0x%p, pkt_reason=%x, pkt_stat=%x\n", 79097c478bd9Sstevel@tonic-gate (void *)sp, reason, sp->cmd_pkt->pkt_statistics); 79107c478bd9Sstevel@tonic-gate } 79117c478bd9Sstevel@tonic-gate } 79127c478bd9Sstevel@tonic-gate 79137c478bd9Sstevel@tonic-gate /* 79147c478bd9Sstevel@tonic-gate * delete specified cmd from the ready queue 79157c478bd9Sstevel@tonic-gate */ 79167c478bd9Sstevel@tonic-gate static int 79177c478bd9Sstevel@tonic-gate fas_remove_from_readyQ(struct fas *fas, struct fas_cmd *sp, int slot) 79187c478bd9Sstevel@tonic-gate { 79197c478bd9Sstevel@tonic-gate struct fas_cmd *ssp, *psp; 79207c478bd9Sstevel@tonic-gate 79217c478bd9Sstevel@tonic-gate /* 79227c478bd9Sstevel@tonic-gate * command has not been started yet and is still in the ready queue 79237c478bd9Sstevel@tonic-gate */ 79247c478bd9Sstevel@tonic-gate if (sp) { 79257c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds > 0); 79267c478bd9Sstevel@tonic-gate /* 79277c478bd9Sstevel@tonic-gate * find packet on the ready queue and remove it 79287c478bd9Sstevel@tonic-gate */ 79297c478bd9Sstevel@tonic-gate for (psp = NULL, ssp = fas->f_readyf[slot]; ssp != NULL; 79307c478bd9Sstevel@tonic-gate psp = ssp, ssp = ssp->cmd_forw) { 79317c478bd9Sstevel@tonic-gate if (ssp == sp) { 79327c478bd9Sstevel@tonic-gate if (fas->f_readyf[slot] == sp) { 79337c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = sp->cmd_forw; 79347c478bd9Sstevel@tonic-gate } else { 79357c478bd9Sstevel@tonic-gate psp->cmd_forw = sp->cmd_forw; 79367c478bd9Sstevel@tonic-gate } 79377c478bd9Sstevel@tonic-gate if (fas->f_readyb[slot] == sp) { 79387c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = psp; 79397c478bd9Sstevel@tonic-gate } 79407c478bd9Sstevel@tonic-gate return (TRUE); 79417c478bd9Sstevel@tonic-gate } 79427c478bd9Sstevel@tonic-gate } 79437c478bd9Sstevel@tonic-gate } 79447c478bd9Sstevel@tonic-gate return (FALSE); 79457c478bd9Sstevel@tonic-gate } 79467c478bd9Sstevel@tonic-gate 79477c478bd9Sstevel@tonic-gate /* 79487c478bd9Sstevel@tonic-gate * add cmd to to head of the readyQ 79497c478bd9Sstevel@tonic-gate * due to tag allocation failure or preemption we have to return 79507c478bd9Sstevel@tonic-gate * this cmd to the readyQ 79517c478bd9Sstevel@tonic-gate */ 79527c478bd9Sstevel@tonic-gate static void 79537c478bd9Sstevel@tonic-gate fas_head_of_readyQ(struct fas *fas, struct fas_cmd *sp) 79547c478bd9Sstevel@tonic-gate { 79557c478bd9Sstevel@tonic-gate /* 79567c478bd9Sstevel@tonic-gate * never return a NOINTR pkt to the readyQ 79577c478bd9Sstevel@tonic-gate * (fas_runpoll will resubmit) 79587c478bd9Sstevel@tonic-gate */ 79597c478bd9Sstevel@tonic-gate if ((sp->cmd_pkt_flags & FLAG_NOINTR) == 0) { 79607c478bd9Sstevel@tonic-gate struct fas_cmd *dp; 79617c478bd9Sstevel@tonic-gate int slot = sp->cmd_slot; 79627c478bd9Sstevel@tonic-gate 79637c478bd9Sstevel@tonic-gate dp = fas->f_readyf[slot]; 79647c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = sp; 79657c478bd9Sstevel@tonic-gate sp->cmd_forw = dp; 79667c478bd9Sstevel@tonic-gate if (fas->f_readyb[slot] == NULL) { 79677c478bd9Sstevel@tonic-gate fas->f_readyb[slot] = sp; 79687c478bd9Sstevel@tonic-gate } 79697c478bd9Sstevel@tonic-gate } 79707c478bd9Sstevel@tonic-gate } 79717c478bd9Sstevel@tonic-gate 79727c478bd9Sstevel@tonic-gate /* 79737c478bd9Sstevel@tonic-gate * flush cmds in ready queue 79747c478bd9Sstevel@tonic-gate */ 79757c478bd9Sstevel@tonic-gate static void 79767c478bd9Sstevel@tonic-gate fas_flush_readyQ(struct fas *fas, int slot) 79777c478bd9Sstevel@tonic-gate { 79787c478bd9Sstevel@tonic-gate if (fas->f_readyf[slot]) { 79797c478bd9Sstevel@tonic-gate struct fas_cmd *sp, *nsp; 79807c478bd9Sstevel@tonic-gate 79817c478bd9Sstevel@tonic-gate IPRINTF1("flushing ready queue, slot=%x\n", slot); 79827c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds > 0); 79837c478bd9Sstevel@tonic-gate 79847c478bd9Sstevel@tonic-gate sp = fas->f_readyf[slot]; 79857c478bd9Sstevel@tonic-gate fas->f_readyf[slot] = fas->f_readyb[slot] = NULL; 79867c478bd9Sstevel@tonic-gate 79877c478bd9Sstevel@tonic-gate while (sp != 0) { 79887c478bd9Sstevel@tonic-gate /* 79897c478bd9Sstevel@tonic-gate * save the forward pointer before calling 79907c478bd9Sstevel@tonic-gate * the completion routine 79917c478bd9Sstevel@tonic-gate */ 79927c478bd9Sstevel@tonic-gate nsp = sp->cmd_forw; 79937c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); 79947c478bd9Sstevel@tonic-gate ASSERT(Tgt(sp) == slot/NLUNS_PER_TARGET); 79957c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 79967c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 79977c478bd9Sstevel@tonic-gate sp = nsp; 79987c478bd9Sstevel@tonic-gate } 79997c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 80007c478bd9Sstevel@tonic-gate } 80017c478bd9Sstevel@tonic-gate } 80027c478bd9Sstevel@tonic-gate 80037c478bd9Sstevel@tonic-gate /* 80047c478bd9Sstevel@tonic-gate * cleanup the tag queue 80057c478bd9Sstevel@tonic-gate * preserve some order by starting with the oldest tag 80067c478bd9Sstevel@tonic-gate */ 80077c478bd9Sstevel@tonic-gate static void 80087c478bd9Sstevel@tonic-gate fas_flush_tagQ(struct fas *fas, int slot) 80097c478bd9Sstevel@tonic-gate { 80107c478bd9Sstevel@tonic-gate ushort_t tag, starttag; 80117c478bd9Sstevel@tonic-gate struct fas_cmd *sp; 80127c478bd9Sstevel@tonic-gate struct f_slots *tagque = fas->f_active[slot]; 80137c478bd9Sstevel@tonic-gate 80147c478bd9Sstevel@tonic-gate if (tagque == NULL) { 80157c478bd9Sstevel@tonic-gate return; 80167c478bd9Sstevel@tonic-gate } 80177c478bd9Sstevel@tonic-gate 80187c478bd9Sstevel@tonic-gate DPRINTF2("flushing entire tag queue, slot=%x, tcmds=%x\n", 80197c478bd9Sstevel@tonic-gate slot, fas->f_tcmds[slot]); 80207c478bd9Sstevel@tonic-gate 80217c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 80227c478bd9Sstevel@tonic-gate { 80237c478bd9Sstevel@tonic-gate int n = 0; 80247c478bd9Sstevel@tonic-gate for (tag = 0; tag < fas->f_active[slot]->f_n_slots; tag++) { 80257c478bd9Sstevel@tonic-gate if ((sp = tagque->f_slot[tag]) != 0) { 80267c478bd9Sstevel@tonic-gate n++; 80277c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); 80287c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_reason == CMD_CMPLT) { 80297c478bd9Sstevel@tonic-gate if ((sp->cmd_flags & CFLAG_FINISHED) == 80307c478bd9Sstevel@tonic-gate 0) { 80317c478bd9Sstevel@tonic-gate debug_enter("fas_flush_tagQ"); 80327c478bd9Sstevel@tonic-gate } 80337c478bd9Sstevel@tonic-gate } 80347c478bd9Sstevel@tonic-gate } 80357c478bd9Sstevel@tonic-gate } 80367c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] == n); 80377c478bd9Sstevel@tonic-gate } 80387c478bd9Sstevel@tonic-gate #endif 80397c478bd9Sstevel@tonic-gate tag = starttag = fas->f_active[slot]->f_tags; 80407c478bd9Sstevel@tonic-gate 80417c478bd9Sstevel@tonic-gate do { 80427c478bd9Sstevel@tonic-gate if ((sp = tagque->f_slot[tag]) != 0) { 80437c478bd9Sstevel@tonic-gate fas_flush_cmd(fas, sp, 0, 0); 80447c478bd9Sstevel@tonic-gate } 80457c478bd9Sstevel@tonic-gate tag = ((ushort_t)(tag + 1)) % 80467c478bd9Sstevel@tonic-gate (ushort_t)fas->f_active[slot]->f_n_slots; 80477c478bd9Sstevel@tonic-gate } while (tag != starttag); 80487c478bd9Sstevel@tonic-gate 80497c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[slot] == 0); 80507c478bd9Sstevel@tonic-gate EPRINTF2("ncmds = %x, ndisc=%x\n", fas->f_ncmds, fas->f_ndisc); 80517c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 80527c478bd9Sstevel@tonic-gate } 80537c478bd9Sstevel@tonic-gate 80547c478bd9Sstevel@tonic-gate /* 80557c478bd9Sstevel@tonic-gate * cleanup one active command 80567c478bd9Sstevel@tonic-gate */ 80577c478bd9Sstevel@tonic-gate static void 80587c478bd9Sstevel@tonic-gate fas_flush_cmd(struct fas *fas, struct fas_cmd *sp, uchar_t reason, 80597c478bd9Sstevel@tonic-gate uint_t stat) 80607c478bd9Sstevel@tonic-gate { 80617c478bd9Sstevel@tonic-gate short slot = sp->cmd_slot; 80627c478bd9Sstevel@tonic-gate 80637c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds > 0); 80647c478bd9Sstevel@tonic-gate ASSERT((sp->cmd_flags & CFLAG_FREE) == 0); 80657c478bd9Sstevel@tonic-gate ASSERT(sp == fas->f_active[slot]->f_slot[sp->cmd_tag[1]]); 80667c478bd9Sstevel@tonic-gate 80677c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, sp, NEW_TIMEOUT); 80687c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, sp); 80697c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, sp, reason, stat); 80707c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, sp); 80717c478bd9Sstevel@tonic-gate 80727c478bd9Sstevel@tonic-gate EPRINTF2("ncmds = %x, ndisc=%x\n", fas->f_ncmds, fas->f_ndisc); 80737c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 80747c478bd9Sstevel@tonic-gate } 80757c478bd9Sstevel@tonic-gate 80767c478bd9Sstevel@tonic-gate /* 80777c478bd9Sstevel@tonic-gate * prepare a proxy cmd (a cmd sent on behalf of the target driver, 80787c478bd9Sstevel@tonic-gate * usually for error recovery or abort/reset) 80797c478bd9Sstevel@tonic-gate */ 80807c478bd9Sstevel@tonic-gate static void 80817c478bd9Sstevel@tonic-gate fas_makeproxy_cmd(struct fas_cmd *sp, struct scsi_address *ap, 80827c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt, int nmsgs, ...) 80837c478bd9Sstevel@tonic-gate { 80847c478bd9Sstevel@tonic-gate va_list vap; 80857c478bd9Sstevel@tonic-gate int i; 80867c478bd9Sstevel@tonic-gate 80877c478bd9Sstevel@tonic-gate ASSERT(nmsgs <= (CDB_GROUP5 - CDB_GROUP0 - 3)); 80887c478bd9Sstevel@tonic-gate 80897c478bd9Sstevel@tonic-gate bzero(sp, sizeof (*sp)); 8090602ca9eaScth bzero(pkt, scsi_pkt_size()); 80917c478bd9Sstevel@tonic-gate 80927c478bd9Sstevel@tonic-gate pkt->pkt_address = *ap; 80937c478bd9Sstevel@tonic-gate pkt->pkt_cdbp = (opaque_t)&sp->cmd_cdb[0]; 80947c478bd9Sstevel@tonic-gate pkt->pkt_scbp = (opaque_t)&sp->cmd_scb; 80957c478bd9Sstevel@tonic-gate pkt->pkt_ha_private = (opaque_t)sp; 80967c478bd9Sstevel@tonic-gate sp->cmd_pkt = pkt; 80977c478bd9Sstevel@tonic-gate sp->cmd_scblen = 1; 80987c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags = pkt->pkt_flags = FLAG_NOINTR; 80997c478bd9Sstevel@tonic-gate sp->cmd_flags = CFLAG_CMDPROXY; 81007c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_TYPE] = FAS_PROXY_SNDMSG; 81017c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] = FALSE; 81027c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA] = (char)nmsgs; 81037c478bd9Sstevel@tonic-gate 81047c478bd9Sstevel@tonic-gate va_start(vap, nmsgs); 81057c478bd9Sstevel@tonic-gate for (i = 0; i < nmsgs; i++) { 81067c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_DATA + 1 + i] = (uchar_t)va_arg(vap, int); 81077c478bd9Sstevel@tonic-gate } 81087c478bd9Sstevel@tonic-gate va_end(vap); 81097c478bd9Sstevel@tonic-gate } 81107c478bd9Sstevel@tonic-gate 81117c478bd9Sstevel@tonic-gate /* 81127c478bd9Sstevel@tonic-gate * send a proxy cmd and check the result 81137c478bd9Sstevel@tonic-gate */ 81147c478bd9Sstevel@tonic-gate static int 81157c478bd9Sstevel@tonic-gate fas_do_proxy_cmd(struct fas *fas, struct fas_cmd *sp, 81167c478bd9Sstevel@tonic-gate struct scsi_address *ap, char *what) 81177c478bd9Sstevel@tonic-gate { 81187c478bd9Sstevel@tonic-gate int rval; 81197c478bd9Sstevel@tonic-gate 81207c478bd9Sstevel@tonic-gate IPRINTF3("Sending proxy %s message to %d.%d\n", what, 81217c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun); 81227c478bd9Sstevel@tonic-gate if (fas_accept_pkt(fas, sp, TRAN_BUSY_OK) == TRAN_ACCEPT && 81237c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason == CMD_CMPLT && 81247c478bd9Sstevel@tonic-gate sp->cmd_cdb[FAS_PROXY_RESULT] == TRUE) { 81257c478bd9Sstevel@tonic-gate IPRINTF3("Proxy %s succeeded for %d.%d\n", what, 81267c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun); 81277c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp != sp); 81287c478bd9Sstevel@tonic-gate rval = TRUE; 81297c478bd9Sstevel@tonic-gate } else { 81307c478bd9Sstevel@tonic-gate IPRINTF5( 81317c478bd9Sstevel@tonic-gate "Proxy %s failed for %d.%d, result=%x, reason=%x\n", what, 81327c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun, sp->cmd_cdb[FAS_PROXY_RESULT], 81337c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_reason); 81347c478bd9Sstevel@tonic-gate ASSERT(fas->f_current_sp != sp); 81357c478bd9Sstevel@tonic-gate rval = FALSE; 81367c478bd9Sstevel@tonic-gate } 81377c478bd9Sstevel@tonic-gate return (rval); 81387c478bd9Sstevel@tonic-gate } 81397c478bd9Sstevel@tonic-gate 81407c478bd9Sstevel@tonic-gate /* 81417c478bd9Sstevel@tonic-gate * abort a connected command by sending an abort msg; hold off on 81427c478bd9Sstevel@tonic-gate * starting new cmds by setting throttles to HOLD_THROTTLE 81437c478bd9Sstevel@tonic-gate */ 81447c478bd9Sstevel@tonic-gate static int 81457c478bd9Sstevel@tonic-gate fas_abort_connected_cmd(struct fas *fas, struct fas_cmd *sp, uchar_t msg) 81467c478bd9Sstevel@tonic-gate { 81477c478bd9Sstevel@tonic-gate int rval = FALSE; 81487c478bd9Sstevel@tonic-gate int flags = sp->cmd_pkt_flags; 81497c478bd9Sstevel@tonic-gate 81507c478bd9Sstevel@tonic-gate /* 81517c478bd9Sstevel@tonic-gate * if reset delay active we cannot access the target. 81527c478bd9Sstevel@tonic-gate */ 81537c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[Tgt(sp)]) { 81547c478bd9Sstevel@tonic-gate return (rval); 81557c478bd9Sstevel@tonic-gate } 81567c478bd9Sstevel@tonic-gate 81577c478bd9Sstevel@tonic-gate /* 81587c478bd9Sstevel@tonic-gate * only abort while in data phase; otherwise we mess up msg phase 81597c478bd9Sstevel@tonic-gate */ 81607c478bd9Sstevel@tonic-gate if (!((fas->f_state == ACTS_DATA) || 81617c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_DATA_DONE))) { 81627c478bd9Sstevel@tonic-gate return (rval); 81637c478bd9Sstevel@tonic-gate } 81647c478bd9Sstevel@tonic-gate 81657c478bd9Sstevel@tonic-gate 81667c478bd9Sstevel@tonic-gate IPRINTF3("Sending abort message %s to connected %d.%d\n", 81677c478bd9Sstevel@tonic-gate scsi_mname(msg), Tgt(sp), Lun(sp)); 81687c478bd9Sstevel@tonic-gate 81697c478bd9Sstevel@tonic-gate 81707c478bd9Sstevel@tonic-gate fas->f_abort_msg_sent = 0; 81717c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 81727c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = msg; 81737c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags |= FLAG_NOINTR; 81747c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 81757c478bd9Sstevel@tonic-gate 81767c478bd9Sstevel@tonic-gate (void) fas_dopoll(fas, SHORT_POLL_TIMEOUT); 81777c478bd9Sstevel@tonic-gate 81787c478bd9Sstevel@tonic-gate /* 81797c478bd9Sstevel@tonic-gate * now check if the msg was taken 81807c478bd9Sstevel@tonic-gate * e_abort is set in fas_handle_msg_out_done when the abort 81817c478bd9Sstevel@tonic-gate * msg has actually gone out (ie. msg out phase occurred 81827c478bd9Sstevel@tonic-gate */ 81837c478bd9Sstevel@tonic-gate if (fas->f_abort_msg_sent && (sp->cmd_flags & CFLAG_COMPLETED)) { 81847c478bd9Sstevel@tonic-gate IPRINTF2("target %d.%d aborted\n", 81857c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp)); 81867c478bd9Sstevel@tonic-gate rval = TRUE; 81877c478bd9Sstevel@tonic-gate } else { 81887c478bd9Sstevel@tonic-gate IPRINTF2("target %d.%d did not abort\n", 81897c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp)); 81907c478bd9Sstevel@tonic-gate } 81917c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags = flags; 81927c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 81937c478bd9Sstevel@tonic-gate return (rval); 81947c478bd9Sstevel@tonic-gate } 81957c478bd9Sstevel@tonic-gate 81967c478bd9Sstevel@tonic-gate /* 81977c478bd9Sstevel@tonic-gate * abort a disconnected command; if it is a tagged command, we need 81987c478bd9Sstevel@tonic-gate * to include the tag 81997c478bd9Sstevel@tonic-gate */ 82007c478bd9Sstevel@tonic-gate static int 82017c478bd9Sstevel@tonic-gate fas_abort_disconnected_cmd(struct fas *fas, struct scsi_address *ap, 82027c478bd9Sstevel@tonic-gate struct fas_cmd *sp, uchar_t msg, int slot) 82037c478bd9Sstevel@tonic-gate { 82047c478bd9Sstevel@tonic-gate auto struct fas_cmd local; 82057c478bd9Sstevel@tonic-gate struct fas_cmd *proxy_cmdp = &local; 8206602ca9eaScth struct scsi_pkt *pkt; 8207602ca9eaScth int rval; 82087c478bd9Sstevel@tonic-gate int target = ap->a_target; 82097c478bd9Sstevel@tonic-gate 82107c478bd9Sstevel@tonic-gate /* 82117c478bd9Sstevel@tonic-gate * if reset delay is active, we cannot start a selection 82127c478bd9Sstevel@tonic-gate * and there shouldn't be a cmd outstanding 82137c478bd9Sstevel@tonic-gate */ 82147c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[target] != 0) { 82157c478bd9Sstevel@tonic-gate return (FALSE); 82167c478bd9Sstevel@tonic-gate } 82177c478bd9Sstevel@tonic-gate 82187c478bd9Sstevel@tonic-gate if (sp) 82197c478bd9Sstevel@tonic-gate ASSERT(sp->cmd_slot == slot); 82207c478bd9Sstevel@tonic-gate 82217c478bd9Sstevel@tonic-gate IPRINTF1("aborting disconnected tagged cmd(s) with %s\n", 82227c478bd9Sstevel@tonic-gate scsi_mname(msg)); 8223602ca9eaScth pkt = kmem_alloc(scsi_pkt_size(), KM_SLEEP); 82247c478bd9Sstevel@tonic-gate if (sp && (TAGGED(target) && (msg == MSG_ABORT_TAG))) { 82257c478bd9Sstevel@tonic-gate int tag = sp->cmd_tag[1]; 82267c478bd9Sstevel@tonic-gate ASSERT(sp == fas->f_active[slot]->f_slot[tag]); 8227602ca9eaScth fas_makeproxy_cmd(proxy_cmdp, ap, pkt, 3, 82287c478bd9Sstevel@tonic-gate MSG_SIMPLE_QTAG, tag, msg); 82297c478bd9Sstevel@tonic-gate } else { 8230602ca9eaScth fas_makeproxy_cmd(proxy_cmdp, ap, pkt, 1, msg); 82317c478bd9Sstevel@tonic-gate } 82327c478bd9Sstevel@tonic-gate 8233602ca9eaScth rval = fas_do_proxy_cmd(fas, proxy_cmdp, ap, scsi_mname(msg)); 8234602ca9eaScth kmem_free(pkt, scsi_pkt_size()); 8235602ca9eaScth return (rval); 82367c478bd9Sstevel@tonic-gate } 82377c478bd9Sstevel@tonic-gate 82387c478bd9Sstevel@tonic-gate /* 82397c478bd9Sstevel@tonic-gate * reset handling: 82407c478bd9Sstevel@tonic-gate * fas_do_scsi_reset assumes that we have already entered the mutex 82417c478bd9Sstevel@tonic-gate */ 82427c478bd9Sstevel@tonic-gate static int 82437c478bd9Sstevel@tonic-gate fas_do_scsi_reset(struct scsi_address *ap, int level) 82447c478bd9Sstevel@tonic-gate { 82457c478bd9Sstevel@tonic-gate int rval = FALSE; 82467c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 82477c478bd9Sstevel@tonic-gate short slot = (ap->a_target * NLUNS_PER_TARGET) | ap->a_lun; 82487c478bd9Sstevel@tonic-gate 82497c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 82507c478bd9Sstevel@tonic-gate IPRINTF3("fas_scsi_reset for slot %x, level=%x, tcmds=%x\n", 82517c478bd9Sstevel@tonic-gate slot, level, fas->f_tcmds[slot]); 82527c478bd9Sstevel@tonic-gate 82537c478bd9Sstevel@tonic-gate fas_move_waitQ_to_readyQ(fas); 82547c478bd9Sstevel@tonic-gate 82557c478bd9Sstevel@tonic-gate if (level == RESET_ALL) { 82567c478bd9Sstevel@tonic-gate /* 82577c478bd9Sstevel@tonic-gate * We know that fas_reset_bus() returns ACTION_RETURN. 82587c478bd9Sstevel@tonic-gate */ 82597c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 82607c478bd9Sstevel@tonic-gate 82617c478bd9Sstevel@tonic-gate /* 82627c478bd9Sstevel@tonic-gate * Now call fas_dopoll() to field the reset interrupt 82637c478bd9Sstevel@tonic-gate * which will then call fas_reset_recovery which will 82647c478bd9Sstevel@tonic-gate * call the completion function for all commands. 82657c478bd9Sstevel@tonic-gate */ 82667c478bd9Sstevel@tonic-gate if (fas_dopoll(fas, SHORT_POLL_TIMEOUT) <= 0) { 82677c478bd9Sstevel@tonic-gate /* 82687c478bd9Sstevel@tonic-gate * reset fas 82697c478bd9Sstevel@tonic-gate */ 82707c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_FAS); 82717c478bd9Sstevel@tonic-gate (void) fas_reset_bus(fas); 82727c478bd9Sstevel@tonic-gate if (fas_dopoll(fas, SHORT_POLL_TIMEOUT) <= 0) { 82737c478bd9Sstevel@tonic-gate fas_log(fas, 82747c478bd9Sstevel@tonic-gate CE_WARN, "reset scsi bus failed"); 82757c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 82767c478bd9Sstevel@tonic-gate } else { 82777c478bd9Sstevel@tonic-gate rval = TRUE; 82787c478bd9Sstevel@tonic-gate } 82797c478bd9Sstevel@tonic-gate } else { 82807c478bd9Sstevel@tonic-gate rval = TRUE; 82817c478bd9Sstevel@tonic-gate } 82827c478bd9Sstevel@tonic-gate 82837c478bd9Sstevel@tonic-gate } else { 82847c478bd9Sstevel@tonic-gate struct fas_cmd *cur_sp = fas->f_current_sp; 82857c478bd9Sstevel@tonic-gate void (*savec)() = NULL; 82867c478bd9Sstevel@tonic-gate 82877c478bd9Sstevel@tonic-gate /* 82887c478bd9Sstevel@tonic-gate * prevent new commands from starting 82897c478bd9Sstevel@tonic-gate */ 82907c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, HOLD_THROTTLE); 82917c478bd9Sstevel@tonic-gate 82927c478bd9Sstevel@tonic-gate /* 82937c478bd9Sstevel@tonic-gate * zero pkt_comp so it won't complete during the reset and 82947c478bd9Sstevel@tonic-gate * we can still update the packet after the reset. 82957c478bd9Sstevel@tonic-gate */ 82967c478bd9Sstevel@tonic-gate if (cur_sp) { 82977c478bd9Sstevel@tonic-gate savec = cur_sp->cmd_pkt->pkt_comp; 82987c478bd9Sstevel@tonic-gate cur_sp->cmd_pkt->pkt_comp = NULL; 82997c478bd9Sstevel@tonic-gate } 83007c478bd9Sstevel@tonic-gate 83017c478bd9Sstevel@tonic-gate /* 83027c478bd9Sstevel@tonic-gate * is this a connected cmd but not selecting? 83037c478bd9Sstevel@tonic-gate */ 83047c478bd9Sstevel@tonic-gate if (cur_sp && (fas->f_state != STATE_FREE) && 83057c478bd9Sstevel@tonic-gate (cur_sp->cmd_pkt->pkt_state != 0) && 83067c478bd9Sstevel@tonic-gate (ap->a_target == (Tgt(cur_sp)))) { 83077c478bd9Sstevel@tonic-gate rval = fas_reset_connected_cmd(fas, ap); 83087c478bd9Sstevel@tonic-gate } 83097c478bd9Sstevel@tonic-gate 83107c478bd9Sstevel@tonic-gate /* 83117c478bd9Sstevel@tonic-gate * if not connected or fas_reset_connected_cmd() failed, 83127c478bd9Sstevel@tonic-gate * attempt a reset_disconnected_cmd 83137c478bd9Sstevel@tonic-gate */ 83147c478bd9Sstevel@tonic-gate if (rval == FALSE) { 83157c478bd9Sstevel@tonic-gate rval = fas_reset_disconnected_cmd(fas, ap); 83167c478bd9Sstevel@tonic-gate } 83177c478bd9Sstevel@tonic-gate 83187c478bd9Sstevel@tonic-gate /* 83197c478bd9Sstevel@tonic-gate * cleanup if reset was successful 83207c478bd9Sstevel@tonic-gate * complete the current sp first. 83217c478bd9Sstevel@tonic-gate */ 83227c478bd9Sstevel@tonic-gate if (cur_sp) { 83237c478bd9Sstevel@tonic-gate cur_sp->cmd_pkt->pkt_comp = savec; 83247c478bd9Sstevel@tonic-gate if (cur_sp->cmd_flags & CFLAG_COMPLETED) { 83257c478bd9Sstevel@tonic-gate if (ap->a_target == (Tgt(cur_sp))) { 83267c478bd9Sstevel@tonic-gate fas_set_pkt_reason(fas, cur_sp, 83277c478bd9Sstevel@tonic-gate CMD_RESET, STAT_DEV_RESET); 83287c478bd9Sstevel@tonic-gate } 83297c478bd9Sstevel@tonic-gate fas_remove_cmd(fas, cur_sp, NEW_TIMEOUT); 83307c478bd9Sstevel@tonic-gate cur_sp->cmd_flags &= ~CFLAG_COMPLETED; 83317c478bd9Sstevel@tonic-gate fas_decrement_ncmds(fas, cur_sp); 83327c478bd9Sstevel@tonic-gate fas_call_pkt_comp(fas, cur_sp); 83337c478bd9Sstevel@tonic-gate } 83347c478bd9Sstevel@tonic-gate } 83357c478bd9Sstevel@tonic-gate 83367c478bd9Sstevel@tonic-gate if (rval == TRUE) { 83377c478bd9Sstevel@tonic-gate fas_reset_cleanup(fas, slot); 83387c478bd9Sstevel@tonic-gate } else { 83397c478bd9Sstevel@tonic-gate IPRINTF1("fas_scsi_reset failed for slot %x\n", slot); 83407c478bd9Sstevel@tonic-gate 83417c478bd9Sstevel@tonic-gate /* 83427c478bd9Sstevel@tonic-gate * restore throttles to max throttle, regardless 83437c478bd9Sstevel@tonic-gate * of what it was (fas_set_throttles() will deal 83447c478bd9Sstevel@tonic-gate * with reset delay active) 83457c478bd9Sstevel@tonic-gate * restoring to the old throttle is not 83467c478bd9Sstevel@tonic-gate * a such a good idea 83477c478bd9Sstevel@tonic-gate */ 83487c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, MAX_THROTTLE); 83497c478bd9Sstevel@tonic-gate 83507c478bd9Sstevel@tonic-gate } 83517c478bd9Sstevel@tonic-gate 83527c478bd9Sstevel@tonic-gate if (fas->f_state == STATE_FREE) { 83537c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 83547c478bd9Sstevel@tonic-gate } 83557c478bd9Sstevel@tonic-gate } 83567c478bd9Sstevel@tonic-gate exit: 83577c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 83587c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 83597c478bd9Sstevel@tonic-gate 83607c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 83617c478bd9Sstevel@tonic-gate if (rval && fas_test_stop) { 83627c478bd9Sstevel@tonic-gate debug_enter("reset succeeded"); 83637c478bd9Sstevel@tonic-gate } 83647c478bd9Sstevel@tonic-gate #endif 83657c478bd9Sstevel@tonic-gate return (rval); 83667c478bd9Sstevel@tonic-gate } 83677c478bd9Sstevel@tonic-gate 83687c478bd9Sstevel@tonic-gate /* 83697c478bd9Sstevel@tonic-gate * reset delay is handled by a separate watchdog; this ensures that 83707c478bd9Sstevel@tonic-gate * regardless of fas_scsi_watchdog_tick, the reset delay will not change 83717c478bd9Sstevel@tonic-gate */ 83727c478bd9Sstevel@tonic-gate static void 83737c478bd9Sstevel@tonic-gate fas_start_watch_reset_delay(struct fas *fas) 83747c478bd9Sstevel@tonic-gate { 83757c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 83767c478bd9Sstevel@tonic-gate if ((fas_reset_watch == 0) && FAS_CAN_SCHED) { 83777c478bd9Sstevel@tonic-gate fas_reset_watch = timeout(fas_watch_reset_delay, NULL, 83787c478bd9Sstevel@tonic-gate drv_usectohz((clock_t)FAS_WATCH_RESET_DELAY_TICK * 1000)); 83797c478bd9Sstevel@tonic-gate } 83807c478bd9Sstevel@tonic-gate ASSERT((fas_reset_watch != 0) || (fas->f_flags & FAS_FLG_NOTIMEOUTS)); 83817c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 83827c478bd9Sstevel@tonic-gate } 83837c478bd9Sstevel@tonic-gate 83847c478bd9Sstevel@tonic-gate /* 83857c478bd9Sstevel@tonic-gate * set throttles to HOLD and set reset_delay for all target/luns 83867c478bd9Sstevel@tonic-gate */ 83877c478bd9Sstevel@tonic-gate static void 83887c478bd9Sstevel@tonic-gate fas_setup_reset_delay(struct fas *fas) 83897c478bd9Sstevel@tonic-gate { 83907c478bd9Sstevel@tonic-gate if (!ddi_in_panic()) { 83917c478bd9Sstevel@tonic-gate int i; 83927c478bd9Sstevel@tonic-gate 83937c478bd9Sstevel@tonic-gate fas_set_throttles(fas, 0, N_SLOTS, HOLD_THROTTLE); 83947c478bd9Sstevel@tonic-gate for (i = 0; i < NTARGETS_WIDE; i++) { 83957c478bd9Sstevel@tonic-gate fas->f_reset_delay[i] = fas->f_scsi_reset_delay; 83967c478bd9Sstevel@tonic-gate } 83977c478bd9Sstevel@tonic-gate fas_start_watch_reset_delay(fas); 83987c478bd9Sstevel@tonic-gate } else { 83997c478bd9Sstevel@tonic-gate drv_usecwait(fas->f_scsi_reset_delay * 1000); 84007c478bd9Sstevel@tonic-gate } 84017c478bd9Sstevel@tonic-gate } 84027c478bd9Sstevel@tonic-gate 84037c478bd9Sstevel@tonic-gate /* 84047c478bd9Sstevel@tonic-gate * fas_watch_reset_delay(_subr) is invoked by timeout() and checks every 84057c478bd9Sstevel@tonic-gate * fas instance for active reset delays 84067c478bd9Sstevel@tonic-gate */ 84077c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 84087c478bd9Sstevel@tonic-gate static void 84097c478bd9Sstevel@tonic-gate fas_watch_reset_delay(void *arg) 84107c478bd9Sstevel@tonic-gate { 84117c478bd9Sstevel@tonic-gate struct fas *fas; 84127c478bd9Sstevel@tonic-gate struct fas *lfas; /* last not_done fas */ 84137c478bd9Sstevel@tonic-gate int not_done = 0; 84147c478bd9Sstevel@tonic-gate 84157c478bd9Sstevel@tonic-gate mutex_enter(&fas_global_mutex); 84167c478bd9Sstevel@tonic-gate fas_reset_watch = 0; 84177c478bd9Sstevel@tonic-gate mutex_exit(&fas_global_mutex); 84187c478bd9Sstevel@tonic-gate 84197c478bd9Sstevel@tonic-gate rw_enter(&fas_global_rwlock, RW_READER); 84207c478bd9Sstevel@tonic-gate for (fas = fas_head; fas != (struct fas *)NULL; fas = fas->f_next) { 84217c478bd9Sstevel@tonic-gate if (fas->f_tran == 0) { 84227c478bd9Sstevel@tonic-gate continue; 84237c478bd9Sstevel@tonic-gate } 84247c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 84257c478bd9Sstevel@tonic-gate not_done += fas_watch_reset_delay_subr(fas); 84267c478bd9Sstevel@tonic-gate lfas = fas; 84277c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 84287c478bd9Sstevel@tonic-gate } 84297c478bd9Sstevel@tonic-gate rw_exit(&fas_global_rwlock); 84307c478bd9Sstevel@tonic-gate if (not_done) { 84317c478bd9Sstevel@tonic-gate ASSERT(lfas != NULL); 84327c478bd9Sstevel@tonic-gate fas_start_watch_reset_delay(lfas); 84337c478bd9Sstevel@tonic-gate } 84347c478bd9Sstevel@tonic-gate } 84357c478bd9Sstevel@tonic-gate 84367c478bd9Sstevel@tonic-gate static int 84377c478bd9Sstevel@tonic-gate fas_watch_reset_delay_subr(struct fas *fas) 84387c478bd9Sstevel@tonic-gate { 84397c478bd9Sstevel@tonic-gate short slot, s; 84407c478bd9Sstevel@tonic-gate int start_slot = -1; 84417c478bd9Sstevel@tonic-gate int done = 0; 84427c478bd9Sstevel@tonic-gate 84437c478bd9Sstevel@tonic-gate for (slot = 0; slot < N_SLOTS; slot += NLUNS_PER_TARGET) { 84447c478bd9Sstevel@tonic-gate 84457c478bd9Sstevel@tonic-gate /* 84467c478bd9Sstevel@tonic-gate * check if a reset delay is active; if so back to full throttle 84477c478bd9Sstevel@tonic-gate * which will unleash the cmds in the ready Q 84487c478bd9Sstevel@tonic-gate */ 84497c478bd9Sstevel@tonic-gate s = slot/NLUNS_PER_TARGET; 84507c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[s] != 0) { 84517c478bd9Sstevel@tonic-gate EPRINTF2("target%d: reset delay=%d\n", s, 84527c478bd9Sstevel@tonic-gate fas->f_reset_delay[s]); 84537c478bd9Sstevel@tonic-gate fas->f_reset_delay[s] -= FAS_WATCH_RESET_DELAY_TICK; 84547c478bd9Sstevel@tonic-gate if (fas->f_reset_delay[s] <= 0) { 84557c478bd9Sstevel@tonic-gate /* 84567c478bd9Sstevel@tonic-gate * clear throttle for all luns on this target 84577c478bd9Sstevel@tonic-gate */ 84587c478bd9Sstevel@tonic-gate fas->f_reset_delay[s] = 0; 84597c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, 84607c478bd9Sstevel@tonic-gate slot, MAX_THROTTLE); 84617c478bd9Sstevel@tonic-gate IPRINTF1("reset delay completed, slot=%x\n", 84627c478bd9Sstevel@tonic-gate slot); 84637c478bd9Sstevel@tonic-gate if (start_slot == -1) { 84647c478bd9Sstevel@tonic-gate start_slot = slot; 84657c478bd9Sstevel@tonic-gate } 84667c478bd9Sstevel@tonic-gate } else { 84677c478bd9Sstevel@tonic-gate done = -1; 84687c478bd9Sstevel@tonic-gate } 84697c478bd9Sstevel@tonic-gate } 84707c478bd9Sstevel@tonic-gate } 84717c478bd9Sstevel@tonic-gate 84727c478bd9Sstevel@tonic-gate /* 84737c478bd9Sstevel@tonic-gate * start a cmd if a reset delay expired 84747c478bd9Sstevel@tonic-gate */ 84757c478bd9Sstevel@tonic-gate if (start_slot != -1 && fas->f_state == STATE_FREE) { 84767c478bd9Sstevel@tonic-gate (void) fas_ustart(fas); 84777c478bd9Sstevel@tonic-gate } 84787c478bd9Sstevel@tonic-gate return (done); 84797c478bd9Sstevel@tonic-gate } 84807c478bd9Sstevel@tonic-gate 84817c478bd9Sstevel@tonic-gate /* 84827c478bd9Sstevel@tonic-gate * cleanup after a device reset. this affects all target's luns 84837c478bd9Sstevel@tonic-gate */ 84847c478bd9Sstevel@tonic-gate static void 84857c478bd9Sstevel@tonic-gate fas_reset_cleanup(struct fas *fas, int slot) 84867c478bd9Sstevel@tonic-gate { 84877c478bd9Sstevel@tonic-gate /* 84887c478bd9Sstevel@tonic-gate * reset msg has been accepted, now cleanup queues; 84897c478bd9Sstevel@tonic-gate * for all luns of this target 84907c478bd9Sstevel@tonic-gate */ 84917c478bd9Sstevel@tonic-gate int i, start, end; 84927c478bd9Sstevel@tonic-gate int target = slot/NLUNS_PER_TARGET; 84937c478bd9Sstevel@tonic-gate 84947c478bd9Sstevel@tonic-gate start = slot & ~(NLUNS_PER_TARGET-1); 84957c478bd9Sstevel@tonic-gate end = start + NLUNS_PER_TARGET; 84967c478bd9Sstevel@tonic-gate IPRINTF4("fas_reset_cleanup: slot %x, start=%x, end=%x, tcmds=%x\n", 84977c478bd9Sstevel@tonic-gate slot, start, end, fas->f_tcmds[slot]); 84987c478bd9Sstevel@tonic-gate 84997c478bd9Sstevel@tonic-gate ASSERT(!(fas->f_current_sp && 85007c478bd9Sstevel@tonic-gate (fas->f_current_sp->cmd_slot == slot) && 85017c478bd9Sstevel@tonic-gate (fas->f_state & STATE_SELECTING))); 85027c478bd9Sstevel@tonic-gate 85037c478bd9Sstevel@tonic-gate /* 85047c478bd9Sstevel@tonic-gate * if we are not in panic set up a reset delay for this target, 85057c478bd9Sstevel@tonic-gate * a zero throttle forces all new requests into the ready Q 85067c478bd9Sstevel@tonic-gate */ 85077c478bd9Sstevel@tonic-gate if (!ddi_in_panic()) { 85087c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, start, HOLD_THROTTLE); 85097c478bd9Sstevel@tonic-gate fas->f_reset_delay[target] = fas->f_scsi_reset_delay; 85107c478bd9Sstevel@tonic-gate fas_start_watch_reset_delay(fas); 85117c478bd9Sstevel@tonic-gate } else { 85127c478bd9Sstevel@tonic-gate drv_usecwait(fas->f_scsi_reset_delay * 1000); 85137c478bd9Sstevel@tonic-gate } 85147c478bd9Sstevel@tonic-gate 85157c478bd9Sstevel@tonic-gate for (i = start; i < end; i++) { 85167c478bd9Sstevel@tonic-gate fas_mark_packets(fas, i, CMD_RESET, STAT_DEV_RESET); 85177c478bd9Sstevel@tonic-gate fas_flush_tagQ(fas, i); 85187c478bd9Sstevel@tonic-gate fas_flush_readyQ(fas, i); 85197c478bd9Sstevel@tonic-gate if (fas->f_arq_pkt[i]) { 85207c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_arq_pkt[i]; 85217c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data = 852219397407SSherry Moore (struct arq_private_data *) 852319397407SSherry Moore (sp->cmd_pkt->pkt_private); 85247c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_comp) { 85257c478bd9Sstevel@tonic-gate ASSERT(arq_data->arq_save_sp == NULL); 85267c478bd9Sstevel@tonic-gate } 85277c478bd9Sstevel@tonic-gate } 85287c478bd9Sstevel@tonic-gate ASSERT(fas->f_tcmds[i] == 0); 85297c478bd9Sstevel@tonic-gate } 85307c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 85317c478bd9Sstevel@tonic-gate 85327c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, target); 85337c478bd9Sstevel@tonic-gate } 85347c478bd9Sstevel@tonic-gate 85357c478bd9Sstevel@tonic-gate /* 85367c478bd9Sstevel@tonic-gate * reset a currently disconnected target 85377c478bd9Sstevel@tonic-gate */ 85387c478bd9Sstevel@tonic-gate static int 85397c478bd9Sstevel@tonic-gate fas_reset_disconnected_cmd(struct fas *fas, struct scsi_address *ap) 85407c478bd9Sstevel@tonic-gate { 85417c478bd9Sstevel@tonic-gate auto struct fas_cmd local; 85427c478bd9Sstevel@tonic-gate struct fas_cmd *sp = &local; 8543602ca9eaScth struct scsi_pkt *pkt; 8544602ca9eaScth int rval; 85457c478bd9Sstevel@tonic-gate 8546602ca9eaScth pkt = kmem_alloc(scsi_pkt_size(), KM_SLEEP); 8547602ca9eaScth fas_makeproxy_cmd(sp, ap, pkt, 1, MSG_DEVICE_RESET); 8548602ca9eaScth rval = fas_do_proxy_cmd(fas, sp, ap, scsi_mname(MSG_DEVICE_RESET)); 8549602ca9eaScth kmem_free(pkt, scsi_pkt_size()); 8550602ca9eaScth return (rval); 85517c478bd9Sstevel@tonic-gate } 85527c478bd9Sstevel@tonic-gate 85537c478bd9Sstevel@tonic-gate /* 85547c478bd9Sstevel@tonic-gate * reset a target with a currently connected command 85557c478bd9Sstevel@tonic-gate * Assert ATN and send MSG_DEVICE_RESET, zero throttles temporarily 85567c478bd9Sstevel@tonic-gate * to prevent new cmds from starting regardless of the outcome 85577c478bd9Sstevel@tonic-gate */ 85587c478bd9Sstevel@tonic-gate static int 85597c478bd9Sstevel@tonic-gate fas_reset_connected_cmd(struct fas *fas, struct scsi_address *ap) 85607c478bd9Sstevel@tonic-gate { 85617c478bd9Sstevel@tonic-gate int rval = FALSE; 85627c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 85637c478bd9Sstevel@tonic-gate int flags = sp->cmd_pkt_flags; 85647c478bd9Sstevel@tonic-gate 85657c478bd9Sstevel@tonic-gate /* 85667c478bd9Sstevel@tonic-gate * only attempt to reset in data phase; during other phases 85677c478bd9Sstevel@tonic-gate * asserting ATN may just cause confusion 85687c478bd9Sstevel@tonic-gate */ 85697c478bd9Sstevel@tonic-gate if (!((fas->f_state == ACTS_DATA) || 85707c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_DATA_DONE))) { 85717c478bd9Sstevel@tonic-gate return (rval); 85727c478bd9Sstevel@tonic-gate } 85737c478bd9Sstevel@tonic-gate 85747c478bd9Sstevel@tonic-gate IPRINTF2("Sending reset message to connected %d.%d\n", 85757c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun); 85767c478bd9Sstevel@tonic-gate fas->f_reset_msg_sent = 0; 85777c478bd9Sstevel@tonic-gate fas->f_omsglen = 1; 85787c478bd9Sstevel@tonic-gate fas->f_cur_msgout[0] = MSG_DEVICE_RESET; 85797c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags |= FLAG_NOINTR; 85807c478bd9Sstevel@tonic-gate 85817c478bd9Sstevel@tonic-gate fas_assert_atn(fas); 85827c478bd9Sstevel@tonic-gate 85837c478bd9Sstevel@tonic-gate /* 85847c478bd9Sstevel@tonic-gate * poll for interrupts until bus free 85857c478bd9Sstevel@tonic-gate */ 85867c478bd9Sstevel@tonic-gate (void) fas_dopoll(fas, SHORT_POLL_TIMEOUT); 85877c478bd9Sstevel@tonic-gate 85887c478bd9Sstevel@tonic-gate /* 85897c478bd9Sstevel@tonic-gate * now check if the msg was taken 85907c478bd9Sstevel@tonic-gate * f_reset is set in fas_handle_msg_out_done when 85917c478bd9Sstevel@tonic-gate * msg has actually gone out (ie. msg out phase occurred) 85927c478bd9Sstevel@tonic-gate */ 85937c478bd9Sstevel@tonic-gate if (fas->f_reset_msg_sent && (sp->cmd_flags & CFLAG_COMPLETED)) { 85947c478bd9Sstevel@tonic-gate IPRINTF2("target %d.%d reset\n", ap->a_target, ap->a_lun); 85957c478bd9Sstevel@tonic-gate rval = TRUE; 85967c478bd9Sstevel@tonic-gate } else { 85977c478bd9Sstevel@tonic-gate IPRINTF2("target %d.%d did not reset\n", 85987c478bd9Sstevel@tonic-gate ap->a_target, ap->a_lun); 85997c478bd9Sstevel@tonic-gate } 86007c478bd9Sstevel@tonic-gate sp->cmd_pkt_flags = flags; 86017c478bd9Sstevel@tonic-gate fas->f_omsglen = 0; 86027c478bd9Sstevel@tonic-gate 86037c478bd9Sstevel@tonic-gate return (rval); 86047c478bd9Sstevel@tonic-gate } 86057c478bd9Sstevel@tonic-gate 86067c478bd9Sstevel@tonic-gate /* 86077c478bd9Sstevel@tonic-gate * reset the scsi bus to blow all commands away 86087c478bd9Sstevel@tonic-gate */ 86097c478bd9Sstevel@tonic-gate static int 86107c478bd9Sstevel@tonic-gate fas_reset_bus(struct fas *fas) 86117c478bd9Sstevel@tonic-gate { 86127c478bd9Sstevel@tonic-gate IPRINTF("fas_reset_bus:\n"); 86137c478bd9Sstevel@tonic-gate New_state(fas, ACTS_RESET); 86147c478bd9Sstevel@tonic-gate 86157c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_SCSIBUS); 86167c478bd9Sstevel@tonic-gate 86177c478bd9Sstevel@tonic-gate /* 86187c478bd9Sstevel@tonic-gate * Now that we've reset the SCSI bus, we'll take a SCSI RESET 86197c478bd9Sstevel@tonic-gate * interrupt and use that to clean up the state of things. 86207c478bd9Sstevel@tonic-gate */ 86217c478bd9Sstevel@tonic-gate return (ACTION_RETURN); 86227c478bd9Sstevel@tonic-gate } 86237c478bd9Sstevel@tonic-gate 86247c478bd9Sstevel@tonic-gate /* 86257c478bd9Sstevel@tonic-gate * fas_reset_recovery is called on the reset interrupt and cleans 86267c478bd9Sstevel@tonic-gate * up all cmds (active or waiting) 86277c478bd9Sstevel@tonic-gate */ 86287c478bd9Sstevel@tonic-gate static int 86297c478bd9Sstevel@tonic-gate fas_reset_recovery(struct fas *fas) 86307c478bd9Sstevel@tonic-gate { 86317c478bd9Sstevel@tonic-gate short slot, start_slot; 86327c478bd9Sstevel@tonic-gate int i; 86337c478bd9Sstevel@tonic-gate int rval = ACTION_SEARCH; 86347c478bd9Sstevel@tonic-gate int max_loop = 0; 86357c478bd9Sstevel@tonic-gate 86367c478bd9Sstevel@tonic-gate IPRINTF("fas_reset_recovery:\n"); 86377c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 86387c478bd9Sstevel@tonic-gate 86397c478bd9Sstevel@tonic-gate /* 86407c478bd9Sstevel@tonic-gate * renegotiate wide and sync for all targets 86417c478bd9Sstevel@tonic-gate */ 86427c478bd9Sstevel@tonic-gate fas->f_sync_known = fas->f_wide_known = 0; 86437c478bd9Sstevel@tonic-gate 86447c478bd9Sstevel@tonic-gate /* 86457c478bd9Sstevel@tonic-gate * reset dma engine 86467c478bd9Sstevel@tonic-gate */ 86477c478bd9Sstevel@tonic-gate FAS_FLUSH_DMA_HARD(fas); 86487c478bd9Sstevel@tonic-gate 86497c478bd9Sstevel@tonic-gate /* 86507c478bd9Sstevel@tonic-gate * set throttles and reset delay 86517c478bd9Sstevel@tonic-gate */ 86527c478bd9Sstevel@tonic-gate fas_setup_reset_delay(fas); 86537c478bd9Sstevel@tonic-gate 86547c478bd9Sstevel@tonic-gate /* 86557c478bd9Sstevel@tonic-gate * clear interrupts until they go away 86567c478bd9Sstevel@tonic-gate */ 86577c478bd9Sstevel@tonic-gate while (INTPENDING(fas) && (max_loop < FAS_RESET_SPIN_MAX_LOOP)) { 86587c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 86597c478bd9Sstevel@tonic-gate fas->f_stat = fas_reg_read(fas, &fasreg->fas_stat); 86607c478bd9Sstevel@tonic-gate fas->f_stat2 = fas_reg_read(fas, &fasreg->fas_stat2); 86617c478bd9Sstevel@tonic-gate fas->f_step = fas_reg_read(fas, &fasreg->fas_step); 86627c478bd9Sstevel@tonic-gate fas->f_intr = fas_reg_read(fas, &fasreg->fas_intr); 86637c478bd9Sstevel@tonic-gate drv_usecwait(FAS_RESET_SPIN_DELAY_USEC); 86647c478bd9Sstevel@tonic-gate max_loop++; 86657c478bd9Sstevel@tonic-gate } 86667c478bd9Sstevel@tonic-gate 86677c478bd9Sstevel@tonic-gate if (max_loop >= FAS_RESET_SPIN_MAX_LOOP) { 86687c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "Resetting SCSI bus failed"); 86697c478bd9Sstevel@tonic-gate } 86707c478bd9Sstevel@tonic-gate 86717c478bd9Sstevel@tonic-gate fas_reg_cmd_write(fas, CMD_FLUSH); 86727c478bd9Sstevel@tonic-gate 86737c478bd9Sstevel@tonic-gate /* 86747c478bd9Sstevel@tonic-gate * reset the chip, this shouldn't be necessary but sometimes 86757c478bd9Sstevel@tonic-gate * we get a hang in the next data in phase 86767c478bd9Sstevel@tonic-gate */ 86777c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_FAS); 86787c478bd9Sstevel@tonic-gate 86797c478bd9Sstevel@tonic-gate /* 86807c478bd9Sstevel@tonic-gate * reset was expected? if not, it must be external bus reset 86817c478bd9Sstevel@tonic-gate */ 86827c478bd9Sstevel@tonic-gate if (fas->f_state != ACTS_RESET) { 86837c478bd9Sstevel@tonic-gate if (fas->f_ncmds) { 86847c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "external SCSI bus reset"); 86857c478bd9Sstevel@tonic-gate } 86867c478bd9Sstevel@tonic-gate } 86877c478bd9Sstevel@tonic-gate 86887c478bd9Sstevel@tonic-gate if (fas->f_ncmds == 0) { 86897c478bd9Sstevel@tonic-gate rval = ACTION_RETURN; 86907c478bd9Sstevel@tonic-gate goto done; 86917c478bd9Sstevel@tonic-gate } 86927c478bd9Sstevel@tonic-gate 86937c478bd9Sstevel@tonic-gate /* 86947c478bd9Sstevel@tonic-gate * completely reset the state of the softc data. 86957c478bd9Sstevel@tonic-gate */ 86967c478bd9Sstevel@tonic-gate fas_internal_reset(fas, FAS_RESET_SOFTC); 86977c478bd9Sstevel@tonic-gate 86987c478bd9Sstevel@tonic-gate /* 86997c478bd9Sstevel@tonic-gate * Hold the state of the host adapter open 87007c478bd9Sstevel@tonic-gate */ 87017c478bd9Sstevel@tonic-gate New_state(fas, ACTS_FROZEN); 87027c478bd9Sstevel@tonic-gate 87037c478bd9Sstevel@tonic-gate /* 87047c478bd9Sstevel@tonic-gate * for right now just claim that all 87057c478bd9Sstevel@tonic-gate * commands have been destroyed by a SCSI reset 87067c478bd9Sstevel@tonic-gate * and let already set reason fields or callers 87077c478bd9Sstevel@tonic-gate * decide otherwise for specific commands. 87087c478bd9Sstevel@tonic-gate */ 87097c478bd9Sstevel@tonic-gate start_slot = fas->f_next_slot; 87107c478bd9Sstevel@tonic-gate slot = start_slot; 87117c478bd9Sstevel@tonic-gate do { 87127c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 87137c478bd9Sstevel@tonic-gate fas_mark_packets(fas, slot, CMD_RESET, STAT_BUS_RESET); 87147c478bd9Sstevel@tonic-gate fas_flush_tagQ(fas, slot); 87157c478bd9Sstevel@tonic-gate fas_flush_readyQ(fas, slot); 87167c478bd9Sstevel@tonic-gate if (fas->f_arq_pkt[slot]) { 87177c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_arq_pkt[slot]; 87187c478bd9Sstevel@tonic-gate struct arq_private_data *arq_data = 871919397407SSherry Moore (struct arq_private_data *) 872019397407SSherry Moore (sp->cmd_pkt->pkt_private); 87217c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_comp) { 87227c478bd9Sstevel@tonic-gate ASSERT(arq_data->arq_save_sp == NULL); 87237c478bd9Sstevel@tonic-gate } 87247c478bd9Sstevel@tonic-gate } 87257c478bd9Sstevel@tonic-gate slot = NEXTSLOT(slot, fas->f_dslot); 87267c478bd9Sstevel@tonic-gate } while (slot != start_slot); 87277c478bd9Sstevel@tonic-gate 87287c478bd9Sstevel@tonic-gate fas_check_ncmds(fas); 87297c478bd9Sstevel@tonic-gate 87307c478bd9Sstevel@tonic-gate /* 87317c478bd9Sstevel@tonic-gate * reset timeouts 87327c478bd9Sstevel@tonic-gate */ 87337c478bd9Sstevel@tonic-gate for (i = 0; i < N_SLOTS; i++) { 87347c478bd9Sstevel@tonic-gate if (fas->f_active[i]) { 87357c478bd9Sstevel@tonic-gate fas->f_active[i]->f_timebase = 0; 87367c478bd9Sstevel@tonic-gate fas->f_active[i]->f_timeout = 0; 87377c478bd9Sstevel@tonic-gate fas->f_active[i]->f_dups = 0; 87387c478bd9Sstevel@tonic-gate } 87397c478bd9Sstevel@tonic-gate } 87407c478bd9Sstevel@tonic-gate 87417c478bd9Sstevel@tonic-gate done: 87427c478bd9Sstevel@tonic-gate /* 87437c478bd9Sstevel@tonic-gate * Move the state back to free... 87447c478bd9Sstevel@tonic-gate */ 87457c478bd9Sstevel@tonic-gate New_state(fas, STATE_FREE); 87467c478bd9Sstevel@tonic-gate ASSERT(fas->f_ncmds >= fas->f_ndisc); 87477c478bd9Sstevel@tonic-gate 87487c478bd9Sstevel@tonic-gate /* 87497c478bd9Sstevel@tonic-gate * perform the reset notification callbacks that are registered. 87507c478bd9Sstevel@tonic-gate */ 87517c478bd9Sstevel@tonic-gate (void) scsi_hba_reset_notify_callback(&fas->f_mutex, 87527c478bd9Sstevel@tonic-gate &fas->f_reset_notify_listf); 87537c478bd9Sstevel@tonic-gate 87547c478bd9Sstevel@tonic-gate /* 87557c478bd9Sstevel@tonic-gate * if reset delay is still active a search is meaningless 87567c478bd9Sstevel@tonic-gate * but do it anyway 87577c478bd9Sstevel@tonic-gate */ 87587c478bd9Sstevel@tonic-gate return (rval); 87597c478bd9Sstevel@tonic-gate } 87607c478bd9Sstevel@tonic-gate 87617c478bd9Sstevel@tonic-gate /* 87627c478bd9Sstevel@tonic-gate * hba_tran ops for quiesce and unquiesce 87637c478bd9Sstevel@tonic-gate */ 87647c478bd9Sstevel@tonic-gate static int 87657c478bd9Sstevel@tonic-gate fas_scsi_quiesce(dev_info_t *dip) 87667c478bd9Sstevel@tonic-gate { 87677c478bd9Sstevel@tonic-gate struct fas *fas; 87687c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran; 87697c478bd9Sstevel@tonic-gate 87707c478bd9Sstevel@tonic-gate tran = ddi_get_driver_private(dip); 87717c478bd9Sstevel@tonic-gate if ((tran == NULL) || ((fas = TRAN2FAS(tran)) == NULL)) { 87727c478bd9Sstevel@tonic-gate return (-1); 87737c478bd9Sstevel@tonic-gate } 87747c478bd9Sstevel@tonic-gate 87757c478bd9Sstevel@tonic-gate return (fas_quiesce_bus(fas)); 87767c478bd9Sstevel@tonic-gate } 87777c478bd9Sstevel@tonic-gate 87787c478bd9Sstevel@tonic-gate static int 87797c478bd9Sstevel@tonic-gate fas_scsi_unquiesce(dev_info_t *dip) 87807c478bd9Sstevel@tonic-gate { 87817c478bd9Sstevel@tonic-gate struct fas *fas; 87827c478bd9Sstevel@tonic-gate scsi_hba_tran_t *tran; 87837c478bd9Sstevel@tonic-gate 87847c478bd9Sstevel@tonic-gate tran = ddi_get_driver_private(dip); 87857c478bd9Sstevel@tonic-gate if ((tran == NULL) || ((fas = TRAN2FAS(tran)) == NULL)) { 87867c478bd9Sstevel@tonic-gate return (-1); 87877c478bd9Sstevel@tonic-gate } 87887c478bd9Sstevel@tonic-gate 87897c478bd9Sstevel@tonic-gate return (fas_unquiesce_bus(fas)); 87907c478bd9Sstevel@tonic-gate } 87917c478bd9Sstevel@tonic-gate 87927c478bd9Sstevel@tonic-gate #ifdef FAS_TEST 87937c478bd9Sstevel@tonic-gate /* 87947c478bd9Sstevel@tonic-gate * torture test functions 87957c478bd9Sstevel@tonic-gate */ 87967c478bd9Sstevel@tonic-gate static void 87977c478bd9Sstevel@tonic-gate fas_test_reset(struct fas *fas, int slot) 87987c478bd9Sstevel@tonic-gate { 87997c478bd9Sstevel@tonic-gate struct scsi_address ap; 88007c478bd9Sstevel@tonic-gate char target = slot/NLUNS_PER_TARGET; 88017c478bd9Sstevel@tonic-gate 88027c478bd9Sstevel@tonic-gate if (fas_rtest & (1 << target)) { 88037c478bd9Sstevel@tonic-gate ap.a_hba_tran = fas->f_tran; 88047c478bd9Sstevel@tonic-gate ap.a_target = target; 88057c478bd9Sstevel@tonic-gate ap.a_lun = 0; 88067c478bd9Sstevel@tonic-gate if ((fas_rtest_type == 1) && 88077c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_DATA_DONE)) { 88087c478bd9Sstevel@tonic-gate if (fas_do_scsi_reset(&ap, RESET_TARGET)) { 88097c478bd9Sstevel@tonic-gate fas_rtest = 0; 88107c478bd9Sstevel@tonic-gate } 88117c478bd9Sstevel@tonic-gate } else if ((fas_rtest_type == 2) && 88127c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_DATA_DONE)) { 88137c478bd9Sstevel@tonic-gate if (fas_do_scsi_reset(&ap, RESET_ALL)) { 88147c478bd9Sstevel@tonic-gate fas_rtest = 0; 88157c478bd9Sstevel@tonic-gate } 88167c478bd9Sstevel@tonic-gate } else { 88177c478bd9Sstevel@tonic-gate if (fas_do_scsi_reset(&ap, RESET_TARGET)) { 88187c478bd9Sstevel@tonic-gate fas_rtest = 0; 88197c478bd9Sstevel@tonic-gate } 88207c478bd9Sstevel@tonic-gate } 88217c478bd9Sstevel@tonic-gate } 88227c478bd9Sstevel@tonic-gate } 88237c478bd9Sstevel@tonic-gate 88247c478bd9Sstevel@tonic-gate static void 88257c478bd9Sstevel@tonic-gate fas_test_abort(struct fas *fas, int slot) 88267c478bd9Sstevel@tonic-gate { 88277c478bd9Sstevel@tonic-gate struct fas_cmd *sp = fas->f_current_sp; 88287c478bd9Sstevel@tonic-gate struct scsi_address ap; 88297c478bd9Sstevel@tonic-gate char target = slot/NLUNS_PER_TARGET; 88307c478bd9Sstevel@tonic-gate struct scsi_pkt *pkt = NULL; 88317c478bd9Sstevel@tonic-gate 88327c478bd9Sstevel@tonic-gate if (fas_atest & (1 << target)) { 88337c478bd9Sstevel@tonic-gate ap.a_hba_tran = fas->f_tran; 88347c478bd9Sstevel@tonic-gate ap.a_target = target; 88357c478bd9Sstevel@tonic-gate ap.a_lun = 0; 88367c478bd9Sstevel@tonic-gate 88377c478bd9Sstevel@tonic-gate if ((fas_atest_disc == 0) && sp && 88387c478bd9Sstevel@tonic-gate (sp->cmd_slot == slot) && 88397c478bd9Sstevel@tonic-gate ((sp->cmd_flags & CFLAG_CMDDISC) == 0)) { 88407c478bd9Sstevel@tonic-gate pkt = sp->cmd_pkt; 88417c478bd9Sstevel@tonic-gate } else if ((fas_atest_disc == 1) && NOTAG(target)) { 88427c478bd9Sstevel@tonic-gate sp = fas->f_active[slot]->f_slot[0]; 88437c478bd9Sstevel@tonic-gate if (sp && (sp->cmd_flags & CFLAG_CMDDISC)) { 88447c478bd9Sstevel@tonic-gate pkt = sp->cmd_pkt; 88457c478bd9Sstevel@tonic-gate } 88467c478bd9Sstevel@tonic-gate } else if ((fas_atest_disc == 1) && (sp == 0) && 88477c478bd9Sstevel@tonic-gate TAGGED(target) && 88487c478bd9Sstevel@tonic-gate (fas->f_tcmds[slot] != 0)) { 88497c478bd9Sstevel@tonic-gate int tag; 88507c478bd9Sstevel@tonic-gate /* 88517c478bd9Sstevel@tonic-gate * find the oldest tag 88527c478bd9Sstevel@tonic-gate */ 88537c478bd9Sstevel@tonic-gate for (tag = NTAGS-1; tag >= 0; tag--) { 885419397407SSherry Moore if ((sp = fas->f_active[slot]->f_slot[tag]) 885519397407SSherry Moore != 0) 88567c478bd9Sstevel@tonic-gate break; 88577c478bd9Sstevel@tonic-gate } 88587c478bd9Sstevel@tonic-gate if (sp) { 88597c478bd9Sstevel@tonic-gate pkt = sp->cmd_pkt; 88607c478bd9Sstevel@tonic-gate ASSERT(sp->cmd_slot == slot); 88617c478bd9Sstevel@tonic-gate } else { 88627c478bd9Sstevel@tonic-gate return; 88637c478bd9Sstevel@tonic-gate } 88647c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 2 && (sp == 0) && 88657c478bd9Sstevel@tonic-gate (fas->f_tcmds[slot] != 0)) { 88667c478bd9Sstevel@tonic-gate pkt = NULL; 88677c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 2 && NOTAG(target)) { 88687c478bd9Sstevel@tonic-gate pkt = NULL; 88697c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 3 && fas->f_readyf[slot]) { 88707c478bd9Sstevel@tonic-gate pkt = fas->f_readyf[slot]->cmd_pkt; 88717c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 4 && 88727c478bd9Sstevel@tonic-gate fas->f_readyf[slot] && fas->f_readyf[slot]->cmd_forw) { 88737c478bd9Sstevel@tonic-gate pkt = fas->f_readyf[slot]->cmd_forw->cmd_pkt; 88747c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 5 && fas->f_readyb[slot]) { 88757c478bd9Sstevel@tonic-gate pkt = fas->f_readyb[slot]->cmd_pkt; 88767c478bd9Sstevel@tonic-gate } else if ((fas_atest_disc == 6) && sp && 88777c478bd9Sstevel@tonic-gate (sp->cmd_slot == slot) && 88787c478bd9Sstevel@tonic-gate (fas->f_state == ACTS_DATA_DONE)) { 88797c478bd9Sstevel@tonic-gate pkt = sp->cmd_pkt; 88807c478bd9Sstevel@tonic-gate } else if (fas_atest_disc == 7) { 88817c478bd9Sstevel@tonic-gate if (fas_do_scsi_abort(&ap, NULL)) { 88827c478bd9Sstevel@tonic-gate if (fas_do_scsi_abort(&ap, NULL)) { 88837c478bd9Sstevel@tonic-gate if (fas_do_scsi_reset(&ap, 88847c478bd9Sstevel@tonic-gate RESET_TARGET)) { 88857c478bd9Sstevel@tonic-gate fas_atest = 0; 88867c478bd9Sstevel@tonic-gate } 88877c478bd9Sstevel@tonic-gate } 88887c478bd9Sstevel@tonic-gate } 88897c478bd9Sstevel@tonic-gate return; 88907c478bd9Sstevel@tonic-gate } else { 88917c478bd9Sstevel@tonic-gate return; 88927c478bd9Sstevel@tonic-gate } 88937c478bd9Sstevel@tonic-gate 88947c478bd9Sstevel@tonic-gate fas_log(fas, CE_NOTE, "aborting pkt=0x%p state=%x\n", 88957c478bd9Sstevel@tonic-gate (void *)pkt, (pkt != NULL? pkt->pkt_state : 0)); 88967c478bd9Sstevel@tonic-gate if (fas_do_scsi_abort(&ap, pkt)) { 88977c478bd9Sstevel@tonic-gate fas_atest = 0; 88987c478bd9Sstevel@tonic-gate } 88997c478bd9Sstevel@tonic-gate } 89007c478bd9Sstevel@tonic-gate } 89017c478bd9Sstevel@tonic-gate #endif /* FAS_TEST */ 89027c478bd9Sstevel@tonic-gate 89037c478bd9Sstevel@tonic-gate /* 89047c478bd9Sstevel@tonic-gate * capability interface 89057c478bd9Sstevel@tonic-gate */ 89067c478bd9Sstevel@tonic-gate static int 89077c478bd9Sstevel@tonic-gate fas_commoncap(struct scsi_address *ap, char *cap, int val, 89087c478bd9Sstevel@tonic-gate int tgtonly, int doset) 89097c478bd9Sstevel@tonic-gate { 89107c478bd9Sstevel@tonic-gate struct fas *fas = ADDR2FAS(ap); 89117c478bd9Sstevel@tonic-gate int cidx; 89127c478bd9Sstevel@tonic-gate int target = ap->a_target; 89137c478bd9Sstevel@tonic-gate ushort_t tshift = (1<<target); 89147c478bd9Sstevel@tonic-gate ushort_t ntshift = ~tshift; 89157c478bd9Sstevel@tonic-gate int rval = FALSE; 89167c478bd9Sstevel@tonic-gate 89177c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 89187c478bd9Sstevel@tonic-gate 89197c478bd9Sstevel@tonic-gate if (cap == (char *)0) { 89207c478bd9Sstevel@tonic-gate goto exit; 89217c478bd9Sstevel@tonic-gate } 89227c478bd9Sstevel@tonic-gate 89237c478bd9Sstevel@tonic-gate cidx = scsi_hba_lookup_capstr(cap); 89247c478bd9Sstevel@tonic-gate if (cidx == -1) { 89257c478bd9Sstevel@tonic-gate rval = UNDEFINED; 89267c478bd9Sstevel@tonic-gate } else if (doset) { 89277c478bd9Sstevel@tonic-gate /* 89287c478bd9Sstevel@tonic-gate * we usually don't allow setting capabilities for 89297c478bd9Sstevel@tonic-gate * other targets! 89307c478bd9Sstevel@tonic-gate */ 89317c478bd9Sstevel@tonic-gate if (!tgtonly) { 89327c478bd9Sstevel@tonic-gate goto exit; 89337c478bd9Sstevel@tonic-gate } 89347c478bd9Sstevel@tonic-gate switch (cidx) { 89357c478bd9Sstevel@tonic-gate case SCSI_CAP_DMA_MAX: 89367c478bd9Sstevel@tonic-gate case SCSI_CAP_MSG_OUT: 89377c478bd9Sstevel@tonic-gate case SCSI_CAP_PARITY: 89387c478bd9Sstevel@tonic-gate case SCSI_CAP_INITIATOR_ID: 89397c478bd9Sstevel@tonic-gate case SCSI_CAP_LINKED_CMDS: 89407c478bd9Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING: 89417c478bd9Sstevel@tonic-gate case SCSI_CAP_RESET_NOTIFICATION: 89427c478bd9Sstevel@tonic-gate /* 89437c478bd9Sstevel@tonic-gate * None of these are settable via 89447c478bd9Sstevel@tonic-gate * the capability interface. 89457c478bd9Sstevel@tonic-gate */ 89467c478bd9Sstevel@tonic-gate break; 89477c478bd9Sstevel@tonic-gate 89487c478bd9Sstevel@tonic-gate case SCSI_CAP_DISCONNECT: 89497c478bd9Sstevel@tonic-gate if (val) 89507c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[ap->a_target] |= 89517c478bd9Sstevel@tonic-gate SCSI_OPTIONS_DR; 89527c478bd9Sstevel@tonic-gate else 89537c478bd9Sstevel@tonic-gate fas->f_target_scsi_options[ap->a_target] &= 89547c478bd9Sstevel@tonic-gate ~SCSI_OPTIONS_DR; 89557c478bd9Sstevel@tonic-gate 89567c478bd9Sstevel@tonic-gate break; 89577c478bd9Sstevel@tonic-gate 89587c478bd9Sstevel@tonic-gate case SCSI_CAP_SYNCHRONOUS: 89597c478bd9Sstevel@tonic-gate if (val) { 89607c478bd9Sstevel@tonic-gate fas->f_force_async &= ~tshift; 89617c478bd9Sstevel@tonic-gate } else { 89627c478bd9Sstevel@tonic-gate fas->f_force_async |= tshift; 89637c478bd9Sstevel@tonic-gate } 89647c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, target); 89657c478bd9Sstevel@tonic-gate rval = TRUE; 89667c478bd9Sstevel@tonic-gate break; 89677c478bd9Sstevel@tonic-gate 89687c478bd9Sstevel@tonic-gate case SCSI_CAP_TAGGED_QING: 89697c478bd9Sstevel@tonic-gate { 89707c478bd9Sstevel@tonic-gate int slot = target * NLUNS_PER_TARGET | ap->a_lun; 89717c478bd9Sstevel@tonic-gate ushort_t old_notag = fas->f_notag; 89727c478bd9Sstevel@tonic-gate 89737c478bd9Sstevel@tonic-gate /* do not allow with active tgt */ 89747c478bd9Sstevel@tonic-gate if (fas->f_tcmds[slot]) { 89757c478bd9Sstevel@tonic-gate break; 89767c478bd9Sstevel@tonic-gate } 89777c478bd9Sstevel@tonic-gate 89787c478bd9Sstevel@tonic-gate slot = target * NLUNS_PER_TARGET | ap->a_lun; 89797c478bd9Sstevel@tonic-gate 89807c478bd9Sstevel@tonic-gate if (val) { 89817c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[target] & 89827c478bd9Sstevel@tonic-gate SCSI_OPTIONS_TAG) { 89837c478bd9Sstevel@tonic-gate IPRINTF1("target %d: TQ enabled\n", 89847c478bd9Sstevel@tonic-gate target); 89857c478bd9Sstevel@tonic-gate fas->f_notag &= ntshift; 89867c478bd9Sstevel@tonic-gate } else { 89877c478bd9Sstevel@tonic-gate break; 89887c478bd9Sstevel@tonic-gate } 89897c478bd9Sstevel@tonic-gate } else { 89907c478bd9Sstevel@tonic-gate IPRINTF1("target %d: TQ disabled\n", 89917c478bd9Sstevel@tonic-gate target); 89927c478bd9Sstevel@tonic-gate fas->f_notag |= tshift; 89937c478bd9Sstevel@tonic-gate } 89947c478bd9Sstevel@tonic-gate 89957c478bd9Sstevel@tonic-gate if (val && fas_alloc_active_slots(fas, slot, 89967c478bd9Sstevel@tonic-gate KM_NOSLEEP)) { 89977c478bd9Sstevel@tonic-gate fas->f_notag = old_notag; 89987c478bd9Sstevel@tonic-gate break; 89997c478bd9Sstevel@tonic-gate } 90007c478bd9Sstevel@tonic-gate 90017c478bd9Sstevel@tonic-gate fas_set_all_lun_throttles(fas, slot, MAX_THROTTLE); 90027c478bd9Sstevel@tonic-gate 90037c478bd9Sstevel@tonic-gate fas_update_props(fas, target); 90047c478bd9Sstevel@tonic-gate rval = TRUE; 90057c478bd9Sstevel@tonic-gate break; 90067c478bd9Sstevel@tonic-gate } 90077c478bd9Sstevel@tonic-gate 90087c478bd9Sstevel@tonic-gate case SCSI_CAP_WIDE_XFER: 90097c478bd9Sstevel@tonic-gate if (val) { 90107c478bd9Sstevel@tonic-gate if (fas->f_target_scsi_options[target] & 90117c478bd9Sstevel@tonic-gate SCSI_OPTIONS_WIDE) { 90127c478bd9Sstevel@tonic-gate fas->f_nowide &= ntshift; 90137c478bd9Sstevel@tonic-gate fas->f_force_narrow &= ~tshift; 90147c478bd9Sstevel@tonic-gate } else { 90157c478bd9Sstevel@tonic-gate break; 90167c478bd9Sstevel@tonic-gate } 90177c478bd9Sstevel@tonic-gate } else { 90187c478bd9Sstevel@tonic-gate fas->f_force_narrow |= tshift; 90197c478bd9Sstevel@tonic-gate } 90207c478bd9Sstevel@tonic-gate fas_force_renegotiation(fas, target); 90217c478bd9Sstevel@tonic-gate rval = TRUE; 90227c478bd9Sstevel@tonic-gate break; 90237c478bd9Sstevel@tonic-gate 90247c478bd9Sstevel@tonic-gate case SCSI_CAP_ARQ: 90257c478bd9Sstevel@tonic-gate if (val) { 90267c478bd9Sstevel@tonic-gate if (fas_create_arq_pkt(fas, ap)) { 90277c478bd9Sstevel@tonic-gate break; 90287c478bd9Sstevel@tonic-gate } 90297c478bd9Sstevel@tonic-gate } else { 90307c478bd9Sstevel@tonic-gate if (fas_delete_arq_pkt(fas, ap)) { 90317c478bd9Sstevel@tonic-gate break; 90327c478bd9Sstevel@tonic-gate } 90337c478bd9Sstevel@tonic-gate } 90347c478bd9Sstevel@tonic-gate rval = TRUE; 90357c478bd9Sstevel@tonic-gate break; 90367c478bd9Sstevel@tonic-gate 90377c478bd9Sstevel@tonic-gate case SCSI_CAP_QFULL_RETRIES: 90387c478bd9Sstevel@tonic-gate fas->f_qfull_retries[target] = (uchar_t)val; 90397c478bd9Sstevel@tonic-gate rval = TRUE; 90407c478bd9Sstevel@tonic-gate break; 90417c478bd9Sstevel@tonic-gate 90427c478bd9Sstevel@tonic-gate case SCSI_CAP_QFULL_RETRY_INTERVAL: 90437c478bd9Sstevel@tonic-gate fas->f_qfull_retry_interval[target] = 90447c478bd9Sstevel@tonic-gate drv_usectohz(val * 1000); 90457c478bd9Sstevel@tonic-gate rval = TRUE; 90467c478bd9Sstevel@tonic-gate break; 90477c478bd9Sstevel@tonic-gate 90487c478bd9Sstevel@tonic-gate default: 90497c478bd9Sstevel@tonic-gate rval = UNDEFINED; 90507c478bd9Sstevel@tonic-gate break; 90517c478bd9Sstevel@tonic-gate } 90527c478bd9Sstevel@tonic-gate 90537c478bd9Sstevel@tonic-gate } else if (doset == 0) { 90547c478bd9Sstevel@tonic-gate int slot = target * NLUNS_PER_TARGET | ap->a_lun; 90557c478bd9Sstevel@tonic-gate 90567c478bd9Sstevel@tonic-gate switch (cidx) { 90577c478bd9Sstevel@tonic-gate case SCSI_CAP_DMA_MAX: 90587c478bd9Sstevel@tonic-gate /* very high limit because of multiple dma windows */ 90597c478bd9Sstevel@tonic-gate rval = 1<<30; 90607c478bd9Sstevel@tonic-gate break; 90617c478bd9Sstevel@tonic-gate case SCSI_CAP_MSG_OUT: 90627c478bd9Sstevel@tonic-gate rval = TRUE; 90637c478bd9Sstevel@tonic-gate break; 90647c478bd9Sstevel@tonic-gate case SCSI_CAP_DISCONNECT: 90657c478bd9Sstevel@tonic-gate if (tgtonly && 90667c478bd9Sstevel@tonic-gate (fas->f_target_scsi_options[target] & 90677c478bd9Sstevel@tonic-gate SCSI_OPTIONS_DR)) { 90687c478bd9Sstevel@tonic-gate rval = TRUE; 90697c478bd9Sstevel@tonic-gate } 90707c478bd9Sstevel@tonic-gate break; 90717c478bd9Sstevel@tonic-gate case SCSI_CAP_SYNCHRONOUS: 90727c478bd9Sstevel@tonic-gate if (tgtonly && fas->f_offset[target]) { 90737c478bd9Sstevel@tonic-gate rval = TRUE; 90747c478bd9Sstevel@tonic-gate } 90757c478bd9Sstevel@tonic-gate break; 90767c478bd9Sstevel@tonic-gate case SCSI_CAP_PARITY: 90777c478bd9Sstevel@tonic-gate rval = TRUE; 90787c478bd9Sstevel@tonic-gate break; 90797c478bd9Sstevel@tonic-gate case SCSI_CAP_INITIATOR_ID: 90807c478bd9Sstevel@tonic-gate rval = MY_ID(fas); 90817c478bd9Sstevel@tonic-gate break; 90827c478bd9Sstevel@tonic-gate case SCSI_CAP_TAGGED_QING: 90837c478bd9Sstevel@tonic-gate if (tgtonly && ((fas->f_notag & tshift) == 0)) { 90847c478bd9Sstevel@tonic-gate rval = TRUE; 90857c478bd9Sstevel@tonic-gate } 90867c478bd9Sstevel@tonic-gate break; 90877c478bd9Sstevel@tonic-gate case SCSI_CAP_WIDE_XFER: 90887c478bd9Sstevel@tonic-gate if ((tgtonly && (fas->f_nowide & tshift) == 0)) { 90897c478bd9Sstevel@tonic-gate rval = TRUE; 90907c478bd9Sstevel@tonic-gate } 90917c478bd9Sstevel@tonic-gate break; 90927c478bd9Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING: 90937c478bd9Sstevel@tonic-gate rval = TRUE; 90947c478bd9Sstevel@tonic-gate break; 90957c478bd9Sstevel@tonic-gate case SCSI_CAP_ARQ: 90967c478bd9Sstevel@tonic-gate if (tgtonly && fas->f_arq_pkt[slot]) { 90977c478bd9Sstevel@tonic-gate rval = TRUE; 90987c478bd9Sstevel@tonic-gate } 90997c478bd9Sstevel@tonic-gate break; 91007c478bd9Sstevel@tonic-gate case SCSI_CAP_LINKED_CMDS: 91017c478bd9Sstevel@tonic-gate break; 91027c478bd9Sstevel@tonic-gate case SCSI_CAP_RESET_NOTIFICATION: 91037c478bd9Sstevel@tonic-gate rval = TRUE; 91047c478bd9Sstevel@tonic-gate break; 91057c478bd9Sstevel@tonic-gate case SCSI_CAP_QFULL_RETRIES: 91067c478bd9Sstevel@tonic-gate rval = fas->f_qfull_retries[target]; 91077c478bd9Sstevel@tonic-gate break; 91087c478bd9Sstevel@tonic-gate case SCSI_CAP_QFULL_RETRY_INTERVAL: 91097c478bd9Sstevel@tonic-gate rval = drv_hztousec( 91107c478bd9Sstevel@tonic-gate fas->f_qfull_retry_interval[target]) / 91117c478bd9Sstevel@tonic-gate 1000; 91127c478bd9Sstevel@tonic-gate break; 91137c478bd9Sstevel@tonic-gate 91147c478bd9Sstevel@tonic-gate default: 91157c478bd9Sstevel@tonic-gate rval = UNDEFINED; 91167c478bd9Sstevel@tonic-gate break; 91177c478bd9Sstevel@tonic-gate } 91187c478bd9Sstevel@tonic-gate } 91197c478bd9Sstevel@tonic-gate exit: 91207c478bd9Sstevel@tonic-gate if (val && tgtonly) { 91217c478bd9Sstevel@tonic-gate fas_update_props(fas, target); 91227c478bd9Sstevel@tonic-gate } 91237c478bd9Sstevel@tonic-gate fas_check_waitQ_and_mutex_exit(fas); 91247c478bd9Sstevel@tonic-gate 91257c478bd9Sstevel@tonic-gate if (doset) { 91267c478bd9Sstevel@tonic-gate IPRINTF6( 91277c478bd9Sstevel@tonic-gate "fas_commoncap:tgt=%x,cap=%s,tgtonly=%x,doset=%x,val=%x,rval=%x\n", 91287c478bd9Sstevel@tonic-gate target, cap, tgtonly, doset, val, rval); 91297c478bd9Sstevel@tonic-gate } 91307c478bd9Sstevel@tonic-gate return (rval); 91317c478bd9Sstevel@tonic-gate } 91327c478bd9Sstevel@tonic-gate 91337c478bd9Sstevel@tonic-gate /* 91347c478bd9Sstevel@tonic-gate * property management 91357c478bd9Sstevel@tonic-gate * fas_update_props: 91367c478bd9Sstevel@tonic-gate * create/update sync/wide/TQ/scsi-options properties for this target 91377c478bd9Sstevel@tonic-gate */ 91387c478bd9Sstevel@tonic-gate static void 91397c478bd9Sstevel@tonic-gate fas_update_props(struct fas *fas, int tgt) 91407c478bd9Sstevel@tonic-gate { 91417c478bd9Sstevel@tonic-gate char property[32]; 91427c478bd9Sstevel@tonic-gate uint_t xfer_speed = 0; 91437c478bd9Sstevel@tonic-gate uint_t xfer_rate = 0; 91447c478bd9Sstevel@tonic-gate int wide_enabled, tq_enabled; 91457c478bd9Sstevel@tonic-gate uint_t regval = fas->f_sync_period[tgt]; 91467c478bd9Sstevel@tonic-gate int offset = fas->f_offset[tgt]; 91477c478bd9Sstevel@tonic-gate 91487c478bd9Sstevel@tonic-gate wide_enabled = ((fas->f_nowide & (1<<tgt)) == 0); 91497c478bd9Sstevel@tonic-gate if (offset && regval) { 91507c478bd9Sstevel@tonic-gate xfer_speed = 91517c478bd9Sstevel@tonic-gate FAS_SYNC_KBPS((regval * fas->f_clock_cycle) / 1000); 91527c478bd9Sstevel@tonic-gate xfer_rate = ((wide_enabled)? 2 : 1) * xfer_speed; 91537c478bd9Sstevel@tonic-gate } 91547c478bd9Sstevel@tonic-gate (void) sprintf(property, "target%x-sync-speed", tgt); 91557c478bd9Sstevel@tonic-gate fas_update_this_prop(fas, property, xfer_rate); 91567c478bd9Sstevel@tonic-gate 91577c478bd9Sstevel@tonic-gate (void) sprintf(property, "target%x-wide", tgt); 91587c478bd9Sstevel@tonic-gate fas_update_this_prop(fas, property, wide_enabled); 91597c478bd9Sstevel@tonic-gate 91607c478bd9Sstevel@tonic-gate (void) sprintf(property, "target%x-TQ", tgt); 91617c478bd9Sstevel@tonic-gate tq_enabled = ((fas->f_notag & (1<<tgt))? 0 : 1); 91627c478bd9Sstevel@tonic-gate fas_update_this_prop(fas, property, tq_enabled); 91637c478bd9Sstevel@tonic-gate 91647c478bd9Sstevel@tonic-gate } 91657c478bd9Sstevel@tonic-gate 91667c478bd9Sstevel@tonic-gate static void 91677c478bd9Sstevel@tonic-gate fas_update_this_prop(struct fas *fas, char *property, int value) 91687c478bd9Sstevel@tonic-gate { 91697c478bd9Sstevel@tonic-gate dev_info_t *dip = fas->f_dev; 91707c478bd9Sstevel@tonic-gate 91717c478bd9Sstevel@tonic-gate IPRINTF2("update prop: %s value=%x\n", property, value); 91727c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(FAS_MUTEX(fas))); 91737c478bd9Sstevel@tonic-gate /* 91747c478bd9Sstevel@tonic-gate * We cannot hold any mutex at this point because the call to 91757c478bd9Sstevel@tonic-gate * ddi_prop_update_int() may block. 91767c478bd9Sstevel@tonic-gate */ 91777c478bd9Sstevel@tonic-gate mutex_exit(FAS_MUTEX(fas)); 91787c478bd9Sstevel@tonic-gate if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, 91797c478bd9Sstevel@tonic-gate property, value) != DDI_PROP_SUCCESS) { 91807c478bd9Sstevel@tonic-gate IPRINTF1("cannot modify/create %s property\n", property); 91817c478bd9Sstevel@tonic-gate } 91827c478bd9Sstevel@tonic-gate mutex_enter(FAS_MUTEX(fas)); 91837c478bd9Sstevel@tonic-gate } 91847c478bd9Sstevel@tonic-gate 91857c478bd9Sstevel@tonic-gate /* 91867c478bd9Sstevel@tonic-gate * allocate active slots array, size is dependent on whether tagQ enabled 91877c478bd9Sstevel@tonic-gate */ 91887c478bd9Sstevel@tonic-gate static int 91897c478bd9Sstevel@tonic-gate fas_alloc_active_slots(struct fas *fas, int slot, int flag) 91907c478bd9Sstevel@tonic-gate { 91917c478bd9Sstevel@tonic-gate int target = slot / NLUNS_PER_TARGET; 91927c478bd9Sstevel@tonic-gate struct f_slots *old_active = fas->f_active[slot]; 91937c478bd9Sstevel@tonic-gate struct f_slots *new_active; 91947c478bd9Sstevel@tonic-gate ushort_t size; 91957c478bd9Sstevel@tonic-gate int rval = -1; 91967c478bd9Sstevel@tonic-gate 91977c478bd9Sstevel@tonic-gate if (fas->f_tcmds[slot]) { 91987c478bd9Sstevel@tonic-gate IPRINTF("cannot change size of active slots array\n"); 91997c478bd9Sstevel@tonic-gate return (rval); 92007c478bd9Sstevel@tonic-gate } 92017c478bd9Sstevel@tonic-gate 92027c478bd9Sstevel@tonic-gate size = ((NOTAG(target)) ? FAS_F_SLOT_SIZE : FAS_F_SLOTS_SIZE_TQ); 92037c478bd9Sstevel@tonic-gate EPRINTF4( 92047c478bd9Sstevel@tonic-gate "fas_alloc_active_slots: target=%x size=%x, old=0x%p, oldsize=%x\n", 92057c478bd9Sstevel@tonic-gate target, size, (void *)old_active, 92067c478bd9Sstevel@tonic-gate ((old_active == NULL) ? -1 : old_active->f_size)); 92077c478bd9Sstevel@tonic-gate 92087c478bd9Sstevel@tonic-gate new_active = kmem_zalloc(size, flag); 92097c478bd9Sstevel@tonic-gate if (new_active == NULL) { 92107c478bd9Sstevel@tonic-gate IPRINTF("new active alloc failed\n"); 92117c478bd9Sstevel@tonic-gate } else { 92127c478bd9Sstevel@tonic-gate fas->f_active[slot] = new_active; 92137c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_n_slots = (NOTAG(target) ? 1 : NTAGS); 92147c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_size = size; 92157c478bd9Sstevel@tonic-gate /* 92167c478bd9Sstevel@tonic-gate * reserve tag 0 for non-tagged cmds to tagged targets 92177c478bd9Sstevel@tonic-gate */ 92187c478bd9Sstevel@tonic-gate if (TAGGED(target)) { 92197c478bd9Sstevel@tonic-gate fas->f_active[slot]->f_tags = 1; 92207c478bd9Sstevel@tonic-gate } 92217c478bd9Sstevel@tonic-gate if (old_active) { 92227c478bd9Sstevel@tonic-gate kmem_free((caddr_t)old_active, old_active->f_size); 92237c478bd9Sstevel@tonic-gate } 92247c478bd9Sstevel@tonic-gate rval = 0; 92257c478bd9Sstevel@tonic-gate } 92267c478bd9Sstevel@tonic-gate return (rval); 92277c478bd9Sstevel@tonic-gate } 92287c478bd9Sstevel@tonic-gate 92297c478bd9Sstevel@tonic-gate /* 92307c478bd9Sstevel@tonic-gate * Error logging, printing, and debug print routines 92317c478bd9Sstevel@tonic-gate */ 92327c478bd9Sstevel@tonic-gate static char *fas_label = "fas"; 92337c478bd9Sstevel@tonic-gate 92347c478bd9Sstevel@tonic-gate /*PRINTFLIKE3*/ 92357c478bd9Sstevel@tonic-gate static void 92367c478bd9Sstevel@tonic-gate fas_log(struct fas *fas, int level, const char *fmt, ...) 92377c478bd9Sstevel@tonic-gate { 92387c478bd9Sstevel@tonic-gate dev_info_t *dev; 92397c478bd9Sstevel@tonic-gate va_list ap; 92407c478bd9Sstevel@tonic-gate 92417c478bd9Sstevel@tonic-gate if (fas) { 92427c478bd9Sstevel@tonic-gate dev = fas->f_dev; 92437c478bd9Sstevel@tonic-gate } else { 92447c478bd9Sstevel@tonic-gate dev = 0; 92457c478bd9Sstevel@tonic-gate } 92467c478bd9Sstevel@tonic-gate 92477c478bd9Sstevel@tonic-gate mutex_enter(&fas_log_mutex); 92487c478bd9Sstevel@tonic-gate 92497c478bd9Sstevel@tonic-gate va_start(ap, fmt); 92507c478bd9Sstevel@tonic-gate (void) vsprintf(fas_log_buf, fmt, ap); 92517c478bd9Sstevel@tonic-gate va_end(ap); 92527c478bd9Sstevel@tonic-gate 92537c478bd9Sstevel@tonic-gate if (level == CE_CONT) { 92547c478bd9Sstevel@tonic-gate scsi_log(dev, fas_label, level, "%s\n", fas_log_buf); 92557c478bd9Sstevel@tonic-gate } else { 92567c478bd9Sstevel@tonic-gate scsi_log(dev, fas_label, level, "%s", fas_log_buf); 92577c478bd9Sstevel@tonic-gate } 92587c478bd9Sstevel@tonic-gate 92597c478bd9Sstevel@tonic-gate mutex_exit(&fas_log_mutex); 92607c478bd9Sstevel@tonic-gate } 92617c478bd9Sstevel@tonic-gate 92627c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 92637c478bd9Sstevel@tonic-gate static void 92647c478bd9Sstevel@tonic-gate fas_printf(struct fas *fas, const char *fmt, ...) 92657c478bd9Sstevel@tonic-gate { 92667c478bd9Sstevel@tonic-gate dev_info_t *dev = 0; 92677c478bd9Sstevel@tonic-gate va_list ap; 92687c478bd9Sstevel@tonic-gate int level = CE_CONT; 92697c478bd9Sstevel@tonic-gate 92707c478bd9Sstevel@tonic-gate mutex_enter(&fas_log_mutex); 92717c478bd9Sstevel@tonic-gate 92727c478bd9Sstevel@tonic-gate va_start(ap, fmt); 92737c478bd9Sstevel@tonic-gate (void) vsprintf(fas_log_buf, fmt, ap); 92747c478bd9Sstevel@tonic-gate va_end(ap); 92757c478bd9Sstevel@tonic-gate 92767c478bd9Sstevel@tonic-gate if (fas) { 92777c478bd9Sstevel@tonic-gate dev = fas->f_dev; 92787c478bd9Sstevel@tonic-gate level = CE_NOTE; 92797c478bd9Sstevel@tonic-gate scsi_log(dev, fas_label, level, "%s", fas_log_buf); 92807c478bd9Sstevel@tonic-gate } else { 92817c478bd9Sstevel@tonic-gate scsi_log(dev, fas_label, level, "%s\n", fas_log_buf); 92827c478bd9Sstevel@tonic-gate } 92837c478bd9Sstevel@tonic-gate 92847c478bd9Sstevel@tonic-gate mutex_exit(&fas_log_mutex); 92857c478bd9Sstevel@tonic-gate } 92867c478bd9Sstevel@tonic-gate 92877c478bd9Sstevel@tonic-gate #ifdef FASDEBUG 92887c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/ 92897c478bd9Sstevel@tonic-gate void 92907c478bd9Sstevel@tonic-gate fas_dprintf(struct fas *fas, const char *fmt, ...) 92917c478bd9Sstevel@tonic-gate { 92927c478bd9Sstevel@tonic-gate dev_info_t *dev = 0; 92937c478bd9Sstevel@tonic-gate va_list ap; 92947c478bd9Sstevel@tonic-gate 92957c478bd9Sstevel@tonic-gate if (fas) { 92967c478bd9Sstevel@tonic-gate dev = fas->f_dev; 92977c478bd9Sstevel@tonic-gate } 92987c478bd9Sstevel@tonic-gate 92997c478bd9Sstevel@tonic-gate mutex_enter(&fas_log_mutex); 93007c478bd9Sstevel@tonic-gate 93017c478bd9Sstevel@tonic-gate va_start(ap, fmt); 93027c478bd9Sstevel@tonic-gate (void) vsprintf(fas_log_buf, fmt, ap); 93037c478bd9Sstevel@tonic-gate va_end(ap); 93047c478bd9Sstevel@tonic-gate 93057c478bd9Sstevel@tonic-gate scsi_log(dev, fas_label, SCSI_DEBUG, "%s", fas_log_buf); 93067c478bd9Sstevel@tonic-gate 93077c478bd9Sstevel@tonic-gate mutex_exit(&fas_log_mutex); 93087c478bd9Sstevel@tonic-gate } 93097c478bd9Sstevel@tonic-gate #endif 93107c478bd9Sstevel@tonic-gate 93117c478bd9Sstevel@tonic-gate 93127c478bd9Sstevel@tonic-gate static void 93137c478bd9Sstevel@tonic-gate fas_printstate(struct fas *fas, char *msg) 93147c478bd9Sstevel@tonic-gate { 93157c478bd9Sstevel@tonic-gate volatile struct fasreg *fasreg = fas->f_reg; 93167c478bd9Sstevel@tonic-gate volatile struct dma *dmar = fas->f_dma; 93177c478bd9Sstevel@tonic-gate uint_t csr = fas_dma_reg_read(fas, &dmar->dma_csr); 93187c478bd9Sstevel@tonic-gate uint_t count = fas_dma_reg_read(fas, &dmar->dma_count); 93197c478bd9Sstevel@tonic-gate uint_t addr = fas_dma_reg_read(fas, &dmar->dma_addr); 93207c478bd9Sstevel@tonic-gate uint_t test = fas_dma_reg_read(fas, &dmar->dma_test); 93217c478bd9Sstevel@tonic-gate uint_t fas_cnt; 93227c478bd9Sstevel@tonic-gate 93237c478bd9Sstevel@tonic-gate fas_log(fas, CE_WARN, "%s: current fas state:", msg); 93247c478bd9Sstevel@tonic-gate fas_printf(NULL, "Latched stat=0x%b intr=0x%b", 93257c478bd9Sstevel@tonic-gate fas->f_stat, FAS_STAT_BITS, fas->f_intr, FAS_INT_BITS); 93267c478bd9Sstevel@tonic-gate fas_printf(NULL, "last msgout: %s, last msgin: %s", 93277c478bd9Sstevel@tonic-gate scsi_mname(fas->f_last_msgout), scsi_mname(fas->f_last_msgin)); 93287c478bd9Sstevel@tonic-gate fas_printf(NULL, "DMA csr=0x%b", csr, dma_bits); 93297c478bd9Sstevel@tonic-gate fas_printf(NULL, 93307c478bd9Sstevel@tonic-gate "addr=%x dmacnt=%x test=%x last=%x last_cnt=%x", 93317c478bd9Sstevel@tonic-gate addr, count, test, fas->f_lastdma, fas->f_lastcount); 93327c478bd9Sstevel@tonic-gate 93337c478bd9Sstevel@tonic-gate GET_FAS_COUNT(fasreg, fas_cnt); 93347c478bd9Sstevel@tonic-gate fas_printf(NULL, "fas state:"); 93357c478bd9Sstevel@tonic-gate fas_printf(NULL, "\tcount(32)=%x cmd=%x stat=%x stat2=%x intr=%x", 93367c478bd9Sstevel@tonic-gate fas_cnt, fasreg->fas_cmd, fasreg->fas_stat, fasreg->fas_stat2, 93377c478bd9Sstevel@tonic-gate fasreg->fas_intr); 93387c478bd9Sstevel@tonic-gate fas_printf(NULL, 93397c478bd9Sstevel@tonic-gate "\tstep=%x fifoflag=%x conf=%x test=%x conf2=%x conf3=%x", 93407c478bd9Sstevel@tonic-gate fasreg->fas_step, fasreg->fas_fifo_flag, fasreg->fas_conf, 93417c478bd9Sstevel@tonic-gate fasreg->fas_test, fasreg->fas_conf2, fasreg->fas_conf3); 93427c478bd9Sstevel@tonic-gate 93437c478bd9Sstevel@tonic-gate if (fas->f_current_sp) { 93447c478bd9Sstevel@tonic-gate fas_dump_cmd(fas, fas->f_current_sp); 93457c478bd9Sstevel@tonic-gate } 93467c478bd9Sstevel@tonic-gate } 93477c478bd9Sstevel@tonic-gate 93487c478bd9Sstevel@tonic-gate /* 93497c478bd9Sstevel@tonic-gate * dump all we know about a cmd 93507c478bd9Sstevel@tonic-gate */ 93517c478bd9Sstevel@tonic-gate static void 93527c478bd9Sstevel@tonic-gate fas_dump_cmd(struct fas *fas, struct fas_cmd *sp) 93537c478bd9Sstevel@tonic-gate { 93547c478bd9Sstevel@tonic-gate int i; 93557c478bd9Sstevel@tonic-gate uchar_t *cp = (uchar_t *)sp->cmd_pkt->pkt_cdbp; 93567c478bd9Sstevel@tonic-gate auto char buf[128]; 93577c478bd9Sstevel@tonic-gate 93587c478bd9Sstevel@tonic-gate buf[0] = '\0'; 93597c478bd9Sstevel@tonic-gate fas_printf(NULL, "Cmd dump for Target %d Lun %d:", 93607c478bd9Sstevel@tonic-gate Tgt(sp), Lun(sp)); 93617c478bd9Sstevel@tonic-gate (void) sprintf(&buf[0], " cdb=["); 93627c478bd9Sstevel@tonic-gate for (i = 0; i < (int)sp->cmd_actual_cdblen; i++) { 93637c478bd9Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], " 0x%x", *cp++); 93647c478bd9Sstevel@tonic-gate } 93657c478bd9Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], " ]"); 93667c478bd9Sstevel@tonic-gate fas_printf(NULL, buf); 93677c478bd9Sstevel@tonic-gate fas_printf(NULL, "State=%s Last State=%s", 93687c478bd9Sstevel@tonic-gate fas_state_name(fas->f_state), fas_state_name(fas->f_laststate)); 93697c478bd9Sstevel@tonic-gate fas_printf(NULL, 93707c478bd9Sstevel@tonic-gate "pkt_state=0x%b pkt_flags=0x%x pkt_statistics=0x%x", 93717c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_state, scsi_state_bits, sp->cmd_pkt_flags, 93727c478bd9Sstevel@tonic-gate sp->cmd_pkt->pkt_statistics); 93737c478bd9Sstevel@tonic-gate if (sp->cmd_pkt->pkt_state & STATE_GOT_STATUS) { 93747c478bd9Sstevel@tonic-gate fas_printf(NULL, "Status=0x%x\n", sp->cmd_pkt->pkt_scbp[0]); 93757c478bd9Sstevel@tonic-gate } 93767c478bd9Sstevel@tonic-gate } 93777c478bd9Sstevel@tonic-gate 93787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 93797c478bd9Sstevel@tonic-gate static void 93807c478bd9Sstevel@tonic-gate fas_short_dump_cmd(struct fas *fas, struct fas_cmd *sp) 93817c478bd9Sstevel@tonic-gate { 93827c478bd9Sstevel@tonic-gate int i; 93837c478bd9Sstevel@tonic-gate uchar_t *cp = (uchar_t *)sp->cmd_pkt->pkt_cdbp; 93847c478bd9Sstevel@tonic-gate auto char buf[128]; 93857c478bd9Sstevel@tonic-gate 93867c478bd9Sstevel@tonic-gate buf[0] = '\0'; 93877c478bd9Sstevel@tonic-gate (void) sprintf(&buf[0], "?%d.%d: cdb=[", Tgt(sp), Lun(sp)); 93887c478bd9Sstevel@tonic-gate for (i = 0; i < (int)sp->cmd_actual_cdblen; i++) { 93897c478bd9Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], " 0x%x", *cp++); 93907c478bd9Sstevel@tonic-gate } 93917c478bd9Sstevel@tonic-gate (void) sprintf(&buf[strlen(buf)], " ]"); 93927c478bd9Sstevel@tonic-gate fas_printf(NULL, buf); 93937c478bd9Sstevel@tonic-gate } 93947c478bd9Sstevel@tonic-gate 93957c478bd9Sstevel@tonic-gate /* 93967c478bd9Sstevel@tonic-gate * state decoding for error messages 93977c478bd9Sstevel@tonic-gate */ 93987c478bd9Sstevel@tonic-gate static char * 93997c478bd9Sstevel@tonic-gate fas_state_name(ushort_t state) 94007c478bd9Sstevel@tonic-gate { 94017c478bd9Sstevel@tonic-gate if (state == STATE_FREE) { 94027c478bd9Sstevel@tonic-gate return ("FREE"); 94037c478bd9Sstevel@tonic-gate } else if (state & STATE_SELECTING) { 94047c478bd9Sstevel@tonic-gate if (state == STATE_SELECT_NORMAL) 94057c478bd9Sstevel@tonic-gate return ("SELECT"); 94067c478bd9Sstevel@tonic-gate else if (state == STATE_SELECT_N_STOP) 94077c478bd9Sstevel@tonic-gate return ("SEL&STOP"); 94087c478bd9Sstevel@tonic-gate else if (state == STATE_SELECT_N_SENDMSG) 94097c478bd9Sstevel@tonic-gate return ("SELECT_SNDMSG"); 94107c478bd9Sstevel@tonic-gate else 94117c478bd9Sstevel@tonic-gate return ("SEL_NO_ATN"); 94127c478bd9Sstevel@tonic-gate } else { 94137c478bd9Sstevel@tonic-gate static struct { 94147c478bd9Sstevel@tonic-gate char *sname; 94157c478bd9Sstevel@tonic-gate char state; 94167c478bd9Sstevel@tonic-gate } names[] = { 94177c478bd9Sstevel@tonic-gate "CMD_START", ACTS_CMD_START, 94187c478bd9Sstevel@tonic-gate "CMD_DONE", ACTS_CMD_DONE, 94197c478bd9Sstevel@tonic-gate "MSG_OUT", ACTS_MSG_OUT, 94207c478bd9Sstevel@tonic-gate "MSG_OUT_DONE", ACTS_MSG_OUT_DONE, 94217c478bd9Sstevel@tonic-gate "MSG_IN", ACTS_MSG_IN, 94227c478bd9Sstevel@tonic-gate "MSG_IN_MORE", ACTS_MSG_IN_MORE, 94237c478bd9Sstevel@tonic-gate "MSG_IN_DONE", ACTS_MSG_IN_DONE, 94247c478bd9Sstevel@tonic-gate "CLEARING", ACTS_CLEARING, 94257c478bd9Sstevel@tonic-gate "DATA", ACTS_DATA, 94267c478bd9Sstevel@tonic-gate "DATA_DONE", ACTS_DATA_DONE, 94277c478bd9Sstevel@tonic-gate "CMD_CMPLT", ACTS_C_CMPLT, 94287c478bd9Sstevel@tonic-gate "UNKNOWN", ACTS_UNKNOWN, 94297c478bd9Sstevel@tonic-gate "RESEL", ACTS_RESEL, 94307c478bd9Sstevel@tonic-gate "ENDVEC", ACTS_ENDVEC, 94317c478bd9Sstevel@tonic-gate "RESET", ACTS_RESET, 94327c478bd9Sstevel@tonic-gate "ABORTING", ACTS_ABORTING, 94337c478bd9Sstevel@tonic-gate "FROZEN", ACTS_FROZEN, 94347c478bd9Sstevel@tonic-gate 0 94357c478bd9Sstevel@tonic-gate }; 94367c478bd9Sstevel@tonic-gate int i; 94377c478bd9Sstevel@tonic-gate for (i = 0; names[i].sname; i++) { 94387c478bd9Sstevel@tonic-gate if (names[i].state == state) 94397c478bd9Sstevel@tonic-gate return (names[i].sname); 94407c478bd9Sstevel@tonic-gate } 94417c478bd9Sstevel@tonic-gate } 94427c478bd9Sstevel@tonic-gate return ("<BAD>"); 94437c478bd9Sstevel@tonic-gate } 9444