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 5f5488aa8Sbharding * Common Development and Distribution License (the "License"). 6f5488aa8Sbharding * 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 /* 22*8c067cfdSAlan Perry * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * SBP2 module 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 307c478bd9Sstevel@tonic-gate #include <sys/errno.h> 317c478bd9Sstevel@tonic-gate #include <sys/cred.h> 327c478bd9Sstevel@tonic-gate #include <sys/conf.h> 33*8c067cfdSAlan Perry #include <sys/disp.h> 347c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 357c478bd9Sstevel@tonic-gate #include <sys/stat.h> 367c478bd9Sstevel@tonic-gate #include <sys/stream.h> 377c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 387c478bd9Sstevel@tonic-gate #include <sys/strsun.h> 397c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 407c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #include <sys/sbp2/impl.h> 437c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1212.h> 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* target routines */ 467c478bd9Sstevel@tonic-gate static void sbp2_tgt_init_sobj(sbp2_tgt_t *); 477c478bd9Sstevel@tonic-gate static void sbp2_tgt_fini_sobj(sbp2_tgt_t *); 487c478bd9Sstevel@tonic-gate static int sbp2_tgt_init_params(sbp2_tgt_t *); 497c478bd9Sstevel@tonic-gate static int sbp2_tgt_init_luns(sbp2_tgt_t *, int); 507c478bd9Sstevel@tonic-gate static void sbp2_tgt_fini_luns(sbp2_tgt_t *); 517c478bd9Sstevel@tonic-gate static int sbp2_tgt_init_bus(sbp2_tgt_t *); 527c478bd9Sstevel@tonic-gate static void sbp2_tgt_fini_bus(sbp2_tgt_t *); 537c478bd9Sstevel@tonic-gate static int sbp2_tgt_mgt_request(sbp2_tgt_t *, int *); 547c478bd9Sstevel@tonic-gate static int sbp2_tgt_task_mgt_request(sbp2_tgt_t *, uint16_t, int, uint64_t, 557c478bd9Sstevel@tonic-gate int *); 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* lun routines */ 587c478bd9Sstevel@tonic-gate static void sbp2_lun_logout_orb(sbp2_lun_t *, sbp2_tgt_t *, int *); 597c478bd9Sstevel@tonic-gate static boolean_t sbp2_lun_accepting_tasks(sbp2_lun_t *); 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* session routines */ 627c478bd9Sstevel@tonic-gate static int sbp2_ses_init(sbp2_ses_t **, sbp2_lun_t *, 637c478bd9Sstevel@tonic-gate void (*)(void *, sbp2_task_t *), void *); 647c478bd9Sstevel@tonic-gate static void sbp2_ses_fini(sbp2_ses_t *); 657c478bd9Sstevel@tonic-gate static sbp2_task_t *sbp2_ses_orbp2task(sbp2_ses_t *, uint64_t); 667c478bd9Sstevel@tonic-gate static void sbp2_ses_append_task(sbp2_ses_t *, sbp2_task_t *); 677c478bd9Sstevel@tonic-gate static void sbp2_ses_reset_pending_tasks(sbp2_ses_t *, uint16_t); 687c478bd9Sstevel@tonic-gate static int sbp2_ses_reconnect_orb(sbp2_ses_t *, int *); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* orb alloc routines */ 717c478bd9Sstevel@tonic-gate static sbp2_bus_buf_t *sbp2_orb_freelist_get(sbp2_lun_t *, sbp2_task_t *, int); 727c478bd9Sstevel@tonic-gate static int sbp2_orb_freelist_put(sbp2_lun_t *, sbp2_bus_buf_t *); 737c478bd9Sstevel@tonic-gate static void sbp2_orb_freelist_destroy(sbp2_lun_t *); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* fetch agent routines */ 767c478bd9Sstevel@tonic-gate static int sbp2_agent_init(sbp2_agent_t *, uint64_t, sbp2_tgt_t *tp); 777c478bd9Sstevel@tonic-gate static void sbp2_agent_fini(sbp2_agent_t *); 787c478bd9Sstevel@tonic-gate static void sbp2_agent_acquire_locked(sbp2_agent_t *); 797c478bd9Sstevel@tonic-gate static void sbp2_agent_release_locked(sbp2_agent_t *); 807c478bd9Sstevel@tonic-gate static void sbp2_agent_acquire(sbp2_agent_t *); 817c478bd9Sstevel@tonic-gate static void sbp2_agent_release(sbp2_agent_t *); 827c478bd9Sstevel@tonic-gate static int sbp2_agent_keepalive(sbp2_agent_t *, int *); 837c478bd9Sstevel@tonic-gate static int sbp2_agent_doorbell(sbp2_agent_t *, int *); 847c478bd9Sstevel@tonic-gate static int sbp2_agent_write_orbp(sbp2_agent_t *, uint64_t, int *); 857c478bd9Sstevel@tonic-gate static int sbp2_agent_reset(sbp2_agent_t *, int *); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate /* callbacks and timeouts */ 887c478bd9Sstevel@tonic-gate static void sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **); 897c478bd9Sstevel@tonic-gate static void sbp2_task_timeout(void *); 907c478bd9Sstevel@tonic-gate static void sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* other */ 937c478bd9Sstevel@tonic-gate static void sbp2_mgt_agent_acquire(sbp2_tgt_t *); 947c478bd9Sstevel@tonic-gate static void sbp2_mgt_agent_release(sbp2_tgt_t *); 957c478bd9Sstevel@tonic-gate static void sbp2_fetch_agent_acquire(sbp2_ses_t *); 967c478bd9Sstevel@tonic-gate static void sbp2_fetch_agent_release(sbp2_ses_t *); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate extern struct mod_ops mod_miscops; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static struct modlmisc sbp2_modlmisc = { 1017c478bd9Sstevel@tonic-gate &mod_miscops, /* module type */ 102f5488aa8Sbharding "Serial Bus Protocol 2 module" /* module name */ 1037c478bd9Sstevel@tonic-gate }; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate static struct modlinkage sbp2_modlinkage = { 1067c478bd9Sstevel@tonic-gate MODREV_1, (void *)&sbp2_modlmisc, NULL 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* tunables */ 1107c478bd9Sstevel@tonic-gate int sbp2_submit_reset_nretries = 3; 1117c478bd9Sstevel@tonic-gate clock_t sbp2_submit_reset_delay = 10; /* microsec */ 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate int sbp2_write_orbp_nretries = 3; 1147c478bd9Sstevel@tonic-gate clock_t sbp2_write_orbp_delay = 10; /* microsec */ 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab msgb)) 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate /* 1197c478bd9Sstevel@tonic-gate * 1207c478bd9Sstevel@tonic-gate * --- loadable module entry points 1217c478bd9Sstevel@tonic-gate * 1227c478bd9Sstevel@tonic-gate */ 1237c478bd9Sstevel@tonic-gate int 1247c478bd9Sstevel@tonic-gate _init(void) 1257c478bd9Sstevel@tonic-gate { 1267c478bd9Sstevel@tonic-gate return (mod_install(&sbp2_modlinkage)); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate int 1317c478bd9Sstevel@tonic-gate _fini(void) 1327c478bd9Sstevel@tonic-gate { 1337c478bd9Sstevel@tonic-gate return (mod_remove(&sbp2_modlinkage)); 1347c478bd9Sstevel@tonic-gate } 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate int 1387c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1397c478bd9Sstevel@tonic-gate { 1407c478bd9Sstevel@tonic-gate return (mod_info(&sbp2_modlinkage, modinfop)); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * 1457c478bd9Sstevel@tonic-gate * --- target routines 1467c478bd9Sstevel@tonic-gate * 1477c478bd9Sstevel@tonic-gate */ 1487c478bd9Sstevel@tonic-gate int 1497c478bd9Sstevel@tonic-gate sbp2_tgt_init(void *bus_hdl, sbp2_bus_t *bus, int maxluns, sbp2_tgt_t **tpp) 1507c478bd9Sstevel@tonic-gate { 1517c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp; 1527c478bd9Sstevel@tonic-gate int ret; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate tp = kmem_zalloc(sizeof (sbp2_tgt_t), KM_SLEEP); 1557c478bd9Sstevel@tonic-gate tp->t_bus = bus; 1567c478bd9Sstevel@tonic-gate tp->t_bus_hdl = bus_hdl; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate sbp2_tgt_init_sobj(tp); 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate if ((ret = sbp2_cfgrom_parse(tp, &tp->t_cfgrom)) != SBP2_SUCCESS) { 1617c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1627c478bd9Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1637c478bd9Sstevel@tonic-gate return (SBP2_ECFGROM); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_init_params(tp)) != SBP2_SUCCESS) { 1677c478bd9Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1687c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1697c478bd9Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1707c478bd9Sstevel@tonic-gate return (ret); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_init_luns(tp, maxluns)) != SBP2_SUCCESS) { 1747c478bd9Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1757c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1767c478bd9Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1777c478bd9Sstevel@tonic-gate return (ret); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_init_bus(tp)) != SBP2_SUCCESS) { 1817c478bd9Sstevel@tonic-gate sbp2_tgt_fini_luns(tp); 1827c478bd9Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1837c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1847c478bd9Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1857c478bd9Sstevel@tonic-gate return (ret); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate *tpp = tp; 1897c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate void 1937c478bd9Sstevel@tonic-gate sbp2_tgt_fini(sbp2_tgt_t *tp) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 1967c478bd9Sstevel@tonic-gate sbp2_tgt_fini_luns(tp); 1977c478bd9Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1987c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1997c478bd9Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate static void 2037c478bd9Sstevel@tonic-gate sbp2_tgt_init_sobj(sbp2_tgt_t *tp) 2047c478bd9Sstevel@tonic-gate { 2057c478bd9Sstevel@tonic-gate mutex_init(&tp->t_mutex, NULL, MUTEX_DRIVER, NULL); 2067c478bd9Sstevel@tonic-gate cv_init(&tp->t_mgt_agent_cv, NULL, CV_DRIVER, NULL); 2077c478bd9Sstevel@tonic-gate cv_init(&tp->t_mgt_status_cv, NULL, CV_DRIVER, NULL); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate static void 2117c478bd9Sstevel@tonic-gate sbp2_tgt_fini_sobj(sbp2_tgt_t *tp) 2127c478bd9Sstevel@tonic-gate { 2137c478bd9Sstevel@tonic-gate cv_destroy(&tp->t_mgt_status_cv); 2147c478bd9Sstevel@tonic-gate cv_destroy(&tp->t_mgt_agent_cv); 2157c478bd9Sstevel@tonic-gate mutex_destroy(&tp->t_mutex); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate static int 2197c478bd9Sstevel@tonic-gate sbp2_tgt_init_params(sbp2_tgt_t *tp) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root; 2227c478bd9Sstevel@tonic-gate sbp2_cfgrom_ent_t *ent; 2237c478bd9Sstevel@tonic-gate uint32_t q; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* MANAGEMENT_AGENT */ 2267c478bd9Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_MGT_AGENT, 2277c478bd9Sstevel@tonic-gate SBP2_KV_MGT_AGENT, 0)) == NULL) { 2287c478bd9Sstevel@tonic-gate return (SBP2_ECFGROM); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate tp->t_mgt_agent = SBP2_CSR_BASE(tp) + ent->ce_data.offset * 4; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* Unit_Characteristics */ 2337c478bd9Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_UNCHAR, 2347c478bd9Sstevel@tonic-gate SBP2_KV_UNCHAR, 0)) == NULL) { 2357c478bd9Sstevel@tonic-gate return (SBP2_ECFGROM); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate q = ent->ce_data.imm; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate /* units of 500 ms -> ms */ 2407c478bd9Sstevel@tonic-gate tp->t_mot = ((q & SBP2_UNCHAR_MOT) >> SBP2_UNCHAR_MOT_SHIFT) * 500; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* quadlets -> bytes */ 2437c478bd9Sstevel@tonic-gate tp->t_orb_size = (q & SBP2_UNCHAR_ORB_SIZE) * 4; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate /* some devices return incorrect values */ 2467c478bd9Sstevel@tonic-gate if (tp->t_mot < SBP2_MOT_MIN) { 2477c478bd9Sstevel@tonic-gate tp->t_mot = SBP2_MOT_DFLT; 2487c478bd9Sstevel@tonic-gate } 2497c478bd9Sstevel@tonic-gate if (tp->t_orb_size < SBP2_ORB_SIZE_MIN) { 2507c478bd9Sstevel@tonic-gate tp->t_orb_size = SBP2_ORB_SIZE_MIN; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2587c478bd9Sstevel@tonic-gate static int 2597c478bd9Sstevel@tonic-gate sbp2_tgt_init_luns(sbp2_tgt_t *tp, int maxluns) 2607c478bd9Sstevel@tonic-gate { 2617c478bd9Sstevel@tonic-gate sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root; 2627c478bd9Sstevel@tonic-gate sbp2_cfgrom_ent_t *ent; 2637c478bd9Sstevel@tonic-gate sbp2_lun_t *lp; 2647c478bd9Sstevel@tonic-gate uint32_t q; 2657c478bd9Sstevel@tonic-gate 2667c478bd9Sstevel@tonic-gate ASSERT(tp->t_nluns == 0); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate tp->t_lun = kmem_zalloc(maxluns * sizeof (sbp2_lun_t), KM_SLEEP); 2697c478bd9Sstevel@tonic-gate tp->t_nluns_alloc = maxluns; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate /* search for Logical_Unit_Number's */ 2727c478bd9Sstevel@tonic-gate for (tp->t_nluns = 0; tp->t_nluns < maxluns; tp->t_nluns++) { 2737c478bd9Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_LUN, 2747c478bd9Sstevel@tonic-gate SBP2_KV_LUN, tp->t_nluns)) == NULL) { 2757c478bd9Sstevel@tonic-gate break; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate q = ent->ce_data.imm; 2787c478bd9Sstevel@tonic-gate lp = &tp->t_lun[tp->t_nluns]; 2797c478bd9Sstevel@tonic-gate lp->l_tgt = tp; 2807c478bd9Sstevel@tonic-gate lp->l_lun = q & SBP2_LUN_NUM; 2817c478bd9Sstevel@tonic-gate lp->l_type = (q & SBP2_LUN_TYPE) >> SBP2_LUN_TYPE_SHIFT; 2827c478bd9Sstevel@tonic-gate mutex_init(&lp->l_orb_freelist.bl_mutex, NULL, MUTEX_DRIVER, 2837c478bd9Sstevel@tonic-gate NULL); 2847c478bd9Sstevel@tonic-gate } 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate if (tp->t_nluns > 0) { 2877c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 2887c478bd9Sstevel@tonic-gate } else { 2897c478bd9Sstevel@tonic-gate kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t)); 2907c478bd9Sstevel@tonic-gate return (SBP2_ECFGROM); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate } 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate static void 2977c478bd9Sstevel@tonic-gate sbp2_tgt_fini_luns(sbp2_tgt_t *tp) 2987c478bd9Sstevel@tonic-gate { 2997c478bd9Sstevel@tonic-gate int i; 3007c478bd9Sstevel@tonic-gate sbp2_lun_t *lp; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* destroy each lun */ 3037c478bd9Sstevel@tonic-gate for (i = 0; i < tp->t_nluns; i++) { 3047c478bd9Sstevel@tonic-gate lp = &tp->t_lun[i]; 3057c478bd9Sstevel@tonic-gate sbp2_orb_freelist_destroy(lp); 3067c478bd9Sstevel@tonic-gate mutex_destroy(&lp->l_orb_freelist.bl_mutex); 3077c478bd9Sstevel@tonic-gate } 3087c478bd9Sstevel@tonic-gate 3097c478bd9Sstevel@tonic-gate kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t)); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * initialize bus buffers and commands 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate static int 3167c478bd9Sstevel@tonic-gate sbp2_tgt_init_bus(sbp2_tgt_t *tp) 3177c478bd9Sstevel@tonic-gate { 3187c478bd9Sstevel@tonic-gate int ret; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate /* 3217c478bd9Sstevel@tonic-gate * We serialize management requests and reuse the same buffers. 3227c478bd9Sstevel@tonic-gate * 3237c478bd9Sstevel@tonic-gate * mgt ORB 3247c478bd9Sstevel@tonic-gate */ 3257c478bd9Sstevel@tonic-gate tp->t_mgt_orb_buf.bb_len = 3267c478bd9Sstevel@tonic-gate SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_mgt_orb_t)); 3277c478bd9Sstevel@tonic-gate tp->t_mgt_orb_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD; 3287c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_orb_buf)) != SBP2_SUCCESS) { 3297c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3307c478bd9Sstevel@tonic-gate return (ret); 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * mgt status FIFO 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_len = sizeof (sbp2_status_t); 3377c478bd9Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED; 3387c478bd9Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_wb_cb = sbp2_mgt_status_fifo_wb_cb; 3397c478bd9Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_sbp2_priv = tp; 3407c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_status_fifo_buf)) != 3417c478bd9Sstevel@tonic-gate SBP2_SUCCESS) { 3427c478bd9Sstevel@tonic-gate return (ret); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * login response 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate tp->t_mgt_login_resp_buf.bb_len = 3497c478bd9Sstevel@tonic-gate SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_login_resp_t)); 3507c478bd9Sstevel@tonic-gate /* 3517c478bd9Sstevel@tonic-gate * read-only should have been sufficient here, but it causes 3527c478bd9Sstevel@tonic-gate * DVMA errors on Grover, while read/write works just fine 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate tp->t_mgt_login_resp_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RW; 3557c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_login_resp_buf)) != 3567c478bd9Sstevel@tonic-gate SBP2_SUCCESS) { 3577c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3587c478bd9Sstevel@tonic-gate return (ret); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* 3627c478bd9Sstevel@tonic-gate * allocate bus commands 3637c478bd9Sstevel@tonic-gate */ 3647c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_CMD(tp, &tp->t_mgt_cmd, 0)) != SBP2_SUCCESS) { 3657c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3667c478bd9Sstevel@tonic-gate return (ret); 3677c478bd9Sstevel@tonic-gate } 3687c478bd9Sstevel@tonic-gate if ((tp->t_mgt_cmd_data = allocb(8, BPRI_HI)) == NULL) { 3697c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3707c478bd9Sstevel@tonic-gate return (SBP2_ENOMEM); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate static void 3777c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(sbp2_tgt_t *tp) 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate if (tp->t_mgt_status_fifo_buf.bb_hdl != NULL) { 3807c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_status_fifo_buf); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate if (tp->t_mgt_orb_buf.bb_hdl != NULL) { 3837c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_orb_buf); 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate if (tp->t_mgt_login_resp_buf.bb_hdl != NULL) { 3867c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_login_resp_buf); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate if (tp->t_mgt_cmd) { 3897c478bd9Sstevel@tonic-gate SBP2_FREE_CMD(tp, tp->t_mgt_cmd); 390f2b7ce3eSartem tp->t_mgt_cmd = NULL; 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate if (tp->t_mgt_cmd_data) { 3937c478bd9Sstevel@tonic-gate freeb(tp->t_mgt_cmd_data); 394f2b7ce3eSartem tp->t_mgt_cmd_data = NULL; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate void 3997c478bd9Sstevel@tonic-gate sbp2_tgt_disconnect(sbp2_tgt_t *tp) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate int 4057c478bd9Sstevel@tonic-gate sbp2_tgt_reconnect(sbp2_tgt_t *tp) 4067c478bd9Sstevel@tonic-gate { 4077c478bd9Sstevel@tonic-gate return (sbp2_tgt_init_bus(tp)); 4087c478bd9Sstevel@tonic-gate } 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * send mgt ORB and wait for status 4127c478bd9Sstevel@tonic-gate * 4137c478bd9Sstevel@tonic-gate * mgt agent should be acquired 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate static int 4167c478bd9Sstevel@tonic-gate sbp2_tgt_mgt_request(sbp2_tgt_t *tp, int *berr) 4177c478bd9Sstevel@tonic-gate { 4187c478bd9Sstevel@tonic-gate clock_t until; 4197c478bd9Sstevel@tonic-gate int ret; 4207c478bd9Sstevel@tonic-gate 421f5488aa8Sbharding /* 422f5488aa8Sbharding * When a ctl operation happens from HAL - this could be 0! 423f5488aa8Sbharding * This will happen when a device is disconected and then 424f5488aa8Sbharding * reconnected. Note there are problems with not being able 425f5488aa8Sbharding * to detach/eject a target before unplugging. That can cause 426f5488aa8Sbharding * this to happen... This problem needs some work elseware! 427f5488aa8Sbharding * This just prevents a needless panic. If we return failure 428f5488aa8Sbharding * the target ultimatly will recover and is usable. 429f5488aa8Sbharding */ 430f5488aa8Sbharding if (tp->t_mgt_cmd_data == 0) { 431f5488aa8Sbharding return (SBP2_FAILURE); 432f5488aa8Sbharding } 433f5488aa8Sbharding 4347c478bd9Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_FALSE; 4357c478bd9Sstevel@tonic-gate 4367c478bd9Sstevel@tonic-gate /* write ORB address into MANAGEMENT_AGENT */ 4377c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(tp->t_mgt_cmd_data->b_rptr, tp->t_mgt_orb_buf.bb_baddr, 4387c478bd9Sstevel@tonic-gate 0); 4397c478bd9Sstevel@tonic-gate tp->t_mgt_cmd_data->b_wptr = tp->t_mgt_cmd_data->b_rptr + 8; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if ((ret = SBP2_WB(tp, tp->t_mgt_cmd, tp->t_mgt_agent, 4427c478bd9Sstevel@tonic-gate tp->t_mgt_cmd_data, 8, berr)) != SBP2_SUCCESS) { 4437c478bd9Sstevel@tonic-gate return (ret); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* wait for login response */ 4477c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 4487c478bd9Sstevel@tonic-gate until = ddi_get_lbolt() + drv_usectohz(tp->t_mot * 1000); 4497c478bd9Sstevel@tonic-gate ret = 1; 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate while (!tp->t_mgt_status_rcvd && (ret > 0)) { 4527c478bd9Sstevel@tonic-gate ret = cv_timedwait(&tp->t_mgt_status_cv, &tp->t_mutex, until); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (!tp->t_mgt_status_rcvd) { 4567c478bd9Sstevel@tonic-gate ret = SBP2_ETIMEOUT; 4577c478bd9Sstevel@tonic-gate } else if ((tp->t_mgt_status.st_param & SBP2_ST_RESP) == 4587c478bd9Sstevel@tonic-gate SBP2_ST_RESP_COMPLETE) { 4597c478bd9Sstevel@tonic-gate ret = SBP2_SUCCESS; 4607c478bd9Sstevel@tonic-gate } else { 4617c478bd9Sstevel@tonic-gate ret = SBP2_FAILURE; 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate return (ret); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Send task management request, one of: 4707c478bd9Sstevel@tonic-gate * 4717c478bd9Sstevel@tonic-gate * ABORT TASK, ABORT TASK SET, LOGICAL UNIT RESET, TARGET RESET 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate static int 4747c478bd9Sstevel@tonic-gate sbp2_tgt_task_mgt_request(sbp2_tgt_t *tp, uint16_t id, int func, uint64_t orbp, 4757c478bd9Sstevel@tonic-gate int *berr) 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate sbp2_task_mgt_orb_t *torb; 4787c478bd9Sstevel@tonic-gate int ret; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate torb = (sbp2_task_mgt_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 4837c478bd9Sstevel@tonic-gate bzero(torb, sizeof (sbp2_task_mgt_orb_t)); 4847c478bd9Sstevel@tonic-gate SBP2_ORBP_SET(torb->to_orb, orbp); 4857c478bd9Sstevel@tonic-gate torb->to_params = SBP2_SWAP16(func | SBP2_ORB_NOTIFY | 4867c478bd9Sstevel@tonic-gate SBP2_ORB_RQ_FMT_SBP2); 4877c478bd9Sstevel@tonic-gate torb->to_login_id = SBP2_SWAP16(id); 4887c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(torb->to_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 4897c478bd9Sstevel@tonic-gate 0); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate ret = sbp2_tgt_mgt_request(tp, berr); 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate return (ret); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate int 4997c478bd9Sstevel@tonic-gate sbp2_tgt_reset(sbp2_tgt_t *tp, int *berr) 5007c478bd9Sstevel@tonic-gate { 5017c478bd9Sstevel@tonic-gate sbp2_lun_t *lp = &tp->t_lun[0]; 5027c478bd9Sstevel@tonic-gate int ret; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate /* issue TARGET RESET */ 5057c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 5067c478bd9Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_TARGET_RESET, 0, berr)) != SBP2_SUCCESS) { 5077c478bd9Sstevel@tonic-gate return (ret); 5087c478bd9Sstevel@tonic-gate } 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate int 5147c478bd9Sstevel@tonic-gate sbp2_tgt_get_cfgrom(sbp2_tgt_t *tp, sbp2_cfgrom_t **crpp) 5157c478bd9Sstevel@tonic-gate { 5167c478bd9Sstevel@tonic-gate *crpp = &tp->t_cfgrom; 5177c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate int 5217c478bd9Sstevel@tonic-gate sbp2_tgt_get_lun_cnt(sbp2_tgt_t *tp) 5227c478bd9Sstevel@tonic-gate { 5237c478bd9Sstevel@tonic-gate return (tp->t_nluns); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate sbp2_lun_t * 5277c478bd9Sstevel@tonic-gate sbp2_tgt_get_lun(sbp2_tgt_t *tp, int num) 5287c478bd9Sstevel@tonic-gate { 5297c478bd9Sstevel@tonic-gate if (num < tp->t_nluns) { 5307c478bd9Sstevel@tonic-gate return (&tp->t_lun[num]); 5317c478bd9Sstevel@tonic-gate } else { 5327c478bd9Sstevel@tonic-gate return (NULL); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367c478bd9Sstevel@tonic-gate /* 5377c478bd9Sstevel@tonic-gate * 5387c478bd9Sstevel@tonic-gate * --- lun routines 5397c478bd9Sstevel@tonic-gate * 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate int 5427c478bd9Sstevel@tonic-gate sbp2_lun_reset(sbp2_lun_t *lp, int *berr) 5437c478bd9Sstevel@tonic-gate { 5447c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 5457c478bd9Sstevel@tonic-gate sbp2_ses_t *sp = lp->l_ses; 5467c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 5477c478bd9Sstevel@tonic-gate int ret; 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* issue LOGICAL UNIT RESET */ 5507c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 5517c478bd9Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_LUN_RESET, 0, berr)) != SBP2_SUCCESS) { 5527c478bd9Sstevel@tonic-gate return (ret); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate /* mark all pending tasks reset and notify the driver */ 5567c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 5577c478bd9Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 5587c478bd9Sstevel@tonic-gate if (task->ts_state < SBP2_TASK_COMP) { 5597c478bd9Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_LUN_RESET; 5607c478bd9Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 5617c478bd9Sstevel@tonic-gate } 5627c478bd9Sstevel@tonic-gate } 5637c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, NULL); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate 5707c478bd9Sstevel@tonic-gate int 5717c478bd9Sstevel@tonic-gate sbp2_lun_login(sbp2_lun_t *lp, sbp2_ses_t **spp, 5727c478bd9Sstevel@tonic-gate void (*cb)(void *, sbp2_task_t *), void *cb_arg, int *berr) 5737c478bd9Sstevel@tonic-gate { 5747c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 5757c478bd9Sstevel@tonic-gate sbp2_ses_t *sp; 5767c478bd9Sstevel@tonic-gate sbp2_login_orb_t *lorb; 5777c478bd9Sstevel@tonic-gate int ret; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate if (cb == NULL) { 5807c478bd9Sstevel@tonic-gate return (SBP2_EINVAL); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate /* multiple sessions not supported yet */ 5847c478bd9Sstevel@tonic-gate if (lp->l_ses != NULL) { 5857c478bd9Sstevel@tonic-gate return (SBP2_EALREADY); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate if ((ret = sbp2_ses_init(&sp, lp, cb, cb_arg)) != SBP2_SUCCESS) { 5897c478bd9Sstevel@tonic-gate return (ret); 5907c478bd9Sstevel@tonic-gate } 5917c478bd9Sstevel@tonic-gate lp->l_ses = sp; 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate /* prepare login ORB */ 5967c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 5977c478bd9Sstevel@tonic-gate lorb = (sbp2_login_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 5987c478bd9Sstevel@tonic-gate bzero(lorb, sizeof (sbp2_login_orb_t)); 5997c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_resp, tp->t_mgt_login_resp_buf.bb_baddr, 0); 6007c478bd9Sstevel@tonic-gate lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGIN | 6017c478bd9Sstevel@tonic-gate SBP2_ORB_LOGIN_EXCL | SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 6027c478bd9Sstevel@tonic-gate lorb->lo_lun = SBP2_SWAP16(lp->l_lun); 6037c478bd9Sstevel@tonic-gate lorb->lo_resp_len = SBP2_SWAP16(tp->t_mgt_login_resp_buf.bb_len); 6047c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_status_fifo, sp->s_status_fifo_buf.bb_baddr, 0); 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate bzero(tp->t_mgt_login_resp_buf.bb_kaddr, sizeof (sbp2_login_resp_t)); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 6097c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate /* send request */ 6127c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) { 6137c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 6147c478bd9Sstevel@tonic-gate sbp2_ses_fini(lp->l_ses); 6157c478bd9Sstevel@tonic-gate lp->l_ses = NULL; 6167c478bd9Sstevel@tonic-gate return (ret); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate /* retrieve response data (XXX sanity checks?) */ 6207c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6217c478bd9Sstevel@tonic-gate (void) SBP2_SYNC_BUF(tp, &tp->t_mgt_login_resp_buf, 0, 0, 6227c478bd9Sstevel@tonic-gate DDI_DMA_SYNC_FORKERNEL); 6237c478bd9Sstevel@tonic-gate bcopy(tp->t_mgt_login_resp_buf.bb_kaddr, &lp->l_login_resp, 6247c478bd9Sstevel@tonic-gate sizeof (sbp2_login_resp_t)); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate /* convert from BE to native endianness */ 6277c478bd9Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_len); 6287c478bd9Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_login_id); 6297c478bd9Sstevel@tonic-gate SBP2_SWAP32_2(lp->l_login_resp.lr_cmd_agent); 6307c478bd9Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_reconnect_hold); 6317c478bd9Sstevel@tonic-gate lp->l_login_resp.lr_reconnect_hold++; 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate sp->s_agent_offset = SBP2_ADDR2UINT64(lp->l_login_resp.lr_cmd_agent); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate lp->l_logged_in = B_TRUE; 6367c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate if ((ret = sbp2_agent_init(&sp->s_agent, sp->s_agent_offset, tp)) != 6417c478bd9Sstevel@tonic-gate SBP2_SUCCESS) { 6427c478bd9Sstevel@tonic-gate sbp2_ses_fini(sp); 6437c478bd9Sstevel@tonic-gate lp->l_ses = NULL; 6447c478bd9Sstevel@tonic-gate return (ret); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate *spp = lp->l_ses; 6487c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 6527c478bd9Sstevel@tonic-gate int 6537c478bd9Sstevel@tonic-gate sbp2_lun_logout(sbp2_lun_t *lp, sbp2_ses_t **sp, int *berr, boolean_t phys) 6547c478bd9Sstevel@tonic-gate { 6557c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate ASSERT(*sp == lp->l_ses); 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6607c478bd9Sstevel@tonic-gate if (lp->l_logged_in) { 6617c478bd9Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 6627c478bd9Sstevel@tonic-gate /* do physical LOGOUT if requested */ 6637c478bd9Sstevel@tonic-gate if (phys) { 6647c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6657c478bd9Sstevel@tonic-gate sbp2_lun_logout_orb(lp, tp, berr); 6667c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate 6707c478bd9Sstevel@tonic-gate sbp2_agent_fini(&lp->l_ses->s_agent); 6717c478bd9Sstevel@tonic-gate sbp2_ses_fini(lp->l_ses); 6727c478bd9Sstevel@tonic-gate lp->l_ses = NULL; 6737c478bd9Sstevel@tonic-gate *sp = NULL; 6747c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 6777c478bd9Sstevel@tonic-gate } 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * Issue LOGOUT mgt orb and wait for response. We are not interested in 6817c478bd9Sstevel@tonic-gate * the success at the time, since the device may be disconnected or hung, 6827c478bd9Sstevel@tonic-gate * just trying to make the best effort. 6837c478bd9Sstevel@tonic-gate */ 6847c478bd9Sstevel@tonic-gate static void 6857c478bd9Sstevel@tonic-gate sbp2_lun_logout_orb(sbp2_lun_t *lp, sbp2_tgt_t *tp, int *berr) 6867c478bd9Sstevel@tonic-gate { 6877c478bd9Sstevel@tonic-gate sbp2_logout_orb_t *lorb; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate /* prepare logout ORB */ 6927c478bd9Sstevel@tonic-gate lorb = (sbp2_logout_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 6937c478bd9Sstevel@tonic-gate bzero(lorb, sizeof (sbp2_logout_orb_t)); 6947c478bd9Sstevel@tonic-gate lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGOUT | 6957c478bd9Sstevel@tonic-gate SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 6967c478bd9Sstevel@tonic-gate lorb->lo_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id); 6977c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 6987c478bd9Sstevel@tonic-gate 0); 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate /* send request */ 7017c478bd9Sstevel@tonic-gate (void) sbp2_tgt_mgt_request(tp, berr); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate static boolean_t 7077c478bd9Sstevel@tonic-gate sbp2_lun_accepting_tasks(sbp2_lun_t *lp) 7087c478bd9Sstevel@tonic-gate { 7097c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 7107c478bd9Sstevel@tonic-gate boolean_t ret; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 7137c478bd9Sstevel@tonic-gate ret = ((lp->l_ses != NULL) && lp->l_logged_in && !lp->l_reconnecting); 7147c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 7157c478bd9Sstevel@tonic-gate return (ret); 7167c478bd9Sstevel@tonic-gate } 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate /* 7197c478bd9Sstevel@tonic-gate * 7207c478bd9Sstevel@tonic-gate * --- session routines 7217c478bd9Sstevel@tonic-gate * 7227c478bd9Sstevel@tonic-gate */ 7237c478bd9Sstevel@tonic-gate static int 7247c478bd9Sstevel@tonic-gate sbp2_ses_init(sbp2_ses_t **spp, sbp2_lun_t *lp, 7257c478bd9Sstevel@tonic-gate void (*cb)(void *, sbp2_task_t *), void *cb_arg) 7267c478bd9Sstevel@tonic-gate { 7277c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 7287c478bd9Sstevel@tonic-gate sbp2_ses_t *sp; 7297c478bd9Sstevel@tonic-gate int ret; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate sp = kmem_zalloc(sizeof (sbp2_ses_t), KM_SLEEP); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate sp->s_tgt = tp; 7347c478bd9Sstevel@tonic-gate sp->s_lun = lp; 7357c478bd9Sstevel@tonic-gate sp->s_status_cb = cb; 7367c478bd9Sstevel@tonic-gate sp->s_status_cb_arg = cb_arg; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate mutex_init(&sp->s_mutex, NULL, MUTEX_DRIVER, 7397c478bd9Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 7407c478bd9Sstevel@tonic-gate mutex_init(&sp->s_task_mutex, NULL, MUTEX_DRIVER, 7417c478bd9Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* 7447c478bd9Sstevel@tonic-gate * status FIFO for block requests 7457c478bd9Sstevel@tonic-gate */ 7467c478bd9Sstevel@tonic-gate sp->s_status_fifo_buf.bb_len = sizeof (sbp2_status_t); 7477c478bd9Sstevel@tonic-gate sp->s_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED; 7487c478bd9Sstevel@tonic-gate sp->s_status_fifo_buf.bb_wb_cb = sbp2_status_fifo_wb_cb; 7497c478bd9Sstevel@tonic-gate sp->s_status_fifo_buf.bb_sbp2_priv = sp; 7507c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &sp->s_status_fifo_buf)) != 7517c478bd9Sstevel@tonic-gate SBP2_SUCCESS) { 7527c478bd9Sstevel@tonic-gate sbp2_ses_fini(sp); 7537c478bd9Sstevel@tonic-gate return (ret); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate 7567c478bd9Sstevel@tonic-gate *spp = sp; 7577c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate static void 7627c478bd9Sstevel@tonic-gate sbp2_ses_fini(sbp2_ses_t *sp) 7637c478bd9Sstevel@tonic-gate { 7647c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_lun->l_tgt; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if (sp->s_status_fifo_buf.bb_hdl != NULL) { 7677c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, &sp->s_status_fifo_buf); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_task_mutex); 7717c478bd9Sstevel@tonic-gate mutex_destroy(&sp->s_mutex); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate kmem_free(sp, sizeof (sbp2_ses_t)); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate int 7777c478bd9Sstevel@tonic-gate sbp2_ses_reconnect(sbp2_ses_t *sp, int *berr, uint16_t nodeID) 7787c478bd9Sstevel@tonic-gate { 7797c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 7807c478bd9Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 7817c478bd9Sstevel@tonic-gate int ret; 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate /* prevent new tasks from being submitted */ 7847c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 7857c478bd9Sstevel@tonic-gate lp->l_reconnecting = B_TRUE; 7867c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * From 10.5 Task management event matrix: 7907c478bd9Sstevel@tonic-gate * Immediately upon detection of a bus reset, all command 7917c478bd9Sstevel@tonic-gate * block fetch agents transition to the reset state and 7927c478bd9Sstevel@tonic-gate * their associated task sets are cleared without 7937c478bd9Sstevel@tonic-gate * the return of completion status. 7947c478bd9Sstevel@tonic-gate * 7957c478bd9Sstevel@tonic-gate * Reset pending tasks so we can retry them later. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate sbp2_ses_reset_pending_tasks(sp, nodeID); 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate ret = sbp2_ses_reconnect_orb(sp, berr); 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 8027c478bd9Sstevel@tonic-gate lp->l_reconnecting = B_FALSE; 8037c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 8047c478bd9Sstevel@tonic-gate 8057c478bd9Sstevel@tonic-gate return (ret); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * Send reconnect ORB. If operation fails, set lp->l_logged_in = B_FALSE. 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate static int 8127c478bd9Sstevel@tonic-gate sbp2_ses_reconnect_orb(sbp2_ses_t *sp, int *berr) 8137c478bd9Sstevel@tonic-gate { 8147c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 8157c478bd9Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 8167c478bd9Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 8177c478bd9Sstevel@tonic-gate sbp2_reconnect_orb_t *rorb; 8187c478bd9Sstevel@tonic-gate int ret; 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate /* prepare login ORB */ 8237c478bd9Sstevel@tonic-gate rorb = (sbp2_reconnect_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 8247c478bd9Sstevel@tonic-gate bzero(rorb, sizeof (sbp2_reconnect_orb_t)); 8257c478bd9Sstevel@tonic-gate rorb->ro_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_RECONNECT | 8267c478bd9Sstevel@tonic-gate SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 8277c478bd9Sstevel@tonic-gate rorb->ro_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id); 8287c478bd9Sstevel@tonic-gate SBP2_ADDR_SET(rorb->ro_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 8297c478bd9Sstevel@tonic-gate 0); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate /* send request */ 8327c478bd9Sstevel@tonic-gate if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) { 8337c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 8347c478bd9Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 8357c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 8367c478bd9Sstevel@tonic-gate } else { 8377c478bd9Sstevel@tonic-gate /* after successful reset fetch agent is in RESET state */ 8387c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 8397c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 8407c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 8417c478bd9Sstevel@tonic-gate } 8427c478bd9Sstevel@tonic-gate 8437c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate return (ret); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate static sbp2_task_t * 8507c478bd9Sstevel@tonic-gate sbp2_ses_orbp2task(sbp2_ses_t *sp, uint64_t orbp) 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate sbp2_task_t *task; 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 8557c478bd9Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 8567c478bd9Sstevel@tonic-gate if (task->ts_buf->bb_baddr == orbp) { 8577c478bd9Sstevel@tonic-gate break; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate } 8607c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 8617c478bd9Sstevel@tonic-gate return (task); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * This is where tasks (command ORB's) are signalled to the target. 8667c478bd9Sstevel@tonic-gate * 'task' argument is allowed to be NULL, in which case the task will be 8677c478bd9Sstevel@tonic-gate * taken from the current task list. 8687c478bd9Sstevel@tonic-gate * 8697c478bd9Sstevel@tonic-gate * Tasks are signalled one at a time by writing into ORB_POINTER register. 8707c478bd9Sstevel@tonic-gate * While SBP-2 allows dynamic task list updates and using DOORBELL register, 8717c478bd9Sstevel@tonic-gate * some devices have bugs that prevent using this strategy: e.g. some LaCie 8727c478bd9Sstevel@tonic-gate * HDD's can corrupt data. Data integrity is more important than performance. 8737c478bd9Sstevel@tonic-gate */ 8747c478bd9Sstevel@tonic-gate int 8757c478bd9Sstevel@tonic-gate sbp2_ses_submit_task(sbp2_ses_t *sp, sbp2_task_t *new_task) 8767c478bd9Sstevel@tonic-gate { 8777c478bd9Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 8787c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 8797c478bd9Sstevel@tonic-gate sbp2_task_t *task; /* task actually being submitted */ 8807c478bd9Sstevel@tonic-gate boolean_t callback; 8817c478bd9Sstevel@tonic-gate timeout_id_t timeout_id; 8827c478bd9Sstevel@tonic-gate int ret; 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate if (!sbp2_lun_accepting_tasks(sp->s_lun)) { 8857c478bd9Sstevel@tonic-gate return (SBP2_ENODEV); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate sbp2_agent_acquire(ap); /* serialize */ 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* if task provided, append it to the list */ 8937c478bd9Sstevel@tonic-gate if (new_task != NULL) { 8947c478bd9Sstevel@tonic-gate ASSERT(new_task->ts_state == SBP2_TASK_INIT); 8957c478bd9Sstevel@tonic-gate sbp2_ses_append_task(sp, new_task); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* if there is already a task in flight, exit */ 8997c478bd9Sstevel@tonic-gate if ((ap->a_active_task != NULL) && 9007c478bd9Sstevel@tonic-gate (ap->a_active_task->ts_state == SBP2_TASK_PEND)) { 9017c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9027c478bd9Sstevel@tonic-gate sbp2_agent_release(ap); 9037c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 9047c478bd9Sstevel@tonic-gate } 9057c478bd9Sstevel@tonic-gate 906*8c067cfdSAlan Perry /* 907*8c067cfdSAlan Perry * cannot submit tasks from interrupt context, 908*8c067cfdSAlan Perry * upper layer driver is responsible to call nudge 909*8c067cfdSAlan Perry */ 910*8c067cfdSAlan Perry if (servicing_interrupt()) { 911*8c067cfdSAlan Perry mutex_exit(&ap->a_mutex); 912*8c067cfdSAlan Perry sbp2_agent_release(ap); 913*8c067cfdSAlan Perry return (SBP2_ECONTEXT); 914*8c067cfdSAlan Perry } 915*8c067cfdSAlan Perry 9167c478bd9Sstevel@tonic-gate /* no active task, grab the first one on the list in INIT state */ 9177c478bd9Sstevel@tonic-gate ap->a_active_task = sbp2_ses_find_task_state(sp, SBP2_TASK_INIT); 9187c478bd9Sstevel@tonic-gate if (ap->a_active_task == NULL) { 9197c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9207c478bd9Sstevel@tonic-gate sbp2_agent_release(ap); 9217c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate task = ap->a_active_task; 9247c478bd9Sstevel@tonic-gate task->ts_ses = sp; 9257c478bd9Sstevel@tonic-gate task->ts_state = SBP2_TASK_PEND; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate /* can't work with a dead agent */ 9287c478bd9Sstevel@tonic-gate if (sbp2_agent_keepalive(ap, &task->ts_bus_error) != SBP2_SUCCESS) { 9297c478bd9Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_DEAD; 9307c478bd9Sstevel@tonic-gate goto error; 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* 9347c478bd9Sstevel@tonic-gate * In theory, we should schedule task timeout after it's been submitted. 9357c478bd9Sstevel@tonic-gate * However, some fast tasks complete even before timeout is scheduled. 9367c478bd9Sstevel@tonic-gate * To avoid additional complications in the code, schedule timeout now. 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate ASSERT(task->ts_timeout_id == 0); 9397c478bd9Sstevel@tonic-gate task->ts_time_start = gethrtime(); 9407c478bd9Sstevel@tonic-gate if (task->ts_timeout > 0) { 9417c478bd9Sstevel@tonic-gate task->ts_timeout_id = timeout(sbp2_task_timeout, task, 9427c478bd9Sstevel@tonic-gate task->ts_timeout * drv_usectohz(1000000)); 9437c478bd9Sstevel@tonic-gate } 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate /* notify fetch agent */ 9467c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_ACTIVE; 9477c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9487c478bd9Sstevel@tonic-gate ret = sbp2_agent_write_orbp(ap, task->ts_buf->bb_baddr, 9497c478bd9Sstevel@tonic-gate &task->ts_bus_error); 9507c478bd9Sstevel@tonic-gate tp->t_stat.stat_submit_orbp++; 9517c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate if (ret != SBP2_SUCCESS) { 9547c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 9557c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_dead++; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate if (task->ts_timeout_id != 0) { 9587c478bd9Sstevel@tonic-gate timeout_id = task->ts_timeout_id; 9597c478bd9Sstevel@tonic-gate task->ts_timeout_id = 0; 9607c478bd9Sstevel@tonic-gate (void) untimeout(timeout_id); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_BUS; 9637c478bd9Sstevel@tonic-gate goto error; 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate sbp2_agent_release(ap); 9697c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate error: 9727c478bd9Sstevel@tonic-gate /* 9737c478bd9Sstevel@tonic-gate * Return immediate error if failed task is the one being submitted, 9747c478bd9Sstevel@tonic-gate * otherwise use callback. 9757c478bd9Sstevel@tonic-gate */ 9767c478bd9Sstevel@tonic-gate callback = (ap->a_active_task != new_task); 977f2b7ce3eSartem ASSERT(task == ap->a_active_task); 9787c478bd9Sstevel@tonic-gate ap->a_active_task = NULL; 9797c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9807c478bd9Sstevel@tonic-gate sbp2_agent_release(ap); 9817c478bd9Sstevel@tonic-gate 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * Remove task from the list. It is important not to change task state 9847c478bd9Sstevel@tonic-gate * to SBP2_TASK_COMP while it's still on the list, to avoid race with 9857c478bd9Sstevel@tonic-gate * upper layer driver (e.g. scsa1394). 9867c478bd9Sstevel@tonic-gate */ 987f2b7ce3eSartem ret = sbp2_ses_remove_task(sp, task); 9887c478bd9Sstevel@tonic-gate ASSERT(ret == SBP2_SUCCESS); 989f2b7ce3eSartem task->ts_state = SBP2_TASK_COMP; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate if (callback) { 992f2b7ce3eSartem sp->s_status_cb(sp->s_status_cb_arg, task); 9937c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 9947c478bd9Sstevel@tonic-gate } else { 9957c478bd9Sstevel@tonic-gate /* upper layer driver is responsible to call nudge */ 9967c478bd9Sstevel@tonic-gate return (SBP2_FAILURE); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate 10007c478bd9Sstevel@tonic-gate void 10017c478bd9Sstevel@tonic-gate sbp2_ses_nudge(sbp2_ses_t *sp) 10027c478bd9Sstevel@tonic-gate { 10037c478bd9Sstevel@tonic-gate (void) sbp2_ses_submit_task(sp, NULL); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate /* 10077c478bd9Sstevel@tonic-gate * append task to the task list 10087c478bd9Sstevel@tonic-gate */ 10097c478bd9Sstevel@tonic-gate static void 10107c478bd9Sstevel@tonic-gate sbp2_ses_append_task(sbp2_ses_t *sp, sbp2_task_t *task) 10117c478bd9Sstevel@tonic-gate { 10127c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 10137c478bd9Sstevel@tonic-gate 10147c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10157c478bd9Sstevel@tonic-gate if (sp->s_task_head == NULL) { 10167c478bd9Sstevel@tonic-gate ASSERT(sp->s_task_tail == NULL); 10177c478bd9Sstevel@tonic-gate ASSERT(sp->s_task_cnt == 0); 10187c478bd9Sstevel@tonic-gate task->ts_prev = task->ts_next = NULL; 10197c478bd9Sstevel@tonic-gate sp->s_task_head = sp->s_task_tail = task; 10207c478bd9Sstevel@tonic-gate } else { 10217c478bd9Sstevel@tonic-gate ASSERT(sp->s_task_cnt > 0); 10227c478bd9Sstevel@tonic-gate task->ts_next = NULL; 10237c478bd9Sstevel@tonic-gate task->ts_prev = sp->s_task_tail; 10247c478bd9Sstevel@tonic-gate sp->s_task_tail->ts_next = task; 10257c478bd9Sstevel@tonic-gate sp->s_task_tail = task; 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate ASSERT(task != task->ts_prev); 10287c478bd9Sstevel@tonic-gate ASSERT(task != task->ts_next); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate sp->s_task_cnt++; 10317c478bd9Sstevel@tonic-gate if (sp->s_task_cnt > tp->t_stat.stat_task_max) { 10327c478bd9Sstevel@tonic-gate tp->t_stat.stat_task_max = sp->s_task_cnt; 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * remove task from the task list 10397c478bd9Sstevel@tonic-gate */ 10407c478bd9Sstevel@tonic-gate static int 10417c478bd9Sstevel@tonic-gate sbp2_ses_remove_task_locked(sbp2_ses_t *sp, sbp2_task_t *task) 10427c478bd9Sstevel@tonic-gate { 10437c478bd9Sstevel@tonic-gate sp->s_task_cnt--; 10447c478bd9Sstevel@tonic-gate if (task == sp->s_task_head) { /* first */ 10457c478bd9Sstevel@tonic-gate ASSERT(task->ts_prev == NULL); 10467c478bd9Sstevel@tonic-gate if (task->ts_next == NULL) { /* and last */ 10477c478bd9Sstevel@tonic-gate ASSERT(sp->s_task_cnt == 0); 10487c478bd9Sstevel@tonic-gate sp->s_task_head = sp->s_task_tail = NULL; 10497c478bd9Sstevel@tonic-gate } else { /* but not last */ 10507c478bd9Sstevel@tonic-gate sp->s_task_head = task->ts_next; 10517c478bd9Sstevel@tonic-gate sp->s_task_head->ts_prev = NULL; 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate } else if (task == sp->s_task_tail) { /* last but not first */ 10547c478bd9Sstevel@tonic-gate ASSERT(task->ts_next == NULL); 10557c478bd9Sstevel@tonic-gate sp->s_task_tail = task->ts_prev; 10567c478bd9Sstevel@tonic-gate sp->s_task_tail->ts_next = NULL; 10577c478bd9Sstevel@tonic-gate } else { /* in the middle */ 10587c478bd9Sstevel@tonic-gate task->ts_prev->ts_next = task->ts_next; 10597c478bd9Sstevel@tonic-gate task->ts_next->ts_prev = task->ts_prev; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate task->ts_prev = task->ts_next = NULL; 10627c478bd9Sstevel@tonic-gate ASSERT(sp->s_task_cnt >= 0); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 10657c478bd9Sstevel@tonic-gate } 10667c478bd9Sstevel@tonic-gate 10677c478bd9Sstevel@tonic-gate int 10687c478bd9Sstevel@tonic-gate sbp2_ses_remove_task(sbp2_ses_t *sp, sbp2_task_t *task) 10697c478bd9Sstevel@tonic-gate { 10707c478bd9Sstevel@tonic-gate int ret; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10737c478bd9Sstevel@tonic-gate ret = sbp2_ses_remove_task_locked(sp, task); 10747c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10757c478bd9Sstevel@tonic-gate 10767c478bd9Sstevel@tonic-gate return (ret); 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate /* 10807c478bd9Sstevel@tonic-gate * Return first task on the list in specified state. 10817c478bd9Sstevel@tonic-gate */ 10827c478bd9Sstevel@tonic-gate sbp2_task_t * 10837c478bd9Sstevel@tonic-gate sbp2_ses_find_task_state(sbp2_ses_t *sp, sbp2_task_state_t state) 10847c478bd9Sstevel@tonic-gate { 10857c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10887c478bd9Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 10897c478bd9Sstevel@tonic-gate if (task->ts_state == state) { 10907c478bd9Sstevel@tonic-gate break; 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10947c478bd9Sstevel@tonic-gate 10957c478bd9Sstevel@tonic-gate return (task); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* 10997c478bd9Sstevel@tonic-gate * Remove first task on the list. Returns pointer to the removed task or NULL. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate sbp2_task_t * 11027c478bd9Sstevel@tonic-gate sbp2_ses_remove_first_task(sbp2_ses_t *sp) 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11077c478bd9Sstevel@tonic-gate task = sp->s_task_head; 11087c478bd9Sstevel@tonic-gate if (task != NULL) { 11097c478bd9Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate return (task); 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* 11177c478bd9Sstevel@tonic-gate * Remove first task on the list only if it's in specified state. 11187c478bd9Sstevel@tonic-gate * Returns pointer to the removed task or NULL. 11197c478bd9Sstevel@tonic-gate */ 11207c478bd9Sstevel@tonic-gate sbp2_task_t * 11217c478bd9Sstevel@tonic-gate sbp2_ses_remove_first_task_state(sbp2_ses_t *sp, sbp2_task_state_t state) 11227c478bd9Sstevel@tonic-gate { 11237c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11267c478bd9Sstevel@tonic-gate if ((sp->s_task_head != NULL) && (sp->s_task_head->ts_state == state)) { 11277c478bd9Sstevel@tonic-gate task = sp->s_task_head; 11287c478bd9Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate return (task); 11337c478bd9Sstevel@tonic-gate } 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * Remove first task on the list. If there's timeout, untimeout it. 11377c478bd9Sstevel@tonic-gate * Returns pointer to the removed task or NULL. 11387c478bd9Sstevel@tonic-gate */ 11397c478bd9Sstevel@tonic-gate sbp2_task_t * 11407c478bd9Sstevel@tonic-gate sbp2_ses_cancel_first_task(sbp2_ses_t *sp) 11417c478bd9Sstevel@tonic-gate { 11427c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 11437c478bd9Sstevel@tonic-gate timeout_id_t timeout_id; 11447c478bd9Sstevel@tonic-gate 11457c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11467c478bd9Sstevel@tonic-gate task = sp->s_task_head; 11477c478bd9Sstevel@tonic-gate if (task != NULL) { 11487c478bd9Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate if ((task != NULL) && ((timeout_id = task->ts_timeout_id) != 0)) { 11537c478bd9Sstevel@tonic-gate task->ts_timeout_id = 0; 11547c478bd9Sstevel@tonic-gate (void) untimeout(timeout_id); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate return (task); 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate 11607c478bd9Sstevel@tonic-gate /* 11617c478bd9Sstevel@tonic-gate * Reset pending tasks on the list to their initial state. 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate static void 11647c478bd9Sstevel@tonic-gate sbp2_ses_reset_pending_tasks(sbp2_ses_t *sp, uint16_t nodeID) 11657c478bd9Sstevel@tonic-gate { 11667c478bd9Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 11677c478bd9Sstevel@tonic-gate sbp2_task_t *task = NULL; 11687c478bd9Sstevel@tonic-gate timeout_id_t timeout_id; 11697c478bd9Sstevel@tonic-gate sbp2_cmd_orb_t *orb; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11727c478bd9Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 11737c478bd9Sstevel@tonic-gate task->ts_state = SBP2_TASK_INIT; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate /* cancel timeout */ 11767c478bd9Sstevel@tonic-gate if ((timeout_id = task->ts_timeout_id) != 0) { 11777c478bd9Sstevel@tonic-gate task->ts_timeout_id = 0; 11787c478bd9Sstevel@tonic-gate (void) untimeout(timeout_id); 11797c478bd9Sstevel@tonic-gate } 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate /* update ORB nodeID */ 11827c478bd9Sstevel@tonic-gate orb = (sbp2_cmd_orb_t *)sbp2_task_orb_kaddr(task); 11837c478bd9Sstevel@tonic-gate *(uint16_t *)orb->co_data_descr = SBP2_SWAP16(nodeID); 11847c478bd9Sstevel@tonic-gate sbp2_task_orb_sync(sp->s_lun, task, DDI_DMA_SYNC_FORDEV); 11857c478bd9Sstevel@tonic-gate } 11867c478bd9Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 11897c478bd9Sstevel@tonic-gate ap->a_active_task = NULL; 11907c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate int 11947c478bd9Sstevel@tonic-gate sbp2_ses_agent_reset(sbp2_ses_t *sp, int *berr) 11957c478bd9Sstevel@tonic-gate { 11967c478bd9Sstevel@tonic-gate return (sbp2_agent_reset(&sp->s_agent, berr)); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate 11997c478bd9Sstevel@tonic-gate int 12007c478bd9Sstevel@tonic-gate sbp2_ses_abort_task(sbp2_ses_t *sp, sbp2_task_t *task, int *berr) 12017c478bd9Sstevel@tonic-gate { 12027c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 12037c478bd9Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 12047c478bd9Sstevel@tonic-gate uint16_t params; 12057c478bd9Sstevel@tonic-gate sbp2_cmd_orb_t *orb = (sbp2_cmd_orb_t *)task->ts_buf->bb_kaddr; 12067c478bd9Sstevel@tonic-gate int ret = SBP2_SUCCESS; 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate /* mark ORB as dummy ORB */ 12097c478bd9Sstevel@tonic-gate params = (orb->co_params & ~SBP2_ORB_RQ_FMT) | SBP2_ORB_RQ_FMT_DUMMY; 12107c478bd9Sstevel@tonic-gate orb->co_params = params; 12117c478bd9Sstevel@tonic-gate (void) SBP2_SYNC_BUF(tp, task->ts_buf, 0, 0, DDI_DMA_SYNC_FORDEV); 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 12147c478bd9Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_ABORT_TASK, task->ts_buf->bb_baddr, berr); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate return (ret); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate int 12217c478bd9Sstevel@tonic-gate sbp2_ses_abort_task_set(sbp2_ses_t *sp, int *berr) 12227c478bd9Sstevel@tonic-gate { 12237c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 12247c478bd9Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 12257c478bd9Sstevel@tonic-gate int ret; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 12287c478bd9Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_ABORT_TASK_SET, 0, berr); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate return (ret); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate /* 12357c478bd9Sstevel@tonic-gate * 12367c478bd9Sstevel@tonic-gate * ORB functions 12377c478bd9Sstevel@tonic-gate * 12387c478bd9Sstevel@tonic-gate * allocate ORB resources 12397c478bd9Sstevel@tonic-gate * 12407c478bd9Sstevel@tonic-gate * we maintain a freelist of ORB's for faster allocation 12417c478bd9Sstevel@tonic-gate */ 12427c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 12437c478bd9Sstevel@tonic-gate static sbp2_bus_buf_t * 12447c478bd9Sstevel@tonic-gate sbp2_orb_freelist_get(sbp2_lun_t *lp, sbp2_task_t *task, int len) 12457c478bd9Sstevel@tonic-gate { 12467c478bd9Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12477c478bd9Sstevel@tonic-gate sbp2_bus_buf_t *buf = NULL; 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12507c478bd9Sstevel@tonic-gate if ((bl->bl_head != NULL) && (bl->bl_head->bb_len == len)) { 12517c478bd9Sstevel@tonic-gate buf = bl->bl_head; 12527c478bd9Sstevel@tonic-gate bl->bl_head = buf->bb_next; 12537c478bd9Sstevel@tonic-gate if (bl->bl_tail == buf) { /* last one? */ 12547c478bd9Sstevel@tonic-gate ASSERT(bl->bl_head == NULL); 12557c478bd9Sstevel@tonic-gate bl->bl_tail = NULL; 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate bl->bl_len--; 12587c478bd9Sstevel@tonic-gate buf->bb_next = NULL; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate return (buf); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate 12657c478bd9Sstevel@tonic-gate static int 12667c478bd9Sstevel@tonic-gate sbp2_orb_freelist_put(sbp2_lun_t *lp, sbp2_bus_buf_t *buf) 12677c478bd9Sstevel@tonic-gate { 12687c478bd9Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12697c478bd9Sstevel@tonic-gate int ret; 12707c478bd9Sstevel@tonic-gate 12717c478bd9Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12727c478bd9Sstevel@tonic-gate if (bl->bl_len < SBP2_ORB_FREELIST_MAX) { 12737c478bd9Sstevel@tonic-gate if (bl->bl_head == NULL) { 12747c478bd9Sstevel@tonic-gate ASSERT(bl->bl_tail == NULL); 12757c478bd9Sstevel@tonic-gate bl->bl_head = bl->bl_tail = buf; 12767c478bd9Sstevel@tonic-gate } else { 12777c478bd9Sstevel@tonic-gate bl->bl_tail->bb_next = buf; 12787c478bd9Sstevel@tonic-gate bl->bl_tail = buf; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate buf->bb_next = NULL; 12817c478bd9Sstevel@tonic-gate bl->bl_len++; 12827c478bd9Sstevel@tonic-gate ret = SBP2_SUCCESS; 12837c478bd9Sstevel@tonic-gate } else { 12847c478bd9Sstevel@tonic-gate ret = SBP2_FAILURE; 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate return (ret); 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate 12917c478bd9Sstevel@tonic-gate static void 12927c478bd9Sstevel@tonic-gate sbp2_orb_freelist_destroy(sbp2_lun_t *lp) 12937c478bd9Sstevel@tonic-gate { 12947c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 12957c478bd9Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12967c478bd9Sstevel@tonic-gate sbp2_bus_buf_t *buf, *buf_next; 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12997c478bd9Sstevel@tonic-gate for (buf = bl->bl_head; buf != NULL; ) { 13007c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, buf); 13017c478bd9Sstevel@tonic-gate buf_next = buf->bb_next; 13027c478bd9Sstevel@tonic-gate kmem_free(buf, sizeof (sbp2_bus_buf_t)); 13037c478bd9Sstevel@tonic-gate buf = buf_next; 13047c478bd9Sstevel@tonic-gate } 13057c478bd9Sstevel@tonic-gate bl->bl_head = bl->bl_tail = NULL; 13067c478bd9Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate int 13107c478bd9Sstevel@tonic-gate sbp2_task_orb_alloc(sbp2_lun_t *lp, sbp2_task_t *task, int len) 13117c478bd9Sstevel@tonic-gate { 13127c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 13137c478bd9Sstevel@tonic-gate int buf_len; 13147c478bd9Sstevel@tonic-gate int ret; 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate buf_len = SBP2_ORB_SIZE_ROUNDUP(tp, len); 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /* try freelist first */ 13197c478bd9Sstevel@tonic-gate if ((task->ts_buf = sbp2_orb_freelist_get(lp, task, buf_len)) != NULL) { 13207c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* if no free buffers, allocate new */ 13247c478bd9Sstevel@tonic-gate task->ts_buf = kmem_zalloc(sizeof (sbp2_bus_buf_t), KM_SLEEP); 13257c478bd9Sstevel@tonic-gate task->ts_buf->bb_len = buf_len; 13267c478bd9Sstevel@tonic-gate task->ts_buf->bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD; 13277c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, task->ts_buf)) != SBP2_SUCCESS) { 13287c478bd9Sstevel@tonic-gate kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t)); 13297c478bd9Sstevel@tonic-gate task->ts_buf = NULL; 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate return (ret); 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate void 13367c478bd9Sstevel@tonic-gate sbp2_task_orb_free(sbp2_lun_t *lp, sbp2_task_t *task) 13377c478bd9Sstevel@tonic-gate { 13387c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate if (task->ts_buf != NULL) { 13417c478bd9Sstevel@tonic-gate if (sbp2_orb_freelist_put(lp, task->ts_buf) != SBP2_SUCCESS) { 13427c478bd9Sstevel@tonic-gate SBP2_FREE_BUF(tp, task->ts_buf); 13437c478bd9Sstevel@tonic-gate kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t)); 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate task->ts_buf = NULL; 13467c478bd9Sstevel@tonic-gate } 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate void * 13507c478bd9Sstevel@tonic-gate sbp2_task_orb_kaddr(sbp2_task_t *task) 13517c478bd9Sstevel@tonic-gate { 13527c478bd9Sstevel@tonic-gate return (task->ts_buf->bb_kaddr); 13537c478bd9Sstevel@tonic-gate } 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate void 13567c478bd9Sstevel@tonic-gate sbp2_task_orb_sync(sbp2_lun_t *lp, sbp2_task_t *task, int flags) 13577c478bd9Sstevel@tonic-gate { 13587c478bd9Sstevel@tonic-gate (void) SBP2_SYNC_BUF(lp->l_tgt, task->ts_buf, 0, 0, flags); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* 13627c478bd9Sstevel@tonic-gate * 13637c478bd9Sstevel@tonic-gate * --- fetch agent routines 13647c478bd9Sstevel@tonic-gate * 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate static int 13677c478bd9Sstevel@tonic-gate sbp2_agent_init(sbp2_agent_t *ap, uint64_t offset, sbp2_tgt_t *tp) 13687c478bd9Sstevel@tonic-gate { 13697c478bd9Sstevel@tonic-gate int ret; 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate /* paranoia */ 13727c478bd9Sstevel@tonic-gate if (offset == 0) { 13737c478bd9Sstevel@tonic-gate return (SBP2_FAILURE); 13747c478bd9Sstevel@tonic-gate } 13757c478bd9Sstevel@tonic-gate 13767c478bd9Sstevel@tonic-gate ap->a_tgt = tp; 13777c478bd9Sstevel@tonic-gate 13787c478bd9Sstevel@tonic-gate ap->a_reg_agent_state = offset + SBP2_AGENT_STATE_OFFSET; 13797c478bd9Sstevel@tonic-gate ap->a_reg_agent_reset = offset + SBP2_AGENT_RESET_OFFSET; 13807c478bd9Sstevel@tonic-gate ap->a_reg_orbp = offset + SBP2_ORB_POINTER_OFFSET; 13817c478bd9Sstevel@tonic-gate ap->a_reg_doorbell = offset + SBP2_DOORBELL_OFFSET; 13827c478bd9Sstevel@tonic-gate ap->a_reg_unsol_status_enable = offset + 13837c478bd9Sstevel@tonic-gate SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET; 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate /* 13867c478bd9Sstevel@tonic-gate * allocate bus commands 13877c478bd9Sstevel@tonic-gate */ 13887c478bd9Sstevel@tonic-gate if ((ret = SBP2_ALLOC_CMD(tp, &ap->a_cmd, 0)) != SBP2_SUCCESS) { 13897c478bd9Sstevel@tonic-gate return (ret); 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate ap->a_cmd_data = allocb(sizeof (sbp2_orbp_t), BPRI_HI); 13927c478bd9Sstevel@tonic-gate if (ap->a_cmd_data == NULL) { 13937c478bd9Sstevel@tonic-gate sbp2_agent_fini(ap); 13947c478bd9Sstevel@tonic-gate return (SBP2_ENOMEM); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate 13977c478bd9Sstevel@tonic-gate mutex_init(&ap->a_mutex, NULL, MUTEX_DRIVER, 13987c478bd9Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 13997c478bd9Sstevel@tonic-gate cv_init(&ap->a_cv, NULL, CV_DRIVER, NULL); 14007c478bd9Sstevel@tonic-gate 14017c478bd9Sstevel@tonic-gate #ifndef __lock_lint 14027c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 14037c478bd9Sstevel@tonic-gate #endif 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate return (SBP2_SUCCESS); 14067c478bd9Sstevel@tonic-gate } 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate static void 14107c478bd9Sstevel@tonic-gate sbp2_agent_fini(sbp2_agent_t *ap) 14117c478bd9Sstevel@tonic-gate { 14127c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = ap->a_tgt; 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* free bus commands */ 14157c478bd9Sstevel@tonic-gate if (ap->a_cmd != NULL) { 14167c478bd9Sstevel@tonic-gate SBP2_FREE_CMD(tp, ap->a_cmd); 14177c478bd9Sstevel@tonic-gate } 14187c478bd9Sstevel@tonic-gate if (ap->a_cmd_data != NULL) { 14197c478bd9Sstevel@tonic-gate freeb(ap->a_cmd_data); 14207c478bd9Sstevel@tonic-gate } 14217c478bd9Sstevel@tonic-gate cv_destroy(&ap->a_cv); 14227c478bd9Sstevel@tonic-gate mutex_destroy(&ap->a_mutex); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate static void 14277c478bd9Sstevel@tonic-gate sbp2_agent_acquire_locked(sbp2_agent_t *ap) 14287c478bd9Sstevel@tonic-gate { 14297c478bd9Sstevel@tonic-gate while (ap->a_acquired) { 14307c478bd9Sstevel@tonic-gate cv_wait(&ap->a_cv, &ap->a_mutex); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate ap->a_acquired = B_TRUE; 14337c478bd9Sstevel@tonic-gate } 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate static void 14377c478bd9Sstevel@tonic-gate sbp2_agent_release_locked(sbp2_agent_t *ap) 14387c478bd9Sstevel@tonic-gate { 14397c478bd9Sstevel@tonic-gate ap->a_acquired = B_FALSE; 14407c478bd9Sstevel@tonic-gate cv_signal(&ap->a_cv); /* wake next waiter */ 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate 14447c478bd9Sstevel@tonic-gate static void 14457c478bd9Sstevel@tonic-gate sbp2_agent_acquire(sbp2_agent_t *ap) 14467c478bd9Sstevel@tonic-gate { 14477c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14487c478bd9Sstevel@tonic-gate sbp2_agent_acquire_locked(ap); 14497c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate static void 14547c478bd9Sstevel@tonic-gate sbp2_agent_release(sbp2_agent_t *ap) 14557c478bd9Sstevel@tonic-gate { 14567c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14577c478bd9Sstevel@tonic-gate sbp2_agent_release_locked(ap); 14587c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14597c478bd9Sstevel@tonic-gate } 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate static int 14637c478bd9Sstevel@tonic-gate sbp2_agent_keepalive(sbp2_agent_t *ap, int *berr) 14647c478bd9Sstevel@tonic-gate { 14657c478bd9Sstevel@tonic-gate boolean_t acquired; 14667c478bd9Sstevel@tonic-gate int ret = SBP2_SUCCESS; 14677c478bd9Sstevel@tonic-gate 14687c478bd9Sstevel@tonic-gate ASSERT(mutex_owned(&ap->a_mutex)); 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate if (ap->a_state == SBP2_AGENT_STATE_DEAD) { 14717c478bd9Sstevel@tonic-gate acquired = ap->a_acquired; 14727c478bd9Sstevel@tonic-gate if (!acquired) { 14737c478bd9Sstevel@tonic-gate sbp2_agent_acquire_locked(ap); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14777c478bd9Sstevel@tonic-gate ret = sbp2_agent_reset(ap, berr); 14787c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate if (!acquired) { 14817c478bd9Sstevel@tonic-gate sbp2_agent_release_locked(ap); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate return (ret); 14867c478bd9Sstevel@tonic-gate } 14877c478bd9Sstevel@tonic-gate 14887c478bd9Sstevel@tonic-gate #ifndef __lock_lint 14897c478bd9Sstevel@tonic-gate static int 14907c478bd9Sstevel@tonic-gate sbp2_agent_doorbell(sbp2_agent_t *ap, int *berr) 14917c478bd9Sstevel@tonic-gate { 14927c478bd9Sstevel@tonic-gate return (SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_doorbell, 0, berr)); 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate #endif 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate /* 14977c478bd9Sstevel@tonic-gate * write into ORB_POINTER register and make sure it reached target 14987c478bd9Sstevel@tonic-gate * 14997c478bd9Sstevel@tonic-gate * From E.2: "If no acknowledgement is received by the initiator after a write 15007c478bd9Sstevel@tonic-gate * to the ORB_POINTER register, the initiator should not retry the write. 15017c478bd9Sstevel@tonic-gate * The recommended method for error recovery is a write to the AGENT_RESET 15027c478bd9Sstevel@tonic-gate * register." So we can retry, but not in case of timeout. 15037c478bd9Sstevel@tonic-gate */ 15047c478bd9Sstevel@tonic-gate static int 15057c478bd9Sstevel@tonic-gate sbp2_agent_write_orbp(sbp2_agent_t *ap, uint64_t baddr, int *berr) 15067c478bd9Sstevel@tonic-gate { 15077c478bd9Sstevel@tonic-gate int i = 0; 15087c478bd9Sstevel@tonic-gate int ret; 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate SBP2_ORBP_SET(ap->a_cmd_data->b_rptr, baddr); 15117c478bd9Sstevel@tonic-gate ap->a_cmd_data->b_wptr = ap->a_cmd_data->b_rptr + 8; 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate for (;;) { 15147c478bd9Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_worbp++; 15157c478bd9Sstevel@tonic-gate if ((ret = SBP2_WB(ap->a_tgt, ap->a_cmd, ap->a_reg_orbp, 15167c478bd9Sstevel@tonic-gate ap->a_cmd_data, 8, berr)) == SBP2_SUCCESS) { 15177c478bd9Sstevel@tonic-gate return (ret); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_worbp_fail++; 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate if ((ret == SBP2_ETIMEOUT) || 15227c478bd9Sstevel@tonic-gate (++i > sbp2_write_orbp_nretries)) { 15237c478bd9Sstevel@tonic-gate break; 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate if (sbp2_write_orbp_delay > 0) { 15267c478bd9Sstevel@tonic-gate drv_usecwait(sbp2_write_orbp_delay); 15277c478bd9Sstevel@tonic-gate } 15287c478bd9Sstevel@tonic-gate } 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate return (ret); 15317c478bd9Sstevel@tonic-gate } 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /* 15357c478bd9Sstevel@tonic-gate * reset fetch agent by writing into AGENT_RESET register 15367c478bd9Sstevel@tonic-gate */ 15377c478bd9Sstevel@tonic-gate static int 15387c478bd9Sstevel@tonic-gate sbp2_agent_reset(sbp2_agent_t *ap, int *berr) 15397c478bd9Sstevel@tonic-gate { 15407c478bd9Sstevel@tonic-gate int i = 0; 15417c478bd9Sstevel@tonic-gate int ret; 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate for (;;) { 15447c478bd9Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_wreset++; 15457c478bd9Sstevel@tonic-gate if ((ret = SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_agent_reset, 15467c478bd9Sstevel@tonic-gate 0, berr)) == SBP2_SUCCESS) { 15477c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 15487c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 15497c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 15507c478bd9Sstevel@tonic-gate break; 15517c478bd9Sstevel@tonic-gate } 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_wreset_fail++; 15547c478bd9Sstevel@tonic-gate if (++i > sbp2_submit_reset_nretries) { 15557c478bd9Sstevel@tonic-gate break; 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate if (sbp2_submit_reset_delay > 0) { 15587c478bd9Sstevel@tonic-gate drv_usecwait(sbp2_submit_reset_delay); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate return (ret); 15627c478bd9Sstevel@tonic-gate } 15637c478bd9Sstevel@tonic-gate 15647c478bd9Sstevel@tonic-gate /* 15657c478bd9Sstevel@tonic-gate * 15667c478bd9Sstevel@tonic-gate * --- callbacks and timeouts 15677c478bd9Sstevel@tonic-gate * 15687c478bd9Sstevel@tonic-gate */ 15697c478bd9Sstevel@tonic-gate /* 15707c478bd9Sstevel@tonic-gate * Status FIFO callback for mgt ORB's. 15717c478bd9Sstevel@tonic-gate */ 15727c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 15737c478bd9Sstevel@tonic-gate static void 15747c478bd9Sstevel@tonic-gate sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp) 15757c478bd9Sstevel@tonic-gate { 15767c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = buf->bb_sbp2_priv; 15777c478bd9Sstevel@tonic-gate int len; 15787c478bd9Sstevel@tonic-gate sbp2_status_t *st; 15797c478bd9Sstevel@tonic-gate uint64_t orbp; 15807c478bd9Sstevel@tonic-gate 15817c478bd9Sstevel@tonic-gate len = MBLKL(*bpp); 15827c478bd9Sstevel@tonic-gate 15837c478bd9Sstevel@tonic-gate /* 8 bytes minimum */ 15847c478bd9Sstevel@tonic-gate if (len < 8) { 15857c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH); 15867c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_short++; 15877c478bd9Sstevel@tonic-gate return; 15887c478bd9Sstevel@tonic-gate } 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate /* convert 2-quadlet header from BE to native endianness */ 15917c478bd9Sstevel@tonic-gate st = (sbp2_status_t *)(*bpp)->b_rptr; 15927c478bd9Sstevel@tonic-gate SBP2_SWAP16_1(st->st_orb_offset_hi); 15937c478bd9Sstevel@tonic-gate SBP2_SWAP32_1(st->st_orb_offset_lo); 15947c478bd9Sstevel@tonic-gate orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo; 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate if (orbp != tp->t_mgt_orb_buf.bb_baddr) { 15977c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 15987c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_mgt_notask++; 15997c478bd9Sstevel@tonic-gate return; 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate /* make a local copy of status block */ 16037c478bd9Sstevel@tonic-gate bzero(&tp->t_mgt_status, sizeof (sbp2_status_t)); 16047c478bd9Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len); 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate /* wake up waiter */ 16097c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 16107c478bd9Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_TRUE; 16117c478bd9Sstevel@tonic-gate cv_signal(&tp->t_mgt_status_cv); 16127c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate static void 16167c478bd9Sstevel@tonic-gate sbp2_task_timeout(void *arg) 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate sbp2_task_t *task = arg; 16197c478bd9Sstevel@tonic-gate sbp2_ses_t *sp = task->ts_ses; 16207c478bd9Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 16237c478bd9Sstevel@tonic-gate 16247c478bd9Sstevel@tonic-gate /* cancelled? */ 16257c478bd9Sstevel@tonic-gate if (task->ts_timeout_id == 0) { 16267c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16277c478bd9Sstevel@tonic-gate return; 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate task->ts_timeout_id = 0; 16307c478bd9Sstevel@tonic-gate task->ts_time_comp = gethrtime(); 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate /* avoid race with other callbacks */ 16337c478bd9Sstevel@tonic-gate if (task->ts_state != SBP2_TASK_PEND) { 16347c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16357c478bd9Sstevel@tonic-gate return; 16367c478bd9Sstevel@tonic-gate } 16377c478bd9Sstevel@tonic-gate 16387c478bd9Sstevel@tonic-gate if (task == ap->a_active_task) { 16397c478bd9Sstevel@tonic-gate ap->a_active_task = NULL; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_TIMEOUT; 16427c478bd9Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 16437c478bd9Sstevel@tonic-gate 16447c478bd9Sstevel@tonic-gate /* we mark agent DEAD so it's reset before next task is submitted */ 16457c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 16467c478bd9Sstevel@tonic-gate sp->s_tgt->t_stat.stat_status_dead++; 16477c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, task); 16507c478bd9Sstevel@tonic-gate } 16517c478bd9Sstevel@tonic-gate 16527c478bd9Sstevel@tonic-gate /* 16537c478bd9Sstevel@tonic-gate * Status FIFO callback for command ORB's. Also used for login ORB. 16547c478bd9Sstevel@tonic-gate */ 16557c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16567c478bd9Sstevel@tonic-gate static void 16577c478bd9Sstevel@tonic-gate sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp) 16587c478bd9Sstevel@tonic-gate { 16597c478bd9Sstevel@tonic-gate sbp2_ses_t *sp = buf->bb_sbp2_priv; 16607c478bd9Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 16617c478bd9Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 16627c478bd9Sstevel@tonic-gate int len; 16637c478bd9Sstevel@tonic-gate sbp2_status_t *st; 16647c478bd9Sstevel@tonic-gate uint8_t src; 16657c478bd9Sstevel@tonic-gate uint64_t orbp; 16667c478bd9Sstevel@tonic-gate sbp2_task_t *task; 16677c478bd9Sstevel@tonic-gate timeout_id_t timeout_id; 16687c478bd9Sstevel@tonic-gate 16697c478bd9Sstevel@tonic-gate len = MBLKL(*bpp); 16707c478bd9Sstevel@tonic-gate 16717c478bd9Sstevel@tonic-gate /* 8 bytes minimum */ 16727c478bd9Sstevel@tonic-gate if (len < 8) { 16737c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH); 16747c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_short++; 16757c478bd9Sstevel@tonic-gate return; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate 16787c478bd9Sstevel@tonic-gate /* convert 2-quadlet header from BE32 to native endianness */ 16797c478bd9Sstevel@tonic-gate st = (sbp2_status_t *)(*bpp)->b_rptr; 16807c478bd9Sstevel@tonic-gate SBP2_SWAP16_1(st->st_orb_offset_hi); 16817c478bd9Sstevel@tonic-gate SBP2_SWAP32_1(st->st_orb_offset_lo); 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo; 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* login ORB status? */ 16867c478bd9Sstevel@tonic-gate if (orbp == tp->t_mgt_orb_buf.bb_baddr) { 16877c478bd9Sstevel@tonic-gate bzero(&tp->t_mgt_status, sizeof (sbp2_status_t)); 16887c478bd9Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len); 16897c478bd9Sstevel@tonic-gate 16907c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 16917c478bd9Sstevel@tonic-gate 16927c478bd9Sstevel@tonic-gate /* wake up waiter */ 16937c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 16947c478bd9Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_TRUE; 16957c478bd9Sstevel@tonic-gate cv_signal(&tp->t_mgt_status_cv); 16967c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 16977c478bd9Sstevel@tonic-gate return; 16987c478bd9Sstevel@tonic-gate } 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate /* dismiss unsolicited status */ 17017c478bd9Sstevel@tonic-gate src = st->st_param & SBP2_ST_SRC; 17027c478bd9Sstevel@tonic-gate if (src == SBP2_ST_SRC_UNSOLICITED) { 17037c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 17047c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_unsolicited++; 17057c478bd9Sstevel@tonic-gate return; 17067c478bd9Sstevel@tonic-gate } 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate /* find task corresponding to this ORB pointer */ 17097c478bd9Sstevel@tonic-gate if ((task = sbp2_ses_orbp2task(sp, orbp)) == NULL) { 17107c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 17117c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_notask++; 17127c478bd9Sstevel@tonic-gate return; 17137c478bd9Sstevel@tonic-gate } 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Copy status block into a local buffer. 17177c478bd9Sstevel@tonic-gate * 17187c478bd9Sstevel@tonic-gate * Note: (ref: B.2) "SBP-2 permits the return of a status block between 17197c478bd9Sstevel@tonic-gate * two and eight quadlets in length. When a truncated status block 17207c478bd9Sstevel@tonic-gate * is stored, the omited quadlets shall be interpreted as if zero 17217c478bd9Sstevel@tonic-gate * values were stored." 17227c478bd9Sstevel@tonic-gate */ 17237c478bd9Sstevel@tonic-gate bzero(&task->ts_status, sizeof (sbp2_status_t)); 17247c478bd9Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &task->ts_status, len); 17257c478bd9Sstevel@tonic-gate 17267c478bd9Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 17297c478bd9Sstevel@tonic-gate 17307c478bd9Sstevel@tonic-gate if ((timeout_id = task->ts_timeout_id) != 0) { 17317c478bd9Sstevel@tonic-gate task->ts_timeout_id = 0; 17327c478bd9Sstevel@tonic-gate (void) untimeout(timeout_id); 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* determine agent state */ 17367c478bd9Sstevel@tonic-gate if (st->st_param & SBP2_ST_DEAD) { 17377c478bd9Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 17387c478bd9Sstevel@tonic-gate tp->t_stat.stat_status_dead++; 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate /* avoid race with other callbacks */ 17427c478bd9Sstevel@tonic-gate if (task->ts_state != SBP2_TASK_PEND) { 17437c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 17447c478bd9Sstevel@tonic-gate return; 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate if (task == ap->a_active_task) { 17487c478bd9Sstevel@tonic-gate ap->a_active_task = NULL; 17497c478bd9Sstevel@tonic-gate } 17507c478bd9Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_NONE; 17517c478bd9Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 17547c478bd9Sstevel@tonic-gate 17557c478bd9Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, task); /* notify the driver */ 17567c478bd9Sstevel@tonic-gate } 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * 17607c478bd9Sstevel@tonic-gate * --- other 17617c478bd9Sstevel@tonic-gate * 17627c478bd9Sstevel@tonic-gate * since mgt agent is shared between LUNs and login sessions, 17637c478bd9Sstevel@tonic-gate * it is safer to serialize mgt requests 17647c478bd9Sstevel@tonic-gate */ 17657c478bd9Sstevel@tonic-gate static void 17667c478bd9Sstevel@tonic-gate sbp2_mgt_agent_acquire(sbp2_tgt_t *tp) 17677c478bd9Sstevel@tonic-gate { 17687c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 17697c478bd9Sstevel@tonic-gate while (tp->t_mgt_agent_acquired) { 17707c478bd9Sstevel@tonic-gate cv_wait(&tp->t_mgt_agent_cv, &tp->t_mutex); 17717c478bd9Sstevel@tonic-gate } 17727c478bd9Sstevel@tonic-gate tp->t_mgt_agent_acquired = B_TRUE; 17737c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 17747c478bd9Sstevel@tonic-gate } 17757c478bd9Sstevel@tonic-gate 17767c478bd9Sstevel@tonic-gate static void 17777c478bd9Sstevel@tonic-gate sbp2_mgt_agent_release(sbp2_tgt_t *tp) 17787c478bd9Sstevel@tonic-gate { 17797c478bd9Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 17807c478bd9Sstevel@tonic-gate tp->t_mgt_agent_acquired = B_FALSE; 17817c478bd9Sstevel@tonic-gate cv_signal(&tp->t_mgt_agent_cv); /* wake next waiter */ 17827c478bd9Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 17837c478bd9Sstevel@tonic-gate } 1784