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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
sbp2_tgt_init(void * bus_hdl,sbp2_bus_t * bus,int maxluns,sbp2_tgt_t ** tpp)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
sbp2_tgt_fini(sbp2_tgt_t * tp)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
sbp2_tgt_init_sobj(sbp2_tgt_t * tp)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
sbp2_tgt_fini_sobj(sbp2_tgt_t * tp)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
sbp2_tgt_init_params(sbp2_tgt_t * tp)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
sbp2_tgt_init_luns(sbp2_tgt_t * tp,int maxluns)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
sbp2_tgt_fini_luns(sbp2_tgt_t * tp)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
sbp2_tgt_init_bus(sbp2_tgt_t * tp)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
sbp2_tgt_fini_bus(sbp2_tgt_t * tp)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
sbp2_tgt_disconnect(sbp2_tgt_t * tp)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
sbp2_tgt_reconnect(sbp2_tgt_t * tp)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
sbp2_tgt_mgt_request(sbp2_tgt_t * tp,int * berr)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
sbp2_tgt_task_mgt_request(sbp2_tgt_t * tp,uint16_t id,int func,uint64_t orbp,int * berr)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
sbp2_tgt_reset(sbp2_tgt_t * tp,int * berr)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
sbp2_tgt_get_cfgrom(sbp2_tgt_t * tp,sbp2_cfgrom_t ** crpp)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
sbp2_tgt_get_lun_cnt(sbp2_tgt_t * tp)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 *
sbp2_tgt_get_lun(sbp2_tgt_t * tp,int num)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
sbp2_lun_reset(sbp2_lun_t * lp,int * berr)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
sbp2_lun_login(sbp2_lun_t * lp,sbp2_ses_t ** spp,void (* cb)(void *,sbp2_task_t *),void * cb_arg,int * berr)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
sbp2_lun_logout(sbp2_lun_t * lp,sbp2_ses_t ** sp,int * berr,boolean_t phys)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
sbp2_lun_logout_orb(sbp2_lun_t * lp,sbp2_tgt_t * tp,int * berr)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
sbp2_lun_accepting_tasks(sbp2_lun_t * lp)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
sbp2_ses_init(sbp2_ses_t ** spp,sbp2_lun_t * lp,void (* cb)(void *,sbp2_task_t *),void * cb_arg)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
sbp2_ses_fini(sbp2_ses_t * sp)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
sbp2_ses_reconnect(sbp2_ses_t * sp,int * berr,uint16_t nodeID)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
sbp2_ses_reconnect_orb(sbp2_ses_t * sp,int * berr)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 *
sbp2_ses_orbp2task(sbp2_ses_t * sp,uint64_t orbp)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
sbp2_ses_submit_task(sbp2_ses_t * sp,sbp2_task_t * new_task)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
sbp2_ses_nudge(sbp2_ses_t * sp)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
sbp2_ses_append_task(sbp2_ses_t * sp,sbp2_task_t * task)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
sbp2_ses_remove_task_locked(sbp2_ses_t * sp,sbp2_task_t * task)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
sbp2_ses_remove_task(sbp2_ses_t * sp,sbp2_task_t * task)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 *
sbp2_ses_find_task_state(sbp2_ses_t * sp,sbp2_task_state_t state)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 *
sbp2_ses_remove_first_task(sbp2_ses_t * sp)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 *
sbp2_ses_remove_first_task_state(sbp2_ses_t * sp,sbp2_task_state_t state)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 *
sbp2_ses_cancel_first_task(sbp2_ses_t * sp)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
sbp2_ses_reset_pending_tasks(sbp2_ses_t * sp,uint16_t nodeID)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
sbp2_ses_agent_reset(sbp2_ses_t * sp,int * berr)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
sbp2_ses_abort_task(sbp2_ses_t * sp,sbp2_task_t * task,int * berr)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
sbp2_ses_abort_task_set(sbp2_ses_t * sp,int * berr)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 *
sbp2_orb_freelist_get(sbp2_lun_t * lp,sbp2_task_t * task,int len)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
sbp2_orb_freelist_put(sbp2_lun_t * lp,sbp2_bus_buf_t * buf)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
sbp2_orb_freelist_destroy(sbp2_lun_t * lp)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
sbp2_task_orb_alloc(sbp2_lun_t * lp,sbp2_task_t * task,int len)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
sbp2_task_orb_free(sbp2_lun_t * lp,sbp2_task_t * task)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 *
sbp2_task_orb_kaddr(sbp2_task_t * task)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
sbp2_task_orb_sync(sbp2_lun_t * lp,sbp2_task_t * task,int flags)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
sbp2_agent_init(sbp2_agent_t * ap,uint64_t offset,sbp2_tgt_t * tp)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
sbp2_agent_fini(sbp2_agent_t * ap)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
sbp2_agent_acquire_locked(sbp2_agent_t * ap)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
sbp2_agent_release_locked(sbp2_agent_t * ap)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
sbp2_agent_acquire(sbp2_agent_t * ap)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
sbp2_agent_release(sbp2_agent_t * ap)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
sbp2_agent_keepalive(sbp2_agent_t * ap,int * berr)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
sbp2_agent_doorbell(sbp2_agent_t * ap,int * berr)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
sbp2_agent_write_orbp(sbp2_agent_t * ap,uint64_t baddr,int * berr)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
sbp2_agent_reset(sbp2_agent_t * ap,int * berr)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
sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t * buf,void * reqh,mblk_t ** bpp)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
sbp2_task_timeout(void * arg)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
sbp2_status_fifo_wb_cb(sbp2_bus_buf_t * buf,void * reqh,mblk_t ** bpp)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
sbp2_mgt_agent_acquire(sbp2_tgt_t * tp)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
sbp2_mgt_agent_release(sbp2_tgt_t * tp)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