10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * SBP2 module 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate #include <sys/param.h> 330Sstevel@tonic-gate #include <sys/errno.h> 340Sstevel@tonic-gate #include <sys/cred.h> 350Sstevel@tonic-gate #include <sys/conf.h> 360Sstevel@tonic-gate #include <sys/modctl.h> 370Sstevel@tonic-gate #include <sys/stat.h> 380Sstevel@tonic-gate #include <sys/stream.h> 390Sstevel@tonic-gate #include <sys/strsubr.h> 400Sstevel@tonic-gate #include <sys/strsun.h> 410Sstevel@tonic-gate #include <sys/ddi.h> 420Sstevel@tonic-gate #include <sys/sunddi.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate #include <sys/sbp2/impl.h> 450Sstevel@tonic-gate #include <sys/1394/ieee1212.h> 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* target routines */ 480Sstevel@tonic-gate static void sbp2_tgt_init_sobj(sbp2_tgt_t *); 490Sstevel@tonic-gate static void sbp2_tgt_fini_sobj(sbp2_tgt_t *); 500Sstevel@tonic-gate static int sbp2_tgt_init_params(sbp2_tgt_t *); 510Sstevel@tonic-gate static int sbp2_tgt_init_luns(sbp2_tgt_t *, int); 520Sstevel@tonic-gate static void sbp2_tgt_fini_luns(sbp2_tgt_t *); 530Sstevel@tonic-gate static int sbp2_tgt_init_bus(sbp2_tgt_t *); 540Sstevel@tonic-gate static void sbp2_tgt_fini_bus(sbp2_tgt_t *); 550Sstevel@tonic-gate static int sbp2_tgt_mgt_request(sbp2_tgt_t *, int *); 560Sstevel@tonic-gate static int sbp2_tgt_task_mgt_request(sbp2_tgt_t *, uint16_t, int, uint64_t, 570Sstevel@tonic-gate int *); 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* lun routines */ 600Sstevel@tonic-gate static void sbp2_lun_logout_orb(sbp2_lun_t *, sbp2_tgt_t *, int *); 610Sstevel@tonic-gate static boolean_t sbp2_lun_accepting_tasks(sbp2_lun_t *); 620Sstevel@tonic-gate 630Sstevel@tonic-gate /* session routines */ 640Sstevel@tonic-gate static int sbp2_ses_init(sbp2_ses_t **, sbp2_lun_t *, 650Sstevel@tonic-gate void (*)(void *, sbp2_task_t *), void *); 660Sstevel@tonic-gate static void sbp2_ses_fini(sbp2_ses_t *); 670Sstevel@tonic-gate static sbp2_task_t *sbp2_ses_orbp2task(sbp2_ses_t *, uint64_t); 680Sstevel@tonic-gate static void sbp2_ses_append_task(sbp2_ses_t *, sbp2_task_t *); 690Sstevel@tonic-gate static void sbp2_ses_reset_pending_tasks(sbp2_ses_t *, uint16_t); 700Sstevel@tonic-gate static int sbp2_ses_reconnect_orb(sbp2_ses_t *, int *); 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* orb alloc routines */ 730Sstevel@tonic-gate static sbp2_bus_buf_t *sbp2_orb_freelist_get(sbp2_lun_t *, sbp2_task_t *, int); 740Sstevel@tonic-gate static int sbp2_orb_freelist_put(sbp2_lun_t *, sbp2_bus_buf_t *); 750Sstevel@tonic-gate static void sbp2_orb_freelist_destroy(sbp2_lun_t *); 760Sstevel@tonic-gate 770Sstevel@tonic-gate /* fetch agent routines */ 780Sstevel@tonic-gate static int sbp2_agent_init(sbp2_agent_t *, uint64_t, sbp2_tgt_t *tp); 790Sstevel@tonic-gate static void sbp2_agent_fini(sbp2_agent_t *); 800Sstevel@tonic-gate static void sbp2_agent_acquire_locked(sbp2_agent_t *); 810Sstevel@tonic-gate static void sbp2_agent_release_locked(sbp2_agent_t *); 820Sstevel@tonic-gate static void sbp2_agent_acquire(sbp2_agent_t *); 830Sstevel@tonic-gate static void sbp2_agent_release(sbp2_agent_t *); 840Sstevel@tonic-gate static int sbp2_agent_keepalive(sbp2_agent_t *, int *); 850Sstevel@tonic-gate static int sbp2_agent_doorbell(sbp2_agent_t *, int *); 860Sstevel@tonic-gate static int sbp2_agent_write_orbp(sbp2_agent_t *, uint64_t, int *); 870Sstevel@tonic-gate static int sbp2_agent_reset(sbp2_agent_t *, int *); 880Sstevel@tonic-gate 890Sstevel@tonic-gate /* callbacks and timeouts */ 900Sstevel@tonic-gate static void sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **); 910Sstevel@tonic-gate static void sbp2_task_timeout(void *); 920Sstevel@tonic-gate static void sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *, void *, mblk_t **); 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* other */ 950Sstevel@tonic-gate static void sbp2_mgt_agent_acquire(sbp2_tgt_t *); 960Sstevel@tonic-gate static void sbp2_mgt_agent_release(sbp2_tgt_t *); 970Sstevel@tonic-gate static void sbp2_fetch_agent_acquire(sbp2_ses_t *); 980Sstevel@tonic-gate static void sbp2_fetch_agent_release(sbp2_ses_t *); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate extern struct mod_ops mod_miscops; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static struct modlmisc sbp2_modlmisc = { 1030Sstevel@tonic-gate &mod_miscops, /* module type */ 1040Sstevel@tonic-gate "Serial Bus Protocol 2 module %I%" /* module name */ 1050Sstevel@tonic-gate }; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static struct modlinkage sbp2_modlinkage = { 1080Sstevel@tonic-gate MODREV_1, (void *)&sbp2_modlmisc, NULL 1090Sstevel@tonic-gate }; 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate /* tunables */ 1120Sstevel@tonic-gate int sbp2_submit_reset_nretries = 3; 1130Sstevel@tonic-gate clock_t sbp2_submit_reset_delay = 10; /* microsec */ 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate int sbp2_write_orbp_nretries = 3; 1160Sstevel@tonic-gate clock_t sbp2_write_orbp_delay = 10; /* microsec */ 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("unique per call", datab msgb)) 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * 1220Sstevel@tonic-gate * --- loadable module entry points 1230Sstevel@tonic-gate * 1240Sstevel@tonic-gate */ 1250Sstevel@tonic-gate int 1260Sstevel@tonic-gate _init(void) 1270Sstevel@tonic-gate { 1280Sstevel@tonic-gate return (mod_install(&sbp2_modlinkage)); 1290Sstevel@tonic-gate } 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate int 1330Sstevel@tonic-gate _fini(void) 1340Sstevel@tonic-gate { 1350Sstevel@tonic-gate return (mod_remove(&sbp2_modlinkage)); 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate int 1400Sstevel@tonic-gate _info(struct modinfo *modinfop) 1410Sstevel@tonic-gate { 1420Sstevel@tonic-gate return (mod_info(&sbp2_modlinkage, modinfop)); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * 1470Sstevel@tonic-gate * --- target routines 1480Sstevel@tonic-gate * 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate int 1510Sstevel@tonic-gate sbp2_tgt_init(void *bus_hdl, sbp2_bus_t *bus, int maxluns, sbp2_tgt_t **tpp) 1520Sstevel@tonic-gate { 1530Sstevel@tonic-gate sbp2_tgt_t *tp; 1540Sstevel@tonic-gate int ret; 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate tp = kmem_zalloc(sizeof (sbp2_tgt_t), KM_SLEEP); 1570Sstevel@tonic-gate tp->t_bus = bus; 1580Sstevel@tonic-gate tp->t_bus_hdl = bus_hdl; 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate sbp2_tgt_init_sobj(tp); 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate if ((ret = sbp2_cfgrom_parse(tp, &tp->t_cfgrom)) != SBP2_SUCCESS) { 1630Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1640Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1650Sstevel@tonic-gate return (SBP2_ECFGROM); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if ((ret = sbp2_tgt_init_params(tp)) != SBP2_SUCCESS) { 1690Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1700Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1710Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1720Sstevel@tonic-gate return (ret); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate if ((ret = sbp2_tgt_init_luns(tp, maxluns)) != SBP2_SUCCESS) { 1760Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1770Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1780Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1790Sstevel@tonic-gate return (ret); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate if ((ret = sbp2_tgt_init_bus(tp)) != SBP2_SUCCESS) { 1830Sstevel@tonic-gate sbp2_tgt_fini_luns(tp); 1840Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 1850Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 1860Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 1870Sstevel@tonic-gate return (ret); 1880Sstevel@tonic-gate } 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate *tpp = tp; 1910Sstevel@tonic-gate return (SBP2_SUCCESS); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate void 1950Sstevel@tonic-gate sbp2_tgt_fini(sbp2_tgt_t *tp) 1960Sstevel@tonic-gate { 1970Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 1980Sstevel@tonic-gate sbp2_tgt_fini_luns(tp); 1990Sstevel@tonic-gate sbp2_cfgrom_free(tp, &tp->t_cfgrom); 2000Sstevel@tonic-gate sbp2_tgt_fini_sobj(tp); 2010Sstevel@tonic-gate kmem_free(tp, sizeof (sbp2_tgt_t)); 2020Sstevel@tonic-gate } 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate static void 2050Sstevel@tonic-gate sbp2_tgt_init_sobj(sbp2_tgt_t *tp) 2060Sstevel@tonic-gate { 2070Sstevel@tonic-gate mutex_init(&tp->t_mutex, NULL, MUTEX_DRIVER, NULL); 2080Sstevel@tonic-gate cv_init(&tp->t_mgt_agent_cv, NULL, CV_DRIVER, NULL); 2090Sstevel@tonic-gate cv_init(&tp->t_mgt_status_cv, NULL, CV_DRIVER, NULL); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate static void 2130Sstevel@tonic-gate sbp2_tgt_fini_sobj(sbp2_tgt_t *tp) 2140Sstevel@tonic-gate { 2150Sstevel@tonic-gate cv_destroy(&tp->t_mgt_status_cv); 2160Sstevel@tonic-gate cv_destroy(&tp->t_mgt_agent_cv); 2170Sstevel@tonic-gate mutex_destroy(&tp->t_mutex); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate static int 2210Sstevel@tonic-gate sbp2_tgt_init_params(sbp2_tgt_t *tp) 2220Sstevel@tonic-gate { 2230Sstevel@tonic-gate sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root; 2240Sstevel@tonic-gate sbp2_cfgrom_ent_t *ent; 2250Sstevel@tonic-gate uint32_t q; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* MANAGEMENT_AGENT */ 2280Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_MGT_AGENT, 2290Sstevel@tonic-gate SBP2_KV_MGT_AGENT, 0)) == NULL) { 2300Sstevel@tonic-gate return (SBP2_ECFGROM); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate tp->t_mgt_agent = SBP2_CSR_BASE(tp) + ent->ce_data.offset * 4; 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* Unit_Characteristics */ 2350Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_UNCHAR, 2360Sstevel@tonic-gate SBP2_KV_UNCHAR, 0)) == NULL) { 2370Sstevel@tonic-gate return (SBP2_ECFGROM); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate q = ent->ce_data.imm; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* units of 500 ms -> ms */ 2420Sstevel@tonic-gate tp->t_mot = ((q & SBP2_UNCHAR_MOT) >> SBP2_UNCHAR_MOT_SHIFT) * 500; 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate /* quadlets -> bytes */ 2450Sstevel@tonic-gate tp->t_orb_size = (q & SBP2_UNCHAR_ORB_SIZE) * 4; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate /* some devices return incorrect values */ 2480Sstevel@tonic-gate if (tp->t_mot < SBP2_MOT_MIN) { 2490Sstevel@tonic-gate tp->t_mot = SBP2_MOT_DFLT; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate if (tp->t_orb_size < SBP2_ORB_SIZE_MIN) { 2520Sstevel@tonic-gate tp->t_orb_size = SBP2_ORB_SIZE_MIN; 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate return (SBP2_SUCCESS); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /*ARGSUSED*/ 2600Sstevel@tonic-gate static int 2610Sstevel@tonic-gate sbp2_tgt_init_luns(sbp2_tgt_t *tp, int maxluns) 2620Sstevel@tonic-gate { 2630Sstevel@tonic-gate sbp2_cfgrom_ent_t *root = &tp->t_cfgrom.cr_root; 2640Sstevel@tonic-gate sbp2_cfgrom_ent_t *ent; 2650Sstevel@tonic-gate sbp2_lun_t *lp; 2660Sstevel@tonic-gate uint32_t q; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate ASSERT(tp->t_nluns == 0); 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate tp->t_lun = kmem_zalloc(maxluns * sizeof (sbp2_lun_t), KM_SLEEP); 2710Sstevel@tonic-gate tp->t_nluns_alloc = maxluns; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* search for Logical_Unit_Number's */ 2740Sstevel@tonic-gate for (tp->t_nluns = 0; tp->t_nluns < maxluns; tp->t_nluns++) { 2750Sstevel@tonic-gate if ((ent = sbp2_cfgrom_ent_by_key(root, SBP2_KT_LUN, 2760Sstevel@tonic-gate SBP2_KV_LUN, tp->t_nluns)) == NULL) { 2770Sstevel@tonic-gate break; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate q = ent->ce_data.imm; 2800Sstevel@tonic-gate lp = &tp->t_lun[tp->t_nluns]; 2810Sstevel@tonic-gate lp->l_tgt = tp; 2820Sstevel@tonic-gate lp->l_lun = q & SBP2_LUN_NUM; 2830Sstevel@tonic-gate lp->l_type = (q & SBP2_LUN_TYPE) >> SBP2_LUN_TYPE_SHIFT; 2840Sstevel@tonic-gate mutex_init(&lp->l_orb_freelist.bl_mutex, NULL, MUTEX_DRIVER, 2850Sstevel@tonic-gate NULL); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate if (tp->t_nluns > 0) { 2890Sstevel@tonic-gate return (SBP2_SUCCESS); 2900Sstevel@tonic-gate } else { 2910Sstevel@tonic-gate kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t)); 2920Sstevel@tonic-gate return (SBP2_ECFGROM); 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate 2980Sstevel@tonic-gate static void 2990Sstevel@tonic-gate sbp2_tgt_fini_luns(sbp2_tgt_t *tp) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate int i; 3020Sstevel@tonic-gate sbp2_lun_t *lp; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* destroy each lun */ 3050Sstevel@tonic-gate for (i = 0; i < tp->t_nluns; i++) { 3060Sstevel@tonic-gate lp = &tp->t_lun[i]; 3070Sstevel@tonic-gate sbp2_orb_freelist_destroy(lp); 3080Sstevel@tonic-gate mutex_destroy(&lp->l_orb_freelist.bl_mutex); 3090Sstevel@tonic-gate } 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate kmem_free(tp->t_lun, tp->t_nluns_alloc * sizeof (sbp2_lun_t)); 3120Sstevel@tonic-gate } 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * initialize bus buffers and commands 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate static int 3180Sstevel@tonic-gate sbp2_tgt_init_bus(sbp2_tgt_t *tp) 3190Sstevel@tonic-gate { 3200Sstevel@tonic-gate int ret; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * We serialize management requests and reuse the same buffers. 3240Sstevel@tonic-gate * 3250Sstevel@tonic-gate * mgt ORB 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate tp->t_mgt_orb_buf.bb_len = 3280Sstevel@tonic-gate SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_mgt_orb_t)); 3290Sstevel@tonic-gate tp->t_mgt_orb_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD; 3300Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_orb_buf)) != SBP2_SUCCESS) { 3310Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3320Sstevel@tonic-gate return (ret); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate /* 3360Sstevel@tonic-gate * mgt status FIFO 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_len = sizeof (sbp2_status_t); 3390Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED; 3400Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_wb_cb = sbp2_mgt_status_fifo_wb_cb; 3410Sstevel@tonic-gate tp->t_mgt_status_fifo_buf.bb_sbp2_priv = tp; 3420Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_status_fifo_buf)) != 3430Sstevel@tonic-gate SBP2_SUCCESS) { 3440Sstevel@tonic-gate return (ret); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate /* 3480Sstevel@tonic-gate * login response 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate tp->t_mgt_login_resp_buf.bb_len = 3510Sstevel@tonic-gate SBP2_ORB_SIZE_ROUNDUP(tp, sizeof (sbp2_login_resp_t)); 3520Sstevel@tonic-gate /* 3530Sstevel@tonic-gate * read-only should have been sufficient here, but it causes 3540Sstevel@tonic-gate * DVMA errors on Grover, while read/write works just fine 3550Sstevel@tonic-gate */ 3560Sstevel@tonic-gate tp->t_mgt_login_resp_buf.bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RW; 3570Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &tp->t_mgt_login_resp_buf)) != 3580Sstevel@tonic-gate SBP2_SUCCESS) { 3590Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3600Sstevel@tonic-gate return (ret); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate /* 3640Sstevel@tonic-gate * allocate bus commands 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate if ((ret = SBP2_ALLOC_CMD(tp, &tp->t_mgt_cmd, 0)) != SBP2_SUCCESS) { 3670Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3680Sstevel@tonic-gate return (ret); 3690Sstevel@tonic-gate } 3700Sstevel@tonic-gate if ((tp->t_mgt_cmd_data = allocb(8, BPRI_HI)) == NULL) { 3710Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 3720Sstevel@tonic-gate return (SBP2_ENOMEM); 3730Sstevel@tonic-gate } 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate return (SBP2_SUCCESS); 3760Sstevel@tonic-gate } 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate static void 3790Sstevel@tonic-gate sbp2_tgt_fini_bus(sbp2_tgt_t *tp) 3800Sstevel@tonic-gate { 3810Sstevel@tonic-gate if (tp->t_mgt_status_fifo_buf.bb_hdl != NULL) { 3820Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_status_fifo_buf); 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate if (tp->t_mgt_orb_buf.bb_hdl != NULL) { 3850Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_orb_buf); 3860Sstevel@tonic-gate } 3870Sstevel@tonic-gate if (tp->t_mgt_login_resp_buf.bb_hdl != NULL) { 3880Sstevel@tonic-gate SBP2_FREE_BUF(tp, &tp->t_mgt_login_resp_buf); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate if (tp->t_mgt_cmd) { 3910Sstevel@tonic-gate SBP2_FREE_CMD(tp, tp->t_mgt_cmd); 392*276Sartem tp->t_mgt_cmd = NULL; 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate if (tp->t_mgt_cmd_data) { 3950Sstevel@tonic-gate freeb(tp->t_mgt_cmd_data); 396*276Sartem tp->t_mgt_cmd_data = NULL; 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate } 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate void 4010Sstevel@tonic-gate sbp2_tgt_disconnect(sbp2_tgt_t *tp) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate sbp2_tgt_fini_bus(tp); 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate int 4070Sstevel@tonic-gate sbp2_tgt_reconnect(sbp2_tgt_t *tp) 4080Sstevel@tonic-gate { 4090Sstevel@tonic-gate return (sbp2_tgt_init_bus(tp)); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * send mgt ORB and wait for status 4140Sstevel@tonic-gate * 4150Sstevel@tonic-gate * mgt agent should be acquired 4160Sstevel@tonic-gate */ 4170Sstevel@tonic-gate static int 4180Sstevel@tonic-gate sbp2_tgt_mgt_request(sbp2_tgt_t *tp, int *berr) 4190Sstevel@tonic-gate { 4200Sstevel@tonic-gate clock_t until; 4210Sstevel@tonic-gate int ret; 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_FALSE; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate /* write ORB address into MANAGEMENT_AGENT */ 4260Sstevel@tonic-gate SBP2_ADDR_SET(tp->t_mgt_cmd_data->b_rptr, tp->t_mgt_orb_buf.bb_baddr, 4270Sstevel@tonic-gate 0); 4280Sstevel@tonic-gate tp->t_mgt_cmd_data->b_wptr = tp->t_mgt_cmd_data->b_rptr + 8; 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate if ((ret = SBP2_WB(tp, tp->t_mgt_cmd, tp->t_mgt_agent, 4310Sstevel@tonic-gate tp->t_mgt_cmd_data, 8, berr)) != SBP2_SUCCESS) { 4320Sstevel@tonic-gate return (ret); 4330Sstevel@tonic-gate } 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate /* wait for login response */ 4360Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 4370Sstevel@tonic-gate until = ddi_get_lbolt() + drv_usectohz(tp->t_mot * 1000); 4380Sstevel@tonic-gate ret = 1; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate while (!tp->t_mgt_status_rcvd && (ret > 0)) { 4410Sstevel@tonic-gate ret = cv_timedwait(&tp->t_mgt_status_cv, &tp->t_mutex, until); 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (!tp->t_mgt_status_rcvd) { 4450Sstevel@tonic-gate ret = SBP2_ETIMEOUT; 4460Sstevel@tonic-gate } else if ((tp->t_mgt_status.st_param & SBP2_ST_RESP) == 4470Sstevel@tonic-gate SBP2_ST_RESP_COMPLETE) { 4480Sstevel@tonic-gate ret = SBP2_SUCCESS; 4490Sstevel@tonic-gate } else { 4500Sstevel@tonic-gate ret = SBP2_FAILURE; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate return (ret); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate /* 4580Sstevel@tonic-gate * Send task management request, one of: 4590Sstevel@tonic-gate * 4600Sstevel@tonic-gate * ABORT TASK, ABORT TASK SET, LOGICAL UNIT RESET, TARGET RESET 4610Sstevel@tonic-gate */ 4620Sstevel@tonic-gate static int 4630Sstevel@tonic-gate sbp2_tgt_task_mgt_request(sbp2_tgt_t *tp, uint16_t id, int func, uint64_t orbp, 4640Sstevel@tonic-gate int *berr) 4650Sstevel@tonic-gate { 4660Sstevel@tonic-gate sbp2_task_mgt_orb_t *torb; 4670Sstevel@tonic-gate int ret; 4680Sstevel@tonic-gate 4690Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate torb = (sbp2_task_mgt_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 4720Sstevel@tonic-gate bzero(torb, sizeof (sbp2_task_mgt_orb_t)); 4730Sstevel@tonic-gate SBP2_ORBP_SET(torb->to_orb, orbp); 4740Sstevel@tonic-gate torb->to_params = SBP2_SWAP16(func | SBP2_ORB_NOTIFY | 4750Sstevel@tonic-gate SBP2_ORB_RQ_FMT_SBP2); 4760Sstevel@tonic-gate torb->to_login_id = SBP2_SWAP16(id); 4770Sstevel@tonic-gate SBP2_ADDR_SET(torb->to_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 4780Sstevel@tonic-gate 0); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate ret = sbp2_tgt_mgt_request(tp, berr); 4810Sstevel@tonic-gate 4820Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate return (ret); 4850Sstevel@tonic-gate } 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate int 4880Sstevel@tonic-gate sbp2_tgt_reset(sbp2_tgt_t *tp, int *berr) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate sbp2_lun_t *lp = &tp->t_lun[0]; 4910Sstevel@tonic-gate int ret; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* issue TARGET RESET */ 4940Sstevel@tonic-gate if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 4950Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_TARGET_RESET, 0, berr)) != SBP2_SUCCESS) { 4960Sstevel@tonic-gate return (ret); 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate return (SBP2_SUCCESS); 5000Sstevel@tonic-gate } 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate int 5030Sstevel@tonic-gate sbp2_tgt_get_cfgrom(sbp2_tgt_t *tp, sbp2_cfgrom_t **crpp) 5040Sstevel@tonic-gate { 5050Sstevel@tonic-gate *crpp = &tp->t_cfgrom; 5060Sstevel@tonic-gate return (SBP2_SUCCESS); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate int 5100Sstevel@tonic-gate sbp2_tgt_get_lun_cnt(sbp2_tgt_t *tp) 5110Sstevel@tonic-gate { 5120Sstevel@tonic-gate return (tp->t_nluns); 5130Sstevel@tonic-gate } 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate sbp2_lun_t * 5160Sstevel@tonic-gate sbp2_tgt_get_lun(sbp2_tgt_t *tp, int num) 5170Sstevel@tonic-gate { 5180Sstevel@tonic-gate if (num < tp->t_nluns) { 5190Sstevel@tonic-gate return (&tp->t_lun[num]); 5200Sstevel@tonic-gate } else { 5210Sstevel@tonic-gate return (NULL); 5220Sstevel@tonic-gate } 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate /* 5260Sstevel@tonic-gate * 5270Sstevel@tonic-gate * --- lun routines 5280Sstevel@tonic-gate * 5290Sstevel@tonic-gate */ 5300Sstevel@tonic-gate int 5310Sstevel@tonic-gate sbp2_lun_reset(sbp2_lun_t *lp, int *berr) 5320Sstevel@tonic-gate { 5330Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 5340Sstevel@tonic-gate sbp2_ses_t *sp = lp->l_ses; 5350Sstevel@tonic-gate sbp2_task_t *task = NULL; 5360Sstevel@tonic-gate int ret; 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate /* issue LOGICAL UNIT RESET */ 5390Sstevel@tonic-gate if ((ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 5400Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_LUN_RESET, 0, berr)) != SBP2_SUCCESS) { 5410Sstevel@tonic-gate return (ret); 5420Sstevel@tonic-gate } 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* mark all pending tasks reset and notify the driver */ 5450Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 5460Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 5470Sstevel@tonic-gate if (task->ts_state < SBP2_TASK_COMP) { 5480Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_LUN_RESET; 5490Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, NULL); 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate return (SBP2_SUCCESS); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate int 5600Sstevel@tonic-gate sbp2_lun_login(sbp2_lun_t *lp, sbp2_ses_t **spp, 5610Sstevel@tonic-gate void (*cb)(void *, sbp2_task_t *), void *cb_arg, int *berr) 5620Sstevel@tonic-gate { 5630Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 5640Sstevel@tonic-gate sbp2_ses_t *sp; 5650Sstevel@tonic-gate sbp2_login_orb_t *lorb; 5660Sstevel@tonic-gate int ret; 5670Sstevel@tonic-gate 5680Sstevel@tonic-gate if (cb == NULL) { 5690Sstevel@tonic-gate return (SBP2_EINVAL); 5700Sstevel@tonic-gate } 5710Sstevel@tonic-gate 5720Sstevel@tonic-gate /* multiple sessions not supported yet */ 5730Sstevel@tonic-gate if (lp->l_ses != NULL) { 5740Sstevel@tonic-gate return (SBP2_EALREADY); 5750Sstevel@tonic-gate } 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if ((ret = sbp2_ses_init(&sp, lp, cb, cb_arg)) != SBP2_SUCCESS) { 5780Sstevel@tonic-gate return (ret); 5790Sstevel@tonic-gate } 5800Sstevel@tonic-gate lp->l_ses = sp; 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate /* prepare login ORB */ 5850Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 5860Sstevel@tonic-gate lorb = (sbp2_login_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 5870Sstevel@tonic-gate bzero(lorb, sizeof (sbp2_login_orb_t)); 5880Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_resp, tp->t_mgt_login_resp_buf.bb_baddr, 0); 5890Sstevel@tonic-gate lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGIN | 5900Sstevel@tonic-gate SBP2_ORB_LOGIN_EXCL | SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 5910Sstevel@tonic-gate lorb->lo_lun = SBP2_SWAP16(lp->l_lun); 5920Sstevel@tonic-gate lorb->lo_resp_len = SBP2_SWAP16(tp->t_mgt_login_resp_buf.bb_len); 5930Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_status_fifo, sp->s_status_fifo_buf.bb_baddr, 0); 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate bzero(tp->t_mgt_login_resp_buf.bb_kaddr, sizeof (sbp2_login_resp_t)); 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 5980Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* send request */ 6010Sstevel@tonic-gate if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) { 6020Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 6030Sstevel@tonic-gate sbp2_ses_fini(lp->l_ses); 6040Sstevel@tonic-gate lp->l_ses = NULL; 6050Sstevel@tonic-gate return (ret); 6060Sstevel@tonic-gate } 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* retrieve response data (XXX sanity checks?) */ 6090Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6100Sstevel@tonic-gate (void) SBP2_SYNC_BUF(tp, &tp->t_mgt_login_resp_buf, 0, 0, 6110Sstevel@tonic-gate DDI_DMA_SYNC_FORKERNEL); 6120Sstevel@tonic-gate bcopy(tp->t_mgt_login_resp_buf.bb_kaddr, &lp->l_login_resp, 6130Sstevel@tonic-gate sizeof (sbp2_login_resp_t)); 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate /* convert from BE to native endianness */ 6160Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_len); 6170Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_login_id); 6180Sstevel@tonic-gate SBP2_SWAP32_2(lp->l_login_resp.lr_cmd_agent); 6190Sstevel@tonic-gate SBP2_SWAP16_1(lp->l_login_resp.lr_reconnect_hold); 6200Sstevel@tonic-gate lp->l_login_resp.lr_reconnect_hold++; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate sp->s_agent_offset = SBP2_ADDR2UINT64(lp->l_login_resp.lr_cmd_agent); 6230Sstevel@tonic-gate 6240Sstevel@tonic-gate lp->l_logged_in = B_TRUE; 6250Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate if ((ret = sbp2_agent_init(&sp->s_agent, sp->s_agent_offset, tp)) != 6300Sstevel@tonic-gate SBP2_SUCCESS) { 6310Sstevel@tonic-gate sbp2_ses_fini(sp); 6320Sstevel@tonic-gate lp->l_ses = NULL; 6330Sstevel@tonic-gate return (ret); 6340Sstevel@tonic-gate } 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate *spp = lp->l_ses; 6370Sstevel@tonic-gate return (SBP2_SUCCESS); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate 6400Sstevel@tonic-gate /*ARGSUSED*/ 6410Sstevel@tonic-gate int 6420Sstevel@tonic-gate sbp2_lun_logout(sbp2_lun_t *lp, sbp2_ses_t **sp, int *berr, boolean_t phys) 6430Sstevel@tonic-gate { 6440Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 6450Sstevel@tonic-gate 6460Sstevel@tonic-gate ASSERT(*sp == lp->l_ses); 6470Sstevel@tonic-gate 6480Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6490Sstevel@tonic-gate if (lp->l_logged_in) { 6500Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 6510Sstevel@tonic-gate /* do physical LOGOUT if requested */ 6520Sstevel@tonic-gate if (phys) { 6530Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6540Sstevel@tonic-gate sbp2_lun_logout_orb(lp, tp, berr); 6550Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 6560Sstevel@tonic-gate } 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate sbp2_agent_fini(&lp->l_ses->s_agent); 6600Sstevel@tonic-gate sbp2_ses_fini(lp->l_ses); 6610Sstevel@tonic-gate lp->l_ses = NULL; 6620Sstevel@tonic-gate *sp = NULL; 6630Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate return (SBP2_SUCCESS); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate /* 6690Sstevel@tonic-gate * Issue LOGOUT mgt orb and wait for response. We are not interested in 6700Sstevel@tonic-gate * the success at the time, since the device may be disconnected or hung, 6710Sstevel@tonic-gate * just trying to make the best effort. 6720Sstevel@tonic-gate */ 6730Sstevel@tonic-gate static void 6740Sstevel@tonic-gate sbp2_lun_logout_orb(sbp2_lun_t *lp, sbp2_tgt_t *tp, int *berr) 6750Sstevel@tonic-gate { 6760Sstevel@tonic-gate sbp2_logout_orb_t *lorb; 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 6790Sstevel@tonic-gate 6800Sstevel@tonic-gate /* prepare logout ORB */ 6810Sstevel@tonic-gate lorb = (sbp2_logout_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 6820Sstevel@tonic-gate bzero(lorb, sizeof (sbp2_logout_orb_t)); 6830Sstevel@tonic-gate lorb->lo_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_LOGOUT | 6840Sstevel@tonic-gate SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 6850Sstevel@tonic-gate lorb->lo_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id); 6860Sstevel@tonic-gate SBP2_ADDR_SET(lorb->lo_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 6870Sstevel@tonic-gate 0); 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate /* send request */ 6900Sstevel@tonic-gate (void) sbp2_tgt_mgt_request(tp, berr); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 6930Sstevel@tonic-gate } 6940Sstevel@tonic-gate 6950Sstevel@tonic-gate static boolean_t 6960Sstevel@tonic-gate sbp2_lun_accepting_tasks(sbp2_lun_t *lp) 6970Sstevel@tonic-gate { 6980Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 6990Sstevel@tonic-gate boolean_t ret; 7000Sstevel@tonic-gate 7010Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 7020Sstevel@tonic-gate ret = ((lp->l_ses != NULL) && lp->l_logged_in && !lp->l_reconnecting); 7030Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 7040Sstevel@tonic-gate return (ret); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate /* 7080Sstevel@tonic-gate * 7090Sstevel@tonic-gate * --- session routines 7100Sstevel@tonic-gate * 7110Sstevel@tonic-gate */ 7120Sstevel@tonic-gate static int 7130Sstevel@tonic-gate sbp2_ses_init(sbp2_ses_t **spp, sbp2_lun_t *lp, 7140Sstevel@tonic-gate void (*cb)(void *, sbp2_task_t *), void *cb_arg) 7150Sstevel@tonic-gate { 7160Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 7170Sstevel@tonic-gate sbp2_ses_t *sp; 7180Sstevel@tonic-gate int ret; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate sp = kmem_zalloc(sizeof (sbp2_ses_t), KM_SLEEP); 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate sp->s_tgt = tp; 7230Sstevel@tonic-gate sp->s_lun = lp; 7240Sstevel@tonic-gate sp->s_status_cb = cb; 7250Sstevel@tonic-gate sp->s_status_cb_arg = cb_arg; 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate mutex_init(&sp->s_mutex, NULL, MUTEX_DRIVER, 7280Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 7290Sstevel@tonic-gate mutex_init(&sp->s_task_mutex, NULL, MUTEX_DRIVER, 7300Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * status FIFO for block requests 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate sp->s_status_fifo_buf.bb_len = sizeof (sbp2_status_t); 7360Sstevel@tonic-gate sp->s_status_fifo_buf.bb_flags = SBP2_BUS_BUF_WR_POSTED; 7370Sstevel@tonic-gate sp->s_status_fifo_buf.bb_wb_cb = sbp2_status_fifo_wb_cb; 7380Sstevel@tonic-gate sp->s_status_fifo_buf.bb_sbp2_priv = sp; 7390Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, &sp->s_status_fifo_buf)) != 7400Sstevel@tonic-gate SBP2_SUCCESS) { 7410Sstevel@tonic-gate sbp2_ses_fini(sp); 7420Sstevel@tonic-gate return (ret); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate *spp = sp; 7460Sstevel@tonic-gate return (SBP2_SUCCESS); 7470Sstevel@tonic-gate } 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate static void 7510Sstevel@tonic-gate sbp2_ses_fini(sbp2_ses_t *sp) 7520Sstevel@tonic-gate { 7530Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_lun->l_tgt; 7540Sstevel@tonic-gate 7550Sstevel@tonic-gate if (sp->s_status_fifo_buf.bb_hdl != NULL) { 7560Sstevel@tonic-gate SBP2_FREE_BUF(tp, &sp->s_status_fifo_buf); 7570Sstevel@tonic-gate } 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate mutex_destroy(&sp->s_task_mutex); 7600Sstevel@tonic-gate mutex_destroy(&sp->s_mutex); 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate kmem_free(sp, sizeof (sbp2_ses_t)); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate int 7660Sstevel@tonic-gate sbp2_ses_reconnect(sbp2_ses_t *sp, int *berr, uint16_t nodeID) 7670Sstevel@tonic-gate { 7680Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 7690Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 7700Sstevel@tonic-gate int ret; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* prevent new tasks from being submitted */ 7730Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 7740Sstevel@tonic-gate lp->l_reconnecting = B_TRUE; 7750Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* 7780Sstevel@tonic-gate * From 10.5 Task management event matrix: 7790Sstevel@tonic-gate * Immediately upon detection of a bus reset, all command 7800Sstevel@tonic-gate * block fetch agents transition to the reset state and 7810Sstevel@tonic-gate * their associated task sets are cleared without 7820Sstevel@tonic-gate * the return of completion status. 7830Sstevel@tonic-gate * 7840Sstevel@tonic-gate * Reset pending tasks so we can retry them later. 7850Sstevel@tonic-gate */ 7860Sstevel@tonic-gate sbp2_ses_reset_pending_tasks(sp, nodeID); 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate ret = sbp2_ses_reconnect_orb(sp, berr); 7890Sstevel@tonic-gate 7900Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 7910Sstevel@tonic-gate lp->l_reconnecting = B_FALSE; 7920Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 7930Sstevel@tonic-gate 7940Sstevel@tonic-gate return (ret); 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate /* 7980Sstevel@tonic-gate * Send reconnect ORB. If operation fails, set lp->l_logged_in = B_FALSE. 7990Sstevel@tonic-gate */ 8000Sstevel@tonic-gate static int 8010Sstevel@tonic-gate sbp2_ses_reconnect_orb(sbp2_ses_t *sp, int *berr) 8020Sstevel@tonic-gate { 8030Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 8040Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 8050Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 8060Sstevel@tonic-gate sbp2_reconnect_orb_t *rorb; 8070Sstevel@tonic-gate int ret; 8080Sstevel@tonic-gate 8090Sstevel@tonic-gate sbp2_mgt_agent_acquire(tp); 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate /* prepare login ORB */ 8120Sstevel@tonic-gate rorb = (sbp2_reconnect_orb_t *)tp->t_mgt_orb_buf.bb_kaddr; 8130Sstevel@tonic-gate bzero(rorb, sizeof (sbp2_reconnect_orb_t)); 8140Sstevel@tonic-gate rorb->ro_params = SBP2_SWAP16(SBP2_ORB_MGT_FUNC_RECONNECT | 8150Sstevel@tonic-gate SBP2_ORB_NOTIFY | SBP2_ORB_RQ_FMT_SBP2); 8160Sstevel@tonic-gate rorb->ro_login_id = SBP2_SWAP16(lp->l_login_resp.lr_login_id); 8170Sstevel@tonic-gate SBP2_ADDR_SET(rorb->ro_status_fifo, tp->t_mgt_status_fifo_buf.bb_baddr, 8180Sstevel@tonic-gate 0); 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate /* send request */ 8210Sstevel@tonic-gate if ((ret = sbp2_tgt_mgt_request(tp, berr)) != SBP2_SUCCESS) { 8220Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 8230Sstevel@tonic-gate lp->l_logged_in = B_FALSE; 8240Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 8250Sstevel@tonic-gate } else { 8260Sstevel@tonic-gate /* after successful reset fetch agent is in RESET state */ 8270Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 8280Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 8290Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 8300Sstevel@tonic-gate } 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate sbp2_mgt_agent_release(tp); 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate return (ret); 8350Sstevel@tonic-gate } 8360Sstevel@tonic-gate 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate static sbp2_task_t * 8390Sstevel@tonic-gate sbp2_ses_orbp2task(sbp2_ses_t *sp, uint64_t orbp) 8400Sstevel@tonic-gate { 8410Sstevel@tonic-gate sbp2_task_t *task; 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 8440Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 8450Sstevel@tonic-gate if (task->ts_buf->bb_baddr == orbp) { 8460Sstevel@tonic-gate break; 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 8500Sstevel@tonic-gate return (task); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate /* 8540Sstevel@tonic-gate * This is where tasks (command ORB's) are signalled to the target. 8550Sstevel@tonic-gate * 'task' argument is allowed to be NULL, in which case the task will be 8560Sstevel@tonic-gate * taken from the current task list. 8570Sstevel@tonic-gate * 8580Sstevel@tonic-gate * Tasks are signalled one at a time by writing into ORB_POINTER register. 8590Sstevel@tonic-gate * While SBP-2 allows dynamic task list updates and using DOORBELL register, 8600Sstevel@tonic-gate * some devices have bugs that prevent using this strategy: e.g. some LaCie 8610Sstevel@tonic-gate * HDD's can corrupt data. Data integrity is more important than performance. 8620Sstevel@tonic-gate */ 8630Sstevel@tonic-gate int 8640Sstevel@tonic-gate sbp2_ses_submit_task(sbp2_ses_t *sp, sbp2_task_t *new_task) 8650Sstevel@tonic-gate { 8660Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 8670Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 8680Sstevel@tonic-gate sbp2_task_t *task; /* task actually being submitted */ 8690Sstevel@tonic-gate boolean_t callback; 8700Sstevel@tonic-gate timeout_id_t timeout_id; 8710Sstevel@tonic-gate int ret; 8720Sstevel@tonic-gate 8730Sstevel@tonic-gate if (!sbp2_lun_accepting_tasks(sp->s_lun)) { 8740Sstevel@tonic-gate return (SBP2_ENODEV); 8750Sstevel@tonic-gate } 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate sbp2_agent_acquire(ap); /* serialize */ 8780Sstevel@tonic-gate 8790Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate /* if task provided, append it to the list */ 8820Sstevel@tonic-gate if (new_task != NULL) { 8830Sstevel@tonic-gate ASSERT(new_task->ts_state == SBP2_TASK_INIT); 8840Sstevel@tonic-gate sbp2_ses_append_task(sp, new_task); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate /* if there is already a task in flight, exit */ 8880Sstevel@tonic-gate if ((ap->a_active_task != NULL) && 8890Sstevel@tonic-gate (ap->a_active_task->ts_state == SBP2_TASK_PEND)) { 8900Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 8910Sstevel@tonic-gate sbp2_agent_release(ap); 8920Sstevel@tonic-gate return (SBP2_SUCCESS); 8930Sstevel@tonic-gate } 8940Sstevel@tonic-gate 8950Sstevel@tonic-gate /* no active task, grab the first one on the list in INIT state */ 8960Sstevel@tonic-gate ap->a_active_task = sbp2_ses_find_task_state(sp, SBP2_TASK_INIT); 8970Sstevel@tonic-gate if (ap->a_active_task == NULL) { 8980Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 8990Sstevel@tonic-gate sbp2_agent_release(ap); 9000Sstevel@tonic-gate return (SBP2_SUCCESS); 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate task = ap->a_active_task; 9030Sstevel@tonic-gate task->ts_ses = sp; 9040Sstevel@tonic-gate task->ts_state = SBP2_TASK_PEND; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate /* can't work with a dead agent */ 9070Sstevel@tonic-gate if (sbp2_agent_keepalive(ap, &task->ts_bus_error) != SBP2_SUCCESS) { 9080Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_DEAD; 9090Sstevel@tonic-gate goto error; 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate /* 9130Sstevel@tonic-gate * In theory, we should schedule task timeout after it's been submitted. 9140Sstevel@tonic-gate * However, some fast tasks complete even before timeout is scheduled. 9150Sstevel@tonic-gate * To avoid additional complications in the code, schedule timeout now. 9160Sstevel@tonic-gate */ 9170Sstevel@tonic-gate ASSERT(task->ts_timeout_id == 0); 9180Sstevel@tonic-gate task->ts_time_start = gethrtime(); 9190Sstevel@tonic-gate if (task->ts_timeout > 0) { 9200Sstevel@tonic-gate task->ts_timeout_id = timeout(sbp2_task_timeout, task, 9210Sstevel@tonic-gate task->ts_timeout * drv_usectohz(1000000)); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate 9240Sstevel@tonic-gate /* notify fetch agent */ 9250Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_ACTIVE; 9260Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9270Sstevel@tonic-gate ret = sbp2_agent_write_orbp(ap, task->ts_buf->bb_baddr, 9280Sstevel@tonic-gate &task->ts_bus_error); 9290Sstevel@tonic-gate tp->t_stat.stat_submit_orbp++; 9300Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 9310Sstevel@tonic-gate 9320Sstevel@tonic-gate if (ret != SBP2_SUCCESS) { 9330Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 9340Sstevel@tonic-gate tp->t_stat.stat_status_dead++; 9350Sstevel@tonic-gate 9360Sstevel@tonic-gate if (task->ts_timeout_id != 0) { 9370Sstevel@tonic-gate timeout_id = task->ts_timeout_id; 9380Sstevel@tonic-gate task->ts_timeout_id = 0; 9390Sstevel@tonic-gate (void) untimeout(timeout_id); 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_BUS; 9420Sstevel@tonic-gate goto error; 9430Sstevel@tonic-gate } 9440Sstevel@tonic-gate 9450Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate sbp2_agent_release(ap); 9480Sstevel@tonic-gate return (SBP2_SUCCESS); 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate error: 9510Sstevel@tonic-gate /* 9520Sstevel@tonic-gate * Return immediate error if failed task is the one being submitted, 9530Sstevel@tonic-gate * otherwise use callback. 9540Sstevel@tonic-gate */ 9550Sstevel@tonic-gate callback = (ap->a_active_task != new_task); 956*276Sartem ASSERT(task == ap->a_active_task); 9570Sstevel@tonic-gate ap->a_active_task = NULL; 9580Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 9590Sstevel@tonic-gate sbp2_agent_release(ap); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate /* 9620Sstevel@tonic-gate * Remove task from the list. It is important not to change task state 9630Sstevel@tonic-gate * to SBP2_TASK_COMP while it's still on the list, to avoid race with 9640Sstevel@tonic-gate * upper layer driver (e.g. scsa1394). 9650Sstevel@tonic-gate */ 966*276Sartem ret = sbp2_ses_remove_task(sp, task); 9670Sstevel@tonic-gate ASSERT(ret == SBP2_SUCCESS); 968*276Sartem task->ts_state = SBP2_TASK_COMP; 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate if (callback) { 971*276Sartem sp->s_status_cb(sp->s_status_cb_arg, task); 9720Sstevel@tonic-gate return (SBP2_SUCCESS); 9730Sstevel@tonic-gate } else { 9740Sstevel@tonic-gate /* upper layer driver is responsible to call nudge */ 9750Sstevel@tonic-gate return (SBP2_FAILURE); 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate } 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate void 9800Sstevel@tonic-gate sbp2_ses_nudge(sbp2_ses_t *sp) 9810Sstevel@tonic-gate { 9820Sstevel@tonic-gate (void) sbp2_ses_submit_task(sp, NULL); 9830Sstevel@tonic-gate } 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate /* 9860Sstevel@tonic-gate * append task to the task list 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate static void 9890Sstevel@tonic-gate sbp2_ses_append_task(sbp2_ses_t *sp, sbp2_task_t *task) 9900Sstevel@tonic-gate { 9910Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 9940Sstevel@tonic-gate if (sp->s_task_head == NULL) { 9950Sstevel@tonic-gate ASSERT(sp->s_task_tail == NULL); 9960Sstevel@tonic-gate ASSERT(sp->s_task_cnt == 0); 9970Sstevel@tonic-gate task->ts_prev = task->ts_next = NULL; 9980Sstevel@tonic-gate sp->s_task_head = sp->s_task_tail = task; 9990Sstevel@tonic-gate } else { 10000Sstevel@tonic-gate ASSERT(sp->s_task_cnt > 0); 10010Sstevel@tonic-gate task->ts_next = NULL; 10020Sstevel@tonic-gate task->ts_prev = sp->s_task_tail; 10030Sstevel@tonic-gate sp->s_task_tail->ts_next = task; 10040Sstevel@tonic-gate sp->s_task_tail = task; 10050Sstevel@tonic-gate } 10060Sstevel@tonic-gate ASSERT(task != task->ts_prev); 10070Sstevel@tonic-gate ASSERT(task != task->ts_next); 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate sp->s_task_cnt++; 10100Sstevel@tonic-gate if (sp->s_task_cnt > tp->t_stat.stat_task_max) { 10110Sstevel@tonic-gate tp->t_stat.stat_task_max = sp->s_task_cnt; 10120Sstevel@tonic-gate } 10130Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10140Sstevel@tonic-gate } 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate /* 10170Sstevel@tonic-gate * remove task from the task list 10180Sstevel@tonic-gate */ 10190Sstevel@tonic-gate static int 10200Sstevel@tonic-gate sbp2_ses_remove_task_locked(sbp2_ses_t *sp, sbp2_task_t *task) 10210Sstevel@tonic-gate { 10220Sstevel@tonic-gate sp->s_task_cnt--; 10230Sstevel@tonic-gate if (task == sp->s_task_head) { /* first */ 10240Sstevel@tonic-gate ASSERT(task->ts_prev == NULL); 10250Sstevel@tonic-gate if (task->ts_next == NULL) { /* and last */ 10260Sstevel@tonic-gate ASSERT(sp->s_task_cnt == 0); 10270Sstevel@tonic-gate sp->s_task_head = sp->s_task_tail = NULL; 10280Sstevel@tonic-gate } else { /* but not last */ 10290Sstevel@tonic-gate sp->s_task_head = task->ts_next; 10300Sstevel@tonic-gate sp->s_task_head->ts_prev = NULL; 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate } else if (task == sp->s_task_tail) { /* last but not first */ 10330Sstevel@tonic-gate ASSERT(task->ts_next == NULL); 10340Sstevel@tonic-gate sp->s_task_tail = task->ts_prev; 10350Sstevel@tonic-gate sp->s_task_tail->ts_next = NULL; 10360Sstevel@tonic-gate } else { /* in the middle */ 10370Sstevel@tonic-gate task->ts_prev->ts_next = task->ts_next; 10380Sstevel@tonic-gate task->ts_next->ts_prev = task->ts_prev; 10390Sstevel@tonic-gate } 10400Sstevel@tonic-gate task->ts_prev = task->ts_next = NULL; 10410Sstevel@tonic-gate ASSERT(sp->s_task_cnt >= 0); 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate return (SBP2_SUCCESS); 10440Sstevel@tonic-gate } 10450Sstevel@tonic-gate 10460Sstevel@tonic-gate int 10470Sstevel@tonic-gate sbp2_ses_remove_task(sbp2_ses_t *sp, sbp2_task_t *task) 10480Sstevel@tonic-gate { 10490Sstevel@tonic-gate int ret; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10520Sstevel@tonic-gate ret = sbp2_ses_remove_task_locked(sp, task); 10530Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate return (ret); 10560Sstevel@tonic-gate } 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate /* 10590Sstevel@tonic-gate * Return first task on the list in specified state. 10600Sstevel@tonic-gate */ 10610Sstevel@tonic-gate sbp2_task_t * 10620Sstevel@tonic-gate sbp2_ses_find_task_state(sbp2_ses_t *sp, sbp2_task_state_t state) 10630Sstevel@tonic-gate { 10640Sstevel@tonic-gate sbp2_task_t *task = NULL; 10650Sstevel@tonic-gate 10660Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10670Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 10680Sstevel@tonic-gate if (task->ts_state == state) { 10690Sstevel@tonic-gate break; 10700Sstevel@tonic-gate } 10710Sstevel@tonic-gate } 10720Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate return (task); 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate 10770Sstevel@tonic-gate /* 10780Sstevel@tonic-gate * Remove first task on the list. Returns pointer to the removed task or NULL. 10790Sstevel@tonic-gate */ 10800Sstevel@tonic-gate sbp2_task_t * 10810Sstevel@tonic-gate sbp2_ses_remove_first_task(sbp2_ses_t *sp) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate sbp2_task_t *task = NULL; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 10860Sstevel@tonic-gate task = sp->s_task_head; 10870Sstevel@tonic-gate if (task != NULL) { 10880Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 10890Sstevel@tonic-gate } 10900Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate return (task); 10930Sstevel@tonic-gate } 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate /* 10960Sstevel@tonic-gate * Remove first task on the list only if it's in specified state. 10970Sstevel@tonic-gate * Returns pointer to the removed task or NULL. 10980Sstevel@tonic-gate */ 10990Sstevel@tonic-gate sbp2_task_t * 11000Sstevel@tonic-gate sbp2_ses_remove_first_task_state(sbp2_ses_t *sp, sbp2_task_state_t state) 11010Sstevel@tonic-gate { 11020Sstevel@tonic-gate sbp2_task_t *task = NULL; 11030Sstevel@tonic-gate 11040Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11050Sstevel@tonic-gate if ((sp->s_task_head != NULL) && (sp->s_task_head->ts_state == state)) { 11060Sstevel@tonic-gate task = sp->s_task_head; 11070Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 11080Sstevel@tonic-gate } 11090Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11100Sstevel@tonic-gate 11110Sstevel@tonic-gate return (task); 11120Sstevel@tonic-gate } 11130Sstevel@tonic-gate 11140Sstevel@tonic-gate /* 11150Sstevel@tonic-gate * Remove first task on the list. If there's timeout, untimeout it. 11160Sstevel@tonic-gate * Returns pointer to the removed task or NULL. 11170Sstevel@tonic-gate */ 11180Sstevel@tonic-gate sbp2_task_t * 11190Sstevel@tonic-gate sbp2_ses_cancel_first_task(sbp2_ses_t *sp) 11200Sstevel@tonic-gate { 11210Sstevel@tonic-gate sbp2_task_t *task = NULL; 11220Sstevel@tonic-gate timeout_id_t timeout_id; 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11250Sstevel@tonic-gate task = sp->s_task_head; 11260Sstevel@tonic-gate if (task != NULL) { 11270Sstevel@tonic-gate (void) sbp2_ses_remove_task_locked(sp, task); 11280Sstevel@tonic-gate } 11290Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate if ((task != NULL) && ((timeout_id = task->ts_timeout_id) != 0)) { 11320Sstevel@tonic-gate task->ts_timeout_id = 0; 11330Sstevel@tonic-gate (void) untimeout(timeout_id); 11340Sstevel@tonic-gate } 11350Sstevel@tonic-gate 11360Sstevel@tonic-gate return (task); 11370Sstevel@tonic-gate } 11380Sstevel@tonic-gate 11390Sstevel@tonic-gate /* 11400Sstevel@tonic-gate * Reset pending tasks on the list to their initial state. 11410Sstevel@tonic-gate */ 11420Sstevel@tonic-gate static void 11430Sstevel@tonic-gate sbp2_ses_reset_pending_tasks(sbp2_ses_t *sp, uint16_t nodeID) 11440Sstevel@tonic-gate { 11450Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 11460Sstevel@tonic-gate sbp2_task_t *task = NULL; 11470Sstevel@tonic-gate timeout_id_t timeout_id; 11480Sstevel@tonic-gate sbp2_cmd_orb_t *orb; 11490Sstevel@tonic-gate 11500Sstevel@tonic-gate mutex_enter(&sp->s_task_mutex); 11510Sstevel@tonic-gate for (task = sp->s_task_head; task != NULL; task = task->ts_next) { 11520Sstevel@tonic-gate task->ts_state = SBP2_TASK_INIT; 11530Sstevel@tonic-gate 11540Sstevel@tonic-gate /* cancel timeout */ 11550Sstevel@tonic-gate if ((timeout_id = task->ts_timeout_id) != 0) { 11560Sstevel@tonic-gate task->ts_timeout_id = 0; 11570Sstevel@tonic-gate (void) untimeout(timeout_id); 11580Sstevel@tonic-gate } 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* update ORB nodeID */ 11610Sstevel@tonic-gate orb = (sbp2_cmd_orb_t *)sbp2_task_orb_kaddr(task); 11620Sstevel@tonic-gate *(uint16_t *)orb->co_data_descr = SBP2_SWAP16(nodeID); 11630Sstevel@tonic-gate sbp2_task_orb_sync(sp->s_lun, task, DDI_DMA_SYNC_FORDEV); 11640Sstevel@tonic-gate } 11650Sstevel@tonic-gate mutex_exit(&sp->s_task_mutex); 11660Sstevel@tonic-gate 11670Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 11680Sstevel@tonic-gate ap->a_active_task = NULL; 11690Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate int 11730Sstevel@tonic-gate sbp2_ses_agent_reset(sbp2_ses_t *sp, int *berr) 11740Sstevel@tonic-gate { 11750Sstevel@tonic-gate return (sbp2_agent_reset(&sp->s_agent, berr)); 11760Sstevel@tonic-gate } 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate int 11790Sstevel@tonic-gate sbp2_ses_abort_task(sbp2_ses_t *sp, sbp2_task_t *task, int *berr) 11800Sstevel@tonic-gate { 11810Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 11820Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 11830Sstevel@tonic-gate uint16_t params; 11840Sstevel@tonic-gate sbp2_cmd_orb_t *orb = (sbp2_cmd_orb_t *)task->ts_buf->bb_kaddr; 11850Sstevel@tonic-gate int ret = SBP2_SUCCESS; 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate /* mark ORB as dummy ORB */ 11880Sstevel@tonic-gate params = (orb->co_params & ~SBP2_ORB_RQ_FMT) | SBP2_ORB_RQ_FMT_DUMMY; 11890Sstevel@tonic-gate orb->co_params = params; 11900Sstevel@tonic-gate (void) SBP2_SYNC_BUF(tp, task->ts_buf, 0, 0, DDI_DMA_SYNC_FORDEV); 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 11930Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_ABORT_TASK, task->ts_buf->bb_baddr, berr); 11940Sstevel@tonic-gate 11950Sstevel@tonic-gate return (ret); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate int 12000Sstevel@tonic-gate sbp2_ses_abort_task_set(sbp2_ses_t *sp, int *berr) 12010Sstevel@tonic-gate { 12020Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 12030Sstevel@tonic-gate sbp2_lun_t *lp = sp->s_lun; 12040Sstevel@tonic-gate int ret; 12050Sstevel@tonic-gate 12060Sstevel@tonic-gate ret = sbp2_tgt_task_mgt_request(tp, lp->l_login_resp.lr_login_id, 12070Sstevel@tonic-gate SBP2_ORB_MGT_FUNC_ABORT_TASK_SET, 0, berr); 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate return (ret); 12100Sstevel@tonic-gate } 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate 12130Sstevel@tonic-gate /* 12140Sstevel@tonic-gate * 12150Sstevel@tonic-gate * ORB functions 12160Sstevel@tonic-gate * 12170Sstevel@tonic-gate * allocate ORB resources 12180Sstevel@tonic-gate * 12190Sstevel@tonic-gate * we maintain a freelist of ORB's for faster allocation 12200Sstevel@tonic-gate */ 12210Sstevel@tonic-gate /*ARGSUSED*/ 12220Sstevel@tonic-gate static sbp2_bus_buf_t * 12230Sstevel@tonic-gate sbp2_orb_freelist_get(sbp2_lun_t *lp, sbp2_task_t *task, int len) 12240Sstevel@tonic-gate { 12250Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12260Sstevel@tonic-gate sbp2_bus_buf_t *buf = NULL; 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12290Sstevel@tonic-gate if ((bl->bl_head != NULL) && (bl->bl_head->bb_len == len)) { 12300Sstevel@tonic-gate buf = bl->bl_head; 12310Sstevel@tonic-gate bl->bl_head = buf->bb_next; 12320Sstevel@tonic-gate if (bl->bl_tail == buf) { /* last one? */ 12330Sstevel@tonic-gate ASSERT(bl->bl_head == NULL); 12340Sstevel@tonic-gate bl->bl_tail = NULL; 12350Sstevel@tonic-gate } 12360Sstevel@tonic-gate bl->bl_len--; 12370Sstevel@tonic-gate buf->bb_next = NULL; 12380Sstevel@tonic-gate } 12390Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate return (buf); 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate static int 12450Sstevel@tonic-gate sbp2_orb_freelist_put(sbp2_lun_t *lp, sbp2_bus_buf_t *buf) 12460Sstevel@tonic-gate { 12470Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12480Sstevel@tonic-gate int ret; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12510Sstevel@tonic-gate if (bl->bl_len < SBP2_ORB_FREELIST_MAX) { 12520Sstevel@tonic-gate if (bl->bl_head == NULL) { 12530Sstevel@tonic-gate ASSERT(bl->bl_tail == NULL); 12540Sstevel@tonic-gate bl->bl_head = bl->bl_tail = buf; 12550Sstevel@tonic-gate } else { 12560Sstevel@tonic-gate bl->bl_tail->bb_next = buf; 12570Sstevel@tonic-gate bl->bl_tail = buf; 12580Sstevel@tonic-gate } 12590Sstevel@tonic-gate buf->bb_next = NULL; 12600Sstevel@tonic-gate bl->bl_len++; 12610Sstevel@tonic-gate ret = SBP2_SUCCESS; 12620Sstevel@tonic-gate } else { 12630Sstevel@tonic-gate ret = SBP2_FAILURE; 12640Sstevel@tonic-gate } 12650Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 12660Sstevel@tonic-gate 12670Sstevel@tonic-gate return (ret); 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate 12700Sstevel@tonic-gate static void 12710Sstevel@tonic-gate sbp2_orb_freelist_destroy(sbp2_lun_t *lp) 12720Sstevel@tonic-gate { 12730Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 12740Sstevel@tonic-gate sbp2_buf_list_t *bl = &lp->l_orb_freelist; 12750Sstevel@tonic-gate sbp2_bus_buf_t *buf, *buf_next; 12760Sstevel@tonic-gate 12770Sstevel@tonic-gate mutex_enter(&bl->bl_mutex); 12780Sstevel@tonic-gate for (buf = bl->bl_head; buf != NULL; ) { 12790Sstevel@tonic-gate SBP2_FREE_BUF(tp, buf); 12800Sstevel@tonic-gate buf_next = buf->bb_next; 12810Sstevel@tonic-gate kmem_free(buf, sizeof (sbp2_bus_buf_t)); 12820Sstevel@tonic-gate buf = buf_next; 12830Sstevel@tonic-gate } 12840Sstevel@tonic-gate bl->bl_head = bl->bl_tail = NULL; 12850Sstevel@tonic-gate mutex_exit(&bl->bl_mutex); 12860Sstevel@tonic-gate } 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate int 12890Sstevel@tonic-gate sbp2_task_orb_alloc(sbp2_lun_t *lp, sbp2_task_t *task, int len) 12900Sstevel@tonic-gate { 12910Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 12920Sstevel@tonic-gate int buf_len; 12930Sstevel@tonic-gate int ret; 12940Sstevel@tonic-gate 12950Sstevel@tonic-gate buf_len = SBP2_ORB_SIZE_ROUNDUP(tp, len); 12960Sstevel@tonic-gate 12970Sstevel@tonic-gate /* try freelist first */ 12980Sstevel@tonic-gate if ((task->ts_buf = sbp2_orb_freelist_get(lp, task, buf_len)) != NULL) { 12990Sstevel@tonic-gate return (SBP2_SUCCESS); 13000Sstevel@tonic-gate } 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate /* if no free buffers, allocate new */ 13030Sstevel@tonic-gate task->ts_buf = kmem_zalloc(sizeof (sbp2_bus_buf_t), KM_SLEEP); 13040Sstevel@tonic-gate task->ts_buf->bb_len = buf_len; 13050Sstevel@tonic-gate task->ts_buf->bb_flags = SBP2_BUS_BUF_DMA | SBP2_BUS_BUF_RD; 13060Sstevel@tonic-gate if ((ret = SBP2_ALLOC_BUF(tp, task->ts_buf)) != SBP2_SUCCESS) { 13070Sstevel@tonic-gate kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t)); 13080Sstevel@tonic-gate task->ts_buf = NULL; 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate 13110Sstevel@tonic-gate return (ret); 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate void 13150Sstevel@tonic-gate sbp2_task_orb_free(sbp2_lun_t *lp, sbp2_task_t *task) 13160Sstevel@tonic-gate { 13170Sstevel@tonic-gate sbp2_tgt_t *tp = lp->l_tgt; 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate if (task->ts_buf != NULL) { 13200Sstevel@tonic-gate if (sbp2_orb_freelist_put(lp, task->ts_buf) != SBP2_SUCCESS) { 13210Sstevel@tonic-gate SBP2_FREE_BUF(tp, task->ts_buf); 13220Sstevel@tonic-gate kmem_free(task->ts_buf, sizeof (sbp2_bus_buf_t)); 13230Sstevel@tonic-gate } 13240Sstevel@tonic-gate task->ts_buf = NULL; 13250Sstevel@tonic-gate } 13260Sstevel@tonic-gate } 13270Sstevel@tonic-gate 13280Sstevel@tonic-gate void * 13290Sstevel@tonic-gate sbp2_task_orb_kaddr(sbp2_task_t *task) 13300Sstevel@tonic-gate { 13310Sstevel@tonic-gate return (task->ts_buf->bb_kaddr); 13320Sstevel@tonic-gate } 13330Sstevel@tonic-gate 13340Sstevel@tonic-gate void 13350Sstevel@tonic-gate sbp2_task_orb_sync(sbp2_lun_t *lp, sbp2_task_t *task, int flags) 13360Sstevel@tonic-gate { 13370Sstevel@tonic-gate (void) SBP2_SYNC_BUF(lp->l_tgt, task->ts_buf, 0, 0, flags); 13380Sstevel@tonic-gate } 13390Sstevel@tonic-gate 13400Sstevel@tonic-gate /* 13410Sstevel@tonic-gate * 13420Sstevel@tonic-gate * --- fetch agent routines 13430Sstevel@tonic-gate * 13440Sstevel@tonic-gate */ 13450Sstevel@tonic-gate static int 13460Sstevel@tonic-gate sbp2_agent_init(sbp2_agent_t *ap, uint64_t offset, sbp2_tgt_t *tp) 13470Sstevel@tonic-gate { 13480Sstevel@tonic-gate int ret; 13490Sstevel@tonic-gate 13500Sstevel@tonic-gate /* paranoia */ 13510Sstevel@tonic-gate if (offset == 0) { 13520Sstevel@tonic-gate return (SBP2_FAILURE); 13530Sstevel@tonic-gate } 13540Sstevel@tonic-gate 13550Sstevel@tonic-gate ap->a_tgt = tp; 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate ap->a_reg_agent_state = offset + SBP2_AGENT_STATE_OFFSET; 13580Sstevel@tonic-gate ap->a_reg_agent_reset = offset + SBP2_AGENT_RESET_OFFSET; 13590Sstevel@tonic-gate ap->a_reg_orbp = offset + SBP2_ORB_POINTER_OFFSET; 13600Sstevel@tonic-gate ap->a_reg_doorbell = offset + SBP2_DOORBELL_OFFSET; 13610Sstevel@tonic-gate ap->a_reg_unsol_status_enable = offset + 13620Sstevel@tonic-gate SBP2_UNSOLICITED_STATUS_ENABLE_OFFSET; 13630Sstevel@tonic-gate 13640Sstevel@tonic-gate /* 13650Sstevel@tonic-gate * allocate bus commands 13660Sstevel@tonic-gate */ 13670Sstevel@tonic-gate if ((ret = SBP2_ALLOC_CMD(tp, &ap->a_cmd, 0)) != SBP2_SUCCESS) { 13680Sstevel@tonic-gate return (ret); 13690Sstevel@tonic-gate } 13700Sstevel@tonic-gate ap->a_cmd_data = allocb(sizeof (sbp2_orbp_t), BPRI_HI); 13710Sstevel@tonic-gate if (ap->a_cmd_data == NULL) { 13720Sstevel@tonic-gate sbp2_agent_fini(ap); 13730Sstevel@tonic-gate return (SBP2_ENOMEM); 13740Sstevel@tonic-gate } 13750Sstevel@tonic-gate 13760Sstevel@tonic-gate mutex_init(&ap->a_mutex, NULL, MUTEX_DRIVER, 13770Sstevel@tonic-gate SBP2_GET_IBLOCK_COOKIE(tp)); 13780Sstevel@tonic-gate cv_init(&ap->a_cv, NULL, CV_DRIVER, NULL); 13790Sstevel@tonic-gate 13800Sstevel@tonic-gate #ifndef __lock_lint 13810Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 13820Sstevel@tonic-gate #endif 13830Sstevel@tonic-gate 13840Sstevel@tonic-gate return (SBP2_SUCCESS); 13850Sstevel@tonic-gate } 13860Sstevel@tonic-gate 13870Sstevel@tonic-gate 13880Sstevel@tonic-gate static void 13890Sstevel@tonic-gate sbp2_agent_fini(sbp2_agent_t *ap) 13900Sstevel@tonic-gate { 13910Sstevel@tonic-gate sbp2_tgt_t *tp = ap->a_tgt; 13920Sstevel@tonic-gate 13930Sstevel@tonic-gate /* free bus commands */ 13940Sstevel@tonic-gate if (ap->a_cmd != NULL) { 13950Sstevel@tonic-gate SBP2_FREE_CMD(tp, ap->a_cmd); 13960Sstevel@tonic-gate } 13970Sstevel@tonic-gate if (ap->a_cmd_data != NULL) { 13980Sstevel@tonic-gate freeb(ap->a_cmd_data); 13990Sstevel@tonic-gate } 14000Sstevel@tonic-gate cv_destroy(&ap->a_cv); 14010Sstevel@tonic-gate mutex_destroy(&ap->a_mutex); 14020Sstevel@tonic-gate } 14030Sstevel@tonic-gate 14040Sstevel@tonic-gate 14050Sstevel@tonic-gate static void 14060Sstevel@tonic-gate sbp2_agent_acquire_locked(sbp2_agent_t *ap) 14070Sstevel@tonic-gate { 14080Sstevel@tonic-gate while (ap->a_acquired) { 14090Sstevel@tonic-gate cv_wait(&ap->a_cv, &ap->a_mutex); 14100Sstevel@tonic-gate } 14110Sstevel@tonic-gate ap->a_acquired = B_TRUE; 14120Sstevel@tonic-gate } 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate 14150Sstevel@tonic-gate static void 14160Sstevel@tonic-gate sbp2_agent_release_locked(sbp2_agent_t *ap) 14170Sstevel@tonic-gate { 14180Sstevel@tonic-gate ap->a_acquired = B_FALSE; 14190Sstevel@tonic-gate cv_signal(&ap->a_cv); /* wake next waiter */ 14200Sstevel@tonic-gate } 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate 14230Sstevel@tonic-gate static void 14240Sstevel@tonic-gate sbp2_agent_acquire(sbp2_agent_t *ap) 14250Sstevel@tonic-gate { 14260Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14270Sstevel@tonic-gate sbp2_agent_acquire_locked(ap); 14280Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14290Sstevel@tonic-gate } 14300Sstevel@tonic-gate 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate static void 14330Sstevel@tonic-gate sbp2_agent_release(sbp2_agent_t *ap) 14340Sstevel@tonic-gate { 14350Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14360Sstevel@tonic-gate sbp2_agent_release_locked(ap); 14370Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14380Sstevel@tonic-gate } 14390Sstevel@tonic-gate 14400Sstevel@tonic-gate 14410Sstevel@tonic-gate static int 14420Sstevel@tonic-gate sbp2_agent_keepalive(sbp2_agent_t *ap, int *berr) 14430Sstevel@tonic-gate { 14440Sstevel@tonic-gate boolean_t acquired; 14450Sstevel@tonic-gate int ret = SBP2_SUCCESS; 14460Sstevel@tonic-gate 14470Sstevel@tonic-gate ASSERT(mutex_owned(&ap->a_mutex)); 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate if (ap->a_state == SBP2_AGENT_STATE_DEAD) { 14500Sstevel@tonic-gate acquired = ap->a_acquired; 14510Sstevel@tonic-gate if (!acquired) { 14520Sstevel@tonic-gate sbp2_agent_acquire_locked(ap); 14530Sstevel@tonic-gate } 14540Sstevel@tonic-gate 14550Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 14560Sstevel@tonic-gate ret = sbp2_agent_reset(ap, berr); 14570Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate if (!acquired) { 14600Sstevel@tonic-gate sbp2_agent_release_locked(ap); 14610Sstevel@tonic-gate } 14620Sstevel@tonic-gate } 14630Sstevel@tonic-gate 14640Sstevel@tonic-gate return (ret); 14650Sstevel@tonic-gate } 14660Sstevel@tonic-gate 14670Sstevel@tonic-gate #ifndef __lock_lint 14680Sstevel@tonic-gate static int 14690Sstevel@tonic-gate sbp2_agent_doorbell(sbp2_agent_t *ap, int *berr) 14700Sstevel@tonic-gate { 14710Sstevel@tonic-gate return (SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_doorbell, 0, berr)); 14720Sstevel@tonic-gate } 14730Sstevel@tonic-gate #endif 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate /* 14760Sstevel@tonic-gate * write into ORB_POINTER register and make sure it reached target 14770Sstevel@tonic-gate * 14780Sstevel@tonic-gate * From E.2: "If no acknowledgement is received by the initiator after a write 14790Sstevel@tonic-gate * to the ORB_POINTER register, the initiator should not retry the write. 14800Sstevel@tonic-gate * The recommended method for error recovery is a write to the AGENT_RESET 14810Sstevel@tonic-gate * register." So we can retry, but not in case of timeout. 14820Sstevel@tonic-gate */ 14830Sstevel@tonic-gate static int 14840Sstevel@tonic-gate sbp2_agent_write_orbp(sbp2_agent_t *ap, uint64_t baddr, int *berr) 14850Sstevel@tonic-gate { 14860Sstevel@tonic-gate int i = 0; 14870Sstevel@tonic-gate int ret; 14880Sstevel@tonic-gate 14890Sstevel@tonic-gate SBP2_ORBP_SET(ap->a_cmd_data->b_rptr, baddr); 14900Sstevel@tonic-gate ap->a_cmd_data->b_wptr = ap->a_cmd_data->b_rptr + 8; 14910Sstevel@tonic-gate 14920Sstevel@tonic-gate for (;;) { 14930Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_worbp++; 14940Sstevel@tonic-gate if ((ret = SBP2_WB(ap->a_tgt, ap->a_cmd, ap->a_reg_orbp, 14950Sstevel@tonic-gate ap->a_cmd_data, 8, berr)) == SBP2_SUCCESS) { 14960Sstevel@tonic-gate return (ret); 14970Sstevel@tonic-gate } 14980Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_worbp_fail++; 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate if ((ret == SBP2_ETIMEOUT) || 15010Sstevel@tonic-gate (++i > sbp2_write_orbp_nretries)) { 15020Sstevel@tonic-gate break; 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate if (sbp2_write_orbp_delay > 0) { 15050Sstevel@tonic-gate drv_usecwait(sbp2_write_orbp_delay); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate } 15080Sstevel@tonic-gate 15090Sstevel@tonic-gate return (ret); 15100Sstevel@tonic-gate } 15110Sstevel@tonic-gate 15120Sstevel@tonic-gate 15130Sstevel@tonic-gate /* 15140Sstevel@tonic-gate * reset fetch agent by writing into AGENT_RESET register 15150Sstevel@tonic-gate */ 15160Sstevel@tonic-gate static int 15170Sstevel@tonic-gate sbp2_agent_reset(sbp2_agent_t *ap, int *berr) 15180Sstevel@tonic-gate { 15190Sstevel@tonic-gate int i = 0; 15200Sstevel@tonic-gate int ret; 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate for (;;) { 15230Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_wreset++; 15240Sstevel@tonic-gate if ((ret = SBP2_WQ(ap->a_tgt, ap->a_cmd, ap->a_reg_agent_reset, 15250Sstevel@tonic-gate 0, berr)) == SBP2_SUCCESS) { 15260Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 15270Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_RESET; 15280Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 15290Sstevel@tonic-gate break; 15300Sstevel@tonic-gate } 15310Sstevel@tonic-gate 15320Sstevel@tonic-gate ap->a_tgt->t_stat.stat_agent_wreset_fail++; 15330Sstevel@tonic-gate if (++i > sbp2_submit_reset_nretries) { 15340Sstevel@tonic-gate break; 15350Sstevel@tonic-gate } 15360Sstevel@tonic-gate if (sbp2_submit_reset_delay > 0) { 15370Sstevel@tonic-gate drv_usecwait(sbp2_submit_reset_delay); 15380Sstevel@tonic-gate } 15390Sstevel@tonic-gate } 15400Sstevel@tonic-gate return (ret); 15410Sstevel@tonic-gate } 15420Sstevel@tonic-gate 15430Sstevel@tonic-gate /* 15440Sstevel@tonic-gate * 15450Sstevel@tonic-gate * --- callbacks and timeouts 15460Sstevel@tonic-gate * 15470Sstevel@tonic-gate */ 15480Sstevel@tonic-gate /* 15490Sstevel@tonic-gate * Status FIFO callback for mgt ORB's. 15500Sstevel@tonic-gate */ 15510Sstevel@tonic-gate /*ARGSUSED*/ 15520Sstevel@tonic-gate static void 15530Sstevel@tonic-gate sbp2_mgt_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp) 15540Sstevel@tonic-gate { 15550Sstevel@tonic-gate sbp2_tgt_t *tp = buf->bb_sbp2_priv; 15560Sstevel@tonic-gate int len; 15570Sstevel@tonic-gate sbp2_status_t *st; 15580Sstevel@tonic-gate uint64_t orbp; 15590Sstevel@tonic-gate 15600Sstevel@tonic-gate len = MBLKL(*bpp); 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate /* 8 bytes minimum */ 15630Sstevel@tonic-gate if (len < 8) { 15640Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH); 15650Sstevel@tonic-gate tp->t_stat.stat_status_short++; 15660Sstevel@tonic-gate return; 15670Sstevel@tonic-gate } 15680Sstevel@tonic-gate 15690Sstevel@tonic-gate /* convert 2-quadlet header from BE to native endianness */ 15700Sstevel@tonic-gate st = (sbp2_status_t *)(*bpp)->b_rptr; 15710Sstevel@tonic-gate SBP2_SWAP16_1(st->st_orb_offset_hi); 15720Sstevel@tonic-gate SBP2_SWAP32_1(st->st_orb_offset_lo); 15730Sstevel@tonic-gate orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo; 15740Sstevel@tonic-gate 15750Sstevel@tonic-gate if (orbp != tp->t_mgt_orb_buf.bb_baddr) { 15760Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 15770Sstevel@tonic-gate tp->t_stat.stat_status_mgt_notask++; 15780Sstevel@tonic-gate return; 15790Sstevel@tonic-gate } 15800Sstevel@tonic-gate 15810Sstevel@tonic-gate /* make a local copy of status block */ 15820Sstevel@tonic-gate bzero(&tp->t_mgt_status, sizeof (sbp2_status_t)); 15830Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len); 15840Sstevel@tonic-gate 15850Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 15860Sstevel@tonic-gate 15870Sstevel@tonic-gate /* wake up waiter */ 15880Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 15890Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_TRUE; 15900Sstevel@tonic-gate cv_signal(&tp->t_mgt_status_cv); 15910Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 15920Sstevel@tonic-gate } 15930Sstevel@tonic-gate 15940Sstevel@tonic-gate static void 15950Sstevel@tonic-gate sbp2_task_timeout(void *arg) 15960Sstevel@tonic-gate { 15970Sstevel@tonic-gate sbp2_task_t *task = arg; 15980Sstevel@tonic-gate sbp2_ses_t *sp = task->ts_ses; 15990Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 16000Sstevel@tonic-gate 16010Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 16020Sstevel@tonic-gate 16030Sstevel@tonic-gate /* cancelled? */ 16040Sstevel@tonic-gate if (task->ts_timeout_id == 0) { 16050Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16060Sstevel@tonic-gate return; 16070Sstevel@tonic-gate } 16080Sstevel@tonic-gate task->ts_timeout_id = 0; 16090Sstevel@tonic-gate task->ts_time_comp = gethrtime(); 16100Sstevel@tonic-gate 16110Sstevel@tonic-gate /* avoid race with other callbacks */ 16120Sstevel@tonic-gate if (task->ts_state != SBP2_TASK_PEND) { 16130Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16140Sstevel@tonic-gate return; 16150Sstevel@tonic-gate } 16160Sstevel@tonic-gate 16170Sstevel@tonic-gate if (task == ap->a_active_task) { 16180Sstevel@tonic-gate ap->a_active_task = NULL; 16190Sstevel@tonic-gate } 16200Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_TIMEOUT; 16210Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate /* we mark agent DEAD so it's reset before next task is submitted */ 16240Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 16250Sstevel@tonic-gate sp->s_tgt->t_stat.stat_status_dead++; 16260Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 16270Sstevel@tonic-gate 16280Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, task); 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate /* 16320Sstevel@tonic-gate * Status FIFO callback for command ORB's. Also used for login ORB. 16330Sstevel@tonic-gate */ 16340Sstevel@tonic-gate /*ARGSUSED*/ 16350Sstevel@tonic-gate static void 16360Sstevel@tonic-gate sbp2_status_fifo_wb_cb(sbp2_bus_buf_t *buf, void *reqh, mblk_t **bpp) 16370Sstevel@tonic-gate { 16380Sstevel@tonic-gate sbp2_ses_t *sp = buf->bb_sbp2_priv; 16390Sstevel@tonic-gate sbp2_tgt_t *tp = sp->s_tgt; 16400Sstevel@tonic-gate sbp2_agent_t *ap = &sp->s_agent; 16410Sstevel@tonic-gate int len; 16420Sstevel@tonic-gate sbp2_status_t *st; 16430Sstevel@tonic-gate uint8_t src; 16440Sstevel@tonic-gate uint64_t orbp; 16450Sstevel@tonic-gate sbp2_task_t *task; 16460Sstevel@tonic-gate timeout_id_t timeout_id; 16470Sstevel@tonic-gate 16480Sstevel@tonic-gate len = MBLKL(*bpp); 16490Sstevel@tonic-gate 16500Sstevel@tonic-gate /* 8 bytes minimum */ 16510Sstevel@tonic-gate if (len < 8) { 16520Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_ELENGTH); 16530Sstevel@tonic-gate tp->t_stat.stat_status_short++; 16540Sstevel@tonic-gate return; 16550Sstevel@tonic-gate } 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate /* convert 2-quadlet header from BE32 to native endianness */ 16580Sstevel@tonic-gate st = (sbp2_status_t *)(*bpp)->b_rptr; 16590Sstevel@tonic-gate SBP2_SWAP16_1(st->st_orb_offset_hi); 16600Sstevel@tonic-gate SBP2_SWAP32_1(st->st_orb_offset_lo); 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate orbp = ((uint64_t)st->st_orb_offset_hi << 32) | st->st_orb_offset_lo; 16630Sstevel@tonic-gate 16640Sstevel@tonic-gate /* login ORB status? */ 16650Sstevel@tonic-gate if (orbp == tp->t_mgt_orb_buf.bb_baddr) { 16660Sstevel@tonic-gate bzero(&tp->t_mgt_status, sizeof (sbp2_status_t)); 16670Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &tp->t_mgt_status, len); 16680Sstevel@tonic-gate 16690Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate /* wake up waiter */ 16720Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 16730Sstevel@tonic-gate tp->t_mgt_status_rcvd = B_TRUE; 16740Sstevel@tonic-gate cv_signal(&tp->t_mgt_status_cv); 16750Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 16760Sstevel@tonic-gate return; 16770Sstevel@tonic-gate } 16780Sstevel@tonic-gate 16790Sstevel@tonic-gate /* dismiss unsolicited status */ 16800Sstevel@tonic-gate src = st->st_param & SBP2_ST_SRC; 16810Sstevel@tonic-gate if (src == SBP2_ST_SRC_UNSOLICITED) { 16820Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 16830Sstevel@tonic-gate tp->t_stat.stat_status_unsolicited++; 16840Sstevel@tonic-gate return; 16850Sstevel@tonic-gate } 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate /* find task corresponding to this ORB pointer */ 16880Sstevel@tonic-gate if ((task = sbp2_ses_orbp2task(sp, orbp)) == NULL) { 16890Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_FAILURE); 16900Sstevel@tonic-gate tp->t_stat.stat_status_notask++; 16910Sstevel@tonic-gate return; 16920Sstevel@tonic-gate } 16930Sstevel@tonic-gate 16940Sstevel@tonic-gate /* 16950Sstevel@tonic-gate * Copy status block into a local buffer. 16960Sstevel@tonic-gate * 16970Sstevel@tonic-gate * Note: (ref: B.2) "SBP-2 permits the return of a status block between 16980Sstevel@tonic-gate * two and eight quadlets in length. When a truncated status block 16990Sstevel@tonic-gate * is stored, the omited quadlets shall be interpreted as if zero 17000Sstevel@tonic-gate * values were stored." 17010Sstevel@tonic-gate */ 17020Sstevel@tonic-gate bzero(&task->ts_status, sizeof (sbp2_status_t)); 17030Sstevel@tonic-gate bcopy((*bpp)->b_rptr, &task->ts_status, len); 17040Sstevel@tonic-gate 17050Sstevel@tonic-gate SBP2_BUF_WR_DONE(tp, buf, reqh, SBP2_BUS_BUF_SUCCESS); 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate mutex_enter(&ap->a_mutex); 17080Sstevel@tonic-gate 17090Sstevel@tonic-gate if ((timeout_id = task->ts_timeout_id) != 0) { 17100Sstevel@tonic-gate task->ts_timeout_id = 0; 17110Sstevel@tonic-gate (void) untimeout(timeout_id); 17120Sstevel@tonic-gate } 17130Sstevel@tonic-gate 17140Sstevel@tonic-gate /* determine agent state */ 17150Sstevel@tonic-gate if (st->st_param & SBP2_ST_DEAD) { 17160Sstevel@tonic-gate ap->a_state = SBP2_AGENT_STATE_DEAD; 17170Sstevel@tonic-gate tp->t_stat.stat_status_dead++; 17180Sstevel@tonic-gate } 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate /* avoid race with other callbacks */ 17210Sstevel@tonic-gate if (task->ts_state != SBP2_TASK_PEND) { 17220Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 17230Sstevel@tonic-gate return; 17240Sstevel@tonic-gate } 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate if (task == ap->a_active_task) { 17270Sstevel@tonic-gate ap->a_active_task = NULL; 17280Sstevel@tonic-gate } 17290Sstevel@tonic-gate task->ts_error = SBP2_TASK_ERR_NONE; 17300Sstevel@tonic-gate task->ts_state = SBP2_TASK_COMP; 17310Sstevel@tonic-gate 17320Sstevel@tonic-gate mutex_exit(&ap->a_mutex); 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate sp->s_status_cb(sp->s_status_cb_arg, task); /* notify the driver */ 17350Sstevel@tonic-gate } 17360Sstevel@tonic-gate 17370Sstevel@tonic-gate /* 17380Sstevel@tonic-gate * 17390Sstevel@tonic-gate * --- other 17400Sstevel@tonic-gate * 17410Sstevel@tonic-gate * since mgt agent is shared between LUNs and login sessions, 17420Sstevel@tonic-gate * it is safer to serialize mgt requests 17430Sstevel@tonic-gate */ 17440Sstevel@tonic-gate static void 17450Sstevel@tonic-gate sbp2_mgt_agent_acquire(sbp2_tgt_t *tp) 17460Sstevel@tonic-gate { 17470Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 17480Sstevel@tonic-gate while (tp->t_mgt_agent_acquired) { 17490Sstevel@tonic-gate cv_wait(&tp->t_mgt_agent_cv, &tp->t_mutex); 17500Sstevel@tonic-gate } 17510Sstevel@tonic-gate tp->t_mgt_agent_acquired = B_TRUE; 17520Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 17530Sstevel@tonic-gate } 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate static void 17560Sstevel@tonic-gate sbp2_mgt_agent_release(sbp2_tgt_t *tp) 17570Sstevel@tonic-gate { 17580Sstevel@tonic-gate mutex_enter(&tp->t_mutex); 17590Sstevel@tonic-gate tp->t_mgt_agent_acquired = B_FALSE; 17600Sstevel@tonic-gate cv_signal(&tp->t_mgt_agent_cv); /* wake next waiter */ 17610Sstevel@tonic-gate mutex_exit(&tp->t_mutex); 17620Sstevel@tonic-gate } 1763