17836SJohn.Forte@Sun.COM /* 27836SJohn.Forte@Sun.COM * CDDL HEADER START 37836SJohn.Forte@Sun.COM * 47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the 57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License"). 67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License. 77836SJohn.Forte@Sun.COM * 87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing. 107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions 117836SJohn.Forte@Sun.COM * and limitations under the License. 127836SJohn.Forte@Sun.COM * 137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 187836SJohn.Forte@Sun.COM * 197836SJohn.Forte@Sun.COM * CDDL HEADER END 207836SJohn.Forte@Sun.COM */ 217836SJohn.Forte@Sun.COM /* 228662SJordan.Vaughan@Sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237836SJohn.Forte@Sun.COM * Use is subject to license terms. 247836SJohn.Forte@Sun.COM */ 257836SJohn.Forte@Sun.COM 267836SJohn.Forte@Sun.COM #include <sys/conf.h> 277836SJohn.Forte@Sun.COM #include <sys/file.h> 287836SJohn.Forte@Sun.COM #include <sys/ddi.h> 297836SJohn.Forte@Sun.COM #include <sys/sunddi.h> 307836SJohn.Forte@Sun.COM #include <sys/modctl.h> 317836SJohn.Forte@Sun.COM #include <sys/scsi/scsi.h> 327836SJohn.Forte@Sun.COM #include <sys/scsi/impl/scsi_reset_notify.h> 337836SJohn.Forte@Sun.COM #include <sys/disp.h> 347836SJohn.Forte@Sun.COM #include <sys/byteorder.h> 357836SJohn.Forte@Sun.COM #include <sys/atomic.h> 367836SJohn.Forte@Sun.COM #include <sys/ethernet.h> 377836SJohn.Forte@Sun.COM #include <sys/sdt.h> 387836SJohn.Forte@Sun.COM #include <sys/nvpair.h> 398662SJordan.Vaughan@Sun.com #include <sys/zone.h> 407836SJohn.Forte@Sun.COM 417836SJohn.Forte@Sun.COM #include <stmf.h> 427836SJohn.Forte@Sun.COM #include <lpif.h> 437836SJohn.Forte@Sun.COM #include <portif.h> 447836SJohn.Forte@Sun.COM #include <stmf_ioctl.h> 457836SJohn.Forte@Sun.COM #include <stmf_impl.h> 467836SJohn.Forte@Sun.COM #include <lun_map.h> 477836SJohn.Forte@Sun.COM #include <stmf_state.h> 4810725SJohn.Forte@Sun.COM #include <pppt_ic_if.h> 497836SJohn.Forte@Sun.COM 507836SJohn.Forte@Sun.COM static uint64_t stmf_session_counter = 0; 517836SJohn.Forte@Sun.COM static uint16_t stmf_rtpid_counter = 0; 5210725SJohn.Forte@Sun.COM /* start messages at 1 */ 5310725SJohn.Forte@Sun.COM static uint64_t stmf_proxy_msg_id = 1; 547836SJohn.Forte@Sun.COM 557836SJohn.Forte@Sun.COM static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 567836SJohn.Forte@Sun.COM static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 577836SJohn.Forte@Sun.COM static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 587836SJohn.Forte@Sun.COM void **result); 597836SJohn.Forte@Sun.COM static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp); 607836SJohn.Forte@Sun.COM static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp); 617836SJohn.Forte@Sun.COM static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 627836SJohn.Forte@Sun.COM cred_t *credp, int *rval); 637836SJohn.Forte@Sun.COM static int stmf_get_stmf_state(stmf_state_desc_t *std); 647836SJohn.Forte@Sun.COM static int stmf_set_stmf_state(stmf_state_desc_t *std); 657836SJohn.Forte@Sun.COM static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu, 667836SJohn.Forte@Sun.COM char *info); 6710725SJohn.Forte@Sun.COM static int stmf_set_alua_state(stmf_alua_state_desc_t *alua_state); 6810725SJohn.Forte@Sun.COM static void stmf_get_alua_state(stmf_alua_state_desc_t *alua_state); 6910725SJohn.Forte@Sun.COM stmf_xfer_data_t *stmf_prepare_tpgs_data(uint8_t ilu_alua); 707836SJohn.Forte@Sun.COM void stmf_svc_init(); 717836SJohn.Forte@Sun.COM stmf_status_t stmf_svc_fini(); 727836SJohn.Forte@Sun.COM void stmf_svc(void *arg); 737836SJohn.Forte@Sun.COM void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info); 747836SJohn.Forte@Sun.COM void stmf_check_freetask(); 757836SJohn.Forte@Sun.COM void stmf_abort_target_reset(scsi_task_t *task); 767836SJohn.Forte@Sun.COM stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, 777836SJohn.Forte@Sun.COM int target_reset); 787836SJohn.Forte@Sun.COM void stmf_target_reset_poll(struct scsi_task *task); 797836SJohn.Forte@Sun.COM void stmf_handle_lun_reset(scsi_task_t *task); 807836SJohn.Forte@Sun.COM void stmf_handle_target_reset(scsi_task_t *task); 817836SJohn.Forte@Sun.COM void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf); 829585STim.Szeto@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 839585STim.Szeto@Sun.COM uint32_t *err_ret); 847836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi); 859585STim.Szeto@Sun.COM int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 869585STim.Szeto@Sun.COM uint32_t *err_ret); 877836SJohn.Forte@Sun.COM void stmf_delete_ppd(stmf_pp_data_t *ppd); 887836SJohn.Forte@Sun.COM void stmf_delete_all_ppds(); 897836SJohn.Forte@Sun.COM void stmf_trace_clear(); 907836SJohn.Forte@Sun.COM void stmf_worker_init(); 917836SJohn.Forte@Sun.COM stmf_status_t stmf_worker_fini(); 927836SJohn.Forte@Sun.COM void stmf_worker_mgmt(); 937836SJohn.Forte@Sun.COM void stmf_worker_task(void *arg); 9410725SJohn.Forte@Sun.COM static void stmf_task_lu_free(scsi_task_t *task, stmf_i_scsi_session_t *iss); 9510725SJohn.Forte@Sun.COM static stmf_status_t stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg, 9610725SJohn.Forte@Sun.COM uint32_t type); 9710725SJohn.Forte@Sun.COM static stmf_status_t stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg); 9810725SJohn.Forte@Sun.COM static stmf_status_t stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg); 9910725SJohn.Forte@Sun.COM static stmf_status_t stmf_ic_rx_status(stmf_ic_status_msg_t *msg); 10010725SJohn.Forte@Sun.COM static stmf_status_t stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg); 10110725SJohn.Forte@Sun.COM void stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s); 10210725SJohn.Forte@Sun.COM 10310725SJohn.Forte@Sun.COM /* pppt modhandle */ 10410725SJohn.Forte@Sun.COM ddi_modhandle_t pppt_mod; 10510725SJohn.Forte@Sun.COM 10610725SJohn.Forte@Sun.COM /* pppt modload imported functions */ 10710725SJohn.Forte@Sun.COM stmf_ic_reg_port_msg_alloc_func_t ic_reg_port_msg_alloc; 10810725SJohn.Forte@Sun.COM stmf_ic_dereg_port_msg_alloc_func_t ic_dereg_port_msg_alloc; 10910725SJohn.Forte@Sun.COM stmf_ic_reg_lun_msg_alloc_func_t ic_reg_lun_msg_alloc; 11010725SJohn.Forte@Sun.COM stmf_ic_dereg_lun_msg_alloc_func_t ic_dereg_lun_msg_alloc; 11110725SJohn.Forte@Sun.COM stmf_ic_lun_active_msg_alloc_func_t ic_lun_active_msg_alloc; 11210725SJohn.Forte@Sun.COM stmf_ic_scsi_cmd_msg_alloc_func_t ic_scsi_cmd_msg_alloc; 11310725SJohn.Forte@Sun.COM stmf_ic_scsi_data_xfer_done_msg_alloc_func_t ic_scsi_data_xfer_done_msg_alloc; 11410725SJohn.Forte@Sun.COM stmf_ic_session_create_msg_alloc_func_t ic_session_reg_msg_alloc; 11510725SJohn.Forte@Sun.COM stmf_ic_session_destroy_msg_alloc_func_t ic_session_dereg_msg_alloc; 11610725SJohn.Forte@Sun.COM stmf_ic_tx_msg_func_t ic_tx_msg; 11710725SJohn.Forte@Sun.COM stmf_ic_msg_free_func_t ic_msg_free; 1187836SJohn.Forte@Sun.COM 1199435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_q(scsi_task_t *, void()); 1209435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_q(scsi_task_t *, void()); 1219435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_io(scsi_task_t *, stmf_data_buf_t *); 1229435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_io(scsi_task_t *, stmf_data_buf_t *); 1239435STim.Szeto@Sun.COM 1247836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops; 1257836SJohn.Forte@Sun.COM 1267836SJohn.Forte@Sun.COM /* =====[ Tunables ]===== */ 1277836SJohn.Forte@Sun.COM /* Internal tracing */ 1287836SJohn.Forte@Sun.COM volatile int stmf_trace_on = 1; 1297836SJohn.Forte@Sun.COM volatile int stmf_trace_buf_size = (1 * 1024 * 1024); 1307836SJohn.Forte@Sun.COM /* 1317836SJohn.Forte@Sun.COM * The reason default task timeout is 75 is because we want the 1327836SJohn.Forte@Sun.COM * host to timeout 1st and mostly host timeout is 60 seconds. 1337836SJohn.Forte@Sun.COM */ 1347836SJohn.Forte@Sun.COM volatile int stmf_default_task_timeout = 75; 1357836SJohn.Forte@Sun.COM /* 1367836SJohn.Forte@Sun.COM * Setting this to one means, you are responsible for config load and keeping 1377836SJohn.Forte@Sun.COM * things in sync with persistent database. 1387836SJohn.Forte@Sun.COM */ 1397836SJohn.Forte@Sun.COM volatile int stmf_allow_modunload = 0; 1407836SJohn.Forte@Sun.COM 1417836SJohn.Forte@Sun.COM volatile int stmf_max_nworkers = 256; 1427836SJohn.Forte@Sun.COM volatile int stmf_min_nworkers = 4; 1437836SJohn.Forte@Sun.COM volatile int stmf_worker_scale_down_delay = 20; 1447836SJohn.Forte@Sun.COM 1457836SJohn.Forte@Sun.COM /* === [ Debugging and fault injection ] === */ 1467836SJohn.Forte@Sun.COM #ifdef DEBUG 1477836SJohn.Forte@Sun.COM volatile int stmf_drop_task_counter = 0; 1487836SJohn.Forte@Sun.COM volatile int stmf_drop_buf_counter = 0; 1497836SJohn.Forte@Sun.COM 1507836SJohn.Forte@Sun.COM #endif 1517836SJohn.Forte@Sun.COM 1527836SJohn.Forte@Sun.COM stmf_state_t stmf_state; 1537836SJohn.Forte@Sun.COM static stmf_lu_t *dlun0; 1547836SJohn.Forte@Sun.COM 1557836SJohn.Forte@Sun.COM static uint8_t stmf_first_zero[] = 1567836SJohn.Forte@Sun.COM { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff }; 1577836SJohn.Forte@Sun.COM static uint8_t stmf_first_one[] = 1587836SJohn.Forte@Sun.COM { 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; 1597836SJohn.Forte@Sun.COM 1607836SJohn.Forte@Sun.COM static kmutex_t trace_buf_lock; 1617836SJohn.Forte@Sun.COM static int trace_buf_size; 1627836SJohn.Forte@Sun.COM static int trace_buf_curndx; 1637836SJohn.Forte@Sun.COM caddr_t stmf_trace_buf; 1647836SJohn.Forte@Sun.COM 1657836SJohn.Forte@Sun.COM static enum { 1667836SJohn.Forte@Sun.COM STMF_WORKERS_DISABLED = 0, 1677836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLING, 1687836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLED 1697836SJohn.Forte@Sun.COM } stmf_workers_state = STMF_WORKERS_DISABLED; 1707836SJohn.Forte@Sun.COM static int stmf_i_max_nworkers; 1717836SJohn.Forte@Sun.COM static int stmf_i_min_nworkers; 1727836SJohn.Forte@Sun.COM static int stmf_nworkers_cur; /* # of workers currently running */ 1737836SJohn.Forte@Sun.COM static int stmf_nworkers_needed; /* # of workers need to be running */ 1747836SJohn.Forte@Sun.COM static int stmf_worker_sel_counter = 0; 1757836SJohn.Forte@Sun.COM static uint32_t stmf_cur_ntasks = 0; 1767836SJohn.Forte@Sun.COM static clock_t stmf_wm_last = 0; 1777836SJohn.Forte@Sun.COM /* 1787836SJohn.Forte@Sun.COM * This is equal to stmf_nworkers_cur while we are increasing # workers and 1797836SJohn.Forte@Sun.COM * stmf_nworkers_needed while we are decreasing the worker count. 1807836SJohn.Forte@Sun.COM */ 1817836SJohn.Forte@Sun.COM static int stmf_nworkers_accepting_cmds; 1827836SJohn.Forte@Sun.COM static stmf_worker_t *stmf_workers = NULL; 1837836SJohn.Forte@Sun.COM static clock_t stmf_worker_mgmt_delay = 2; 1847836SJohn.Forte@Sun.COM static clock_t stmf_worker_scale_down_timer = 0; 1857836SJohn.Forte@Sun.COM static int stmf_worker_scale_down_qd = 0; 1867836SJohn.Forte@Sun.COM 1877836SJohn.Forte@Sun.COM static struct cb_ops stmf_cb_ops = { 1887836SJohn.Forte@Sun.COM stmf_open, /* open */ 1897836SJohn.Forte@Sun.COM stmf_close, /* close */ 1907836SJohn.Forte@Sun.COM nodev, /* strategy */ 1917836SJohn.Forte@Sun.COM nodev, /* print */ 1927836SJohn.Forte@Sun.COM nodev, /* dump */ 1937836SJohn.Forte@Sun.COM nodev, /* read */ 1947836SJohn.Forte@Sun.COM nodev, /* write */ 1957836SJohn.Forte@Sun.COM stmf_ioctl, /* ioctl */ 1967836SJohn.Forte@Sun.COM nodev, /* devmap */ 1977836SJohn.Forte@Sun.COM nodev, /* mmap */ 1987836SJohn.Forte@Sun.COM nodev, /* segmap */ 1997836SJohn.Forte@Sun.COM nochpoll, /* chpoll */ 2007836SJohn.Forte@Sun.COM ddi_prop_op, /* cb_prop_op */ 2017836SJohn.Forte@Sun.COM 0, /* streamtab */ 2027836SJohn.Forte@Sun.COM D_NEW | D_MP, /* cb_flag */ 2037836SJohn.Forte@Sun.COM CB_REV, /* rev */ 2047836SJohn.Forte@Sun.COM nodev, /* aread */ 2057836SJohn.Forte@Sun.COM nodev /* awrite */ 2067836SJohn.Forte@Sun.COM }; 2077836SJohn.Forte@Sun.COM 2087836SJohn.Forte@Sun.COM static struct dev_ops stmf_ops = { 2097836SJohn.Forte@Sun.COM DEVO_REV, 2107836SJohn.Forte@Sun.COM 0, 2117836SJohn.Forte@Sun.COM stmf_getinfo, 2127836SJohn.Forte@Sun.COM nulldev, /* identify */ 2137836SJohn.Forte@Sun.COM nulldev, /* probe */ 2147836SJohn.Forte@Sun.COM stmf_attach, 2157836SJohn.Forte@Sun.COM stmf_detach, 2167836SJohn.Forte@Sun.COM nodev, /* reset */ 2177836SJohn.Forte@Sun.COM &stmf_cb_ops, 2187836SJohn.Forte@Sun.COM NULL, /* bus_ops */ 2197836SJohn.Forte@Sun.COM NULL /* power */ 2207836SJohn.Forte@Sun.COM }; 2217836SJohn.Forte@Sun.COM 2229435STim.Szeto@Sun.COM #define STMF_NAME "COMSTAR STMF" 2239435STim.Szeto@Sun.COM #define STMF_MODULE_NAME "stmf" 2247836SJohn.Forte@Sun.COM 2257836SJohn.Forte@Sun.COM static struct modldrv modldrv = { 2267836SJohn.Forte@Sun.COM &mod_driverops, 2277836SJohn.Forte@Sun.COM STMF_NAME, 2287836SJohn.Forte@Sun.COM &stmf_ops 2297836SJohn.Forte@Sun.COM }; 2307836SJohn.Forte@Sun.COM 2317836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = { 2327836SJohn.Forte@Sun.COM MODREV_1, 2337836SJohn.Forte@Sun.COM &modldrv, 2347836SJohn.Forte@Sun.COM NULL 2357836SJohn.Forte@Sun.COM }; 2367836SJohn.Forte@Sun.COM 2377836SJohn.Forte@Sun.COM int 2387836SJohn.Forte@Sun.COM _init(void) 2397836SJohn.Forte@Sun.COM { 2407836SJohn.Forte@Sun.COM int ret; 2417836SJohn.Forte@Sun.COM 2427836SJohn.Forte@Sun.COM ret = mod_install(&modlinkage); 2437836SJohn.Forte@Sun.COM if (ret) 2447836SJohn.Forte@Sun.COM return (ret); 2457836SJohn.Forte@Sun.COM stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP); 2467836SJohn.Forte@Sun.COM trace_buf_size = stmf_trace_buf_size; 2477836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 2487836SJohn.Forte@Sun.COM mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0); 2497836SJohn.Forte@Sun.COM bzero(&stmf_state, sizeof (stmf_state_t)); 2507836SJohn.Forte@Sun.COM /* STMF service is off by default */ 2517836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 2527836SJohn.Forte@Sun.COM mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL); 2537836SJohn.Forte@Sun.COM cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL); 2547836SJohn.Forte@Sun.COM stmf_session_counter = (uint64_t)ddi_get_lbolt(); 2557836SJohn.Forte@Sun.COM stmf_view_init(); 2567836SJohn.Forte@Sun.COM stmf_svc_init(); 2577836SJohn.Forte@Sun.COM stmf_dlun_init(); 2587836SJohn.Forte@Sun.COM return (ret); 2597836SJohn.Forte@Sun.COM } 2607836SJohn.Forte@Sun.COM 2617836SJohn.Forte@Sun.COM int 2627836SJohn.Forte@Sun.COM _fini(void) 2637836SJohn.Forte@Sun.COM { 2647836SJohn.Forte@Sun.COM int ret; 2657836SJohn.Forte@Sun.COM 2667836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) 2677836SJohn.Forte@Sun.COM return (EBUSY); 2687836SJohn.Forte@Sun.COM if ((!stmf_allow_modunload) && 2697836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) { 2707836SJohn.Forte@Sun.COM return (EBUSY); 2717836SJohn.Forte@Sun.COM } 2727836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlps || stmf_state.stmf_npps) { 2737836SJohn.Forte@Sun.COM return (EBUSY); 2747836SJohn.Forte@Sun.COM } 2757836SJohn.Forte@Sun.COM if (stmf_dlun_fini() != STMF_SUCCESS) 2767836SJohn.Forte@Sun.COM return (EBUSY); 2777836SJohn.Forte@Sun.COM if (stmf_worker_fini() != STMF_SUCCESS) { 2787836SJohn.Forte@Sun.COM stmf_dlun_init(); 2797836SJohn.Forte@Sun.COM return (EBUSY); 2807836SJohn.Forte@Sun.COM } 2817836SJohn.Forte@Sun.COM if (stmf_svc_fini() != STMF_SUCCESS) { 2827836SJohn.Forte@Sun.COM stmf_dlun_init(); 2837836SJohn.Forte@Sun.COM stmf_worker_init(); 2847836SJohn.Forte@Sun.COM return (EBUSY); 2857836SJohn.Forte@Sun.COM } 2867836SJohn.Forte@Sun.COM 2877836SJohn.Forte@Sun.COM ret = mod_remove(&modlinkage); 2887836SJohn.Forte@Sun.COM if (ret) { 2897836SJohn.Forte@Sun.COM stmf_svc_init(); 2907836SJohn.Forte@Sun.COM stmf_dlun_init(); 2917836SJohn.Forte@Sun.COM stmf_worker_init(); 2927836SJohn.Forte@Sun.COM return (ret); 2937836SJohn.Forte@Sun.COM } 2947836SJohn.Forte@Sun.COM 2957836SJohn.Forte@Sun.COM stmf_view_clear_config(); 2967836SJohn.Forte@Sun.COM kmem_free(stmf_trace_buf, stmf_trace_buf_size); 2977836SJohn.Forte@Sun.COM mutex_destroy(&trace_buf_lock); 2987836SJohn.Forte@Sun.COM mutex_destroy(&stmf_state.stmf_lock); 2997836SJohn.Forte@Sun.COM cv_destroy(&stmf_state.stmf_cv); 3007836SJohn.Forte@Sun.COM return (ret); 3017836SJohn.Forte@Sun.COM } 3027836SJohn.Forte@Sun.COM 3037836SJohn.Forte@Sun.COM int 3047836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop) 3057836SJohn.Forte@Sun.COM { 3067836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfop)); 3077836SJohn.Forte@Sun.COM } 3087836SJohn.Forte@Sun.COM 3097836SJohn.Forte@Sun.COM /* ARGSUSED */ 3107836SJohn.Forte@Sun.COM static int 3117836SJohn.Forte@Sun.COM stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 3127836SJohn.Forte@Sun.COM { 3137836SJohn.Forte@Sun.COM switch (cmd) { 3147836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2DEVINFO: 3157836SJohn.Forte@Sun.COM *result = stmf_state.stmf_dip; 3167836SJohn.Forte@Sun.COM break; 3177836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2INSTANCE: 3189585STim.Szeto@Sun.COM *result = 3199585STim.Szeto@Sun.COM (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip); 3207836SJohn.Forte@Sun.COM break; 3217836SJohn.Forte@Sun.COM default: 3227836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3237836SJohn.Forte@Sun.COM } 3247836SJohn.Forte@Sun.COM 3257836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3267836SJohn.Forte@Sun.COM } 3277836SJohn.Forte@Sun.COM 3287836SJohn.Forte@Sun.COM static int 3297836SJohn.Forte@Sun.COM stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3307836SJohn.Forte@Sun.COM { 3317836SJohn.Forte@Sun.COM switch (cmd) { 3327836SJohn.Forte@Sun.COM case DDI_ATTACH: 3337836SJohn.Forte@Sun.COM stmf_state.stmf_dip = dip; 3347836SJohn.Forte@Sun.COM 3357836SJohn.Forte@Sun.COM if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0, 3367836SJohn.Forte@Sun.COM DDI_NT_STMF, 0) != DDI_SUCCESS) { 3377836SJohn.Forte@Sun.COM break; 3387836SJohn.Forte@Sun.COM } 3397836SJohn.Forte@Sun.COM ddi_report_dev(dip); 3407836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3417836SJohn.Forte@Sun.COM } 3427836SJohn.Forte@Sun.COM 3437836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3447836SJohn.Forte@Sun.COM } 3457836SJohn.Forte@Sun.COM 3467836SJohn.Forte@Sun.COM static int 3477836SJohn.Forte@Sun.COM stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3487836SJohn.Forte@Sun.COM { 3497836SJohn.Forte@Sun.COM switch (cmd) { 3507836SJohn.Forte@Sun.COM case DDI_DETACH: 3517836SJohn.Forte@Sun.COM ddi_remove_minor_node(dip, 0); 3527836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3537836SJohn.Forte@Sun.COM } 3547836SJohn.Forte@Sun.COM 3557836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3567836SJohn.Forte@Sun.COM } 3577836SJohn.Forte@Sun.COM 3587836SJohn.Forte@Sun.COM /* ARGSUSED */ 3597836SJohn.Forte@Sun.COM static int 3607836SJohn.Forte@Sun.COM stmf_open(dev_t *devp, int flag, int otype, cred_t *credp) 3617836SJohn.Forte@Sun.COM { 3627836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3637836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open) { 3647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3657836SJohn.Forte@Sun.COM return (EBUSY); 3667836SJohn.Forte@Sun.COM } 3677836SJohn.Forte@Sun.COM if (flag & FEXCL) { 3687836SJohn.Forte@Sun.COM if (stmf_state.stmf_opened) { 3697836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3707836SJohn.Forte@Sun.COM return (EBUSY); 3717836SJohn.Forte@Sun.COM } 3727836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 1; 3737836SJohn.Forte@Sun.COM } 3747836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 1; 3757836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3767836SJohn.Forte@Sun.COM return (0); 3777836SJohn.Forte@Sun.COM } 3787836SJohn.Forte@Sun.COM 3797836SJohn.Forte@Sun.COM /* ARGSUSED */ 3807836SJohn.Forte@Sun.COM static int 3817836SJohn.Forte@Sun.COM stmf_close(dev_t dev, int flag, int otype, cred_t *credp) 3827836SJohn.Forte@Sun.COM { 3837836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3847836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 0; 3857836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open && 3867836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) { 3877836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_NONE; 3887836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 3897836SJohn.Forte@Sun.COM stmf_view_clear_config(); 3907836SJohn.Forte@Sun.COM stmf_view_init(); 3917836SJohn.Forte@Sun.COM } 3927836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 0; 3937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3947836SJohn.Forte@Sun.COM return (0); 3957836SJohn.Forte@Sun.COM } 3967836SJohn.Forte@Sun.COM 3977836SJohn.Forte@Sun.COM int 3987836SJohn.Forte@Sun.COM stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd, 3997836SJohn.Forte@Sun.COM void **ibuf, void **obuf) 4007836SJohn.Forte@Sun.COM { 4017836SJohn.Forte@Sun.COM int ret; 4027836SJohn.Forte@Sun.COM 4037836SJohn.Forte@Sun.COM *ibuf = NULL; 4047836SJohn.Forte@Sun.COM *obuf = NULL; 4057836SJohn.Forte@Sun.COM *iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP); 4067836SJohn.Forte@Sun.COM 4077836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode); 4087836SJohn.Forte@Sun.COM if (ret) 4097836SJohn.Forte@Sun.COM return (EFAULT); 4107836SJohn.Forte@Sun.COM if ((*iocd)->stmf_version != STMF_VERSION_1) { 4117836SJohn.Forte@Sun.COM ret = EINVAL; 4127836SJohn.Forte@Sun.COM goto copyin_iocdata_done; 4137836SJohn.Forte@Sun.COM } 4147836SJohn.Forte@Sun.COM if ((*iocd)->stmf_ibuf_size) { 4157836SJohn.Forte@Sun.COM *ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP); 4167836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf), 4177836SJohn.Forte@Sun.COM *ibuf, (*iocd)->stmf_ibuf_size, mode); 4187836SJohn.Forte@Sun.COM } 4197836SJohn.Forte@Sun.COM if ((*iocd)->stmf_obuf_size) 4207836SJohn.Forte@Sun.COM *obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP); 4217836SJohn.Forte@Sun.COM 4227836SJohn.Forte@Sun.COM if (ret == 0) 4237836SJohn.Forte@Sun.COM return (0); 4247836SJohn.Forte@Sun.COM ret = EFAULT; 4257836SJohn.Forte@Sun.COM copyin_iocdata_done:; 4267836SJohn.Forte@Sun.COM if (*obuf) { 4277836SJohn.Forte@Sun.COM kmem_free(*obuf, (*iocd)->stmf_obuf_size); 4287836SJohn.Forte@Sun.COM *obuf = NULL; 4297836SJohn.Forte@Sun.COM } 4307836SJohn.Forte@Sun.COM if (*ibuf) { 4317836SJohn.Forte@Sun.COM kmem_free(*ibuf, (*iocd)->stmf_ibuf_size); 4327836SJohn.Forte@Sun.COM *ibuf = NULL; 4337836SJohn.Forte@Sun.COM } 4347836SJohn.Forte@Sun.COM kmem_free(*iocd, sizeof (stmf_iocdata_t)); 4357836SJohn.Forte@Sun.COM return (ret); 4367836SJohn.Forte@Sun.COM } 4377836SJohn.Forte@Sun.COM 4387836SJohn.Forte@Sun.COM int 4397836SJohn.Forte@Sun.COM stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf) 4407836SJohn.Forte@Sun.COM { 4417836SJohn.Forte@Sun.COM int ret; 4427836SJohn.Forte@Sun.COM 4437836SJohn.Forte@Sun.COM if (iocd->stmf_obuf_size) { 4447836SJohn.Forte@Sun.COM ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf, 4457836SJohn.Forte@Sun.COM iocd->stmf_obuf_size, mode); 4467836SJohn.Forte@Sun.COM if (ret) 4477836SJohn.Forte@Sun.COM return (EFAULT); 4487836SJohn.Forte@Sun.COM } 4497836SJohn.Forte@Sun.COM ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode); 4507836SJohn.Forte@Sun.COM if (ret) 4517836SJohn.Forte@Sun.COM return (EFAULT); 4527836SJohn.Forte@Sun.COM return (0); 4537836SJohn.Forte@Sun.COM } 4547836SJohn.Forte@Sun.COM 4557836SJohn.Forte@Sun.COM /* ARGSUSED */ 4567836SJohn.Forte@Sun.COM static int 4577836SJohn.Forte@Sun.COM stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 4587836SJohn.Forte@Sun.COM cred_t *credp, int *rval) 4597836SJohn.Forte@Sun.COM { 4607836SJohn.Forte@Sun.COM stmf_iocdata_t *iocd; 4617836SJohn.Forte@Sun.COM void *ibuf = NULL, *obuf = NULL; 4627836SJohn.Forte@Sun.COM slist_lu_t *luid_list; 4637836SJohn.Forte@Sun.COM slist_target_port_t *lportid_list; 4647836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 4657836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 4667836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 4677836SJohn.Forte@Sun.COM slist_scsi_session_t *iss_list; 4687836SJohn.Forte@Sun.COM sioc_lu_props_t *lup; 4697836SJohn.Forte@Sun.COM sioc_target_port_props_t *lportp; 4709585STim.Szeto@Sun.COM stmf_ppioctl_data_t *ppi, *ppi_out = NULL; 4719585STim.Szeto@Sun.COM uint64_t *ppi_token = NULL; 4729585STim.Szeto@Sun.COM uint8_t *p_id, *id; 4737836SJohn.Forte@Sun.COM stmf_state_desc_t *std; 4747836SJohn.Forte@Sun.COM stmf_status_t ctl_ret; 4757836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 4767836SJohn.Forte@Sun.COM int ret = 0; 4777836SJohn.Forte@Sun.COM uint32_t n; 4787836SJohn.Forte@Sun.COM int i; 4797836SJohn.Forte@Sun.COM stmf_group_op_data_t *grp_entry; 4807836SJohn.Forte@Sun.COM stmf_group_name_t *grpname; 4817836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve; 4827836SJohn.Forte@Sun.COM stmf_id_type_t idtype; 4837836SJohn.Forte@Sun.COM stmf_id_data_t *id_entry; 4847836SJohn.Forte@Sun.COM stmf_id_list_t *id_list; 4857836SJohn.Forte@Sun.COM stmf_view_entry_t *view_entry; 4867836SJohn.Forte@Sun.COM uint32_t veid; 4877836SJohn.Forte@Sun.COM 4887836SJohn.Forte@Sun.COM if ((cmd & 0xff000000) != STMF_IOCTL) { 4897836SJohn.Forte@Sun.COM return (ENOTTY); 4907836SJohn.Forte@Sun.COM } 4917836SJohn.Forte@Sun.COM 4927836SJohn.Forte@Sun.COM if (drv_priv(credp) != 0) { 4937836SJohn.Forte@Sun.COM return (EPERM); 4947836SJohn.Forte@Sun.COM } 4957836SJohn.Forte@Sun.COM 4967836SJohn.Forte@Sun.COM ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf); 4977836SJohn.Forte@Sun.COM if (ret) 4987836SJohn.Forte@Sun.COM return (ret); 4997836SJohn.Forte@Sun.COM iocd->stmf_error = 0; 5007836SJohn.Forte@Sun.COM 5017836SJohn.Forte@Sun.COM switch (cmd) { 5027836SJohn.Forte@Sun.COM case STMF_IOCTL_LU_LIST: 5039585STim.Szeto@Sun.COM /* retrieves both registered/unregistered */ 5049585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5059585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 5069585STim.Szeto@Sun.COM n = min(id_list->id_count, 5079585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 5089585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 5099585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 5109585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 5119585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 5129585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 5139585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 5149585STim.Szeto@Sun.COM } 5159585STim.Szeto@Sun.COM 5169585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (slist_lu_t); 5179585STim.Szeto@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 5189585STim.Szeto@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 5199585STim.Szeto@Sun.COM if (stmf_lookup_id(id_list, 16, id + 4) == NULL) { 5209585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 5219585STim.Szeto@Sun.COM if (i < n) { 5229585STim.Szeto@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 5239585STim.Szeto@Sun.COM sizeof (slist_lu_t)); 5249585STim.Szeto@Sun.COM i++; 5259585STim.Szeto@Sun.COM } 5269585STim.Szeto@Sun.COM } 5279585STim.Szeto@Sun.COM } 5289585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = i; 5299585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5309585STim.Szeto@Sun.COM break; 5319585STim.Szeto@Sun.COM 5329585STim.Szeto@Sun.COM case STMF_IOCTL_REG_LU_LIST: 5337836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5347836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus; 5357836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlus, 5368662SJordan.Vaughan@Sun.com (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 5377836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5387836SJohn.Forte@Sun.COM ilu = stmf_state.stmf_ilulist; 5397836SJohn.Forte@Sun.COM luid_list = (slist_lu_t *)obuf; 5407836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5417836SJohn.Forte@Sun.COM uint8_t *id; 5427836SJohn.Forte@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 5437836SJohn.Forte@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 16); 5447836SJohn.Forte@Sun.COM ilu = ilu->ilu_next; 5457836SJohn.Forte@Sun.COM } 5467836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5477836SJohn.Forte@Sun.COM break; 5487836SJohn.Forte@Sun.COM 5499585STim.Szeto@Sun.COM case STMF_IOCTL_VE_LU_LIST: 5509585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5519585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 5529585STim.Szeto@Sun.COM n = min(id_list->id_count, 5539585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 5549585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 5559585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = n; 5569585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 5579585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 5589585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 5599585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 5609585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 5619585STim.Szeto@Sun.COM } 5629585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5639585STim.Szeto@Sun.COM break; 5649585STim.Szeto@Sun.COM 5657836SJohn.Forte@Sun.COM case STMF_IOCTL_TARGET_PORT_LIST: 5667836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5677836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports; 5687836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlports, 5698662SJordan.Vaughan@Sun.com (iocd->stmf_obuf_size)/sizeof (slist_target_port_t)); 5707836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5717836SJohn.Forte@Sun.COM ilport = stmf_state.stmf_ilportlist; 5727836SJohn.Forte@Sun.COM lportid_list = (slist_target_port_t *)obuf; 5737836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5747836SJohn.Forte@Sun.COM uint8_t *id; 5757836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5767836SJohn.Forte@Sun.COM bcopy(id, lportid_list[i].target, id[3] + 4); 5777836SJohn.Forte@Sun.COM ilport = ilport->ilport_next; 5787836SJohn.Forte@Sun.COM } 5797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5807836SJohn.Forte@Sun.COM break; 5817836SJohn.Forte@Sun.COM 5827836SJohn.Forte@Sun.COM case STMF_IOCTL_SESSION_LIST: 5837836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 5847836SJohn.Forte@Sun.COM if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) || 5857836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4))) { 5867836SJohn.Forte@Sun.COM ret = EINVAL; 5877836SJohn.Forte@Sun.COM break; 5887836SJohn.Forte@Sun.COM } 5897836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5907836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; ilport = 5918662SJordan.Vaughan@Sun.com ilport->ilport_next) { 5927836SJohn.Forte@Sun.COM uint8_t *id; 5937836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5947836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 5957836SJohn.Forte@Sun.COM (bcmp(p_id + 4, id + 4, id[3]) == 0)) { 5967836SJohn.Forte@Sun.COM break; 5977836SJohn.Forte@Sun.COM } 5987836SJohn.Forte@Sun.COM } 5997836SJohn.Forte@Sun.COM if (ilport == NULL) { 6007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6017836SJohn.Forte@Sun.COM ret = ENOENT; 6027836SJohn.Forte@Sun.COM break; 6037836SJohn.Forte@Sun.COM } 6047836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions; 6057836SJohn.Forte@Sun.COM n = min(ilport->ilport_nsessions, 6067836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t)); 6077836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 6087836SJohn.Forte@Sun.COM iss = ilport->ilport_ss_list; 6097836SJohn.Forte@Sun.COM iss_list = (slist_scsi_session_t *)obuf; 6107836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 6117836SJohn.Forte@Sun.COM uint8_t *id; 6127836SJohn.Forte@Sun.COM id = (uint8_t *)iss->iss_ss->ss_rport_id; 6137836SJohn.Forte@Sun.COM bcopy(id, iss_list[i].initiator, id[3] + 4); 6147836SJohn.Forte@Sun.COM iss_list[i].creation_time = (uint32_t) 6157836SJohn.Forte@Sun.COM iss->iss_creation_time; 6167836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_rport_alias) { 6177836SJohn.Forte@Sun.COM (void) strncpy(iss_list[i].alias, 6187836SJohn.Forte@Sun.COM iss->iss_ss->ss_rport_alias, 255); 6197836SJohn.Forte@Sun.COM iss_list[i].alias[255] = 0; 6207836SJohn.Forte@Sun.COM } else { 6217836SJohn.Forte@Sun.COM iss_list[i].alias[0] = 0; 6227836SJohn.Forte@Sun.COM } 6237836SJohn.Forte@Sun.COM iss = iss->iss_next; 6247836SJohn.Forte@Sun.COM } 6257836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6267836SJohn.Forte@Sun.COM break; 6277836SJohn.Forte@Sun.COM 6287836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_LU_PROPERTIES: 6297836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 6307836SJohn.Forte@Sun.COM if ((iocd->stmf_ibuf_size < 16) || 6317836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) || 6327836SJohn.Forte@Sun.COM (p_id[0] == 0)) { 6337836SJohn.Forte@Sun.COM ret = EINVAL; 6347836SJohn.Forte@Sun.COM break; 6357836SJohn.Forte@Sun.COM } 6367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6377836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 6387836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 6397836SJohn.Forte@Sun.COM break; 6407836SJohn.Forte@Sun.COM } 6417836SJohn.Forte@Sun.COM if (ilu == NULL) { 6427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6437836SJohn.Forte@Sun.COM ret = ENOENT; 6447836SJohn.Forte@Sun.COM break; 6457836SJohn.Forte@Sun.COM } 6467836SJohn.Forte@Sun.COM lup = (sioc_lu_props_t *)obuf; 6477836SJohn.Forte@Sun.COM bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16); 6487836SJohn.Forte@Sun.COM lup->lu_state = ilu->ilu_state & 0x0f; 6497836SJohn.Forte@Sun.COM lup->lu_present = 1; /* XXX */ 6507836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_provider_name, 6517836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_lp->lp_name, 255); 6527836SJohn.Forte@Sun.COM lup->lu_provider_name[254] = 0; 6537836SJohn.Forte@Sun.COM if (ilu->ilu_lu->lu_alias) { 6547836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_alias, 6557836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_alias, 255); 6567836SJohn.Forte@Sun.COM lup->lu_alias[255] = 0; 6577836SJohn.Forte@Sun.COM } else { 6587836SJohn.Forte@Sun.COM lup->lu_alias[0] = 0; 6597836SJohn.Forte@Sun.COM } 6607836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6617836SJohn.Forte@Sun.COM break; 6627836SJohn.Forte@Sun.COM 6637836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES: 6647836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 6657836SJohn.Forte@Sun.COM if ((p_id == NULL) || 6667836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4)) || 6677836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < 6687836SJohn.Forte@Sun.COM sizeof (sioc_target_port_props_t))) { 6697836SJohn.Forte@Sun.COM ret = EINVAL; 6707836SJohn.Forte@Sun.COM break; 6717836SJohn.Forte@Sun.COM } 6727836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6737836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 6747836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 6757836SJohn.Forte@Sun.COM uint8_t *id; 6767836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 6777836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 6787836SJohn.Forte@Sun.COM (bcmp(p_id+4, id+4, id[3]) == 0)) 6797836SJohn.Forte@Sun.COM break; 6807836SJohn.Forte@Sun.COM } 6817836SJohn.Forte@Sun.COM if (ilport == NULL) { 6827836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6837836SJohn.Forte@Sun.COM ret = ENOENT; 6847836SJohn.Forte@Sun.COM break; 6857836SJohn.Forte@Sun.COM } 6867836SJohn.Forte@Sun.COM lportp = (sioc_target_port_props_t *)obuf; 6877836SJohn.Forte@Sun.COM bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id, 6887836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_id->ident_length + 4); 6897836SJohn.Forte@Sun.COM lportp->tgt_state = ilport->ilport_state & 0x0f; 6907836SJohn.Forte@Sun.COM lportp->tgt_present = 1; /* XXX */ 6917836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_provider_name, 6927836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_pp->pp_name, 255); 6937836SJohn.Forte@Sun.COM lportp->tgt_provider_name[254] = 0; 6947836SJohn.Forte@Sun.COM if (ilport->ilport_lport->lport_alias) { 6957836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_alias, 6967836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_alias, 255); 6977836SJohn.Forte@Sun.COM lportp->tgt_alias[255] = 0; 6987836SJohn.Forte@Sun.COM } else { 6997836SJohn.Forte@Sun.COM lportp->tgt_alias[0] = 0; 7007836SJohn.Forte@Sun.COM } 7017836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7027836SJohn.Forte@Sun.COM break; 7037836SJohn.Forte@Sun.COM 7047836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_STMF_STATE: 7057836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7067836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 7077836SJohn.Forte@Sun.COM ret = EINVAL; 7087836SJohn.Forte@Sun.COM break; 7097836SJohn.Forte@Sun.COM } 7107836SJohn.Forte@Sun.COM ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf); 7117836SJohn.Forte@Sun.COM break; 7127836SJohn.Forte@Sun.COM 7137836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_STMF_STATE: 7147836SJohn.Forte@Sun.COM if ((obuf == NULL) || 7157836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) { 7167836SJohn.Forte@Sun.COM ret = EINVAL; 7177836SJohn.Forte@Sun.COM break; 7187836SJohn.Forte@Sun.COM } 7197836SJohn.Forte@Sun.COM ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf); 7207836SJohn.Forte@Sun.COM break; 7217836SJohn.Forte@Sun.COM 72210725SJohn.Forte@Sun.COM case STMF_IOCTL_SET_ALUA_STATE: 72310725SJohn.Forte@Sun.COM if ((ibuf == NULL) || 72410725SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_alua_state_desc_t))) { 72510725SJohn.Forte@Sun.COM ret = EINVAL; 72610725SJohn.Forte@Sun.COM break; 72710725SJohn.Forte@Sun.COM } 72810725SJohn.Forte@Sun.COM ret = stmf_set_alua_state((stmf_alua_state_desc_t *)ibuf); 72910725SJohn.Forte@Sun.COM break; 73010725SJohn.Forte@Sun.COM 73110725SJohn.Forte@Sun.COM case STMF_IOCTL_GET_ALUA_STATE: 73210725SJohn.Forte@Sun.COM if ((obuf == NULL) || 73310725SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_alua_state_desc_t))) { 73410725SJohn.Forte@Sun.COM ret = EINVAL; 73510725SJohn.Forte@Sun.COM break; 73610725SJohn.Forte@Sun.COM } 73710725SJohn.Forte@Sun.COM stmf_get_alua_state((stmf_alua_state_desc_t *)obuf); 73810725SJohn.Forte@Sun.COM break; 73910725SJohn.Forte@Sun.COM 7407836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_LU_STATE: 7417836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 7427836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 7437836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 7447836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7457836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 7467836SJohn.Forte@Sun.COM ret = EINVAL; 7477836SJohn.Forte@Sun.COM break; 7487836SJohn.Forte@Sun.COM } 7497836SJohn.Forte@Sun.COM p_id = std->ident; 7507836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7517836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 7527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7537836SJohn.Forte@Sun.COM ret = EBUSY; 7547836SJohn.Forte@Sun.COM break; 7557836SJohn.Forte@Sun.COM } 7567836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 7577836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 7587836SJohn.Forte@Sun.COM break; 7597836SJohn.Forte@Sun.COM } 7607836SJohn.Forte@Sun.COM if (ilu == NULL) { 7617836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7627836SJohn.Forte@Sun.COM ret = ENOENT; 7637836SJohn.Forte@Sun.COM break; 7647836SJohn.Forte@Sun.COM } 7657836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 7667836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7677836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE : 7687836SJohn.Forte@Sun.COM STMF_CMD_LU_OFFLINE; 7697836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi); 7707836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 7717836SJohn.Forte@Sun.COM ret = 0; 7727836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 7737836SJohn.Forte@Sun.COM ret = EIO; 7747836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7757836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 7767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7777836SJohn.Forte@Sun.COM break; 7787836SJohn.Forte@Sun.COM 7797836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_TARGET_PORT_STATE: 7807836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 7817836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 7827836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 7837836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7847836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 7857836SJohn.Forte@Sun.COM ret = EINVAL; 7867836SJohn.Forte@Sun.COM break; 7877836SJohn.Forte@Sun.COM } 7887836SJohn.Forte@Sun.COM p_id = std->ident; 7897836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7907836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 7917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7927836SJohn.Forte@Sun.COM ret = EBUSY; 7937836SJohn.Forte@Sun.COM break; 7947836SJohn.Forte@Sun.COM } 7957836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 7967836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 7977836SJohn.Forte@Sun.COM uint8_t *id; 7987836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 7997836SJohn.Forte@Sun.COM if ((id[3] == p_id[3]) && 8007836SJohn.Forte@Sun.COM (bcmp(id+4, p_id+4, id[3]) == 0)) { 8017836SJohn.Forte@Sun.COM break; 8027836SJohn.Forte@Sun.COM } 8037836SJohn.Forte@Sun.COM } 8047836SJohn.Forte@Sun.COM if (ilport == NULL) { 8057836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8067836SJohn.Forte@Sun.COM ret = ENOENT; 8077836SJohn.Forte@Sun.COM break; 8087836SJohn.Forte@Sun.COM } 8097836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 8107836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8117836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? 8127836SJohn.Forte@Sun.COM STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE; 8137836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi); 8147836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 8157836SJohn.Forte@Sun.COM ret = 0; 8167836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 8177836SJohn.Forte@Sun.COM ret = EIO; 8187836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8197836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 8207836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8217836SJohn.Forte@Sun.COM break; 8227836SJohn.Forte@Sun.COM 8237836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_HG_ENTRY: 8247836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 8257836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8267836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TG_ENTRY: 8277836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8287836SJohn.Forte@Sun.COM ret = EACCES; 8297836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8307836SJohn.Forte@Sun.COM break; 8317836SJohn.Forte@Sun.COM } 8327836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_ADD_TG_ENTRY) { 8337836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 8347836SJohn.Forte@Sun.COM } 8357836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 8367836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8377836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 8387836SJohn.Forte@Sun.COM ret = EINVAL; 8397836SJohn.Forte@Sun.COM break; 8407836SJohn.Forte@Sun.COM } 8417836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 8427836SJohn.Forte@Sun.COM ret = EINVAL; 8437836SJohn.Forte@Sun.COM break; /* not allowed */ 8447836SJohn.Forte@Sun.COM } 8457836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8467836SJohn.Forte@Sun.COM ret = stmf_add_group_member(grp_entry->group.name, 8477836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8487836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8497836SJohn.Forte@Sun.COM grp_entry->ident[3], 8507836SJohn.Forte@Sun.COM idtype, 8517836SJohn.Forte@Sun.COM &iocd->stmf_error); 8527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8537836SJohn.Forte@Sun.COM break; 8547836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HG_ENTRY: 8557836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 8567836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8577836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TG_ENTRY: 8587836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8597836SJohn.Forte@Sun.COM ret = EACCES; 8607836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8617836SJohn.Forte@Sun.COM break; 8627836SJohn.Forte@Sun.COM } 8637836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) { 8647836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 8657836SJohn.Forte@Sun.COM } 8667836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 8677836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8687836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 8697836SJohn.Forte@Sun.COM ret = EINVAL; 8707836SJohn.Forte@Sun.COM break; 8717836SJohn.Forte@Sun.COM } 8727836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 8737836SJohn.Forte@Sun.COM ret = EINVAL; 8747836SJohn.Forte@Sun.COM break; /* not allowed */ 8757836SJohn.Forte@Sun.COM } 8767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8777836SJohn.Forte@Sun.COM ret = stmf_remove_group_member(grp_entry->group.name, 8787836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8797836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8807836SJohn.Forte@Sun.COM grp_entry->ident[3], 8817836SJohn.Forte@Sun.COM idtype, 8827836SJohn.Forte@Sun.COM &iocd->stmf_error); 8837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8847836SJohn.Forte@Sun.COM break; 8857836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_HOST_GROUP: 8867836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8877836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8887836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_TARGET_GROUP: 8897836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8907836SJohn.Forte@Sun.COM ret = EACCES; 8917836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8927836SJohn.Forte@Sun.COM break; 8937836SJohn.Forte@Sun.COM } 8947836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8957836SJohn.Forte@Sun.COM 8967836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP) 8977836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8987836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8997836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 9007836SJohn.Forte@Sun.COM ret = EINVAL; 9017836SJohn.Forte@Sun.COM break; 9027836SJohn.Forte@Sun.COM } 9037836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 9047836SJohn.Forte@Sun.COM ret = EINVAL; 9057836SJohn.Forte@Sun.COM break; /* not allowed */ 9067836SJohn.Forte@Sun.COM } 9077836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9087836SJohn.Forte@Sun.COM ret = stmf_add_group(grpname->name, 9097836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 9107836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9117836SJohn.Forte@Sun.COM break; 9127836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HOST_GROUP: 9137836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 9147836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9157836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TARGET_GROUP: 9167836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9177836SJohn.Forte@Sun.COM ret = EACCES; 9187836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9197836SJohn.Forte@Sun.COM break; 9207836SJohn.Forte@Sun.COM } 9217836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 9227836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP) 9237836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 9247836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9257836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 9267836SJohn.Forte@Sun.COM ret = EINVAL; 9277836SJohn.Forte@Sun.COM break; 9287836SJohn.Forte@Sun.COM } 9297836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 9307836SJohn.Forte@Sun.COM ret = EINVAL; 9317836SJohn.Forte@Sun.COM break; /* not allowed */ 9327836SJohn.Forte@Sun.COM } 9337836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9347836SJohn.Forte@Sun.COM ret = stmf_remove_group(grpname->name, 9357836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 9367836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9377836SJohn.Forte@Sun.COM break; 93810691STim.Szeto@Sun.COM case STMF_IOCTL_VALIDATE_VIEW: 9397836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_VIEW_ENTRY: 9407836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9417836SJohn.Forte@Sun.COM ret = EACCES; 9427836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9437836SJohn.Forte@Sun.COM break; 9447836SJohn.Forte@Sun.COM } 9457836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 9467836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9477836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 9487836SJohn.Forte@Sun.COM ret = EINVAL; 9497836SJohn.Forte@Sun.COM break; 9507836SJohn.Forte@Sun.COM } 9517836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) 9527836SJohn.Forte@Sun.COM ve->ve_lu_nbr[2] = 0xFF; 9537836SJohn.Forte@Sun.COM if (ve->ve_all_hosts) { 9547836SJohn.Forte@Sun.COM ve->ve_host_group.name[0] = '*'; 9557836SJohn.Forte@Sun.COM ve->ve_host_group.name_size = 1; 9567836SJohn.Forte@Sun.COM } 9577836SJohn.Forte@Sun.COM if (ve->ve_all_targets) { 9587836SJohn.Forte@Sun.COM ve->ve_target_group.name[0] = '*'; 9597836SJohn.Forte@Sun.COM ve->ve_target_group.name_size = 1; 9607836SJohn.Forte@Sun.COM } 9617836SJohn.Forte@Sun.COM if (ve->ve_ndx_valid) 9627836SJohn.Forte@Sun.COM veid = ve->ve_ndx; 9637836SJohn.Forte@Sun.COM else 9647836SJohn.Forte@Sun.COM veid = 0xffffffff; 9657836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 96610691STim.Szeto@Sun.COM if (cmd == STMF_IOCTL_ADD_VIEW_ENTRY) { 96710691STim.Szeto@Sun.COM ret = stmf_add_ve(ve->ve_host_group.name, 96810691STim.Szeto@Sun.COM ve->ve_host_group.name_size, 96910691STim.Szeto@Sun.COM ve->ve_target_group.name, 97010691STim.Szeto@Sun.COM ve->ve_target_group.name_size, 97110691STim.Szeto@Sun.COM ve->ve_guid, 97210691STim.Szeto@Sun.COM &veid, 97310691STim.Szeto@Sun.COM ve->ve_lu_nbr, 97410691STim.Szeto@Sun.COM &iocd->stmf_error); 97510691STim.Szeto@Sun.COM } else { /* STMF_IOCTL_VALIDATE_VIEW */ 97610691STim.Szeto@Sun.COM ret = stmf_validate_lun_ve(ve->ve_host_group.name, 97710691STim.Szeto@Sun.COM ve->ve_host_group.name_size, 97810691STim.Szeto@Sun.COM ve->ve_target_group.name, 97910691STim.Szeto@Sun.COM ve->ve_target_group.name_size, 98010691STim.Szeto@Sun.COM ve->ve_lu_nbr, 98110691STim.Szeto@Sun.COM &iocd->stmf_error); 98210691STim.Szeto@Sun.COM } 9837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9847836SJohn.Forte@Sun.COM if (ret == 0 && 9857836SJohn.Forte@Sun.COM (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) && 9867836SJohn.Forte@Sun.COM iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) { 9877836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve_ret = 9887836SJohn.Forte@Sun.COM (stmf_view_op_entry_t *)obuf; 9897836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = 1; 9907836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = 1; 9917836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9927836SJohn.Forte@Sun.COM ve_ret->ve_ndx = veid; 9937836SJohn.Forte@Sun.COM ve_ret->ve_ndx_valid = 1; 9947836SJohn.Forte@Sun.COM } 9957836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) { 9967836SJohn.Forte@Sun.COM ve_ret->ve_lu_number_valid = 1; 9977836SJohn.Forte@Sun.COM bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8); 9987836SJohn.Forte@Sun.COM } 9997836SJohn.Forte@Sun.COM } 10007836SJohn.Forte@Sun.COM break; 10017836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_VIEW_ENTRY: 10027836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 10037836SJohn.Forte@Sun.COM ret = EACCES; 10047836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 10057836SJohn.Forte@Sun.COM break; 10067836SJohn.Forte@Sun.COM } 10077836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 10087836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 10097836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 10107836SJohn.Forte@Sun.COM ret = EINVAL; 10117836SJohn.Forte@Sun.COM break; 10127836SJohn.Forte@Sun.COM } 10137836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 10147836SJohn.Forte@Sun.COM ret = EINVAL; 10157836SJohn.Forte@Sun.COM break; 10167836SJohn.Forte@Sun.COM } 10177836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10187836SJohn.Forte@Sun.COM ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx, 10197836SJohn.Forte@Sun.COM &iocd->stmf_error); 10207836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10217836SJohn.Forte@Sun.COM break; 10227836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_LIST: 10237836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 10247836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 10257836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_LIST: 10267836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_LIST) 10277836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 10287836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10297836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 10307836SJohn.Forte@Sun.COM n = min(id_list->id_count, 10317836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t)); 10327836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 10337836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 10347836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)obuf; 10357836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 10369585STim.Szeto@Sun.COM if (id_entry->id_data[0] == '*') { 10379585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries > 0) { 10389585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries--; 10399585STim.Szeto@Sun.COM } 10409585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 10419585STim.Szeto@Sun.COM continue; 10429585STim.Szeto@Sun.COM } 10439585STim.Szeto@Sun.COM grpname->name_size = id_entry->id_data_size; 10449585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grpname->name, 10457836SJohn.Forte@Sun.COM id_entry->id_data_size); 10469585STim.Szeto@Sun.COM grpname++; 10477836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 10487836SJohn.Forte@Sun.COM } 10497836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10507836SJohn.Forte@Sun.COM break; 10517836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_ENTRIES: 10527836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 10537836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 10547836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_ENTRIES: 10557836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 10567836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 10577836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 10587836SJohn.Forte@Sun.COM ret = EINVAL; 10597836SJohn.Forte@Sun.COM break; 10607836SJohn.Forte@Sun.COM } 10617836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_ENTRIES) { 10627836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 10637836SJohn.Forte@Sun.COM } 10647836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10657836SJohn.Forte@Sun.COM id_entry = stmf_lookup_id(id_list, grpname->name_size, 10667836SJohn.Forte@Sun.COM grpname->name); 10677836SJohn.Forte@Sun.COM if (!id_entry) 10687836SJohn.Forte@Sun.COM ret = ENODEV; 10697836SJohn.Forte@Sun.COM else { 10707836SJohn.Forte@Sun.COM stmf_ge_ident_t *grp_entry; 10717836SJohn.Forte@Sun.COM id_list = (stmf_id_list_t *)id_entry->id_impl_specific; 10727836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 10737836SJohn.Forte@Sun.COM n = min(id_list->id_count, 10747836SJohn.Forte@Sun.COM iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t)); 10757836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 10767836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 10777836SJohn.Forte@Sun.COM grp_entry = (stmf_ge_ident_t *)obuf; 10787836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 10799585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grp_entry->ident, 10807836SJohn.Forte@Sun.COM id_entry->id_data_size); 10819585STim.Szeto@Sun.COM grp_entry->ident_size = id_entry->id_data_size; 10827836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 10839585STim.Szeto@Sun.COM grp_entry++; 10847836SJohn.Forte@Sun.COM } 10857836SJohn.Forte@Sun.COM } 10867836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10877836SJohn.Forte@Sun.COM break; 10889585STim.Szeto@Sun.COM 10897836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_VE_LIST: 10907836SJohn.Forte@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 10917836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10927836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 10939585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 10949585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 10959585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 10969585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 10979585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 10989585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 10999585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 11009585STim.Szeto@Sun.COM continue; 11017836SJohn.Forte@Sun.COM ve->ve_ndx_valid = 1; 11027836SJohn.Forte@Sun.COM ve->ve_ndx = view_entry->ve_id; 11037836SJohn.Forte@Sun.COM ve->ve_lu_number_valid = 1; 11047836SJohn.Forte@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 11057836SJohn.Forte@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 11067836SJohn.Forte@Sun.COM view_entry->ve_luid->id_data_size); 11079585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 11087836SJohn.Forte@Sun.COM ve->ve_all_hosts = 1; 11099585STim.Szeto@Sun.COM } else { 11107836SJohn.Forte@Sun.COM bcopy(view_entry->ve_hg->id_data, 11117836SJohn.Forte@Sun.COM ve->ve_host_group.name, 11127836SJohn.Forte@Sun.COM view_entry->ve_hg->id_data_size); 11139585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 11149585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 11159585STim.Szeto@Sun.COM } 11169585STim.Szeto@Sun.COM 11179585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 11187836SJohn.Forte@Sun.COM ve->ve_all_targets = 1; 11199585STim.Szeto@Sun.COM } else { 11207836SJohn.Forte@Sun.COM bcopy(view_entry->ve_tg->id_data, 11217836SJohn.Forte@Sun.COM ve->ve_target_group.name, 11227836SJohn.Forte@Sun.COM view_entry->ve_tg->id_data_size); 11239585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 11249585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 11259585STim.Szeto@Sun.COM } 11269585STim.Szeto@Sun.COM ve++; 11277836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries++; 11287836SJohn.Forte@Sun.COM } 11297836SJohn.Forte@Sun.COM } 11307836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11317836SJohn.Forte@Sun.COM break; 11329585STim.Szeto@Sun.COM 11339585STim.Szeto@Sun.COM case STMF_IOCTL_LU_VE_LIST: 11349585STim.Szeto@Sun.COM p_id = (uint8_t *)ibuf; 11359585STim.Szeto@Sun.COM if ((iocd->stmf_ibuf_size != 16) || 11369585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) { 11379585STim.Szeto@Sun.COM ret = EINVAL; 11389585STim.Szeto@Sun.COM break; 11399585STim.Szeto@Sun.COM } 11409585STim.Szeto@Sun.COM 11419585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 11429585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 11439585STim.Szeto@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 11449585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 11459585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 11469585STim.Szeto@Sun.COM if (bcmp(id_entry->id_data, p_id, 16) != 0) 11479585STim.Szeto@Sun.COM continue; 11489585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 11499585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 11509585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 11519585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 11529585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 11539585STim.Szeto@Sun.COM continue; 11549585STim.Szeto@Sun.COM ve->ve_ndx_valid = 1; 11559585STim.Szeto@Sun.COM ve->ve_ndx = view_entry->ve_id; 11569585STim.Szeto@Sun.COM ve->ve_lu_number_valid = 1; 11579585STim.Szeto@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 11589585STim.Szeto@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 11599585STim.Szeto@Sun.COM view_entry->ve_luid->id_data_size); 11609585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 11619585STim.Szeto@Sun.COM ve->ve_all_hosts = 1; 11629585STim.Szeto@Sun.COM } else { 11639585STim.Szeto@Sun.COM bcopy(view_entry->ve_hg->id_data, 11649585STim.Szeto@Sun.COM ve->ve_host_group.name, 11659585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size); 11669585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 11679585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 11689585STim.Szeto@Sun.COM } 11699585STim.Szeto@Sun.COM 11709585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 11719585STim.Szeto@Sun.COM ve->ve_all_targets = 1; 11729585STim.Szeto@Sun.COM } else { 11739585STim.Szeto@Sun.COM bcopy(view_entry->ve_tg->id_data, 11749585STim.Szeto@Sun.COM ve->ve_target_group.name, 11759585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size); 11769585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 11779585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 11789585STim.Szeto@Sun.COM } 11799585STim.Szeto@Sun.COM ve++; 11809585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries++; 11819585STim.Szeto@Sun.COM } 11829585STim.Szeto@Sun.COM break; 11839585STim.Szeto@Sun.COM } 11849585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11859585STim.Szeto@Sun.COM break; 11869585STim.Szeto@Sun.COM 11877836SJohn.Forte@Sun.COM case STMF_IOCTL_LOAD_PP_DATA: 11887836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11897836SJohn.Forte@Sun.COM ret = EACCES; 11907836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11917836SJohn.Forte@Sun.COM break; 11927836SJohn.Forte@Sun.COM } 11937836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11947836SJohn.Forte@Sun.COM if ((ppi == NULL) || 11957836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11967836SJohn.Forte@Sun.COM ret = EINVAL; 11977836SJohn.Forte@Sun.COM break; 11987836SJohn.Forte@Sun.COM } 11999585STim.Szeto@Sun.COM /* returned token */ 12009585STim.Szeto@Sun.COM ppi_token = (uint64_t *)obuf; 12019585STim.Szeto@Sun.COM if ((ppi_token == NULL) || 12029585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (uint64_t))) { 12039585STim.Szeto@Sun.COM ret = EINVAL; 12049585STim.Szeto@Sun.COM break; 12059585STim.Szeto@Sun.COM } 12069585STim.Szeto@Sun.COM ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error); 12079585STim.Szeto@Sun.COM break; 12089585STim.Szeto@Sun.COM 12099585STim.Szeto@Sun.COM case STMF_IOCTL_GET_PP_DATA: 12109585STim.Szeto@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 12119585STim.Szeto@Sun.COM ret = EACCES; 12129585STim.Szeto@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 12139585STim.Szeto@Sun.COM break; 12149585STim.Szeto@Sun.COM } 12159585STim.Szeto@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 12169585STim.Szeto@Sun.COM if (ppi == NULL || 12179585STim.Szeto@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 12189585STim.Szeto@Sun.COM ret = EINVAL; 12199585STim.Szeto@Sun.COM break; 12209585STim.Szeto@Sun.COM } 12219585STim.Szeto@Sun.COM ppi_out = (stmf_ppioctl_data_t *)obuf; 12229585STim.Szeto@Sun.COM if ((ppi_out == NULL) || 12239585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) { 12249585STim.Szeto@Sun.COM ret = EINVAL; 12259585STim.Szeto@Sun.COM break; 12269585STim.Szeto@Sun.COM } 12279585STim.Szeto@Sun.COM ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error); 12287836SJohn.Forte@Sun.COM break; 12297836SJohn.Forte@Sun.COM 12307836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_PP_DATA: 12317836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 12327836SJohn.Forte@Sun.COM ret = EACCES; 12337836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 12347836SJohn.Forte@Sun.COM break; 12357836SJohn.Forte@Sun.COM } 12367836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 12377836SJohn.Forte@Sun.COM if ((ppi == NULL) || 12387836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 12397836SJohn.Forte@Sun.COM ret = EINVAL; 12407836SJohn.Forte@Sun.COM break; 12417836SJohn.Forte@Sun.COM } 12427836SJohn.Forte@Sun.COM ret = stmf_delete_ppd_ioctl(ppi); 12437836SJohn.Forte@Sun.COM break; 12447836SJohn.Forte@Sun.COM 12457836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_TRACE: 12467836SJohn.Forte@Sun.COM stmf_trace_clear(); 12477836SJohn.Forte@Sun.COM break; 12487836SJohn.Forte@Sun.COM 12497836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TRACE: 12507836SJohn.Forte@Sun.COM if (iocd->stmf_ibuf_size && ibuf) { 12517836SJohn.Forte@Sun.COM ((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0; 12527836SJohn.Forte@Sun.COM stmf_trace("\nstradm", "%s\n", ibuf); 12537836SJohn.Forte@Sun.COM } 12547836SJohn.Forte@Sun.COM break; 12557836SJohn.Forte@Sun.COM 12567836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE_POSITION: 12577836SJohn.Forte@Sun.COM if (obuf && (iocd->stmf_obuf_size > 3)) { 12587836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12597836SJohn.Forte@Sun.COM *((int *)obuf) = trace_buf_curndx; 12607836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12617836SJohn.Forte@Sun.COM } else { 12627836SJohn.Forte@Sun.COM ret = EINVAL; 12637836SJohn.Forte@Sun.COM } 12647836SJohn.Forte@Sun.COM break; 12657836SJohn.Forte@Sun.COM 12667836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE: 12677836SJohn.Forte@Sun.COM if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) { 12687836SJohn.Forte@Sun.COM ret = EINVAL; 12697836SJohn.Forte@Sun.COM break; 12707836SJohn.Forte@Sun.COM } 12717836SJohn.Forte@Sun.COM i = *((int *)ibuf); 12727836SJohn.Forte@Sun.COM if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) > 12737836SJohn.Forte@Sun.COM trace_buf_size)) { 12747836SJohn.Forte@Sun.COM ret = EINVAL; 12757836SJohn.Forte@Sun.COM break; 12767836SJohn.Forte@Sun.COM } 12777836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12787836SJohn.Forte@Sun.COM bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size); 12797836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12807836SJohn.Forte@Sun.COM break; 12817836SJohn.Forte@Sun.COM 12827836SJohn.Forte@Sun.COM default: 12837836SJohn.Forte@Sun.COM ret = ENOTTY; 12847836SJohn.Forte@Sun.COM } 12857836SJohn.Forte@Sun.COM 12867836SJohn.Forte@Sun.COM if (ret == 0) { 12877836SJohn.Forte@Sun.COM ret = stmf_copyout_iocdata(data, mode, iocd, obuf); 12887836SJohn.Forte@Sun.COM } else if (iocd->stmf_error) { 12897836SJohn.Forte@Sun.COM (void) stmf_copyout_iocdata(data, mode, iocd, obuf); 12907836SJohn.Forte@Sun.COM } 12917836SJohn.Forte@Sun.COM if (obuf) { 12927836SJohn.Forte@Sun.COM kmem_free(obuf, iocd->stmf_obuf_size); 12937836SJohn.Forte@Sun.COM obuf = NULL; 12947836SJohn.Forte@Sun.COM } 12957836SJohn.Forte@Sun.COM if (ibuf) { 12967836SJohn.Forte@Sun.COM kmem_free(ibuf, iocd->stmf_ibuf_size); 12977836SJohn.Forte@Sun.COM ibuf = NULL; 12987836SJohn.Forte@Sun.COM } 12997836SJohn.Forte@Sun.COM kmem_free(iocd, sizeof (stmf_iocdata_t)); 13007836SJohn.Forte@Sun.COM return (ret); 13017836SJohn.Forte@Sun.COM } 13027836SJohn.Forte@Sun.COM 13037836SJohn.Forte@Sun.COM static int 13047836SJohn.Forte@Sun.COM stmf_get_service_state() 13057836SJohn.Forte@Sun.COM { 13067836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 13077836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 13087836SJohn.Forte@Sun.COM int online = 0; 13097836SJohn.Forte@Sun.COM int offline = 0; 13107836SJohn.Forte@Sun.COM int onlining = 0; 13117836SJohn.Forte@Sun.COM int offlining = 0; 13127836SJohn.Forte@Sun.COM 13137836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 13147836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 13157836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 13167836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) 13177836SJohn.Forte@Sun.COM offline++; 13187836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINE) 13197836SJohn.Forte@Sun.COM online++; 13207836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINING) 13217836SJohn.Forte@Sun.COM onlining++; 13227836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_OFFLINING) 13237836SJohn.Forte@Sun.COM offlining++; 13247836SJohn.Forte@Sun.COM } 13257836SJohn.Forte@Sun.COM 13267836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 13277836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 13287836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) 13297836SJohn.Forte@Sun.COM offline++; 13307836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINE) 13317836SJohn.Forte@Sun.COM online++; 13327836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINING) 13337836SJohn.Forte@Sun.COM onlining++; 13347836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_OFFLINING) 13357836SJohn.Forte@Sun.COM offlining++; 13367836SJohn.Forte@Sun.COM } 13377836SJohn.Forte@Sun.COM 13387836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 13397836SJohn.Forte@Sun.COM if (onlining) 13407836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINING); 13417836SJohn.Forte@Sun.COM else 13427836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINE); 13437836SJohn.Forte@Sun.COM } 13447836SJohn.Forte@Sun.COM 13457836SJohn.Forte@Sun.COM if (offlining) { 13467836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINING); 13477836SJohn.Forte@Sun.COM } 13487836SJohn.Forte@Sun.COM 13497836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINE); 13507836SJohn.Forte@Sun.COM } 13517836SJohn.Forte@Sun.COM 13527836SJohn.Forte@Sun.COM static int 13537836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std) 13547836SJohn.Forte@Sun.COM { 13557836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 13567836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 13577836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 13587836SJohn.Forte@Sun.COM int svc_state; 13597836SJohn.Forte@Sun.COM 13607836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 13617836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 13627836SJohn.Forte@Sun.COM 13637836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 13647836SJohn.Forte@Sun.COM if (!stmf_state.stmf_exclusive_open) { 13657836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13667836SJohn.Forte@Sun.COM return (EACCES); 13677836SJohn.Forte@Sun.COM } 13687836SJohn.Forte@Sun.COM 13697836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 13707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13717836SJohn.Forte@Sun.COM return (EBUSY); 13727836SJohn.Forte@Sun.COM } 13737836SJohn.Forte@Sun.COM 13747836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_ONLINE) && 13757836SJohn.Forte@Sun.COM (std->state != STMF_STATE_OFFLINE)) { 13767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13777836SJohn.Forte@Sun.COM return (EINVAL); 13787836SJohn.Forte@Sun.COM } 13797836SJohn.Forte@Sun.COM 13807836SJohn.Forte@Sun.COM svc_state = stmf_get_service_state(); 13817836SJohn.Forte@Sun.COM if ((svc_state == STMF_STATE_OFFLINING) || 13827836SJohn.Forte@Sun.COM (svc_state == STMF_STATE_ONLINING)) { 13837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13847836SJohn.Forte@Sun.COM return (EBUSY); 13857836SJohn.Forte@Sun.COM } 13867836SJohn.Forte@Sun.COM 13877836SJohn.Forte@Sun.COM if (svc_state == STMF_STATE_OFFLINE) { 13887836SJohn.Forte@Sun.COM if (std->config_state == STMF_CONFIG_INIT) { 13897836SJohn.Forte@Sun.COM if (std->state != STMF_STATE_OFFLINE) { 13907836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13917836SJohn.Forte@Sun.COM return (EINVAL); 13927836SJohn.Forte@Sun.COM } 13937836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT; 13947836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 13957836SJohn.Forte@Sun.COM stmf_view_clear_config(); 13967836SJohn.Forte@Sun.COM stmf_view_init(); 13977836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13987836SJohn.Forte@Sun.COM return (0); 13997836SJohn.Forte@Sun.COM } 140010716SSusan.Gleeson@Sun.COM if ((stmf_state.stmf_config_state == STMF_CONFIG_INIT) || 140110716SSusan.Gleeson@Sun.COM (stmf_state.stmf_config_state == STMF_CONFIG_NONE)) { 14027836SJohn.Forte@Sun.COM if (std->config_state != STMF_CONFIG_INIT_DONE) { 14037836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14047836SJohn.Forte@Sun.COM return (EINVAL); 14057836SJohn.Forte@Sun.COM } 14067836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE; 14077836SJohn.Forte@Sun.COM } 14087836SJohn.Forte@Sun.COM if (std->state == STMF_STATE_OFFLINE) { 14097836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14107836SJohn.Forte@Sun.COM return (0); 14117836SJohn.Forte@Sun.COM } 14127836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 14137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14147836SJohn.Forte@Sun.COM return (EINVAL); 14157836SJohn.Forte@Sun.COM } 14167836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 14177836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 1; 14187836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14197836SJohn.Forte@Sun.COM 14207836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 14217836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 14227836SJohn.Forte@Sun.COM if (ilport->ilport_prev_state != STMF_STATE_ONLINE) 14237836SJohn.Forte@Sun.COM continue; 14247836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, 14258662SJordan.Vaughan@Sun.com ilport->ilport_lport, &ssi); 14267836SJohn.Forte@Sun.COM } 14277836SJohn.Forte@Sun.COM 14287836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 14297836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 14307836SJohn.Forte@Sun.COM if (ilu->ilu_prev_state != STMF_STATE_ONLINE) 14317836SJohn.Forte@Sun.COM continue; 14327836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi); 14337836SJohn.Forte@Sun.COM } 14347836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14357836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 14367836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14377836SJohn.Forte@Sun.COM return (0); 14387836SJohn.Forte@Sun.COM } 14397836SJohn.Forte@Sun.COM 14407836SJohn.Forte@Sun.COM /* svc_state is STMF_STATE_ONLINE here */ 14417836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_OFFLINE) || 14427836SJohn.Forte@Sun.COM (std->config_state == STMF_CONFIG_INIT)) { 14437836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14447836SJohn.Forte@Sun.COM return (EACCES); 14457836SJohn.Forte@Sun.COM } 14467836SJohn.Forte@Sun.COM 14477836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 14487836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 144910560SSusan.Gleeson@Sun.COM 14507836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14517836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 14527836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 14537836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) 14547836SJohn.Forte@Sun.COM continue; 14557836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, 14567836SJohn.Forte@Sun.COM ilport->ilport_lport, &ssi); 14577836SJohn.Forte@Sun.COM } 14587836SJohn.Forte@Sun.COM 14597836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 14607836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 14617836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) 14627836SJohn.Forte@Sun.COM continue; 14637836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi); 14647836SJohn.Forte@Sun.COM } 14657836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14667836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 14677836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14687836SJohn.Forte@Sun.COM return (0); 14697836SJohn.Forte@Sun.COM } 14707836SJohn.Forte@Sun.COM 14717836SJohn.Forte@Sun.COM static int 14727836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std) 14737836SJohn.Forte@Sun.COM { 14747836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14757836SJohn.Forte@Sun.COM std->state = stmf_get_service_state(); 14767836SJohn.Forte@Sun.COM std->config_state = stmf_state.stmf_config_state; 14777836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14787836SJohn.Forte@Sun.COM 14797836SJohn.Forte@Sun.COM return (0); 14807836SJohn.Forte@Sun.COM } 14817836SJohn.Forte@Sun.COM 148210725SJohn.Forte@Sun.COM /* 148310725SJohn.Forte@Sun.COM * handles registration message from pppt for a logical unit 148410725SJohn.Forte@Sun.COM */ 148510725SJohn.Forte@Sun.COM stmf_status_t 148610725SJohn.Forte@Sun.COM stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg, uint32_t type) 148710725SJohn.Forte@Sun.COM { 148810725SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 148910725SJohn.Forte@Sun.COM stmf_lu_provider_t *lp; 149010725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 149110725SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) { 149210725SJohn.Forte@Sun.COM if (strcmp(msg->icrl_lu_provider_name, 149310725SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 149410725SJohn.Forte@Sun.COM lp = ilp->ilp_lp; 149510725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 149610725SJohn.Forte@Sun.COM lp->lp_proxy_msg(msg->icrl_lun_id, msg->icrl_cb_arg, 149710725SJohn.Forte@Sun.COM msg->icrl_cb_arg_len, type); 149810725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 149910725SJohn.Forte@Sun.COM } 150010725SJohn.Forte@Sun.COM } 150110725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 150210725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 150310725SJohn.Forte@Sun.COM } 150410725SJohn.Forte@Sun.COM 150510725SJohn.Forte@Sun.COM /* 150610725SJohn.Forte@Sun.COM * handles de-registration message from pppt for a logical unit 150710725SJohn.Forte@Sun.COM */ 150810725SJohn.Forte@Sun.COM stmf_status_t 150910725SJohn.Forte@Sun.COM stmf_ic_lu_dereg(stmf_ic_reg_dereg_lun_msg_t *msg) 151010725SJohn.Forte@Sun.COM { 151110725SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 151210725SJohn.Forte@Sun.COM stmf_lu_provider_t *lp; 151310725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 151410725SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; ilp = ilp->ilp_next) { 151510725SJohn.Forte@Sun.COM if (strcmp(msg->icrl_lu_provider_name, 151610725SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 151710725SJohn.Forte@Sun.COM lp = ilp->ilp_lp; 151810725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 151910725SJohn.Forte@Sun.COM lp->lp_proxy_msg(msg->icrl_lun_id, NULL, 0, 152010725SJohn.Forte@Sun.COM STMF_MSG_LU_DEREGISTER); 152110725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 152210725SJohn.Forte@Sun.COM } 152310725SJohn.Forte@Sun.COM } 152410725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 152510725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 152610725SJohn.Forte@Sun.COM } 152710725SJohn.Forte@Sun.COM 152810725SJohn.Forte@Sun.COM /* 152910725SJohn.Forte@Sun.COM * helper function to find a task that matches a task_msgid 153010725SJohn.Forte@Sun.COM */ 153110725SJohn.Forte@Sun.COM scsi_task_t * 153210725SJohn.Forte@Sun.COM find_task_from_msgid(uint8_t *lu_id, stmf_ic_msgid_t task_msgid) 153310725SJohn.Forte@Sun.COM { 153410725SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 153510725SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 153610725SJohn.Forte@Sun.COM 153710725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 153810725SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 153910725SJohn.Forte@Sun.COM if (bcmp(lu_id, ilu->ilu_lu->lu_id->ident, 16) == 0) { 154010725SJohn.Forte@Sun.COM break; 154110725SJohn.Forte@Sun.COM } 154210725SJohn.Forte@Sun.COM } 154310725SJohn.Forte@Sun.COM 154410725SJohn.Forte@Sun.COM if (ilu == NULL) { 154510725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 154610725SJohn.Forte@Sun.COM return (NULL); 154710725SJohn.Forte@Sun.COM } 154810725SJohn.Forte@Sun.COM 154910725SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 155010725SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 155110725SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 155210725SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_IN_FREE_LIST | 155310725SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) { 155410725SJohn.Forte@Sun.COM continue; 155510725SJohn.Forte@Sun.COM } 155610725SJohn.Forte@Sun.COM if (itask->itask_proxy_msg_id == task_msgid) { 155710725SJohn.Forte@Sun.COM break; 155810725SJohn.Forte@Sun.COM } 155910725SJohn.Forte@Sun.COM } 156010725SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 156110725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 156210725SJohn.Forte@Sun.COM 156310725SJohn.Forte@Sun.COM if (itask != NULL) { 156410725SJohn.Forte@Sun.COM return (itask->itask_task); 156510725SJohn.Forte@Sun.COM } else { 156610725SJohn.Forte@Sun.COM /* task not found. Likely already aborted. */ 156710725SJohn.Forte@Sun.COM return (NULL); 156810725SJohn.Forte@Sun.COM } 156910725SJohn.Forte@Sun.COM } 157010725SJohn.Forte@Sun.COM 157110725SJohn.Forte@Sun.COM /* 157210725SJohn.Forte@Sun.COM * message received from pppt/ic 157310725SJohn.Forte@Sun.COM */ 157410725SJohn.Forte@Sun.COM stmf_status_t 157510725SJohn.Forte@Sun.COM stmf_msg_rx(stmf_ic_msg_t *msg) 157610725SJohn.Forte@Sun.COM { 157710725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 157810725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state != 1) { 157910725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 158010725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf alua state is disabled"); 158110725SJohn.Forte@Sun.COM ic_msg_free(msg); 158210725SJohn.Forte@Sun.COM return (STMF_FAILURE); 158310725SJohn.Forte@Sun.COM } 158410725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 158510725SJohn.Forte@Sun.COM 158610725SJohn.Forte@Sun.COM switch (msg->icm_msg_type) { 158710725SJohn.Forte@Sun.COM case STMF_ICM_REGISTER_LUN: 158810725SJohn.Forte@Sun.COM (void) stmf_ic_lu_reg( 158910725SJohn.Forte@Sun.COM (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg, 159010725SJohn.Forte@Sun.COM STMF_MSG_LU_REGISTER); 159110725SJohn.Forte@Sun.COM break; 159210725SJohn.Forte@Sun.COM case STMF_ICM_LUN_ACTIVE: 159310725SJohn.Forte@Sun.COM (void) stmf_ic_lu_reg( 159410725SJohn.Forte@Sun.COM (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg, 159510725SJohn.Forte@Sun.COM STMF_MSG_LU_ACTIVE); 159610725SJohn.Forte@Sun.COM break; 159710725SJohn.Forte@Sun.COM case STMF_ICM_DEREGISTER_LUN: 159810725SJohn.Forte@Sun.COM (void) stmf_ic_lu_dereg( 159910725SJohn.Forte@Sun.COM (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg); 160010725SJohn.Forte@Sun.COM break; 160110725SJohn.Forte@Sun.COM case STMF_ICM_SCSI_DATA: 160210725SJohn.Forte@Sun.COM (void) stmf_ic_rx_scsi_data( 160310725SJohn.Forte@Sun.COM (stmf_ic_scsi_data_msg_t *)msg->icm_msg); 160410725SJohn.Forte@Sun.COM break; 160510725SJohn.Forte@Sun.COM case STMF_ICM_SCSI_STATUS: 160610725SJohn.Forte@Sun.COM (void) stmf_ic_rx_scsi_status( 160710725SJohn.Forte@Sun.COM (stmf_ic_scsi_status_msg_t *)msg->icm_msg); 160810725SJohn.Forte@Sun.COM break; 160910725SJohn.Forte@Sun.COM case STMF_ICM_STATUS: 161010725SJohn.Forte@Sun.COM (void) stmf_ic_rx_status( 161110725SJohn.Forte@Sun.COM (stmf_ic_status_msg_t *)msg->icm_msg); 161210725SJohn.Forte@Sun.COM break; 161310725SJohn.Forte@Sun.COM default: 161410725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "unknown message received %d", 161510725SJohn.Forte@Sun.COM msg->icm_msg_type); 161610725SJohn.Forte@Sun.COM ic_msg_free(msg); 161710725SJohn.Forte@Sun.COM return (STMF_FAILURE); 161810725SJohn.Forte@Sun.COM } 161910725SJohn.Forte@Sun.COM ic_msg_free(msg); 162010725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 162110725SJohn.Forte@Sun.COM } 162210725SJohn.Forte@Sun.COM 162310725SJohn.Forte@Sun.COM stmf_status_t 162410725SJohn.Forte@Sun.COM stmf_ic_rx_status(stmf_ic_status_msg_t *msg) 162510725SJohn.Forte@Sun.COM { 162610725SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 162710725SJohn.Forte@Sun.COM 162810725SJohn.Forte@Sun.COM if (msg->ics_msg_type != STMF_ICM_REGISTER_PROXY_PORT) { 162910725SJohn.Forte@Sun.COM /* for now, ignore other message status */ 163010725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 163110725SJohn.Forte@Sun.COM } 163210725SJohn.Forte@Sun.COM 163310725SJohn.Forte@Sun.COM if (msg->ics_status != STMF_SUCCESS) { 163410725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 163510725SJohn.Forte@Sun.COM } 163610725SJohn.Forte@Sun.COM 163710725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 163810725SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 163910725SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 164010725SJohn.Forte@Sun.COM if (msg->ics_msgid == ilport->ilport_reg_msgid) { 164110725SJohn.Forte@Sun.COM ilport->ilport_proxy_registered = 1; 164210725SJohn.Forte@Sun.COM break; 164310725SJohn.Forte@Sun.COM } 164410725SJohn.Forte@Sun.COM } 164510725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 164610725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 164710725SJohn.Forte@Sun.COM } 164810725SJohn.Forte@Sun.COM 164910725SJohn.Forte@Sun.COM /* 165010725SJohn.Forte@Sun.COM * handles scsi status message from pppt 165110725SJohn.Forte@Sun.COM */ 165210725SJohn.Forte@Sun.COM stmf_status_t 165310725SJohn.Forte@Sun.COM stmf_ic_rx_scsi_status(stmf_ic_scsi_status_msg_t *msg) 165410725SJohn.Forte@Sun.COM { 165510725SJohn.Forte@Sun.COM scsi_task_t *task; 165610725SJohn.Forte@Sun.COM 165710725SJohn.Forte@Sun.COM task = find_task_from_msgid(msg->icss_lun_id, msg->icss_task_msgid); 165810725SJohn.Forte@Sun.COM 165910725SJohn.Forte@Sun.COM if (task == NULL) { 166010725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 166110725SJohn.Forte@Sun.COM } 166210725SJohn.Forte@Sun.COM 166310725SJohn.Forte@Sun.COM task->task_scsi_status = msg->icss_status; 166410725SJohn.Forte@Sun.COM task->task_sense_data = msg->icss_sense; 166510725SJohn.Forte@Sun.COM task->task_sense_length = msg->icss_sense_len; 166610725SJohn.Forte@Sun.COM (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE); 166710725SJohn.Forte@Sun.COM 166810725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 166910725SJohn.Forte@Sun.COM } 167010725SJohn.Forte@Sun.COM 167110725SJohn.Forte@Sun.COM /* 167210725SJohn.Forte@Sun.COM * handles scsi data message from pppt 167310725SJohn.Forte@Sun.COM */ 167410725SJohn.Forte@Sun.COM stmf_status_t 167510725SJohn.Forte@Sun.COM stmf_ic_rx_scsi_data(stmf_ic_scsi_data_msg_t *msg) 167610725SJohn.Forte@Sun.COM { 167710725SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 167810725SJohn.Forte@Sun.COM scsi_task_t *task; 167910725SJohn.Forte@Sun.COM stmf_xfer_data_t *xd = NULL; 168010725SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 168110725SJohn.Forte@Sun.COM uint32_t sz, minsz, xd_sz, asz; 168210725SJohn.Forte@Sun.COM 168310725SJohn.Forte@Sun.COM task = find_task_from_msgid(msg->icsd_lun_id, msg->icsd_task_msgid); 168410725SJohn.Forte@Sun.COM if (task == NULL) { 168510725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_xfer_done_msg = NULL; 168610725SJohn.Forte@Sun.COM static uint64_t data_msg_id; 168710725SJohn.Forte@Sun.COM stmf_status_t ic_ret = STMF_FAILURE; 168810725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 168910725SJohn.Forte@Sun.COM data_msg_id = stmf_proxy_msg_id++; 169010725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 169110725SJohn.Forte@Sun.COM /* 169210725SJohn.Forte@Sun.COM * send xfer done status to pppt 169310725SJohn.Forte@Sun.COM * for now, set the session id to 0 as we cannot 169410725SJohn.Forte@Sun.COM * ascertain it since we cannot find the task 169510725SJohn.Forte@Sun.COM */ 169610725SJohn.Forte@Sun.COM ic_xfer_done_msg = ic_scsi_data_xfer_done_msg_alloc( 169710725SJohn.Forte@Sun.COM msg->icsd_task_msgid, 0, STMF_FAILURE, data_msg_id); 169810725SJohn.Forte@Sun.COM if (ic_xfer_done_msg) { 169910725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_xfer_done_msg); 170010725SJohn.Forte@Sun.COM if (ic_ret != STMF_IC_MSG_SUCCESS) { 170110725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "unable to xmit proxy msg"); 170210725SJohn.Forte@Sun.COM } 170310725SJohn.Forte@Sun.COM } 170410725SJohn.Forte@Sun.COM return (STMF_FAILURE); 170510725SJohn.Forte@Sun.COM } 170610725SJohn.Forte@Sun.COM 170710725SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 170810725SJohn.Forte@Sun.COM dbuf = itask->itask_proxy_dbuf; 170910725SJohn.Forte@Sun.COM /* 171010725SJohn.Forte@Sun.COM * stmf will now take over the task handling for this task 171110725SJohn.Forte@Sun.COM * but it still needs to be treated differently from other 171210725SJohn.Forte@Sun.COM * default handled tasks, hence the ITASK_PROXY_TASK 171310725SJohn.Forte@Sun.COM */ 171410725SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_PROXY_TASK; 171510725SJohn.Forte@Sun.COM 171610725SJohn.Forte@Sun.COM task->task_cmd_xfer_length = msg->icsd_data_len; 171710725SJohn.Forte@Sun.COM 171810725SJohn.Forte@Sun.COM if (task->task_additional_flags & 171910725SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 172010725SJohn.Forte@Sun.COM task->task_expected_xfer_length = 172110725SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 172210725SJohn.Forte@Sun.COM } 172310725SJohn.Forte@Sun.COM 172410725SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 172510725SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 172610725SJohn.Forte@Sun.COM 172710725SJohn.Forte@Sun.COM xd_sz = msg->icsd_data_len; 172810725SJohn.Forte@Sun.COM asz = xd_sz + sizeof (*xd) - 4; 172910725SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP); 173010725SJohn.Forte@Sun.COM 173110725SJohn.Forte@Sun.COM if (xd == NULL) { 173210725SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 173310725SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 173410725SJohn.Forte@Sun.COM return (STMF_FAILURE); 173510725SJohn.Forte@Sun.COM } 173610725SJohn.Forte@Sun.COM 173710725SJohn.Forte@Sun.COM xd->alloc_size = asz; 173810725SJohn.Forte@Sun.COM xd->size_left = xd_sz; 173910725SJohn.Forte@Sun.COM bcopy(msg->icsd_data, xd->buf, xd_sz); 174010725SJohn.Forte@Sun.COM 174110725SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 174210725SJohn.Forte@Sun.COM xd->size_left = sz; 174310725SJohn.Forte@Sun.COM minsz = min(512, sz); 174410725SJohn.Forte@Sun.COM 174510725SJohn.Forte@Sun.COM if (dbuf == NULL) 174610725SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 174710725SJohn.Forte@Sun.COM if (dbuf == NULL) { 174810725SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 174910725SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 175010725SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 175110725SJohn.Forte@Sun.COM return (STMF_FAILURE); 175210725SJohn.Forte@Sun.COM } 175310725SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 175410725SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 175510725SJohn.Forte@Sun.COM 175610725SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 175710725SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 175810725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 175910725SJohn.Forte@Sun.COM } 176010725SJohn.Forte@Sun.COM 176110725SJohn.Forte@Sun.COM stmf_status_t 176210725SJohn.Forte@Sun.COM stmf_proxy_scsi_cmd(scsi_task_t *task, stmf_data_buf_t *dbuf) 176310725SJohn.Forte@Sun.COM { 176410725SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 176510725SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 176610725SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 176710725SJohn.Forte@Sun.COM (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 176810725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_cmd_msg; 176910725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret; 177010725SJohn.Forte@Sun.COM stmf_status_t ret = STMF_FAILURE; 177110725SJohn.Forte@Sun.COM 177210725SJohn.Forte@Sun.COM if (ilport->ilport_proxy_registered == 0) { 177310725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "proxy port not registered"); 177410725SJohn.Forte@Sun.COM return (STMF_FAILURE); 177510725SJohn.Forte@Sun.COM } 177610725SJohn.Forte@Sun.COM 177710725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state != 1) { 177810725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf alua state is disabled"); 177910725SJohn.Forte@Sun.COM return (STMF_FAILURE); 178010725SJohn.Forte@Sun.COM } 178110725SJohn.Forte@Sun.COM 178210725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 178310725SJohn.Forte@Sun.COM itask->itask_proxy_msg_id = stmf_proxy_msg_id++; 178410725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 178510725SJohn.Forte@Sun.COM itask->itask_proxy_dbuf = dbuf; 178610725SJohn.Forte@Sun.COM if (dbuf) { 178710725SJohn.Forte@Sun.COM ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id, 178810725SJohn.Forte@Sun.COM task, dbuf->db_data_size, dbuf->db_sglist[0].seg_addr, 178910725SJohn.Forte@Sun.COM itask->itask_proxy_msg_id); 179010725SJohn.Forte@Sun.COM } else { 179110725SJohn.Forte@Sun.COM ic_cmd_msg = ic_scsi_cmd_msg_alloc(itask->itask_proxy_msg_id, 179210725SJohn.Forte@Sun.COM task, 0, NULL, itask->itask_proxy_msg_id); 179310725SJohn.Forte@Sun.COM } 179410725SJohn.Forte@Sun.COM if (ic_cmd_msg) { 179510725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_cmd_msg); 179610725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 179710725SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 179810725SJohn.Forte@Sun.COM } 179910725SJohn.Forte@Sun.COM } 180010725SJohn.Forte@Sun.COM return (ret); 180110725SJohn.Forte@Sun.COM } 180210725SJohn.Forte@Sun.COM 180310725SJohn.Forte@Sun.COM 180410725SJohn.Forte@Sun.COM stmf_status_t 180510725SJohn.Forte@Sun.COM pppt_modload() 180610725SJohn.Forte@Sun.COM { 180710725SJohn.Forte@Sun.COM int error; 180810725SJohn.Forte@Sun.COM 180910725SJohn.Forte@Sun.COM if (pppt_mod == NULL && ((pppt_mod = 181010725SJohn.Forte@Sun.COM ddi_modopen("drv/pppt", KRTLD_MODE_FIRST, &error)) == NULL)) { 181110725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Unable to load pppt"); 181210725SJohn.Forte@Sun.COM return (STMF_FAILURE); 181310725SJohn.Forte@Sun.COM } 181410725SJohn.Forte@Sun.COM 181510725SJohn.Forte@Sun.COM if (ic_reg_port_msg_alloc == NULL && ((ic_reg_port_msg_alloc = 181610725SJohn.Forte@Sun.COM (stmf_ic_reg_port_msg_alloc_func_t) 181710725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_reg_port_msg_alloc", 181810725SJohn.Forte@Sun.COM &error)) == NULL)) { 181910725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 182010725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_reg_port_msg_alloc"); 182110725SJohn.Forte@Sun.COM return (STMF_FAILURE); 182210725SJohn.Forte@Sun.COM } 182310725SJohn.Forte@Sun.COM 182410725SJohn.Forte@Sun.COM 182510725SJohn.Forte@Sun.COM if (ic_dereg_port_msg_alloc == NULL && ((ic_dereg_port_msg_alloc = 182610725SJohn.Forte@Sun.COM (stmf_ic_dereg_port_msg_alloc_func_t) 182710725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_dereg_port_msg_alloc", 182810725SJohn.Forte@Sun.COM &error)) == NULL)) { 182910725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 183010725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_dereg_port_msg_alloc"); 183110725SJohn.Forte@Sun.COM return (STMF_FAILURE); 183210725SJohn.Forte@Sun.COM } 183310725SJohn.Forte@Sun.COM 183410725SJohn.Forte@Sun.COM if (ic_reg_lun_msg_alloc == NULL && ((ic_reg_lun_msg_alloc = 183510725SJohn.Forte@Sun.COM (stmf_ic_reg_lun_msg_alloc_func_t) 183610725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_reg_lun_msg_alloc", 183710725SJohn.Forte@Sun.COM &error)) == NULL)) { 183810725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 183910725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_reg_lun_msg_alloc"); 184010725SJohn.Forte@Sun.COM return (STMF_FAILURE); 184110725SJohn.Forte@Sun.COM } 184210725SJohn.Forte@Sun.COM 184310725SJohn.Forte@Sun.COM if (ic_lun_active_msg_alloc == NULL && ((ic_lun_active_msg_alloc = 184410725SJohn.Forte@Sun.COM (stmf_ic_lun_active_msg_alloc_func_t) 184510725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_lun_active_msg_alloc", 184610725SJohn.Forte@Sun.COM &error)) == NULL)) { 184710725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 184810725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_lun_active_msg_alloc"); 184910725SJohn.Forte@Sun.COM return (STMF_FAILURE); 185010725SJohn.Forte@Sun.COM } 185110725SJohn.Forte@Sun.COM 185210725SJohn.Forte@Sun.COM if (ic_dereg_lun_msg_alloc == NULL && ((ic_dereg_lun_msg_alloc = 185310725SJohn.Forte@Sun.COM (stmf_ic_dereg_lun_msg_alloc_func_t) 185410725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_dereg_lun_msg_alloc", 185510725SJohn.Forte@Sun.COM &error)) == NULL)) { 185610725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 185710725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_dereg_lun_msg_alloc"); 185810725SJohn.Forte@Sun.COM return (STMF_FAILURE); 185910725SJohn.Forte@Sun.COM } 186010725SJohn.Forte@Sun.COM 186110725SJohn.Forte@Sun.COM if (ic_scsi_cmd_msg_alloc == NULL && ((ic_scsi_cmd_msg_alloc = 186210725SJohn.Forte@Sun.COM (stmf_ic_scsi_cmd_msg_alloc_func_t) 186310725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_scsi_cmd_msg_alloc", 186410725SJohn.Forte@Sun.COM &error)) == NULL)) { 186510725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 186610725SJohn.Forte@Sun.COM "Unable to find symbol - stmf_ic_scsi_cmd_msg_alloc"); 186710725SJohn.Forte@Sun.COM return (STMF_FAILURE); 186810725SJohn.Forte@Sun.COM } 186910725SJohn.Forte@Sun.COM 187010725SJohn.Forte@Sun.COM if (ic_scsi_data_xfer_done_msg_alloc == NULL && 187110725SJohn.Forte@Sun.COM ((ic_scsi_data_xfer_done_msg_alloc = 187210725SJohn.Forte@Sun.COM (stmf_ic_scsi_data_xfer_done_msg_alloc_func_t) 187310725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_scsi_data_xfer_done_msg_alloc", 187410725SJohn.Forte@Sun.COM &error)) == NULL)) { 187510725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 187610725SJohn.Forte@Sun.COM "Unable to find symbol -" 187710725SJohn.Forte@Sun.COM "stmf_ic_scsi_data_xfer_done_msg_alloc"); 187810725SJohn.Forte@Sun.COM return (STMF_FAILURE); 187910725SJohn.Forte@Sun.COM } 188010725SJohn.Forte@Sun.COM 188110725SJohn.Forte@Sun.COM if (ic_session_reg_msg_alloc == NULL && 188210725SJohn.Forte@Sun.COM ((ic_session_reg_msg_alloc = 188310725SJohn.Forte@Sun.COM (stmf_ic_session_create_msg_alloc_func_t) 188410725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_session_create_msg_alloc", 188510725SJohn.Forte@Sun.COM &error)) == NULL)) { 188610725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 188710725SJohn.Forte@Sun.COM "Unable to find symbol -" 188810725SJohn.Forte@Sun.COM "stmf_ic_session_create_msg_alloc"); 188910725SJohn.Forte@Sun.COM return (STMF_FAILURE); 189010725SJohn.Forte@Sun.COM } 189110725SJohn.Forte@Sun.COM 189210725SJohn.Forte@Sun.COM if (ic_session_dereg_msg_alloc == NULL && 189310725SJohn.Forte@Sun.COM ((ic_session_dereg_msg_alloc = 189410725SJohn.Forte@Sun.COM (stmf_ic_session_destroy_msg_alloc_func_t) 189510725SJohn.Forte@Sun.COM ddi_modsym(pppt_mod, "stmf_ic_session_destroy_msg_alloc", 189610725SJohn.Forte@Sun.COM &error)) == NULL)) { 189710725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 189810725SJohn.Forte@Sun.COM "Unable to find symbol -" 189910725SJohn.Forte@Sun.COM "stmf_ic_session_destroy_msg_alloc"); 190010725SJohn.Forte@Sun.COM return (STMF_FAILURE); 190110725SJohn.Forte@Sun.COM } 190210725SJohn.Forte@Sun.COM 190310725SJohn.Forte@Sun.COM if (ic_tx_msg == NULL && ((ic_tx_msg = 190410725SJohn.Forte@Sun.COM (stmf_ic_tx_msg_func_t)ddi_modsym(pppt_mod, "stmf_ic_tx_msg", 190510725SJohn.Forte@Sun.COM &error)) == NULL)) { 190610725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_tx_msg"); 190710725SJohn.Forte@Sun.COM return (STMF_FAILURE); 190810725SJohn.Forte@Sun.COM } 190910725SJohn.Forte@Sun.COM 191010725SJohn.Forte@Sun.COM if (ic_msg_free == NULL && ((ic_msg_free = 191110725SJohn.Forte@Sun.COM (stmf_ic_msg_free_func_t)ddi_modsym(pppt_mod, "stmf_ic_msg_free", 191210725SJohn.Forte@Sun.COM &error)) == NULL)) { 191310725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Unable to find symbol - stmf_ic_msg_free"); 191410725SJohn.Forte@Sun.COM return (STMF_FAILURE); 191510725SJohn.Forte@Sun.COM } 191610725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 191710725SJohn.Forte@Sun.COM } 191810725SJohn.Forte@Sun.COM 191910725SJohn.Forte@Sun.COM static void 192010725SJohn.Forte@Sun.COM stmf_get_alua_state(stmf_alua_state_desc_t *alua_state) 192110725SJohn.Forte@Sun.COM { 192210725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 192310725SJohn.Forte@Sun.COM alua_state->alua_node = stmf_state.stmf_alua_node; 192410725SJohn.Forte@Sun.COM alua_state->alua_state = stmf_state.stmf_alua_state; 192510725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 192610725SJohn.Forte@Sun.COM } 192710725SJohn.Forte@Sun.COM 192810725SJohn.Forte@Sun.COM 192910725SJohn.Forte@Sun.COM static int 193010725SJohn.Forte@Sun.COM stmf_set_alua_state(stmf_alua_state_desc_t *alua_state) 193110725SJohn.Forte@Sun.COM { 193210725SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 193310725SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 193410725SJohn.Forte@Sun.COM stmf_lu_t *lu; 193510725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret; 193610725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_reg_lun, *ic_reg_port; 193710725SJohn.Forte@Sun.COM stmf_local_port_t *lport; 193810725SJohn.Forte@Sun.COM int ret = 0; 193910725SJohn.Forte@Sun.COM 194010725SJohn.Forte@Sun.COM if (alua_state->alua_state > 1 || alua_state->alua_node > 1) { 194110725SJohn.Forte@Sun.COM return (EINVAL); 194210725SJohn.Forte@Sun.COM } 194310725SJohn.Forte@Sun.COM 194410725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 194510725SJohn.Forte@Sun.COM if (alua_state->alua_state == 1) { 194610725SJohn.Forte@Sun.COM if (pppt_modload() == STMF_FAILURE) { 194710725SJohn.Forte@Sun.COM ret = EIO; 194810725SJohn.Forte@Sun.COM goto err; 194910725SJohn.Forte@Sun.COM } 195010725SJohn.Forte@Sun.COM if (alua_state->alua_node != 0) { 195110725SJohn.Forte@Sun.COM /* reset existing rtpids to new base */ 195210725SJohn.Forte@Sun.COM cmn_err(CE_NOTE, "non-zero alua node set"); 195310725SJohn.Forte@Sun.COM stmf_rtpid_counter = 255; 195410725SJohn.Forte@Sun.COM } 195510725SJohn.Forte@Sun.COM stmf_state.stmf_alua_node = alua_state->alua_node; 195610725SJohn.Forte@Sun.COM stmf_state.stmf_alua_state = 1; 195710725SJohn.Forte@Sun.COM /* register existing local ports with ppp */ 195810725SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 195910725SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 196010725SJohn.Forte@Sun.COM /* skip standby ports */ 196110725SJohn.Forte@Sun.COM if (ilport->ilport_standby == 1) { 196210725SJohn.Forte@Sun.COM continue; 196310725SJohn.Forte@Sun.COM } 196410725SJohn.Forte@Sun.COM if (alua_state->alua_node != 0) { 196510725SJohn.Forte@Sun.COM ilport->ilport_rtpid = 196610725SJohn.Forte@Sun.COM atomic_add_16_nv(&stmf_rtpid_counter, 1); 196710725SJohn.Forte@Sun.COM } 196810725SJohn.Forte@Sun.COM lport = ilport->ilport_lport; 196910725SJohn.Forte@Sun.COM ic_reg_port = ic_reg_port_msg_alloc( 197010725SJohn.Forte@Sun.COM lport->lport_id, ilport->ilport_rtpid, 197110725SJohn.Forte@Sun.COM 0, NULL, stmf_proxy_msg_id); 197210725SJohn.Forte@Sun.COM if (ic_reg_port) { 197310725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_reg_port); 197410725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 197510725SJohn.Forte@Sun.COM ilport->ilport_reg_msgid = 197610725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 197710725SJohn.Forte@Sun.COM } else { 197810725SJohn.Forte@Sun.COM cmn_err(CE_WARN, 197910725SJohn.Forte@Sun.COM "error on port registration " 198010725SJohn.Forte@Sun.COM "port - %s", 198110725SJohn.Forte@Sun.COM ilport->ilport_kstat_tgt_name); 198210725SJohn.Forte@Sun.COM } 198310725SJohn.Forte@Sun.COM } 198410725SJohn.Forte@Sun.COM } 198510725SJohn.Forte@Sun.COM /* register existing logical units */ 198610725SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 198710725SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 198810725SJohn.Forte@Sun.COM if (ilu->ilu_access != STMF_LU_ACTIVE) { 198910725SJohn.Forte@Sun.COM continue; 199010725SJohn.Forte@Sun.COM } 199110725SJohn.Forte@Sun.COM /* register with proxy module */ 199210725SJohn.Forte@Sun.COM lu = ilu->ilu_lu; 199310725SJohn.Forte@Sun.COM if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 && 199410725SJohn.Forte@Sun.COM lu->lu_lp->lp_alua_support) { 199510725SJohn.Forte@Sun.COM ilu->ilu_alua = 1; 199610725SJohn.Forte@Sun.COM /* allocate the register message */ 199710725SJohn.Forte@Sun.COM ic_reg_lun = ic_reg_lun_msg_alloc( 199810725SJohn.Forte@Sun.COM lu->lu_id->ident, lu->lu_lp->lp_name, 199910725SJohn.Forte@Sun.COM lu->lu_proxy_reg_arg_len, 200010725SJohn.Forte@Sun.COM (uint8_t *)lu->lu_proxy_reg_arg, 200110725SJohn.Forte@Sun.COM stmf_proxy_msg_id); 200210725SJohn.Forte@Sun.COM /* send the message */ 200310725SJohn.Forte@Sun.COM if (ic_reg_lun) { 200410725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_reg_lun); 200510725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 200610725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 200710725SJohn.Forte@Sun.COM } 200810725SJohn.Forte@Sun.COM } 200910725SJohn.Forte@Sun.COM } 201010725SJohn.Forte@Sun.COM } 201110725SJohn.Forte@Sun.COM } else { 201210725SJohn.Forte@Sun.COM stmf_state.stmf_alua_state = 0; 201310725SJohn.Forte@Sun.COM } 201410725SJohn.Forte@Sun.COM 201510725SJohn.Forte@Sun.COM err: 201610725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 201710725SJohn.Forte@Sun.COM return (ret); 201810725SJohn.Forte@Sun.COM } 201910725SJohn.Forte@Sun.COM 202010725SJohn.Forte@Sun.COM 20217836SJohn.Forte@Sun.COM typedef struct { 20227836SJohn.Forte@Sun.COM void *bp; /* back pointer from internal struct to main struct */ 20237836SJohn.Forte@Sun.COM int alloc_size; 20247836SJohn.Forte@Sun.COM } __istmf_t; 20257836SJohn.Forte@Sun.COM 20267836SJohn.Forte@Sun.COM typedef struct { 20277836SJohn.Forte@Sun.COM __istmf_t *fp; /* Framework private */ 20287836SJohn.Forte@Sun.COM void *cp; /* Caller private */ 20297836SJohn.Forte@Sun.COM void *ss; /* struct specific */ 20307836SJohn.Forte@Sun.COM } __stmf_t; 20317836SJohn.Forte@Sun.COM 20327836SJohn.Forte@Sun.COM static struct { 20337836SJohn.Forte@Sun.COM int shared; 20347836SJohn.Forte@Sun.COM int fw_private; 20357836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 }, 20367836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_provider_t), 20377836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_provider_t) }, 20387836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_port_provider_t), 20397836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_port_provider_t) }, 20407836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_local_port_t), 20417836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_local_port_t) }, 20427836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_t), 20437836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_t) }, 20447836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_scsi_session_t), 20457836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_session_t) }, 20467836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(scsi_task_t), 20477836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_task_t) }, 20487836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_data_buf_t), 20497836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) }, 20507836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_dbuf_store_t), 20517836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) } 20527836SJohn.Forte@Sun.COM 20537836SJohn.Forte@Sun.COM }; 20547836SJohn.Forte@Sun.COM 20557836SJohn.Forte@Sun.COM void * 20567836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags) 20577836SJohn.Forte@Sun.COM { 20587836SJohn.Forte@Sun.COM int stmf_size; 20597836SJohn.Forte@Sun.COM int kmem_flag; 20607836SJohn.Forte@Sun.COM __stmf_t *sh; 20617836SJohn.Forte@Sun.COM 20627836SJohn.Forte@Sun.COM if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS)) 20637836SJohn.Forte@Sun.COM return (NULL); 20647836SJohn.Forte@Sun.COM 20657836SJohn.Forte@Sun.COM if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) { 20667836SJohn.Forte@Sun.COM kmem_flag = KM_NOSLEEP; 20677836SJohn.Forte@Sun.COM } else { 20687836SJohn.Forte@Sun.COM kmem_flag = KM_SLEEP; 20697836SJohn.Forte@Sun.COM } 20707836SJohn.Forte@Sun.COM 20717836SJohn.Forte@Sun.COM additional_size = (additional_size + 7) & (~7); 20727836SJohn.Forte@Sun.COM stmf_size = stmf_sizes[struct_id].shared + 20738662SJordan.Vaughan@Sun.com stmf_sizes[struct_id].fw_private + additional_size; 20747836SJohn.Forte@Sun.COM 20757836SJohn.Forte@Sun.COM sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag); 20767836SJohn.Forte@Sun.COM 20777836SJohn.Forte@Sun.COM if (sh == NULL) 20787836SJohn.Forte@Sun.COM return (NULL); 20797836SJohn.Forte@Sun.COM 20809087SZhong.Wang@Sun.COM /* 20819087SZhong.Wang@Sun.COM * In principle, the implementation inside stmf_alloc should not 20829087SZhong.Wang@Sun.COM * be changed anyway. But the original order of framework private 20839087SZhong.Wang@Sun.COM * data and caller private data does not support sglist in the caller 20849087SZhong.Wang@Sun.COM * private data. 20859087SZhong.Wang@Sun.COM * To work around this, the memory segments of framework private 20869087SZhong.Wang@Sun.COM * data and caller private data are re-ordered here. 20879087SZhong.Wang@Sun.COM * A better solution is to provide a specific interface to allocate 20889087SZhong.Wang@Sun.COM * the sglist, then we will not need this workaround any more. 20899087SZhong.Wang@Sun.COM * But before the new interface is available, the memory segment 20909087SZhong.Wang@Sun.COM * ordering should be kept as is. 20919087SZhong.Wang@Sun.COM */ 20929087SZhong.Wang@Sun.COM sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); 20939087SZhong.Wang@Sun.COM sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, 20949087SZhong.Wang@Sun.COM stmf_sizes[struct_id].shared + additional_size); 20957836SJohn.Forte@Sun.COM 20967836SJohn.Forte@Sun.COM sh->fp->bp = sh; 20977836SJohn.Forte@Sun.COM /* Just store the total size instead of storing additional size */ 20987836SJohn.Forte@Sun.COM sh->fp->alloc_size = stmf_size; 20997836SJohn.Forte@Sun.COM 21007836SJohn.Forte@Sun.COM return (sh); 21017836SJohn.Forte@Sun.COM } 21027836SJohn.Forte@Sun.COM 21037836SJohn.Forte@Sun.COM void 21047836SJohn.Forte@Sun.COM stmf_free(void *ptr) 21057836SJohn.Forte@Sun.COM { 21067836SJohn.Forte@Sun.COM __stmf_t *sh = (__stmf_t *)ptr; 21077836SJohn.Forte@Sun.COM 21087836SJohn.Forte@Sun.COM /* 21097836SJohn.Forte@Sun.COM * So far we dont need any struct specific processing. If such 21107836SJohn.Forte@Sun.COM * a need ever arises, then store the struct id in the framework 21117836SJohn.Forte@Sun.COM * private section and get it here as sh->fp->struct_id. 21127836SJohn.Forte@Sun.COM */ 21137836SJohn.Forte@Sun.COM kmem_free(ptr, sh->fp->alloc_size); 21147836SJohn.Forte@Sun.COM } 21157836SJohn.Forte@Sun.COM 21167836SJohn.Forte@Sun.COM /* 21177836SJohn.Forte@Sun.COM * Given a pointer to stmf_lu_t, verifies if this lu is registered with the 21187836SJohn.Forte@Sun.COM * framework and returns a pointer to framework private data for the lu. 21197836SJohn.Forte@Sun.COM * Returns NULL if the lu was not found. 21207836SJohn.Forte@Sun.COM */ 21217836SJohn.Forte@Sun.COM stmf_i_lu_t * 21227836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu) 21237836SJohn.Forte@Sun.COM { 21247836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 21257836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 21267836SJohn.Forte@Sun.COM 21277836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 21287836SJohn.Forte@Sun.COM if (ilu->ilu_lu == lu) 21297836SJohn.Forte@Sun.COM return (ilu); 21307836SJohn.Forte@Sun.COM } 21317836SJohn.Forte@Sun.COM return (NULL); 21327836SJohn.Forte@Sun.COM } 21337836SJohn.Forte@Sun.COM 21347836SJohn.Forte@Sun.COM /* 21358818STim.Szeto@Sun.COM * Given a pointer to stmf_local_port_t, verifies if this lport is registered 21368818STim.Szeto@Sun.COM * with the framework and returns a pointer to framework private data for 21378818STim.Szeto@Sun.COM * the lport. 21388818STim.Szeto@Sun.COM * Returns NULL if the lport was not found. 21397836SJohn.Forte@Sun.COM */ 21407836SJohn.Forte@Sun.COM stmf_i_local_port_t * 21417836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport) 21427836SJohn.Forte@Sun.COM { 21437836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 21447836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 21457836SJohn.Forte@Sun.COM 21467836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 21477836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 21487836SJohn.Forte@Sun.COM if (ilport->ilport_lport == lport) 21497836SJohn.Forte@Sun.COM return (ilport); 21507836SJohn.Forte@Sun.COM } 21517836SJohn.Forte@Sun.COM return (NULL); 21527836SJohn.Forte@Sun.COM } 21537836SJohn.Forte@Sun.COM 21547836SJohn.Forte@Sun.COM stmf_status_t 21557836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp) 21567836SJohn.Forte@Sun.COM { 21577836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 21587836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 21597836SJohn.Forte@Sun.COM uint32_t cb_flags; 21607836SJohn.Forte@Sun.COM 216110725SJohn.Forte@Sun.COM if (lp->lp_lpif_rev != LPIF_REV_1 && lp->lp_lpif_rev != LPIF_REV_2) 21627836SJohn.Forte@Sun.COM return (STMF_FAILURE); 21637836SJohn.Forte@Sun.COM 21647836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 21657836SJohn.Forte@Sun.COM ilp->ilp_next = stmf_state.stmf_ilplist; 21667836SJohn.Forte@Sun.COM stmf_state.stmf_ilplist = ilp; 21677836SJohn.Forte@Sun.COM stmf_state.stmf_nlps++; 21687836SJohn.Forte@Sun.COM 21697836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 21707836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 21717836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, lp->lp_name) == 0) { 21727836SJohn.Forte@Sun.COM break; 21737836SJohn.Forte@Sun.COM } 21747836SJohn.Forte@Sun.COM } 21757836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 21767836SJohn.Forte@Sun.COM goto rlp_bail_out; 21777836SJohn.Forte@Sun.COM } 21787836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 21797836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 21807836SJohn.Forte@Sun.COM if (lp->lp_cb == NULL) 21817836SJohn.Forte@Sun.COM goto rlp_bail_out; 21827836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 21837836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 21847836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 21857836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 21867836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 21877836SJohn.Forte@Sun.COM lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 21887836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 21897836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 21907836SJohn.Forte@Sun.COM 21917836SJohn.Forte@Sun.COM rlp_bail_out: 21927836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 21937836SJohn.Forte@Sun.COM 21947836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 21957836SJohn.Forte@Sun.COM } 21967836SJohn.Forte@Sun.COM 21977836SJohn.Forte@Sun.COM stmf_status_t 21987836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp) 21997836SJohn.Forte@Sun.COM { 22007836SJohn.Forte@Sun.COM stmf_i_lu_provider_t **ppilp; 22017836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 22027836SJohn.Forte@Sun.COM 22037836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22047836SJohn.Forte@Sun.COM if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) { 22057836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22067836SJohn.Forte@Sun.COM return (STMF_BUSY); 22077836SJohn.Forte@Sun.COM } 22087836SJohn.Forte@Sun.COM for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL; 22097836SJohn.Forte@Sun.COM ppilp = &((*ppilp)->ilp_next)) { 22107836SJohn.Forte@Sun.COM if (*ppilp == ilp) { 22117836SJohn.Forte@Sun.COM *ppilp = ilp->ilp_next; 22127836SJohn.Forte@Sun.COM stmf_state.stmf_nlps--; 22137836SJohn.Forte@Sun.COM if (ilp->ilp_ppd) { 22147836SJohn.Forte@Sun.COM ilp->ilp_ppd->ppd_provider = NULL; 22157836SJohn.Forte@Sun.COM ilp->ilp_ppd = NULL; 22167836SJohn.Forte@Sun.COM } 22177836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22187836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22197836SJohn.Forte@Sun.COM } 22207836SJohn.Forte@Sun.COM } 22217836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22227836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 22237836SJohn.Forte@Sun.COM } 22247836SJohn.Forte@Sun.COM 22257836SJohn.Forte@Sun.COM stmf_status_t 22267836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp) 22277836SJohn.Forte@Sun.COM { 22287836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 22297836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 22307836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 22317836SJohn.Forte@Sun.COM uint32_t cb_flags; 22327836SJohn.Forte@Sun.COM 22337836SJohn.Forte@Sun.COM if (pp->pp_portif_rev != PORTIF_REV_1) 22347836SJohn.Forte@Sun.COM return (STMF_FAILURE); 22357836SJohn.Forte@Sun.COM 22367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22377836SJohn.Forte@Sun.COM ipp->ipp_next = stmf_state.stmf_ipplist; 22387836SJohn.Forte@Sun.COM stmf_state.stmf_ipplist = ipp; 22397836SJohn.Forte@Sun.COM stmf_state.stmf_npps++; 22407836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 22417836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 22427836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, pp->pp_name) == 0) { 22437836SJohn.Forte@Sun.COM break; 22447836SJohn.Forte@Sun.COM } 22457836SJohn.Forte@Sun.COM } 22467836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 22477836SJohn.Forte@Sun.COM goto rpp_bail_out; 22487836SJohn.Forte@Sun.COM } 22497836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 22507836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 22517836SJohn.Forte@Sun.COM if (pp->pp_cb == NULL) 22527836SJohn.Forte@Sun.COM goto rpp_bail_out; 22537836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 22547836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 22557836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 22567836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 22577836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22587836SJohn.Forte@Sun.COM pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 22597836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22607836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 22617836SJohn.Forte@Sun.COM 22627836SJohn.Forte@Sun.COM rpp_bail_out: 22637836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22647836SJohn.Forte@Sun.COM 22657836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22667836SJohn.Forte@Sun.COM } 22677836SJohn.Forte@Sun.COM 22687836SJohn.Forte@Sun.COM stmf_status_t 22697836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp) 22707836SJohn.Forte@Sun.COM { 22717836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 22727836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 22737836SJohn.Forte@Sun.COM stmf_i_port_provider_t **ppipp; 22747836SJohn.Forte@Sun.COM 22757836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22767836SJohn.Forte@Sun.COM if (ipp->ipp_npps || ipp->ipp_cb_in_progress) { 22777836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22787836SJohn.Forte@Sun.COM return (STMF_BUSY); 22797836SJohn.Forte@Sun.COM } 22807836SJohn.Forte@Sun.COM for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL; 22817836SJohn.Forte@Sun.COM ppipp = &((*ppipp)->ipp_next)) { 22827836SJohn.Forte@Sun.COM if (*ppipp == ipp) { 22837836SJohn.Forte@Sun.COM *ppipp = ipp->ipp_next; 22847836SJohn.Forte@Sun.COM stmf_state.stmf_npps--; 22857836SJohn.Forte@Sun.COM if (ipp->ipp_ppd) { 22867836SJohn.Forte@Sun.COM ipp->ipp_ppd->ppd_provider = NULL; 22877836SJohn.Forte@Sun.COM ipp->ipp_ppd = NULL; 22887836SJohn.Forte@Sun.COM } 22897836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22907836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22917836SJohn.Forte@Sun.COM } 22927836SJohn.Forte@Sun.COM } 22937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22947836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 22957836SJohn.Forte@Sun.COM } 22967836SJohn.Forte@Sun.COM 22977836SJohn.Forte@Sun.COM int 22989585STim.Szeto@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 22999585STim.Szeto@Sun.COM uint32_t *err_ret) 23007836SJohn.Forte@Sun.COM { 23017836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp; 23027836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 23037836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 23047836SJohn.Forte@Sun.COM nvlist_t *nv; 23057836SJohn.Forte@Sun.COM int s; 23067836SJohn.Forte@Sun.COM int ret; 23077836SJohn.Forte@Sun.COM 23089585STim.Szeto@Sun.COM *err_ret = 0; 23099585STim.Szeto@Sun.COM 23107836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 23117836SJohn.Forte@Sun.COM return (EINVAL); 23127836SJohn.Forte@Sun.COM } 23137836SJohn.Forte@Sun.COM 23147836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 23157836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 23167836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 23177836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 23187836SJohn.Forte@Sun.COM continue; 23197836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 23207836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 23217836SJohn.Forte@Sun.COM continue; 23227836SJohn.Forte@Sun.COM } 23237836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 23247836SJohn.Forte@Sun.COM break; 23257836SJohn.Forte@Sun.COM } 23267836SJohn.Forte@Sun.COM 23277836SJohn.Forte@Sun.COM if (ppd == NULL) { 23287836SJohn.Forte@Sun.COM /* New provider */ 23297836SJohn.Forte@Sun.COM s = strlen(ppi->ppi_name); 23307836SJohn.Forte@Sun.COM if (s > 254) { 23317836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23327836SJohn.Forte@Sun.COM return (EINVAL); 23337836SJohn.Forte@Sun.COM } 23347836SJohn.Forte@Sun.COM s += sizeof (stmf_pp_data_t) - 7; 23357836SJohn.Forte@Sun.COM 23367836SJohn.Forte@Sun.COM ppd = kmem_zalloc(s, KM_NOSLEEP); 23377836SJohn.Forte@Sun.COM if (ppd == NULL) { 23387836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23397836SJohn.Forte@Sun.COM return (ENOMEM); 23407836SJohn.Forte@Sun.COM } 23417836SJohn.Forte@Sun.COM ppd->ppd_alloc_size = s; 23427836SJohn.Forte@Sun.COM (void) strcpy(ppd->ppd_name, ppi->ppi_name); 23437836SJohn.Forte@Sun.COM 23447836SJohn.Forte@Sun.COM /* See if this provider already exists */ 23457836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 23467836SJohn.Forte@Sun.COM ppd->ppd_lu_provider = 1; 23477836SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; 23487836SJohn.Forte@Sun.COM ilp = ilp->ilp_next) { 23497836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 23507836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 23517836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 23527836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 23537836SJohn.Forte@Sun.COM break; 23547836SJohn.Forte@Sun.COM } 23557836SJohn.Forte@Sun.COM } 23567836SJohn.Forte@Sun.COM } else { 23577836SJohn.Forte@Sun.COM ppd->ppd_port_provider = 1; 23587836SJohn.Forte@Sun.COM for (ipp = stmf_state.stmf_ipplist; ipp != NULL; 23597836SJohn.Forte@Sun.COM ipp = ipp->ipp_next) { 23607836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 23617836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_name) == 0) { 23627836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 23637836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 23647836SJohn.Forte@Sun.COM break; 23657836SJohn.Forte@Sun.COM } 23667836SJohn.Forte@Sun.COM } 23677836SJohn.Forte@Sun.COM } 23687836SJohn.Forte@Sun.COM 23697836SJohn.Forte@Sun.COM /* Link this ppd in */ 23707836SJohn.Forte@Sun.COM ppd->ppd_next = stmf_state.stmf_ppdlist; 23717836SJohn.Forte@Sun.COM stmf_state.stmf_ppdlist = ppd; 23727836SJohn.Forte@Sun.COM } 23737836SJohn.Forte@Sun.COM 23749585STim.Szeto@Sun.COM /* 23759585STim.Szeto@Sun.COM * User is requesting that the token be checked. 23769585STim.Szeto@Sun.COM * If there was another set after the user's get 23779585STim.Szeto@Sun.COM * it's an error 23789585STim.Szeto@Sun.COM */ 23799585STim.Szeto@Sun.COM if (ppi->ppi_token_valid) { 23809585STim.Szeto@Sun.COM if (ppi->ppi_token != ppd->ppd_token) { 23819585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_PPD_UPDATED; 23829585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23839585STim.Szeto@Sun.COM return (EINVAL); 23849585STim.Szeto@Sun.COM } 23859585STim.Szeto@Sun.COM } 23869585STim.Szeto@Sun.COM 23877836SJohn.Forte@Sun.COM if ((ret = nvlist_unpack((char *)ppi->ppi_data, 23887836SJohn.Forte@Sun.COM (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) { 23897836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23907836SJohn.Forte@Sun.COM return (ret); 23917836SJohn.Forte@Sun.COM } 23927836SJohn.Forte@Sun.COM 23937836SJohn.Forte@Sun.COM /* Free any existing lists and add this one to the ppd */ 23947836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 23957836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 23967836SJohn.Forte@Sun.COM ppd->ppd_nv = nv; 23977836SJohn.Forte@Sun.COM 23989585STim.Szeto@Sun.COM /* set the token for writes */ 23999585STim.Szeto@Sun.COM ppd->ppd_token++; 24009585STim.Szeto@Sun.COM /* return token to caller */ 24019585STim.Szeto@Sun.COM if (ppi_token) { 24029585STim.Szeto@Sun.COM *ppi_token = ppd->ppd_token; 24039585STim.Szeto@Sun.COM } 24049585STim.Szeto@Sun.COM 24057836SJohn.Forte@Sun.COM /* If there is a provider registered, do the notifications */ 24067836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 24077836SJohn.Forte@Sun.COM uint32_t cb_flags = 0; 24087836SJohn.Forte@Sun.COM 24097836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 24107836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 24117836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 24127836SJohn.Forte@Sun.COM ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider; 24137836SJohn.Forte@Sun.COM if (ilp->ilp_lp->lp_cb == NULL) 24147836SJohn.Forte@Sun.COM goto bail_out; 24157836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 24167836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24177836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_cb(ilp->ilp_lp, 24187836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 24197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 24207836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 24217836SJohn.Forte@Sun.COM } else { 24227836SJohn.Forte@Sun.COM ipp = (stmf_i_port_provider_t *)ppd->ppd_provider; 24237836SJohn.Forte@Sun.COM if (ipp->ipp_pp->pp_cb == NULL) 24247836SJohn.Forte@Sun.COM goto bail_out; 24257836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 24267836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24277836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_cb(ipp->ipp_pp, 24287836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 24297836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 24307836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 24317836SJohn.Forte@Sun.COM } 24327836SJohn.Forte@Sun.COM } 24337836SJohn.Forte@Sun.COM 24347836SJohn.Forte@Sun.COM bail_out: 24357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24367836SJohn.Forte@Sun.COM 24377836SJohn.Forte@Sun.COM return (0); 24387836SJohn.Forte@Sun.COM } 24397836SJohn.Forte@Sun.COM 24407836SJohn.Forte@Sun.COM void 24417836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd) 24427836SJohn.Forte@Sun.COM { 24437836SJohn.Forte@Sun.COM stmf_pp_data_t **pppd; 24447836SJohn.Forte@Sun.COM 24457836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 24467836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 24477836SJohn.Forte@Sun.COM if (ppd->ppd_lu_provider) { 24487836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 24497836SJohn.Forte@Sun.COM ppd->ppd_provider)->ilp_ppd = NULL; 24507836SJohn.Forte@Sun.COM } else { 24517836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 24527836SJohn.Forte@Sun.COM ppd->ppd_provider)->ipp_ppd = NULL; 24537836SJohn.Forte@Sun.COM } 24547836SJohn.Forte@Sun.COM ppd->ppd_provider = NULL; 24557836SJohn.Forte@Sun.COM } 24567836SJohn.Forte@Sun.COM 24577836SJohn.Forte@Sun.COM for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL; 24588662SJordan.Vaughan@Sun.com pppd = &((*pppd)->ppd_next)) { 24597836SJohn.Forte@Sun.COM if (*pppd == ppd) 24607836SJohn.Forte@Sun.COM break; 24617836SJohn.Forte@Sun.COM } 24627836SJohn.Forte@Sun.COM 24637836SJohn.Forte@Sun.COM if (*pppd == NULL) 24647836SJohn.Forte@Sun.COM return; 24657836SJohn.Forte@Sun.COM 24667836SJohn.Forte@Sun.COM *pppd = ppd->ppd_next; 24677836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 24687836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 24697836SJohn.Forte@Sun.COM 24707836SJohn.Forte@Sun.COM kmem_free(ppd, ppd->ppd_alloc_size); 24717836SJohn.Forte@Sun.COM } 24727836SJohn.Forte@Sun.COM 24737836SJohn.Forte@Sun.COM int 24747836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi) 24757836SJohn.Forte@Sun.COM { 24767836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 24777836SJohn.Forte@Sun.COM int ret = ENOENT; 24787836SJohn.Forte@Sun.COM 24797836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 24807836SJohn.Forte@Sun.COM return (EINVAL); 24817836SJohn.Forte@Sun.COM } 24827836SJohn.Forte@Sun.COM 24837836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 24847836SJohn.Forte@Sun.COM 24857836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 24867836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 24877836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 24887836SJohn.Forte@Sun.COM continue; 24897836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 24907836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 24917836SJohn.Forte@Sun.COM continue; 24927836SJohn.Forte@Sun.COM } 24937836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 24947836SJohn.Forte@Sun.COM break; 24957836SJohn.Forte@Sun.COM } 24967836SJohn.Forte@Sun.COM 24977836SJohn.Forte@Sun.COM if (ppd) { 24987836SJohn.Forte@Sun.COM ret = 0; 24997836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 25007836SJohn.Forte@Sun.COM } 25017836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25027836SJohn.Forte@Sun.COM 25037836SJohn.Forte@Sun.COM return (ret); 25047836SJohn.Forte@Sun.COM } 25057836SJohn.Forte@Sun.COM 25069585STim.Szeto@Sun.COM int 25079585STim.Szeto@Sun.COM stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 25089585STim.Szeto@Sun.COM uint32_t *err_ret) 25099585STim.Szeto@Sun.COM { 25109585STim.Szeto@Sun.COM stmf_pp_data_t *ppd; 25119585STim.Szeto@Sun.COM size_t req_size; 25129585STim.Szeto@Sun.COM int ret = ENOENT; 25139585STim.Szeto@Sun.COM char *bufp = (char *)ppi_out->ppi_data; 25149585STim.Szeto@Sun.COM 25159585STim.Szeto@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 25169585STim.Szeto@Sun.COM return (EINVAL); 25179585STim.Szeto@Sun.COM } 25189585STim.Szeto@Sun.COM 25199585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 25209585STim.Szeto@Sun.COM 25219585STim.Szeto@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 25229585STim.Szeto@Sun.COM if (ppi->ppi_lu_provider) { 25239585STim.Szeto@Sun.COM if (!ppd->ppd_lu_provider) 25249585STim.Szeto@Sun.COM continue; 25259585STim.Szeto@Sun.COM } else if (ppi->ppi_port_provider) { 25269585STim.Szeto@Sun.COM if (!ppd->ppd_port_provider) 25279585STim.Szeto@Sun.COM continue; 25289585STim.Szeto@Sun.COM } 25299585STim.Szeto@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 25309585STim.Szeto@Sun.COM break; 25319585STim.Szeto@Sun.COM } 25329585STim.Szeto@Sun.COM 25339585STim.Szeto@Sun.COM if (ppd && ppd->ppd_nv) { 25349585STim.Szeto@Sun.COM ppi_out->ppi_token = ppd->ppd_token; 25359585STim.Szeto@Sun.COM if ((ret = nvlist_size(ppd->ppd_nv, &req_size, 25369585STim.Szeto@Sun.COM NV_ENCODE_XDR)) != 0) { 25379585STim.Szeto@Sun.COM goto done; 25389585STim.Szeto@Sun.COM } 25399585STim.Szeto@Sun.COM ppi_out->ppi_data_size = req_size; 25409585STim.Szeto@Sun.COM if (req_size > ppi->ppi_data_size) { 25419585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_INSUFFICIENT_BUF; 25429585STim.Szeto@Sun.COM ret = EINVAL; 25439585STim.Szeto@Sun.COM goto done; 25449585STim.Szeto@Sun.COM } 25459585STim.Szeto@Sun.COM 25469585STim.Szeto@Sun.COM if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size, 25479585STim.Szeto@Sun.COM NV_ENCODE_XDR, 0)) != 0) { 25489585STim.Szeto@Sun.COM goto done; 25499585STim.Szeto@Sun.COM } 25509585STim.Szeto@Sun.COM ret = 0; 25519585STim.Szeto@Sun.COM } 25529585STim.Szeto@Sun.COM 25539585STim.Szeto@Sun.COM done: 25549585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25559585STim.Szeto@Sun.COM 25569585STim.Szeto@Sun.COM return (ret); 25579585STim.Szeto@Sun.COM } 25589585STim.Szeto@Sun.COM 25597836SJohn.Forte@Sun.COM void 25607836SJohn.Forte@Sun.COM stmf_delete_all_ppds() 25617836SJohn.Forte@Sun.COM { 25627836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd, *nppd; 25637836SJohn.Forte@Sun.COM 25647836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 25657836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) { 25667836SJohn.Forte@Sun.COM nppd = ppd->ppd_next; 25677836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 25687836SJohn.Forte@Sun.COM } 25697836SJohn.Forte@Sun.COM } 25707836SJohn.Forte@Sun.COM 25719435STim.Szeto@Sun.COM /* 25729435STim.Szeto@Sun.COM * 16 is the max string length of a protocol_ident, increase 25739435STim.Szeto@Sun.COM * the size if needed. 25749435STim.Szeto@Sun.COM */ 25759435STim.Szeto@Sun.COM #define STMF_KSTAT_LU_SZ (STMF_GUID_INPUT + 1 + 256) 25769435STim.Szeto@Sun.COM #define STMF_KSTAT_TGT_SZ (256 * 2 + 16) 25779435STim.Szeto@Sun.COM 25789435STim.Szeto@Sun.COM typedef struct stmf_kstat_lu_info { 25799435STim.Szeto@Sun.COM kstat_named_t i_lun_guid; 25809435STim.Szeto@Sun.COM kstat_named_t i_lun_alias; 25819435STim.Szeto@Sun.COM } stmf_kstat_lu_info_t; 25829435STim.Szeto@Sun.COM 25839435STim.Szeto@Sun.COM typedef struct stmf_kstat_tgt_info { 25849435STim.Szeto@Sun.COM kstat_named_t i_tgt_name; 25859435STim.Szeto@Sun.COM kstat_named_t i_tgt_alias; 25869435STim.Szeto@Sun.COM kstat_named_t i_protocol; 25879435STim.Szeto@Sun.COM } stmf_kstat_tgt_info_t; 25889435STim.Szeto@Sun.COM 25899435STim.Szeto@Sun.COM /* 25909435STim.Szeto@Sun.COM * This array matches the Protocol Identifier in stmf_ioctl.h 25919435STim.Szeto@Sun.COM */ 25929435STim.Szeto@Sun.COM char *protocol_ident[PROTOCOL_ANY] = { 25939435STim.Szeto@Sun.COM "Fibre Channel", 25949435STim.Szeto@Sun.COM "Parallel SCSI", 25959435STim.Szeto@Sun.COM "SSA", 25969435STim.Szeto@Sun.COM "IEEE_1394", 25979435STim.Szeto@Sun.COM "SRP", 25989435STim.Szeto@Sun.COM "iSCSI", 25999435STim.Szeto@Sun.COM "SAS", 26009435STim.Szeto@Sun.COM "ADT", 26019435STim.Szeto@Sun.COM "ATAPI", 26029435STim.Szeto@Sun.COM "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN" 26039435STim.Szeto@Sun.COM }; 26049435STim.Szeto@Sun.COM 26059435STim.Szeto@Sun.COM /* 26069435STim.Szeto@Sun.COM * Update the lun wait/run queue count 26079435STim.Szeto@Sun.COM */ 26089435STim.Szeto@Sun.COM static void 26099435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(scsi_task_t *task, void func()) 26109435STim.Szeto@Sun.COM { 26119435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 26129435STim.Szeto@Sun.COM kstat_io_t *kip; 26139435STim.Szeto@Sun.COM 26149435STim.Szeto@Sun.COM if (task->task_lu == dlun0) 26159435STim.Szeto@Sun.COM return; 26169435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 26179435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 26189435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 26199435STim.Szeto@Sun.COM if (kip != NULL) { 26209435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 26219435STim.Szeto@Sun.COM func(kip); 26229435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 26239435STim.Szeto@Sun.COM } 26249435STim.Szeto@Sun.COM } 26259435STim.Szeto@Sun.COM } 26269435STim.Szeto@Sun.COM 26279435STim.Szeto@Sun.COM /* 26289435STim.Szeto@Sun.COM * Update the target(lport) wait/run queue count 26299435STim.Szeto@Sun.COM */ 26309435STim.Szeto@Sun.COM static void 26319435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(scsi_task_t *task, void func()) 26329435STim.Szeto@Sun.COM { 26339435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 26349435STim.Szeto@Sun.COM kstat_io_t *kip; 26359435STim.Szeto@Sun.COM 26369435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 26379435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 26389435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 26399435STim.Szeto@Sun.COM if (kip != NULL) { 26409435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 26419435STim.Szeto@Sun.COM func(kip); 26429435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 26439435STim.Szeto@Sun.COM } 26449435STim.Szeto@Sun.COM } 26459435STim.Szeto@Sun.COM } 26469435STim.Szeto@Sun.COM 26479435STim.Szeto@Sun.COM static void 26489435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 26499435STim.Szeto@Sun.COM { 26509435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 26519435STim.Szeto@Sun.COM kstat_io_t *kip; 26529435STim.Szeto@Sun.COM 26539435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 26549435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 26559435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 26569435STim.Szeto@Sun.COM if (kip != NULL) { 26579435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 26589435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 26599435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 26609435STim.Szeto@Sun.COM } 26619435STim.Szeto@Sun.COM } 26629435STim.Szeto@Sun.COM } 26639435STim.Szeto@Sun.COM 26649435STim.Szeto@Sun.COM static void 26659435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 26669435STim.Szeto@Sun.COM { 26679435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 26689435STim.Szeto@Sun.COM kstat_io_t *kip; 26699435STim.Szeto@Sun.COM 26709435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 26719435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 26729435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 26739435STim.Szeto@Sun.COM if (kip != NULL) { 26749435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 26759435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 26769435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 26779435STim.Szeto@Sun.COM } 26789435STim.Szeto@Sun.COM } 26799435STim.Szeto@Sun.COM } 26809435STim.Szeto@Sun.COM 26819435STim.Szeto@Sun.COM static void 26829435STim.Szeto@Sun.COM stmf_create_kstat_lu(stmf_i_lu_t *ilu) 26839435STim.Szeto@Sun.COM { 26849435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 26859435STim.Szeto@Sun.COM stmf_kstat_lu_info_t *ks_lu; 26869435STim.Szeto@Sun.COM 26879435STim.Szeto@Sun.COM /* create kstat lun info */ 26889435STim.Szeto@Sun.COM ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ, 26899435STim.Szeto@Sun.COM KM_NOSLEEP); 26909435STim.Szeto@Sun.COM if (ks_lu == NULL) { 26919435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 26929435STim.Szeto@Sun.COM return; 26939435STim.Szeto@Sun.COM } 26949435STim.Szeto@Sun.COM 26959435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 26969435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu); 26979435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0, 26989435STim.Szeto@Sun.COM ks_nm, "misc", KSTAT_TYPE_NAMED, 26999435STim.Szeto@Sun.COM sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t), 27009435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 27019435STim.Szeto@Sun.COM kmem_free(ks_lu, STMF_KSTAT_LU_SZ); 27029435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu failed"); 27039435STim.Szeto@Sun.COM return; 27049435STim.Szeto@Sun.COM } 27059435STim.Szeto@Sun.COM 27069435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ; 27079435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data = ks_lu; 27089435STim.Szeto@Sun.COM 27099435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_guid, "lun-guid", 27109435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 27119435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_alias, "lun-alias", 27129435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 27139435STim.Szeto@Sun.COM 27149435STim.Szeto@Sun.COM /* convert guid to hex string */ 27159435STim.Szeto@Sun.COM int i; 27169435STim.Szeto@Sun.COM uint8_t *p = ilu->ilu_lu->lu_id->ident; 27179435STim.Szeto@Sun.COM bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid)); 27189435STim.Szeto@Sun.COM for (i = 0; i < STMF_GUID_INPUT / 2; i++) { 27199435STim.Szeto@Sun.COM (void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]); 27209435STim.Szeto@Sun.COM } 27219435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_guid, 27229435STim.Szeto@Sun.COM (const char *)ilu->ilu_ascii_hex_guid); 27239435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_alias, 27249435STim.Szeto@Sun.COM (const char *)ilu->ilu_lu->lu_alias); 27259435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_info); 27269435STim.Szeto@Sun.COM 27279435STim.Szeto@Sun.COM /* create kstat lun io */ 27289435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 27299435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu); 27309435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 27319435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 27329435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu_io failed"); 27339435STim.Szeto@Sun.COM return; 27349435STim.Szeto@Sun.COM } 27359435STim.Szeto@Sun.COM mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0); 27369435STim.Szeto@Sun.COM ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock; 27379435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_io); 27389435STim.Szeto@Sun.COM } 27399435STim.Szeto@Sun.COM 27409435STim.Szeto@Sun.COM static void 27419435STim.Szeto@Sun.COM stmf_create_kstat_lport(stmf_i_local_port_t *ilport) 27429435STim.Szeto@Sun.COM { 27439435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 27449435STim.Szeto@Sun.COM stmf_kstat_tgt_info_t *ks_tgt; 27459435STim.Szeto@Sun.COM int id, len; 27469435STim.Szeto@Sun.COM 27479435STim.Szeto@Sun.COM /* create kstat lport info */ 27489435STim.Szeto@Sun.COM ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ, 27499435STim.Szeto@Sun.COM KM_NOSLEEP); 27509435STim.Szeto@Sun.COM if (ks_tgt == NULL) { 27519435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 27529435STim.Szeto@Sun.COM return; 27539435STim.Szeto@Sun.COM } 27549435STim.Szeto@Sun.COM 27559435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 27569435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport); 27579435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME, 27589435STim.Szeto@Sun.COM 0, ks_nm, "misc", KSTAT_TYPE_NAMED, 27599435STim.Szeto@Sun.COM sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t), 27609435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 27619435STim.Szeto@Sun.COM kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ); 27629435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target failed"); 27639435STim.Szeto@Sun.COM return; 27649435STim.Szeto@Sun.COM } 27659435STim.Szeto@Sun.COM 27669435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ; 27679435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data = ks_tgt; 27689435STim.Szeto@Sun.COM 27699435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_name, "target-name", 27709435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 27719435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias", 27729435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 27739435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_protocol, "protocol", 27749435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 27759435STim.Szeto@Sun.COM 27769435STim.Szeto@Sun.COM /* ident might not be null terminated */ 27779435STim.Szeto@Sun.COM len = ilport->ilport_lport->lport_id->ident_length; 27789435STim.Szeto@Sun.COM bcopy(ilport->ilport_lport->lport_id->ident, 27799435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name, len); 27809435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name[len + 1] = NULL; 27819435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_name, 27829435STim.Szeto@Sun.COM (const char *)ilport->ilport_kstat_tgt_name); 27839435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_alias, 27849435STim.Szeto@Sun.COM (const char *)ilport->ilport_lport->lport_alias); 27859435STim.Szeto@Sun.COM /* protocol */ 27869435STim.Szeto@Sun.COM if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) { 27879435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: protocol_id out of bound"); 27889435STim.Szeto@Sun.COM id = PROTOCOL_ANY; 27899435STim.Szeto@Sun.COM } 27909435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]); 27919435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_info); 27929435STim.Szeto@Sun.COM 27939435STim.Szeto@Sun.COM /* create kstat lport io */ 27949435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 27959435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport); 27969435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 27979435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 27989435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target_io failed"); 27999435STim.Szeto@Sun.COM return; 28009435STim.Szeto@Sun.COM } 28019435STim.Szeto@Sun.COM mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0); 28029435STim.Szeto@Sun.COM ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock; 28039435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_io); 28049435STim.Szeto@Sun.COM } 28059435STim.Szeto@Sun.COM 280610725SJohn.Forte@Sun.COM /* 280710725SJohn.Forte@Sun.COM * set the asymmetric access state for a logical unit 280810725SJohn.Forte@Sun.COM * caller is responsible for establishing SCSI unit attention on 280910725SJohn.Forte@Sun.COM * state change 281010725SJohn.Forte@Sun.COM */ 281110725SJohn.Forte@Sun.COM stmf_status_t 281210725SJohn.Forte@Sun.COM stmf_set_lu_access(stmf_lu_t *lu, uint8_t access_state) 281310725SJohn.Forte@Sun.COM { 281410725SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 281510725SJohn.Forte@Sun.COM uint8_t *p1, *p2; 281610725SJohn.Forte@Sun.COM 281710725SJohn.Forte@Sun.COM if ((access_state != STMF_LU_STANDBY) && 281810725SJohn.Forte@Sun.COM (access_state != STMF_LU_ACTIVE)) { 281910725SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 282010725SJohn.Forte@Sun.COM } 282110725SJohn.Forte@Sun.COM 282210725SJohn.Forte@Sun.COM p1 = &lu->lu_id->ident[0]; 282310725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 282410725SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 282510725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 282610725SJohn.Forte@Sun.COM return (STMF_BUSY); 282710725SJohn.Forte@Sun.COM } 282810725SJohn.Forte@Sun.COM 282910725SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 283010725SJohn.Forte@Sun.COM p2 = &ilu->ilu_lu->lu_id->ident[0]; 283110725SJohn.Forte@Sun.COM if (bcmp(p1, p2, 16) == 0) { 283210725SJohn.Forte@Sun.COM break; 283310725SJohn.Forte@Sun.COM } 283410725SJohn.Forte@Sun.COM } 283510725SJohn.Forte@Sun.COM 283610725SJohn.Forte@Sun.COM if (!ilu) { 283710725SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 283810725SJohn.Forte@Sun.COM } else { 283910725SJohn.Forte@Sun.COM /* 284010725SJohn.Forte@Sun.COM * We're changing access state on an existing logical unit 284110725SJohn.Forte@Sun.COM * Send the proxy registration message for this logical unit 284210725SJohn.Forte@Sun.COM * if we're in alua mode. 284310725SJohn.Forte@Sun.COM * If the requested state is STMF_LU_ACTIVE, we want to register 284410725SJohn.Forte@Sun.COM * this logical unit. 284510725SJohn.Forte@Sun.COM * If the requested state is STMF_LU_STANDBY, we're going to 284610725SJohn.Forte@Sun.COM * abort all tasks for this logical unit. 284710725SJohn.Forte@Sun.COM */ 284810725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state == 1 && 284910725SJohn.Forte@Sun.COM access_state == STMF_LU_ACTIVE) { 285010725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS; 285110725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_reg_lun; 285210725SJohn.Forte@Sun.COM if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 && 285310725SJohn.Forte@Sun.COM lu->lu_lp->lp_alua_support) { 285410725SJohn.Forte@Sun.COM ilu->ilu_alua = 1; 285510725SJohn.Forte@Sun.COM /* allocate the register message */ 285610725SJohn.Forte@Sun.COM ic_reg_lun = ic_lun_active_msg_alloc(p1, 285710725SJohn.Forte@Sun.COM lu->lu_lp->lp_name, 285810725SJohn.Forte@Sun.COM lu->lu_proxy_reg_arg_len, 285910725SJohn.Forte@Sun.COM (uint8_t *)lu->lu_proxy_reg_arg, 286010725SJohn.Forte@Sun.COM stmf_proxy_msg_id); 286110725SJohn.Forte@Sun.COM /* send the message */ 286210725SJohn.Forte@Sun.COM if (ic_reg_lun) { 286310725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_reg_lun); 286410725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 286510725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 286610725SJohn.Forte@Sun.COM } 286710725SJohn.Forte@Sun.COM } 286810725SJohn.Forte@Sun.COM } 286910725SJohn.Forte@Sun.COM } else if (stmf_state.stmf_alua_state == 1 && 287010725SJohn.Forte@Sun.COM access_state == STMF_LU_STANDBY) { 287110725SJohn.Forte@Sun.COM /* abort all tasks for this lu */ 287210725SJohn.Forte@Sun.COM stmf_task_lu_killall(lu, NULL, STMF_ABORTED); 287310725SJohn.Forte@Sun.COM } 287410725SJohn.Forte@Sun.COM } 287510725SJohn.Forte@Sun.COM 287610725SJohn.Forte@Sun.COM ilu->ilu_access = access_state; 287710725SJohn.Forte@Sun.COM 287810725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 287910725SJohn.Forte@Sun.COM return (STMF_SUCCESS); 288010725SJohn.Forte@Sun.COM } 288110725SJohn.Forte@Sun.COM 288210725SJohn.Forte@Sun.COM 28837836SJohn.Forte@Sun.COM stmf_status_t 28847836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu) 28857836SJohn.Forte@Sun.COM { 28867836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 28877836SJohn.Forte@Sun.COM uint8_t *p1, *p2; 28887836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 28897836SJohn.Forte@Sun.COM stmf_id_data_t *luid; 28907836SJohn.Forte@Sun.COM 28917836SJohn.Forte@Sun.COM if ((lu->lu_id->ident_type != ID_TYPE_NAA) || 28927836SJohn.Forte@Sun.COM (lu->lu_id->ident_length != 16) || 28937836SJohn.Forte@Sun.COM ((lu->lu_id->ident[0] & 0xf0) != 0x60)) { 28947836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 28957836SJohn.Forte@Sun.COM } 28967836SJohn.Forte@Sun.COM p1 = &lu->lu_id->ident[0]; 28977836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 28987836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 28997836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 29007836SJohn.Forte@Sun.COM return (STMF_BUSY); 29017836SJohn.Forte@Sun.COM } 29027836SJohn.Forte@Sun.COM 29037836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 29047836SJohn.Forte@Sun.COM p2 = &ilu->ilu_lu->lu_id->ident[0]; 29057836SJohn.Forte@Sun.COM if (bcmp(p1, p2, 16) == 0) { 29067836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 29077836SJohn.Forte@Sun.COM return (STMF_ALREADY); 29087836SJohn.Forte@Sun.COM } 29097836SJohn.Forte@Sun.COM } 29107836SJohn.Forte@Sun.COM 29117836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 29127836SJohn.Forte@Sun.COM luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 29137836SJohn.Forte@Sun.COM lu->lu_id->ident_length, lu->lu_id->ident); 29147836SJohn.Forte@Sun.COM if (luid) { 29157836SJohn.Forte@Sun.COM luid->id_pt_to_object = (void *)ilu; 29167836SJohn.Forte@Sun.COM ilu->ilu_luid = luid; 29177836SJohn.Forte@Sun.COM } 29187836SJohn.Forte@Sun.COM ilu->ilu_alias = NULL; 29197836SJohn.Forte@Sun.COM 29207836SJohn.Forte@Sun.COM ilu->ilu_next = stmf_state.stmf_ilulist; 29217836SJohn.Forte@Sun.COM ilu->ilu_prev = NULL; 29227836SJohn.Forte@Sun.COM if (ilu->ilu_next) 29237836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu; 29247836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu; 29257836SJohn.Forte@Sun.COM stmf_state.stmf_nlus++; 29267836SJohn.Forte@Sun.COM if (lu->lu_lp) { 29277836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 29287836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus++; 29297836SJohn.Forte@Sun.COM } 29307836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 29317836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl); 29329435STim.Szeto@Sun.COM stmf_create_kstat_lu(ilu); 293310725SJohn.Forte@Sun.COM /* 293410725SJohn.Forte@Sun.COM * register with proxy module if available and logical unit 293510725SJohn.Forte@Sun.COM * is in active state 293610725SJohn.Forte@Sun.COM */ 293710725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state == 1 && 293810725SJohn.Forte@Sun.COM ilu->ilu_access == STMF_LU_ACTIVE) { 293910725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS; 294010725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_reg_lun; 294110725SJohn.Forte@Sun.COM if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 && 294210725SJohn.Forte@Sun.COM lu->lu_lp->lp_alua_support) { 294310725SJohn.Forte@Sun.COM ilu->ilu_alua = 1; 294410725SJohn.Forte@Sun.COM /* allocate the register message */ 294510725SJohn.Forte@Sun.COM ic_reg_lun = ic_reg_lun_msg_alloc(p1, 294610725SJohn.Forte@Sun.COM lu->lu_lp->lp_name, lu->lu_proxy_reg_arg_len, 294710725SJohn.Forte@Sun.COM (uint8_t *)lu->lu_proxy_reg_arg, stmf_proxy_msg_id); 294810725SJohn.Forte@Sun.COM /* send the message */ 294910725SJohn.Forte@Sun.COM if (ic_reg_lun) { 295010725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_reg_lun); 295110725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 295210725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 295310725SJohn.Forte@Sun.COM } 295410725SJohn.Forte@Sun.COM } 295510725SJohn.Forte@Sun.COM } 295610725SJohn.Forte@Sun.COM } 29577836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 29587836SJohn.Forte@Sun.COM 29597836SJohn.Forte@Sun.COM /* XXX we should probably check if this lu can be brought online */ 29607836SJohn.Forte@Sun.COM ilu->ilu_prev_state = STMF_STATE_ONLINE; 29617836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 29627836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 29637836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 29647836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci); 29657836SJohn.Forte@Sun.COM } 29667836SJohn.Forte@Sun.COM 29677836SJohn.Forte@Sun.COM /* XXX: Generate event */ 29687836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 29697836SJohn.Forte@Sun.COM } 29707836SJohn.Forte@Sun.COM 29717836SJohn.Forte@Sun.COM stmf_status_t 29727836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu) 29737836SJohn.Forte@Sun.COM { 29747836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 29757836SJohn.Forte@Sun.COM 29767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 29777836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 29787836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 29797836SJohn.Forte@Sun.COM return (STMF_BUSY); 29807836SJohn.Forte@Sun.COM } 29817836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu(lu); 29827836SJohn.Forte@Sun.COM if (ilu == NULL) { 29837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 29847836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 29857836SJohn.Forte@Sun.COM } 29867836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 29877836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 29887836SJohn.Forte@Sun.COM while (ilu->ilu_flags & ILU_STALL_DEREGISTER) { 29897836SJohn.Forte@Sun.COM cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock); 29907836SJohn.Forte@Sun.COM } 29917836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 29927836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 29937836SJohn.Forte@Sun.COM 29947836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 29957836SJohn.Forte@Sun.COM do { 29967836SJohn.Forte@Sun.COM itask = nitask; 29977836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 29987836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 29997836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 30007836SJohn.Forte@Sun.COM } while (nitask != NULL); 30017836SJohn.Forte@Sun.COM 30027836SJohn.Forte@Sun.COM ilu->ilu_tasks = ilu->ilu_free_tasks = NULL; 30037836SJohn.Forte@Sun.COM ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0; 30047836SJohn.Forte@Sun.COM } 300510725SJohn.Forte@Sun.COM /* de-register with proxy if available */ 300610725SJohn.Forte@Sun.COM if (ilu->ilu_access == STMF_LU_ACTIVE && 300710725SJohn.Forte@Sun.COM stmf_state.stmf_alua_state == 1) { 300810725SJohn.Forte@Sun.COM /* de-register with proxy module */ 300910725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret = STMF_IC_MSG_SUCCESS; 301010725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_dereg_lun; 301110725SJohn.Forte@Sun.COM if (lu->lu_lp && lu->lu_lp->lp_lpif_rev == LPIF_REV_2 && 301210725SJohn.Forte@Sun.COM lu->lu_lp->lp_alua_support) { 301310725SJohn.Forte@Sun.COM ilu->ilu_alua = 1; 301410725SJohn.Forte@Sun.COM /* allocate the de-register message */ 301510725SJohn.Forte@Sun.COM ic_dereg_lun = ic_dereg_lun_msg_alloc( 301610725SJohn.Forte@Sun.COM lu->lu_id->ident, lu->lu_lp->lp_name, 0, 301710725SJohn.Forte@Sun.COM NULL, stmf_proxy_msg_id); 301810725SJohn.Forte@Sun.COM /* send the message */ 301910725SJohn.Forte@Sun.COM if (ic_dereg_lun) { 302010725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_dereg_lun); 302110725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 302210725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 302310725SJohn.Forte@Sun.COM } 302410725SJohn.Forte@Sun.COM } 302510725SJohn.Forte@Sun.COM } 302610725SJohn.Forte@Sun.COM } 30277836SJohn.Forte@Sun.COM 30287836SJohn.Forte@Sun.COM if (ilu->ilu_next) 30297836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu->ilu_prev; 30307836SJohn.Forte@Sun.COM if (ilu->ilu_prev) 30317836SJohn.Forte@Sun.COM ilu->ilu_prev->ilu_next = ilu->ilu_next; 30327836SJohn.Forte@Sun.COM else 30337836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu->ilu_next; 30347836SJohn.Forte@Sun.COM stmf_state.stmf_nlus--; 30357836SJohn.Forte@Sun.COM 30367836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_draining) { 30377836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 30387836SJohn.Forte@Sun.COM } 30397836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_timing) { 30407836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 30417836SJohn.Forte@Sun.COM } 30427836SJohn.Forte@Sun.COM if (lu->lu_lp) { 30437836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 30447836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus--; 30457836SJohn.Forte@Sun.COM } 30467836SJohn.Forte@Sun.COM if (ilu->ilu_luid) { 30477836SJohn.Forte@Sun.COM ((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object = 30487836SJohn.Forte@Sun.COM NULL; 30497836SJohn.Forte@Sun.COM ilu->ilu_luid = NULL; 30507836SJohn.Forte@Sun.COM } 30517836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl); 30527836SJohn.Forte@Sun.COM } else { 30537836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 30547836SJohn.Forte@Sun.COM return (STMF_BUSY); 30557836SJohn.Forte@Sun.COM } 30569435STim.Szeto@Sun.COM if (ilu->ilu_kstat_info) { 305710421STim.Szeto@Sun.COM kmem_free(ilu->ilu_kstat_info->ks_data, 305810421STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data_size); 30599435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_info); 30609435STim.Szeto@Sun.COM } 30619435STim.Szeto@Sun.COM if (ilu->ilu_kstat_io) { 30629435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_io); 30639435STim.Szeto@Sun.COM mutex_destroy(&ilu->ilu_kstat_lock); 30649435STim.Szeto@Sun.COM } 30657836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 30667836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 30677836SJohn.Forte@Sun.COM } 30687836SJohn.Forte@Sun.COM 306910725SJohn.Forte@Sun.COM void 307010725SJohn.Forte@Sun.COM stmf_set_port_standby(stmf_local_port_t *lport, uint16_t rtpid) 307110725SJohn.Forte@Sun.COM { 307210725SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 307310725SJohn.Forte@Sun.COM (stmf_i_local_port_t *)lport->lport_stmf_private; 307410725SJohn.Forte@Sun.COM ilport->ilport_rtpid = rtpid; 307510725SJohn.Forte@Sun.COM ilport->ilport_standby = 1; 307610725SJohn.Forte@Sun.COM } 307710725SJohn.Forte@Sun.COM 30787836SJohn.Forte@Sun.COM stmf_status_t 30797836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport) 30807836SJohn.Forte@Sun.COM { 30817836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 30827836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 30837836SJohn.Forte@Sun.COM int start_workers = 0; 30847836SJohn.Forte@Sun.COM 30857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 30867836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 30877836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 30887836SJohn.Forte@Sun.COM return (STMF_BUSY); 30897836SJohn.Forte@Sun.COM } 30907836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 30917836SJohn.Forte@Sun.COM rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL); 30927836SJohn.Forte@Sun.COM 30937836SJohn.Forte@Sun.COM ilport->ilport_next = stmf_state.stmf_ilportlist; 30947836SJohn.Forte@Sun.COM ilport->ilport_prev = NULL; 30957836SJohn.Forte@Sun.COM if (ilport->ilport_next) 30967836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport; 30977836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport; 30987836SJohn.Forte@Sun.COM stmf_state.stmf_nlports++; 30997836SJohn.Forte@Sun.COM if (lport->lport_pp) { 31007836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 31017836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps++; 31027836SJohn.Forte@Sun.COM } 31037836SJohn.Forte@Sun.COM ilport->ilport_tg = 31047836SJohn.Forte@Sun.COM stmf_lookup_group_for_target(lport->lport_id->ident, 31058662SJordan.Vaughan@Sun.com lport->lport_id->ident_length); 310610725SJohn.Forte@Sun.COM 310710725SJohn.Forte@Sun.COM /* 310810725SJohn.Forte@Sun.COM * rtpid will/must be set if this is a standby port 310910725SJohn.Forte@Sun.COM * only register ports that are not standby (proxy) ports 311010725SJohn.Forte@Sun.COM */ 311110725SJohn.Forte@Sun.COM if (ilport->ilport_standby == 0) { 311210725SJohn.Forte@Sun.COM ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1); 311310725SJohn.Forte@Sun.COM } 311410725SJohn.Forte@Sun.COM 311510725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state == 1 && 311610725SJohn.Forte@Sun.COM ilport->ilport_standby == 0) { 311710725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_reg_port; 311810725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret; 311910725SJohn.Forte@Sun.COM stmf_local_port_t *lport; 312010725SJohn.Forte@Sun.COM lport = ilport->ilport_lport; 312110725SJohn.Forte@Sun.COM ic_reg_port = ic_reg_port_msg_alloc( 312210725SJohn.Forte@Sun.COM lport->lport_id, ilport->ilport_rtpid, 312310725SJohn.Forte@Sun.COM 0, NULL, stmf_proxy_msg_id); 312410725SJohn.Forte@Sun.COM if (ic_reg_port) { 312510725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_reg_port); 312610725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 312710725SJohn.Forte@Sun.COM ilport->ilport_reg_msgid = stmf_proxy_msg_id++; 312810725SJohn.Forte@Sun.COM } else { 312910725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "error on port registration " 313010725SJohn.Forte@Sun.COM "port - %s", ilport->ilport_kstat_tgt_name); 313110725SJohn.Forte@Sun.COM } 313210725SJohn.Forte@Sun.COM } 313310725SJohn.Forte@Sun.COM } 31347836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl); 31359435STim.Szeto@Sun.COM stmf_create_kstat_lport(ilport); 31367836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) { 31377836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLING; 31387836SJohn.Forte@Sun.COM start_workers = 1; 31397836SJohn.Forte@Sun.COM } 31407836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31417836SJohn.Forte@Sun.COM 31427836SJohn.Forte@Sun.COM if (start_workers) 31437836SJohn.Forte@Sun.COM stmf_worker_init(); 31447836SJohn.Forte@Sun.COM 31457836SJohn.Forte@Sun.COM /* XXX we should probably check if this lport can be brought online */ 31467836SJohn.Forte@Sun.COM ilport->ilport_prev_state = STMF_STATE_ONLINE; 31477836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 31487836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 31497836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 31507836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci); 31517836SJohn.Forte@Sun.COM } 31527836SJohn.Forte@Sun.COM 31537836SJohn.Forte@Sun.COM /* XXX: Generate event */ 31547836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 31557836SJohn.Forte@Sun.COM } 31567836SJohn.Forte@Sun.COM 31577836SJohn.Forte@Sun.COM stmf_status_t 31587836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport) 31597836SJohn.Forte@Sun.COM { 31607836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 31617836SJohn.Forte@Sun.COM 31627836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 31637836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 31647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31657836SJohn.Forte@Sun.COM return (STMF_BUSY); 31667836SJohn.Forte@Sun.COM } 316710725SJohn.Forte@Sun.COM 31687836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 316910725SJohn.Forte@Sun.COM 317010725SJohn.Forte@Sun.COM /* 317110725SJohn.Forte@Sun.COM * deregister ports that are not standby (proxy) 317210725SJohn.Forte@Sun.COM */ 317310725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state == 1 && 317410725SJohn.Forte@Sun.COM ilport->ilport_standby == 0) { 317510725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_dereg_port; 317610725SJohn.Forte@Sun.COM stmf_ic_msg_status_t ic_ret; 317710725SJohn.Forte@Sun.COM ic_dereg_port = ic_dereg_port_msg_alloc( 317810725SJohn.Forte@Sun.COM lport->lport_id, 0, NULL, stmf_proxy_msg_id); 317910725SJohn.Forte@Sun.COM if (ic_dereg_port) { 318010725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_dereg_port); 318110725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 318210725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 318310725SJohn.Forte@Sun.COM } 318410725SJohn.Forte@Sun.COM } 318510725SJohn.Forte@Sun.COM } 318610725SJohn.Forte@Sun.COM 31877836SJohn.Forte@Sun.COM if (ilport->ilport_nsessions == 0) { 31887836SJohn.Forte@Sun.COM if (ilport->ilport_next) 31897836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport->ilport_prev; 31907836SJohn.Forte@Sun.COM if (ilport->ilport_prev) 31917836SJohn.Forte@Sun.COM ilport->ilport_prev->ilport_next = ilport->ilport_next; 31927836SJohn.Forte@Sun.COM else 31937836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport->ilport_next; 31947836SJohn.Forte@Sun.COM rw_destroy(&ilport->ilport_lock); 31957836SJohn.Forte@Sun.COM stmf_state.stmf_nlports--; 31967836SJohn.Forte@Sun.COM if (lport->lport_pp) { 31977836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 31987836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps--; 31997836SJohn.Forte@Sun.COM } 32007836SJohn.Forte@Sun.COM ilport->ilport_tg = NULL; 32017836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl); 32027836SJohn.Forte@Sun.COM } else { 32037836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 32047836SJohn.Forte@Sun.COM return (STMF_BUSY); 32057836SJohn.Forte@Sun.COM } 32069435STim.Szeto@Sun.COM if (ilport->ilport_kstat_info) { 320710421STim.Szeto@Sun.COM kmem_free(ilport->ilport_kstat_info->ks_data, 320810421STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data_size); 32099435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_info); 32109435STim.Szeto@Sun.COM } 32119435STim.Szeto@Sun.COM if (ilport->ilport_kstat_io) { 32129435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_io); 32139435STim.Szeto@Sun.COM mutex_destroy(&ilport->ilport_kstat_lock); 32149435STim.Szeto@Sun.COM } 32157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 32167836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 32177836SJohn.Forte@Sun.COM } 32187836SJohn.Forte@Sun.COM 32197836SJohn.Forte@Sun.COM /* 32207836SJohn.Forte@Sun.COM * Port provider has to make sure that register/deregister session and 32217836SJohn.Forte@Sun.COM * port are serialized calls. 32227836SJohn.Forte@Sun.COM */ 32237836SJohn.Forte@Sun.COM stmf_status_t 32247836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 32257836SJohn.Forte@Sun.COM { 32267836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 32277836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 32287836SJohn.Forte@Sun.COM lport->lport_stmf_private; 32297836SJohn.Forte@Sun.COM uint8_t lun[8]; 32307836SJohn.Forte@Sun.COM 32317836SJohn.Forte@Sun.COM /* 32327836SJohn.Forte@Sun.COM * Port state has to be online to register a scsi session. It is 32337836SJohn.Forte@Sun.COM * possible that we started an offline operation and a new SCSI 32347836SJohn.Forte@Sun.COM * session started at the same time (in that case also we are going 32357836SJohn.Forte@Sun.COM * to fail the registeration). But any other state is simply 32367836SJohn.Forte@Sun.COM * a bad port provider implementation. 32377836SJohn.Forte@Sun.COM */ 32387836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 32397836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 32407836SJohn.Forte@Sun.COM stmf_trace(lport->lport_alias, "Port is trying to " 32417836SJohn.Forte@Sun.COM "register a session while the state is neither " 32427836SJohn.Forte@Sun.COM "online nor offlining"); 32437836SJohn.Forte@Sun.COM } 32447836SJohn.Forte@Sun.COM return (STMF_FAILURE); 32457836SJohn.Forte@Sun.COM } 32467836SJohn.Forte@Sun.COM bzero(lun, 8); 32477836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 32487836SJohn.Forte@Sun.COM iss->iss_flags |= ISS_BEING_CREATED; 32497836SJohn.Forte@Sun.COM 32507836SJohn.Forte@Sun.COM /* sessions use the ilport_lock. No separate lock is required */ 32517836SJohn.Forte@Sun.COM iss->iss_lockp = &ilport->ilport_lock; 32527836SJohn.Forte@Sun.COM (void) stmf_session_create_lun_map(ilport, iss); 32537836SJohn.Forte@Sun.COM 32547836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 32557836SJohn.Forte@Sun.COM ilport->ilport_nsessions++; 32567836SJohn.Forte@Sun.COM iss->iss_next = ilport->ilport_ss_list; 32577836SJohn.Forte@Sun.COM ilport->ilport_ss_list = iss; 32587836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 32597836SJohn.Forte@Sun.COM 32607836SJohn.Forte@Sun.COM iss->iss_creation_time = ddi_get_time(); 32617836SJohn.Forte@Sun.COM ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1); 32627836SJohn.Forte@Sun.COM iss->iss_flags &= ~ISS_BEING_CREATED; 326310725SJohn.Forte@Sun.COM /* XXX should we remove ISS_LUN_INVENTORY_CHANGED on new session? */ 326410725SJohn.Forte@Sun.COM iss->iss_flags &= ~ISS_LUN_INVENTORY_CHANGED; 32658859STim.Szeto@Sun.COM DTRACE_PROBE2(session__online, stmf_local_port_t *, lport, 32668859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 32677836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 32687836SJohn.Forte@Sun.COM } 32697836SJohn.Forte@Sun.COM 32707836SJohn.Forte@Sun.COM void 32717836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 32727836SJohn.Forte@Sun.COM { 32737836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 32748662SJordan.Vaughan@Sun.com lport->lport_stmf_private; 32757836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss, **ppss; 32767836SJohn.Forte@Sun.COM int found = 0; 327710725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_session_dereg; 327810725SJohn.Forte@Sun.COM stmf_status_t ic_ret = STMF_FAILURE; 32797836SJohn.Forte@Sun.COM 32808859STim.Szeto@Sun.COM DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport, 32818859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 32828859STim.Szeto@Sun.COM 32837836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 32847836SJohn.Forte@Sun.COM if (ss->ss_rport_alias) { 32857836SJohn.Forte@Sun.COM ss->ss_rport_alias = NULL; 32867836SJohn.Forte@Sun.COM } 32877836SJohn.Forte@Sun.COM 32887836SJohn.Forte@Sun.COM try_dereg_ss_again: 32897836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 32907836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 32918662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 32927836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_EVENT_ACTIVE) { 32937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 32947836SJohn.Forte@Sun.COM delay(1); 32957836SJohn.Forte@Sun.COM goto try_dereg_ss_again; 32967836SJohn.Forte@Sun.COM } 329710725SJohn.Forte@Sun.COM 329810725SJohn.Forte@Sun.COM /* dereg proxy session if not standby port */ 329910725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_state == 1 && ilport->ilport_standby == 0) { 330010725SJohn.Forte@Sun.COM ic_session_dereg = ic_session_dereg_msg_alloc( 330110725SJohn.Forte@Sun.COM ss, stmf_proxy_msg_id); 330210725SJohn.Forte@Sun.COM if (ic_session_dereg) { 330310725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_session_dereg); 330410725SJohn.Forte@Sun.COM if (ic_ret == STMF_IC_MSG_SUCCESS) { 330510725SJohn.Forte@Sun.COM stmf_proxy_msg_id++; 330610725SJohn.Forte@Sun.COM } 330710725SJohn.Forte@Sun.COM } 330810725SJohn.Forte@Sun.COM } 330910725SJohn.Forte@Sun.COM 33107836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 331110725SJohn.Forte@Sun.COM 33127836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 33137836SJohn.Forte@Sun.COM for (ppss = &ilport->ilport_ss_list; *ppss != NULL; 33147836SJohn.Forte@Sun.COM ppss = &((*ppss)->iss_next)) { 33157836SJohn.Forte@Sun.COM if (iss == (*ppss)) { 33167836SJohn.Forte@Sun.COM *ppss = (*ppss)->iss_next; 33177836SJohn.Forte@Sun.COM found = 1; 33187836SJohn.Forte@Sun.COM break; 33197836SJohn.Forte@Sun.COM } 33207836SJohn.Forte@Sun.COM } 33217836SJohn.Forte@Sun.COM if (!found) { 33227836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "Deregister session called for non existent" 33237836SJohn.Forte@Sun.COM " session"); 33247836SJohn.Forte@Sun.COM } 33257836SJohn.Forte@Sun.COM ilport->ilport_nsessions--; 33267836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 33277836SJohn.Forte@Sun.COM 33287836SJohn.Forte@Sun.COM (void) stmf_session_destroy_lun_map(ilport, iss); 33297836SJohn.Forte@Sun.COM } 33307836SJohn.Forte@Sun.COM 33317836SJohn.Forte@Sun.COM stmf_i_scsi_session_t * 33327836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked) 33337836SJohn.Forte@Sun.COM { 33347836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 33357836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 33367836SJohn.Forte@Sun.COM 33377836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 33387836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 33398662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 33407836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 33417836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 33428662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 33437836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_session_id == session_id) { 33447836SJohn.Forte@Sun.COM if (!stay_locked) 33457836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 33467836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 33477836SJohn.Forte@Sun.COM return (iss); 33487836SJohn.Forte@Sun.COM } 33497836SJohn.Forte@Sun.COM } 33507836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 33517836SJohn.Forte@Sun.COM } 33527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 33537836SJohn.Forte@Sun.COM return (NULL); 33547836SJohn.Forte@Sun.COM } 33557836SJohn.Forte@Sun.COM 33567836SJohn.Forte@Sun.COM void 33577836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl) 33587836SJohn.Forte@Sun.COM { 33597836SJohn.Forte@Sun.COM stmf_itl_data_t **itlpp; 33607836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 33617836SJohn.Forte@Sun.COM 33627836SJohn.Forte@Sun.COM ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED); 33637836SJohn.Forte@Sun.COM 33647836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 33657836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 33667836SJohn.Forte@Sun.COM for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL; 33678662SJordan.Vaughan@Sun.com itlpp = &(*itlpp)->itl_next) { 33687836SJohn.Forte@Sun.COM if ((*itlpp) == itl) 33697836SJohn.Forte@Sun.COM break; 33707836SJohn.Forte@Sun.COM } 33717836SJohn.Forte@Sun.COM ASSERT((*itlpp) != NULL); 33727836SJohn.Forte@Sun.COM *itlpp = itl->itl_next; 33737836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 33747836SJohn.Forte@Sun.COM lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle, 33758662SJordan.Vaughan@Sun.com (uint32_t)itl->itl_hdlrm_reason); 33767836SJohn.Forte@Sun.COM kmem_free(itl, sizeof (*itl)); 33777836SJohn.Forte@Sun.COM } 33787836SJohn.Forte@Sun.COM 33797836SJohn.Forte@Sun.COM stmf_status_t 33807836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun, 33817836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 33827836SJohn.Forte@Sun.COM { 33837836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 33847836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 33857836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 33867836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 33877836SJohn.Forte@Sun.COM uint16_t n; 33887836SJohn.Forte@Sun.COM 33897836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 33907836SJohn.Forte@Sun.COM if (ss == NULL) { 33917836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 33927836SJohn.Forte@Sun.COM if (iss == NULL) 33937836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 33947836SJohn.Forte@Sun.COM } else { 33957836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 33967836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 33977836SJohn.Forte@Sun.COM } 33987836SJohn.Forte@Sun.COM 33997836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 34007836SJohn.Forte@Sun.COM lun_map_ent = (stmf_lun_map_ent_t *) 34018662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 34027836SJohn.Forte@Sun.COM if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) { 34037836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 34047836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 34057836SJohn.Forte@Sun.COM } 34067836SJohn.Forte@Sun.COM if (lun_map_ent->ent_itl_datap != NULL) { 34077836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 34087836SJohn.Forte@Sun.COM return (STMF_ALREADY); 34097836SJohn.Forte@Sun.COM } 34107836SJohn.Forte@Sun.COM 34117836SJohn.Forte@Sun.COM itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP); 34127836SJohn.Forte@Sun.COM if (itl == NULL) { 34137836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 34147836SJohn.Forte@Sun.COM return (STMF_ALLOC_FAILURE); 34157836SJohn.Forte@Sun.COM } 34167836SJohn.Forte@Sun.COM 34177836SJohn.Forte@Sun.COM itl->itl_counter = 1; 34187836SJohn.Forte@Sun.COM itl->itl_lun = n; 34197836SJohn.Forte@Sun.COM itl->itl_handle = itl_handle; 34207836SJohn.Forte@Sun.COM itl->itl_session = iss; 34217836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 34227836SJohn.Forte@Sun.COM itl->itl_next = ilu->ilu_itl_list; 34237836SJohn.Forte@Sun.COM ilu->ilu_itl_list = itl; 34247836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 34257836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap = itl; 34267836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 34277836SJohn.Forte@Sun.COM 34287836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 34297836SJohn.Forte@Sun.COM } 34307836SJohn.Forte@Sun.COM 34317836SJohn.Forte@Sun.COM void 34327836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason) 34337836SJohn.Forte@Sun.COM { 34347836SJohn.Forte@Sun.COM uint8_t old, new; 34357836SJohn.Forte@Sun.COM 34367836SJohn.Forte@Sun.COM do { 34377836SJohn.Forte@Sun.COM old = new = itl->itl_flags; 34387836SJohn.Forte@Sun.COM if (old & STMF_ITL_BEING_TERMINATED) 34397836SJohn.Forte@Sun.COM return; 34407836SJohn.Forte@Sun.COM new |= STMF_ITL_BEING_TERMINATED; 34417836SJohn.Forte@Sun.COM } while (atomic_cas_8(&itl->itl_flags, old, new) != old); 34427836SJohn.Forte@Sun.COM itl->itl_hdlrm_reason = hdlrm_reason; 34437836SJohn.Forte@Sun.COM 34447836SJohn.Forte@Sun.COM ASSERT(itl->itl_counter); 34457836SJohn.Forte@Sun.COM 34467836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itl->itl_counter, -1)) 34477836SJohn.Forte@Sun.COM return; 34487836SJohn.Forte@Sun.COM 34497836SJohn.Forte@Sun.COM drv_usecwait(10); 34507836SJohn.Forte@Sun.COM if (itl->itl_counter) 34517836SJohn.Forte@Sun.COM return; 34527836SJohn.Forte@Sun.COM 34537836SJohn.Forte@Sun.COM stmf_release_itl_handle(lu, itl); 34547836SJohn.Forte@Sun.COM } 34557836SJohn.Forte@Sun.COM 34567836SJohn.Forte@Sun.COM stmf_status_t 34577836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu) 34587836SJohn.Forte@Sun.COM { 34597836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 34607836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 34617836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 34627836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 34637836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 34647836SJohn.Forte@Sun.COM uint32_t nmaps, nu; 34657836SJohn.Forte@Sun.COM stmf_itl_data_t **itl_list; 34667836SJohn.Forte@Sun.COM int i; 34677836SJohn.Forte@Sun.COM 34687836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 34697836SJohn.Forte@Sun.COM 34707836SJohn.Forte@Sun.COM dereg_itl_start:; 34717836SJohn.Forte@Sun.COM nmaps = ilu->ilu_ref_cnt; 34727836SJohn.Forte@Sun.COM if (nmaps == 0) 34737836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 34747836SJohn.Forte@Sun.COM itl_list = (stmf_itl_data_t **)kmem_zalloc( 34758662SJordan.Vaughan@Sun.com nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP); 34767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 34777836SJohn.Forte@Sun.COM if (nmaps != ilu->ilu_ref_cnt) { 34787836SJohn.Forte@Sun.COM /* Something changed, start all over */ 34797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 34807836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 34817836SJohn.Forte@Sun.COM goto dereg_itl_start; 34827836SJohn.Forte@Sun.COM } 34837836SJohn.Forte@Sun.COM nu = 0; 34847836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 34858662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 34867836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 34877836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 34888662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 34897836SJohn.Forte@Sun.COM lm = iss->iss_sm; 34907836SJohn.Forte@Sun.COM if (!lm) 34917836SJohn.Forte@Sun.COM continue; 34927836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 34937836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 34947836SJohn.Forte@Sun.COM continue; 34957836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 34967836SJohn.Forte@Sun.COM if ((ent->ent_lu == lu) && 34978662SJordan.Vaughan@Sun.com (ent->ent_itl_datap)) { 34987836SJohn.Forte@Sun.COM itl_list[nu++] = ent->ent_itl_datap; 34997836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 35007836SJohn.Forte@Sun.COM if (nu == nmaps) { 35017836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 35027836SJohn.Forte@Sun.COM goto dai_scan_done; 35037836SJohn.Forte@Sun.COM } 35047836SJohn.Forte@Sun.COM } 35057836SJohn.Forte@Sun.COM } /* lun table for a session */ 35067836SJohn.Forte@Sun.COM } /* sessions */ 35077836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 35087836SJohn.Forte@Sun.COM } /* ports */ 35097836SJohn.Forte@Sun.COM 35107836SJohn.Forte@Sun.COM dai_scan_done: 35117836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35127836SJohn.Forte@Sun.COM 35137836SJohn.Forte@Sun.COM for (i = 0; i < nu; i++) { 35147836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl_list[i], 35158662SJordan.Vaughan@Sun.com STMF_ITL_REASON_DEREG_REQUEST); 35167836SJohn.Forte@Sun.COM } 35177836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 35187836SJohn.Forte@Sun.COM 35197836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 35207836SJohn.Forte@Sun.COM } 35217836SJohn.Forte@Sun.COM 35227836SJohn.Forte@Sun.COM stmf_status_t 35237836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun, 35247836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 35257836SJohn.Forte@Sun.COM { 35267836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 35277836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 35287836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 35297836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 35307836SJohn.Forte@Sun.COM int i; 35317836SJohn.Forte@Sun.COM uint16_t n; 35327836SJohn.Forte@Sun.COM 35337836SJohn.Forte@Sun.COM if (ss == NULL) { 35347836SJohn.Forte@Sun.COM if (session_id == STMF_SESSION_ID_NONE) 35357836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 35367836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 35377836SJohn.Forte@Sun.COM if (iss == NULL) 35387836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 35397836SJohn.Forte@Sun.COM } else { 35407836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 35417836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 35427836SJohn.Forte@Sun.COM } 35437836SJohn.Forte@Sun.COM lm = iss->iss_sm; 35447836SJohn.Forte@Sun.COM if (lm == NULL) { 35457836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 35467836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 35477836SJohn.Forte@Sun.COM } 35487836SJohn.Forte@Sun.COM 35497836SJohn.Forte@Sun.COM if (lun) { 35507836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 35517836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 35528662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 35537836SJohn.Forte@Sun.COM } else { 35547836SJohn.Forte@Sun.COM if (itl_handle == NULL) { 35557836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 35567836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 35577836SJohn.Forte@Sun.COM } 35587836SJohn.Forte@Sun.COM ent = NULL; 35597836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 35607836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 35617836SJohn.Forte@Sun.COM continue; 35627836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 35637836SJohn.Forte@Sun.COM if (ent->ent_itl_datap && 35647836SJohn.Forte@Sun.COM (ent->ent_itl_datap->itl_handle == itl_handle)) { 35657836SJohn.Forte@Sun.COM break; 35667836SJohn.Forte@Sun.COM } 35677836SJohn.Forte@Sun.COM } 35687836SJohn.Forte@Sun.COM } 35697836SJohn.Forte@Sun.COM if ((ent == NULL) || (ent->ent_lu != lu) || 35708662SJordan.Vaughan@Sun.com (ent->ent_itl_datap == NULL)) { 35717836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 35727836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 35737836SJohn.Forte@Sun.COM } 35747836SJohn.Forte@Sun.COM itl = ent->ent_itl_datap; 35757836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 35767836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 35777836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST); 35787836SJohn.Forte@Sun.COM 35797836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 35807836SJohn.Forte@Sun.COM } 35817836SJohn.Forte@Sun.COM 35827836SJohn.Forte@Sun.COM stmf_status_t 35837836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss, 35847836SJohn.Forte@Sun.COM uint64_t session_id, void **itl_handle_retp) 35857836SJohn.Forte@Sun.COM { 35867836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 35877836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 35887836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 35897836SJohn.Forte@Sun.COM stmf_status_t ret; 35907836SJohn.Forte@Sun.COM int i; 35917836SJohn.Forte@Sun.COM uint16_t n; 35927836SJohn.Forte@Sun.COM 35937836SJohn.Forte@Sun.COM if (ss == NULL) { 35947836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 35957836SJohn.Forte@Sun.COM if (iss == NULL) 35967836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 35977836SJohn.Forte@Sun.COM } else { 35987836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 35997836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 36007836SJohn.Forte@Sun.COM } 36017836SJohn.Forte@Sun.COM 36027836SJohn.Forte@Sun.COM ent = NULL; 36037836SJohn.Forte@Sun.COM if (lun == NULL) { 36047836SJohn.Forte@Sun.COM lm = iss->iss_sm; 36057836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 36067836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 36077836SJohn.Forte@Sun.COM continue; 36087836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 36097836SJohn.Forte@Sun.COM if (ent->ent_lu == lu) 36107836SJohn.Forte@Sun.COM break; 36117836SJohn.Forte@Sun.COM } 36127836SJohn.Forte@Sun.COM } else { 36137836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 36147836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 36158662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 36167836SJohn.Forte@Sun.COM if (lu && (ent->ent_lu != lu)) 36177836SJohn.Forte@Sun.COM ent = NULL; 36187836SJohn.Forte@Sun.COM } 36197836SJohn.Forte@Sun.COM if (ent && ent->ent_itl_datap) { 36207836SJohn.Forte@Sun.COM *itl_handle_retp = ent->ent_itl_datap->itl_handle; 36217836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 36227836SJohn.Forte@Sun.COM } else { 36237836SJohn.Forte@Sun.COM ret = STMF_NOT_FOUND; 36247836SJohn.Forte@Sun.COM } 36257836SJohn.Forte@Sun.COM 36267836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 36277836SJohn.Forte@Sun.COM return (ret); 36287836SJohn.Forte@Sun.COM } 36297836SJohn.Forte@Sun.COM 36307836SJohn.Forte@Sun.COM stmf_data_buf_t * 36317836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 36327836SJohn.Forte@Sun.COM uint32_t flags) 36337836SJohn.Forte@Sun.COM { 36347836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36357836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 36367836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 36377836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 36387836SJohn.Forte@Sun.COM uint8_t ndx; 36397836SJohn.Forte@Sun.COM 36407836SJohn.Forte@Sun.COM ndx = stmf_first_zero[itask->itask_allocated_buf_map]; 36417836SJohn.Forte@Sun.COM if (ndx == 0xff) 36427836SJohn.Forte@Sun.COM return (NULL); 36437836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf( 36447836SJohn.Forte@Sun.COM task, size, pminsize, flags); 36457836SJohn.Forte@Sun.COM if (dbuf) { 36467836SJohn.Forte@Sun.COM task->task_cur_nbufs++; 36477836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map |= (1 << ndx); 36487836SJohn.Forte@Sun.COM dbuf->db_handle = ndx; 36497836SJohn.Forte@Sun.COM return (dbuf); 36507836SJohn.Forte@Sun.COM } 36517836SJohn.Forte@Sun.COM 36527836SJohn.Forte@Sun.COM return (NULL); 36537836SJohn.Forte@Sun.COM } 36547836SJohn.Forte@Sun.COM 36557836SJohn.Forte@Sun.COM void 36567836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf) 36577836SJohn.Forte@Sun.COM { 36587836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36597836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 36607836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 36617836SJohn.Forte@Sun.COM 36627836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle); 36637836SJohn.Forte@Sun.COM task->task_cur_nbufs--; 36647836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf); 36657836SJohn.Forte@Sun.COM } 36667836SJohn.Forte@Sun.COM 36677836SJohn.Forte@Sun.COM stmf_data_buf_t * 36687836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h) 36697836SJohn.Forte@Sun.COM { 36707836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 36717836SJohn.Forte@Sun.COM 36727836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 36737836SJohn.Forte@Sun.COM if (h > 3) 36747836SJohn.Forte@Sun.COM return (NULL); 36757836SJohn.Forte@Sun.COM return (itask->itask_dbufs[h]); 36767836SJohn.Forte@Sun.COM } 36777836SJohn.Forte@Sun.COM 36787836SJohn.Forte@Sun.COM /* ARGSUSED */ 36797836SJohn.Forte@Sun.COM struct scsi_task * 36807836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss, 36817836SJohn.Forte@Sun.COM uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id) 36827836SJohn.Forte@Sun.COM { 36837836SJohn.Forte@Sun.COM stmf_lu_t *lu; 36847836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 36857836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 36867836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 36877836SJohn.Forte@Sun.COM stmf_i_scsi_task_t **ppitask; 36887836SJohn.Forte@Sun.COM scsi_task_t *task; 36897836SJohn.Forte@Sun.COM uint64_t *p; 36907836SJohn.Forte@Sun.COM uint8_t *l; 36917836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 36927836SJohn.Forte@Sun.COM uint16_t cdb_length; 36937836SJohn.Forte@Sun.COM uint16_t luNbr; 36947836SJohn.Forte@Sun.COM uint8_t new_task = 0; 36957836SJohn.Forte@Sun.COM 36967836SJohn.Forte@Sun.COM /* 36977836SJohn.Forte@Sun.COM * We allocate 7 extra bytes for CDB to provide a cdb pointer which 36987836SJohn.Forte@Sun.COM * is guaranteed to be 8 byte aligned. Some LU providers like OSD 36997836SJohn.Forte@Sun.COM * depend upon this alignment. 37007836SJohn.Forte@Sun.COM */ 37017836SJohn.Forte@Sun.COM if (cdb_length_in >= 16) 37027836SJohn.Forte@Sun.COM cdb_length = cdb_length_in + 7; 37037836SJohn.Forte@Sun.COM else 37047836SJohn.Forte@Sun.COM cdb_length = 16 + 7; 37057836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 37067836SJohn.Forte@Sun.COM luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 37077836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 37087836SJohn.Forte@Sun.COM lun_map_ent = 37097836SJohn.Forte@Sun.COM (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr); 37107836SJohn.Forte@Sun.COM if (!lun_map_ent) { 37117836SJohn.Forte@Sun.COM lu = dlun0; 37127836SJohn.Forte@Sun.COM } else { 37137836SJohn.Forte@Sun.COM lu = lun_map_ent->ent_lu; 37147836SJohn.Forte@Sun.COM } 37157836SJohn.Forte@Sun.COM ilu = lu->lu_stmf_private; 37167836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 37177836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 37187836SJohn.Forte@Sun.COM return (NULL); 37197836SJohn.Forte@Sun.COM } 37207836SJohn.Forte@Sun.COM do { 37217836SJohn.Forte@Sun.COM if (ilu->ilu_free_tasks == NULL) { 37227836SJohn.Forte@Sun.COM new_task = 1; 37237836SJohn.Forte@Sun.COM break; 37247836SJohn.Forte@Sun.COM } 37257836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 37267836SJohn.Forte@Sun.COM for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) && 37277836SJohn.Forte@Sun.COM ((*ppitask)->itask_cdb_buf_size < cdb_length); 37288662SJordan.Vaughan@Sun.com ppitask = &((*ppitask)->itask_lu_free_next)) 37298662SJordan.Vaughan@Sun.com ; 37307836SJohn.Forte@Sun.COM if (*ppitask) { 37317836SJohn.Forte@Sun.COM itask = *ppitask; 37327836SJohn.Forte@Sun.COM *ppitask = (*ppitask)->itask_lu_free_next; 37337836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 37347836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free) 37357836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 37367836SJohn.Forte@Sun.COM } else { 37377836SJohn.Forte@Sun.COM new_task = 1; 37387836SJohn.Forte@Sun.COM } 37397836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 37407836SJohn.Forte@Sun.COM /* CONSTCOND */ 37417836SJohn.Forte@Sun.COM } while (0); 37427836SJohn.Forte@Sun.COM 37437836SJohn.Forte@Sun.COM if (!new_task) { 37447836SJohn.Forte@Sun.COM task = itask->itask_task; 37457836SJohn.Forte@Sun.COM task->task_timeout = 0; 37467836SJohn.Forte@Sun.COM p = (uint64_t *)&task->task_flags; 37477836SJohn.Forte@Sun.COM *p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0; 37487836SJohn.Forte@Sun.COM itask->itask_ncmds = 0; 37497836SJohn.Forte@Sun.COM } else { 37507836SJohn.Forte@Sun.COM task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK, 37517836SJohn.Forte@Sun.COM cdb_length, AF_FORCE_NOSLEEP); 37527836SJohn.Forte@Sun.COM if (task == NULL) { 37537836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 37547836SJohn.Forte@Sun.COM return (NULL); 37557836SJohn.Forte@Sun.COM } 37567836SJohn.Forte@Sun.COM task->task_lu = lu; 37577836SJohn.Forte@Sun.COM l = task->task_lun_no; 37587836SJohn.Forte@Sun.COM l[0] = lun[0]; 37597836SJohn.Forte@Sun.COM l[1] = lun[1]; 37607836SJohn.Forte@Sun.COM l[2] = lun[2]; 37617836SJohn.Forte@Sun.COM l[3] = lun[3]; 37627836SJohn.Forte@Sun.COM l[4] = lun[4]; 37637836SJohn.Forte@Sun.COM l[5] = lun[5]; 37647836SJohn.Forte@Sun.COM l[6] = lun[6]; 37657836SJohn.Forte@Sun.COM l[7] = lun[7]; 37667836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)task->task_port_private; 37677836SJohn.Forte@Sun.COM if ((ulong_t)(task->task_cdb) & 7ul) { 37687836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)(((ulong_t) 37697836SJohn.Forte@Sun.COM (task->task_cdb) + 7ul) & ~(7ul)); 37707836SJohn.Forte@Sun.COM } 37717836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 37727836SJohn.Forte@Sun.COM itask->itask_cdb_buf_size = cdb_length; 37737836SJohn.Forte@Sun.COM } 37747836SJohn.Forte@Sun.COM task->task_session = ss; 37757836SJohn.Forte@Sun.COM task->task_lport = lport; 37767836SJohn.Forte@Sun.COM task->task_cdb_length = cdb_length_in; 37777836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_TRANSITION; 37787836SJohn.Forte@Sun.COM 37797836SJohn.Forte@Sun.COM if (new_task) { 37807836SJohn.Forte@Sun.COM if (lu->lu_task_alloc(task) != STMF_SUCCESS) { 37817836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 37827836SJohn.Forte@Sun.COM stmf_free(task); 37837836SJohn.Forte@Sun.COM return (NULL); 37847836SJohn.Forte@Sun.COM } 37857836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 37867836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 37877836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 37887836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 37897836SJohn.Forte@Sun.COM stmf_free(task); 37907836SJohn.Forte@Sun.COM return (NULL); 37917836SJohn.Forte@Sun.COM } 37927836SJohn.Forte@Sun.COM itask->itask_lu_next = ilu->ilu_tasks; 37937836SJohn.Forte@Sun.COM if (ilu->ilu_tasks) 37947836SJohn.Forte@Sun.COM ilu->ilu_tasks->itask_lu_prev = itask; 37957836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask; 37967836SJohn.Forte@Sun.COM /* kmem_zalloc automatically makes itask->itask_lu_prev NULL */ 37977836SJohn.Forte@Sun.COM ilu->ilu_ntasks++; 37987836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 37997836SJohn.Forte@Sun.COM } 38007836SJohn.Forte@Sun.COM 38017836SJohn.Forte@Sun.COM itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr; 38027836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, 1); 38037836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 38047836SJohn.Forte@Sun.COM 38057836SJohn.Forte@Sun.COM if ((lun_map_ent != NULL) && ((itask->itask_itl_datap = 38067836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap) != NULL)) { 38077836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_itl_datap->itl_counter, 1); 38087836SJohn.Forte@Sun.COM task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle; 38097836SJohn.Forte@Sun.COM } else { 38107836SJohn.Forte@Sun.COM itask->itask_itl_datap = NULL; 38117836SJohn.Forte@Sun.COM task->task_lu_itl_handle = NULL; 38127836SJohn.Forte@Sun.COM } 38137836SJohn.Forte@Sun.COM 38147836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 38157836SJohn.Forte@Sun.COM return (task); 38167836SJohn.Forte@Sun.COM } 38177836SJohn.Forte@Sun.COM 381810725SJohn.Forte@Sun.COM static void 381910725SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task, stmf_i_scsi_session_t *iss) 38207836SJohn.Forte@Sun.COM { 38217836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 38227836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 38237836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 38247836SJohn.Forte@Sun.COM 382510725SJohn.Forte@Sun.COM ASSERT(rw_lock_held(iss->iss_lockp)); 38267836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_FREE_LIST; 38277836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 38287836SJohn.Forte@Sun.COM itask->itask_lu_free_next = ilu->ilu_free_tasks; 38297836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask; 38307836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free++; 38317836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 38327836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, -1); 38337836SJohn.Forte@Sun.COM } 38347836SJohn.Forte@Sun.COM 38357836SJohn.Forte@Sun.COM void 38367836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu) 38377836SJohn.Forte@Sun.COM { 38387836SJohn.Forte@Sun.COM uint32_t num_to_release, ndx; 38397836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 38407836SJohn.Forte@Sun.COM stmf_lu_t *lu = ilu->ilu_lu; 38417836SJohn.Forte@Sun.COM 38427836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free); 38437836SJohn.Forte@Sun.COM 38447836SJohn.Forte@Sun.COM /* free half of the minimal free of the free tasks */ 38457836SJohn.Forte@Sun.COM num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2; 38467836SJohn.Forte@Sun.COM if (!num_to_release) { 38477836SJohn.Forte@Sun.COM return; 38487836SJohn.Forte@Sun.COM } 38497836SJohn.Forte@Sun.COM for (ndx = 0; ndx < num_to_release; ndx++) { 38507836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 38517836SJohn.Forte@Sun.COM itask = ilu->ilu_free_tasks; 38527836SJohn.Forte@Sun.COM if (itask == NULL) { 38537836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 38547836SJohn.Forte@Sun.COM break; 38557836SJohn.Forte@Sun.COM } 38567836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask->itask_lu_free_next; 38577836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 38587836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 38597836SJohn.Forte@Sun.COM 38607836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 38617836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 38627836SJohn.Forte@Sun.COM if (itask->itask_lu_next) 38637836SJohn.Forte@Sun.COM itask->itask_lu_next->itask_lu_prev = 38647836SJohn.Forte@Sun.COM itask->itask_lu_prev; 38657836SJohn.Forte@Sun.COM if (itask->itask_lu_prev) 38667836SJohn.Forte@Sun.COM itask->itask_lu_prev->itask_lu_next = 38677836SJohn.Forte@Sun.COM itask->itask_lu_next; 38687836SJohn.Forte@Sun.COM else 38697836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask->itask_lu_next; 38707836SJohn.Forte@Sun.COM 38717836SJohn.Forte@Sun.COM ilu->ilu_ntasks--; 38727836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 38737836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 38747836SJohn.Forte@Sun.COM } 38757836SJohn.Forte@Sun.COM } 38767836SJohn.Forte@Sun.COM 38777836SJohn.Forte@Sun.COM /* 38787836SJohn.Forte@Sun.COM * Called with stmf_lock held 38797836SJohn.Forte@Sun.COM */ 38807836SJohn.Forte@Sun.COM void 38817836SJohn.Forte@Sun.COM stmf_check_freetask() 38827836SJohn.Forte@Sun.COM { 38837836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 38847836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 38857836SJohn.Forte@Sun.COM 38867836SJohn.Forte@Sun.COM /* stmf_svc_ilu_draining may get changed after stmf_lock is released */ 38877836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) { 38887836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 38897836SJohn.Forte@Sun.COM if (!ilu->ilu_ntasks_min_free) { 38907836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 38917836SJohn.Forte@Sun.COM continue; 38927836SJohn.Forte@Sun.COM } 38937836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 38947836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 38957836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(ilu); 38967836SJohn.Forte@Sun.COM /* 38977836SJohn.Forte@Sun.COM * we do not care about the accuracy of 38987836SJohn.Forte@Sun.COM * ilu_ntasks_min_free, so we don't lock here 38997836SJohn.Forte@Sun.COM */ 39007836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 39017836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 39027836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 39037836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 39047836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 39057836SJohn.Forte@Sun.COM break; 39067836SJohn.Forte@Sun.COM } 39077836SJohn.Forte@Sun.COM } 39087836SJohn.Forte@Sun.COM 39097836SJohn.Forte@Sun.COM void 39107836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu) 39117836SJohn.Forte@Sun.COM { 39127836SJohn.Forte@Sun.COM clock_t l = ddi_get_lbolt(); 39137836SJohn.Forte@Sun.COM clock_t ps = drv_usectohz(1000000); 39147836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 39157836SJohn.Forte@Sun.COM scsi_task_t *task; 39167836SJohn.Forte@Sun.COM uint32_t to; 39177836SJohn.Forte@Sun.COM 39187836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 39197836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 39207836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 39217836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_IN_FREE_LIST | 39227836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) { 39237836SJohn.Forte@Sun.COM continue; 39247836SJohn.Forte@Sun.COM } 39257836SJohn.Forte@Sun.COM task = itask->itask_task; 39267836SJohn.Forte@Sun.COM if (task->task_timeout == 0) 39277836SJohn.Forte@Sun.COM to = stmf_default_task_timeout; 39287836SJohn.Forte@Sun.COM else 39297836SJohn.Forte@Sun.COM to = task->task_timeout; 39307836SJohn.Forte@Sun.COM if ((itask->itask_start_time + (to * ps)) > l) 39317836SJohn.Forte@Sun.COM continue; 39327836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 39337836SJohn.Forte@Sun.COM STMF_TIMEOUT, NULL); 39347836SJohn.Forte@Sun.COM } 39357836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 39367836SJohn.Forte@Sun.COM } 39377836SJohn.Forte@Sun.COM 39387836SJohn.Forte@Sun.COM /* 39397836SJohn.Forte@Sun.COM * Called with stmf_lock held 39407836SJohn.Forte@Sun.COM */ 39417836SJohn.Forte@Sun.COM void 39427836SJohn.Forte@Sun.COM stmf_check_ilu_timing() 39437836SJohn.Forte@Sun.COM { 39447836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 39457836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 39467836SJohn.Forte@Sun.COM 39477836SJohn.Forte@Sun.COM /* stmf_svc_ilu_timing may get changed after stmf_lock is released */ 39487836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) { 39497836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 39507836SJohn.Forte@Sun.COM if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) { 39517836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr2 == 0) { 39527836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2; 39537836SJohn.Forte@Sun.COM continue; 39547836SJohn.Forte@Sun.COM } 39557836SJohn.Forte@Sun.COM } else { 39567836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr1 == 0) { 39577836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 39587836SJohn.Forte@Sun.COM continue; 39597836SJohn.Forte@Sun.COM } 39607836SJohn.Forte@Sun.COM } 39617836SJohn.Forte@Sun.COM /* 39627836SJohn.Forte@Sun.COM * If we are here then it means that there is some slowdown 39637836SJohn.Forte@Sun.COM * in tasks on this lu. We need to check. 39647836SJohn.Forte@Sun.COM */ 39657836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 39667836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 39677836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(ilu); 39687836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 39697836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 39707836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 39717836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 39727836SJohn.Forte@Sun.COM break; 39737836SJohn.Forte@Sun.COM } 39747836SJohn.Forte@Sun.COM } 39757836SJohn.Forte@Sun.COM 39767836SJohn.Forte@Sun.COM /* 39777836SJohn.Forte@Sun.COM * Kills all tasks on a lu except tm_task 39787836SJohn.Forte@Sun.COM */ 39797836SJohn.Forte@Sun.COM void 39807836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s) 39817836SJohn.Forte@Sun.COM { 39827836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 39837836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 39847836SJohn.Forte@Sun.COM 39857836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 39867836SJohn.Forte@Sun.COM 39877836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 39887836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 39897836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_FREE_LIST) 39907836SJohn.Forte@Sun.COM continue; 39917836SJohn.Forte@Sun.COM if (itask->itask_task == tm_task) 39927836SJohn.Forte@Sun.COM continue; 39937836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL); 39947836SJohn.Forte@Sun.COM } 39957836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 39967836SJohn.Forte@Sun.COM } 39977836SJohn.Forte@Sun.COM 39987836SJohn.Forte@Sun.COM void 39997836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport) 40007836SJohn.Forte@Sun.COM { 40017836SJohn.Forte@Sun.COM int i; 40027836SJohn.Forte@Sun.COM uint8_t map; 40037836SJohn.Forte@Sun.COM 40047836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 40057836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 40067836SJohn.Forte@Sun.COM if (map & 1) { 40077836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 40087836SJohn.Forte@Sun.COM 40097836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 40107836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 40117836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 40127836SJohn.Forte@Sun.COM } 40137836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf( 40147836SJohn.Forte@Sun.COM lport->lport_ds, dbuf); 40157836SJohn.Forte@Sun.COM } 40167836SJohn.Forte@Sun.COM map >>= 1; 40177836SJohn.Forte@Sun.COM } 40187836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 40197836SJohn.Forte@Sun.COM } 40207836SJohn.Forte@Sun.COM } 40217836SJohn.Forte@Sun.COM 40227836SJohn.Forte@Sun.COM void 40237836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task) 40247836SJohn.Forte@Sun.COM { 40257836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 40267836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 40278662SJordan.Vaughan@Sun.com task->task_stmf_private; 402810725SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 402910725SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 40307836SJohn.Forte@Sun.COM 40318859STim.Szeto@Sun.COM DTRACE_PROBE1(stmf__task__end, scsi_task_t *, task); 40327836SJohn.Forte@Sun.COM stmf_free_task_bufs(itask, lport); 40337836SJohn.Forte@Sun.COM if (itask->itask_itl_datap) { 40347836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter, 40357836SJohn.Forte@Sun.COM -1) == 0) { 40367836SJohn.Forte@Sun.COM stmf_release_itl_handle(task->task_lu, 40378662SJordan.Vaughan@Sun.com itask->itask_itl_datap); 40387836SJohn.Forte@Sun.COM } 40397836SJohn.Forte@Sun.COM } 404010725SJohn.Forte@Sun.COM 404110725SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 40427836SJohn.Forte@Sun.COM lport->lport_task_free(task); 40437836SJohn.Forte@Sun.COM if (itask->itask_worker) { 40447836SJohn.Forte@Sun.COM atomic_add_32(&stmf_cur_ntasks, -1); 40457836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_worker->worker_ref_count, -1); 40467836SJohn.Forte@Sun.COM } 40477836SJohn.Forte@Sun.COM /* 40487836SJohn.Forte@Sun.COM * After calling stmf_task_lu_free, the task pointer can no longer 40497836SJohn.Forte@Sun.COM * be trusted. 40507836SJohn.Forte@Sun.COM */ 405110725SJohn.Forte@Sun.COM stmf_task_lu_free(task, iss); 405210725SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 40537836SJohn.Forte@Sun.COM } 40547836SJohn.Forte@Sun.COM 40557836SJohn.Forte@Sun.COM void 40567836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 40577836SJohn.Forte@Sun.COM { 40587836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 40597836SJohn.Forte@Sun.COM task->task_stmf_private; 40607836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 40617836SJohn.Forte@Sun.COM int nv; 40627836SJohn.Forte@Sun.COM uint32_t old, new; 40637836SJohn.Forte@Sun.COM uint32_t ct; 40647836SJohn.Forte@Sun.COM stmf_worker_t *w, *w1; 40657836SJohn.Forte@Sun.COM uint8_t tm; 40667836SJohn.Forte@Sun.COM 40677836SJohn.Forte@Sun.COM if (task->task_max_nbufs > 4) 40687836SJohn.Forte@Sun.COM task->task_max_nbufs = 4; 40697836SJohn.Forte@Sun.COM task->task_cur_nbufs = 0; 40707836SJohn.Forte@Sun.COM /* Latest value of currently running tasks */ 40717836SJohn.Forte@Sun.COM ct = atomic_add_32_nv(&stmf_cur_ntasks, 1); 40727836SJohn.Forte@Sun.COM 40737836SJohn.Forte@Sun.COM /* Select the next worker using round robin */ 40747836SJohn.Forte@Sun.COM nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1); 40757836SJohn.Forte@Sun.COM if (nv >= stmf_nworkers_accepting_cmds) { 40767836SJohn.Forte@Sun.COM int s = nv; 40777836SJohn.Forte@Sun.COM do { 40787836SJohn.Forte@Sun.COM nv -= stmf_nworkers_accepting_cmds; 40797836SJohn.Forte@Sun.COM } while (nv >= stmf_nworkers_accepting_cmds); 40807836SJohn.Forte@Sun.COM if (nv < 0) 40817836SJohn.Forte@Sun.COM nv = 0; 40827836SJohn.Forte@Sun.COM /* Its ok if this cas fails */ 40837836SJohn.Forte@Sun.COM (void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter, 40847836SJohn.Forte@Sun.COM s, nv); 40857836SJohn.Forte@Sun.COM } 40867836SJohn.Forte@Sun.COM w = &stmf_workers[nv]; 40877836SJohn.Forte@Sun.COM 40887836SJohn.Forte@Sun.COM /* 40897836SJohn.Forte@Sun.COM * A worker can be pinned by interrupt. So select the next one 40907836SJohn.Forte@Sun.COM * if it has lower load. 40917836SJohn.Forte@Sun.COM */ 40927836SJohn.Forte@Sun.COM if ((nv + 1) >= stmf_nworkers_accepting_cmds) { 40937836SJohn.Forte@Sun.COM w1 = stmf_workers; 40947836SJohn.Forte@Sun.COM } else { 40957836SJohn.Forte@Sun.COM w1 = &stmf_workers[nv + 1]; 40967836SJohn.Forte@Sun.COM } 40977836SJohn.Forte@Sun.COM if (w1->worker_queue_depth < w->worker_queue_depth) 40987836SJohn.Forte@Sun.COM w = w1; 40999435STim.Szeto@Sun.COM 41007836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 41017836SJohn.Forte@Sun.COM if (((w->worker_flags & STMF_WORKER_STARTED) == 0) || 41027836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 41037836SJohn.Forte@Sun.COM /* 41047836SJohn.Forte@Sun.COM * Maybe we are in the middle of a change. Just go to 41057836SJohn.Forte@Sun.COM * the 1st worker. 41067836SJohn.Forte@Sun.COM */ 41077836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 41087836SJohn.Forte@Sun.COM w = stmf_workers; 41097836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 41107836SJohn.Forte@Sun.COM } 41117836SJohn.Forte@Sun.COM itask->itask_worker = w; 41127836SJohn.Forte@Sun.COM /* 41137836SJohn.Forte@Sun.COM * Track max system load inside the worker as we already have the 41147836SJohn.Forte@Sun.COM * worker lock (no point implementing another lock). The service 41157836SJohn.Forte@Sun.COM * thread will do the comparisons and figure out the max overall 41167836SJohn.Forte@Sun.COM * system load. 41177836SJohn.Forte@Sun.COM */ 41187836SJohn.Forte@Sun.COM if (w->worker_max_sys_qdepth_pu < ct) 41197836SJohn.Forte@Sun.COM w->worker_max_sys_qdepth_pu = ct; 41207836SJohn.Forte@Sun.COM 41217836SJohn.Forte@Sun.COM do { 41227836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 41237836SJohn.Forte@Sun.COM new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE; 41247836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 41257836SJohn.Forte@Sun.COM tm = task->task_mgmt_function; 41267836SJohn.Forte@Sun.COM if ((tm == TM_TARGET_RESET) || 41277836SJohn.Forte@Sun.COM (tm == TM_TARGET_COLD_RESET) || 41287836SJohn.Forte@Sun.COM (tm == TM_TARGET_WARM_RESET)) { 41297836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 41307836SJohn.Forte@Sun.COM } 41317836SJohn.Forte@Sun.COM } else if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 41327836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 41337836SJohn.Forte@Sun.COM } 41347836SJohn.Forte@Sun.COM new &= ~ITASK_IN_TRANSITION; 41357836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 41367836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 41377836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 41387836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 41397836SJohn.Forte@Sun.COM } else { 41407836SJohn.Forte@Sun.COM w->worker_task_head = itask; 41417836SJohn.Forte@Sun.COM } 41427836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 41437836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 41447836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 41457836SJohn.Forte@Sun.COM } 41467836SJohn.Forte@Sun.COM atomic_add_32(&w->worker_ref_count, 1); 41477836SJohn.Forte@Sun.COM itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK; 41487836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 41497836SJohn.Forte@Sun.COM if (dbuf) { 41507836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 1; 41517836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = dbuf; 41527836SJohn.Forte@Sun.COM dbuf->db_handle = 0; 41537836SJohn.Forte@Sun.COM } else { 41547836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 41557836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = NULL; 41567836SJohn.Forte@Sun.COM } 41579435STim.Szeto@Sun.COM 41589435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_enter); 41599435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_enter); 41609435STim.Szeto@Sun.COM 41617836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 41627836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 41637836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 41647836SJohn.Forte@Sun.COM 41657836SJohn.Forte@Sun.COM /* 41667836SJohn.Forte@Sun.COM * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE 41677836SJohn.Forte@Sun.COM * was set between checking of ILU_RESET_ACTIVE and clearing of the 41687836SJohn.Forte@Sun.COM * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here. 41697836SJohn.Forte@Sun.COM */ 41707836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 41717836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL); 41727836SJohn.Forte@Sun.COM } 41737836SJohn.Forte@Sun.COM } 41747836SJohn.Forte@Sun.COM 41757836SJohn.Forte@Sun.COM /* 41767836SJohn.Forte@Sun.COM * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++ 41777836SJohn.Forte@Sun.COM * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already 41787836SJohn.Forte@Sun.COM * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot 41797836SJohn.Forte@Sun.COM * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course 41807836SJohn.Forte@Sun.COM * the LU will make this call only if we call the LU's abort entry point. 41817836SJohn.Forte@Sun.COM * we will only call that entry point if ITASK_KNOWN_TO_LU was set. 41827836SJohn.Forte@Sun.COM * 41837836SJohn.Forte@Sun.COM * Same logic applies for the port. 41847836SJohn.Forte@Sun.COM * 41857836SJohn.Forte@Sun.COM * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU 41867836SJohn.Forte@Sun.COM * and KNOWN_TO_TGT_PORT are reset. 41877836SJohn.Forte@Sun.COM * 41887836SJohn.Forte@Sun.COM * +++++++++++++++++++++++++++++++++++++++++++++++ 41897836SJohn.Forte@Sun.COM */ 41907836SJohn.Forte@Sun.COM 41917836SJohn.Forte@Sun.COM stmf_status_t 41927836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) 41937836SJohn.Forte@Sun.COM { 41948859STim.Szeto@Sun.COM stmf_status_t ret; 41958859STim.Szeto@Sun.COM 41967836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 41977836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 41987836SJohn.Forte@Sun.COM 41997836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 42007836SJohn.Forte@Sun.COM uint32_t new, old; 42017836SJohn.Forte@Sun.COM do { 42027836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 42037836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 42047836SJohn.Forte@Sun.COM return (STMF_ABORTED); 42057836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 42067836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 42077836SJohn.Forte@Sun.COM } 42087836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 42097836SJohn.Forte@Sun.COM return (STMF_ABORTED); 42107836SJohn.Forte@Sun.COM #ifdef DEBUG 42117836SJohn.Forte@Sun.COM if (stmf_drop_buf_counter > 0) { 42128662SJordan.Vaughan@Sun.com if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) == 42138662SJordan.Vaughan@Sun.com 1) 42147836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 42157836SJohn.Forte@Sun.COM } 42167836SJohn.Forte@Sun.COM #endif 42179435STim.Szeto@Sun.COM 42189435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(task, dbuf); 42199435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(task, dbuf); 42209435STim.Szeto@Sun.COM 42218859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, task, 42228859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 42238859STim.Szeto@Sun.COM ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags); 42248859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__end, scsi_task_t *, task, 42258859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 42268859STim.Szeto@Sun.COM return (ret); 42277836SJohn.Forte@Sun.COM } 42287836SJohn.Forte@Sun.COM 42297836SJohn.Forte@Sun.COM void 42307836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof) 42317836SJohn.Forte@Sun.COM { 42327836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 42337836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 42347836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 42357836SJohn.Forte@Sun.COM uint32_t new, old; 423610421STim.Szeto@Sun.COM uint8_t update_queue_flags, free_it, queue_it, kstat_it; 42377836SJohn.Forte@Sun.COM 42387836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 42397836SJohn.Forte@Sun.COM do { 42407836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 42417836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 42427836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 42437836SJohn.Forte@Sun.COM return; 42447836SJohn.Forte@Sun.COM } 42457836SJohn.Forte@Sun.COM free_it = 0; 424610421STim.Szeto@Sun.COM kstat_it = 0; 42477836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 42487836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 42497836SJohn.Forte@Sun.COM task->task_completion_status = dbuf->db_xfer_status; 42507836SJohn.Forte@Sun.COM free_it = 1; 425110421STim.Szeto@Sun.COM kstat_it = 1; 42527836SJohn.Forte@Sun.COM } 42537836SJohn.Forte@Sun.COM /* 42547836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 42557836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 42567836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 42577836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 42587836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 42597836SJohn.Forte@Sun.COM * free this task. 42607836SJohn.Forte@Sun.COM */ 42617836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 42627836SJohn.Forte@Sun.COM free_it = 0; 42637836SJohn.Forte@Sun.COM update_queue_flags = 1; 42647836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 42657836SJohn.Forte@Sun.COM queue_it = 0; 42667836SJohn.Forte@Sun.COM } else { 42677836SJohn.Forte@Sun.COM queue_it = 1; 42687836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 42697836SJohn.Forte@Sun.COM } 42707836SJohn.Forte@Sun.COM } else { 42717836SJohn.Forte@Sun.COM update_queue_flags = 0; 42727836SJohn.Forte@Sun.COM queue_it = 0; 42737836SJohn.Forte@Sun.COM } 42747836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 42757836SJohn.Forte@Sun.COM 427610421STim.Szeto@Sun.COM if (kstat_it) { 427710421STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 427810421STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 427910421STim.Szeto@Sun.COM } 42807836SJohn.Forte@Sun.COM if (update_queue_flags) { 42817836SJohn.Forte@Sun.COM uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE; 42827836SJohn.Forte@Sun.COM 42837836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 42847836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = cmd; 42857836SJohn.Forte@Sun.COM if (queue_it) { 42867836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 42877836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 42887836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 42897836SJohn.Forte@Sun.COM } else { 42907836SJohn.Forte@Sun.COM w->worker_task_head = itask; 42917836SJohn.Forte@Sun.COM } 42927836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 42937836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > 42947836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu) { 42957836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 42967836SJohn.Forte@Sun.COM } 42977836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 42987836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 42997836SJohn.Forte@Sun.COM } 43007836SJohn.Forte@Sun.COM } 43017836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 43027836SJohn.Forte@Sun.COM 43037836SJohn.Forte@Sun.COM if (free_it) { 43047836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 43057836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 43067836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 43077836SJohn.Forte@Sun.COM stmf_task_free(task); 43087836SJohn.Forte@Sun.COM } 43097836SJohn.Forte@Sun.COM } 43107836SJohn.Forte@Sun.COM } 43117836SJohn.Forte@Sun.COM 43127836SJohn.Forte@Sun.COM stmf_status_t 43137836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 43147836SJohn.Forte@Sun.COM { 43158859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task); 43168859STim.Szeto@Sun.COM 43177836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 43188662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 43197836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 43207836SJohn.Forte@Sun.COM uint32_t new, old; 43217836SJohn.Forte@Sun.COM do { 43227836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 43237836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 43247836SJohn.Forte@Sun.COM return (STMF_ABORTED); 43257836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 43267836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 43277836SJohn.Forte@Sun.COM } 43287836SJohn.Forte@Sun.COM 43297836SJohn.Forte@Sun.COM if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) { 43307836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 43317836SJohn.Forte@Sun.COM } 43327836SJohn.Forte@Sun.COM 43337836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 43347836SJohn.Forte@Sun.COM return (STMF_ABORTED); 43357836SJohn.Forte@Sun.COM 43367836SJohn.Forte@Sun.COM if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) { 43377836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 43387836SJohn.Forte@Sun.COM task->task_resid = 0; 43397836SJohn.Forte@Sun.COM } else if (task->task_cmd_xfer_length > 43407836SJohn.Forte@Sun.COM task->task_expected_xfer_length) { 43417836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_OVER; 43427836SJohn.Forte@Sun.COM task->task_resid = task->task_cmd_xfer_length - 43438662SJordan.Vaughan@Sun.com task->task_expected_xfer_length; 43447836SJohn.Forte@Sun.COM } else if (task->task_nbytes_transferred < 43458662SJordan.Vaughan@Sun.com task->task_expected_xfer_length) { 43467836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_UNDER; 43477836SJohn.Forte@Sun.COM task->task_resid = task->task_expected_xfer_length - 43488662SJordan.Vaughan@Sun.com task->task_nbytes_transferred; 43497836SJohn.Forte@Sun.COM } else { 43507836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 43517836SJohn.Forte@Sun.COM task->task_resid = 0; 43527836SJohn.Forte@Sun.COM } 43537836SJohn.Forte@Sun.COM return (task->task_lport->lport_send_status(task, ioflags)); 43547836SJohn.Forte@Sun.COM } 43557836SJohn.Forte@Sun.COM 43567836SJohn.Forte@Sun.COM void 43577836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof) 43587836SJohn.Forte@Sun.COM { 43597836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 43607836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 43617836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 43627836SJohn.Forte@Sun.COM uint32_t new, old; 436310421STim.Szeto@Sun.COM uint8_t free_it, queue_it, kstat_it; 43647836SJohn.Forte@Sun.COM 43657836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 43667836SJohn.Forte@Sun.COM do { 43677836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 43687836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 43697836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 43707836SJohn.Forte@Sun.COM return; 43717836SJohn.Forte@Sun.COM } 43727836SJohn.Forte@Sun.COM free_it = 0; 437310421STim.Szeto@Sun.COM kstat_it = 0; 43747836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 43757836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 43767836SJohn.Forte@Sun.COM free_it = 1; 437710421STim.Szeto@Sun.COM kstat_it = 1; 43787836SJohn.Forte@Sun.COM } 43797836SJohn.Forte@Sun.COM /* 43807836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 43817836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 43827836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 43837836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 43847836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 43857836SJohn.Forte@Sun.COM * free this task. 43867836SJohn.Forte@Sun.COM */ 43877836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 43887836SJohn.Forte@Sun.COM free_it = 0; 43897836SJohn.Forte@Sun.COM queue_it = 1; 43907836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 43917836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "status completion received" 43927836SJohn.Forte@Sun.COM " when task is already in worker queue " 43937836SJohn.Forte@Sun.COM " task = %p", (void *)task); 43947836SJohn.Forte@Sun.COM } 43957836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 43967836SJohn.Forte@Sun.COM } else { 43977836SJohn.Forte@Sun.COM queue_it = 0; 43987836SJohn.Forte@Sun.COM } 43997836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 44007836SJohn.Forte@Sun.COM task->task_completion_status = s; 44017836SJohn.Forte@Sun.COM 440210421STim.Szeto@Sun.COM if (kstat_it) { 440310421STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 440410421STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 440510421STim.Szeto@Sun.COM } 44069435STim.Szeto@Sun.COM 44077836SJohn.Forte@Sun.COM if (queue_it) { 44087836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 44097836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = 44107836SJohn.Forte@Sun.COM ITASK_CMD_STATUS_DONE; 44117836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 44127836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 44137836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 44147836SJohn.Forte@Sun.COM } else { 44157836SJohn.Forte@Sun.COM w->worker_task_head = itask; 44167836SJohn.Forte@Sun.COM } 44177836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 44187836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 44197836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 44207836SJohn.Forte@Sun.COM } 44217836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 44227836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 44237836SJohn.Forte@Sun.COM } 44247836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 44257836SJohn.Forte@Sun.COM 44267836SJohn.Forte@Sun.COM if (free_it) { 44277836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 44287836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 44297836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 44307836SJohn.Forte@Sun.COM stmf_task_free(task); 44317836SJohn.Forte@Sun.COM } else { 44327836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "LU is done with the task but LPORT " 44337836SJohn.Forte@Sun.COM " is not done, itask %p", (void *)itask); 44347836SJohn.Forte@Sun.COM } 44357836SJohn.Forte@Sun.COM } 44367836SJohn.Forte@Sun.COM } 44377836SJohn.Forte@Sun.COM 44387836SJohn.Forte@Sun.COM void 44397836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task) 44407836SJohn.Forte@Sun.COM { 44417836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 44428662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 44437836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 44447836SJohn.Forte@Sun.COM uint32_t new, old; 44457836SJohn.Forte@Sun.COM 44467836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 44477836SJohn.Forte@Sun.COM do { 44487836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 44497836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 44507836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 44517836SJohn.Forte@Sun.COM return; 44527836SJohn.Forte@Sun.COM } 44537836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 44547836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "task_lu_done received" 44557836SJohn.Forte@Sun.COM " when task is in worker queue " 44567836SJohn.Forte@Sun.COM " task = %p", (void *)task); 44577836SJohn.Forte@Sun.COM } 44587836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 44597836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 44607836SJohn.Forte@Sun.COM 44617836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 44627836SJohn.Forte@Sun.COM 44637836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 44647836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 44657836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 44667836SJohn.Forte@Sun.COM stmf_task_free(task); 44677836SJohn.Forte@Sun.COM } else { 44687836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but " 44697836SJohn.Forte@Sun.COM " the task is still not done, task = %p", (void *)task); 44707836SJohn.Forte@Sun.COM } 44717836SJohn.Forte@Sun.COM } 44727836SJohn.Forte@Sun.COM 44737836SJohn.Forte@Sun.COM void 44747836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s) 44757836SJohn.Forte@Sun.COM { 44767836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 44777836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 44787836SJohn.Forte@Sun.COM stmf_worker_t *w; 44797836SJohn.Forte@Sun.COM uint32_t old, new; 44807836SJohn.Forte@Sun.COM 44817836SJohn.Forte@Sun.COM do { 44827836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 44837836SJohn.Forte@Sun.COM if ((old & ITASK_BEING_ABORTED) || 44847836SJohn.Forte@Sun.COM ((old & (ITASK_KNOWN_TO_TGT_PORT | 44857836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU)) == 0)) { 44867836SJohn.Forte@Sun.COM return; 44877836SJohn.Forte@Sun.COM } 44887836SJohn.Forte@Sun.COM new |= ITASK_BEING_ABORTED; 44897836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 44907836SJohn.Forte@Sun.COM task->task_completion_status = s; 44917836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 44927836SJohn.Forte@Sun.COM 44937836SJohn.Forte@Sun.COM if (((w = itask->itask_worker) == NULL) || 44947836SJohn.Forte@Sun.COM (itask->itask_flags & ITASK_IN_TRANSITION)) { 44957836SJohn.Forte@Sun.COM return; 44967836SJohn.Forte@Sun.COM } 44977836SJohn.Forte@Sun.COM 44987836SJohn.Forte@Sun.COM /* Queue it and get out */ 44997836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 45007836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) { 45017836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 45027836SJohn.Forte@Sun.COM return; 45037836SJohn.Forte@Sun.COM } 45047836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 45057836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 45067836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 45077836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 45087836SJohn.Forte@Sun.COM } else { 45097836SJohn.Forte@Sun.COM w->worker_task_head = itask; 45107836SJohn.Forte@Sun.COM } 45117836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 45127836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 45137836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 45147836SJohn.Forte@Sun.COM } 45157836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 45167836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 45177836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 45187836SJohn.Forte@Sun.COM } 45197836SJohn.Forte@Sun.COM 45207836SJohn.Forte@Sun.COM void 45217836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg) 45227836SJohn.Forte@Sun.COM { 45237836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = NULL; 45247836SJohn.Forte@Sun.COM uint32_t old, new, f, rf; 45257836SJohn.Forte@Sun.COM 45268859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task, 45278859STim.Szeto@Sun.COM stmf_status_t, s); 45288859STim.Szeto@Sun.COM 45297836SJohn.Forte@Sun.COM switch (abort_cmd) { 45307836SJohn.Forte@Sun.COM case STMF_QUEUE_ABORT_LU: 45317836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)arg, task, s); 45327836SJohn.Forte@Sun.COM return; 45337836SJohn.Forte@Sun.COM case STMF_QUEUE_TASK_ABORT: 45347836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(task, s); 45357836SJohn.Forte@Sun.COM return; 45367836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LPORT: 45377836SJohn.Forte@Sun.COM rf = ITASK_TGT_PORT_ABORT_CALLED; 45387836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_TGT_PORT; 45397836SJohn.Forte@Sun.COM break; 45407836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LU: 45417836SJohn.Forte@Sun.COM rf = ITASK_LU_ABORT_CALLED; 45427836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_LU; 45437836SJohn.Forte@Sun.COM break; 45447836SJohn.Forte@Sun.COM default: 45457836SJohn.Forte@Sun.COM return; 45467836SJohn.Forte@Sun.COM } 45477836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 45487836SJohn.Forte@Sun.COM f |= ITASK_BEING_ABORTED | rf; 45497836SJohn.Forte@Sun.COM do { 45507836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 45517836SJohn.Forte@Sun.COM if ((old & f) != f) { 45527836SJohn.Forte@Sun.COM return; 45537836SJohn.Forte@Sun.COM } 45547836SJohn.Forte@Sun.COM new &= ~rf; 45557836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 45567836SJohn.Forte@Sun.COM } 45577836SJohn.Forte@Sun.COM 45587836SJohn.Forte@Sun.COM void 45597836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 45607836SJohn.Forte@Sun.COM { 45617836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 45627836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 45637836SJohn.Forte@Sun.COM unsigned long long st; 45647836SJohn.Forte@Sun.COM 45657836SJohn.Forte@Sun.COM st = s; /* gcc fix */ 45667836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 45677836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 45687836SJohn.Forte@Sun.COM "task %p, lu failed to abort ret=%llx", (void *)task, st); 45697836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LU_DONE) == 0) { 45707836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 45717836SJohn.Forte@Sun.COM "Task aborted but LU is not finished, task =" 45727836SJohn.Forte@Sun.COM "%p, s=%llx, iof=%x", (void *)task, st, iof); 45737836SJohn.Forte@Sun.COM } else { 45747836SJohn.Forte@Sun.COM /* 45757836SJohn.Forte@Sun.COM * LU abort successfully 45767836SJohn.Forte@Sun.COM */ 45777836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU); 45787836SJohn.Forte@Sun.COM return; 45797836SJohn.Forte@Sun.COM } 45807836SJohn.Forte@Sun.COM 45817836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 45827836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 45837836SJohn.Forte@Sun.COM } 45847836SJohn.Forte@Sun.COM 45857836SJohn.Forte@Sun.COM void 45867836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 45877836SJohn.Forte@Sun.COM { 458810421STim.Szeto@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 45897836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 45907836SJohn.Forte@Sun.COM unsigned long long st; 459110421STim.Szeto@Sun.COM uint32_t old, new; 45927836SJohn.Forte@Sun.COM 45937836SJohn.Forte@Sun.COM st = s; 45947836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 45957836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 45967836SJohn.Forte@Sun.COM "task %p, tgt port failed to abort ret=%llx", (void *)task, 45977836SJohn.Forte@Sun.COM st); 45987836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LPORT_DONE) == 0) { 45997836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 46007836SJohn.Forte@Sun.COM "Task aborted but tgt port is not finished, " 46017836SJohn.Forte@Sun.COM "task=%p, s=%llx, iof=%x", (void *)task, st, iof); 46027836SJohn.Forte@Sun.COM } else { 46037836SJohn.Forte@Sun.COM /* 460410421STim.Szeto@Sun.COM * LPORT abort successfully 46057836SJohn.Forte@Sun.COM */ 460610421STim.Szeto@Sun.COM do { 460710421STim.Szeto@Sun.COM old = new = itask->itask_flags; 460810421STim.Szeto@Sun.COM if (!(old & ITASK_KNOWN_TO_TGT_PORT)) 460910421STim.Szeto@Sun.COM return; 461010421STim.Szeto@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 461110421STim.Szeto@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 461210421STim.Szeto@Sun.COM 461310421STim.Szeto@Sun.COM if (!(itask->itask_flags & ITASK_KSTAT_IN_RUNQ)) { 461410421STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_exit); 461510421STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_exit); 461610421STim.Szeto@Sun.COM } else { 461710421STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 461810421STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 461910421STim.Szeto@Sun.COM } 46207836SJohn.Forte@Sun.COM return; 46217836SJohn.Forte@Sun.COM } 46227836SJohn.Forte@Sun.COM 46237836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 46247836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 46257836SJohn.Forte@Sun.COM } 46267836SJohn.Forte@Sun.COM 46277836SJohn.Forte@Sun.COM stmf_status_t 46287836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout) 46297836SJohn.Forte@Sun.COM { 46307836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 46317836SJohn.Forte@Sun.COM task->task_stmf_private; 46327836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 46337836SJohn.Forte@Sun.COM int i; 46347836SJohn.Forte@Sun.COM 46357836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU); 46367836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 46377836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 46387836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 46397836SJohn.Forte@Sun.COM return (STMF_BUSY); 46407836SJohn.Forte@Sun.COM } 46417836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 46427836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) { 46437836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 46447836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 46457836SJohn.Forte@Sun.COM } 46467836SJohn.Forte@Sun.COM } 46477836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU; 46487836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 46497836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 46507836SJohn.Forte@Sun.COM } else { 46517836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 46527836SJohn.Forte@Sun.COM if (t == 0) 46537836SJohn.Forte@Sun.COM t = 1; 46547836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 46557836SJohn.Forte@Sun.COM } 46567836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 46577836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 46587836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 46597836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 46607836SJohn.Forte@Sun.COM } else { 46617836SJohn.Forte@Sun.COM w->worker_task_head = itask; 46627836SJohn.Forte@Sun.COM } 46637836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 46647836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 46657836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 46667836SJohn.Forte@Sun.COM } 46677836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 46687836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 46697836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 46707836SJohn.Forte@Sun.COM } 46717836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 46727836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 46737836SJohn.Forte@Sun.COM } 46747836SJohn.Forte@Sun.COM 46757836SJohn.Forte@Sun.COM stmf_status_t 46767836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout) 46777836SJohn.Forte@Sun.COM { 46787836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 46797836SJohn.Forte@Sun.COM task->task_stmf_private; 46807836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 46817836SJohn.Forte@Sun.COM int i; 46827836SJohn.Forte@Sun.COM 46837836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT); 46847836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 46857836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 46867836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 46877836SJohn.Forte@Sun.COM return (STMF_BUSY); 46887836SJohn.Forte@Sun.COM } 46897836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 46907836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) { 46917836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 46927836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 46937836SJohn.Forte@Sun.COM } 46947836SJohn.Forte@Sun.COM } 46957836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT; 46967836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 46977836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 46987836SJohn.Forte@Sun.COM } else { 46997836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 47007836SJohn.Forte@Sun.COM if (t == 0) 47017836SJohn.Forte@Sun.COM t = 1; 47027836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 47037836SJohn.Forte@Sun.COM } 47047836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 47057836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 47067836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 47077836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 47087836SJohn.Forte@Sun.COM } else { 47097836SJohn.Forte@Sun.COM w->worker_task_head = itask; 47107836SJohn.Forte@Sun.COM } 47117836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 47127836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 47137836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 47147836SJohn.Forte@Sun.COM } 47157836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 47167836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 47177836SJohn.Forte@Sun.COM } 47187836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 47197836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 47207836SJohn.Forte@Sun.COM } 47217836SJohn.Forte@Sun.COM 47227836SJohn.Forte@Sun.COM void 47237836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task) 47247836SJohn.Forte@Sun.COM { 47257836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 47267836SJohn.Forte@Sun.COM stmf_lu_t *lu; 47277836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 47287836SJohn.Forte@Sun.COM unsigned long long ret; 47297836SJohn.Forte@Sun.COM uint32_t old, new; 47307836SJohn.Forte@Sun.COM uint8_t call_lu_abort, call_port_abort; 47317836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 47327836SJohn.Forte@Sun.COM 47337836SJohn.Forte@Sun.COM lu = task->task_lu; 47347836SJohn.Forte@Sun.COM lport = task->task_lport; 47357836SJohn.Forte@Sun.COM do { 47367836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 47377836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) == 47387836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU) { 47397836SJohn.Forte@Sun.COM new |= ITASK_LU_ABORT_CALLED; 47407836SJohn.Forte@Sun.COM call_lu_abort = 1; 47417836SJohn.Forte@Sun.COM } else { 47427836SJohn.Forte@Sun.COM call_lu_abort = 0; 47437836SJohn.Forte@Sun.COM } 47447836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 47457836SJohn.Forte@Sun.COM 47467836SJohn.Forte@Sun.COM if (call_lu_abort) { 47477836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) { 47487836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 47497836SJohn.Forte@Sun.COM } else { 47507836SJohn.Forte@Sun.COM ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 47517836SJohn.Forte@Sun.COM } 47527836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 47537836SJohn.Forte@Sun.COM stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE); 47547836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 47557836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 47567836SJohn.Forte@Sun.COM ~ITASK_LU_ABORT_CALLED); 47577836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 47587836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 47597836SJohn.Forte@Sun.COM "Abort failed by LU %p, ret %llx", (void *)lu, ret); 47607836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 47617836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 47627836SJohn.Forte@Sun.COM } 47637836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_LU) { 47647836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 47657836SJohn.Forte@Sun.COM STMF_SEC2TICK(lu->lu_abort_timeout? 47667836SJohn.Forte@Sun.COM lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) { 47677836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 47687836SJohn.Forte@Sun.COM "lu abort timed out"); 47697836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 47707836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 1, info); 47717836SJohn.Forte@Sun.COM } 47727836SJohn.Forte@Sun.COM } 47737836SJohn.Forte@Sun.COM 47747836SJohn.Forte@Sun.COM do { 47757836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 47767836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_TGT_PORT | 47777836SJohn.Forte@Sun.COM ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) { 47787836SJohn.Forte@Sun.COM new |= ITASK_TGT_PORT_ABORT_CALLED; 47797836SJohn.Forte@Sun.COM call_port_abort = 1; 47807836SJohn.Forte@Sun.COM } else { 47817836SJohn.Forte@Sun.COM call_port_abort = 0; 47827836SJohn.Forte@Sun.COM } 47837836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 47847836SJohn.Forte@Sun.COM if (call_port_abort) { 47858662SJordan.Vaughan@Sun.com ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0); 47867836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 47877836SJohn.Forte@Sun.COM stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE); 47887836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 47897836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 47907836SJohn.Forte@Sun.COM ~ITASK_TGT_PORT_ABORT_CALLED); 47917836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 47927836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 47937836SJohn.Forte@Sun.COM "Abort failed by tgt port %p ret %llx", 47947836SJohn.Forte@Sun.COM (void *)lport, ret); 47957836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 47967836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 47977836SJohn.Forte@Sun.COM } 47987836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) { 47997836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 48007836SJohn.Forte@Sun.COM STMF_SEC2TICK(lport->lport_abort_timeout? 48017836SJohn.Forte@Sun.COM lport->lport_abort_timeout : 48027836SJohn.Forte@Sun.COM ITASK_DEFAULT_ABORT_TIMEOUT))) { 48037836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 48047836SJohn.Forte@Sun.COM "lport abort timed out"); 48057836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 48067836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 0, info); 48077836SJohn.Forte@Sun.COM } 48087836SJohn.Forte@Sun.COM } 48097836SJohn.Forte@Sun.COM } 48107836SJohn.Forte@Sun.COM 48117836SJohn.Forte@Sun.COM stmf_status_t 48127836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg) 48137836SJohn.Forte@Sun.COM { 48147836SJohn.Forte@Sun.COM stmf_status_t ret; 48157836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 48167836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 48177836SJohn.Forte@Sun.COM stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; 48187836SJohn.Forte@Sun.COM 48197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 48207836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 48217836SJohn.Forte@Sun.COM if (cmd & STMF_CMD_LU_OP) { 48227836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu((stmf_lu_t *)obj); 48237836SJohn.Forte@Sun.COM if (ilu == NULL) { 48247836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48257836SJohn.Forte@Sun.COM } 48268859STim.Szeto@Sun.COM DTRACE_PROBE3(lu__state__change, 48278859STim.Szeto@Sun.COM stmf_lu_t *, ilu->ilu_lu, 48288859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 48297836SJohn.Forte@Sun.COM } else if (cmd & STMF_CMD_LPORT_OP) { 48307836SJohn.Forte@Sun.COM ilport = stmf_lookup_lport((stmf_local_port_t *)obj); 48317836SJohn.Forte@Sun.COM if (ilport == NULL) { 48327836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48337836SJohn.Forte@Sun.COM } 48348859STim.Szeto@Sun.COM DTRACE_PROBE3(lport__state__change, 48358859STim.Szeto@Sun.COM stmf_local_port_t *, ilport->ilport_lport, 48368859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 48377836SJohn.Forte@Sun.COM } else { 48387836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48397836SJohn.Forte@Sun.COM } 48407836SJohn.Forte@Sun.COM 48417836SJohn.Forte@Sun.COM switch (cmd) { 48427836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 48437836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_ONLINE) { 48447836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 48457836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48467836SJohn.Forte@Sun.COM } 48477836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINE) { 48487836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 48497836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48507836SJohn.Forte@Sun.COM } 48517836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINING; 48527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 48537836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 48547836SJohn.Forte@Sun.COM break; 48557836SJohn.Forte@Sun.COM 48567836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE_COMPLETE: 48577836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINING) { 48587836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 48597836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48607836SJohn.Forte@Sun.COM } 48617836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 48627836SJohn.Forte@Sun.COM STMF_SUCCESS) { 48637836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 48647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 48657836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 48667836SJohn.Forte@Sun.COM STMF_ACK_LU_ONLINE_COMPLETE, arg); 48677836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 48687836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 48697836SJohn.Forte@Sun.COM } else { 48707836SJohn.Forte@Sun.COM /* XXX: should throw a meesage an record more data */ 48717836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 48727836SJohn.Forte@Sun.COM } 48737836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 48747836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48757836SJohn.Forte@Sun.COM 48767836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 48777836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 48787836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 48797836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48807836SJohn.Forte@Sun.COM } 48817836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) { 48827836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 48837836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48847836SJohn.Forte@Sun.COM } 48857836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINING; 48867836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 48877836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 48887836SJohn.Forte@Sun.COM break; 48897836SJohn.Forte@Sun.COM 48907836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE_COMPLETE: 48917836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINING) { 48927836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 48937836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 48947836SJohn.Forte@Sun.COM } 48957836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 48967836SJohn.Forte@Sun.COM STMF_SUCCESS) { 48977836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 48987836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 48997836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 49007836SJohn.Forte@Sun.COM STMF_ACK_LU_OFFLINE_COMPLETE, arg); 49017836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 49027836SJohn.Forte@Sun.COM } else { 49037836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 49047836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 49057836SJohn.Forte@Sun.COM } 49067836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 49077836SJohn.Forte@Sun.COM break; 49087836SJohn.Forte@Sun.COM 49097836SJohn.Forte@Sun.COM /* 49107836SJohn.Forte@Sun.COM * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online. 49117836SJohn.Forte@Sun.COM * It's related with hardware disable/enable. 49127836SJohn.Forte@Sun.COM */ 49137836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 49147836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_ONLINE) { 49157836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 49167836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49177836SJohn.Forte@Sun.COM } 49187836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINE) { 49197836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 49207836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49217836SJohn.Forte@Sun.COM } 49227836SJohn.Forte@Sun.COM 49237836SJohn.Forte@Sun.COM /* 49247836SJohn.Forte@Sun.COM * Only user request can recover the port from the 49257836SJohn.Forte@Sun.COM * FORCED_OFFLINE state 49267836SJohn.Forte@Sun.COM */ 49277836SJohn.Forte@Sun.COM if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) { 49287836SJohn.Forte@Sun.COM if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { 49297836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 49307836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49317836SJohn.Forte@Sun.COM } 49327836SJohn.Forte@Sun.COM } 49337836SJohn.Forte@Sun.COM 49347836SJohn.Forte@Sun.COM /* 49357836SJohn.Forte@Sun.COM * Avoid too frequent request to online 49367836SJohn.Forte@Sun.COM */ 49377836SJohn.Forte@Sun.COM if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) { 49387836SJohn.Forte@Sun.COM ilport->ilport_online_times = 0; 49397836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 0; 49407836SJohn.Forte@Sun.COM } 49417836SJohn.Forte@Sun.COM if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) && 49427836SJohn.Forte@Sun.COM (ilport->ilport_online_times >= 4)) { 49437836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 49447836SJohn.Forte@Sun.COM ilport->ilport_flags |= ILPORT_FORCED_OFFLINE; 49457836SJohn.Forte@Sun.COM stmf_trace(NULL, "stmf_ctl: too frequent request to " 49467836SJohn.Forte@Sun.COM "online the port"); 49477836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_ctl: too frequent request to " 49487836SJohn.Forte@Sun.COM "online the port, set FORCED_OFFLINE now"); 49497836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49507836SJohn.Forte@Sun.COM } 49517836SJohn.Forte@Sun.COM if (ilport->ilport_online_times > 0) { 49527836SJohn.Forte@Sun.COM if (ilport->ilport_online_times == 1) { 49537836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = ddi_get_lbolt() - 49547836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock; 49557836SJohn.Forte@Sun.COM } else { 49567836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 49577836SJohn.Forte@Sun.COM (ilport->ilport_avg_interval + 49587836SJohn.Forte@Sun.COM ddi_get_lbolt() - 49597836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock) >> 1; 49607836SJohn.Forte@Sun.COM } 49617836SJohn.Forte@Sun.COM } 49627836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock = ddi_get_lbolt(); 49637836SJohn.Forte@Sun.COM ilport->ilport_online_times++; 49647836SJohn.Forte@Sun.COM 49657836SJohn.Forte@Sun.COM /* 49667836SJohn.Forte@Sun.COM * Submit online service request 49677836SJohn.Forte@Sun.COM */ 49687836SJohn.Forte@Sun.COM ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE; 49697836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINING; 49707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 49717836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 49727836SJohn.Forte@Sun.COM break; 49737836SJohn.Forte@Sun.COM 49747836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE_COMPLETE: 49757836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINING) { 49767836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 49777836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49787836SJohn.Forte@Sun.COM } 49797836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 49807836SJohn.Forte@Sun.COM STMF_SUCCESS) { 49817836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 49827836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 49837836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 49847836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 49857836SJohn.Forte@Sun.COM STMF_ACK_LPORT_ONLINE_COMPLETE, arg); 49867836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 49877836SJohn.Forte@Sun.COM } else { 49887836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 49897836SJohn.Forte@Sun.COM } 49907836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 49917836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49927836SJohn.Forte@Sun.COM 49937836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 49947836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) { 49957836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 49967836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 49977836SJohn.Forte@Sun.COM } 49987836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 49997836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 50007836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 50017836SJohn.Forte@Sun.COM } 50027836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINING; 50037836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 50047836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 50057836SJohn.Forte@Sun.COM break; 50067836SJohn.Forte@Sun.COM 50077836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE_COMPLETE: 50087836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 50097836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 50107836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 50117836SJohn.Forte@Sun.COM } 50127836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 50137836SJohn.Forte@Sun.COM STMF_SUCCESS) { 50147836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 50157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 50167836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 50177836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 50187836SJohn.Forte@Sun.COM STMF_ACK_LPORT_OFFLINE_COMPLETE, arg); 50197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 50207836SJohn.Forte@Sun.COM } else { 50217836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 50227836SJohn.Forte@Sun.COM } 50237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 50247836SJohn.Forte@Sun.COM break; 50257836SJohn.Forte@Sun.COM 50267836SJohn.Forte@Sun.COM default: 50277836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd); 50287836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 50297836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 50307836SJohn.Forte@Sun.COM } 50317836SJohn.Forte@Sun.COM 50327836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50337836SJohn.Forte@Sun.COM 50347836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:; 50357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 50367836SJohn.Forte@Sun.COM return (ret); 50377836SJohn.Forte@Sun.COM } 50387836SJohn.Forte@Sun.COM 50397836SJohn.Forte@Sun.COM /* ARGSUSED */ 50407836SJohn.Forte@Sun.COM stmf_status_t 50417836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 50427836SJohn.Forte@Sun.COM uint32_t *bufsizep) 50437836SJohn.Forte@Sun.COM { 50447836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 50457836SJohn.Forte@Sun.COM } 50467836SJohn.Forte@Sun.COM 50477836SJohn.Forte@Sun.COM /* ARGSUSED */ 50487836SJohn.Forte@Sun.COM stmf_status_t 50497836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 50507836SJohn.Forte@Sun.COM uint32_t *bufsizep) 50517836SJohn.Forte@Sun.COM { 50527836SJohn.Forte@Sun.COM uint32_t cl = SI_GET_CLASS(cmd); 50537836SJohn.Forte@Sun.COM 50547836SJohn.Forte@Sun.COM if (cl == SI_STMF) { 50557836SJohn.Forte@Sun.COM return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep)); 50567836SJohn.Forte@Sun.COM } 50577836SJohn.Forte@Sun.COM if (cl == SI_LPORT) { 50588662SJordan.Vaughan@Sun.com return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1, 50598662SJordan.Vaughan@Sun.com arg2, buf, bufsizep)); 50607836SJohn.Forte@Sun.COM } else if (cl == SI_LU) { 50618662SJordan.Vaughan@Sun.com return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf, 50628662SJordan.Vaughan@Sun.com bufsizep)); 50637836SJohn.Forte@Sun.COM } 50647836SJohn.Forte@Sun.COM 50657836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 50667836SJohn.Forte@Sun.COM } 50677836SJohn.Forte@Sun.COM 50687836SJohn.Forte@Sun.COM /* 50699857SPeter.Cudhea@Sun.COM * Used by port providers. pwwn is 8 byte wwn, sdid is the devid used by 50707836SJohn.Forte@Sun.COM * stmf to register local ports. The ident should have 20 bytes in buffer 50717836SJohn.Forte@Sun.COM * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string. 50727836SJohn.Forte@Sun.COM */ 50737836SJohn.Forte@Sun.COM void 50747836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn, 50757836SJohn.Forte@Sun.COM uint8_t protocol_id) 50767836SJohn.Forte@Sun.COM { 50779857SPeter.Cudhea@Sun.COM char wwn_str[20+1]; 50789857SPeter.Cudhea@Sun.COM 50797836SJohn.Forte@Sun.COM sdid->protocol_id = protocol_id; 50807836SJohn.Forte@Sun.COM sdid->piv = 1; 50817836SJohn.Forte@Sun.COM sdid->code_set = CODE_SET_ASCII; 50827836SJohn.Forte@Sun.COM sdid->association = ID_IS_TARGET_PORT; 50837836SJohn.Forte@Sun.COM sdid->ident_length = 20; 50849857SPeter.Cudhea@Sun.COM /* Convert wwn value to "wwn.XXXXXXXXXXXXXXXX" format */ 50859857SPeter.Cudhea@Sun.COM (void) snprintf(wwn_str, sizeof (wwn_str), 50867836SJohn.Forte@Sun.COM "wwn.%02X%02X%02X%02X%02X%02X%02X%02X", 50877836SJohn.Forte@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 50889857SPeter.Cudhea@Sun.COM bcopy(wwn_str, (char *)sdid->ident, 20); 50897836SJohn.Forte@Sun.COM } 50907836SJohn.Forte@Sun.COM 50919857SPeter.Cudhea@Sun.COM 50927836SJohn.Forte@Sun.COM stmf_xfer_data_t * 509310725SJohn.Forte@Sun.COM stmf_prepare_tpgs_data(uint8_t ilu_alua) 50947836SJohn.Forte@Sun.COM { 50957836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 50967836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 50977836SJohn.Forte@Sun.COM uint8_t *p; 509810725SJohn.Forte@Sun.COM uint32_t sz, asz, nports = 0, nports_standby = 0; 50997836SJohn.Forte@Sun.COM 51007836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 510110725SJohn.Forte@Sun.COM /* check if any ports are standby and create second group */ 510210725SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 510310725SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 510410725SJohn.Forte@Sun.COM if (ilport->ilport_standby == 1) { 510510725SJohn.Forte@Sun.COM nports_standby++; 510610725SJohn.Forte@Sun.COM } else { 510710725SJohn.Forte@Sun.COM nports++; 510810725SJohn.Forte@Sun.COM } 510910725SJohn.Forte@Sun.COM } 511010725SJohn.Forte@Sun.COM 511110725SJohn.Forte@Sun.COM /* The spec only allows for 255 ports to be reported per group */ 511210725SJohn.Forte@Sun.COM nports = min(nports, 255); 511310725SJohn.Forte@Sun.COM nports_standby = min(nports_standby, 255); 51147836SJohn.Forte@Sun.COM sz = (nports * 4) + 12; 511510725SJohn.Forte@Sun.COM if (nports_standby && ilu_alua) { 511610725SJohn.Forte@Sun.COM sz += (nports_standby * 4) + 8; 511710725SJohn.Forte@Sun.COM } 51187836SJohn.Forte@Sun.COM asz = sz + sizeof (*xd) - 4; 51197836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP); 51207836SJohn.Forte@Sun.COM if (xd == NULL) { 51217836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 51227836SJohn.Forte@Sun.COM return (NULL); 51237836SJohn.Forte@Sun.COM } 51247836SJohn.Forte@Sun.COM xd->alloc_size = asz; 51257836SJohn.Forte@Sun.COM xd->size_left = sz; 51267836SJohn.Forte@Sun.COM 51277836SJohn.Forte@Sun.COM p = xd->buf; 51287836SJohn.Forte@Sun.COM 51297836SJohn.Forte@Sun.COM *((uint32_t *)p) = BE_32(sz - 4); 51307836SJohn.Forte@Sun.COM p += 4; 51317836SJohn.Forte@Sun.COM p[0] = 0x80; /* PREF */ 513210725SJohn.Forte@Sun.COM p[1] = 5; /* AO_SUP, S_SUP */ 513310725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_node == 1) { 513410725SJohn.Forte@Sun.COM p[3] = 1; /* Group 1 */ 513510725SJohn.Forte@Sun.COM } else { 513610725SJohn.Forte@Sun.COM p[3] = 0; /* Group 0 */ 513710725SJohn.Forte@Sun.COM } 51387836SJohn.Forte@Sun.COM p[7] = nports & 0xff; 51397836SJohn.Forte@Sun.COM p += 8; 514010725SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 514110725SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 514210725SJohn.Forte@Sun.COM if (ilport->ilport_standby == 1) { 514310725SJohn.Forte@Sun.COM continue; 514410725SJohn.Forte@Sun.COM } 51457836SJohn.Forte@Sun.COM ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid); 514610725SJohn.Forte@Sun.COM p += 4; 514710725SJohn.Forte@Sun.COM } 514810725SJohn.Forte@Sun.COM if (nports_standby && ilu_alua) { 514910725SJohn.Forte@Sun.COM p[0] = 0x02; /* Non PREF, Standby */ 515010725SJohn.Forte@Sun.COM p[1] = 5; /* AO_SUP, S_SUP */ 515110725SJohn.Forte@Sun.COM if (stmf_state.stmf_alua_node == 1) { 515210725SJohn.Forte@Sun.COM p[3] = 0; /* Group 0 */ 515310725SJohn.Forte@Sun.COM } else { 515410725SJohn.Forte@Sun.COM p[3] = 1; /* Group 1 */ 515510725SJohn.Forte@Sun.COM } 515610725SJohn.Forte@Sun.COM p[7] = nports_standby & 0xff; 515710725SJohn.Forte@Sun.COM p += 8; 515810725SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 515910725SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 516010725SJohn.Forte@Sun.COM if (ilport->ilport_standby == 0) { 516110725SJohn.Forte@Sun.COM continue; 516210725SJohn.Forte@Sun.COM } 516310725SJohn.Forte@Sun.COM ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid); 516410725SJohn.Forte@Sun.COM p += 4; 516510725SJohn.Forte@Sun.COM } 516610725SJohn.Forte@Sun.COM } 516710725SJohn.Forte@Sun.COM 51687836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 51697836SJohn.Forte@Sun.COM 51707836SJohn.Forte@Sun.COM return (xd); 51717836SJohn.Forte@Sun.COM } 51727836SJohn.Forte@Sun.COM 51739585STim.Szeto@Sun.COM struct scsi_devid_desc * 51749585STim.Szeto@Sun.COM stmf_scsilib_get_devid_desc(uint16_t rtpid) 51759585STim.Szeto@Sun.COM { 51769585STim.Szeto@Sun.COM scsi_devid_desc_t *devid = NULL; 51779585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 51789585STim.Szeto@Sun.COM 51799585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 51809585STim.Szeto@Sun.COM 51819585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 51829585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 51839585STim.Szeto@Sun.COM if (ilport->ilport_rtpid == rtpid) { 51849585STim.Szeto@Sun.COM scsi_devid_desc_t *id = ilport->ilport_lport->lport_id; 51859585STim.Szeto@Sun.COM uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 + 51869585STim.Szeto@Sun.COM id->ident_length; 51879585STim.Szeto@Sun.COM devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz, 51889585STim.Szeto@Sun.COM KM_NOSLEEP); 51899585STim.Szeto@Sun.COM if (devid != NULL) { 51909585STim.Szeto@Sun.COM bcopy(id, devid, id_sz); 51919585STim.Szeto@Sun.COM } 51929585STim.Szeto@Sun.COM break; 51939585STim.Szeto@Sun.COM } 51949585STim.Szeto@Sun.COM } 51959585STim.Szeto@Sun.COM 51969585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 51979585STim.Szeto@Sun.COM return (devid); 51989585STim.Szeto@Sun.COM } 51999585STim.Szeto@Sun.COM 52009585STim.Szeto@Sun.COM uint16_t 52019585STim.Szeto@Sun.COM stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid) 52029585STim.Szeto@Sun.COM { 52039585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 52049585STim.Szeto@Sun.COM scsi_devid_desc_t *id; 52059585STim.Szeto@Sun.COM uint16_t rtpid = 0; 52069585STim.Szeto@Sun.COM 52079585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 52089585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 52099585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 52109585STim.Szeto@Sun.COM id = ilport->ilport_lport->lport_id; 52119585STim.Szeto@Sun.COM if ((devid->ident_length == id->ident_length) && 52129585STim.Szeto@Sun.COM (memcmp(devid->ident, id->ident, id->ident_length) == 0)) { 52139585STim.Szeto@Sun.COM rtpid = ilport->ilport_rtpid; 52149585STim.Szeto@Sun.COM break; 52159585STim.Szeto@Sun.COM } 52169585STim.Szeto@Sun.COM } 52179585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 52189585STim.Szeto@Sun.COM return (rtpid); 52199585STim.Szeto@Sun.COM } 52207836SJohn.Forte@Sun.COM 52217836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0; 52227836SJohn.Forte@Sun.COM 52237836SJohn.Forte@Sun.COM stmf_status_t 52247836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id) 52257836SJohn.Forte@Sun.COM { 5226*10765SJohn.Forte@Sun.COM return (stmf_scsilib_uniq_lu_id2(company_id, 0, lu_id)); 5227*10765SJohn.Forte@Sun.COM } 5228*10765SJohn.Forte@Sun.COM 5229*10765SJohn.Forte@Sun.COM stmf_status_t 5230*10765SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id2(uint32_t company_id, uint32_t host_id, 5231*10765SJohn.Forte@Sun.COM scsi_devid_desc_t *lu_id) 5232*10765SJohn.Forte@Sun.COM { 52337836SJohn.Forte@Sun.COM uint8_t *p; 52347836SJohn.Forte@Sun.COM struct timeval32 timestamp32; 52357836SJohn.Forte@Sun.COM uint32_t *t = (uint32_t *)×tamp32; 52367836SJohn.Forte@Sun.COM struct ether_addr mac; 52377836SJohn.Forte@Sun.COM uint8_t *e = (uint8_t *)&mac; 5238*10765SJohn.Forte@Sun.COM int hid = (int)host_id; 52397836SJohn.Forte@Sun.COM 52407836SJohn.Forte@Sun.COM if (company_id == COMPANY_ID_NONE) 52417836SJohn.Forte@Sun.COM company_id = COMPANY_ID_SUN; 52427836SJohn.Forte@Sun.COM 52437836SJohn.Forte@Sun.COM if (lu_id->ident_length != 0x10) 52447836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 52457836SJohn.Forte@Sun.COM 52467836SJohn.Forte@Sun.COM p = (uint8_t *)lu_id; 52477836SJohn.Forte@Sun.COM 52487836SJohn.Forte@Sun.COM atomic_add_16(&stmf_lu_id_gen_number, 1); 52497836SJohn.Forte@Sun.COM 52507836SJohn.Forte@Sun.COM p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10; 52517836SJohn.Forte@Sun.COM p[4] = ((company_id >> 20) & 0xf) | 0x60; 52527836SJohn.Forte@Sun.COM p[5] = (company_id >> 12) & 0xff; 52537836SJohn.Forte@Sun.COM p[6] = (company_id >> 4) & 0xff; 52547836SJohn.Forte@Sun.COM p[7] = (company_id << 4) & 0xf0; 5255*10765SJohn.Forte@Sun.COM if (hid == 0 && !localetheraddr((struct ether_addr *)NULL, &mac)) { 5256*10765SJohn.Forte@Sun.COM hid = BE_32((int)zone_get_hostid(NULL)); 5257*10765SJohn.Forte@Sun.COM } 5258*10765SJohn.Forte@Sun.COM if (hid != 0) { 52597836SJohn.Forte@Sun.COM e[0] = (hid >> 24) & 0xff; 52607836SJohn.Forte@Sun.COM e[1] = (hid >> 16) & 0xff; 52617836SJohn.Forte@Sun.COM e[2] = (hid >> 8) & 0xff; 52627836SJohn.Forte@Sun.COM e[3] = hid & 0xff; 52637836SJohn.Forte@Sun.COM e[4] = e[5] = 0; 52647836SJohn.Forte@Sun.COM } 52657836SJohn.Forte@Sun.COM bcopy(e, p+8, 6); 52667836SJohn.Forte@Sun.COM uniqtime32(×tamp32); 52677836SJohn.Forte@Sun.COM *t = BE_32(*t); 52687836SJohn.Forte@Sun.COM bcopy(t, p+14, 4); 52697836SJohn.Forte@Sun.COM p[18] = (stmf_lu_id_gen_number >> 8) & 0xff; 52707836SJohn.Forte@Sun.COM p[19] = stmf_lu_id_gen_number & 0xff; 52717836SJohn.Forte@Sun.COM 52727836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 52737836SJohn.Forte@Sun.COM } 52747836SJohn.Forte@Sun.COM 52757836SJohn.Forte@Sun.COM /* 52767836SJohn.Forte@Sun.COM * saa is sense key, ASC, ASCQ 52777836SJohn.Forte@Sun.COM */ 52787836SJohn.Forte@Sun.COM void 52797836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa) 52807836SJohn.Forte@Sun.COM { 52817836SJohn.Forte@Sun.COM uint8_t sd[18]; 52827836SJohn.Forte@Sun.COM task->task_scsi_status = st; 52837836SJohn.Forte@Sun.COM if (st == 2) { 52847836SJohn.Forte@Sun.COM bzero(sd, 18); 52857836SJohn.Forte@Sun.COM sd[0] = 0x70; 52867836SJohn.Forte@Sun.COM sd[2] = (saa >> 16) & 0xf; 52877836SJohn.Forte@Sun.COM sd[7] = 10; 52887836SJohn.Forte@Sun.COM sd[12] = (saa >> 8) & 0xff; 52897836SJohn.Forte@Sun.COM sd[13] = saa & 0xff; 52907836SJohn.Forte@Sun.COM task->task_sense_data = sd; 52917836SJohn.Forte@Sun.COM task->task_sense_length = 18; 52927836SJohn.Forte@Sun.COM } else { 52937836SJohn.Forte@Sun.COM task->task_sense_data = NULL; 52947836SJohn.Forte@Sun.COM task->task_sense_length = 0; 52957836SJohn.Forte@Sun.COM } 52967836SJohn.Forte@Sun.COM (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE); 52977836SJohn.Forte@Sun.COM } 52987836SJohn.Forte@Sun.COM 52997836SJohn.Forte@Sun.COM uint32_t 53007836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page, 53017836SJohn.Forte@Sun.COM uint32_t page_len, uint8_t byte0, uint32_t vpd_mask) 53027836SJohn.Forte@Sun.COM { 53037836SJohn.Forte@Sun.COM uint8_t *p = NULL; 53047836SJohn.Forte@Sun.COM uint8_t small_buf[32]; 53057836SJohn.Forte@Sun.COM uint32_t sz = 0; 53067836SJohn.Forte@Sun.COM uint32_t n = 4; 53077836SJohn.Forte@Sun.COM uint32_t m = 0; 53087836SJohn.Forte@Sun.COM uint32_t last_bit = 0; 53097836SJohn.Forte@Sun.COM 53107836SJohn.Forte@Sun.COM if (page_len < 4) 53117836SJohn.Forte@Sun.COM return (0); 53127836SJohn.Forte@Sun.COM if (page_len > 65535) 53137836SJohn.Forte@Sun.COM page_len = 65535; 53147836SJohn.Forte@Sun.COM 53157836SJohn.Forte@Sun.COM page[0] = byte0; 53167836SJohn.Forte@Sun.COM page[1] = 0x83; 53177836SJohn.Forte@Sun.COM 53187836SJohn.Forte@Sun.COM /* CONSTCOND */ 53197836SJohn.Forte@Sun.COM while (1) { 53207836SJohn.Forte@Sun.COM m += sz; 53217836SJohn.Forte@Sun.COM if (sz && (page_len > n)) { 53227836SJohn.Forte@Sun.COM uint32_t copysz; 53237836SJohn.Forte@Sun.COM copysz = page_len > (n + sz) ? sz : page_len - n; 53247836SJohn.Forte@Sun.COM bcopy(p, page + n, copysz); 53257836SJohn.Forte@Sun.COM n += copysz; 53267836SJohn.Forte@Sun.COM } 53277836SJohn.Forte@Sun.COM vpd_mask &= ~last_bit; 53287836SJohn.Forte@Sun.COM if (vpd_mask == 0) 53297836SJohn.Forte@Sun.COM break; 53307836SJohn.Forte@Sun.COM 53317836SJohn.Forte@Sun.COM if (vpd_mask & STMF_VPD_LU_ID) { 53327836SJohn.Forte@Sun.COM last_bit = STMF_VPD_LU_ID; 53337836SJohn.Forte@Sun.COM sz = task->task_lu->lu_id->ident_length + 4; 53347836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lu->lu_id; 53357836SJohn.Forte@Sun.COM continue; 53367836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TARGET_ID) { 53377836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TARGET_ID; 53387836SJohn.Forte@Sun.COM sz = task->task_lport->lport_id->ident_length + 4; 53397836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lport->lport_id; 53407836SJohn.Forte@Sun.COM continue; 53417836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TP_GROUP) { 534210725SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 53437836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TP_GROUP; 53447836SJohn.Forte@Sun.COM p = small_buf; 53457836SJohn.Forte@Sun.COM bzero(p, 8); 53467836SJohn.Forte@Sun.COM p[0] = 1; 53477836SJohn.Forte@Sun.COM p[1] = 0x15; 53487836SJohn.Forte@Sun.COM p[3] = 4; 534910725SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *) 535010725SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private; 535110725SJohn.Forte@Sun.COM if (ilport->ilport_rtpid > 255) { 535210725SJohn.Forte@Sun.COM p[7] = 1; /* Group 1 */ 535310725SJohn.Forte@Sun.COM } 53547836SJohn.Forte@Sun.COM sz = 8; 53557836SJohn.Forte@Sun.COM continue; 53567836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) { 53577836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 53587836SJohn.Forte@Sun.COM 53597836SJohn.Forte@Sun.COM last_bit = STMF_VPD_RELATIVE_TP_ID; 53607836SJohn.Forte@Sun.COM p = small_buf; 53617836SJohn.Forte@Sun.COM bzero(p, 8); 53627836SJohn.Forte@Sun.COM p[0] = 1; 53637836SJohn.Forte@Sun.COM p[1] = 0x14; 53647836SJohn.Forte@Sun.COM p[3] = 4; 53657836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *) 53668662SJordan.Vaughan@Sun.com task->task_lport->lport_stmf_private; 53677836SJohn.Forte@Sun.COM p[6] = (ilport->ilport_rtpid >> 8) & 0xff; 53687836SJohn.Forte@Sun.COM p[7] = ilport->ilport_rtpid & 0xff; 53697836SJohn.Forte@Sun.COM sz = 8; 53707836SJohn.Forte@Sun.COM continue; 53717836SJohn.Forte@Sun.COM } else { 53727836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid vpd_mask"); 53737836SJohn.Forte@Sun.COM break; 53747836SJohn.Forte@Sun.COM } 53757836SJohn.Forte@Sun.COM } 53767836SJohn.Forte@Sun.COM 53777836SJohn.Forte@Sun.COM page[2] = (m >> 8) & 0xff; 53787836SJohn.Forte@Sun.COM page[3] = m & 0xff; 53797836SJohn.Forte@Sun.COM 53807836SJohn.Forte@Sun.COM return (n); 53817836SJohn.Forte@Sun.COM } 53827836SJohn.Forte@Sun.COM 53837836SJohn.Forte@Sun.COM void 53847836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf) 53857836SJohn.Forte@Sun.COM { 53867836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 53878662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 538810725SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = 538910725SJohn.Forte@Sun.COM (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 53907836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 53917836SJohn.Forte@Sun.COM uint32_t sz, minsz; 53927836SJohn.Forte@Sun.COM 53937836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING; 53947836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 53957836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 53967836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 53977836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 53987836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 53997836SJohn.Forte@Sun.COM 54007836SJohn.Forte@Sun.COM if (task->task_additional_flags & 54017836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 54027836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 54037836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 54047836SJohn.Forte@Sun.COM } 54057836SJohn.Forte@Sun.COM 54069962SWayne.Ihde@Sun.COM if (task->task_cmd_xfer_length == 0) { 54079962SWayne.Ihde@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 54089962SWayne.Ihde@Sun.COM return; 54099962SWayne.Ihde@Sun.COM } 54109962SWayne.Ihde@Sun.COM if (task->task_cmd_xfer_length < 4) { 54117836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 54128662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 54137836SJohn.Forte@Sun.COM return; 54147836SJohn.Forte@Sun.COM } 54157836SJohn.Forte@Sun.COM 54167836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 54177836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 54187836SJohn.Forte@Sun.COM 541910725SJohn.Forte@Sun.COM xd = stmf_prepare_tpgs_data(ilu->ilu_alua); 54207836SJohn.Forte@Sun.COM 54217836SJohn.Forte@Sun.COM if (xd == NULL) { 54227836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 54237836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 54247836SJohn.Forte@Sun.COM return; 54257836SJohn.Forte@Sun.COM } 54267836SJohn.Forte@Sun.COM 54277836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 54287836SJohn.Forte@Sun.COM xd->size_left = sz; 54297836SJohn.Forte@Sun.COM minsz = min(512, sz); 54307836SJohn.Forte@Sun.COM 54317836SJohn.Forte@Sun.COM if (dbuf == NULL) 54327836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 54337836SJohn.Forte@Sun.COM if (dbuf == NULL) { 54347836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 54357836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 54367836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 54377836SJohn.Forte@Sun.COM return; 54387836SJohn.Forte@Sun.COM } 54397836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 54407836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 54417836SJohn.Forte@Sun.COM 54427836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 54437836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 54447836SJohn.Forte@Sun.COM 54457836SJohn.Forte@Sun.COM } 54467836SJohn.Forte@Sun.COM 54477836SJohn.Forte@Sun.COM void 54487836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task) 54497836SJohn.Forte@Sun.COM { 545010725SJohn.Forte@Sun.COM 54517836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 54527836SJohn.Forte@Sun.COM /* 54537836SJohn.Forte@Sun.COM * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET 54547836SJohn.Forte@Sun.COM * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state 54557836SJohn.Forte@Sun.COM * in these cases. This needs to be changed to abort only the required 54567836SJohn.Forte@Sun.COM * set. 54577836SJohn.Forte@Sun.COM */ 54587836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 54597836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 54607836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 54617836SJohn.Forte@Sun.COM case TM_LUN_RESET: 54627836SJohn.Forte@Sun.COM stmf_handle_lun_reset(task); 546310725SJohn.Forte@Sun.COM /* issue the reset to the proxy node as well */ 546410725SJohn.Forte@Sun.COM (void) stmf_proxy_scsi_cmd(task, NULL); 54657836SJohn.Forte@Sun.COM return; 54667836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 54677836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 54687836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 54697836SJohn.Forte@Sun.COM stmf_handle_target_reset(task); 54707836SJohn.Forte@Sun.COM return; 54717836SJohn.Forte@Sun.COM default: 54727836SJohn.Forte@Sun.COM /* We dont support this task mgmt function */ 54737836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 54747836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CMD_IU); 54757836SJohn.Forte@Sun.COM return; 54767836SJohn.Forte@Sun.COM } 54777836SJohn.Forte@Sun.COM } 54787836SJohn.Forte@Sun.COM 54797836SJohn.Forte@Sun.COM void 54807836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task) 54817836SJohn.Forte@Sun.COM { 54827836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 54837836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 54847836SJohn.Forte@Sun.COM 54857836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 54867836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 54877836SJohn.Forte@Sun.COM 54887836SJohn.Forte@Sun.COM /* 54897836SJohn.Forte@Sun.COM * To sync with target reset, grab this lock. The LU is not going 54907836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 54917836SJohn.Forte@Sun.COM */ 54927836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 54937836SJohn.Forte@Sun.COM 54947836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 54957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 54967836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 54978662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 54987836SJohn.Forte@Sun.COM return; 54997836SJohn.Forte@Sun.COM } 55007836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 55017836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 55027836SJohn.Forte@Sun.COM 55037836SJohn.Forte@Sun.COM /* 55047836SJohn.Forte@Sun.COM * Mark this task as the one causing LU reset so that we know who 55057836SJohn.Forte@Sun.COM * was responsible for setting the ILU_RESET_ACTIVE. In case this 55067836SJohn.Forte@Sun.COM * task itself gets aborted, we will clear ILU_RESET_ACTIVE. 55077836SJohn.Forte@Sun.COM */ 55087836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET; 55097836SJohn.Forte@Sun.COM 55107836SJohn.Forte@Sun.COM /* Initiatiate abort on all commands on this LU except this one */ 55117836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu); 55127836SJohn.Forte@Sun.COM 55137836SJohn.Forte@Sun.COM /* Start polling on this task */ 55147836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 55157836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 55167836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 55178662SJordan.Vaughan@Sun.com NULL); 55187836SJohn.Forte@Sun.COM return; 55197836SJohn.Forte@Sun.COM } 55207836SJohn.Forte@Sun.COM } 55217836SJohn.Forte@Sun.COM 55227836SJohn.Forte@Sun.COM void 55237836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task) 55247836SJohn.Forte@Sun.COM { 55257836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 55267836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 55277836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 55287836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 55297836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 55307836SJohn.Forte@Sun.COM int i, lf; 55317836SJohn.Forte@Sun.COM 55327836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 55337836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private; 55347836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 55357836SJohn.Forte@Sun.COM 55367836SJohn.Forte@Sun.COM /* 55377836SJohn.Forte@Sun.COM * To sync with LUN reset, grab this lock. The session is not going 55387836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 55397836SJohn.Forte@Sun.COM */ 55407836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 55417979SSumit.Gupta@Sun.COM 55427979SSumit.Gupta@Sun.COM /* Grab the session lock as a writer to prevent any changes in it */ 55437979SSumit.Gupta@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 55447979SSumit.Gupta@Sun.COM 55457836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_RESET_ACTIVE) { 55467979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 55477836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 55487836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 55498662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 55507836SJohn.Forte@Sun.COM return; 55517836SJohn.Forte@Sun.COM } 55527836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE); 55537836SJohn.Forte@Sun.COM 55547836SJohn.Forte@Sun.COM /* 55557836SJohn.Forte@Sun.COM * Now go through each LUN in this session and make sure all of them 55567836SJohn.Forte@Sun.COM * can be reset. 55577836SJohn.Forte@Sun.COM */ 55587836SJohn.Forte@Sun.COM lm = iss->iss_sm; 55597836SJohn.Forte@Sun.COM for (i = 0, lf = 0; i < lm->lm_nentries; i++) { 55607836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 55617836SJohn.Forte@Sun.COM continue; 55627836SJohn.Forte@Sun.COM lf++; 55637836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 55647836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 55657836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 55667836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 55677979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 55687836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 55697836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 55708662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 55717836SJohn.Forte@Sun.COM return; 55727836SJohn.Forte@Sun.COM } 55737836SJohn.Forte@Sun.COM } 55747836SJohn.Forte@Sun.COM if (lf == 0) { 55757836SJohn.Forte@Sun.COM /* No luns in this session */ 55767836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 55777979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 55787836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 55797836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 55807836SJohn.Forte@Sun.COM return; 55817836SJohn.Forte@Sun.COM } 55827836SJohn.Forte@Sun.COM 55837836SJohn.Forte@Sun.COM /* ok, start the damage */ 55847836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | 55858662SJordan.Vaughan@Sun.com ITASK_CAUSING_TARGET_RESET; 55867836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 55877836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 55887836SJohn.Forte@Sun.COM continue; 55897836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 55907836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 55917836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 55927836SJohn.Forte@Sun.COM } 55937979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 55947836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 55957836SJohn.Forte@Sun.COM 55967836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 55977836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 55987836SJohn.Forte@Sun.COM continue; 55997836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 56007836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, 56018662SJordan.Vaughan@Sun.com lm_ent->ent_lu); 56027836SJohn.Forte@Sun.COM } 56037836SJohn.Forte@Sun.COM 56047836SJohn.Forte@Sun.COM /* Start polling on this task */ 56057836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 56067836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 56077836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 56088662SJordan.Vaughan@Sun.com NULL); 56097836SJohn.Forte@Sun.COM return; 56107836SJohn.Forte@Sun.COM } 56117836SJohn.Forte@Sun.COM } 56127836SJohn.Forte@Sun.COM 56137836SJohn.Forte@Sun.COM int 56147836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask) 56157836SJohn.Forte@Sun.COM { 56167836SJohn.Forte@Sun.COM scsi_task_t *task = itask->itask_task; 56177836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 56187836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 56197836SJohn.Forte@Sun.COM 56207836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 56217836SJohn.Forte@Sun.COM if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) || 56227836SJohn.Forte@Sun.COM (task->task_cdb[0] == SCMD_INQUIRY)) { 56237836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56247836SJohn.Forte@Sun.COM return (0); 56257836SJohn.Forte@Sun.COM } 56267836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 56278662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 56287836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56297836SJohn.Forte@Sun.COM 56307836SJohn.Forte@Sun.COM if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 56317836SJohn.Forte@Sun.COM return (0); 56327836SJohn.Forte@Sun.COM } 56337836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 56347836SJohn.Forte@Sun.COM STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED); 56357836SJohn.Forte@Sun.COM return (1); 56367836SJohn.Forte@Sun.COM } 56377836SJohn.Forte@Sun.COM 56387836SJohn.Forte@Sun.COM void 56397836SJohn.Forte@Sun.COM stmf_worker_init() 56407836SJohn.Forte@Sun.COM { 56417836SJohn.Forte@Sun.COM uint32_t i; 56427836SJohn.Forte@Sun.COM 56437836SJohn.Forte@Sun.COM /* Make local copy of global tunables */ 56447836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_max_nworkers; 56457836SJohn.Forte@Sun.COM stmf_i_min_nworkers = stmf_min_nworkers; 56467836SJohn.Forte@Sun.COM 56477836SJohn.Forte@Sun.COM ASSERT(stmf_workers == NULL); 56487836SJohn.Forte@Sun.COM if (stmf_i_min_nworkers < 4) { 56497836SJohn.Forte@Sun.COM stmf_i_min_nworkers = 4; 56507836SJohn.Forte@Sun.COM } 56517836SJohn.Forte@Sun.COM if (stmf_i_max_nworkers < stmf_i_min_nworkers) { 56527836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_i_min_nworkers; 56537836SJohn.Forte@Sun.COM } 56547836SJohn.Forte@Sun.COM stmf_workers = (stmf_worker_t *)kmem_zalloc( 56557836SJohn.Forte@Sun.COM sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP); 56567836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 56577836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 56587836SJohn.Forte@Sun.COM mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 56597836SJohn.Forte@Sun.COM cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 56607836SJohn.Forte@Sun.COM } 56617836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 56627836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 56637836SJohn.Forte@Sun.COM 56647836SJohn.Forte@Sun.COM /* Workers will be started by stmf_worker_mgmt() */ 56657836SJohn.Forte@Sun.COM 56667836SJohn.Forte@Sun.COM /* Lets wait for atleast one worker to start */ 56677836SJohn.Forte@Sun.COM while (stmf_nworkers_cur == 0) 56687836SJohn.Forte@Sun.COM delay(drv_usectohz(20 * 1000)); 56697836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000); 56707836SJohn.Forte@Sun.COM } 56717836SJohn.Forte@Sun.COM 56727836SJohn.Forte@Sun.COM stmf_status_t 56737836SJohn.Forte@Sun.COM stmf_worker_fini() 56747836SJohn.Forte@Sun.COM { 56757836SJohn.Forte@Sun.COM int i; 56767836SJohn.Forte@Sun.COM clock_t sb; 56777836SJohn.Forte@Sun.COM 56787836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) 56797836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56807836SJohn.Forte@Sun.COM ASSERT(stmf_workers); 56817836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_DISABLED; 56827836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 56837836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 56847836SJohn.Forte@Sun.COM 56857836SJohn.Forte@Sun.COM sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000); 56867836SJohn.Forte@Sun.COM /* Wait for all the threads to die */ 56877836SJohn.Forte@Sun.COM while (stmf_nworkers_cur != 0) { 56887836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > sb) { 56897836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 56907836SJohn.Forte@Sun.COM return (STMF_BUSY); 56917836SJohn.Forte@Sun.COM } 56927836SJohn.Forte@Sun.COM delay(drv_usectohz(100 * 1000)); 56937836SJohn.Forte@Sun.COM } 56947836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 56957836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 56967836SJohn.Forte@Sun.COM mutex_destroy(&w->worker_lock); 56977836SJohn.Forte@Sun.COM cv_destroy(&w->worker_cv); 56987836SJohn.Forte@Sun.COM } 56997836SJohn.Forte@Sun.COM kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers); 57007836SJohn.Forte@Sun.COM stmf_workers = NULL; 57017836SJohn.Forte@Sun.COM 57027836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57037836SJohn.Forte@Sun.COM } 57047836SJohn.Forte@Sun.COM 57057836SJohn.Forte@Sun.COM void 57067836SJohn.Forte@Sun.COM stmf_worker_task(void *arg) 57077836SJohn.Forte@Sun.COM { 57087836SJohn.Forte@Sun.COM stmf_worker_t *w; 57097836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 57107836SJohn.Forte@Sun.COM scsi_task_t *task; 57117836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 57127836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 57137836SJohn.Forte@Sun.COM stmf_lu_t *lu; 57147836SJohn.Forte@Sun.COM clock_t wait_timer = 0; 57157836SJohn.Forte@Sun.COM clock_t wait_ticks; 57167836SJohn.Forte@Sun.COM uint32_t old, new; 57177836SJohn.Forte@Sun.COM uint8_t curcmd; 57187836SJohn.Forte@Sun.COM uint8_t abort_free; 57197836SJohn.Forte@Sun.COM uint8_t wait_queue; 57207836SJohn.Forte@Sun.COM uint8_t dec_qdepth; 57217836SJohn.Forte@Sun.COM 57227836SJohn.Forte@Sun.COM w = (stmf_worker_t *)arg; 57237836SJohn.Forte@Sun.COM wait_ticks = drv_usectohz(10000); 57247836SJohn.Forte@Sun.COM 57257836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 57267836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE; 57277836SJohn.Forte@Sun.COM stmf_worker_loop:; 57287836SJohn.Forte@Sun.COM if ((w->worker_ref_count == 0) && 57297836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 57307836SJohn.Forte@Sun.COM w->worker_flags &= ~(STMF_WORKER_STARTED | 57317836SJohn.Forte@Sun.COM STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE); 57327836SJohn.Forte@Sun.COM w->worker_tid = NULL; 57337836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 57347836SJohn.Forte@Sun.COM thread_exit(); 57357836SJohn.Forte@Sun.COM } 57367836SJohn.Forte@Sun.COM /* CONSTCOND */ 57377836SJohn.Forte@Sun.COM while (1) { 57387836SJohn.Forte@Sun.COM dec_qdepth = 0; 57397836SJohn.Forte@Sun.COM if (wait_timer && (ddi_get_lbolt() >= wait_timer)) { 57407836SJohn.Forte@Sun.COM wait_timer = 0; 57417979SSumit.Gupta@Sun.COM if (w->worker_wait_head) { 57427979SSumit.Gupta@Sun.COM ASSERT(w->worker_wait_tail); 57437979SSumit.Gupta@Sun.COM if (w->worker_task_head == NULL) 57447979SSumit.Gupta@Sun.COM w->worker_task_head = 57457979SSumit.Gupta@Sun.COM w->worker_wait_head; 57467979SSumit.Gupta@Sun.COM else 57477979SSumit.Gupta@Sun.COM w->worker_task_tail->itask_worker_next = 57488662SJordan.Vaughan@Sun.com w->worker_wait_head; 57497979SSumit.Gupta@Sun.COM w->worker_task_tail = w->worker_wait_tail; 57507979SSumit.Gupta@Sun.COM w->worker_wait_head = w->worker_wait_tail = 57517979SSumit.Gupta@Sun.COM NULL; 57527979SSumit.Gupta@Sun.COM } 57537836SJohn.Forte@Sun.COM } 57547836SJohn.Forte@Sun.COM if ((itask = w->worker_task_head) == NULL) { 57557836SJohn.Forte@Sun.COM break; 57567836SJohn.Forte@Sun.COM } 57577836SJohn.Forte@Sun.COM task = itask->itask_task; 57587836SJohn.Forte@Sun.COM w->worker_task_head = itask->itask_worker_next; 57597836SJohn.Forte@Sun.COM if (w->worker_task_head == NULL) 57607836SJohn.Forte@Sun.COM w->worker_task_tail = NULL; 57617836SJohn.Forte@Sun.COM 57627836SJohn.Forte@Sun.COM wait_queue = 0; 57637836SJohn.Forte@Sun.COM abort_free = 0; 57647836SJohn.Forte@Sun.COM if (itask->itask_ncmds > 0) { 57657836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1]; 57667836SJohn.Forte@Sun.COM } else { 57677836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_BEING_ABORTED); 57687836SJohn.Forte@Sun.COM } 57697836SJohn.Forte@Sun.COM do { 57707836SJohn.Forte@Sun.COM old = itask->itask_flags; 57717836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 57727836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 57737836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[0] = 57747836SJohn.Forte@Sun.COM ITASK_CMD_ABORT; 57757836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 57767836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_MASK) == 57777836SJohn.Forte@Sun.COM ITASK_CMD_NEW_TASK) { 577810421STim.Szeto@Sun.COM /* 577910421STim.Szeto@Sun.COM * set ITASK_KSTAT_IN_RUNQ, this flag 578010421STim.Szeto@Sun.COM * will not reset until task completed 578110421STim.Szeto@Sun.COM */ 578210421STim.Szeto@Sun.COM new = old | ITASK_KNOWN_TO_LU | 578310421STim.Szeto@Sun.COM ITASK_KSTAT_IN_RUNQ; 57847836SJohn.Forte@Sun.COM } else { 57857836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 57867836SJohn.Forte@Sun.COM } 57877836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 57887836SJohn.Forte@Sun.COM 57897836SJohn.Forte@Sun.COM out_itask_flag_loop: 57907836SJohn.Forte@Sun.COM 57917836SJohn.Forte@Sun.COM /* 57927836SJohn.Forte@Sun.COM * Decide if this task needs to go to a queue and/or if 57937836SJohn.Forte@Sun.COM * we can decrement the itask_cmd_stack. 57947836SJohn.Forte@Sun.COM */ 57957836SJohn.Forte@Sun.COM if (curcmd == ITASK_CMD_ABORT) { 57967836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_KNOWN_TO_LU | 57977836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT)) { 57987836SJohn.Forte@Sun.COM wait_queue = 1; 57997836SJohn.Forte@Sun.COM } else { 58007836SJohn.Forte@Sun.COM abort_free = 1; 58017836SJohn.Forte@Sun.COM } 58027836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_POLL) && 58037836SJohn.Forte@Sun.COM (itask->itask_poll_timeout > ddi_get_lbolt())) { 58047836SJohn.Forte@Sun.COM wait_queue = 1; 58057836SJohn.Forte@Sun.COM } 58067836SJohn.Forte@Sun.COM 58077836SJohn.Forte@Sun.COM if (wait_queue) { 58087836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 58097836SJohn.Forte@Sun.COM if (w->worker_wait_tail) { 58107836SJohn.Forte@Sun.COM w->worker_wait_tail->itask_worker_next = itask; 58117836SJohn.Forte@Sun.COM } else { 58127836SJohn.Forte@Sun.COM w->worker_wait_head = itask; 58137836SJohn.Forte@Sun.COM } 58147836SJohn.Forte@Sun.COM w->worker_wait_tail = itask; 58157836SJohn.Forte@Sun.COM if (wait_timer == 0) { 58167836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + wait_ticks; 58177836SJohn.Forte@Sun.COM } 58187836SJohn.Forte@Sun.COM } else if ((--(itask->itask_ncmds)) != 0) { 58197836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 58207836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 58217836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 58227836SJohn.Forte@Sun.COM } else { 58237836SJohn.Forte@Sun.COM w->worker_task_head = itask; 58247836SJohn.Forte@Sun.COM } 58257836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 58267836SJohn.Forte@Sun.COM } else { 58277836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 58287836SJohn.Forte@Sun.COM ~ITASK_IN_WORKER_QUEUE); 58297836SJohn.Forte@Sun.COM /* 58307836SJohn.Forte@Sun.COM * This is where the queue depth should go down by 58317836SJohn.Forte@Sun.COM * one but we delay that on purpose to account for 58327836SJohn.Forte@Sun.COM * the call into the provider. The actual decrement 58337836SJohn.Forte@Sun.COM * happens after the worker has done its job. 58347836SJohn.Forte@Sun.COM */ 58357836SJohn.Forte@Sun.COM dec_qdepth = 1; 58367836SJohn.Forte@Sun.COM } 58377836SJohn.Forte@Sun.COM 58387836SJohn.Forte@Sun.COM /* We made it here means we are going to call LU */ 58397836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) 58407836SJohn.Forte@Sun.COM lu = task->task_lu; 58417836SJohn.Forte@Sun.COM else 58427836SJohn.Forte@Sun.COM lu = dlun0; 58437836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)]; 58447836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 58457836SJohn.Forte@Sun.COM curcmd &= ITASK_CMD_MASK; 58467836SJohn.Forte@Sun.COM switch (curcmd) { 58477836SJohn.Forte@Sun.COM case ITASK_CMD_NEW_TASK: 58487836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 58497836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 58509435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_to_runq); 58519435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_to_runq); 58527836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) { 58537836SJohn.Forte@Sun.COM if (stmf_handle_cmd_during_ic(itask)) 58547836SJohn.Forte@Sun.COM break; 58557836SJohn.Forte@Sun.COM } 58567836SJohn.Forte@Sun.COM #ifdef DEBUG 58577836SJohn.Forte@Sun.COM if (stmf_drop_task_counter > 0) { 58587836SJohn.Forte@Sun.COM if (atomic_add_32_nv( 58597836SJohn.Forte@Sun.COM (uint32_t *)&stmf_drop_task_counter, 58607836SJohn.Forte@Sun.COM -1) == 1) { 58617836SJohn.Forte@Sun.COM break; 58627836SJohn.Forte@Sun.COM } 58637836SJohn.Forte@Sun.COM } 58647836SJohn.Forte@Sun.COM #endif 58658859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task); 58667836SJohn.Forte@Sun.COM lu->lu_new_task(task, dbuf); 58677836SJohn.Forte@Sun.COM break; 58687836SJohn.Forte@Sun.COM case ITASK_CMD_DATA_XFER_DONE: 58697836SJohn.Forte@Sun.COM lu->lu_dbuf_xfer_done(task, dbuf); 58707836SJohn.Forte@Sun.COM break; 58717836SJohn.Forte@Sun.COM case ITASK_CMD_STATUS_DONE: 58727836SJohn.Forte@Sun.COM lu->lu_send_status_done(task); 58737836SJohn.Forte@Sun.COM break; 58747836SJohn.Forte@Sun.COM case ITASK_CMD_ABORT: 58757836SJohn.Forte@Sun.COM if (abort_free) { 58767836SJohn.Forte@Sun.COM stmf_task_free(task); 58777836SJohn.Forte@Sun.COM } else { 58787836SJohn.Forte@Sun.COM stmf_do_task_abort(task); 58797836SJohn.Forte@Sun.COM } 58807836SJohn.Forte@Sun.COM break; 58817836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LU: 58827836SJohn.Forte@Sun.COM if (!wait_queue) { 58837836SJohn.Forte@Sun.COM lu->lu_task_poll(task); 58847836SJohn.Forte@Sun.COM } 58857836SJohn.Forte@Sun.COM break; 58867836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LPORT: 58877836SJohn.Forte@Sun.COM if (!wait_queue) 58887836SJohn.Forte@Sun.COM task->task_lport->lport_task_poll(task); 58897836SJohn.Forte@Sun.COM break; 58907836SJohn.Forte@Sun.COM case ITASK_CMD_SEND_STATUS: 58917836SJohn.Forte@Sun.COM /* case ITASK_CMD_XFER_DATA: */ 58927836SJohn.Forte@Sun.COM break; 58937836SJohn.Forte@Sun.COM } 58947836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 58957836SJohn.Forte@Sun.COM if (dec_qdepth) { 58967836SJohn.Forte@Sun.COM w->worker_queue_depth--; 58977836SJohn.Forte@Sun.COM } 58987836SJohn.Forte@Sun.COM } 58997836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) { 59007836SJohn.Forte@Sun.COM if (w->worker_ref_count == 0) 59017836SJohn.Forte@Sun.COM goto stmf_worker_loop; 59027836SJohn.Forte@Sun.COM else 59037836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + 1; 59047836SJohn.Forte@Sun.COM } 59057836SJohn.Forte@Sun.COM w->worker_flags &= ~STMF_WORKER_ACTIVE; 59067836SJohn.Forte@Sun.COM if (wait_timer) { 59077836SJohn.Forte@Sun.COM (void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer); 59087836SJohn.Forte@Sun.COM } else { 59097836SJohn.Forte@Sun.COM cv_wait(&w->worker_cv, &w->worker_lock); 59107836SJohn.Forte@Sun.COM } 59117836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_ACTIVE; 59127836SJohn.Forte@Sun.COM goto stmf_worker_loop; 59137836SJohn.Forte@Sun.COM } 59147836SJohn.Forte@Sun.COM 59157836SJohn.Forte@Sun.COM void 59167836SJohn.Forte@Sun.COM stmf_worker_mgmt() 59177836SJohn.Forte@Sun.COM { 59187836SJohn.Forte@Sun.COM int i; 59197836SJohn.Forte@Sun.COM int workers_needed; 59207836SJohn.Forte@Sun.COM uint32_t qd; 59217836SJohn.Forte@Sun.COM clock_t tps, d = 0; 59227836SJohn.Forte@Sun.COM uint32_t cur_max_ntasks = 0; 59237836SJohn.Forte@Sun.COM stmf_worker_t *w; 59247836SJohn.Forte@Sun.COM 59257836SJohn.Forte@Sun.COM /* Check if we are trying to increase the # of threads */ 59267836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) { 59277836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) { 59287836SJohn.Forte@Sun.COM stmf_nworkers_cur++; 59297836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds++; 59307836SJohn.Forte@Sun.COM } else { 59317836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 59327836SJohn.Forte@Sun.COM return; 59337836SJohn.Forte@Sun.COM } 59347836SJohn.Forte@Sun.COM } 59357836SJohn.Forte@Sun.COM /* Check if we are trying to decrease the # of workers */ 59367836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 59377836SJohn.Forte@Sun.COM if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) { 59387836SJohn.Forte@Sun.COM stmf_nworkers_cur--; 59397836SJohn.Forte@Sun.COM /* 59407836SJohn.Forte@Sun.COM * stmf_nworkers_accepting_cmds has already been 59417836SJohn.Forte@Sun.COM * updated by the request to reduce the # of workers. 59427836SJohn.Forte@Sun.COM */ 59437836SJohn.Forte@Sun.COM } else { 59447836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 59457836SJohn.Forte@Sun.COM return; 59467836SJohn.Forte@Sun.COM } 59477836SJohn.Forte@Sun.COM } 59487836SJohn.Forte@Sun.COM /* Check if we are being asked to quit */ 59497836SJohn.Forte@Sun.COM if (stmf_workers_state != STMF_WORKERS_ENABLED) { 59507836SJohn.Forte@Sun.COM if (stmf_nworkers_cur) { 59517836SJohn.Forte@Sun.COM workers_needed = 0; 59527836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 59537836SJohn.Forte@Sun.COM } 59547836SJohn.Forte@Sun.COM return; 59557836SJohn.Forte@Sun.COM } 59567836SJohn.Forte@Sun.COM /* Check if we are starting */ 59577836SJohn.Forte@Sun.COM if (stmf_nworkers_cur < stmf_i_min_nworkers) { 59587836SJohn.Forte@Sun.COM workers_needed = stmf_i_min_nworkers; 59597836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 59607836SJohn.Forte@Sun.COM } 59617836SJohn.Forte@Sun.COM 59627836SJohn.Forte@Sun.COM tps = drv_usectohz(1 * 1000 * 1000); 59637836SJohn.Forte@Sun.COM if ((stmf_wm_last != 0) && 59647836SJohn.Forte@Sun.COM ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) { 59657836SJohn.Forte@Sun.COM qd = 0; 59667836SJohn.Forte@Sun.COM for (i = 0; i < stmf_nworkers_accepting_cmds; i++) { 59677836SJohn.Forte@Sun.COM qd += stmf_workers[i].worker_max_qdepth_pu; 59687836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_qdepth_pu = 0; 59697836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_max_sys_qdepth_pu > 59707836SJohn.Forte@Sun.COM cur_max_ntasks) { 59717836SJohn.Forte@Sun.COM cur_max_ntasks = 59727836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu; 59737836SJohn.Forte@Sun.COM } 59747836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu = 0; 59757836SJohn.Forte@Sun.COM } 59767836SJohn.Forte@Sun.COM } 59777836SJohn.Forte@Sun.COM stmf_wm_last = ddi_get_lbolt(); 59787836SJohn.Forte@Sun.COM if (d <= tps) { 59797836SJohn.Forte@Sun.COM /* still ramping up */ 59807836SJohn.Forte@Sun.COM return; 59817836SJohn.Forte@Sun.COM } 59827836SJohn.Forte@Sun.COM /* max qdepth cannot be more than max tasks */ 59837836SJohn.Forte@Sun.COM if (qd > cur_max_ntasks) 59847836SJohn.Forte@Sun.COM qd = cur_max_ntasks; 59857836SJohn.Forte@Sun.COM 59867836SJohn.Forte@Sun.COM /* See if we have more workers */ 59877836SJohn.Forte@Sun.COM if (qd < stmf_nworkers_accepting_cmds) { 59887836SJohn.Forte@Sun.COM /* 59897836SJohn.Forte@Sun.COM * Since we dont reduce the worker count right away, monitor 59907836SJohn.Forte@Sun.COM * the highest load during the scale_down_delay. 59917836SJohn.Forte@Sun.COM */ 59927836SJohn.Forte@Sun.COM if (qd > stmf_worker_scale_down_qd) 59937836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = qd; 59947836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_timer == 0) { 59957836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = ddi_get_lbolt() + 59967836SJohn.Forte@Sun.COM drv_usectohz(stmf_worker_scale_down_delay * 59977836SJohn.Forte@Sun.COM 1000 * 1000); 59987836SJohn.Forte@Sun.COM return; 59997836SJohn.Forte@Sun.COM } 60007836SJohn.Forte@Sun.COM if (ddi_get_lbolt() < stmf_worker_scale_down_timer) { 60017836SJohn.Forte@Sun.COM return; 60027836SJohn.Forte@Sun.COM } 60037836SJohn.Forte@Sun.COM /* Its time to reduce the workers */ 60047836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd < stmf_i_min_nworkers) 60057836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_min_nworkers; 60067836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd > stmf_i_max_nworkers) 60077836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_max_nworkers; 60087836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd == stmf_nworkers_cur) 60097836SJohn.Forte@Sun.COM return; 60107836SJohn.Forte@Sun.COM workers_needed = stmf_worker_scale_down_qd; 60117836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 60127836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 60137836SJohn.Forte@Sun.COM } 60147836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 60157836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = 0; 60167836SJohn.Forte@Sun.COM if (qd > stmf_i_max_nworkers) 60177836SJohn.Forte@Sun.COM qd = stmf_i_max_nworkers; 60187836SJohn.Forte@Sun.COM if (qd < stmf_i_min_nworkers) 60197836SJohn.Forte@Sun.COM qd = stmf_i_min_nworkers; 60207836SJohn.Forte@Sun.COM if (qd == stmf_nworkers_cur) 60217836SJohn.Forte@Sun.COM return; 60227836SJohn.Forte@Sun.COM workers_needed = qd; 60237836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 60247836SJohn.Forte@Sun.COM 60257836SJohn.Forte@Sun.COM /* NOTREACHED */ 60267836SJohn.Forte@Sun.COM return; 60277836SJohn.Forte@Sun.COM 60287836SJohn.Forte@Sun.COM worker_mgmt_trigger_change: 60297836SJohn.Forte@Sun.COM ASSERT(workers_needed != stmf_nworkers_cur); 60307836SJohn.Forte@Sun.COM if (workers_needed > stmf_nworkers_cur) { 60317836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 60327836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < workers_needed; i++) { 60337836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 60347836SJohn.Forte@Sun.COM w->worker_tid = thread_create(NULL, 0, stmf_worker_task, 60357836SJohn.Forte@Sun.COM (void *)&stmf_workers[i], 0, &p0, TS_RUN, 60367836SJohn.Forte@Sun.COM minclsyspri); 60377836SJohn.Forte@Sun.COM } 60387836SJohn.Forte@Sun.COM return; 60397836SJohn.Forte@Sun.COM } 60407836SJohn.Forte@Sun.COM /* At this point we know that we are decreasing the # of workers */ 60417836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds = workers_needed; 60427836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 60437836SJohn.Forte@Sun.COM /* Signal the workers that its time to quit */ 60447836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 60457836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 60467836SJohn.Forte@Sun.COM ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED)); 60477836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 60487836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_TERMINATE; 60497836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 60507836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 60517836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 60527836SJohn.Forte@Sun.COM } 60537836SJohn.Forte@Sun.COM } 60547836SJohn.Forte@Sun.COM 60557836SJohn.Forte@Sun.COM /* 60567836SJohn.Forte@Sun.COM * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private). 60577836SJohn.Forte@Sun.COM * If all the data has been filled out, frees the xd and makes 60587836SJohn.Forte@Sun.COM * db_lu_private NULL. 60597836SJohn.Forte@Sun.COM */ 60607836SJohn.Forte@Sun.COM void 60617836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf) 60627836SJohn.Forte@Sun.COM { 60637836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 60647836SJohn.Forte@Sun.COM uint8_t *p; 60657836SJohn.Forte@Sun.COM int i; 60667836SJohn.Forte@Sun.COM uint32_t s; 60677836SJohn.Forte@Sun.COM 60687836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 60697836SJohn.Forte@Sun.COM dbuf->db_data_size = 0; 60707836SJohn.Forte@Sun.COM dbuf->db_relative_offset = xd->size_done; 60717836SJohn.Forte@Sun.COM for (i = 0; i < dbuf->db_sglist_length; i++) { 60727836SJohn.Forte@Sun.COM s = min(xd->size_left, dbuf->db_sglist[i].seg_length); 60737836SJohn.Forte@Sun.COM p = &xd->buf[xd->size_done]; 60747836SJohn.Forte@Sun.COM bcopy(p, dbuf->db_sglist[i].seg_addr, s); 60757836SJohn.Forte@Sun.COM xd->size_left -= s; 60767836SJohn.Forte@Sun.COM xd->size_done += s; 60777836SJohn.Forte@Sun.COM dbuf->db_data_size += s; 60787836SJohn.Forte@Sun.COM if (xd->size_left == 0) { 60797836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 60807836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 60817836SJohn.Forte@Sun.COM return; 60827836SJohn.Forte@Sun.COM } 60837836SJohn.Forte@Sun.COM } 60847836SJohn.Forte@Sun.COM } 60857836SJohn.Forte@Sun.COM 60867836SJohn.Forte@Sun.COM /* ARGSUSED */ 60877836SJohn.Forte@Sun.COM stmf_status_t 60887836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task) 60897836SJohn.Forte@Sun.COM { 60907836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 60917836SJohn.Forte@Sun.COM } 60927836SJohn.Forte@Sun.COM 60937836SJohn.Forte@Sun.COM void 60947836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 60957836SJohn.Forte@Sun.COM { 60967836SJohn.Forte@Sun.COM uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; 60977836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 60987836SJohn.Forte@Sun.COM uint32_t sz, minsz; 60997836SJohn.Forte@Sun.COM uint8_t *p; 61007836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 61017836SJohn.Forte@Sun.COM uint8_t inq_page_length = 31; 61027836SJohn.Forte@Sun.COM 61037836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 61047836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(task); 61057836SJohn.Forte@Sun.COM return; 61067836SJohn.Forte@Sun.COM } 61077836SJohn.Forte@Sun.COM 61087836SJohn.Forte@Sun.COM switch (cdbp[0]) { 61097836SJohn.Forte@Sun.COM case SCMD_INQUIRY: 61107836SJohn.Forte@Sun.COM /* 61117836SJohn.Forte@Sun.COM * Basic protocol checks. In addition, only reply to 61127836SJohn.Forte@Sun.COM * standard inquiry. Otherwise, the LU provider needs 61137836SJohn.Forte@Sun.COM * to respond. 61147836SJohn.Forte@Sun.COM */ 61157836SJohn.Forte@Sun.COM 61167836SJohn.Forte@Sun.COM if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) { 61177836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 61187836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 61197836SJohn.Forte@Sun.COM return; 61207836SJohn.Forte@Sun.COM } 61217836SJohn.Forte@Sun.COM 61227836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 61237836SJohn.Forte@Sun.COM (((uint32_t)cdbp[3]) << 8) | cdbp[4]; 61247836SJohn.Forte@Sun.COM 61257836SJohn.Forte@Sun.COM if (task->task_additional_flags & 61267836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 61277836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 61287836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 61297836SJohn.Forte@Sun.COM } 61307836SJohn.Forte@Sun.COM 61317836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 61327836SJohn.Forte@Sun.COM min(36, task->task_cmd_xfer_length)); 61337836SJohn.Forte@Sun.COM minsz = 36; 61347836SJohn.Forte@Sun.COM 61357836SJohn.Forte@Sun.COM if (sz == 0) { 61367836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 61377836SJohn.Forte@Sun.COM return; 61387836SJohn.Forte@Sun.COM } 61397836SJohn.Forte@Sun.COM 61407836SJohn.Forte@Sun.COM if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) { 61417836SJohn.Forte@Sun.COM /* 61427836SJohn.Forte@Sun.COM * Ignore any preallocated dbuf if the size is less 61437836SJohn.Forte@Sun.COM * than 36. It will be freed during the task_free. 61447836SJohn.Forte@Sun.COM */ 61457836SJohn.Forte@Sun.COM dbuf = NULL; 61467836SJohn.Forte@Sun.COM } 61477836SJohn.Forte@Sun.COM if (dbuf == NULL) 61487836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0); 61497836SJohn.Forte@Sun.COM if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) { 61507836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 61517836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 61527836SJohn.Forte@Sun.COM return; 61537836SJohn.Forte@Sun.COM } 61547836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 61557836SJohn.Forte@Sun.COM 61567836SJohn.Forte@Sun.COM p = dbuf->db_sglist[0].seg_addr; 61577836SJohn.Forte@Sun.COM 61587836SJohn.Forte@Sun.COM /* 61597836SJohn.Forte@Sun.COM * Standard inquiry handling only. 61607836SJohn.Forte@Sun.COM */ 61617836SJohn.Forte@Sun.COM 61627836SJohn.Forte@Sun.COM bzero(p, inq_page_length + 5); 61637836SJohn.Forte@Sun.COM 61647836SJohn.Forte@Sun.COM p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN; 61657836SJohn.Forte@Sun.COM p[2] = 5; 61667836SJohn.Forte@Sun.COM p[3] = 0x12; 61677836SJohn.Forte@Sun.COM p[4] = inq_page_length; 61687836SJohn.Forte@Sun.COM p[6] = 0x80; 61697836SJohn.Forte@Sun.COM 61707836SJohn.Forte@Sun.COM (void) strncpy((char *)p+8, "SUN ", 8); 61717836SJohn.Forte@Sun.COM (void) strncpy((char *)p+16, "COMSTAR ", 16); 61727836SJohn.Forte@Sun.COM (void) strncpy((char *)p+32, "1.0 ", 4); 61737836SJohn.Forte@Sun.COM 61747836SJohn.Forte@Sun.COM dbuf->db_data_size = sz; 61757836SJohn.Forte@Sun.COM dbuf->db_relative_offset = 0; 61767836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 61777836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 61787836SJohn.Forte@Sun.COM 61797836SJohn.Forte@Sun.COM return; 61807836SJohn.Forte@Sun.COM 61817836SJohn.Forte@Sun.COM case SCMD_REPORT_LUNS: 61827836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 61837836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 61847836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 61857836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 61867836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 61877836SJohn.Forte@Sun.COM 61887836SJohn.Forte@Sun.COM if (task->task_additional_flags & 61897836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 61907836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 61917836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 61927836SJohn.Forte@Sun.COM } 61937836SJohn.Forte@Sun.COM 61947836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 61957836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 61967836SJohn.Forte@Sun.COM 61977836SJohn.Forte@Sun.COM if (sz < 16) { 61987836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 61998662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 62007836SJohn.Forte@Sun.COM return; 62017836SJohn.Forte@Sun.COM } 62027836SJohn.Forte@Sun.COM 62037836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 62047836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 62057836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 62067836SJohn.Forte@Sun.COM xd = stmf_session_prepare_report_lun_data(iss->iss_sm); 62077836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 62087836SJohn.Forte@Sun.COM 62097836SJohn.Forte@Sun.COM if (xd == NULL) { 62107836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 62117836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 62127836SJohn.Forte@Sun.COM return; 62137836SJohn.Forte@Sun.COM } 62147836SJohn.Forte@Sun.COM 62157836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 62167836SJohn.Forte@Sun.COM xd->size_left = sz; 62177836SJohn.Forte@Sun.COM minsz = min(512, sz); 62187836SJohn.Forte@Sun.COM 62197836SJohn.Forte@Sun.COM if (dbuf == NULL) 62207836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 62217836SJohn.Forte@Sun.COM if (dbuf == NULL) { 62227836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 62237836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 62247836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 62257836SJohn.Forte@Sun.COM return; 62267836SJohn.Forte@Sun.COM } 62277836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 62287836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 62297836SJohn.Forte@Sun.COM 62307836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 62318662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 62327836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 62337836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 62347836SJohn.Forte@Sun.COM return; 62357836SJohn.Forte@Sun.COM } 62367836SJohn.Forte@Sun.COM 62377836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE); 62387836SJohn.Forte@Sun.COM } 62397836SJohn.Forte@Sun.COM 62407836SJohn.Forte@Sun.COM void 62417836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf) 62427836SJohn.Forte@Sun.COM { 624310725SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 624410725SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 624510725SJohn.Forte@Sun.COM 62467836SJohn.Forte@Sun.COM if (dbuf->db_xfer_status != STMF_SUCCESS) { 62477836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 62487836SJohn.Forte@Sun.COM dbuf->db_xfer_status, NULL); 62497836SJohn.Forte@Sun.COM return; 62507836SJohn.Forte@Sun.COM } 62517836SJohn.Forte@Sun.COM task->task_nbytes_transferred = dbuf->db_data_size; 62527836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 62537836SJohn.Forte@Sun.COM /* There is more */ 62547836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 62557836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 62567836SJohn.Forte@Sun.COM return; 62577836SJohn.Forte@Sun.COM } 625810725SJohn.Forte@Sun.COM /* 625910725SJohn.Forte@Sun.COM * If this is a proxy task, it will need to be completed from the 626010725SJohn.Forte@Sun.COM * proxy port provider. This message lets pppt know that the xfer 626110725SJohn.Forte@Sun.COM * is complete. When we receive the status from pppt, we will 626210725SJohn.Forte@Sun.COM * then relay that status back to the lport. 626310725SJohn.Forte@Sun.COM */ 626410725SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_PROXY_TASK) { 626510725SJohn.Forte@Sun.COM stmf_ic_msg_t *ic_xfer_done_msg = NULL; 626610725SJohn.Forte@Sun.COM stmf_status_t ic_ret = STMF_FAILURE; 626710725SJohn.Forte@Sun.COM uint64_t session_msg_id; 626810725SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 626910725SJohn.Forte@Sun.COM session_msg_id = stmf_proxy_msg_id++; 627010725SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 627110725SJohn.Forte@Sun.COM /* send xfer done status to pppt */ 627210725SJohn.Forte@Sun.COM ic_xfer_done_msg = ic_scsi_data_xfer_done_msg_alloc( 627310725SJohn.Forte@Sun.COM itask->itask_proxy_msg_id, 627410725SJohn.Forte@Sun.COM task->task_session->ss_session_id, 627510725SJohn.Forte@Sun.COM STMF_SUCCESS, session_msg_id); 627610725SJohn.Forte@Sun.COM if (ic_xfer_done_msg) { 627710725SJohn.Forte@Sun.COM ic_ret = ic_tx_msg(ic_xfer_done_msg); 627810725SJohn.Forte@Sun.COM if (ic_ret != STMF_IC_MSG_SUCCESS) { 627910725SJohn.Forte@Sun.COM cmn_err(CE_WARN, "unable to xmit session msg"); 628010725SJohn.Forte@Sun.COM } 628110725SJohn.Forte@Sun.COM } 628210725SJohn.Forte@Sun.COM /* task will be completed from pppt */ 628310725SJohn.Forte@Sun.COM return; 628410725SJohn.Forte@Sun.COM } 62857836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 62867836SJohn.Forte@Sun.COM } 62877836SJohn.Forte@Sun.COM 62887836SJohn.Forte@Sun.COM /* ARGSUSED */ 62897836SJohn.Forte@Sun.COM void 62907836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task) 62917836SJohn.Forte@Sun.COM { 62927836SJohn.Forte@Sun.COM } 62937836SJohn.Forte@Sun.COM 62947836SJohn.Forte@Sun.COM /* ARGSUSED */ 62957836SJohn.Forte@Sun.COM void 62967836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task) 62977836SJohn.Forte@Sun.COM { 62987836SJohn.Forte@Sun.COM } 62997836SJohn.Forte@Sun.COM 63007836SJohn.Forte@Sun.COM /* ARGSUSED */ 63017836SJohn.Forte@Sun.COM stmf_status_t 63027836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags) 63037836SJohn.Forte@Sun.COM { 63047836SJohn.Forte@Sun.COM scsi_task_t *task = (scsi_task_t *)arg; 63057836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 63068662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 63077836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 63087836SJohn.Forte@Sun.COM int i; 63097836SJohn.Forte@Sun.COM uint8_t map; 63107836SJohn.Forte@Sun.COM 63117836SJohn.Forte@Sun.COM ASSERT(abort_cmd == STMF_LU_ABORT_TASK); 63127836SJohn.Forte@Sun.COM if ((task->task_mgmt_function) && (itask->itask_flags & 63137836SJohn.Forte@Sun.COM (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) { 63147836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 63157836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 63167836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 63177836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 63187836SJohn.Forte@Sun.COM case TM_LUN_RESET: 63197836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 63207836SJohn.Forte@Sun.COM break; 63217836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 63227836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 63237836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 63247836SJohn.Forte@Sun.COM stmf_abort_target_reset(task); 63257836SJohn.Forte@Sun.COM break; 63267836SJohn.Forte@Sun.COM } 63277836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 63287836SJohn.Forte@Sun.COM } 63297836SJohn.Forte@Sun.COM 63307836SJohn.Forte@Sun.COM /* 63317836SJohn.Forte@Sun.COM * OK so its not a task mgmt. Make sure we free any xd sitting 63327836SJohn.Forte@Sun.COM * inside any dbuf. 63337836SJohn.Forte@Sun.COM */ 63347836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 63357836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 63367836SJohn.Forte@Sun.COM if ((map & 1) && 63377836SJohn.Forte@Sun.COM ((itask->itask_dbufs[i])->db_lu_private)) { 63387836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 63397836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 63407836SJohn.Forte@Sun.COM 63417836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 63427836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 63437836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 63447836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 63457836SJohn.Forte@Sun.COM } 63467836SJohn.Forte@Sun.COM map >>= 1; 63477836SJohn.Forte@Sun.COM } 63487836SJohn.Forte@Sun.COM } 63497836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 63507836SJohn.Forte@Sun.COM } 63517836SJohn.Forte@Sun.COM 63527836SJohn.Forte@Sun.COM void 63537836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task) 63547836SJohn.Forte@Sun.COM { 63557836SJohn.Forte@Sun.COM /* Right now we only do this for handling task management functions */ 63567836SJohn.Forte@Sun.COM ASSERT(task->task_mgmt_function); 63577836SJohn.Forte@Sun.COM 63587836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 63597836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 63607836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 63617836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 63627836SJohn.Forte@Sun.COM case TM_LUN_RESET: 63637836SJohn.Forte@Sun.COM (void) stmf_lun_reset_poll(task->task_lu, task, 0); 63647836SJohn.Forte@Sun.COM return; 63657836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 63667836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 63677836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 63687836SJohn.Forte@Sun.COM stmf_target_reset_poll(task); 63697836SJohn.Forte@Sun.COM return; 63707836SJohn.Forte@Sun.COM } 63717836SJohn.Forte@Sun.COM } 63727836SJohn.Forte@Sun.COM 63737836SJohn.Forte@Sun.COM /* ARGSUSED */ 63747836SJohn.Forte@Sun.COM void 63757836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg) 63767836SJohn.Forte@Sun.COM { 63777836SJohn.Forte@Sun.COM /* This function will never be called */ 63787836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd); 63797836SJohn.Forte@Sun.COM } 63807836SJohn.Forte@Sun.COM 63817836SJohn.Forte@Sun.COM void 63827836SJohn.Forte@Sun.COM stmf_dlun_init() 63837836SJohn.Forte@Sun.COM { 63847836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 63857836SJohn.Forte@Sun.COM 63867836SJohn.Forte@Sun.COM dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0); 63877836SJohn.Forte@Sun.COM dlun0->lu_task_alloc = stmf_dlun0_task_alloc; 63887836SJohn.Forte@Sun.COM dlun0->lu_new_task = stmf_dlun0_new_task; 63897836SJohn.Forte@Sun.COM dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done; 63907836SJohn.Forte@Sun.COM dlun0->lu_send_status_done = stmf_dlun0_status_done; 63917836SJohn.Forte@Sun.COM dlun0->lu_task_free = stmf_dlun0_task_free; 63927836SJohn.Forte@Sun.COM dlun0->lu_abort = stmf_dlun0_abort; 63937836SJohn.Forte@Sun.COM dlun0->lu_task_poll = stmf_dlun0_task_poll; 63947836SJohn.Forte@Sun.COM dlun0->lu_ctl = stmf_dlun0_ctl; 63957836SJohn.Forte@Sun.COM 63967836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 63977836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 63987836SJohn.Forte@Sun.COM } 63997836SJohn.Forte@Sun.COM 64007836SJohn.Forte@Sun.COM stmf_status_t 64017836SJohn.Forte@Sun.COM stmf_dlun_fini() 64027836SJohn.Forte@Sun.COM { 64037836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 64047836SJohn.Forte@Sun.COM 64057836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 64067836SJohn.Forte@Sun.COM 64077836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 64087836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 64097836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 64107836SJohn.Forte@Sun.COM 64117836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 64127836SJohn.Forte@Sun.COM do { 64137836SJohn.Forte@Sun.COM itask = nitask; 64147836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 64157836SJohn.Forte@Sun.COM dlun0->lu_task_free(itask->itask_task); 64167836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 64177836SJohn.Forte@Sun.COM } while (nitask != NULL); 64187836SJohn.Forte@Sun.COM 64197836SJohn.Forte@Sun.COM } 64207836SJohn.Forte@Sun.COM stmf_free(dlun0); 64217836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 64227836SJohn.Forte@Sun.COM } 64237836SJohn.Forte@Sun.COM 64247836SJohn.Forte@Sun.COM void 64257836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task) 64267836SJohn.Forte@Sun.COM { 64277836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 64288662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 64297836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 64307836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 64317836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 64327836SJohn.Forte@Sun.COM int i; 64337836SJohn.Forte@Sun.COM 64347836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 64357836SJohn.Forte@Sun.COM 64367836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 64377836SJohn.Forte@Sun.COM lm = iss->iss_sm; 64387836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 64397836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 64407836SJohn.Forte@Sun.COM continue; 64417836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 64427836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 64437836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 64447836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 64457836SJohn.Forte@Sun.COM } 64467836SJohn.Forte@Sun.COM } 64477836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 64487836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 64497836SJohn.Forte@Sun.COM } 64507836SJohn.Forte@Sun.COM 64517836SJohn.Forte@Sun.COM /* 64527836SJohn.Forte@Sun.COM * The return value is only used by function managing target reset. 64537836SJohn.Forte@Sun.COM */ 64547836SJohn.Forte@Sun.COM stmf_status_t 64557836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset) 64567836SJohn.Forte@Sun.COM { 64577836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 64587836SJohn.Forte@Sun.COM int ntasks_pending; 64597836SJohn.Forte@Sun.COM 64607836SJohn.Forte@Sun.COM ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free; 64617836SJohn.Forte@Sun.COM /* 64627836SJohn.Forte@Sun.COM * This function is also used during Target reset. The idea is that 64637836SJohn.Forte@Sun.COM * once all the commands are aborted, call the LU's reset entry 64647836SJohn.Forte@Sun.COM * point (abort entry point with a reset flag). But if this Task 64657836SJohn.Forte@Sun.COM * mgmt is running on this LU then all the tasks cannot be aborted. 64667836SJohn.Forte@Sun.COM * one task (this task) will still be running which is OK. 64677836SJohn.Forte@Sun.COM */ 64687836SJohn.Forte@Sun.COM if ((ntasks_pending == 0) || ((task->task_lu == lu) && 64697836SJohn.Forte@Sun.COM (ntasks_pending == 1))) { 64707836SJohn.Forte@Sun.COM stmf_status_t ret; 64717836SJohn.Forte@Sun.COM 64727836SJohn.Forte@Sun.COM if ((task->task_mgmt_function == TM_LUN_RESET) || 64737836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_RESET) || 64747836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_WARM_RESET) || 64757836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_COLD_RESET)) { 64767836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0); 64777836SJohn.Forte@Sun.COM } else { 64787836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 64797836SJohn.Forte@Sun.COM } 64807836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 64817836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 64827836SJohn.Forte@Sun.COM } 64837836SJohn.Forte@Sun.COM if (target_reset) { 64847836SJohn.Forte@Sun.COM return (ret); 64857836SJohn.Forte@Sun.COM } 64867836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 64877836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 64887836SJohn.Forte@Sun.COM return (ret); 64897836SJohn.Forte@Sun.COM } 64907836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 64917836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL); 64927836SJohn.Forte@Sun.COM return (ret); 64937836SJohn.Forte@Sun.COM } 64947836SJohn.Forte@Sun.COM } 64957836SJohn.Forte@Sun.COM 64967836SJohn.Forte@Sun.COM if (target_reset) { 64977836SJohn.Forte@Sun.COM /* Tell target reset polling code that we are not done */ 64987836SJohn.Forte@Sun.COM return (STMF_BUSY); 64997836SJohn.Forte@Sun.COM } 65007836SJohn.Forte@Sun.COM 65017836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 65027836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 65037836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 65047836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 65057836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 65067836SJohn.Forte@Sun.COM } 65077836SJohn.Forte@Sun.COM 65087836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 65097836SJohn.Forte@Sun.COM } 65107836SJohn.Forte@Sun.COM 65117836SJohn.Forte@Sun.COM void 65127836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task) 65137836SJohn.Forte@Sun.COM { 65147836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 65158662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 65167836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 65177836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 65187836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 65197836SJohn.Forte@Sun.COM stmf_status_t ret; 65207836SJohn.Forte@Sun.COM int i; 65217836SJohn.Forte@Sun.COM int not_done = 0; 65227836SJohn.Forte@Sun.COM 65237836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 65247836SJohn.Forte@Sun.COM 65257836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 65267836SJohn.Forte@Sun.COM lm = iss->iss_sm; 65277836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 65287836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 65297836SJohn.Forte@Sun.COM continue; 65307836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 65317836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 65327836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 65337836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 65347836SJohn.Forte@Sun.COM ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1); 65357836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 65367836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) 65377836SJohn.Forte@Sun.COM continue; 65387836SJohn.Forte@Sun.COM not_done = 1; 65397836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 65407836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 65417836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 65427836SJohn.Forte@Sun.COM STMF_ABORTED, NULL); 65437836SJohn.Forte@Sun.COM return; 65447836SJohn.Forte@Sun.COM } 65457836SJohn.Forte@Sun.COM } 65467836SJohn.Forte@Sun.COM } 65477836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 65487836SJohn.Forte@Sun.COM 65497836SJohn.Forte@Sun.COM if (not_done) { 65507836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 65517836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 65527836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 65537836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 65547836SJohn.Forte@Sun.COM return; 65557836SJohn.Forte@Sun.COM } 65567836SJohn.Forte@Sun.COM return; 65577836SJohn.Forte@Sun.COM } 65587836SJohn.Forte@Sun.COM 65597836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 65607836SJohn.Forte@Sun.COM 65617836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 65627836SJohn.Forte@Sun.COM } 65637836SJohn.Forte@Sun.COM 65647836SJohn.Forte@Sun.COM stmf_status_t 65657836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid) 65667836SJohn.Forte@Sun.COM { 65677836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 65687836SJohn.Forte@Sun.COM 65697836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 65707836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 65717836SJohn.Forte@Sun.COM } 65727836SJohn.Forte@Sun.COM 65737836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid); 65747836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 65757836SJohn.Forte@Sun.COM } 65767836SJohn.Forte@Sun.COM 65777836SJohn.Forte@Sun.COM stmf_status_t 65787836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid) 65797836SJohn.Forte@Sun.COM { 65807836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 65817836SJohn.Forte@Sun.COM 65827836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 65837836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl); 65847836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 65857836SJohn.Forte@Sun.COM } 65867836SJohn.Forte@Sun.COM 65877836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 65887836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 65897836SJohn.Forte@Sun.COM } 65907836SJohn.Forte@Sun.COM 65917836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid); 65927836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 65937836SJohn.Forte@Sun.COM } 65947836SJohn.Forte@Sun.COM 65957836SJohn.Forte@Sun.COM stmf_status_t 65967836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid) 65977836SJohn.Forte@Sun.COM { 65987836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 65998662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 66007836SJohn.Forte@Sun.COM 66017836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 66027836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 66037836SJohn.Forte@Sun.COM } 66047836SJohn.Forte@Sun.COM 66057836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid); 66067836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 66077836SJohn.Forte@Sun.COM } 66087836SJohn.Forte@Sun.COM 66097836SJohn.Forte@Sun.COM stmf_status_t 66107836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid) 66117836SJohn.Forte@Sun.COM { 66127836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 66138662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 66147836SJohn.Forte@Sun.COM 66157836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 66167836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl); 66177836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 66187836SJohn.Forte@Sun.COM } 66197836SJohn.Forte@Sun.COM 66207836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 66217836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 66227836SJohn.Forte@Sun.COM } 66237836SJohn.Forte@Sun.COM 66247836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid); 66257836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 66267836SJohn.Forte@Sun.COM } 66277836SJohn.Forte@Sun.COM 66287836SJohn.Forte@Sun.COM void 66297836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags) 66307836SJohn.Forte@Sun.COM { 66317836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) && 66327836SJohn.Forte@Sun.COM (ilu->ilu_lu->lu_event_handler != NULL)) { 66337836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags); 66347836SJohn.Forte@Sun.COM } 66357836SJohn.Forte@Sun.COM } 66367836SJohn.Forte@Sun.COM 66377836SJohn.Forte@Sun.COM void 66387836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg, 66397836SJohn.Forte@Sun.COM uint32_t flags) 66407836SJohn.Forte@Sun.COM { 66417836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) && 66427836SJohn.Forte@Sun.COM (ilport->ilport_lport->lport_event_handler != NULL)) { 66437836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_event_handler( 66447836SJohn.Forte@Sun.COM ilport->ilport_lport, eventid, arg, flags); 66457836SJohn.Forte@Sun.COM } 66467836SJohn.Forte@Sun.COM } 66477836SJohn.Forte@Sun.COM 66487836SJohn.Forte@Sun.COM void 66497836SJohn.Forte@Sun.COM stmf_svc_init() 66507836SJohn.Forte@Sun.COM { 66517836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 66527836SJohn.Forte@Sun.COM return; 66537836SJohn.Forte@Sun.COM stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1, 66547836SJohn.Forte@Sun.COM TASKQ_DEFAULTPRI, 0); 66557836SJohn.Forte@Sun.COM (void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq, 66567836SJohn.Forte@Sun.COM stmf_svc, 0, DDI_SLEEP); 66577836SJohn.Forte@Sun.COM } 66587836SJohn.Forte@Sun.COM 66597836SJohn.Forte@Sun.COM stmf_status_t 66607836SJohn.Forte@Sun.COM stmf_svc_fini() 66617836SJohn.Forte@Sun.COM { 66627836SJohn.Forte@Sun.COM uint32_t i; 66637836SJohn.Forte@Sun.COM 66647836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 66657836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) { 66667836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE; 66677836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 66687836SJohn.Forte@Sun.COM } 66697836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 66707836SJohn.Forte@Sun.COM 66717836SJohn.Forte@Sun.COM /* Wait for 5 seconds */ 66727836SJohn.Forte@Sun.COM for (i = 0; i < 500; i++) { 66737836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 66747836SJohn.Forte@Sun.COM delay(drv_usectohz(10000)); 66757836SJohn.Forte@Sun.COM else 66767836SJohn.Forte@Sun.COM break; 66777836SJohn.Forte@Sun.COM } 66787836SJohn.Forte@Sun.COM if (i == 500) 66797836SJohn.Forte@Sun.COM return (STMF_BUSY); 66807836SJohn.Forte@Sun.COM 66817836SJohn.Forte@Sun.COM ddi_taskq_destroy(stmf_state.stmf_svc_taskq); 66827836SJohn.Forte@Sun.COM 66837836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 66847836SJohn.Forte@Sun.COM } 66857836SJohn.Forte@Sun.COM 66867836SJohn.Forte@Sun.COM /* ARGSUSED */ 66877836SJohn.Forte@Sun.COM void 66887836SJohn.Forte@Sun.COM stmf_svc(void *arg) 66897836SJohn.Forte@Sun.COM { 66907836SJohn.Forte@Sun.COM stmf_svc_req_t *req, **preq; 66917836SJohn.Forte@Sun.COM clock_t td; 66927836SJohn.Forte@Sun.COM clock_t drain_start, drain_next = 0; 66937836SJohn.Forte@Sun.COM clock_t timing_start, timing_next = 0; 66947836SJohn.Forte@Sun.COM clock_t worker_delay = 0; 66957836SJohn.Forte@Sun.COM int deq; 66967836SJohn.Forte@Sun.COM stmf_lu_t *lu; 66977836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 66987836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 66997836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport, *next_ilport; 67007836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 67017836SJohn.Forte@Sun.COM 67027836SJohn.Forte@Sun.COM td = drv_usectohz(20000); 67037836SJohn.Forte@Sun.COM 67047836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 67057836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE; 67067836SJohn.Forte@Sun.COM 67077836SJohn.Forte@Sun.COM stmf_svc_loop: 67087836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) { 67097836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= 67107836SJohn.Forte@Sun.COM ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE); 67117836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 67127836SJohn.Forte@Sun.COM return; 67137836SJohn.Forte@Sun.COM } 67147836SJohn.Forte@Sun.COM 67157836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) { 67167836SJohn.Forte@Sun.COM int waitq_add = 0; 67177836SJohn.Forte@Sun.COM req = stmf_state.stmf_svc_active; 67187836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req->svc_next; 67197836SJohn.Forte@Sun.COM 67207836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 67217836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 67227836SJohn.Forte@Sun.COM /* Fallthrough */ 67237836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 67247836SJohn.Forte@Sun.COM /* Fallthrough */ 67257836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 67267836SJohn.Forte@Sun.COM /* Nothing to do */ 67277836SJohn.Forte@Sun.COM waitq_add = 1; 67287836SJohn.Forte@Sun.COM break; 67297836SJohn.Forte@Sun.COM 67307836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 67317836SJohn.Forte@Sun.COM /* Remove all mappings of this LU */ 67327836SJohn.Forte@Sun.COM stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj); 67337836SJohn.Forte@Sun.COM /* Kill all the pending I/Os for this LU */ 67347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 67357836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL, 67368662SJordan.Vaughan@Sun.com STMF_ABORTED); 67377836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 67387836SJohn.Forte@Sun.COM waitq_add = 1; 67397836SJohn.Forte@Sun.COM break; 67407836SJohn.Forte@Sun.COM default: 67417836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d", 67427836SJohn.Forte@Sun.COM req->svc_cmd); 67437836SJohn.Forte@Sun.COM } 67447836SJohn.Forte@Sun.COM 67457836SJohn.Forte@Sun.COM if (waitq_add) { 67467836SJohn.Forte@Sun.COM /* Put it in the wait queue */ 67477836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_waiting; 67487836SJohn.Forte@Sun.COM stmf_state.stmf_svc_waiting = req; 67497836SJohn.Forte@Sun.COM } 67507836SJohn.Forte@Sun.COM } 67517836SJohn.Forte@Sun.COM 67527836SJohn.Forte@Sun.COM /* The waiting list is not going to be modified by anybody else */ 67537836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 67547836SJohn.Forte@Sun.COM 67557836SJohn.Forte@Sun.COM for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) { 67567836SJohn.Forte@Sun.COM req = *preq; 67577836SJohn.Forte@Sun.COM deq = 0; 67587836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 67597836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 67607836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 67617836SJohn.Forte@Sun.COM deq = 1; 67627836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 67637836SJohn.Forte@Sun.COM break; 67647836SJohn.Forte@Sun.COM 67657836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 67667836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 67677836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 67687836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks != ilu->ilu_ntasks_free) 67697836SJohn.Forte@Sun.COM break; 67707836SJohn.Forte@Sun.COM deq = 1; 67717836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 67727836SJohn.Forte@Sun.COM break; 67737836SJohn.Forte@Sun.COM 67747836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 67757836SJohn.Forte@Sun.COM /* Fallthrough */ 67767836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 67777836SJohn.Forte@Sun.COM lport = (stmf_local_port_t *)req->svc_obj; 67787836SJohn.Forte@Sun.COM deq = 1; 67797836SJohn.Forte@Sun.COM lport->lport_ctl(lport, req->svc_cmd, &req->svc_info); 67807836SJohn.Forte@Sun.COM break; 67817836SJohn.Forte@Sun.COM } 67827836SJohn.Forte@Sun.COM if (deq) { 67837836SJohn.Forte@Sun.COM *preq = req->svc_next; 67847836SJohn.Forte@Sun.COM kmem_free(req, req->svc_req_alloc_size); 67857836SJohn.Forte@Sun.COM } else { 67867836SJohn.Forte@Sun.COM preq = &req->svc_next; 67877836SJohn.Forte@Sun.COM } 67887836SJohn.Forte@Sun.COM } 67897836SJohn.Forte@Sun.COM 67907836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 67917836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active == NULL) { 67927836SJohn.Forte@Sun.COM /* Do timeouts */ 67937836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 67947836SJohn.Forte@Sun.COM ((!timing_next) || (ddi_get_lbolt() >= timing_next))) { 67957836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 67967836SJohn.Forte@Sun.COM /* we are starting a new round */ 67977836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = 67987836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 67997836SJohn.Forte@Sun.COM timing_start = ddi_get_lbolt(); 68007836SJohn.Forte@Sun.COM } 68017836SJohn.Forte@Sun.COM stmf_check_ilu_timing(); 68027836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 68037836SJohn.Forte@Sun.COM /* we finished a complete round */ 68047836SJohn.Forte@Sun.COM timing_next = 68057836SJohn.Forte@Sun.COM timing_start + drv_usectohz(5*1000*1000); 68067836SJohn.Forte@Sun.COM } else { 68077836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 68087836SJohn.Forte@Sun.COM timing_next = 68097836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 68107836SJohn.Forte@Sun.COM } 68117836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 68127836SJohn.Forte@Sun.COM goto stmf_svc_loop; 68137836SJohn.Forte@Sun.COM } 68147836SJohn.Forte@Sun.COM /* Check if there are free tasks to clear */ 68157836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 68167836SJohn.Forte@Sun.COM ((!drain_next) || (ddi_get_lbolt() >= drain_next))) { 68177836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 68187836SJohn.Forte@Sun.COM /* we are starting a new round */ 68197836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = 68207836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 68217836SJohn.Forte@Sun.COM drain_start = ddi_get_lbolt(); 68227836SJohn.Forte@Sun.COM } 68237836SJohn.Forte@Sun.COM stmf_check_freetask(); 68247836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 68257836SJohn.Forte@Sun.COM /* we finished a complete round */ 68267836SJohn.Forte@Sun.COM drain_next = 68277836SJohn.Forte@Sun.COM drain_start + drv_usectohz(10*1000*1000); 68287836SJohn.Forte@Sun.COM } else { 68297836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 68307836SJohn.Forte@Sun.COM drain_next = 68317836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 68327836SJohn.Forte@Sun.COM } 68337836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 68347836SJohn.Forte@Sun.COM goto stmf_svc_loop; 68357836SJohn.Forte@Sun.COM } 68367836SJohn.Forte@Sun.COM 68377836SJohn.Forte@Sun.COM /* Check if we need to run worker_mgmt */ 68387836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > worker_delay) { 68397836SJohn.Forte@Sun.COM stmf_worker_mgmt(); 68407836SJohn.Forte@Sun.COM worker_delay = ddi_get_lbolt() + 68417836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay; 68427836SJohn.Forte@Sun.COM } 68437836SJohn.Forte@Sun.COM 68447836SJohn.Forte@Sun.COM /* Check if any active session got its 1st LUN */ 68457836SJohn.Forte@Sun.COM if (stmf_state.stmf_process_initial_luns) { 68467836SJohn.Forte@Sun.COM int stmf_level = 0; 68477836SJohn.Forte@Sun.COM int port_level; 68487836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 68497836SJohn.Forte@Sun.COM ilport = next_ilport) { 68507836SJohn.Forte@Sun.COM next_ilport = ilport->ilport_next; 68517836SJohn.Forte@Sun.COM if ((ilport->ilport_flags & 68527836SJohn.Forte@Sun.COM ILPORT_SS_GOT_INITIAL_LUNS) == 0) { 68537836SJohn.Forte@Sun.COM continue; 68547836SJohn.Forte@Sun.COM } 68557836SJohn.Forte@Sun.COM port_level = 0; 68567836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_READER); 68577836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss; 68587836SJohn.Forte@Sun.COM iss = iss->iss_next) { 68597836SJohn.Forte@Sun.COM if ((iss->iss_flags & 68607836SJohn.Forte@Sun.COM ISS_GOT_INITIAL_LUNS) == 0) { 68617836SJohn.Forte@Sun.COM continue; 68627836SJohn.Forte@Sun.COM } 68637836SJohn.Forte@Sun.COM port_level++; 68647836SJohn.Forte@Sun.COM stmf_level++; 68657836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 68668662SJordan.Vaughan@Sun.com ~ISS_GOT_INITIAL_LUNS); 68677836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, 68688662SJordan.Vaughan@Sun.com ISS_EVENT_ACTIVE); 68697836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 68707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 68717836SJohn.Forte@Sun.COM stmf_generate_lport_event(ilport, 68727836SJohn.Forte@Sun.COM LPORT_EVENT_INITIAL_LUN_MAPPED, 68737836SJohn.Forte@Sun.COM iss->iss_ss, 0); 68747836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 68758662SJordan.Vaughan@Sun.com ~ISS_EVENT_ACTIVE); 68767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 68777836SJohn.Forte@Sun.COM /* 68787836SJohn.Forte@Sun.COM * scan all the ilports again as the 68797836SJohn.Forte@Sun.COM * ilport list might have changed. 68807836SJohn.Forte@Sun.COM */ 68817836SJohn.Forte@Sun.COM next_ilport = 68828662SJordan.Vaughan@Sun.com stmf_state.stmf_ilportlist; 68837836SJohn.Forte@Sun.COM break; 68847836SJohn.Forte@Sun.COM } 68857836SJohn.Forte@Sun.COM if (port_level == 0) { 68867836SJohn.Forte@Sun.COM atomic_and_32(&ilport->ilport_flags, 68878662SJordan.Vaughan@Sun.com ~ILPORT_SS_GOT_INITIAL_LUNS); 68887836SJohn.Forte@Sun.COM } 68897836SJohn.Forte@Sun.COM /* drop the lock if we are holding it. */ 68907836SJohn.Forte@Sun.COM if (rw_lock_held(&ilport->ilport_lock)) 68917836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 68927836SJohn.Forte@Sun.COM 68937836SJohn.Forte@Sun.COM /* Max 4 session at a time */ 68947836SJohn.Forte@Sun.COM if (stmf_level >= 4) { 68957836SJohn.Forte@Sun.COM break; 68967836SJohn.Forte@Sun.COM } 68977836SJohn.Forte@Sun.COM } 68987836SJohn.Forte@Sun.COM if (stmf_level == 0) { 68997836SJohn.Forte@Sun.COM stmf_state.stmf_process_initial_luns = 0; 69007836SJohn.Forte@Sun.COM } 69017836SJohn.Forte@Sun.COM } 69027836SJohn.Forte@Sun.COM 69037836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE; 69047836SJohn.Forte@Sun.COM (void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock, 69057836SJohn.Forte@Sun.COM ddi_get_lbolt() + td); 69067836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE; 69077836SJohn.Forte@Sun.COM } 69087836SJohn.Forte@Sun.COM goto stmf_svc_loop; 69097836SJohn.Forte@Sun.COM } 69107836SJohn.Forte@Sun.COM 69117836SJohn.Forte@Sun.COM void 69127836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info) 69137836SJohn.Forte@Sun.COM { 69147836SJohn.Forte@Sun.COM stmf_svc_req_t *req; 69157836SJohn.Forte@Sun.COM int s; 69167836SJohn.Forte@Sun.COM 69177836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&stmf_state.stmf_lock)); 69187836SJohn.Forte@Sun.COM s = sizeof (stmf_svc_req_t); 69197836SJohn.Forte@Sun.COM if (info->st_additional_info) { 69207836SJohn.Forte@Sun.COM s += strlen(info->st_additional_info) + 1; 69217836SJohn.Forte@Sun.COM } 69227836SJohn.Forte@Sun.COM req = kmem_zalloc(s, KM_SLEEP); 69237836SJohn.Forte@Sun.COM 69247836SJohn.Forte@Sun.COM req->svc_cmd = cmd; 69257836SJohn.Forte@Sun.COM req->svc_obj = obj; 69267836SJohn.Forte@Sun.COM req->svc_info.st_rflags = info->st_rflags; 69277836SJohn.Forte@Sun.COM if (info->st_additional_info) { 69287836SJohn.Forte@Sun.COM req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req, 69297836SJohn.Forte@Sun.COM sizeof (stmf_svc_req_t))); 69307836SJohn.Forte@Sun.COM (void) strcpy(req->svc_info.st_additional_info, 69317836SJohn.Forte@Sun.COM info->st_additional_info); 69327836SJohn.Forte@Sun.COM } 69337836SJohn.Forte@Sun.COM req->svc_req_alloc_size = s; 69347836SJohn.Forte@Sun.COM 69357836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 69367836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_active; 69377836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req; 69387836SJohn.Forte@Sun.COM if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) { 69397836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 69407836SJohn.Forte@Sun.COM } 69417836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 69427836SJohn.Forte@Sun.COM } 69437836SJohn.Forte@Sun.COM 69447836SJohn.Forte@Sun.COM void 69457836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...) 69467836SJohn.Forte@Sun.COM { 69477836SJohn.Forte@Sun.COM va_list args; 69487836SJohn.Forte@Sun.COM char tbuf[160]; 69497836SJohn.Forte@Sun.COM int len; 69507836SJohn.Forte@Sun.COM 69517836SJohn.Forte@Sun.COM if (!stmf_trace_on) 69527836SJohn.Forte@Sun.COM return; 69537836SJohn.Forte@Sun.COM len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "", 69547836SJohn.Forte@Sun.COM ddi_get_lbolt()); 69557836SJohn.Forte@Sun.COM va_start(args, fmt); 69567836SJohn.Forte@Sun.COM len += vsnprintf(tbuf + len, 158 - len, fmt, args); 69577836SJohn.Forte@Sun.COM va_end(args); 69587836SJohn.Forte@Sun.COM 69597836SJohn.Forte@Sun.COM if (len > 158) { 69607836SJohn.Forte@Sun.COM len = 158; 69617836SJohn.Forte@Sun.COM } 69627836SJohn.Forte@Sun.COM tbuf[len++] = '\n'; 69637836SJohn.Forte@Sun.COM tbuf[len] = 0; 69647836SJohn.Forte@Sun.COM 69657836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 69667836SJohn.Forte@Sun.COM bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1); 69677836SJohn.Forte@Sun.COM trace_buf_curndx += len; 69687836SJohn.Forte@Sun.COM if (trace_buf_curndx > (trace_buf_size - 320)) 69697836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 69707836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 69717836SJohn.Forte@Sun.COM } 69727836SJohn.Forte@Sun.COM 69737836SJohn.Forte@Sun.COM void 69747836SJohn.Forte@Sun.COM stmf_trace_clear() 69757836SJohn.Forte@Sun.COM { 69767836SJohn.Forte@Sun.COM if (!stmf_trace_on) 69777836SJohn.Forte@Sun.COM return; 69787836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 69797836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 69807836SJohn.Forte@Sun.COM if (trace_buf_size > 0) 69817836SJohn.Forte@Sun.COM stmf_trace_buf[0] = 0; 69827836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 69837836SJohn.Forte@Sun.COM } 69847836SJohn.Forte@Sun.COM 69857836SJohn.Forte@Sun.COM static void 69867836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info) 69877836SJohn.Forte@Sun.COM { 698810421STim.Szeto@Sun.COM stmf_state_change_info_t change_info; 69897836SJohn.Forte@Sun.COM void *ctl_private; 699010421STim.Szeto@Sun.COM uint32_t ctl_cmd; 69917836SJohn.Forte@Sun.COM int msg = 0; 69927836SJohn.Forte@Sun.COM 69937836SJohn.Forte@Sun.COM stmf_trace("FROM STMF", "abort_task_offline called for %s: %s", 69947836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : "no additional info"); 69957836SJohn.Forte@Sun.COM change_info.st_additional_info = info; 69967836SJohn.Forte@Sun.COM if (offline_lu) { 69977836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 69987836SJohn.Forte@Sun.COM STMF_RFLAG_LU_ABORT; 69997836SJohn.Forte@Sun.COM ctl_private = task->task_lu; 70007836SJohn.Forte@Sun.COM if (((stmf_i_lu_t *) 70017836SJohn.Forte@Sun.COM task->task_lu->lu_stmf_private)->ilu_state == 70027836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 70037836SJohn.Forte@Sun.COM msg = 1; 70047836SJohn.Forte@Sun.COM } 70057836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LU_OFFLINE; 70067836SJohn.Forte@Sun.COM } else { 70077836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 70087836SJohn.Forte@Sun.COM STMF_RFLAG_LPORT_ABORT; 70097836SJohn.Forte@Sun.COM ctl_private = task->task_lport; 70107836SJohn.Forte@Sun.COM if (((stmf_i_local_port_t *) 70117836SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private)->ilport_state == 70127836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 70137836SJohn.Forte@Sun.COM msg = 1; 70147836SJohn.Forte@Sun.COM } 70157836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LPORT_OFFLINE; 70167836SJohn.Forte@Sun.COM } 70177836SJohn.Forte@Sun.COM 70187836SJohn.Forte@Sun.COM if (msg) { 70197836SJohn.Forte@Sun.COM stmf_trace(0, "Calling stmf_ctl to offline %s : %s", 70207836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : 70217836SJohn.Forte@Sun.COM "<no additional info>"); 70227836SJohn.Forte@Sun.COM } 70237836SJohn.Forte@Sun.COM (void) stmf_ctl(ctl_cmd, ctl_private, &change_info); 70247836SJohn.Forte@Sun.COM } 7025