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> 487836SJohn.Forte@Sun.COM 497836SJohn.Forte@Sun.COM static uint64_t stmf_session_counter = 0; 507836SJohn.Forte@Sun.COM static uint16_t stmf_rtpid_counter = 0; 517836SJohn.Forte@Sun.COM 527836SJohn.Forte@Sun.COM static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 537836SJohn.Forte@Sun.COM static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 547836SJohn.Forte@Sun.COM static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 557836SJohn.Forte@Sun.COM void **result); 567836SJohn.Forte@Sun.COM static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp); 577836SJohn.Forte@Sun.COM static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp); 587836SJohn.Forte@Sun.COM static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 597836SJohn.Forte@Sun.COM cred_t *credp, int *rval); 607836SJohn.Forte@Sun.COM static int stmf_get_stmf_state(stmf_state_desc_t *std); 617836SJohn.Forte@Sun.COM static int stmf_set_stmf_state(stmf_state_desc_t *std); 627836SJohn.Forte@Sun.COM static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu, 637836SJohn.Forte@Sun.COM char *info); 647836SJohn.Forte@Sun.COM void stmf_svc_init(); 657836SJohn.Forte@Sun.COM stmf_status_t stmf_svc_fini(); 667836SJohn.Forte@Sun.COM void stmf_svc(void *arg); 677836SJohn.Forte@Sun.COM void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info); 687836SJohn.Forte@Sun.COM void stmf_check_freetask(); 697836SJohn.Forte@Sun.COM void stmf_abort_target_reset(scsi_task_t *task); 707836SJohn.Forte@Sun.COM stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, 717836SJohn.Forte@Sun.COM int target_reset); 727836SJohn.Forte@Sun.COM void stmf_target_reset_poll(struct scsi_task *task); 737836SJohn.Forte@Sun.COM void stmf_handle_lun_reset(scsi_task_t *task); 747836SJohn.Forte@Sun.COM void stmf_handle_target_reset(scsi_task_t *task); 757836SJohn.Forte@Sun.COM void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf); 769585STim.Szeto@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 779585STim.Szeto@Sun.COM uint32_t *err_ret); 787836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi); 799585STim.Szeto@Sun.COM int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 809585STim.Szeto@Sun.COM uint32_t *err_ret); 817836SJohn.Forte@Sun.COM void stmf_delete_ppd(stmf_pp_data_t *ppd); 827836SJohn.Forte@Sun.COM void stmf_delete_all_ppds(); 837836SJohn.Forte@Sun.COM void stmf_trace_clear(); 847836SJohn.Forte@Sun.COM void stmf_worker_init(); 857836SJohn.Forte@Sun.COM stmf_status_t stmf_worker_fini(); 867836SJohn.Forte@Sun.COM void stmf_worker_mgmt(); 877836SJohn.Forte@Sun.COM void stmf_worker_task(void *arg); 887836SJohn.Forte@Sun.COM 899435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_q(scsi_task_t *, void()); 909435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_q(scsi_task_t *, void()); 919435STim.Szeto@Sun.COM static void stmf_update_kstat_lu_io(scsi_task_t *, stmf_data_buf_t *); 929435STim.Szeto@Sun.COM static void stmf_update_kstat_lport_io(scsi_task_t *, stmf_data_buf_t *); 939435STim.Szeto@Sun.COM 947836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops; 957836SJohn.Forte@Sun.COM 967836SJohn.Forte@Sun.COM /* =====[ Tunables ]===== */ 977836SJohn.Forte@Sun.COM /* Internal tracing */ 987836SJohn.Forte@Sun.COM volatile int stmf_trace_on = 1; 997836SJohn.Forte@Sun.COM volatile int stmf_trace_buf_size = (1 * 1024 * 1024); 1007836SJohn.Forte@Sun.COM /* 1017836SJohn.Forte@Sun.COM * The reason default task timeout is 75 is because we want the 1027836SJohn.Forte@Sun.COM * host to timeout 1st and mostly host timeout is 60 seconds. 1037836SJohn.Forte@Sun.COM */ 1047836SJohn.Forte@Sun.COM volatile int stmf_default_task_timeout = 75; 1057836SJohn.Forte@Sun.COM /* 1067836SJohn.Forte@Sun.COM * Setting this to one means, you are responsible for config load and keeping 1077836SJohn.Forte@Sun.COM * things in sync with persistent database. 1087836SJohn.Forte@Sun.COM */ 1097836SJohn.Forte@Sun.COM volatile int stmf_allow_modunload = 0; 1107836SJohn.Forte@Sun.COM 1117836SJohn.Forte@Sun.COM volatile int stmf_max_nworkers = 256; 1127836SJohn.Forte@Sun.COM volatile int stmf_min_nworkers = 4; 1137836SJohn.Forte@Sun.COM volatile int stmf_worker_scale_down_delay = 20; 1147836SJohn.Forte@Sun.COM 1157836SJohn.Forte@Sun.COM /* === [ Debugging and fault injection ] === */ 1167836SJohn.Forte@Sun.COM #ifdef DEBUG 1177836SJohn.Forte@Sun.COM volatile int stmf_drop_task_counter = 0; 1187836SJohn.Forte@Sun.COM volatile int stmf_drop_buf_counter = 0; 1197836SJohn.Forte@Sun.COM 1207836SJohn.Forte@Sun.COM #endif 1217836SJohn.Forte@Sun.COM 1227836SJohn.Forte@Sun.COM stmf_state_t stmf_state; 1237836SJohn.Forte@Sun.COM static stmf_lu_t *dlun0; 1247836SJohn.Forte@Sun.COM 1257836SJohn.Forte@Sun.COM static uint8_t stmf_first_zero[] = 1267836SJohn.Forte@Sun.COM { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff }; 1277836SJohn.Forte@Sun.COM static uint8_t stmf_first_one[] = 1287836SJohn.Forte@Sun.COM { 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; 1297836SJohn.Forte@Sun.COM 1307836SJohn.Forte@Sun.COM static kmutex_t trace_buf_lock; 1317836SJohn.Forte@Sun.COM static int trace_buf_size; 1327836SJohn.Forte@Sun.COM static int trace_buf_curndx; 1337836SJohn.Forte@Sun.COM caddr_t stmf_trace_buf; 1347836SJohn.Forte@Sun.COM 1357836SJohn.Forte@Sun.COM static enum { 1367836SJohn.Forte@Sun.COM STMF_WORKERS_DISABLED = 0, 1377836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLING, 1387836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLED 1397836SJohn.Forte@Sun.COM } stmf_workers_state = STMF_WORKERS_DISABLED; 1407836SJohn.Forte@Sun.COM static int stmf_i_max_nworkers; 1417836SJohn.Forte@Sun.COM static int stmf_i_min_nworkers; 1427836SJohn.Forte@Sun.COM static int stmf_nworkers_cur; /* # of workers currently running */ 1437836SJohn.Forte@Sun.COM static int stmf_nworkers_needed; /* # of workers need to be running */ 1447836SJohn.Forte@Sun.COM static int stmf_worker_sel_counter = 0; 1457836SJohn.Forte@Sun.COM static uint32_t stmf_cur_ntasks = 0; 1467836SJohn.Forte@Sun.COM static clock_t stmf_wm_last = 0; 1477836SJohn.Forte@Sun.COM /* 1487836SJohn.Forte@Sun.COM * This is equal to stmf_nworkers_cur while we are increasing # workers and 1497836SJohn.Forte@Sun.COM * stmf_nworkers_needed while we are decreasing the worker count. 1507836SJohn.Forte@Sun.COM */ 1517836SJohn.Forte@Sun.COM static int stmf_nworkers_accepting_cmds; 1527836SJohn.Forte@Sun.COM static stmf_worker_t *stmf_workers = NULL; 1537836SJohn.Forte@Sun.COM static clock_t stmf_worker_mgmt_delay = 2; 1547836SJohn.Forte@Sun.COM static clock_t stmf_worker_scale_down_timer = 0; 1557836SJohn.Forte@Sun.COM static int stmf_worker_scale_down_qd = 0; 1567836SJohn.Forte@Sun.COM 1577836SJohn.Forte@Sun.COM static struct cb_ops stmf_cb_ops = { 1587836SJohn.Forte@Sun.COM stmf_open, /* open */ 1597836SJohn.Forte@Sun.COM stmf_close, /* close */ 1607836SJohn.Forte@Sun.COM nodev, /* strategy */ 1617836SJohn.Forte@Sun.COM nodev, /* print */ 1627836SJohn.Forte@Sun.COM nodev, /* dump */ 1637836SJohn.Forte@Sun.COM nodev, /* read */ 1647836SJohn.Forte@Sun.COM nodev, /* write */ 1657836SJohn.Forte@Sun.COM stmf_ioctl, /* ioctl */ 1667836SJohn.Forte@Sun.COM nodev, /* devmap */ 1677836SJohn.Forte@Sun.COM nodev, /* mmap */ 1687836SJohn.Forte@Sun.COM nodev, /* segmap */ 1697836SJohn.Forte@Sun.COM nochpoll, /* chpoll */ 1707836SJohn.Forte@Sun.COM ddi_prop_op, /* cb_prop_op */ 1717836SJohn.Forte@Sun.COM 0, /* streamtab */ 1727836SJohn.Forte@Sun.COM D_NEW | D_MP, /* cb_flag */ 1737836SJohn.Forte@Sun.COM CB_REV, /* rev */ 1747836SJohn.Forte@Sun.COM nodev, /* aread */ 1757836SJohn.Forte@Sun.COM nodev /* awrite */ 1767836SJohn.Forte@Sun.COM }; 1777836SJohn.Forte@Sun.COM 1787836SJohn.Forte@Sun.COM static struct dev_ops stmf_ops = { 1797836SJohn.Forte@Sun.COM DEVO_REV, 1807836SJohn.Forte@Sun.COM 0, 1817836SJohn.Forte@Sun.COM stmf_getinfo, 1827836SJohn.Forte@Sun.COM nulldev, /* identify */ 1837836SJohn.Forte@Sun.COM nulldev, /* probe */ 1847836SJohn.Forte@Sun.COM stmf_attach, 1857836SJohn.Forte@Sun.COM stmf_detach, 1867836SJohn.Forte@Sun.COM nodev, /* reset */ 1877836SJohn.Forte@Sun.COM &stmf_cb_ops, 1887836SJohn.Forte@Sun.COM NULL, /* bus_ops */ 1897836SJohn.Forte@Sun.COM NULL /* power */ 1907836SJohn.Forte@Sun.COM }; 1917836SJohn.Forte@Sun.COM 1929435STim.Szeto@Sun.COM #define STMF_NAME "COMSTAR STMF" 1939435STim.Szeto@Sun.COM #define STMF_MODULE_NAME "stmf" 1947836SJohn.Forte@Sun.COM 1957836SJohn.Forte@Sun.COM static struct modldrv modldrv = { 1967836SJohn.Forte@Sun.COM &mod_driverops, 1977836SJohn.Forte@Sun.COM STMF_NAME, 1987836SJohn.Forte@Sun.COM &stmf_ops 1997836SJohn.Forte@Sun.COM }; 2007836SJohn.Forte@Sun.COM 2017836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = { 2027836SJohn.Forte@Sun.COM MODREV_1, 2037836SJohn.Forte@Sun.COM &modldrv, 2047836SJohn.Forte@Sun.COM NULL 2057836SJohn.Forte@Sun.COM }; 2067836SJohn.Forte@Sun.COM 2077836SJohn.Forte@Sun.COM int 2087836SJohn.Forte@Sun.COM _init(void) 2097836SJohn.Forte@Sun.COM { 2107836SJohn.Forte@Sun.COM int ret; 2117836SJohn.Forte@Sun.COM 2127836SJohn.Forte@Sun.COM ret = mod_install(&modlinkage); 2137836SJohn.Forte@Sun.COM if (ret) 2147836SJohn.Forte@Sun.COM return (ret); 2157836SJohn.Forte@Sun.COM stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP); 2167836SJohn.Forte@Sun.COM trace_buf_size = stmf_trace_buf_size; 2177836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 2187836SJohn.Forte@Sun.COM mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0); 2197836SJohn.Forte@Sun.COM bzero(&stmf_state, sizeof (stmf_state_t)); 2207836SJohn.Forte@Sun.COM /* STMF service is off by default */ 2217836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 2227836SJohn.Forte@Sun.COM mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL); 2237836SJohn.Forte@Sun.COM cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL); 2247836SJohn.Forte@Sun.COM stmf_session_counter = (uint64_t)ddi_get_lbolt(); 2257836SJohn.Forte@Sun.COM stmf_view_init(); 2267836SJohn.Forte@Sun.COM stmf_svc_init(); 2277836SJohn.Forte@Sun.COM stmf_dlun_init(); 2287836SJohn.Forte@Sun.COM return (ret); 2297836SJohn.Forte@Sun.COM } 2307836SJohn.Forte@Sun.COM 2317836SJohn.Forte@Sun.COM int 2327836SJohn.Forte@Sun.COM _fini(void) 2337836SJohn.Forte@Sun.COM { 2347836SJohn.Forte@Sun.COM int ret; 2357836SJohn.Forte@Sun.COM 2367836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) 2377836SJohn.Forte@Sun.COM return (EBUSY); 2387836SJohn.Forte@Sun.COM if ((!stmf_allow_modunload) && 2397836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) { 2407836SJohn.Forte@Sun.COM return (EBUSY); 2417836SJohn.Forte@Sun.COM } 2427836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlps || stmf_state.stmf_npps) { 2437836SJohn.Forte@Sun.COM return (EBUSY); 2447836SJohn.Forte@Sun.COM } 2457836SJohn.Forte@Sun.COM if (stmf_dlun_fini() != STMF_SUCCESS) 2467836SJohn.Forte@Sun.COM return (EBUSY); 2477836SJohn.Forte@Sun.COM if (stmf_worker_fini() != STMF_SUCCESS) { 2487836SJohn.Forte@Sun.COM stmf_dlun_init(); 2497836SJohn.Forte@Sun.COM return (EBUSY); 2507836SJohn.Forte@Sun.COM } 2517836SJohn.Forte@Sun.COM if (stmf_svc_fini() != STMF_SUCCESS) { 2527836SJohn.Forte@Sun.COM stmf_dlun_init(); 2537836SJohn.Forte@Sun.COM stmf_worker_init(); 2547836SJohn.Forte@Sun.COM return (EBUSY); 2557836SJohn.Forte@Sun.COM } 2567836SJohn.Forte@Sun.COM 2577836SJohn.Forte@Sun.COM ret = mod_remove(&modlinkage); 2587836SJohn.Forte@Sun.COM if (ret) { 2597836SJohn.Forte@Sun.COM stmf_svc_init(); 2607836SJohn.Forte@Sun.COM stmf_dlun_init(); 2617836SJohn.Forte@Sun.COM stmf_worker_init(); 2627836SJohn.Forte@Sun.COM return (ret); 2637836SJohn.Forte@Sun.COM } 2647836SJohn.Forte@Sun.COM 2657836SJohn.Forte@Sun.COM stmf_view_clear_config(); 2667836SJohn.Forte@Sun.COM kmem_free(stmf_trace_buf, stmf_trace_buf_size); 2677836SJohn.Forte@Sun.COM mutex_destroy(&trace_buf_lock); 2687836SJohn.Forte@Sun.COM mutex_destroy(&stmf_state.stmf_lock); 2697836SJohn.Forte@Sun.COM cv_destroy(&stmf_state.stmf_cv); 2707836SJohn.Forte@Sun.COM return (ret); 2717836SJohn.Forte@Sun.COM } 2727836SJohn.Forte@Sun.COM 2737836SJohn.Forte@Sun.COM int 2747836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop) 2757836SJohn.Forte@Sun.COM { 2767836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfop)); 2777836SJohn.Forte@Sun.COM } 2787836SJohn.Forte@Sun.COM 2797836SJohn.Forte@Sun.COM /* ARGSUSED */ 2807836SJohn.Forte@Sun.COM static int 2817836SJohn.Forte@Sun.COM stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 2827836SJohn.Forte@Sun.COM { 2837836SJohn.Forte@Sun.COM switch (cmd) { 2847836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2DEVINFO: 2857836SJohn.Forte@Sun.COM *result = stmf_state.stmf_dip; 2867836SJohn.Forte@Sun.COM break; 2877836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2INSTANCE: 2889585STim.Szeto@Sun.COM *result = 2899585STim.Szeto@Sun.COM (void *)(uintptr_t)ddi_get_instance(stmf_state.stmf_dip); 2907836SJohn.Forte@Sun.COM break; 2917836SJohn.Forte@Sun.COM default: 2927836SJohn.Forte@Sun.COM return (DDI_FAILURE); 2937836SJohn.Forte@Sun.COM } 2947836SJohn.Forte@Sun.COM 2957836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 2967836SJohn.Forte@Sun.COM } 2977836SJohn.Forte@Sun.COM 2987836SJohn.Forte@Sun.COM static int 2997836SJohn.Forte@Sun.COM stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 3007836SJohn.Forte@Sun.COM { 3017836SJohn.Forte@Sun.COM switch (cmd) { 3027836SJohn.Forte@Sun.COM case DDI_ATTACH: 3037836SJohn.Forte@Sun.COM stmf_state.stmf_dip = dip; 3047836SJohn.Forte@Sun.COM 3057836SJohn.Forte@Sun.COM if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0, 3067836SJohn.Forte@Sun.COM DDI_NT_STMF, 0) != DDI_SUCCESS) { 3077836SJohn.Forte@Sun.COM break; 3087836SJohn.Forte@Sun.COM } 3097836SJohn.Forte@Sun.COM ddi_report_dev(dip); 3107836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3117836SJohn.Forte@Sun.COM } 3127836SJohn.Forte@Sun.COM 3137836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3147836SJohn.Forte@Sun.COM } 3157836SJohn.Forte@Sun.COM 3167836SJohn.Forte@Sun.COM static int 3177836SJohn.Forte@Sun.COM stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3187836SJohn.Forte@Sun.COM { 3197836SJohn.Forte@Sun.COM switch (cmd) { 3207836SJohn.Forte@Sun.COM case DDI_DETACH: 3217836SJohn.Forte@Sun.COM ddi_remove_minor_node(dip, 0); 3227836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3237836SJohn.Forte@Sun.COM } 3247836SJohn.Forte@Sun.COM 3257836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3267836SJohn.Forte@Sun.COM } 3277836SJohn.Forte@Sun.COM 3287836SJohn.Forte@Sun.COM /* ARGSUSED */ 3297836SJohn.Forte@Sun.COM static int 3307836SJohn.Forte@Sun.COM stmf_open(dev_t *devp, int flag, int otype, cred_t *credp) 3317836SJohn.Forte@Sun.COM { 3327836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3337836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open) { 3347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3357836SJohn.Forte@Sun.COM return (EBUSY); 3367836SJohn.Forte@Sun.COM } 3377836SJohn.Forte@Sun.COM if (flag & FEXCL) { 3387836SJohn.Forte@Sun.COM if (stmf_state.stmf_opened) { 3397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3407836SJohn.Forte@Sun.COM return (EBUSY); 3417836SJohn.Forte@Sun.COM } 3427836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 1; 3437836SJohn.Forte@Sun.COM } 3447836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 1; 3457836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3467836SJohn.Forte@Sun.COM return (0); 3477836SJohn.Forte@Sun.COM } 3487836SJohn.Forte@Sun.COM 3497836SJohn.Forte@Sun.COM /* ARGSUSED */ 3507836SJohn.Forte@Sun.COM static int 3517836SJohn.Forte@Sun.COM stmf_close(dev_t dev, int flag, int otype, cred_t *credp) 3527836SJohn.Forte@Sun.COM { 3537836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3547836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 0; 3557836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open && 3567836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) { 3577836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_NONE; 3587836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 3597836SJohn.Forte@Sun.COM stmf_view_clear_config(); 3607836SJohn.Forte@Sun.COM stmf_view_init(); 3617836SJohn.Forte@Sun.COM } 3627836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 0; 3637836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3647836SJohn.Forte@Sun.COM return (0); 3657836SJohn.Forte@Sun.COM } 3667836SJohn.Forte@Sun.COM 3677836SJohn.Forte@Sun.COM int 3687836SJohn.Forte@Sun.COM stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd, 3697836SJohn.Forte@Sun.COM void **ibuf, void **obuf) 3707836SJohn.Forte@Sun.COM { 3717836SJohn.Forte@Sun.COM int ret; 3727836SJohn.Forte@Sun.COM 3737836SJohn.Forte@Sun.COM *ibuf = NULL; 3747836SJohn.Forte@Sun.COM *obuf = NULL; 3757836SJohn.Forte@Sun.COM *iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP); 3767836SJohn.Forte@Sun.COM 3777836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode); 3787836SJohn.Forte@Sun.COM if (ret) 3797836SJohn.Forte@Sun.COM return (EFAULT); 3807836SJohn.Forte@Sun.COM if ((*iocd)->stmf_version != STMF_VERSION_1) { 3817836SJohn.Forte@Sun.COM ret = EINVAL; 3827836SJohn.Forte@Sun.COM goto copyin_iocdata_done; 3837836SJohn.Forte@Sun.COM } 3847836SJohn.Forte@Sun.COM if ((*iocd)->stmf_ibuf_size) { 3857836SJohn.Forte@Sun.COM *ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP); 3867836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf), 3877836SJohn.Forte@Sun.COM *ibuf, (*iocd)->stmf_ibuf_size, mode); 3887836SJohn.Forte@Sun.COM } 3897836SJohn.Forte@Sun.COM if ((*iocd)->stmf_obuf_size) 3907836SJohn.Forte@Sun.COM *obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP); 3917836SJohn.Forte@Sun.COM 3927836SJohn.Forte@Sun.COM if (ret == 0) 3937836SJohn.Forte@Sun.COM return (0); 3947836SJohn.Forte@Sun.COM ret = EFAULT; 3957836SJohn.Forte@Sun.COM copyin_iocdata_done:; 3967836SJohn.Forte@Sun.COM if (*obuf) { 3977836SJohn.Forte@Sun.COM kmem_free(*obuf, (*iocd)->stmf_obuf_size); 3987836SJohn.Forte@Sun.COM *obuf = NULL; 3997836SJohn.Forte@Sun.COM } 4007836SJohn.Forte@Sun.COM if (*ibuf) { 4017836SJohn.Forte@Sun.COM kmem_free(*ibuf, (*iocd)->stmf_ibuf_size); 4027836SJohn.Forte@Sun.COM *ibuf = NULL; 4037836SJohn.Forte@Sun.COM } 4047836SJohn.Forte@Sun.COM kmem_free(*iocd, sizeof (stmf_iocdata_t)); 4057836SJohn.Forte@Sun.COM return (ret); 4067836SJohn.Forte@Sun.COM } 4077836SJohn.Forte@Sun.COM 4087836SJohn.Forte@Sun.COM int 4097836SJohn.Forte@Sun.COM stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf) 4107836SJohn.Forte@Sun.COM { 4117836SJohn.Forte@Sun.COM int ret; 4127836SJohn.Forte@Sun.COM 4137836SJohn.Forte@Sun.COM if (iocd->stmf_obuf_size) { 4147836SJohn.Forte@Sun.COM ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf, 4157836SJohn.Forte@Sun.COM iocd->stmf_obuf_size, mode); 4167836SJohn.Forte@Sun.COM if (ret) 4177836SJohn.Forte@Sun.COM return (EFAULT); 4187836SJohn.Forte@Sun.COM } 4197836SJohn.Forte@Sun.COM ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode); 4207836SJohn.Forte@Sun.COM if (ret) 4217836SJohn.Forte@Sun.COM return (EFAULT); 4227836SJohn.Forte@Sun.COM return (0); 4237836SJohn.Forte@Sun.COM } 4247836SJohn.Forte@Sun.COM 4257836SJohn.Forte@Sun.COM /* ARGSUSED */ 4267836SJohn.Forte@Sun.COM static int 4277836SJohn.Forte@Sun.COM stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 4287836SJohn.Forte@Sun.COM cred_t *credp, int *rval) 4297836SJohn.Forte@Sun.COM { 4307836SJohn.Forte@Sun.COM stmf_iocdata_t *iocd; 4317836SJohn.Forte@Sun.COM void *ibuf = NULL, *obuf = NULL; 4327836SJohn.Forte@Sun.COM slist_lu_t *luid_list; 4337836SJohn.Forte@Sun.COM slist_target_port_t *lportid_list; 4347836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 4357836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 4367836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 4377836SJohn.Forte@Sun.COM slist_scsi_session_t *iss_list; 4387836SJohn.Forte@Sun.COM sioc_lu_props_t *lup; 4397836SJohn.Forte@Sun.COM sioc_target_port_props_t *lportp; 4409585STim.Szeto@Sun.COM stmf_ppioctl_data_t *ppi, *ppi_out = NULL; 4419585STim.Szeto@Sun.COM uint64_t *ppi_token = NULL; 4429585STim.Szeto@Sun.COM uint8_t *p_id, *id; 4437836SJohn.Forte@Sun.COM stmf_state_desc_t *std; 4447836SJohn.Forte@Sun.COM stmf_status_t ctl_ret; 4457836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 4467836SJohn.Forte@Sun.COM int ret = 0; 4477836SJohn.Forte@Sun.COM uint32_t n; 4487836SJohn.Forte@Sun.COM int i; 4497836SJohn.Forte@Sun.COM stmf_group_op_data_t *grp_entry; 4507836SJohn.Forte@Sun.COM stmf_group_name_t *grpname; 4517836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve; 4527836SJohn.Forte@Sun.COM stmf_id_type_t idtype; 4537836SJohn.Forte@Sun.COM stmf_id_data_t *id_entry; 4547836SJohn.Forte@Sun.COM stmf_id_list_t *id_list; 4557836SJohn.Forte@Sun.COM stmf_view_entry_t *view_entry; 4567836SJohn.Forte@Sun.COM uint32_t veid; 4577836SJohn.Forte@Sun.COM 4587836SJohn.Forte@Sun.COM if ((cmd & 0xff000000) != STMF_IOCTL) { 4597836SJohn.Forte@Sun.COM return (ENOTTY); 4607836SJohn.Forte@Sun.COM } 4617836SJohn.Forte@Sun.COM 4627836SJohn.Forte@Sun.COM if (drv_priv(credp) != 0) { 4637836SJohn.Forte@Sun.COM return (EPERM); 4647836SJohn.Forte@Sun.COM } 4657836SJohn.Forte@Sun.COM 4667836SJohn.Forte@Sun.COM ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf); 4677836SJohn.Forte@Sun.COM if (ret) 4687836SJohn.Forte@Sun.COM return (ret); 4697836SJohn.Forte@Sun.COM iocd->stmf_error = 0; 4707836SJohn.Forte@Sun.COM 4717836SJohn.Forte@Sun.COM switch (cmd) { 4727836SJohn.Forte@Sun.COM case STMF_IOCTL_LU_LIST: 4739585STim.Szeto@Sun.COM /* retrieves both registered/unregistered */ 4749585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4759585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 4769585STim.Szeto@Sun.COM n = min(id_list->id_count, 4779585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 4789585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 4799585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 4809585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 4819585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 4829585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 4839585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 4849585STim.Szeto@Sun.COM } 4859585STim.Szeto@Sun.COM 4869585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (slist_lu_t); 4879585STim.Szeto@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 4889585STim.Szeto@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 4899585STim.Szeto@Sun.COM if (stmf_lookup_id(id_list, 16, id + 4) == NULL) { 4909585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 4919585STim.Szeto@Sun.COM if (i < n) { 4929585STim.Szeto@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 4939585STim.Szeto@Sun.COM sizeof (slist_lu_t)); 4949585STim.Szeto@Sun.COM i++; 4959585STim.Szeto@Sun.COM } 4969585STim.Szeto@Sun.COM } 4979585STim.Szeto@Sun.COM } 4989585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = i; 4999585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5009585STim.Szeto@Sun.COM break; 5019585STim.Szeto@Sun.COM 5029585STim.Szeto@Sun.COM case STMF_IOCTL_REG_LU_LIST: 5037836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5047836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus; 5057836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlus, 5068662SJordan.Vaughan@Sun.com (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 5077836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5087836SJohn.Forte@Sun.COM ilu = stmf_state.stmf_ilulist; 5097836SJohn.Forte@Sun.COM luid_list = (slist_lu_t *)obuf; 5107836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5117836SJohn.Forte@Sun.COM uint8_t *id; 5127836SJohn.Forte@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 5137836SJohn.Forte@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 16); 5147836SJohn.Forte@Sun.COM ilu = ilu->ilu_next; 5157836SJohn.Forte@Sun.COM } 5167836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5177836SJohn.Forte@Sun.COM break; 5187836SJohn.Forte@Sun.COM 5199585STim.Szeto@Sun.COM case STMF_IOCTL_VE_LU_LIST: 5209585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5219585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 5229585STim.Szeto@Sun.COM n = min(id_list->id_count, 5239585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 5249585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 5259585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = n; 5269585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 5279585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 5289585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 5299585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 5309585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 5319585STim.Szeto@Sun.COM } 5329585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5339585STim.Szeto@Sun.COM break; 5349585STim.Szeto@Sun.COM 5357836SJohn.Forte@Sun.COM case STMF_IOCTL_TARGET_PORT_LIST: 5367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5377836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports; 5387836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlports, 5398662SJordan.Vaughan@Sun.com (iocd->stmf_obuf_size)/sizeof (slist_target_port_t)); 5407836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5417836SJohn.Forte@Sun.COM ilport = stmf_state.stmf_ilportlist; 5427836SJohn.Forte@Sun.COM lportid_list = (slist_target_port_t *)obuf; 5437836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5447836SJohn.Forte@Sun.COM uint8_t *id; 5457836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5467836SJohn.Forte@Sun.COM bcopy(id, lportid_list[i].target, id[3] + 4); 5477836SJohn.Forte@Sun.COM ilport = ilport->ilport_next; 5487836SJohn.Forte@Sun.COM } 5497836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5507836SJohn.Forte@Sun.COM break; 5517836SJohn.Forte@Sun.COM 5527836SJohn.Forte@Sun.COM case STMF_IOCTL_SESSION_LIST: 5537836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 5547836SJohn.Forte@Sun.COM if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) || 5557836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4))) { 5567836SJohn.Forte@Sun.COM ret = EINVAL; 5577836SJohn.Forte@Sun.COM break; 5587836SJohn.Forte@Sun.COM } 5597836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5607836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; ilport = 5618662SJordan.Vaughan@Sun.com ilport->ilport_next) { 5627836SJohn.Forte@Sun.COM uint8_t *id; 5637836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5647836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 5657836SJohn.Forte@Sun.COM (bcmp(p_id + 4, id + 4, id[3]) == 0)) { 5667836SJohn.Forte@Sun.COM break; 5677836SJohn.Forte@Sun.COM } 5687836SJohn.Forte@Sun.COM } 5697836SJohn.Forte@Sun.COM if (ilport == NULL) { 5707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5717836SJohn.Forte@Sun.COM ret = ENOENT; 5727836SJohn.Forte@Sun.COM break; 5737836SJohn.Forte@Sun.COM } 5747836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions; 5757836SJohn.Forte@Sun.COM n = min(ilport->ilport_nsessions, 5767836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t)); 5777836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5787836SJohn.Forte@Sun.COM iss = ilport->ilport_ss_list; 5797836SJohn.Forte@Sun.COM iss_list = (slist_scsi_session_t *)obuf; 5807836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5817836SJohn.Forte@Sun.COM uint8_t *id; 5827836SJohn.Forte@Sun.COM id = (uint8_t *)iss->iss_ss->ss_rport_id; 5837836SJohn.Forte@Sun.COM bcopy(id, iss_list[i].initiator, id[3] + 4); 5847836SJohn.Forte@Sun.COM iss_list[i].creation_time = (uint32_t) 5857836SJohn.Forte@Sun.COM iss->iss_creation_time; 5867836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_rport_alias) { 5877836SJohn.Forte@Sun.COM (void) strncpy(iss_list[i].alias, 5887836SJohn.Forte@Sun.COM iss->iss_ss->ss_rport_alias, 255); 5897836SJohn.Forte@Sun.COM iss_list[i].alias[255] = 0; 5907836SJohn.Forte@Sun.COM } else { 5917836SJohn.Forte@Sun.COM iss_list[i].alias[0] = 0; 5927836SJohn.Forte@Sun.COM } 5937836SJohn.Forte@Sun.COM iss = iss->iss_next; 5947836SJohn.Forte@Sun.COM } 5957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5967836SJohn.Forte@Sun.COM break; 5977836SJohn.Forte@Sun.COM 5987836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_LU_PROPERTIES: 5997836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 6007836SJohn.Forte@Sun.COM if ((iocd->stmf_ibuf_size < 16) || 6017836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) || 6027836SJohn.Forte@Sun.COM (p_id[0] == 0)) { 6037836SJohn.Forte@Sun.COM ret = EINVAL; 6047836SJohn.Forte@Sun.COM break; 6057836SJohn.Forte@Sun.COM } 6067836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6077836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 6087836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 6097836SJohn.Forte@Sun.COM break; 6107836SJohn.Forte@Sun.COM } 6117836SJohn.Forte@Sun.COM if (ilu == NULL) { 6127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6137836SJohn.Forte@Sun.COM ret = ENOENT; 6147836SJohn.Forte@Sun.COM break; 6157836SJohn.Forte@Sun.COM } 6167836SJohn.Forte@Sun.COM lup = (sioc_lu_props_t *)obuf; 6177836SJohn.Forte@Sun.COM bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16); 6187836SJohn.Forte@Sun.COM lup->lu_state = ilu->ilu_state & 0x0f; 6197836SJohn.Forte@Sun.COM lup->lu_present = 1; /* XXX */ 6207836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_provider_name, 6217836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_lp->lp_name, 255); 6227836SJohn.Forte@Sun.COM lup->lu_provider_name[254] = 0; 6237836SJohn.Forte@Sun.COM if (ilu->ilu_lu->lu_alias) { 6247836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_alias, 6257836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_alias, 255); 6267836SJohn.Forte@Sun.COM lup->lu_alias[255] = 0; 6277836SJohn.Forte@Sun.COM } else { 6287836SJohn.Forte@Sun.COM lup->lu_alias[0] = 0; 6297836SJohn.Forte@Sun.COM } 6307836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6317836SJohn.Forte@Sun.COM break; 6327836SJohn.Forte@Sun.COM 6337836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES: 6347836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 6357836SJohn.Forte@Sun.COM if ((p_id == NULL) || 6367836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4)) || 6377836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < 6387836SJohn.Forte@Sun.COM sizeof (sioc_target_port_props_t))) { 6397836SJohn.Forte@Sun.COM ret = EINVAL; 6407836SJohn.Forte@Sun.COM break; 6417836SJohn.Forte@Sun.COM } 6427836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6437836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 6447836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 6457836SJohn.Forte@Sun.COM uint8_t *id; 6467836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 6477836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 6487836SJohn.Forte@Sun.COM (bcmp(p_id+4, id+4, id[3]) == 0)) 6497836SJohn.Forte@Sun.COM break; 6507836SJohn.Forte@Sun.COM } 6517836SJohn.Forte@Sun.COM if (ilport == NULL) { 6527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6537836SJohn.Forte@Sun.COM ret = ENOENT; 6547836SJohn.Forte@Sun.COM break; 6557836SJohn.Forte@Sun.COM } 6567836SJohn.Forte@Sun.COM lportp = (sioc_target_port_props_t *)obuf; 6577836SJohn.Forte@Sun.COM bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id, 6587836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_id->ident_length + 4); 6597836SJohn.Forte@Sun.COM lportp->tgt_state = ilport->ilport_state & 0x0f; 6607836SJohn.Forte@Sun.COM lportp->tgt_present = 1; /* XXX */ 6617836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_provider_name, 6627836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_pp->pp_name, 255); 6637836SJohn.Forte@Sun.COM lportp->tgt_provider_name[254] = 0; 6647836SJohn.Forte@Sun.COM if (ilport->ilport_lport->lport_alias) { 6657836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_alias, 6667836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_alias, 255); 6677836SJohn.Forte@Sun.COM lportp->tgt_alias[255] = 0; 6687836SJohn.Forte@Sun.COM } else { 6697836SJohn.Forte@Sun.COM lportp->tgt_alias[0] = 0; 6707836SJohn.Forte@Sun.COM } 6717836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6727836SJohn.Forte@Sun.COM break; 6737836SJohn.Forte@Sun.COM 6747836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_STMF_STATE: 6757836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 6767836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 6777836SJohn.Forte@Sun.COM ret = EINVAL; 6787836SJohn.Forte@Sun.COM break; 6797836SJohn.Forte@Sun.COM } 6807836SJohn.Forte@Sun.COM ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf); 6817836SJohn.Forte@Sun.COM break; 6827836SJohn.Forte@Sun.COM 6837836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_STMF_STATE: 6847836SJohn.Forte@Sun.COM if ((obuf == NULL) || 6857836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) { 6867836SJohn.Forte@Sun.COM ret = EINVAL; 6877836SJohn.Forte@Sun.COM break; 6887836SJohn.Forte@Sun.COM } 6897836SJohn.Forte@Sun.COM ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf); 6907836SJohn.Forte@Sun.COM break; 6917836SJohn.Forte@Sun.COM 6927836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_LU_STATE: 6937836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 6947836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 6957836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 6967836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 6977836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 6987836SJohn.Forte@Sun.COM ret = EINVAL; 6997836SJohn.Forte@Sun.COM break; 7007836SJohn.Forte@Sun.COM } 7017836SJohn.Forte@Sun.COM p_id = std->ident; 7027836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7037836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 7047836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7057836SJohn.Forte@Sun.COM ret = EBUSY; 7067836SJohn.Forte@Sun.COM break; 7077836SJohn.Forte@Sun.COM } 7087836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 7097836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 7107836SJohn.Forte@Sun.COM break; 7117836SJohn.Forte@Sun.COM } 7127836SJohn.Forte@Sun.COM if (ilu == NULL) { 7137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7147836SJohn.Forte@Sun.COM ret = ENOENT; 7157836SJohn.Forte@Sun.COM break; 7167836SJohn.Forte@Sun.COM } 7177836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 7187836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7197836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE : 7207836SJohn.Forte@Sun.COM STMF_CMD_LU_OFFLINE; 7217836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi); 7227836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 7237836SJohn.Forte@Sun.COM ret = 0; 7247836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 7257836SJohn.Forte@Sun.COM ret = EIO; 7267836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7277836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 7287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7297836SJohn.Forte@Sun.COM break; 7307836SJohn.Forte@Sun.COM 7317836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_TARGET_PORT_STATE: 7327836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 7337836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 7347836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 7357836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7367836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 7377836SJohn.Forte@Sun.COM ret = EINVAL; 7387836SJohn.Forte@Sun.COM break; 7397836SJohn.Forte@Sun.COM } 7407836SJohn.Forte@Sun.COM p_id = std->ident; 7417836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7427836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 7437836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7447836SJohn.Forte@Sun.COM ret = EBUSY; 7457836SJohn.Forte@Sun.COM break; 7467836SJohn.Forte@Sun.COM } 7477836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 7487836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 7497836SJohn.Forte@Sun.COM uint8_t *id; 7507836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 7517836SJohn.Forte@Sun.COM if ((id[3] == p_id[3]) && 7527836SJohn.Forte@Sun.COM (bcmp(id+4, p_id+4, id[3]) == 0)) { 7537836SJohn.Forte@Sun.COM break; 7547836SJohn.Forte@Sun.COM } 7557836SJohn.Forte@Sun.COM } 7567836SJohn.Forte@Sun.COM if (ilport == NULL) { 7577836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7587836SJohn.Forte@Sun.COM ret = ENOENT; 7597836SJohn.Forte@Sun.COM break; 7607836SJohn.Forte@Sun.COM } 7617836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 7627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7637836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? 7647836SJohn.Forte@Sun.COM STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE; 7657836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi); 7667836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 7677836SJohn.Forte@Sun.COM ret = 0; 7687836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 7697836SJohn.Forte@Sun.COM ret = EIO; 7707836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7717836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 7727836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7737836SJohn.Forte@Sun.COM break; 7747836SJohn.Forte@Sun.COM 7757836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_HG_ENTRY: 7767836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 7777836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 7787836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TG_ENTRY: 7797836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 7807836SJohn.Forte@Sun.COM ret = EACCES; 7817836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 7827836SJohn.Forte@Sun.COM break; 7837836SJohn.Forte@Sun.COM } 7847836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_ADD_TG_ENTRY) { 7857836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 7867836SJohn.Forte@Sun.COM } 7877836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 7887836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7897836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 7907836SJohn.Forte@Sun.COM ret = EINVAL; 7917836SJohn.Forte@Sun.COM break; 7927836SJohn.Forte@Sun.COM } 7937836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 7947836SJohn.Forte@Sun.COM ret = EINVAL; 7957836SJohn.Forte@Sun.COM break; /* not allowed */ 7967836SJohn.Forte@Sun.COM } 7977836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7987836SJohn.Forte@Sun.COM ret = stmf_add_group_member(grp_entry->group.name, 7997836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8007836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8017836SJohn.Forte@Sun.COM grp_entry->ident[3], 8027836SJohn.Forte@Sun.COM idtype, 8037836SJohn.Forte@Sun.COM &iocd->stmf_error); 8047836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8057836SJohn.Forte@Sun.COM break; 8067836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HG_ENTRY: 8077836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 8087836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8097836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TG_ENTRY: 8107836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8117836SJohn.Forte@Sun.COM ret = EACCES; 8127836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8137836SJohn.Forte@Sun.COM break; 8147836SJohn.Forte@Sun.COM } 8157836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) { 8167836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 8177836SJohn.Forte@Sun.COM } 8187836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 8197836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8207836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 8217836SJohn.Forte@Sun.COM ret = EINVAL; 8227836SJohn.Forte@Sun.COM break; 8237836SJohn.Forte@Sun.COM } 8247836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 8257836SJohn.Forte@Sun.COM ret = EINVAL; 8267836SJohn.Forte@Sun.COM break; /* not allowed */ 8277836SJohn.Forte@Sun.COM } 8287836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8297836SJohn.Forte@Sun.COM ret = stmf_remove_group_member(grp_entry->group.name, 8307836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8317836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8327836SJohn.Forte@Sun.COM grp_entry->ident[3], 8337836SJohn.Forte@Sun.COM idtype, 8347836SJohn.Forte@Sun.COM &iocd->stmf_error); 8357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8367836SJohn.Forte@Sun.COM break; 8377836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_HOST_GROUP: 8387836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8397836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8407836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_TARGET_GROUP: 8417836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8427836SJohn.Forte@Sun.COM ret = EACCES; 8437836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8447836SJohn.Forte@Sun.COM break; 8457836SJohn.Forte@Sun.COM } 8467836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8477836SJohn.Forte@Sun.COM 8487836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP) 8497836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8507836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8517836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8527836SJohn.Forte@Sun.COM ret = EINVAL; 8537836SJohn.Forte@Sun.COM break; 8547836SJohn.Forte@Sun.COM } 8557836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8567836SJohn.Forte@Sun.COM ret = EINVAL; 8577836SJohn.Forte@Sun.COM break; /* not allowed */ 8587836SJohn.Forte@Sun.COM } 8597836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8607836SJohn.Forte@Sun.COM ret = stmf_add_group(grpname->name, 8617836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 8627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8637836SJohn.Forte@Sun.COM break; 8647836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HOST_GROUP: 8657836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8667836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8677836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TARGET_GROUP: 8687836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8697836SJohn.Forte@Sun.COM ret = EACCES; 8707836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8717836SJohn.Forte@Sun.COM break; 8727836SJohn.Forte@Sun.COM } 8737836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8747836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP) 8757836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8767836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8777836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8787836SJohn.Forte@Sun.COM ret = EINVAL; 8797836SJohn.Forte@Sun.COM break; 8807836SJohn.Forte@Sun.COM } 8817836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8827836SJohn.Forte@Sun.COM ret = EINVAL; 8837836SJohn.Forte@Sun.COM break; /* not allowed */ 8847836SJohn.Forte@Sun.COM } 8857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8867836SJohn.Forte@Sun.COM ret = stmf_remove_group(grpname->name, 8877836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 8887836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8897836SJohn.Forte@Sun.COM break; 8907836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_VIEW_ENTRY: 8917836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8927836SJohn.Forte@Sun.COM ret = EACCES; 8937836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8947836SJohn.Forte@Sun.COM break; 8957836SJohn.Forte@Sun.COM } 8967836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 8977836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8987836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 8997836SJohn.Forte@Sun.COM ret = EINVAL; 9007836SJohn.Forte@Sun.COM break; 9017836SJohn.Forte@Sun.COM } 9027836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) 9037836SJohn.Forte@Sun.COM ve->ve_lu_nbr[2] = 0xFF; 9047836SJohn.Forte@Sun.COM if (ve->ve_all_hosts) { 9057836SJohn.Forte@Sun.COM ve->ve_host_group.name[0] = '*'; 9067836SJohn.Forte@Sun.COM ve->ve_host_group.name_size = 1; 9077836SJohn.Forte@Sun.COM } 9087836SJohn.Forte@Sun.COM if (ve->ve_all_targets) { 9097836SJohn.Forte@Sun.COM ve->ve_target_group.name[0] = '*'; 9107836SJohn.Forte@Sun.COM ve->ve_target_group.name_size = 1; 9117836SJohn.Forte@Sun.COM } 9127836SJohn.Forte@Sun.COM if (ve->ve_ndx_valid) 9137836SJohn.Forte@Sun.COM veid = ve->ve_ndx; 9147836SJohn.Forte@Sun.COM else 9157836SJohn.Forte@Sun.COM veid = 0xffffffff; 9167836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9177836SJohn.Forte@Sun.COM ret = stmf_add_ve(ve->ve_host_group.name, 9187836SJohn.Forte@Sun.COM ve->ve_host_group.name_size, 9197836SJohn.Forte@Sun.COM ve->ve_target_group.name, 9207836SJohn.Forte@Sun.COM ve->ve_target_group.name_size, 9217836SJohn.Forte@Sun.COM ve->ve_guid, 9227836SJohn.Forte@Sun.COM &veid, 9237836SJohn.Forte@Sun.COM ve->ve_lu_nbr, 9247836SJohn.Forte@Sun.COM &iocd->stmf_error); 9257836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9267836SJohn.Forte@Sun.COM if (ret == 0 && 9277836SJohn.Forte@Sun.COM (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) && 9287836SJohn.Forte@Sun.COM iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) { 9297836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve_ret = 9307836SJohn.Forte@Sun.COM (stmf_view_op_entry_t *)obuf; 9317836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = 1; 9327836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = 1; 9337836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9347836SJohn.Forte@Sun.COM ve_ret->ve_ndx = veid; 9357836SJohn.Forte@Sun.COM ve_ret->ve_ndx_valid = 1; 9367836SJohn.Forte@Sun.COM } 9377836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) { 9387836SJohn.Forte@Sun.COM ve_ret->ve_lu_number_valid = 1; 9397836SJohn.Forte@Sun.COM bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8); 9407836SJohn.Forte@Sun.COM } 9417836SJohn.Forte@Sun.COM } 9427836SJohn.Forte@Sun.COM break; 9437836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_VIEW_ENTRY: 9447836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9457836SJohn.Forte@Sun.COM ret = EACCES; 9467836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9477836SJohn.Forte@Sun.COM break; 9487836SJohn.Forte@Sun.COM } 9497836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 9507836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9517836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 9527836SJohn.Forte@Sun.COM ret = EINVAL; 9537836SJohn.Forte@Sun.COM break; 9547836SJohn.Forte@Sun.COM } 9557836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9567836SJohn.Forte@Sun.COM ret = EINVAL; 9577836SJohn.Forte@Sun.COM break; 9587836SJohn.Forte@Sun.COM } 9597836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9607836SJohn.Forte@Sun.COM ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx, 9617836SJohn.Forte@Sun.COM &iocd->stmf_error); 9627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9637836SJohn.Forte@Sun.COM break; 9647836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_LIST: 9657836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 9667836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9677836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_LIST: 9687836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_LIST) 9697836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 9707836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9717836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 9727836SJohn.Forte@Sun.COM n = min(id_list->id_count, 9737836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t)); 9747836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 9757836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 9767836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)obuf; 9777836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 9789585STim.Szeto@Sun.COM if (id_entry->id_data[0] == '*') { 9799585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries > 0) { 9809585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries--; 9819585STim.Szeto@Sun.COM } 9829585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 9839585STim.Szeto@Sun.COM continue; 9849585STim.Szeto@Sun.COM } 9859585STim.Szeto@Sun.COM grpname->name_size = id_entry->id_data_size; 9869585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grpname->name, 9877836SJohn.Forte@Sun.COM id_entry->id_data_size); 9889585STim.Szeto@Sun.COM grpname++; 9897836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 9907836SJohn.Forte@Sun.COM } 9917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9927836SJohn.Forte@Sun.COM break; 9937836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_ENTRIES: 9947836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 9957836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9967836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_ENTRIES: 9977836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 9987836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9997836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 10007836SJohn.Forte@Sun.COM ret = EINVAL; 10017836SJohn.Forte@Sun.COM break; 10027836SJohn.Forte@Sun.COM } 10037836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_ENTRIES) { 10047836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 10057836SJohn.Forte@Sun.COM } 10067836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10077836SJohn.Forte@Sun.COM id_entry = stmf_lookup_id(id_list, grpname->name_size, 10087836SJohn.Forte@Sun.COM grpname->name); 10097836SJohn.Forte@Sun.COM if (!id_entry) 10107836SJohn.Forte@Sun.COM ret = ENODEV; 10117836SJohn.Forte@Sun.COM else { 10127836SJohn.Forte@Sun.COM stmf_ge_ident_t *grp_entry; 10137836SJohn.Forte@Sun.COM id_list = (stmf_id_list_t *)id_entry->id_impl_specific; 10147836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 10157836SJohn.Forte@Sun.COM n = min(id_list->id_count, 10167836SJohn.Forte@Sun.COM iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t)); 10177836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 10187836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 10197836SJohn.Forte@Sun.COM grp_entry = (stmf_ge_ident_t *)obuf; 10207836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 10219585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grp_entry->ident, 10227836SJohn.Forte@Sun.COM id_entry->id_data_size); 10239585STim.Szeto@Sun.COM grp_entry->ident_size = id_entry->id_data_size; 10247836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 10259585STim.Szeto@Sun.COM grp_entry++; 10267836SJohn.Forte@Sun.COM } 10277836SJohn.Forte@Sun.COM } 10287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10297836SJohn.Forte@Sun.COM break; 10309585STim.Szeto@Sun.COM 10317836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_VE_LIST: 10327836SJohn.Forte@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 10337836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10347836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 10359585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 10369585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 10379585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 10389585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 10399585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 10409585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 10419585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 10429585STim.Szeto@Sun.COM continue; 10437836SJohn.Forte@Sun.COM ve->ve_ndx_valid = 1; 10447836SJohn.Forte@Sun.COM ve->ve_ndx = view_entry->ve_id; 10457836SJohn.Forte@Sun.COM ve->ve_lu_number_valid = 1; 10467836SJohn.Forte@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 10477836SJohn.Forte@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 10487836SJohn.Forte@Sun.COM view_entry->ve_luid->id_data_size); 10499585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 10507836SJohn.Forte@Sun.COM ve->ve_all_hosts = 1; 10519585STim.Szeto@Sun.COM } else { 10527836SJohn.Forte@Sun.COM bcopy(view_entry->ve_hg->id_data, 10537836SJohn.Forte@Sun.COM ve->ve_host_group.name, 10547836SJohn.Forte@Sun.COM view_entry->ve_hg->id_data_size); 10559585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 10569585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 10579585STim.Szeto@Sun.COM } 10589585STim.Szeto@Sun.COM 10599585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 10607836SJohn.Forte@Sun.COM ve->ve_all_targets = 1; 10619585STim.Szeto@Sun.COM } else { 10627836SJohn.Forte@Sun.COM bcopy(view_entry->ve_tg->id_data, 10637836SJohn.Forte@Sun.COM ve->ve_target_group.name, 10647836SJohn.Forte@Sun.COM view_entry->ve_tg->id_data_size); 10659585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 10669585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 10679585STim.Szeto@Sun.COM } 10689585STim.Szeto@Sun.COM ve++; 10697836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries++; 10707836SJohn.Forte@Sun.COM } 10717836SJohn.Forte@Sun.COM } 10727836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10737836SJohn.Forte@Sun.COM break; 10749585STim.Szeto@Sun.COM 10759585STim.Szeto@Sun.COM case STMF_IOCTL_LU_VE_LIST: 10769585STim.Szeto@Sun.COM p_id = (uint8_t *)ibuf; 10779585STim.Szeto@Sun.COM if ((iocd->stmf_ibuf_size != 16) || 10789585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) { 10799585STim.Szeto@Sun.COM ret = EINVAL; 10809585STim.Szeto@Sun.COM break; 10819585STim.Szeto@Sun.COM } 10829585STim.Szeto@Sun.COM 10839585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 10849585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10859585STim.Szeto@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 10869585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 10879585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 10889585STim.Szeto@Sun.COM if (bcmp(id_entry->id_data, p_id, 16) != 0) 10899585STim.Szeto@Sun.COM continue; 10909585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 10919585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 10929585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 10939585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 10949585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 10959585STim.Szeto@Sun.COM continue; 10969585STim.Szeto@Sun.COM ve->ve_ndx_valid = 1; 10979585STim.Szeto@Sun.COM ve->ve_ndx = view_entry->ve_id; 10989585STim.Szeto@Sun.COM ve->ve_lu_number_valid = 1; 10999585STim.Szeto@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 11009585STim.Szeto@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 11019585STim.Szeto@Sun.COM view_entry->ve_luid->id_data_size); 11029585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 11039585STim.Szeto@Sun.COM ve->ve_all_hosts = 1; 11049585STim.Szeto@Sun.COM } else { 11059585STim.Szeto@Sun.COM bcopy(view_entry->ve_hg->id_data, 11069585STim.Szeto@Sun.COM ve->ve_host_group.name, 11079585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size); 11089585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 11099585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 11109585STim.Szeto@Sun.COM } 11119585STim.Szeto@Sun.COM 11129585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 11139585STim.Szeto@Sun.COM ve->ve_all_targets = 1; 11149585STim.Szeto@Sun.COM } else { 11159585STim.Szeto@Sun.COM bcopy(view_entry->ve_tg->id_data, 11169585STim.Szeto@Sun.COM ve->ve_target_group.name, 11179585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size); 11189585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 11199585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 11209585STim.Szeto@Sun.COM } 11219585STim.Szeto@Sun.COM ve++; 11229585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries++; 11239585STim.Szeto@Sun.COM } 11249585STim.Szeto@Sun.COM break; 11259585STim.Szeto@Sun.COM } 11269585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11279585STim.Szeto@Sun.COM break; 11289585STim.Szeto@Sun.COM 11297836SJohn.Forte@Sun.COM case STMF_IOCTL_LOAD_PP_DATA: 11307836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11317836SJohn.Forte@Sun.COM ret = EACCES; 11327836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11337836SJohn.Forte@Sun.COM break; 11347836SJohn.Forte@Sun.COM } 11357836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11367836SJohn.Forte@Sun.COM if ((ppi == NULL) || 11377836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11387836SJohn.Forte@Sun.COM ret = EINVAL; 11397836SJohn.Forte@Sun.COM break; 11407836SJohn.Forte@Sun.COM } 11419585STim.Szeto@Sun.COM /* returned token */ 11429585STim.Szeto@Sun.COM ppi_token = (uint64_t *)obuf; 11439585STim.Szeto@Sun.COM if ((ppi_token == NULL) || 11449585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (uint64_t))) { 11459585STim.Szeto@Sun.COM ret = EINVAL; 11469585STim.Szeto@Sun.COM break; 11479585STim.Szeto@Sun.COM } 11489585STim.Szeto@Sun.COM ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error); 11499585STim.Szeto@Sun.COM break; 11509585STim.Szeto@Sun.COM 11519585STim.Szeto@Sun.COM case STMF_IOCTL_GET_PP_DATA: 11529585STim.Szeto@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11539585STim.Szeto@Sun.COM ret = EACCES; 11549585STim.Szeto@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11559585STim.Szeto@Sun.COM break; 11569585STim.Szeto@Sun.COM } 11579585STim.Szeto@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11589585STim.Szeto@Sun.COM if (ppi == NULL || 11599585STim.Szeto@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11609585STim.Szeto@Sun.COM ret = EINVAL; 11619585STim.Szeto@Sun.COM break; 11629585STim.Szeto@Sun.COM } 11639585STim.Szeto@Sun.COM ppi_out = (stmf_ppioctl_data_t *)obuf; 11649585STim.Szeto@Sun.COM if ((ppi_out == NULL) || 11659585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) { 11669585STim.Szeto@Sun.COM ret = EINVAL; 11679585STim.Szeto@Sun.COM break; 11689585STim.Szeto@Sun.COM } 11699585STim.Szeto@Sun.COM ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error); 11707836SJohn.Forte@Sun.COM break; 11717836SJohn.Forte@Sun.COM 11727836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_PP_DATA: 11737836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11747836SJohn.Forte@Sun.COM ret = EACCES; 11757836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11767836SJohn.Forte@Sun.COM break; 11777836SJohn.Forte@Sun.COM } 11787836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11797836SJohn.Forte@Sun.COM if ((ppi == NULL) || 11807836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11817836SJohn.Forte@Sun.COM ret = EINVAL; 11827836SJohn.Forte@Sun.COM break; 11837836SJohn.Forte@Sun.COM } 11847836SJohn.Forte@Sun.COM ret = stmf_delete_ppd_ioctl(ppi); 11857836SJohn.Forte@Sun.COM break; 11867836SJohn.Forte@Sun.COM 11877836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_TRACE: 11887836SJohn.Forte@Sun.COM stmf_trace_clear(); 11897836SJohn.Forte@Sun.COM break; 11907836SJohn.Forte@Sun.COM 11917836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TRACE: 11927836SJohn.Forte@Sun.COM if (iocd->stmf_ibuf_size && ibuf) { 11937836SJohn.Forte@Sun.COM ((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0; 11947836SJohn.Forte@Sun.COM stmf_trace("\nstradm", "%s\n", ibuf); 11957836SJohn.Forte@Sun.COM } 11967836SJohn.Forte@Sun.COM break; 11977836SJohn.Forte@Sun.COM 11987836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE_POSITION: 11997836SJohn.Forte@Sun.COM if (obuf && (iocd->stmf_obuf_size > 3)) { 12007836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12017836SJohn.Forte@Sun.COM *((int *)obuf) = trace_buf_curndx; 12027836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12037836SJohn.Forte@Sun.COM } else { 12047836SJohn.Forte@Sun.COM ret = EINVAL; 12057836SJohn.Forte@Sun.COM } 12067836SJohn.Forte@Sun.COM break; 12077836SJohn.Forte@Sun.COM 12087836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE: 12097836SJohn.Forte@Sun.COM if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) { 12107836SJohn.Forte@Sun.COM ret = EINVAL; 12117836SJohn.Forte@Sun.COM break; 12127836SJohn.Forte@Sun.COM } 12137836SJohn.Forte@Sun.COM i = *((int *)ibuf); 12147836SJohn.Forte@Sun.COM if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) > 12157836SJohn.Forte@Sun.COM trace_buf_size)) { 12167836SJohn.Forte@Sun.COM ret = EINVAL; 12177836SJohn.Forte@Sun.COM break; 12187836SJohn.Forte@Sun.COM } 12197836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12207836SJohn.Forte@Sun.COM bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size); 12217836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12227836SJohn.Forte@Sun.COM break; 12237836SJohn.Forte@Sun.COM 12247836SJohn.Forte@Sun.COM default: 12257836SJohn.Forte@Sun.COM ret = ENOTTY; 12267836SJohn.Forte@Sun.COM } 12277836SJohn.Forte@Sun.COM 12287836SJohn.Forte@Sun.COM if (ret == 0) { 12297836SJohn.Forte@Sun.COM ret = stmf_copyout_iocdata(data, mode, iocd, obuf); 12307836SJohn.Forte@Sun.COM } else if (iocd->stmf_error) { 12317836SJohn.Forte@Sun.COM (void) stmf_copyout_iocdata(data, mode, iocd, obuf); 12327836SJohn.Forte@Sun.COM } 12337836SJohn.Forte@Sun.COM if (obuf) { 12347836SJohn.Forte@Sun.COM kmem_free(obuf, iocd->stmf_obuf_size); 12357836SJohn.Forte@Sun.COM obuf = NULL; 12367836SJohn.Forte@Sun.COM } 12377836SJohn.Forte@Sun.COM if (ibuf) { 12387836SJohn.Forte@Sun.COM kmem_free(ibuf, iocd->stmf_ibuf_size); 12397836SJohn.Forte@Sun.COM ibuf = NULL; 12407836SJohn.Forte@Sun.COM } 12417836SJohn.Forte@Sun.COM kmem_free(iocd, sizeof (stmf_iocdata_t)); 12427836SJohn.Forte@Sun.COM return (ret); 12437836SJohn.Forte@Sun.COM } 12447836SJohn.Forte@Sun.COM 12457836SJohn.Forte@Sun.COM static int 12467836SJohn.Forte@Sun.COM stmf_get_service_state() 12477836SJohn.Forte@Sun.COM { 12487836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 12497836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 12507836SJohn.Forte@Sun.COM int online = 0; 12517836SJohn.Forte@Sun.COM int offline = 0; 12527836SJohn.Forte@Sun.COM int onlining = 0; 12537836SJohn.Forte@Sun.COM int offlining = 0; 12547836SJohn.Forte@Sun.COM 12557836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 12567836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 12577836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 12587836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) 12597836SJohn.Forte@Sun.COM offline++; 12607836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINE) 12617836SJohn.Forte@Sun.COM online++; 12627836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINING) 12637836SJohn.Forte@Sun.COM onlining++; 12647836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_OFFLINING) 12657836SJohn.Forte@Sun.COM offlining++; 12667836SJohn.Forte@Sun.COM } 12677836SJohn.Forte@Sun.COM 12687836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 12697836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 12707836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) 12717836SJohn.Forte@Sun.COM offline++; 12727836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINE) 12737836SJohn.Forte@Sun.COM online++; 12747836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINING) 12757836SJohn.Forte@Sun.COM onlining++; 12767836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_OFFLINING) 12777836SJohn.Forte@Sun.COM offlining++; 12787836SJohn.Forte@Sun.COM } 12797836SJohn.Forte@Sun.COM 12807836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 12817836SJohn.Forte@Sun.COM if (onlining) 12827836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINING); 12837836SJohn.Forte@Sun.COM else 12847836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINE); 12857836SJohn.Forte@Sun.COM } 12867836SJohn.Forte@Sun.COM 12877836SJohn.Forte@Sun.COM if (offlining) { 12887836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINING); 12897836SJohn.Forte@Sun.COM } 12907836SJohn.Forte@Sun.COM 12917836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINE); 12927836SJohn.Forte@Sun.COM } 12937836SJohn.Forte@Sun.COM 12947836SJohn.Forte@Sun.COM static int 12957836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std) 12967836SJohn.Forte@Sun.COM { 12977836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 12987836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 12997836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 13007836SJohn.Forte@Sun.COM int svc_state; 13017836SJohn.Forte@Sun.COM 13027836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 13037836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 13047836SJohn.Forte@Sun.COM 13057836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 13067836SJohn.Forte@Sun.COM if (!stmf_state.stmf_exclusive_open) { 13077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13087836SJohn.Forte@Sun.COM return (EACCES); 13097836SJohn.Forte@Sun.COM } 13107836SJohn.Forte@Sun.COM 13117836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 13127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13137836SJohn.Forte@Sun.COM return (EBUSY); 13147836SJohn.Forte@Sun.COM } 13157836SJohn.Forte@Sun.COM 13167836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_ONLINE) && 13177836SJohn.Forte@Sun.COM (std->state != STMF_STATE_OFFLINE)) { 13187836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13197836SJohn.Forte@Sun.COM return (EINVAL); 13207836SJohn.Forte@Sun.COM } 13217836SJohn.Forte@Sun.COM 13227836SJohn.Forte@Sun.COM svc_state = stmf_get_service_state(); 13237836SJohn.Forte@Sun.COM if ((svc_state == STMF_STATE_OFFLINING) || 13247836SJohn.Forte@Sun.COM (svc_state == STMF_STATE_ONLINING)) { 13257836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13267836SJohn.Forte@Sun.COM return (EBUSY); 13277836SJohn.Forte@Sun.COM } 13287836SJohn.Forte@Sun.COM 13297836SJohn.Forte@Sun.COM if (svc_state == STMF_STATE_OFFLINE) { 13307836SJohn.Forte@Sun.COM if (std->config_state == STMF_CONFIG_INIT) { 13317836SJohn.Forte@Sun.COM if (std->state != STMF_STATE_OFFLINE) { 13327836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13337836SJohn.Forte@Sun.COM return (EINVAL); 13347836SJohn.Forte@Sun.COM } 13357836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT; 13367836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 13377836SJohn.Forte@Sun.COM stmf_view_clear_config(); 13387836SJohn.Forte@Sun.COM stmf_view_init(); 13397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13407836SJohn.Forte@Sun.COM return (0); 13417836SJohn.Forte@Sun.COM } 13427836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 13437836SJohn.Forte@Sun.COM if (std->config_state != STMF_CONFIG_INIT_DONE) { 13447836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13457836SJohn.Forte@Sun.COM return (EINVAL); 13467836SJohn.Forte@Sun.COM } 13477836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE; 13487836SJohn.Forte@Sun.COM } 13497836SJohn.Forte@Sun.COM if (std->state == STMF_STATE_OFFLINE) { 13507836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13517836SJohn.Forte@Sun.COM return (0); 13527836SJohn.Forte@Sun.COM } 13537836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 13547836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13557836SJohn.Forte@Sun.COM return (EINVAL); 13567836SJohn.Forte@Sun.COM } 13577836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 13587836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 1; 13597836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13607836SJohn.Forte@Sun.COM 13617836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 13627836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 13637836SJohn.Forte@Sun.COM if (ilport->ilport_prev_state != STMF_STATE_ONLINE) 13647836SJohn.Forte@Sun.COM continue; 13657836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, 13668662SJordan.Vaughan@Sun.com ilport->ilport_lport, &ssi); 13677836SJohn.Forte@Sun.COM } 13687836SJohn.Forte@Sun.COM 13697836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 13707836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 13717836SJohn.Forte@Sun.COM if (ilu->ilu_prev_state != STMF_STATE_ONLINE) 13727836SJohn.Forte@Sun.COM continue; 13737836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi); 13747836SJohn.Forte@Sun.COM } 13757836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 13767836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 13777836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13787836SJohn.Forte@Sun.COM return (0); 13797836SJohn.Forte@Sun.COM } 13807836SJohn.Forte@Sun.COM 13817836SJohn.Forte@Sun.COM /* svc_state is STMF_STATE_ONLINE here */ 13827836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_OFFLINE) || 13837836SJohn.Forte@Sun.COM (std->config_state == STMF_CONFIG_INIT)) { 13847836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13857836SJohn.Forte@Sun.COM return (EACCES); 13867836SJohn.Forte@Sun.COM } 13877836SJohn.Forte@Sun.COM 13887836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 13897836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 13907836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 13917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13927836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 13937836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 13947836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) 13957836SJohn.Forte@Sun.COM continue; 13967836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, 13977836SJohn.Forte@Sun.COM ilport->ilport_lport, &ssi); 13987836SJohn.Forte@Sun.COM } 13997836SJohn.Forte@Sun.COM 14007836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 14017836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 14027836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) 14037836SJohn.Forte@Sun.COM continue; 14047836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi); 14057836SJohn.Forte@Sun.COM } 14067836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14077836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 14087836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14097836SJohn.Forte@Sun.COM return (0); 14107836SJohn.Forte@Sun.COM } 14117836SJohn.Forte@Sun.COM 14127836SJohn.Forte@Sun.COM static int 14137836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std) 14147836SJohn.Forte@Sun.COM { 14157836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14167836SJohn.Forte@Sun.COM std->state = stmf_get_service_state(); 14177836SJohn.Forte@Sun.COM std->config_state = stmf_state.stmf_config_state; 14187836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14197836SJohn.Forte@Sun.COM 14207836SJohn.Forte@Sun.COM return (0); 14217836SJohn.Forte@Sun.COM } 14227836SJohn.Forte@Sun.COM 14237836SJohn.Forte@Sun.COM typedef struct { 14247836SJohn.Forte@Sun.COM void *bp; /* back pointer from internal struct to main struct */ 14257836SJohn.Forte@Sun.COM int alloc_size; 14267836SJohn.Forte@Sun.COM } __istmf_t; 14277836SJohn.Forte@Sun.COM 14287836SJohn.Forte@Sun.COM typedef struct { 14297836SJohn.Forte@Sun.COM __istmf_t *fp; /* Framework private */ 14307836SJohn.Forte@Sun.COM void *cp; /* Caller private */ 14317836SJohn.Forte@Sun.COM void *ss; /* struct specific */ 14327836SJohn.Forte@Sun.COM } __stmf_t; 14337836SJohn.Forte@Sun.COM 14347836SJohn.Forte@Sun.COM static struct { 14357836SJohn.Forte@Sun.COM int shared; 14367836SJohn.Forte@Sun.COM int fw_private; 14377836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 }, 14387836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_provider_t), 14397836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_provider_t) }, 14407836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_port_provider_t), 14417836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_port_provider_t) }, 14427836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_local_port_t), 14437836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_local_port_t) }, 14447836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_t), 14457836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_t) }, 14467836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_scsi_session_t), 14477836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_session_t) }, 14487836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(scsi_task_t), 14497836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_task_t) }, 14507836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_data_buf_t), 14517836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) }, 14527836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_dbuf_store_t), 14537836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) } 14547836SJohn.Forte@Sun.COM 14557836SJohn.Forte@Sun.COM }; 14567836SJohn.Forte@Sun.COM 14577836SJohn.Forte@Sun.COM void * 14587836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags) 14597836SJohn.Forte@Sun.COM { 14607836SJohn.Forte@Sun.COM int stmf_size; 14617836SJohn.Forte@Sun.COM int kmem_flag; 14627836SJohn.Forte@Sun.COM __stmf_t *sh; 14637836SJohn.Forte@Sun.COM 14647836SJohn.Forte@Sun.COM if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS)) 14657836SJohn.Forte@Sun.COM return (NULL); 14667836SJohn.Forte@Sun.COM 14677836SJohn.Forte@Sun.COM if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) { 14687836SJohn.Forte@Sun.COM kmem_flag = KM_NOSLEEP; 14697836SJohn.Forte@Sun.COM } else { 14707836SJohn.Forte@Sun.COM kmem_flag = KM_SLEEP; 14717836SJohn.Forte@Sun.COM } 14727836SJohn.Forte@Sun.COM 14737836SJohn.Forte@Sun.COM additional_size = (additional_size + 7) & (~7); 14747836SJohn.Forte@Sun.COM stmf_size = stmf_sizes[struct_id].shared + 14758662SJordan.Vaughan@Sun.com stmf_sizes[struct_id].fw_private + additional_size; 14767836SJohn.Forte@Sun.COM 14777836SJohn.Forte@Sun.COM sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag); 14787836SJohn.Forte@Sun.COM 14797836SJohn.Forte@Sun.COM if (sh == NULL) 14807836SJohn.Forte@Sun.COM return (NULL); 14817836SJohn.Forte@Sun.COM 14829087SZhong.Wang@Sun.COM /* 14839087SZhong.Wang@Sun.COM * In principle, the implementation inside stmf_alloc should not 14849087SZhong.Wang@Sun.COM * be changed anyway. But the original order of framework private 14859087SZhong.Wang@Sun.COM * data and caller private data does not support sglist in the caller 14869087SZhong.Wang@Sun.COM * private data. 14879087SZhong.Wang@Sun.COM * To work around this, the memory segments of framework private 14889087SZhong.Wang@Sun.COM * data and caller private data are re-ordered here. 14899087SZhong.Wang@Sun.COM * A better solution is to provide a specific interface to allocate 14909087SZhong.Wang@Sun.COM * the sglist, then we will not need this workaround any more. 14919087SZhong.Wang@Sun.COM * But before the new interface is available, the memory segment 14929087SZhong.Wang@Sun.COM * ordering should be kept as is. 14939087SZhong.Wang@Sun.COM */ 14949087SZhong.Wang@Sun.COM sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); 14959087SZhong.Wang@Sun.COM sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, 14969087SZhong.Wang@Sun.COM stmf_sizes[struct_id].shared + additional_size); 14977836SJohn.Forte@Sun.COM 14987836SJohn.Forte@Sun.COM sh->fp->bp = sh; 14997836SJohn.Forte@Sun.COM /* Just store the total size instead of storing additional size */ 15007836SJohn.Forte@Sun.COM sh->fp->alloc_size = stmf_size; 15017836SJohn.Forte@Sun.COM 15027836SJohn.Forte@Sun.COM return (sh); 15037836SJohn.Forte@Sun.COM } 15047836SJohn.Forte@Sun.COM 15057836SJohn.Forte@Sun.COM void 15067836SJohn.Forte@Sun.COM stmf_free(void *ptr) 15077836SJohn.Forte@Sun.COM { 15087836SJohn.Forte@Sun.COM __stmf_t *sh = (__stmf_t *)ptr; 15097836SJohn.Forte@Sun.COM 15107836SJohn.Forte@Sun.COM /* 15117836SJohn.Forte@Sun.COM * So far we dont need any struct specific processing. If such 15127836SJohn.Forte@Sun.COM * a need ever arises, then store the struct id in the framework 15137836SJohn.Forte@Sun.COM * private section and get it here as sh->fp->struct_id. 15147836SJohn.Forte@Sun.COM */ 15157836SJohn.Forte@Sun.COM kmem_free(ptr, sh->fp->alloc_size); 15167836SJohn.Forte@Sun.COM } 15177836SJohn.Forte@Sun.COM 15187836SJohn.Forte@Sun.COM /* 15197836SJohn.Forte@Sun.COM * Given a pointer to stmf_lu_t, verifies if this lu is registered with the 15207836SJohn.Forte@Sun.COM * framework and returns a pointer to framework private data for the lu. 15217836SJohn.Forte@Sun.COM * Returns NULL if the lu was not found. 15227836SJohn.Forte@Sun.COM */ 15237836SJohn.Forte@Sun.COM stmf_i_lu_t * 15247836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu) 15257836SJohn.Forte@Sun.COM { 15267836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 15277836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 15287836SJohn.Forte@Sun.COM 15297836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 15307836SJohn.Forte@Sun.COM if (ilu->ilu_lu == lu) 15317836SJohn.Forte@Sun.COM return (ilu); 15327836SJohn.Forte@Sun.COM } 15337836SJohn.Forte@Sun.COM return (NULL); 15347836SJohn.Forte@Sun.COM } 15357836SJohn.Forte@Sun.COM 15367836SJohn.Forte@Sun.COM /* 15378818STim.Szeto@Sun.COM * Given a pointer to stmf_local_port_t, verifies if this lport is registered 15388818STim.Szeto@Sun.COM * with the framework and returns a pointer to framework private data for 15398818STim.Szeto@Sun.COM * the lport. 15408818STim.Szeto@Sun.COM * Returns NULL if the lport was not found. 15417836SJohn.Forte@Sun.COM */ 15427836SJohn.Forte@Sun.COM stmf_i_local_port_t * 15437836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport) 15447836SJohn.Forte@Sun.COM { 15457836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 15467836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 15477836SJohn.Forte@Sun.COM 15487836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 15497836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 15507836SJohn.Forte@Sun.COM if (ilport->ilport_lport == lport) 15517836SJohn.Forte@Sun.COM return (ilport); 15527836SJohn.Forte@Sun.COM } 15537836SJohn.Forte@Sun.COM return (NULL); 15547836SJohn.Forte@Sun.COM } 15557836SJohn.Forte@Sun.COM 15567836SJohn.Forte@Sun.COM stmf_status_t 15577836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp) 15587836SJohn.Forte@Sun.COM { 15597836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 15607836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 15617836SJohn.Forte@Sun.COM uint32_t cb_flags; 15627836SJohn.Forte@Sun.COM 15637836SJohn.Forte@Sun.COM if (lp->lp_lpif_rev != LPIF_REV_1) 15647836SJohn.Forte@Sun.COM return (STMF_FAILURE); 15657836SJohn.Forte@Sun.COM 15667836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15677836SJohn.Forte@Sun.COM ilp->ilp_next = stmf_state.stmf_ilplist; 15687836SJohn.Forte@Sun.COM stmf_state.stmf_ilplist = ilp; 15697836SJohn.Forte@Sun.COM stmf_state.stmf_nlps++; 15707836SJohn.Forte@Sun.COM 15717836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 15727836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 15737836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, lp->lp_name) == 0) { 15747836SJohn.Forte@Sun.COM break; 15757836SJohn.Forte@Sun.COM } 15767836SJohn.Forte@Sun.COM } 15777836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 15787836SJohn.Forte@Sun.COM goto rlp_bail_out; 15797836SJohn.Forte@Sun.COM } 15807836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 15817836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 15827836SJohn.Forte@Sun.COM if (lp->lp_cb == NULL) 15837836SJohn.Forte@Sun.COM goto rlp_bail_out; 15847836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 15857836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 15867836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 15877836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 15887836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15897836SJohn.Forte@Sun.COM lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 15907836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15917836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 15927836SJohn.Forte@Sun.COM 15937836SJohn.Forte@Sun.COM rlp_bail_out: 15947836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15957836SJohn.Forte@Sun.COM 15967836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 15977836SJohn.Forte@Sun.COM } 15987836SJohn.Forte@Sun.COM 15997836SJohn.Forte@Sun.COM stmf_status_t 16007836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp) 16017836SJohn.Forte@Sun.COM { 16027836SJohn.Forte@Sun.COM stmf_i_lu_provider_t **ppilp; 16037836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 16047836SJohn.Forte@Sun.COM 16057836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16067836SJohn.Forte@Sun.COM if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) { 16077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16087836SJohn.Forte@Sun.COM return (STMF_BUSY); 16097836SJohn.Forte@Sun.COM } 16107836SJohn.Forte@Sun.COM for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL; 16117836SJohn.Forte@Sun.COM ppilp = &((*ppilp)->ilp_next)) { 16127836SJohn.Forte@Sun.COM if (*ppilp == ilp) { 16137836SJohn.Forte@Sun.COM *ppilp = ilp->ilp_next; 16147836SJohn.Forte@Sun.COM stmf_state.stmf_nlps--; 16157836SJohn.Forte@Sun.COM if (ilp->ilp_ppd) { 16167836SJohn.Forte@Sun.COM ilp->ilp_ppd->ppd_provider = NULL; 16177836SJohn.Forte@Sun.COM ilp->ilp_ppd = NULL; 16187836SJohn.Forte@Sun.COM } 16197836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16207836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16217836SJohn.Forte@Sun.COM } 16227836SJohn.Forte@Sun.COM } 16237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16247836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 16257836SJohn.Forte@Sun.COM } 16267836SJohn.Forte@Sun.COM 16277836SJohn.Forte@Sun.COM stmf_status_t 16287836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp) 16297836SJohn.Forte@Sun.COM { 16307836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 16317836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 16327836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 16337836SJohn.Forte@Sun.COM uint32_t cb_flags; 16347836SJohn.Forte@Sun.COM 16357836SJohn.Forte@Sun.COM if (pp->pp_portif_rev != PORTIF_REV_1) 16367836SJohn.Forte@Sun.COM return (STMF_FAILURE); 16377836SJohn.Forte@Sun.COM 16387836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16397836SJohn.Forte@Sun.COM ipp->ipp_next = stmf_state.stmf_ipplist; 16407836SJohn.Forte@Sun.COM stmf_state.stmf_ipplist = ipp; 16417836SJohn.Forte@Sun.COM stmf_state.stmf_npps++; 16427836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 16437836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 16447836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, pp->pp_name) == 0) { 16457836SJohn.Forte@Sun.COM break; 16467836SJohn.Forte@Sun.COM } 16477836SJohn.Forte@Sun.COM } 16487836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 16497836SJohn.Forte@Sun.COM goto rpp_bail_out; 16507836SJohn.Forte@Sun.COM } 16517836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 16527836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 16537836SJohn.Forte@Sun.COM if (pp->pp_cb == NULL) 16547836SJohn.Forte@Sun.COM goto rpp_bail_out; 16557836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 16567836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 16577836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 16587836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 16597836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16607836SJohn.Forte@Sun.COM pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 16617836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16627836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 16637836SJohn.Forte@Sun.COM 16647836SJohn.Forte@Sun.COM rpp_bail_out: 16657836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16667836SJohn.Forte@Sun.COM 16677836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16687836SJohn.Forte@Sun.COM } 16697836SJohn.Forte@Sun.COM 16707836SJohn.Forte@Sun.COM stmf_status_t 16717836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp) 16727836SJohn.Forte@Sun.COM { 16737836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 16747836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 16757836SJohn.Forte@Sun.COM stmf_i_port_provider_t **ppipp; 16767836SJohn.Forte@Sun.COM 16777836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16787836SJohn.Forte@Sun.COM if (ipp->ipp_npps || ipp->ipp_cb_in_progress) { 16797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16807836SJohn.Forte@Sun.COM return (STMF_BUSY); 16817836SJohn.Forte@Sun.COM } 16827836SJohn.Forte@Sun.COM for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL; 16837836SJohn.Forte@Sun.COM ppipp = &((*ppipp)->ipp_next)) { 16847836SJohn.Forte@Sun.COM if (*ppipp == ipp) { 16857836SJohn.Forte@Sun.COM *ppipp = ipp->ipp_next; 16867836SJohn.Forte@Sun.COM stmf_state.stmf_npps--; 16877836SJohn.Forte@Sun.COM if (ipp->ipp_ppd) { 16887836SJohn.Forte@Sun.COM ipp->ipp_ppd->ppd_provider = NULL; 16897836SJohn.Forte@Sun.COM ipp->ipp_ppd = NULL; 16907836SJohn.Forte@Sun.COM } 16917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16927836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16937836SJohn.Forte@Sun.COM } 16947836SJohn.Forte@Sun.COM } 16957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16967836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 16977836SJohn.Forte@Sun.COM } 16987836SJohn.Forte@Sun.COM 16997836SJohn.Forte@Sun.COM int 17009585STim.Szeto@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 17019585STim.Szeto@Sun.COM uint32_t *err_ret) 17027836SJohn.Forte@Sun.COM { 17037836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp; 17047836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 17057836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 17067836SJohn.Forte@Sun.COM nvlist_t *nv; 17077836SJohn.Forte@Sun.COM int s; 17087836SJohn.Forte@Sun.COM int ret; 17097836SJohn.Forte@Sun.COM 17109585STim.Szeto@Sun.COM *err_ret = 0; 17119585STim.Szeto@Sun.COM 17127836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 17137836SJohn.Forte@Sun.COM return (EINVAL); 17147836SJohn.Forte@Sun.COM } 17157836SJohn.Forte@Sun.COM 17167836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 17177836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 17187836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 17197836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 17207836SJohn.Forte@Sun.COM continue; 17217836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 17227836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 17237836SJohn.Forte@Sun.COM continue; 17247836SJohn.Forte@Sun.COM } 17257836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 17267836SJohn.Forte@Sun.COM break; 17277836SJohn.Forte@Sun.COM } 17287836SJohn.Forte@Sun.COM 17297836SJohn.Forte@Sun.COM if (ppd == NULL) { 17307836SJohn.Forte@Sun.COM /* New provider */ 17317836SJohn.Forte@Sun.COM s = strlen(ppi->ppi_name); 17327836SJohn.Forte@Sun.COM if (s > 254) { 17337836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17347836SJohn.Forte@Sun.COM return (EINVAL); 17357836SJohn.Forte@Sun.COM } 17367836SJohn.Forte@Sun.COM s += sizeof (stmf_pp_data_t) - 7; 17377836SJohn.Forte@Sun.COM 17387836SJohn.Forte@Sun.COM ppd = kmem_zalloc(s, KM_NOSLEEP); 17397836SJohn.Forte@Sun.COM if (ppd == NULL) { 17407836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17417836SJohn.Forte@Sun.COM return (ENOMEM); 17427836SJohn.Forte@Sun.COM } 17437836SJohn.Forte@Sun.COM ppd->ppd_alloc_size = s; 17447836SJohn.Forte@Sun.COM (void) strcpy(ppd->ppd_name, ppi->ppi_name); 17457836SJohn.Forte@Sun.COM 17467836SJohn.Forte@Sun.COM /* See if this provider already exists */ 17477836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 17487836SJohn.Forte@Sun.COM ppd->ppd_lu_provider = 1; 17497836SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; 17507836SJohn.Forte@Sun.COM ilp = ilp->ilp_next) { 17517836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 17527836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 17537836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 17547836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 17557836SJohn.Forte@Sun.COM break; 17567836SJohn.Forte@Sun.COM } 17577836SJohn.Forte@Sun.COM } 17587836SJohn.Forte@Sun.COM } else { 17597836SJohn.Forte@Sun.COM ppd->ppd_port_provider = 1; 17607836SJohn.Forte@Sun.COM for (ipp = stmf_state.stmf_ipplist; ipp != NULL; 17617836SJohn.Forte@Sun.COM ipp = ipp->ipp_next) { 17627836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 17637836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_name) == 0) { 17647836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 17657836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 17667836SJohn.Forte@Sun.COM break; 17677836SJohn.Forte@Sun.COM } 17687836SJohn.Forte@Sun.COM } 17697836SJohn.Forte@Sun.COM } 17707836SJohn.Forte@Sun.COM 17717836SJohn.Forte@Sun.COM /* Link this ppd in */ 17727836SJohn.Forte@Sun.COM ppd->ppd_next = stmf_state.stmf_ppdlist; 17737836SJohn.Forte@Sun.COM stmf_state.stmf_ppdlist = ppd; 17747836SJohn.Forte@Sun.COM } 17757836SJohn.Forte@Sun.COM 17769585STim.Szeto@Sun.COM /* 17779585STim.Szeto@Sun.COM * User is requesting that the token be checked. 17789585STim.Szeto@Sun.COM * If there was another set after the user's get 17799585STim.Szeto@Sun.COM * it's an error 17809585STim.Szeto@Sun.COM */ 17819585STim.Szeto@Sun.COM if (ppi->ppi_token_valid) { 17829585STim.Szeto@Sun.COM if (ppi->ppi_token != ppd->ppd_token) { 17839585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_PPD_UPDATED; 17849585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17859585STim.Szeto@Sun.COM return (EINVAL); 17869585STim.Szeto@Sun.COM } 17879585STim.Szeto@Sun.COM } 17889585STim.Szeto@Sun.COM 17897836SJohn.Forte@Sun.COM if ((ret = nvlist_unpack((char *)ppi->ppi_data, 17907836SJohn.Forte@Sun.COM (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) { 17917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17927836SJohn.Forte@Sun.COM return (ret); 17937836SJohn.Forte@Sun.COM } 17947836SJohn.Forte@Sun.COM 17957836SJohn.Forte@Sun.COM /* Free any existing lists and add this one to the ppd */ 17967836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 17977836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 17987836SJohn.Forte@Sun.COM ppd->ppd_nv = nv; 17997836SJohn.Forte@Sun.COM 18009585STim.Szeto@Sun.COM /* set the token for writes */ 18019585STim.Szeto@Sun.COM ppd->ppd_token++; 18029585STim.Szeto@Sun.COM /* return token to caller */ 18039585STim.Szeto@Sun.COM if (ppi_token) { 18049585STim.Szeto@Sun.COM *ppi_token = ppd->ppd_token; 18059585STim.Szeto@Sun.COM } 18069585STim.Szeto@Sun.COM 18077836SJohn.Forte@Sun.COM /* If there is a provider registered, do the notifications */ 18087836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 18097836SJohn.Forte@Sun.COM uint32_t cb_flags = 0; 18107836SJohn.Forte@Sun.COM 18117836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 18127836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 18137836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 18147836SJohn.Forte@Sun.COM ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider; 18157836SJohn.Forte@Sun.COM if (ilp->ilp_lp->lp_cb == NULL) 18167836SJohn.Forte@Sun.COM goto bail_out; 18177836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 18187836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18197836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_cb(ilp->ilp_lp, 18207836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 18217836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18227836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 18237836SJohn.Forte@Sun.COM } else { 18247836SJohn.Forte@Sun.COM ipp = (stmf_i_port_provider_t *)ppd->ppd_provider; 18257836SJohn.Forte@Sun.COM if (ipp->ipp_pp->pp_cb == NULL) 18267836SJohn.Forte@Sun.COM goto bail_out; 18277836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 18287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18297836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_cb(ipp->ipp_pp, 18307836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 18317836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18327836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 18337836SJohn.Forte@Sun.COM } 18347836SJohn.Forte@Sun.COM } 18357836SJohn.Forte@Sun.COM 18367836SJohn.Forte@Sun.COM bail_out: 18377836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18387836SJohn.Forte@Sun.COM 18397836SJohn.Forte@Sun.COM return (0); 18407836SJohn.Forte@Sun.COM } 18417836SJohn.Forte@Sun.COM 18427836SJohn.Forte@Sun.COM void 18437836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd) 18447836SJohn.Forte@Sun.COM { 18457836SJohn.Forte@Sun.COM stmf_pp_data_t **pppd; 18467836SJohn.Forte@Sun.COM 18477836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 18487836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 18497836SJohn.Forte@Sun.COM if (ppd->ppd_lu_provider) { 18507836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 18517836SJohn.Forte@Sun.COM ppd->ppd_provider)->ilp_ppd = NULL; 18527836SJohn.Forte@Sun.COM } else { 18537836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 18547836SJohn.Forte@Sun.COM ppd->ppd_provider)->ipp_ppd = NULL; 18557836SJohn.Forte@Sun.COM } 18567836SJohn.Forte@Sun.COM ppd->ppd_provider = NULL; 18577836SJohn.Forte@Sun.COM } 18587836SJohn.Forte@Sun.COM 18597836SJohn.Forte@Sun.COM for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL; 18608662SJordan.Vaughan@Sun.com pppd = &((*pppd)->ppd_next)) { 18617836SJohn.Forte@Sun.COM if (*pppd == ppd) 18627836SJohn.Forte@Sun.COM break; 18637836SJohn.Forte@Sun.COM } 18647836SJohn.Forte@Sun.COM 18657836SJohn.Forte@Sun.COM if (*pppd == NULL) 18667836SJohn.Forte@Sun.COM return; 18677836SJohn.Forte@Sun.COM 18687836SJohn.Forte@Sun.COM *pppd = ppd->ppd_next; 18697836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 18707836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 18717836SJohn.Forte@Sun.COM 18727836SJohn.Forte@Sun.COM kmem_free(ppd, ppd->ppd_alloc_size); 18737836SJohn.Forte@Sun.COM } 18747836SJohn.Forte@Sun.COM 18757836SJohn.Forte@Sun.COM int 18767836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi) 18777836SJohn.Forte@Sun.COM { 18787836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 18797836SJohn.Forte@Sun.COM int ret = ENOENT; 18807836SJohn.Forte@Sun.COM 18817836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 18827836SJohn.Forte@Sun.COM return (EINVAL); 18837836SJohn.Forte@Sun.COM } 18847836SJohn.Forte@Sun.COM 18857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18867836SJohn.Forte@Sun.COM 18877836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 18887836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 18897836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 18907836SJohn.Forte@Sun.COM continue; 18917836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 18927836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 18937836SJohn.Forte@Sun.COM continue; 18947836SJohn.Forte@Sun.COM } 18957836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 18967836SJohn.Forte@Sun.COM break; 18977836SJohn.Forte@Sun.COM } 18987836SJohn.Forte@Sun.COM 18997836SJohn.Forte@Sun.COM if (ppd) { 19007836SJohn.Forte@Sun.COM ret = 0; 19017836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 19027836SJohn.Forte@Sun.COM } 19037836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19047836SJohn.Forte@Sun.COM 19057836SJohn.Forte@Sun.COM return (ret); 19067836SJohn.Forte@Sun.COM } 19077836SJohn.Forte@Sun.COM 19089585STim.Szeto@Sun.COM int 19099585STim.Szeto@Sun.COM stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 19109585STim.Szeto@Sun.COM uint32_t *err_ret) 19119585STim.Szeto@Sun.COM { 19129585STim.Szeto@Sun.COM stmf_pp_data_t *ppd; 19139585STim.Szeto@Sun.COM size_t req_size; 19149585STim.Szeto@Sun.COM int ret = ENOENT; 19159585STim.Szeto@Sun.COM char *bufp = (char *)ppi_out->ppi_data; 19169585STim.Szeto@Sun.COM 19179585STim.Szeto@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 19189585STim.Szeto@Sun.COM return (EINVAL); 19199585STim.Szeto@Sun.COM } 19209585STim.Szeto@Sun.COM 19219585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 19229585STim.Szeto@Sun.COM 19239585STim.Szeto@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 19249585STim.Szeto@Sun.COM if (ppi->ppi_lu_provider) { 19259585STim.Szeto@Sun.COM if (!ppd->ppd_lu_provider) 19269585STim.Szeto@Sun.COM continue; 19279585STim.Szeto@Sun.COM } else if (ppi->ppi_port_provider) { 19289585STim.Szeto@Sun.COM if (!ppd->ppd_port_provider) 19299585STim.Szeto@Sun.COM continue; 19309585STim.Szeto@Sun.COM } 19319585STim.Szeto@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 19329585STim.Szeto@Sun.COM break; 19339585STim.Szeto@Sun.COM } 19349585STim.Szeto@Sun.COM 19359585STim.Szeto@Sun.COM if (ppd && ppd->ppd_nv) { 19369585STim.Szeto@Sun.COM ppi_out->ppi_token = ppd->ppd_token; 19379585STim.Szeto@Sun.COM if ((ret = nvlist_size(ppd->ppd_nv, &req_size, 19389585STim.Szeto@Sun.COM NV_ENCODE_XDR)) != 0) { 19399585STim.Szeto@Sun.COM goto done; 19409585STim.Szeto@Sun.COM } 19419585STim.Szeto@Sun.COM ppi_out->ppi_data_size = req_size; 19429585STim.Szeto@Sun.COM if (req_size > ppi->ppi_data_size) { 19439585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_INSUFFICIENT_BUF; 19449585STim.Szeto@Sun.COM ret = EINVAL; 19459585STim.Szeto@Sun.COM goto done; 19469585STim.Szeto@Sun.COM } 19479585STim.Szeto@Sun.COM 19489585STim.Szeto@Sun.COM if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size, 19499585STim.Szeto@Sun.COM NV_ENCODE_XDR, 0)) != 0) { 19509585STim.Szeto@Sun.COM goto done; 19519585STim.Szeto@Sun.COM } 19529585STim.Szeto@Sun.COM ret = 0; 19539585STim.Szeto@Sun.COM } 19549585STim.Szeto@Sun.COM 19559585STim.Szeto@Sun.COM done: 19569585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19579585STim.Szeto@Sun.COM 19589585STim.Szeto@Sun.COM return (ret); 19599585STim.Szeto@Sun.COM } 19609585STim.Szeto@Sun.COM 19617836SJohn.Forte@Sun.COM void 19627836SJohn.Forte@Sun.COM stmf_delete_all_ppds() 19637836SJohn.Forte@Sun.COM { 19647836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd, *nppd; 19657836SJohn.Forte@Sun.COM 19667836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 19677836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) { 19687836SJohn.Forte@Sun.COM nppd = ppd->ppd_next; 19697836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 19707836SJohn.Forte@Sun.COM } 19717836SJohn.Forte@Sun.COM } 19727836SJohn.Forte@Sun.COM 19739435STim.Szeto@Sun.COM /* 19749435STim.Szeto@Sun.COM * 16 is the max string length of a protocol_ident, increase 19759435STim.Szeto@Sun.COM * the size if needed. 19769435STim.Szeto@Sun.COM */ 19779435STim.Szeto@Sun.COM #define STMF_KSTAT_LU_SZ (STMF_GUID_INPUT + 1 + 256) 19789435STim.Szeto@Sun.COM #define STMF_KSTAT_TGT_SZ (256 * 2 + 16) 19799435STim.Szeto@Sun.COM 19809435STim.Szeto@Sun.COM typedef struct stmf_kstat_lu_info { 19819435STim.Szeto@Sun.COM kstat_named_t i_lun_guid; 19829435STim.Szeto@Sun.COM kstat_named_t i_lun_alias; 19839435STim.Szeto@Sun.COM } stmf_kstat_lu_info_t; 19849435STim.Szeto@Sun.COM 19859435STim.Szeto@Sun.COM typedef struct stmf_kstat_tgt_info { 19869435STim.Szeto@Sun.COM kstat_named_t i_tgt_name; 19879435STim.Szeto@Sun.COM kstat_named_t i_tgt_alias; 19889435STim.Szeto@Sun.COM kstat_named_t i_protocol; 19899435STim.Szeto@Sun.COM } stmf_kstat_tgt_info_t; 19909435STim.Szeto@Sun.COM 19919435STim.Szeto@Sun.COM /* 19929435STim.Szeto@Sun.COM * This array matches the Protocol Identifier in stmf_ioctl.h 19939435STim.Szeto@Sun.COM */ 19949435STim.Szeto@Sun.COM char *protocol_ident[PROTOCOL_ANY] = { 19959435STim.Szeto@Sun.COM "Fibre Channel", 19969435STim.Szeto@Sun.COM "Parallel SCSI", 19979435STim.Szeto@Sun.COM "SSA", 19989435STim.Szeto@Sun.COM "IEEE_1394", 19999435STim.Szeto@Sun.COM "SRP", 20009435STim.Szeto@Sun.COM "iSCSI", 20019435STim.Szeto@Sun.COM "SAS", 20029435STim.Szeto@Sun.COM "ADT", 20039435STim.Szeto@Sun.COM "ATAPI", 20049435STim.Szeto@Sun.COM "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN" 20059435STim.Szeto@Sun.COM }; 20069435STim.Szeto@Sun.COM 20079435STim.Szeto@Sun.COM /* 20089435STim.Szeto@Sun.COM * Update the lun wait/run queue count 20099435STim.Szeto@Sun.COM */ 20109435STim.Szeto@Sun.COM static void 20119435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(scsi_task_t *task, void func()) 20129435STim.Szeto@Sun.COM { 20139435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 20149435STim.Szeto@Sun.COM kstat_io_t *kip; 20159435STim.Szeto@Sun.COM 20169435STim.Szeto@Sun.COM if (task->task_lu == dlun0) 20179435STim.Szeto@Sun.COM return; 20189435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 20199435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 20209435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 20219435STim.Szeto@Sun.COM if (kip != NULL) { 20229435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 20239435STim.Szeto@Sun.COM func(kip); 20249435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 20259435STim.Szeto@Sun.COM } 20269435STim.Szeto@Sun.COM } 20279435STim.Szeto@Sun.COM } 20289435STim.Szeto@Sun.COM 20299435STim.Szeto@Sun.COM /* 20309435STim.Szeto@Sun.COM * Update the target(lport) wait/run queue count 20319435STim.Szeto@Sun.COM */ 20329435STim.Szeto@Sun.COM static void 20339435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(scsi_task_t *task, void func()) 20349435STim.Szeto@Sun.COM { 20359435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 20369435STim.Szeto@Sun.COM kstat_io_t *kip; 20379435STim.Szeto@Sun.COM 20389435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 20399435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 20409435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 20419435STim.Szeto@Sun.COM if (kip != NULL) { 20429435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 20439435STim.Szeto@Sun.COM func(kip); 20449435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 20459435STim.Szeto@Sun.COM } 20469435STim.Szeto@Sun.COM } 20479435STim.Szeto@Sun.COM } 20489435STim.Szeto@Sun.COM 20499435STim.Szeto@Sun.COM static void 20509435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 20519435STim.Szeto@Sun.COM { 20529435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 20539435STim.Szeto@Sun.COM kstat_io_t *kip; 20549435STim.Szeto@Sun.COM 20559435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 20569435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 20579435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 20589435STim.Szeto@Sun.COM if (kip != NULL) { 20599435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 20609435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 20619435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 20629435STim.Szeto@Sun.COM } 20639435STim.Szeto@Sun.COM } 20649435STim.Szeto@Sun.COM } 20659435STim.Szeto@Sun.COM 20669435STim.Szeto@Sun.COM static void 20679435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 20689435STim.Szeto@Sun.COM { 20699435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 20709435STim.Szeto@Sun.COM kstat_io_t *kip; 20719435STim.Szeto@Sun.COM 20729435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 20739435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 20749435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 20759435STim.Szeto@Sun.COM if (kip != NULL) { 20769435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 20779435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 20789435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 20799435STim.Szeto@Sun.COM } 20809435STim.Szeto@Sun.COM } 20819435STim.Szeto@Sun.COM } 20829435STim.Szeto@Sun.COM 20839435STim.Szeto@Sun.COM static void 20849435STim.Szeto@Sun.COM stmf_create_kstat_lu(stmf_i_lu_t *ilu) 20859435STim.Szeto@Sun.COM { 20869435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 20879435STim.Szeto@Sun.COM stmf_kstat_lu_info_t *ks_lu; 20889435STim.Szeto@Sun.COM 20899435STim.Szeto@Sun.COM /* create kstat lun info */ 20909435STim.Szeto@Sun.COM ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ, 20919435STim.Szeto@Sun.COM KM_NOSLEEP); 20929435STim.Szeto@Sun.COM if (ks_lu == NULL) { 20939435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 20949435STim.Szeto@Sun.COM return; 20959435STim.Szeto@Sun.COM } 20969435STim.Szeto@Sun.COM 20979435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 20989435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu); 20999435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0, 21009435STim.Szeto@Sun.COM ks_nm, "misc", KSTAT_TYPE_NAMED, 21019435STim.Szeto@Sun.COM sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t), 21029435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 21039435STim.Szeto@Sun.COM kmem_free(ks_lu, STMF_KSTAT_LU_SZ); 21049435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu failed"); 21059435STim.Szeto@Sun.COM return; 21069435STim.Szeto@Sun.COM } 21079435STim.Szeto@Sun.COM 21089435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ; 21099435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data = ks_lu; 21109435STim.Szeto@Sun.COM 21119435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_guid, "lun-guid", 21129435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21139435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_alias, "lun-alias", 21149435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21159435STim.Szeto@Sun.COM 21169435STim.Szeto@Sun.COM /* convert guid to hex string */ 21179435STim.Szeto@Sun.COM int i; 21189435STim.Szeto@Sun.COM uint8_t *p = ilu->ilu_lu->lu_id->ident; 21199435STim.Szeto@Sun.COM bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid)); 21209435STim.Szeto@Sun.COM for (i = 0; i < STMF_GUID_INPUT / 2; i++) { 21219435STim.Szeto@Sun.COM (void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]); 21229435STim.Szeto@Sun.COM } 21239435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_guid, 21249435STim.Szeto@Sun.COM (const char *)ilu->ilu_ascii_hex_guid); 21259435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_alias, 21269435STim.Szeto@Sun.COM (const char *)ilu->ilu_lu->lu_alias); 21279435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_info); 21289435STim.Szeto@Sun.COM 21299435STim.Szeto@Sun.COM /* create kstat lun io */ 21309435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21319435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu); 21329435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 21339435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 21349435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu_io failed"); 21359435STim.Szeto@Sun.COM return; 21369435STim.Szeto@Sun.COM } 21379435STim.Szeto@Sun.COM mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0); 21389435STim.Szeto@Sun.COM ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock; 21399435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_io); 21409435STim.Szeto@Sun.COM } 21419435STim.Szeto@Sun.COM 21429435STim.Szeto@Sun.COM static void 21439435STim.Szeto@Sun.COM stmf_create_kstat_lport(stmf_i_local_port_t *ilport) 21449435STim.Szeto@Sun.COM { 21459435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 21469435STim.Szeto@Sun.COM stmf_kstat_tgt_info_t *ks_tgt; 21479435STim.Szeto@Sun.COM int id, len; 21489435STim.Szeto@Sun.COM 21499435STim.Szeto@Sun.COM /* create kstat lport info */ 21509435STim.Szeto@Sun.COM ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ, 21519435STim.Szeto@Sun.COM KM_NOSLEEP); 21529435STim.Szeto@Sun.COM if (ks_tgt == NULL) { 21539435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 21549435STim.Szeto@Sun.COM return; 21559435STim.Szeto@Sun.COM } 21569435STim.Szeto@Sun.COM 21579435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21589435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport); 21599435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME, 21609435STim.Szeto@Sun.COM 0, ks_nm, "misc", KSTAT_TYPE_NAMED, 21619435STim.Szeto@Sun.COM sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t), 21629435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 21639435STim.Szeto@Sun.COM kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ); 21649435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target failed"); 21659435STim.Szeto@Sun.COM return; 21669435STim.Szeto@Sun.COM } 21679435STim.Szeto@Sun.COM 21689435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ; 21699435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data = ks_tgt; 21709435STim.Szeto@Sun.COM 21719435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_name, "target-name", 21729435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21739435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias", 21749435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21759435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_protocol, "protocol", 21769435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21779435STim.Szeto@Sun.COM 21789435STim.Szeto@Sun.COM /* ident might not be null terminated */ 21799435STim.Szeto@Sun.COM len = ilport->ilport_lport->lport_id->ident_length; 21809435STim.Szeto@Sun.COM bcopy(ilport->ilport_lport->lport_id->ident, 21819435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name, len); 21829435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name[len + 1] = NULL; 21839435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_name, 21849435STim.Szeto@Sun.COM (const char *)ilport->ilport_kstat_tgt_name); 21859435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_alias, 21869435STim.Szeto@Sun.COM (const char *)ilport->ilport_lport->lport_alias); 21879435STim.Szeto@Sun.COM /* protocol */ 21889435STim.Szeto@Sun.COM if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) { 21899435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: protocol_id out of bound"); 21909435STim.Szeto@Sun.COM id = PROTOCOL_ANY; 21919435STim.Szeto@Sun.COM } 21929435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]); 21939435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_info); 21949435STim.Szeto@Sun.COM 21959435STim.Szeto@Sun.COM /* create kstat lport io */ 21969435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21979435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport); 21989435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 21999435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 22009435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target_io failed"); 22019435STim.Szeto@Sun.COM return; 22029435STim.Szeto@Sun.COM } 22039435STim.Szeto@Sun.COM mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0); 22049435STim.Szeto@Sun.COM ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock; 22059435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_io); 22069435STim.Szeto@Sun.COM } 22079435STim.Szeto@Sun.COM 22087836SJohn.Forte@Sun.COM stmf_status_t 22097836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu) 22107836SJohn.Forte@Sun.COM { 22117836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 22127836SJohn.Forte@Sun.COM uint8_t *p1, *p2; 22137836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 22147836SJohn.Forte@Sun.COM stmf_id_data_t *luid; 22157836SJohn.Forte@Sun.COM 22167836SJohn.Forte@Sun.COM if ((lu->lu_id->ident_type != ID_TYPE_NAA) || 22177836SJohn.Forte@Sun.COM (lu->lu_id->ident_length != 16) || 22187836SJohn.Forte@Sun.COM ((lu->lu_id->ident[0] & 0xf0) != 0x60)) { 22197836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 22207836SJohn.Forte@Sun.COM } 22217836SJohn.Forte@Sun.COM p1 = &lu->lu_id->ident[0]; 22227836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22237836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 22247836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22257836SJohn.Forte@Sun.COM return (STMF_BUSY); 22267836SJohn.Forte@Sun.COM } 22277836SJohn.Forte@Sun.COM 22287836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 22297836SJohn.Forte@Sun.COM p2 = &ilu->ilu_lu->lu_id->ident[0]; 22307836SJohn.Forte@Sun.COM if (bcmp(p1, p2, 16) == 0) { 22317836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22327836SJohn.Forte@Sun.COM return (STMF_ALREADY); 22337836SJohn.Forte@Sun.COM } 22347836SJohn.Forte@Sun.COM } 22357836SJohn.Forte@Sun.COM 22367836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 22377836SJohn.Forte@Sun.COM luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 22387836SJohn.Forte@Sun.COM lu->lu_id->ident_length, lu->lu_id->ident); 22397836SJohn.Forte@Sun.COM if (luid) { 22407836SJohn.Forte@Sun.COM luid->id_pt_to_object = (void *)ilu; 22417836SJohn.Forte@Sun.COM ilu->ilu_luid = luid; 22427836SJohn.Forte@Sun.COM } 22437836SJohn.Forte@Sun.COM ilu->ilu_alias = NULL; 22447836SJohn.Forte@Sun.COM 22457836SJohn.Forte@Sun.COM ilu->ilu_next = stmf_state.stmf_ilulist; 22467836SJohn.Forte@Sun.COM ilu->ilu_prev = NULL; 22477836SJohn.Forte@Sun.COM if (ilu->ilu_next) 22487836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu; 22497836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu; 22507836SJohn.Forte@Sun.COM stmf_state.stmf_nlus++; 22517836SJohn.Forte@Sun.COM if (lu->lu_lp) { 22527836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 22537836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus++; 22547836SJohn.Forte@Sun.COM } 22557836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 22567836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl); 22579435STim.Szeto@Sun.COM stmf_create_kstat_lu(ilu); 22587836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22597836SJohn.Forte@Sun.COM 22607836SJohn.Forte@Sun.COM /* XXX we should probably check if this lu can be brought online */ 22617836SJohn.Forte@Sun.COM ilu->ilu_prev_state = STMF_STATE_ONLINE; 22627836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 22637836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 22647836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 22657836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci); 22667836SJohn.Forte@Sun.COM } 22677836SJohn.Forte@Sun.COM 22687836SJohn.Forte@Sun.COM /* XXX: Generate event */ 22697836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22707836SJohn.Forte@Sun.COM } 22717836SJohn.Forte@Sun.COM 22727836SJohn.Forte@Sun.COM stmf_status_t 22737836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu) 22747836SJohn.Forte@Sun.COM { 22757836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 22767836SJohn.Forte@Sun.COM 22777836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22787836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 22797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22807836SJohn.Forte@Sun.COM return (STMF_BUSY); 22817836SJohn.Forte@Sun.COM } 22827836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu(lu); 22837836SJohn.Forte@Sun.COM if (ilu == NULL) { 22847836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22857836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 22867836SJohn.Forte@Sun.COM } 22877836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 22887836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 22897836SJohn.Forte@Sun.COM while (ilu->ilu_flags & ILU_STALL_DEREGISTER) { 22907836SJohn.Forte@Sun.COM cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock); 22917836SJohn.Forte@Sun.COM } 22927836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 22937836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 22947836SJohn.Forte@Sun.COM 22957836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 22967836SJohn.Forte@Sun.COM do { 22977836SJohn.Forte@Sun.COM itask = nitask; 22987836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 22997836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 23007836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 23017836SJohn.Forte@Sun.COM } while (nitask != NULL); 23027836SJohn.Forte@Sun.COM 23037836SJohn.Forte@Sun.COM ilu->ilu_tasks = ilu->ilu_free_tasks = NULL; 23047836SJohn.Forte@Sun.COM ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0; 23057836SJohn.Forte@Sun.COM } 23067836SJohn.Forte@Sun.COM 23077836SJohn.Forte@Sun.COM if (ilu->ilu_next) 23087836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu->ilu_prev; 23097836SJohn.Forte@Sun.COM if (ilu->ilu_prev) 23107836SJohn.Forte@Sun.COM ilu->ilu_prev->ilu_next = ilu->ilu_next; 23117836SJohn.Forte@Sun.COM else 23127836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu->ilu_next; 23137836SJohn.Forte@Sun.COM stmf_state.stmf_nlus--; 23147836SJohn.Forte@Sun.COM 23157836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_draining) { 23167836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 23177836SJohn.Forte@Sun.COM } 23187836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_timing) { 23197836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 23207836SJohn.Forte@Sun.COM } 23217836SJohn.Forte@Sun.COM if (lu->lu_lp) { 23227836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 23237836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus--; 23247836SJohn.Forte@Sun.COM } 23257836SJohn.Forte@Sun.COM if (ilu->ilu_luid) { 23267836SJohn.Forte@Sun.COM ((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object = 23277836SJohn.Forte@Sun.COM NULL; 23287836SJohn.Forte@Sun.COM ilu->ilu_luid = NULL; 23297836SJohn.Forte@Sun.COM } 23307836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl); 23317836SJohn.Forte@Sun.COM } else { 23327836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23337836SJohn.Forte@Sun.COM return (STMF_BUSY); 23347836SJohn.Forte@Sun.COM } 23359435STim.Szeto@Sun.COM if (ilu->ilu_kstat_info) { 23369435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_info); 23379435STim.Szeto@Sun.COM } 23389435STim.Szeto@Sun.COM if (ilu->ilu_kstat_io) { 23399435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_io); 23409435STim.Szeto@Sun.COM mutex_destroy(&ilu->ilu_kstat_lock); 23419435STim.Szeto@Sun.COM } 23427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23437836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 23447836SJohn.Forte@Sun.COM } 23457836SJohn.Forte@Sun.COM 23467836SJohn.Forte@Sun.COM stmf_status_t 23477836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport) 23487836SJohn.Forte@Sun.COM { 23497836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 23507836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 23517836SJohn.Forte@Sun.COM int start_workers = 0; 23527836SJohn.Forte@Sun.COM 23537836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 23547836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 23557836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23567836SJohn.Forte@Sun.COM return (STMF_BUSY); 23577836SJohn.Forte@Sun.COM } 23587836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 23597836SJohn.Forte@Sun.COM rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL); 23607836SJohn.Forte@Sun.COM 23617836SJohn.Forte@Sun.COM ilport->ilport_next = stmf_state.stmf_ilportlist; 23627836SJohn.Forte@Sun.COM ilport->ilport_prev = NULL; 23637836SJohn.Forte@Sun.COM if (ilport->ilport_next) 23647836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport; 23657836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport; 23667836SJohn.Forte@Sun.COM stmf_state.stmf_nlports++; 23677836SJohn.Forte@Sun.COM if (lport->lport_pp) { 23687836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 23697836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps++; 23707836SJohn.Forte@Sun.COM } 23717836SJohn.Forte@Sun.COM ilport->ilport_tg = 23727836SJohn.Forte@Sun.COM stmf_lookup_group_for_target(lport->lport_id->ident, 23738662SJordan.Vaughan@Sun.com lport->lport_id->ident_length); 23747836SJohn.Forte@Sun.COM ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1); 23757836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl); 23769435STim.Szeto@Sun.COM stmf_create_kstat_lport(ilport); 23777836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) { 23787836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLING; 23797836SJohn.Forte@Sun.COM start_workers = 1; 23807836SJohn.Forte@Sun.COM } 23817836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23827836SJohn.Forte@Sun.COM 23837836SJohn.Forte@Sun.COM if (start_workers) 23847836SJohn.Forte@Sun.COM stmf_worker_init(); 23857836SJohn.Forte@Sun.COM 23867836SJohn.Forte@Sun.COM /* XXX we should probably check if this lport can be brought online */ 23877836SJohn.Forte@Sun.COM ilport->ilport_prev_state = STMF_STATE_ONLINE; 23887836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 23897836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 23907836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 23917836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci); 23927836SJohn.Forte@Sun.COM } 23937836SJohn.Forte@Sun.COM 23947836SJohn.Forte@Sun.COM /* XXX: Generate event */ 23957836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 23967836SJohn.Forte@Sun.COM } 23977836SJohn.Forte@Sun.COM 23987836SJohn.Forte@Sun.COM stmf_status_t 23997836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport) 24007836SJohn.Forte@Sun.COM { 24017836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 24027836SJohn.Forte@Sun.COM 24037836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 24047836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 24057836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24067836SJohn.Forte@Sun.COM return (STMF_BUSY); 24077836SJohn.Forte@Sun.COM } 24087836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 24097836SJohn.Forte@Sun.COM if (ilport->ilport_nsessions == 0) { 24107836SJohn.Forte@Sun.COM if (ilport->ilport_next) 24117836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport->ilport_prev; 24127836SJohn.Forte@Sun.COM if (ilport->ilport_prev) 24137836SJohn.Forte@Sun.COM ilport->ilport_prev->ilport_next = ilport->ilport_next; 24147836SJohn.Forte@Sun.COM else 24157836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport->ilport_next; 24167836SJohn.Forte@Sun.COM rw_destroy(&ilport->ilport_lock); 24177836SJohn.Forte@Sun.COM stmf_state.stmf_nlports--; 24187836SJohn.Forte@Sun.COM if (lport->lport_pp) { 24197836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 24207836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps--; 24217836SJohn.Forte@Sun.COM } 24227836SJohn.Forte@Sun.COM ilport->ilport_tg = NULL; 24237836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl); 24247836SJohn.Forte@Sun.COM } else { 24257836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24267836SJohn.Forte@Sun.COM return (STMF_BUSY); 24277836SJohn.Forte@Sun.COM } 24289435STim.Szeto@Sun.COM if (ilport->ilport_kstat_info) { 24299435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_info); 24309435STim.Szeto@Sun.COM } 24319435STim.Szeto@Sun.COM if (ilport->ilport_kstat_io) { 24329435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_io); 24339435STim.Szeto@Sun.COM mutex_destroy(&ilport->ilport_kstat_lock); 24349435STim.Szeto@Sun.COM } 24357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24367836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 24377836SJohn.Forte@Sun.COM } 24387836SJohn.Forte@Sun.COM 24397836SJohn.Forte@Sun.COM /* 24407836SJohn.Forte@Sun.COM * Port provider has to make sure that register/deregister session and 24417836SJohn.Forte@Sun.COM * port are serialized calls. 24427836SJohn.Forte@Sun.COM */ 24437836SJohn.Forte@Sun.COM stmf_status_t 24447836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 24457836SJohn.Forte@Sun.COM { 24467836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 24477836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 24487836SJohn.Forte@Sun.COM lport->lport_stmf_private; 24497836SJohn.Forte@Sun.COM uint8_t lun[8]; 24507836SJohn.Forte@Sun.COM 24517836SJohn.Forte@Sun.COM /* 24527836SJohn.Forte@Sun.COM * Port state has to be online to register a scsi session. It is 24537836SJohn.Forte@Sun.COM * possible that we started an offline operation and a new SCSI 24547836SJohn.Forte@Sun.COM * session started at the same time (in that case also we are going 24557836SJohn.Forte@Sun.COM * to fail the registeration). But any other state is simply 24567836SJohn.Forte@Sun.COM * a bad port provider implementation. 24577836SJohn.Forte@Sun.COM */ 24587836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 24597836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 24607836SJohn.Forte@Sun.COM stmf_trace(lport->lport_alias, "Port is trying to " 24617836SJohn.Forte@Sun.COM "register a session while the state is neither " 24627836SJohn.Forte@Sun.COM "online nor offlining"); 24637836SJohn.Forte@Sun.COM } 24647836SJohn.Forte@Sun.COM return (STMF_FAILURE); 24657836SJohn.Forte@Sun.COM } 24667836SJohn.Forte@Sun.COM bzero(lun, 8); 24677836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 24687836SJohn.Forte@Sun.COM iss->iss_flags |= ISS_BEING_CREATED; 24697836SJohn.Forte@Sun.COM 24707836SJohn.Forte@Sun.COM /* sessions use the ilport_lock. No separate lock is required */ 24717836SJohn.Forte@Sun.COM iss->iss_lockp = &ilport->ilport_lock; 24727836SJohn.Forte@Sun.COM (void) stmf_session_create_lun_map(ilport, iss); 24737836SJohn.Forte@Sun.COM 24747836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 24757836SJohn.Forte@Sun.COM ilport->ilport_nsessions++; 24767836SJohn.Forte@Sun.COM iss->iss_next = ilport->ilport_ss_list; 24777836SJohn.Forte@Sun.COM ilport->ilport_ss_list = iss; 24787836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 24797836SJohn.Forte@Sun.COM 24807836SJohn.Forte@Sun.COM iss->iss_creation_time = ddi_get_time(); 24817836SJohn.Forte@Sun.COM ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1); 24827836SJohn.Forte@Sun.COM iss->iss_flags &= ~ISS_BEING_CREATED; 24838859STim.Szeto@Sun.COM DTRACE_PROBE2(session__online, stmf_local_port_t *, lport, 24848859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 24857836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 24867836SJohn.Forte@Sun.COM } 24877836SJohn.Forte@Sun.COM 24887836SJohn.Forte@Sun.COM void 24897836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 24907836SJohn.Forte@Sun.COM { 24917836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 24928662SJordan.Vaughan@Sun.com lport->lport_stmf_private; 24937836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss, **ppss; 24947836SJohn.Forte@Sun.COM int found = 0; 24957836SJohn.Forte@Sun.COM 24968859STim.Szeto@Sun.COM DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport, 24978859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 24988859STim.Szeto@Sun.COM 24997836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 25007836SJohn.Forte@Sun.COM if (ss->ss_rport_alias) { 25017836SJohn.Forte@Sun.COM ss->ss_rport_alias = NULL; 25027836SJohn.Forte@Sun.COM } 25037836SJohn.Forte@Sun.COM 25047836SJohn.Forte@Sun.COM try_dereg_ss_again: 25057836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 25067836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 25078662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 25087836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_EVENT_ACTIVE) { 25097836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25107836SJohn.Forte@Sun.COM delay(1); 25117836SJohn.Forte@Sun.COM goto try_dereg_ss_again; 25127836SJohn.Forte@Sun.COM } 25137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25147836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 25157836SJohn.Forte@Sun.COM for (ppss = &ilport->ilport_ss_list; *ppss != NULL; 25167836SJohn.Forte@Sun.COM ppss = &((*ppss)->iss_next)) { 25177836SJohn.Forte@Sun.COM if (iss == (*ppss)) { 25187836SJohn.Forte@Sun.COM *ppss = (*ppss)->iss_next; 25197836SJohn.Forte@Sun.COM found = 1; 25207836SJohn.Forte@Sun.COM break; 25217836SJohn.Forte@Sun.COM } 25227836SJohn.Forte@Sun.COM } 25237836SJohn.Forte@Sun.COM if (!found) { 25247836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "Deregister session called for non existent" 25257836SJohn.Forte@Sun.COM " session"); 25267836SJohn.Forte@Sun.COM } 25277836SJohn.Forte@Sun.COM ilport->ilport_nsessions--; 25287836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25297836SJohn.Forte@Sun.COM 25307836SJohn.Forte@Sun.COM (void) stmf_session_destroy_lun_map(ilport, iss); 25317836SJohn.Forte@Sun.COM } 25327836SJohn.Forte@Sun.COM 25337836SJohn.Forte@Sun.COM stmf_i_scsi_session_t * 25347836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked) 25357836SJohn.Forte@Sun.COM { 25367836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 25377836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 25387836SJohn.Forte@Sun.COM 25397836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 25407836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 25418662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 25427836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 25437836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 25448662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 25457836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_session_id == session_id) { 25467836SJohn.Forte@Sun.COM if (!stay_locked) 25477836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25497836SJohn.Forte@Sun.COM return (iss); 25507836SJohn.Forte@Sun.COM } 25517836SJohn.Forte@Sun.COM } 25527836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25537836SJohn.Forte@Sun.COM } 25547836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25557836SJohn.Forte@Sun.COM return (NULL); 25567836SJohn.Forte@Sun.COM } 25577836SJohn.Forte@Sun.COM 25587836SJohn.Forte@Sun.COM void 25597836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl) 25607836SJohn.Forte@Sun.COM { 25617836SJohn.Forte@Sun.COM stmf_itl_data_t **itlpp; 25627836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 25637836SJohn.Forte@Sun.COM 25647836SJohn.Forte@Sun.COM ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED); 25657836SJohn.Forte@Sun.COM 25667836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 25677836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25687836SJohn.Forte@Sun.COM for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL; 25698662SJordan.Vaughan@Sun.com itlpp = &(*itlpp)->itl_next) { 25707836SJohn.Forte@Sun.COM if ((*itlpp) == itl) 25717836SJohn.Forte@Sun.COM break; 25727836SJohn.Forte@Sun.COM } 25737836SJohn.Forte@Sun.COM ASSERT((*itlpp) != NULL); 25747836SJohn.Forte@Sun.COM *itlpp = itl->itl_next; 25757836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25767836SJohn.Forte@Sun.COM lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle, 25778662SJordan.Vaughan@Sun.com (uint32_t)itl->itl_hdlrm_reason); 25787836SJohn.Forte@Sun.COM kmem_free(itl, sizeof (*itl)); 25797836SJohn.Forte@Sun.COM } 25807836SJohn.Forte@Sun.COM 25817836SJohn.Forte@Sun.COM stmf_status_t 25827836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun, 25837836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 25847836SJohn.Forte@Sun.COM { 25857836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 25867836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 25877836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 25887836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 25897836SJohn.Forte@Sun.COM uint16_t n; 25907836SJohn.Forte@Sun.COM 25917836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 25927836SJohn.Forte@Sun.COM if (ss == NULL) { 25937836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 25947836SJohn.Forte@Sun.COM if (iss == NULL) 25957836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 25967836SJohn.Forte@Sun.COM } else { 25977836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 25987836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 25997836SJohn.Forte@Sun.COM } 26007836SJohn.Forte@Sun.COM 26017836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 26027836SJohn.Forte@Sun.COM lun_map_ent = (stmf_lun_map_ent_t *) 26038662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 26047836SJohn.Forte@Sun.COM if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) { 26057836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26067836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 26077836SJohn.Forte@Sun.COM } 26087836SJohn.Forte@Sun.COM if (lun_map_ent->ent_itl_datap != NULL) { 26097836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26107836SJohn.Forte@Sun.COM return (STMF_ALREADY); 26117836SJohn.Forte@Sun.COM } 26127836SJohn.Forte@Sun.COM 26137836SJohn.Forte@Sun.COM itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP); 26147836SJohn.Forte@Sun.COM if (itl == NULL) { 26157836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26167836SJohn.Forte@Sun.COM return (STMF_ALLOC_FAILURE); 26177836SJohn.Forte@Sun.COM } 26187836SJohn.Forte@Sun.COM 26197836SJohn.Forte@Sun.COM itl->itl_counter = 1; 26207836SJohn.Forte@Sun.COM itl->itl_lun = n; 26217836SJohn.Forte@Sun.COM itl->itl_handle = itl_handle; 26227836SJohn.Forte@Sun.COM itl->itl_session = iss; 26237836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 26247836SJohn.Forte@Sun.COM itl->itl_next = ilu->ilu_itl_list; 26257836SJohn.Forte@Sun.COM ilu->ilu_itl_list = itl; 26267836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 26277836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap = itl; 26287836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26297836SJohn.Forte@Sun.COM 26307836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 26317836SJohn.Forte@Sun.COM } 26327836SJohn.Forte@Sun.COM 26337836SJohn.Forte@Sun.COM void 26347836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason) 26357836SJohn.Forte@Sun.COM { 26367836SJohn.Forte@Sun.COM uint8_t old, new; 26377836SJohn.Forte@Sun.COM 26387836SJohn.Forte@Sun.COM do { 26397836SJohn.Forte@Sun.COM old = new = itl->itl_flags; 26407836SJohn.Forte@Sun.COM if (old & STMF_ITL_BEING_TERMINATED) 26417836SJohn.Forte@Sun.COM return; 26427836SJohn.Forte@Sun.COM new |= STMF_ITL_BEING_TERMINATED; 26437836SJohn.Forte@Sun.COM } while (atomic_cas_8(&itl->itl_flags, old, new) != old); 26447836SJohn.Forte@Sun.COM itl->itl_hdlrm_reason = hdlrm_reason; 26457836SJohn.Forte@Sun.COM 26467836SJohn.Forte@Sun.COM ASSERT(itl->itl_counter); 26477836SJohn.Forte@Sun.COM 26487836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itl->itl_counter, -1)) 26497836SJohn.Forte@Sun.COM return; 26507836SJohn.Forte@Sun.COM 26517836SJohn.Forte@Sun.COM drv_usecwait(10); 26527836SJohn.Forte@Sun.COM if (itl->itl_counter) 26537836SJohn.Forte@Sun.COM return; 26547836SJohn.Forte@Sun.COM 26557836SJohn.Forte@Sun.COM stmf_release_itl_handle(lu, itl); 26567836SJohn.Forte@Sun.COM } 26577836SJohn.Forte@Sun.COM 26587836SJohn.Forte@Sun.COM stmf_status_t 26597836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu) 26607836SJohn.Forte@Sun.COM { 26617836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 26627836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 26637836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 26647836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 26657836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 26667836SJohn.Forte@Sun.COM uint32_t nmaps, nu; 26677836SJohn.Forte@Sun.COM stmf_itl_data_t **itl_list; 26687836SJohn.Forte@Sun.COM int i; 26697836SJohn.Forte@Sun.COM 26707836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 26717836SJohn.Forte@Sun.COM 26727836SJohn.Forte@Sun.COM dereg_itl_start:; 26737836SJohn.Forte@Sun.COM nmaps = ilu->ilu_ref_cnt; 26747836SJohn.Forte@Sun.COM if (nmaps == 0) 26757836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 26767836SJohn.Forte@Sun.COM itl_list = (stmf_itl_data_t **)kmem_zalloc( 26778662SJordan.Vaughan@Sun.com nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP); 26787836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 26797836SJohn.Forte@Sun.COM if (nmaps != ilu->ilu_ref_cnt) { 26807836SJohn.Forte@Sun.COM /* Something changed, start all over */ 26817836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 26827836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 26837836SJohn.Forte@Sun.COM goto dereg_itl_start; 26847836SJohn.Forte@Sun.COM } 26857836SJohn.Forte@Sun.COM nu = 0; 26867836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 26878662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 26887836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 26897836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 26908662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 26917836SJohn.Forte@Sun.COM lm = iss->iss_sm; 26927836SJohn.Forte@Sun.COM if (!lm) 26937836SJohn.Forte@Sun.COM continue; 26947836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 26957836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 26967836SJohn.Forte@Sun.COM continue; 26977836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 26987836SJohn.Forte@Sun.COM if ((ent->ent_lu == lu) && 26998662SJordan.Vaughan@Sun.com (ent->ent_itl_datap)) { 27007836SJohn.Forte@Sun.COM itl_list[nu++] = ent->ent_itl_datap; 27017836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 27027836SJohn.Forte@Sun.COM if (nu == nmaps) { 27037836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 27047836SJohn.Forte@Sun.COM goto dai_scan_done; 27057836SJohn.Forte@Sun.COM } 27067836SJohn.Forte@Sun.COM } 27077836SJohn.Forte@Sun.COM } /* lun table for a session */ 27087836SJohn.Forte@Sun.COM } /* sessions */ 27097836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 27107836SJohn.Forte@Sun.COM } /* ports */ 27117836SJohn.Forte@Sun.COM 27127836SJohn.Forte@Sun.COM dai_scan_done: 27137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 27147836SJohn.Forte@Sun.COM 27157836SJohn.Forte@Sun.COM for (i = 0; i < nu; i++) { 27167836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl_list[i], 27178662SJordan.Vaughan@Sun.com STMF_ITL_REASON_DEREG_REQUEST); 27187836SJohn.Forte@Sun.COM } 27197836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 27207836SJohn.Forte@Sun.COM 27217836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 27227836SJohn.Forte@Sun.COM } 27237836SJohn.Forte@Sun.COM 27247836SJohn.Forte@Sun.COM stmf_status_t 27257836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun, 27267836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 27277836SJohn.Forte@Sun.COM { 27287836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 27297836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 27307836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 27317836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 27327836SJohn.Forte@Sun.COM int i; 27337836SJohn.Forte@Sun.COM uint16_t n; 27347836SJohn.Forte@Sun.COM 27357836SJohn.Forte@Sun.COM if (ss == NULL) { 27367836SJohn.Forte@Sun.COM if (session_id == STMF_SESSION_ID_NONE) 27377836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 27387836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 27397836SJohn.Forte@Sun.COM if (iss == NULL) 27407836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27417836SJohn.Forte@Sun.COM } else { 27427836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 27437836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 27447836SJohn.Forte@Sun.COM } 27457836SJohn.Forte@Sun.COM lm = iss->iss_sm; 27467836SJohn.Forte@Sun.COM if (lm == NULL) { 27477836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27487836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27497836SJohn.Forte@Sun.COM } 27507836SJohn.Forte@Sun.COM 27517836SJohn.Forte@Sun.COM if (lun) { 27527836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 27537836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 27548662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 27557836SJohn.Forte@Sun.COM } else { 27567836SJohn.Forte@Sun.COM if (itl_handle == NULL) { 27577836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27587836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 27597836SJohn.Forte@Sun.COM } 27607836SJohn.Forte@Sun.COM ent = NULL; 27617836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 27627836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 27637836SJohn.Forte@Sun.COM continue; 27647836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 27657836SJohn.Forte@Sun.COM if (ent->ent_itl_datap && 27667836SJohn.Forte@Sun.COM (ent->ent_itl_datap->itl_handle == itl_handle)) { 27677836SJohn.Forte@Sun.COM break; 27687836SJohn.Forte@Sun.COM } 27697836SJohn.Forte@Sun.COM } 27707836SJohn.Forte@Sun.COM } 27717836SJohn.Forte@Sun.COM if ((ent == NULL) || (ent->ent_lu != lu) || 27728662SJordan.Vaughan@Sun.com (ent->ent_itl_datap == NULL)) { 27737836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27747836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27757836SJohn.Forte@Sun.COM } 27767836SJohn.Forte@Sun.COM itl = ent->ent_itl_datap; 27777836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 27787836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27797836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST); 27807836SJohn.Forte@Sun.COM 27817836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 27827836SJohn.Forte@Sun.COM } 27837836SJohn.Forte@Sun.COM 27847836SJohn.Forte@Sun.COM stmf_status_t 27857836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss, 27867836SJohn.Forte@Sun.COM uint64_t session_id, void **itl_handle_retp) 27877836SJohn.Forte@Sun.COM { 27887836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 27897836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 27907836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 27917836SJohn.Forte@Sun.COM stmf_status_t ret; 27927836SJohn.Forte@Sun.COM int i; 27937836SJohn.Forte@Sun.COM uint16_t n; 27947836SJohn.Forte@Sun.COM 27957836SJohn.Forte@Sun.COM if (ss == NULL) { 27967836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 27977836SJohn.Forte@Sun.COM if (iss == NULL) 27987836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27997836SJohn.Forte@Sun.COM } else { 28007836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 28017836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 28027836SJohn.Forte@Sun.COM } 28037836SJohn.Forte@Sun.COM 28047836SJohn.Forte@Sun.COM ent = NULL; 28057836SJohn.Forte@Sun.COM if (lun == NULL) { 28067836SJohn.Forte@Sun.COM lm = iss->iss_sm; 28077836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 28087836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 28097836SJohn.Forte@Sun.COM continue; 28107836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 28117836SJohn.Forte@Sun.COM if (ent->ent_lu == lu) 28127836SJohn.Forte@Sun.COM break; 28137836SJohn.Forte@Sun.COM } 28147836SJohn.Forte@Sun.COM } else { 28157836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 28167836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 28178662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 28187836SJohn.Forte@Sun.COM if (lu && (ent->ent_lu != lu)) 28197836SJohn.Forte@Sun.COM ent = NULL; 28207836SJohn.Forte@Sun.COM } 28217836SJohn.Forte@Sun.COM if (ent && ent->ent_itl_datap) { 28227836SJohn.Forte@Sun.COM *itl_handle_retp = ent->ent_itl_datap->itl_handle; 28237836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 28247836SJohn.Forte@Sun.COM } else { 28257836SJohn.Forte@Sun.COM ret = STMF_NOT_FOUND; 28267836SJohn.Forte@Sun.COM } 28277836SJohn.Forte@Sun.COM 28287836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 28297836SJohn.Forte@Sun.COM return (ret); 28307836SJohn.Forte@Sun.COM } 28317836SJohn.Forte@Sun.COM 28327836SJohn.Forte@Sun.COM stmf_data_buf_t * 28337836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 28347836SJohn.Forte@Sun.COM uint32_t flags) 28357836SJohn.Forte@Sun.COM { 28367836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 28377836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 28387836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 28397836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 28407836SJohn.Forte@Sun.COM uint8_t ndx; 28417836SJohn.Forte@Sun.COM 28427836SJohn.Forte@Sun.COM ndx = stmf_first_zero[itask->itask_allocated_buf_map]; 28437836SJohn.Forte@Sun.COM if (ndx == 0xff) 28447836SJohn.Forte@Sun.COM return (NULL); 28457836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf( 28467836SJohn.Forte@Sun.COM task, size, pminsize, flags); 28477836SJohn.Forte@Sun.COM if (dbuf) { 28487836SJohn.Forte@Sun.COM task->task_cur_nbufs++; 28497836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map |= (1 << ndx); 28507836SJohn.Forte@Sun.COM dbuf->db_handle = ndx; 28517836SJohn.Forte@Sun.COM return (dbuf); 28527836SJohn.Forte@Sun.COM } 28537836SJohn.Forte@Sun.COM 28547836SJohn.Forte@Sun.COM return (NULL); 28557836SJohn.Forte@Sun.COM } 28567836SJohn.Forte@Sun.COM 28577836SJohn.Forte@Sun.COM void 28587836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf) 28597836SJohn.Forte@Sun.COM { 28607836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 28617836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 28627836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 28637836SJohn.Forte@Sun.COM 28647836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle); 28657836SJohn.Forte@Sun.COM task->task_cur_nbufs--; 28667836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf); 28677836SJohn.Forte@Sun.COM } 28687836SJohn.Forte@Sun.COM 28697836SJohn.Forte@Sun.COM stmf_data_buf_t * 28707836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h) 28717836SJohn.Forte@Sun.COM { 28727836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 28737836SJohn.Forte@Sun.COM 28747836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 28757836SJohn.Forte@Sun.COM if (h > 3) 28767836SJohn.Forte@Sun.COM return (NULL); 28777836SJohn.Forte@Sun.COM return (itask->itask_dbufs[h]); 28787836SJohn.Forte@Sun.COM } 28797836SJohn.Forte@Sun.COM 28807836SJohn.Forte@Sun.COM /* ARGSUSED */ 28817836SJohn.Forte@Sun.COM struct scsi_task * 28827836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss, 28837836SJohn.Forte@Sun.COM uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id) 28847836SJohn.Forte@Sun.COM { 28857836SJohn.Forte@Sun.COM stmf_lu_t *lu; 28867836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 28877836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 28887836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 28897836SJohn.Forte@Sun.COM stmf_i_scsi_task_t **ppitask; 28907836SJohn.Forte@Sun.COM scsi_task_t *task; 28917836SJohn.Forte@Sun.COM uint64_t *p; 28927836SJohn.Forte@Sun.COM uint8_t *l; 28937836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 28947836SJohn.Forte@Sun.COM uint16_t cdb_length; 28957836SJohn.Forte@Sun.COM uint16_t luNbr; 28967836SJohn.Forte@Sun.COM uint8_t new_task = 0; 28977836SJohn.Forte@Sun.COM 28987836SJohn.Forte@Sun.COM /* 28997836SJohn.Forte@Sun.COM * We allocate 7 extra bytes for CDB to provide a cdb pointer which 29007836SJohn.Forte@Sun.COM * is guaranteed to be 8 byte aligned. Some LU providers like OSD 29017836SJohn.Forte@Sun.COM * depend upon this alignment. 29027836SJohn.Forte@Sun.COM */ 29037836SJohn.Forte@Sun.COM if (cdb_length_in >= 16) 29047836SJohn.Forte@Sun.COM cdb_length = cdb_length_in + 7; 29057836SJohn.Forte@Sun.COM else 29067836SJohn.Forte@Sun.COM cdb_length = 16 + 7; 29077836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 29087836SJohn.Forte@Sun.COM luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 29097836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 29107836SJohn.Forte@Sun.COM lun_map_ent = 29117836SJohn.Forte@Sun.COM (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr); 29127836SJohn.Forte@Sun.COM if (!lun_map_ent) { 29137836SJohn.Forte@Sun.COM lu = dlun0; 29147836SJohn.Forte@Sun.COM } else { 29157836SJohn.Forte@Sun.COM lu = lun_map_ent->ent_lu; 29167836SJohn.Forte@Sun.COM } 29177836SJohn.Forte@Sun.COM ilu = lu->lu_stmf_private; 29187836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 29197836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29207836SJohn.Forte@Sun.COM return (NULL); 29217836SJohn.Forte@Sun.COM } 29227836SJohn.Forte@Sun.COM do { 29237836SJohn.Forte@Sun.COM if (ilu->ilu_free_tasks == NULL) { 29247836SJohn.Forte@Sun.COM new_task = 1; 29257836SJohn.Forte@Sun.COM break; 29267836SJohn.Forte@Sun.COM } 29277836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 29287836SJohn.Forte@Sun.COM for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) && 29297836SJohn.Forte@Sun.COM ((*ppitask)->itask_cdb_buf_size < cdb_length); 29308662SJordan.Vaughan@Sun.com ppitask = &((*ppitask)->itask_lu_free_next)) 29318662SJordan.Vaughan@Sun.com ; 29327836SJohn.Forte@Sun.COM if (*ppitask) { 29337836SJohn.Forte@Sun.COM itask = *ppitask; 29347836SJohn.Forte@Sun.COM *ppitask = (*ppitask)->itask_lu_free_next; 29357836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 29367836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free) 29377836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 29387836SJohn.Forte@Sun.COM } else { 29397836SJohn.Forte@Sun.COM new_task = 1; 29407836SJohn.Forte@Sun.COM } 29417836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 29427836SJohn.Forte@Sun.COM /* CONSTCOND */ 29437836SJohn.Forte@Sun.COM } while (0); 29447836SJohn.Forte@Sun.COM 29457836SJohn.Forte@Sun.COM if (!new_task) { 29467836SJohn.Forte@Sun.COM task = itask->itask_task; 29477836SJohn.Forte@Sun.COM task->task_timeout = 0; 29487836SJohn.Forte@Sun.COM p = (uint64_t *)&task->task_flags; 29497836SJohn.Forte@Sun.COM *p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0; 29507836SJohn.Forte@Sun.COM itask->itask_ncmds = 0; 29517836SJohn.Forte@Sun.COM } else { 29527836SJohn.Forte@Sun.COM task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK, 29537836SJohn.Forte@Sun.COM cdb_length, AF_FORCE_NOSLEEP); 29547836SJohn.Forte@Sun.COM if (task == NULL) { 29557836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29567836SJohn.Forte@Sun.COM return (NULL); 29577836SJohn.Forte@Sun.COM } 29587836SJohn.Forte@Sun.COM task->task_lu = lu; 29597836SJohn.Forte@Sun.COM l = task->task_lun_no; 29607836SJohn.Forte@Sun.COM l[0] = lun[0]; 29617836SJohn.Forte@Sun.COM l[1] = lun[1]; 29627836SJohn.Forte@Sun.COM l[2] = lun[2]; 29637836SJohn.Forte@Sun.COM l[3] = lun[3]; 29647836SJohn.Forte@Sun.COM l[4] = lun[4]; 29657836SJohn.Forte@Sun.COM l[5] = lun[5]; 29667836SJohn.Forte@Sun.COM l[6] = lun[6]; 29677836SJohn.Forte@Sun.COM l[7] = lun[7]; 29687836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)task->task_port_private; 29697836SJohn.Forte@Sun.COM if ((ulong_t)(task->task_cdb) & 7ul) { 29707836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)(((ulong_t) 29717836SJohn.Forte@Sun.COM (task->task_cdb) + 7ul) & ~(7ul)); 29727836SJohn.Forte@Sun.COM } 29737836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 29747836SJohn.Forte@Sun.COM itask->itask_cdb_buf_size = cdb_length; 29757836SJohn.Forte@Sun.COM } 29767836SJohn.Forte@Sun.COM task->task_session = ss; 29777836SJohn.Forte@Sun.COM task->task_lport = lport; 29787836SJohn.Forte@Sun.COM task->task_cdb_length = cdb_length_in; 29797836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_TRANSITION; 29807836SJohn.Forte@Sun.COM 29817836SJohn.Forte@Sun.COM if (new_task) { 29827836SJohn.Forte@Sun.COM if (lu->lu_task_alloc(task) != STMF_SUCCESS) { 29837836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29847836SJohn.Forte@Sun.COM stmf_free(task); 29857836SJohn.Forte@Sun.COM return (NULL); 29867836SJohn.Forte@Sun.COM } 29877836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 29887836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 29897836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 29907836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29917836SJohn.Forte@Sun.COM stmf_free(task); 29927836SJohn.Forte@Sun.COM return (NULL); 29937836SJohn.Forte@Sun.COM } 29947836SJohn.Forte@Sun.COM itask->itask_lu_next = ilu->ilu_tasks; 29957836SJohn.Forte@Sun.COM if (ilu->ilu_tasks) 29967836SJohn.Forte@Sun.COM ilu->ilu_tasks->itask_lu_prev = itask; 29977836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask; 29987836SJohn.Forte@Sun.COM /* kmem_zalloc automatically makes itask->itask_lu_prev NULL */ 29997836SJohn.Forte@Sun.COM ilu->ilu_ntasks++; 30007836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30017836SJohn.Forte@Sun.COM } 30027836SJohn.Forte@Sun.COM 30037836SJohn.Forte@Sun.COM itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr; 30047836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, 1); 30057836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 30067836SJohn.Forte@Sun.COM 30077836SJohn.Forte@Sun.COM if ((lun_map_ent != NULL) && ((itask->itask_itl_datap = 30087836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap) != NULL)) { 30097836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_itl_datap->itl_counter, 1); 30107836SJohn.Forte@Sun.COM task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle; 30117836SJohn.Forte@Sun.COM } else { 30127836SJohn.Forte@Sun.COM itask->itask_itl_datap = NULL; 30137836SJohn.Forte@Sun.COM task->task_lu_itl_handle = NULL; 30147836SJohn.Forte@Sun.COM } 30157836SJohn.Forte@Sun.COM 30167836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30177836SJohn.Forte@Sun.COM return (task); 30187836SJohn.Forte@Sun.COM } 30197836SJohn.Forte@Sun.COM 30207836SJohn.Forte@Sun.COM void 30217836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task) 30227836SJohn.Forte@Sun.COM { 30237836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 30247836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 30257836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 30267836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 30277836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 30287836SJohn.Forte@Sun.COM 30297836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 30307836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_FREE_LIST; 30317836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30327836SJohn.Forte@Sun.COM itask->itask_lu_free_next = ilu->ilu_free_tasks; 30337836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask; 30347836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free++; 30357836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30367836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, -1); 30377836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30387836SJohn.Forte@Sun.COM } 30397836SJohn.Forte@Sun.COM 30407836SJohn.Forte@Sun.COM void 30417836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu) 30427836SJohn.Forte@Sun.COM { 30437836SJohn.Forte@Sun.COM uint32_t num_to_release, ndx; 30447836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 30457836SJohn.Forte@Sun.COM stmf_lu_t *lu = ilu->ilu_lu; 30467836SJohn.Forte@Sun.COM 30477836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free); 30487836SJohn.Forte@Sun.COM 30497836SJohn.Forte@Sun.COM /* free half of the minimal free of the free tasks */ 30507836SJohn.Forte@Sun.COM num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2; 30517836SJohn.Forte@Sun.COM if (!num_to_release) { 30527836SJohn.Forte@Sun.COM return; 30537836SJohn.Forte@Sun.COM } 30547836SJohn.Forte@Sun.COM for (ndx = 0; ndx < num_to_release; ndx++) { 30557836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30567836SJohn.Forte@Sun.COM itask = ilu->ilu_free_tasks; 30577836SJohn.Forte@Sun.COM if (itask == NULL) { 30587836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30597836SJohn.Forte@Sun.COM break; 30607836SJohn.Forte@Sun.COM } 30617836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask->itask_lu_free_next; 30627836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 30637836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30647836SJohn.Forte@Sun.COM 30657836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 30667836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30677836SJohn.Forte@Sun.COM if (itask->itask_lu_next) 30687836SJohn.Forte@Sun.COM itask->itask_lu_next->itask_lu_prev = 30697836SJohn.Forte@Sun.COM itask->itask_lu_prev; 30707836SJohn.Forte@Sun.COM if (itask->itask_lu_prev) 30717836SJohn.Forte@Sun.COM itask->itask_lu_prev->itask_lu_next = 30727836SJohn.Forte@Sun.COM itask->itask_lu_next; 30737836SJohn.Forte@Sun.COM else 30747836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask->itask_lu_next; 30757836SJohn.Forte@Sun.COM 30767836SJohn.Forte@Sun.COM ilu->ilu_ntasks--; 30777836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30787836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 30797836SJohn.Forte@Sun.COM } 30807836SJohn.Forte@Sun.COM } 30817836SJohn.Forte@Sun.COM 30827836SJohn.Forte@Sun.COM /* 30837836SJohn.Forte@Sun.COM * Called with stmf_lock held 30847836SJohn.Forte@Sun.COM */ 30857836SJohn.Forte@Sun.COM void 30867836SJohn.Forte@Sun.COM stmf_check_freetask() 30877836SJohn.Forte@Sun.COM { 30887836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 30897836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 30907836SJohn.Forte@Sun.COM 30917836SJohn.Forte@Sun.COM /* stmf_svc_ilu_draining may get changed after stmf_lock is released */ 30927836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) { 30937836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 30947836SJohn.Forte@Sun.COM if (!ilu->ilu_ntasks_min_free) { 30957836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 30967836SJohn.Forte@Sun.COM continue; 30977836SJohn.Forte@Sun.COM } 30987836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 30997836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31007836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(ilu); 31017836SJohn.Forte@Sun.COM /* 31027836SJohn.Forte@Sun.COM * we do not care about the accuracy of 31037836SJohn.Forte@Sun.COM * ilu_ntasks_min_free, so we don't lock here 31047836SJohn.Forte@Sun.COM */ 31057836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 31067836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 31077836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 31087836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 31097836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 31107836SJohn.Forte@Sun.COM break; 31117836SJohn.Forte@Sun.COM } 31127836SJohn.Forte@Sun.COM } 31137836SJohn.Forte@Sun.COM 31147836SJohn.Forte@Sun.COM void 31157836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu) 31167836SJohn.Forte@Sun.COM { 31177836SJohn.Forte@Sun.COM clock_t l = ddi_get_lbolt(); 31187836SJohn.Forte@Sun.COM clock_t ps = drv_usectohz(1000000); 31197836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 31207836SJohn.Forte@Sun.COM scsi_task_t *task; 31217836SJohn.Forte@Sun.COM uint32_t to; 31227836SJohn.Forte@Sun.COM 31237836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 31247836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 31257836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 31267836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_IN_FREE_LIST | 31277836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) { 31287836SJohn.Forte@Sun.COM continue; 31297836SJohn.Forte@Sun.COM } 31307836SJohn.Forte@Sun.COM task = itask->itask_task; 31317836SJohn.Forte@Sun.COM if (task->task_timeout == 0) 31327836SJohn.Forte@Sun.COM to = stmf_default_task_timeout; 31337836SJohn.Forte@Sun.COM else 31347836SJohn.Forte@Sun.COM to = task->task_timeout; 31357836SJohn.Forte@Sun.COM if ((itask->itask_start_time + (to * ps)) > l) 31367836SJohn.Forte@Sun.COM continue; 31377836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 31387836SJohn.Forte@Sun.COM STMF_TIMEOUT, NULL); 31397836SJohn.Forte@Sun.COM } 31407836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 31417836SJohn.Forte@Sun.COM } 31427836SJohn.Forte@Sun.COM 31437836SJohn.Forte@Sun.COM /* 31447836SJohn.Forte@Sun.COM * Called with stmf_lock held 31457836SJohn.Forte@Sun.COM */ 31467836SJohn.Forte@Sun.COM void 31477836SJohn.Forte@Sun.COM stmf_check_ilu_timing() 31487836SJohn.Forte@Sun.COM { 31497836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 31507836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 31517836SJohn.Forte@Sun.COM 31527836SJohn.Forte@Sun.COM /* stmf_svc_ilu_timing may get changed after stmf_lock is released */ 31537836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) { 31547836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 31557836SJohn.Forte@Sun.COM if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) { 31567836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr2 == 0) { 31577836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2; 31587836SJohn.Forte@Sun.COM continue; 31597836SJohn.Forte@Sun.COM } 31607836SJohn.Forte@Sun.COM } else { 31617836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr1 == 0) { 31627836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 31637836SJohn.Forte@Sun.COM continue; 31647836SJohn.Forte@Sun.COM } 31657836SJohn.Forte@Sun.COM } 31667836SJohn.Forte@Sun.COM /* 31677836SJohn.Forte@Sun.COM * If we are here then it means that there is some slowdown 31687836SJohn.Forte@Sun.COM * in tasks on this lu. We need to check. 31697836SJohn.Forte@Sun.COM */ 31707836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 31717836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31727836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(ilu); 31737836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 31747836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 31757836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 31767836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 31777836SJohn.Forte@Sun.COM break; 31787836SJohn.Forte@Sun.COM } 31797836SJohn.Forte@Sun.COM } 31807836SJohn.Forte@Sun.COM 31817836SJohn.Forte@Sun.COM /* 31827836SJohn.Forte@Sun.COM * Kills all tasks on a lu except tm_task 31837836SJohn.Forte@Sun.COM */ 31847836SJohn.Forte@Sun.COM void 31857836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s) 31867836SJohn.Forte@Sun.COM { 31877836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 31887836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 31897836SJohn.Forte@Sun.COM 31907836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 31917836SJohn.Forte@Sun.COM 31927836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 31937836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 31947836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_FREE_LIST) 31957836SJohn.Forte@Sun.COM continue; 31967836SJohn.Forte@Sun.COM if (itask->itask_task == tm_task) 31977836SJohn.Forte@Sun.COM continue; 31987836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL); 31997836SJohn.Forte@Sun.COM } 32007836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 32017836SJohn.Forte@Sun.COM } 32027836SJohn.Forte@Sun.COM 32037836SJohn.Forte@Sun.COM void 32047836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport) 32057836SJohn.Forte@Sun.COM { 32067836SJohn.Forte@Sun.COM int i; 32077836SJohn.Forte@Sun.COM uint8_t map; 32087836SJohn.Forte@Sun.COM 32097836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 32107836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 32117836SJohn.Forte@Sun.COM if (map & 1) { 32127836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 32137836SJohn.Forte@Sun.COM 32147836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 32157836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 32167836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 32177836SJohn.Forte@Sun.COM } 32187836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf( 32197836SJohn.Forte@Sun.COM lport->lport_ds, dbuf); 32207836SJohn.Forte@Sun.COM } 32217836SJohn.Forte@Sun.COM map >>= 1; 32227836SJohn.Forte@Sun.COM } 32237836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 32247836SJohn.Forte@Sun.COM } 32257836SJohn.Forte@Sun.COM } 32267836SJohn.Forte@Sun.COM 32277836SJohn.Forte@Sun.COM void 32287836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task) 32297836SJohn.Forte@Sun.COM { 32307836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 32317836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 32328662SJordan.Vaughan@Sun.com task->task_stmf_private; 32337836SJohn.Forte@Sun.COM 32348859STim.Szeto@Sun.COM DTRACE_PROBE1(stmf__task__end, scsi_task_t *, task); 32357836SJohn.Forte@Sun.COM stmf_free_task_bufs(itask, lport); 32367836SJohn.Forte@Sun.COM if (itask->itask_itl_datap) { 32377836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter, 32387836SJohn.Forte@Sun.COM -1) == 0) { 32397836SJohn.Forte@Sun.COM stmf_release_itl_handle(task->task_lu, 32408662SJordan.Vaughan@Sun.com itask->itask_itl_datap); 32417836SJohn.Forte@Sun.COM } 32427836SJohn.Forte@Sun.COM } 32437836SJohn.Forte@Sun.COM lport->lport_task_free(task); 32447836SJohn.Forte@Sun.COM if (itask->itask_worker) { 32457836SJohn.Forte@Sun.COM atomic_add_32(&stmf_cur_ntasks, -1); 32467836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_worker->worker_ref_count, -1); 32477836SJohn.Forte@Sun.COM } 32487836SJohn.Forte@Sun.COM /* 32497836SJohn.Forte@Sun.COM * After calling stmf_task_lu_free, the task pointer can no longer 32507836SJohn.Forte@Sun.COM * be trusted. 32517836SJohn.Forte@Sun.COM */ 32527836SJohn.Forte@Sun.COM stmf_task_lu_free(task); 32537836SJohn.Forte@Sun.COM } 32547836SJohn.Forte@Sun.COM 32557836SJohn.Forte@Sun.COM void 32567836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 32577836SJohn.Forte@Sun.COM { 32587836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 32597836SJohn.Forte@Sun.COM task->task_stmf_private; 32607836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 32617836SJohn.Forte@Sun.COM int nv; 32627836SJohn.Forte@Sun.COM uint32_t old, new; 32637836SJohn.Forte@Sun.COM uint32_t ct; 32647836SJohn.Forte@Sun.COM stmf_worker_t *w, *w1; 32657836SJohn.Forte@Sun.COM uint8_t tm; 32667836SJohn.Forte@Sun.COM 32677836SJohn.Forte@Sun.COM if (task->task_max_nbufs > 4) 32687836SJohn.Forte@Sun.COM task->task_max_nbufs = 4; 32697836SJohn.Forte@Sun.COM task->task_cur_nbufs = 0; 32707836SJohn.Forte@Sun.COM /* Latest value of currently running tasks */ 32717836SJohn.Forte@Sun.COM ct = atomic_add_32_nv(&stmf_cur_ntasks, 1); 32727836SJohn.Forte@Sun.COM 32737836SJohn.Forte@Sun.COM /* Select the next worker using round robin */ 32747836SJohn.Forte@Sun.COM nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1); 32757836SJohn.Forte@Sun.COM if (nv >= stmf_nworkers_accepting_cmds) { 32767836SJohn.Forte@Sun.COM int s = nv; 32777836SJohn.Forte@Sun.COM do { 32787836SJohn.Forte@Sun.COM nv -= stmf_nworkers_accepting_cmds; 32797836SJohn.Forte@Sun.COM } while (nv >= stmf_nworkers_accepting_cmds); 32807836SJohn.Forte@Sun.COM if (nv < 0) 32817836SJohn.Forte@Sun.COM nv = 0; 32827836SJohn.Forte@Sun.COM /* Its ok if this cas fails */ 32837836SJohn.Forte@Sun.COM (void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter, 32847836SJohn.Forte@Sun.COM s, nv); 32857836SJohn.Forte@Sun.COM } 32867836SJohn.Forte@Sun.COM w = &stmf_workers[nv]; 32877836SJohn.Forte@Sun.COM 32887836SJohn.Forte@Sun.COM /* 32897836SJohn.Forte@Sun.COM * A worker can be pinned by interrupt. So select the next one 32907836SJohn.Forte@Sun.COM * if it has lower load. 32917836SJohn.Forte@Sun.COM */ 32927836SJohn.Forte@Sun.COM if ((nv + 1) >= stmf_nworkers_accepting_cmds) { 32937836SJohn.Forte@Sun.COM w1 = stmf_workers; 32947836SJohn.Forte@Sun.COM } else { 32957836SJohn.Forte@Sun.COM w1 = &stmf_workers[nv + 1]; 32967836SJohn.Forte@Sun.COM } 32977836SJohn.Forte@Sun.COM if (w1->worker_queue_depth < w->worker_queue_depth) 32987836SJohn.Forte@Sun.COM w = w1; 32999435STim.Szeto@Sun.COM 33007836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33017836SJohn.Forte@Sun.COM if (((w->worker_flags & STMF_WORKER_STARTED) == 0) || 33027836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 33037836SJohn.Forte@Sun.COM /* 33047836SJohn.Forte@Sun.COM * Maybe we are in the middle of a change. Just go to 33057836SJohn.Forte@Sun.COM * the 1st worker. 33067836SJohn.Forte@Sun.COM */ 33077836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33087836SJohn.Forte@Sun.COM w = stmf_workers; 33097836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33107836SJohn.Forte@Sun.COM } 33117836SJohn.Forte@Sun.COM itask->itask_worker = w; 33127836SJohn.Forte@Sun.COM /* 33137836SJohn.Forte@Sun.COM * Track max system load inside the worker as we already have the 33147836SJohn.Forte@Sun.COM * worker lock (no point implementing another lock). The service 33157836SJohn.Forte@Sun.COM * thread will do the comparisons and figure out the max overall 33167836SJohn.Forte@Sun.COM * system load. 33177836SJohn.Forte@Sun.COM */ 33187836SJohn.Forte@Sun.COM if (w->worker_max_sys_qdepth_pu < ct) 33197836SJohn.Forte@Sun.COM w->worker_max_sys_qdepth_pu = ct; 33207836SJohn.Forte@Sun.COM 33217836SJohn.Forte@Sun.COM do { 33227836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 33237836SJohn.Forte@Sun.COM new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE; 33247836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 33257836SJohn.Forte@Sun.COM tm = task->task_mgmt_function; 33267836SJohn.Forte@Sun.COM if ((tm == TM_TARGET_RESET) || 33277836SJohn.Forte@Sun.COM (tm == TM_TARGET_COLD_RESET) || 33287836SJohn.Forte@Sun.COM (tm == TM_TARGET_WARM_RESET)) { 33297836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 33307836SJohn.Forte@Sun.COM } 33317836SJohn.Forte@Sun.COM } else if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 33327836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 33337836SJohn.Forte@Sun.COM } 33347836SJohn.Forte@Sun.COM new &= ~ITASK_IN_TRANSITION; 33357836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 33367836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 33377836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 33387836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 33397836SJohn.Forte@Sun.COM } else { 33407836SJohn.Forte@Sun.COM w->worker_task_head = itask; 33417836SJohn.Forte@Sun.COM } 33427836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 33437836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 33447836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 33457836SJohn.Forte@Sun.COM } 33467836SJohn.Forte@Sun.COM atomic_add_32(&w->worker_ref_count, 1); 33477836SJohn.Forte@Sun.COM itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK; 33487836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 33497836SJohn.Forte@Sun.COM if (dbuf) { 33507836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 1; 33517836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = dbuf; 33527836SJohn.Forte@Sun.COM dbuf->db_handle = 0; 33537836SJohn.Forte@Sun.COM } else { 33547836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 33557836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = NULL; 33567836SJohn.Forte@Sun.COM } 33579435STim.Szeto@Sun.COM 33589435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_enter); 33599435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_enter); 33609435STim.Szeto@Sun.COM 33617836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 33627836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 33637836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33647836SJohn.Forte@Sun.COM 33657836SJohn.Forte@Sun.COM /* 33667836SJohn.Forte@Sun.COM * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE 33677836SJohn.Forte@Sun.COM * was set between checking of ILU_RESET_ACTIVE and clearing of the 33687836SJohn.Forte@Sun.COM * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here. 33697836SJohn.Forte@Sun.COM */ 33707836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 33717836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL); 33727836SJohn.Forte@Sun.COM } 33737836SJohn.Forte@Sun.COM } 33747836SJohn.Forte@Sun.COM 33757836SJohn.Forte@Sun.COM /* 33767836SJohn.Forte@Sun.COM * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++ 33777836SJohn.Forte@Sun.COM * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already 33787836SJohn.Forte@Sun.COM * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot 33797836SJohn.Forte@Sun.COM * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course 33807836SJohn.Forte@Sun.COM * the LU will make this call only if we call the LU's abort entry point. 33817836SJohn.Forte@Sun.COM * we will only call that entry point if ITASK_KNOWN_TO_LU was set. 33827836SJohn.Forte@Sun.COM * 33837836SJohn.Forte@Sun.COM * Same logic applies for the port. 33847836SJohn.Forte@Sun.COM * 33857836SJohn.Forte@Sun.COM * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU 33867836SJohn.Forte@Sun.COM * and KNOWN_TO_TGT_PORT are reset. 33877836SJohn.Forte@Sun.COM * 33887836SJohn.Forte@Sun.COM * +++++++++++++++++++++++++++++++++++++++++++++++ 33897836SJohn.Forte@Sun.COM */ 33907836SJohn.Forte@Sun.COM 33917836SJohn.Forte@Sun.COM stmf_status_t 33927836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) 33937836SJohn.Forte@Sun.COM { 33948859STim.Szeto@Sun.COM stmf_status_t ret; 33958859STim.Szeto@Sun.COM 33967836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 33977836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 33987836SJohn.Forte@Sun.COM 33997836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 34007836SJohn.Forte@Sun.COM uint32_t new, old; 34017836SJohn.Forte@Sun.COM do { 34027836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 34037836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 34047836SJohn.Forte@Sun.COM return (STMF_ABORTED); 34057836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 34067836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34077836SJohn.Forte@Sun.COM } 34087836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 34097836SJohn.Forte@Sun.COM return (STMF_ABORTED); 34107836SJohn.Forte@Sun.COM #ifdef DEBUG 34117836SJohn.Forte@Sun.COM if (stmf_drop_buf_counter > 0) { 34128662SJordan.Vaughan@Sun.com if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) == 34138662SJordan.Vaughan@Sun.com 1) 34147836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 34157836SJohn.Forte@Sun.COM } 34167836SJohn.Forte@Sun.COM #endif 34179435STim.Szeto@Sun.COM 34189435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(task, dbuf); 34199435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(task, dbuf); 34209435STim.Szeto@Sun.COM 34218859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, task, 34228859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 34238859STim.Szeto@Sun.COM ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags); 34248859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__end, scsi_task_t *, task, 34258859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 34268859STim.Szeto@Sun.COM return (ret); 34277836SJohn.Forte@Sun.COM } 34287836SJohn.Forte@Sun.COM 34297836SJohn.Forte@Sun.COM void 34307836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof) 34317836SJohn.Forte@Sun.COM { 34327836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 34337836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 34347836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 34357836SJohn.Forte@Sun.COM uint32_t new, old; 34367836SJohn.Forte@Sun.COM uint8_t update_queue_flags, free_it, queue_it; 34377836SJohn.Forte@Sun.COM 34387836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 34397836SJohn.Forte@Sun.COM do { 34407836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 34417836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 34427836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 34437836SJohn.Forte@Sun.COM return; 34447836SJohn.Forte@Sun.COM } 34457836SJohn.Forte@Sun.COM free_it = 0; 34467836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 34477836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 34487836SJohn.Forte@Sun.COM task->task_completion_status = dbuf->db_xfer_status; 34497836SJohn.Forte@Sun.COM free_it = 1; 34507836SJohn.Forte@Sun.COM } 34517836SJohn.Forte@Sun.COM /* 34527836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 34537836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 34547836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 34557836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 34567836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 34577836SJohn.Forte@Sun.COM * free this task. 34587836SJohn.Forte@Sun.COM */ 34597836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 34607836SJohn.Forte@Sun.COM free_it = 0; 34617836SJohn.Forte@Sun.COM update_queue_flags = 1; 34627836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 34637836SJohn.Forte@Sun.COM queue_it = 0; 34647836SJohn.Forte@Sun.COM } else { 34657836SJohn.Forte@Sun.COM queue_it = 1; 34667836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 34677836SJohn.Forte@Sun.COM } 34687836SJohn.Forte@Sun.COM } else { 34697836SJohn.Forte@Sun.COM update_queue_flags = 0; 34707836SJohn.Forte@Sun.COM queue_it = 0; 34717836SJohn.Forte@Sun.COM } 34727836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34737836SJohn.Forte@Sun.COM 34747836SJohn.Forte@Sun.COM if (update_queue_flags) { 34757836SJohn.Forte@Sun.COM uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE; 34767836SJohn.Forte@Sun.COM 34777836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 34787836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = cmd; 34797836SJohn.Forte@Sun.COM if (queue_it) { 34807836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 34817836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 34827836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 34837836SJohn.Forte@Sun.COM } else { 34847836SJohn.Forte@Sun.COM w->worker_task_head = itask; 34857836SJohn.Forte@Sun.COM } 34867836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 34877836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > 34887836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu) { 34897836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 34907836SJohn.Forte@Sun.COM } 34917836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 34927836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 34937836SJohn.Forte@Sun.COM } 34947836SJohn.Forte@Sun.COM } 34957836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 34967836SJohn.Forte@Sun.COM 34977836SJohn.Forte@Sun.COM if (free_it) { 34987836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 34997836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 35007836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 35019435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 35029435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 35037836SJohn.Forte@Sun.COM stmf_task_free(task); 35047836SJohn.Forte@Sun.COM } 35057836SJohn.Forte@Sun.COM } 35067836SJohn.Forte@Sun.COM } 35077836SJohn.Forte@Sun.COM 35087836SJohn.Forte@Sun.COM stmf_status_t 35097836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 35107836SJohn.Forte@Sun.COM { 35118859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task); 35128859STim.Szeto@Sun.COM 35137836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 35148662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 35157836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 35167836SJohn.Forte@Sun.COM uint32_t new, old; 35177836SJohn.Forte@Sun.COM do { 35187836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 35197836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 35207836SJohn.Forte@Sun.COM return (STMF_ABORTED); 35217836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 35227836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 35237836SJohn.Forte@Sun.COM } 35247836SJohn.Forte@Sun.COM 35257836SJohn.Forte@Sun.COM if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) { 35267836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 35277836SJohn.Forte@Sun.COM } 35287836SJohn.Forte@Sun.COM 35297836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 35307836SJohn.Forte@Sun.COM return (STMF_ABORTED); 35317836SJohn.Forte@Sun.COM 35327836SJohn.Forte@Sun.COM if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) { 35337836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 35347836SJohn.Forte@Sun.COM task->task_resid = 0; 35357836SJohn.Forte@Sun.COM } else if (task->task_cmd_xfer_length > 35367836SJohn.Forte@Sun.COM task->task_expected_xfer_length) { 35377836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_OVER; 35387836SJohn.Forte@Sun.COM task->task_resid = task->task_cmd_xfer_length - 35398662SJordan.Vaughan@Sun.com task->task_expected_xfer_length; 35407836SJohn.Forte@Sun.COM } else if (task->task_nbytes_transferred < 35418662SJordan.Vaughan@Sun.com task->task_expected_xfer_length) { 35427836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_UNDER; 35437836SJohn.Forte@Sun.COM task->task_resid = task->task_expected_xfer_length - 35448662SJordan.Vaughan@Sun.com task->task_nbytes_transferred; 35457836SJohn.Forte@Sun.COM } else { 35467836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 35477836SJohn.Forte@Sun.COM task->task_resid = 0; 35487836SJohn.Forte@Sun.COM } 35497836SJohn.Forte@Sun.COM return (task->task_lport->lport_send_status(task, ioflags)); 35507836SJohn.Forte@Sun.COM } 35517836SJohn.Forte@Sun.COM 35527836SJohn.Forte@Sun.COM void 35537836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof) 35547836SJohn.Forte@Sun.COM { 35557836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 35567836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 35577836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 35587836SJohn.Forte@Sun.COM uint32_t new, old; 35597836SJohn.Forte@Sun.COM uint8_t free_it, queue_it; 35607836SJohn.Forte@Sun.COM 35617836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 35627836SJohn.Forte@Sun.COM do { 35637836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 35647836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 35657836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 35667836SJohn.Forte@Sun.COM return; 35677836SJohn.Forte@Sun.COM } 35687836SJohn.Forte@Sun.COM free_it = 0; 35697836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 35707836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 35717836SJohn.Forte@Sun.COM free_it = 1; 35727836SJohn.Forte@Sun.COM } 35737836SJohn.Forte@Sun.COM /* 35747836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 35757836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 35767836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 35777836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 35787836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 35797836SJohn.Forte@Sun.COM * free this task. 35807836SJohn.Forte@Sun.COM */ 35817836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 35827836SJohn.Forte@Sun.COM free_it = 0; 35837836SJohn.Forte@Sun.COM queue_it = 1; 35847836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 35857836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "status completion received" 35867836SJohn.Forte@Sun.COM " when task is already in worker queue " 35877836SJohn.Forte@Sun.COM " task = %p", (void *)task); 35887836SJohn.Forte@Sun.COM } 35897836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 35907836SJohn.Forte@Sun.COM } else { 35917836SJohn.Forte@Sun.COM queue_it = 0; 35927836SJohn.Forte@Sun.COM } 35937836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 35947836SJohn.Forte@Sun.COM task->task_completion_status = s; 35957836SJohn.Forte@Sun.COM 35969435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 35979435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 35989435STim.Szeto@Sun.COM 35997836SJohn.Forte@Sun.COM if (queue_it) { 36007836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 36017836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = 36027836SJohn.Forte@Sun.COM ITASK_CMD_STATUS_DONE; 36037836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 36047836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 36057836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 36067836SJohn.Forte@Sun.COM } else { 36077836SJohn.Forte@Sun.COM w->worker_task_head = itask; 36087836SJohn.Forte@Sun.COM } 36097836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 36107836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 36117836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 36127836SJohn.Forte@Sun.COM } 36137836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 36147836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 36157836SJohn.Forte@Sun.COM } 36167836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36177836SJohn.Forte@Sun.COM 36187836SJohn.Forte@Sun.COM if (free_it) { 36197836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 36207836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 36217836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 36227836SJohn.Forte@Sun.COM stmf_task_free(task); 36237836SJohn.Forte@Sun.COM } else { 36247836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "LU is done with the task but LPORT " 36257836SJohn.Forte@Sun.COM " is not done, itask %p", (void *)itask); 36267836SJohn.Forte@Sun.COM } 36277836SJohn.Forte@Sun.COM } 36287836SJohn.Forte@Sun.COM } 36297836SJohn.Forte@Sun.COM 36307836SJohn.Forte@Sun.COM void 36317836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task) 36327836SJohn.Forte@Sun.COM { 36337836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36348662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 36357836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 36367836SJohn.Forte@Sun.COM uint32_t new, old; 36377836SJohn.Forte@Sun.COM 36387836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 36397836SJohn.Forte@Sun.COM do { 36407836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 36417836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 36427836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36437836SJohn.Forte@Sun.COM return; 36447836SJohn.Forte@Sun.COM } 36457836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 36467836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "task_lu_done received" 36477836SJohn.Forte@Sun.COM " when task is in worker queue " 36487836SJohn.Forte@Sun.COM " task = %p", (void *)task); 36497836SJohn.Forte@Sun.COM } 36507836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 36517836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 36527836SJohn.Forte@Sun.COM 36537836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36547836SJohn.Forte@Sun.COM 36557836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 36567836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 36577836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 36587836SJohn.Forte@Sun.COM stmf_task_free(task); 36597836SJohn.Forte@Sun.COM } else { 36607836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but " 36617836SJohn.Forte@Sun.COM " the task is still not done, task = %p", (void *)task); 36627836SJohn.Forte@Sun.COM } 36637836SJohn.Forte@Sun.COM } 36647836SJohn.Forte@Sun.COM 36657836SJohn.Forte@Sun.COM void 36667836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s) 36677836SJohn.Forte@Sun.COM { 36687836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36697836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 36707836SJohn.Forte@Sun.COM stmf_worker_t *w; 36717836SJohn.Forte@Sun.COM uint32_t old, new; 36727836SJohn.Forte@Sun.COM 36737836SJohn.Forte@Sun.COM do { 36747836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 36757836SJohn.Forte@Sun.COM if ((old & ITASK_BEING_ABORTED) || 36767836SJohn.Forte@Sun.COM ((old & (ITASK_KNOWN_TO_TGT_PORT | 36777836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU)) == 0)) { 36787836SJohn.Forte@Sun.COM return; 36797836SJohn.Forte@Sun.COM } 36807836SJohn.Forte@Sun.COM new |= ITASK_BEING_ABORTED; 36817836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 36827836SJohn.Forte@Sun.COM task->task_completion_status = s; 36837836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 36847836SJohn.Forte@Sun.COM 36857836SJohn.Forte@Sun.COM if (((w = itask->itask_worker) == NULL) || 36867836SJohn.Forte@Sun.COM (itask->itask_flags & ITASK_IN_TRANSITION)) { 36877836SJohn.Forte@Sun.COM return; 36887836SJohn.Forte@Sun.COM } 36897836SJohn.Forte@Sun.COM 36907836SJohn.Forte@Sun.COM /* Queue it and get out */ 36917836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 36927836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) { 36937836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36947836SJohn.Forte@Sun.COM return; 36957836SJohn.Forte@Sun.COM } 36967836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 36977836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 36987836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 36997836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 37007836SJohn.Forte@Sun.COM } else { 37017836SJohn.Forte@Sun.COM w->worker_task_head = itask; 37027836SJohn.Forte@Sun.COM } 37037836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 37047836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 37057836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 37067836SJohn.Forte@Sun.COM } 37077836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 37087836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 37097836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 37107836SJohn.Forte@Sun.COM } 37117836SJohn.Forte@Sun.COM 37127836SJohn.Forte@Sun.COM void 37137836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg) 37147836SJohn.Forte@Sun.COM { 37157836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = NULL; 37167836SJohn.Forte@Sun.COM uint32_t old, new, f, rf; 37177836SJohn.Forte@Sun.COM 37188859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task, 37198859STim.Szeto@Sun.COM stmf_status_t, s); 37208859STim.Szeto@Sun.COM 37217836SJohn.Forte@Sun.COM switch (abort_cmd) { 37227836SJohn.Forte@Sun.COM case STMF_QUEUE_ABORT_LU: 37237836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)arg, task, s); 37247836SJohn.Forte@Sun.COM return; 37257836SJohn.Forte@Sun.COM case STMF_QUEUE_TASK_ABORT: 37267836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(task, s); 37277836SJohn.Forte@Sun.COM return; 37287836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LPORT: 37297836SJohn.Forte@Sun.COM rf = ITASK_TGT_PORT_ABORT_CALLED; 37307836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_TGT_PORT; 37317836SJohn.Forte@Sun.COM break; 37327836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LU: 37337836SJohn.Forte@Sun.COM rf = ITASK_LU_ABORT_CALLED; 37347836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_LU; 37357836SJohn.Forte@Sun.COM break; 37367836SJohn.Forte@Sun.COM default: 37377836SJohn.Forte@Sun.COM return; 37387836SJohn.Forte@Sun.COM } 37397836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 37407836SJohn.Forte@Sun.COM f |= ITASK_BEING_ABORTED | rf; 37417836SJohn.Forte@Sun.COM do { 37427836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 37437836SJohn.Forte@Sun.COM if ((old & f) != f) { 37447836SJohn.Forte@Sun.COM return; 37457836SJohn.Forte@Sun.COM } 37467836SJohn.Forte@Sun.COM new &= ~rf; 37477836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 37487836SJohn.Forte@Sun.COM } 37497836SJohn.Forte@Sun.COM 37507836SJohn.Forte@Sun.COM void 37517836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 37527836SJohn.Forte@Sun.COM { 37537836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 37547836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 37557836SJohn.Forte@Sun.COM unsigned long long st; 37567836SJohn.Forte@Sun.COM 37577836SJohn.Forte@Sun.COM st = s; /* gcc fix */ 37587836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 37597836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37607836SJohn.Forte@Sun.COM "task %p, lu failed to abort ret=%llx", (void *)task, st); 37617836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LU_DONE) == 0) { 37627836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37637836SJohn.Forte@Sun.COM "Task aborted but LU is not finished, task =" 37647836SJohn.Forte@Sun.COM "%p, s=%llx, iof=%x", (void *)task, st, iof); 37657836SJohn.Forte@Sun.COM } else { 37667836SJohn.Forte@Sun.COM /* 37677836SJohn.Forte@Sun.COM * LU abort successfully 37687836SJohn.Forte@Sun.COM */ 37697836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU); 37707836SJohn.Forte@Sun.COM return; 37717836SJohn.Forte@Sun.COM } 37727836SJohn.Forte@Sun.COM 37737836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 37747836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 37757836SJohn.Forte@Sun.COM } 37767836SJohn.Forte@Sun.COM 37777836SJohn.Forte@Sun.COM void 37787836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 37797836SJohn.Forte@Sun.COM { 37807836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 37817836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 37827836SJohn.Forte@Sun.COM unsigned long long st; 37837836SJohn.Forte@Sun.COM 37847836SJohn.Forte@Sun.COM st = s; 37857836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 37867836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37877836SJohn.Forte@Sun.COM "task %p, tgt port failed to abort ret=%llx", (void *)task, 37887836SJohn.Forte@Sun.COM st); 37897836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LPORT_DONE) == 0) { 37907836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37917836SJohn.Forte@Sun.COM "Task aborted but tgt port is not finished, " 37927836SJohn.Forte@Sun.COM "task=%p, s=%llx, iof=%x", (void *)task, st, iof); 37937836SJohn.Forte@Sun.COM } else { 37947836SJohn.Forte@Sun.COM /* 37957836SJohn.Forte@Sun.COM * LU abort successfully 37967836SJohn.Forte@Sun.COM */ 37977836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT); 37987836SJohn.Forte@Sun.COM return; 37997836SJohn.Forte@Sun.COM } 38007836SJohn.Forte@Sun.COM 38017836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 38027836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 38037836SJohn.Forte@Sun.COM } 38047836SJohn.Forte@Sun.COM 38057836SJohn.Forte@Sun.COM stmf_status_t 38067836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout) 38077836SJohn.Forte@Sun.COM { 38087836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 38097836SJohn.Forte@Sun.COM task->task_stmf_private; 38107836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 38117836SJohn.Forte@Sun.COM int i; 38127836SJohn.Forte@Sun.COM 38137836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU); 38147836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 38157836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 38167836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38177836SJohn.Forte@Sun.COM return (STMF_BUSY); 38187836SJohn.Forte@Sun.COM } 38197836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 38207836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) { 38217836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38227836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38237836SJohn.Forte@Sun.COM } 38247836SJohn.Forte@Sun.COM } 38257836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU; 38267836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 38277836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 38287836SJohn.Forte@Sun.COM } else { 38297836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 38307836SJohn.Forte@Sun.COM if (t == 0) 38317836SJohn.Forte@Sun.COM t = 1; 38327836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 38337836SJohn.Forte@Sun.COM } 38347836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 38357836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 38367836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 38377836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 38387836SJohn.Forte@Sun.COM } else { 38397836SJohn.Forte@Sun.COM w->worker_task_head = itask; 38407836SJohn.Forte@Sun.COM } 38417836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 38427836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 38437836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 38447836SJohn.Forte@Sun.COM } 38457836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 38467836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 38477836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 38487836SJohn.Forte@Sun.COM } 38497836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38507836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38517836SJohn.Forte@Sun.COM } 38527836SJohn.Forte@Sun.COM 38537836SJohn.Forte@Sun.COM stmf_status_t 38547836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout) 38557836SJohn.Forte@Sun.COM { 38567836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 38577836SJohn.Forte@Sun.COM task->task_stmf_private; 38587836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 38597836SJohn.Forte@Sun.COM int i; 38607836SJohn.Forte@Sun.COM 38617836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT); 38627836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 38637836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 38647836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38657836SJohn.Forte@Sun.COM return (STMF_BUSY); 38667836SJohn.Forte@Sun.COM } 38677836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 38687836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) { 38697836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38707836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38717836SJohn.Forte@Sun.COM } 38727836SJohn.Forte@Sun.COM } 38737836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT; 38747836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 38757836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 38767836SJohn.Forte@Sun.COM } else { 38777836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 38787836SJohn.Forte@Sun.COM if (t == 0) 38797836SJohn.Forte@Sun.COM t = 1; 38807836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 38817836SJohn.Forte@Sun.COM } 38827836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 38837836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 38847836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 38857836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 38867836SJohn.Forte@Sun.COM } else { 38877836SJohn.Forte@Sun.COM w->worker_task_head = itask; 38887836SJohn.Forte@Sun.COM } 38897836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 38907836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 38917836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 38927836SJohn.Forte@Sun.COM } 38937836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 38947836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 38957836SJohn.Forte@Sun.COM } 38967836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38977836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38987836SJohn.Forte@Sun.COM } 38997836SJohn.Forte@Sun.COM 39007836SJohn.Forte@Sun.COM void 39017836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task) 39027836SJohn.Forte@Sun.COM { 39037836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 39047836SJohn.Forte@Sun.COM stmf_lu_t *lu; 39057836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 39067836SJohn.Forte@Sun.COM unsigned long long ret; 39077836SJohn.Forte@Sun.COM uint32_t old, new; 39087836SJohn.Forte@Sun.COM uint8_t call_lu_abort, call_port_abort; 39097836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 39107836SJohn.Forte@Sun.COM 39117836SJohn.Forte@Sun.COM lu = task->task_lu; 39127836SJohn.Forte@Sun.COM lport = task->task_lport; 39137836SJohn.Forte@Sun.COM do { 39147836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 39157836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) == 39167836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU) { 39177836SJohn.Forte@Sun.COM new |= ITASK_LU_ABORT_CALLED; 39187836SJohn.Forte@Sun.COM call_lu_abort = 1; 39197836SJohn.Forte@Sun.COM } else { 39207836SJohn.Forte@Sun.COM call_lu_abort = 0; 39217836SJohn.Forte@Sun.COM } 39227836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 39237836SJohn.Forte@Sun.COM 39247836SJohn.Forte@Sun.COM if (call_lu_abort) { 39257836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) { 39267836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 39277836SJohn.Forte@Sun.COM } else { 39287836SJohn.Forte@Sun.COM ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 39297836SJohn.Forte@Sun.COM } 39307836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 39317836SJohn.Forte@Sun.COM stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE); 39327836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 39337836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 39347836SJohn.Forte@Sun.COM ~ITASK_LU_ABORT_CALLED); 39357836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 39367836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39377836SJohn.Forte@Sun.COM "Abort failed by LU %p, ret %llx", (void *)lu, ret); 39387836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39397836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 39407836SJohn.Forte@Sun.COM } 39417836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_LU) { 39427836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 39437836SJohn.Forte@Sun.COM STMF_SEC2TICK(lu->lu_abort_timeout? 39447836SJohn.Forte@Sun.COM lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) { 39457836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39467836SJohn.Forte@Sun.COM "lu abort timed out"); 39477836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39487836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 1, info); 39497836SJohn.Forte@Sun.COM } 39507836SJohn.Forte@Sun.COM } 39517836SJohn.Forte@Sun.COM 39527836SJohn.Forte@Sun.COM do { 39537836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 39547836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_TGT_PORT | 39557836SJohn.Forte@Sun.COM ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) { 39567836SJohn.Forte@Sun.COM new |= ITASK_TGT_PORT_ABORT_CALLED; 39577836SJohn.Forte@Sun.COM call_port_abort = 1; 39587836SJohn.Forte@Sun.COM } else { 39597836SJohn.Forte@Sun.COM call_port_abort = 0; 39607836SJohn.Forte@Sun.COM } 39617836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 39627836SJohn.Forte@Sun.COM if (call_port_abort) { 39638662SJordan.Vaughan@Sun.com ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0); 39647836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 39657836SJohn.Forte@Sun.COM stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE); 39667836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 39677836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 39687836SJohn.Forte@Sun.COM ~ITASK_TGT_PORT_ABORT_CALLED); 39697836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 39707836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39717836SJohn.Forte@Sun.COM "Abort failed by tgt port %p ret %llx", 39727836SJohn.Forte@Sun.COM (void *)lport, ret); 39737836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39747836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 39757836SJohn.Forte@Sun.COM } 39767836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) { 39777836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 39787836SJohn.Forte@Sun.COM STMF_SEC2TICK(lport->lport_abort_timeout? 39797836SJohn.Forte@Sun.COM lport->lport_abort_timeout : 39807836SJohn.Forte@Sun.COM ITASK_DEFAULT_ABORT_TIMEOUT))) { 39817836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39827836SJohn.Forte@Sun.COM "lport abort timed out"); 39837836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39847836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 0, info); 39857836SJohn.Forte@Sun.COM } 39867836SJohn.Forte@Sun.COM } 39877836SJohn.Forte@Sun.COM } 39887836SJohn.Forte@Sun.COM 39897836SJohn.Forte@Sun.COM stmf_status_t 39907836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg) 39917836SJohn.Forte@Sun.COM { 39927836SJohn.Forte@Sun.COM stmf_status_t ret; 39937836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 39947836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 39957836SJohn.Forte@Sun.COM stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; 39967836SJohn.Forte@Sun.COM 39977836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 39987836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 39997836SJohn.Forte@Sun.COM if (cmd & STMF_CMD_LU_OP) { 40007836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu((stmf_lu_t *)obj); 40017836SJohn.Forte@Sun.COM if (ilu == NULL) { 40027836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40037836SJohn.Forte@Sun.COM } 40048859STim.Szeto@Sun.COM DTRACE_PROBE3(lu__state__change, 40058859STim.Szeto@Sun.COM stmf_lu_t *, ilu->ilu_lu, 40068859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 40077836SJohn.Forte@Sun.COM } else if (cmd & STMF_CMD_LPORT_OP) { 40087836SJohn.Forte@Sun.COM ilport = stmf_lookup_lport((stmf_local_port_t *)obj); 40097836SJohn.Forte@Sun.COM if (ilport == NULL) { 40107836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40117836SJohn.Forte@Sun.COM } 40128859STim.Szeto@Sun.COM DTRACE_PROBE3(lport__state__change, 40138859STim.Szeto@Sun.COM stmf_local_port_t *, ilport->ilport_lport, 40148859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 40157836SJohn.Forte@Sun.COM } else { 40167836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40177836SJohn.Forte@Sun.COM } 40187836SJohn.Forte@Sun.COM 40197836SJohn.Forte@Sun.COM switch (cmd) { 40207836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 40217836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_ONLINE) { 40227836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 40237836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40247836SJohn.Forte@Sun.COM } 40257836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINE) { 40267836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40277836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40287836SJohn.Forte@Sun.COM } 40297836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINING; 40307836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40317836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 40327836SJohn.Forte@Sun.COM break; 40337836SJohn.Forte@Sun.COM 40347836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE_COMPLETE: 40357836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINING) { 40367836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40377836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40387836SJohn.Forte@Sun.COM } 40397836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 40407836SJohn.Forte@Sun.COM STMF_SUCCESS) { 40417836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 40427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40437836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 40447836SJohn.Forte@Sun.COM STMF_ACK_LU_ONLINE_COMPLETE, arg); 40457836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40467836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 40477836SJohn.Forte@Sun.COM } else { 40487836SJohn.Forte@Sun.COM /* XXX: should throw a meesage an record more data */ 40497836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 40507836SJohn.Forte@Sun.COM } 40517836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 40527836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40537836SJohn.Forte@Sun.COM 40547836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 40557836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 40567836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 40577836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40587836SJohn.Forte@Sun.COM } 40597836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) { 40607836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40617836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40627836SJohn.Forte@Sun.COM } 40637836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINING; 40647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40657836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 40667836SJohn.Forte@Sun.COM break; 40677836SJohn.Forte@Sun.COM 40687836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE_COMPLETE: 40697836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINING) { 40707836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40717836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40727836SJohn.Forte@Sun.COM } 40737836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 40747836SJohn.Forte@Sun.COM STMF_SUCCESS) { 40757836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 40767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40777836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 40787836SJohn.Forte@Sun.COM STMF_ACK_LU_OFFLINE_COMPLETE, arg); 40797836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40807836SJohn.Forte@Sun.COM } else { 40817836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 40827836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 40837836SJohn.Forte@Sun.COM } 40847836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40857836SJohn.Forte@Sun.COM break; 40867836SJohn.Forte@Sun.COM 40877836SJohn.Forte@Sun.COM /* 40887836SJohn.Forte@Sun.COM * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online. 40897836SJohn.Forte@Sun.COM * It's related with hardware disable/enable. 40907836SJohn.Forte@Sun.COM */ 40917836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 40927836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_ONLINE) { 40937836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 40947836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40957836SJohn.Forte@Sun.COM } 40967836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINE) { 40977836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40987836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40997836SJohn.Forte@Sun.COM } 41007836SJohn.Forte@Sun.COM 41017836SJohn.Forte@Sun.COM /* 41027836SJohn.Forte@Sun.COM * Only user request can recover the port from the 41037836SJohn.Forte@Sun.COM * FORCED_OFFLINE state 41047836SJohn.Forte@Sun.COM */ 41057836SJohn.Forte@Sun.COM if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) { 41067836SJohn.Forte@Sun.COM if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { 41077836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 41087836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41097836SJohn.Forte@Sun.COM } 41107836SJohn.Forte@Sun.COM } 41117836SJohn.Forte@Sun.COM 41127836SJohn.Forte@Sun.COM /* 41137836SJohn.Forte@Sun.COM * Avoid too frequent request to online 41147836SJohn.Forte@Sun.COM */ 41157836SJohn.Forte@Sun.COM if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) { 41167836SJohn.Forte@Sun.COM ilport->ilport_online_times = 0; 41177836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 0; 41187836SJohn.Forte@Sun.COM } 41197836SJohn.Forte@Sun.COM if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) && 41207836SJohn.Forte@Sun.COM (ilport->ilport_online_times >= 4)) { 41217836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 41227836SJohn.Forte@Sun.COM ilport->ilport_flags |= ILPORT_FORCED_OFFLINE; 41237836SJohn.Forte@Sun.COM stmf_trace(NULL, "stmf_ctl: too frequent request to " 41247836SJohn.Forte@Sun.COM "online the port"); 41257836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_ctl: too frequent request to " 41267836SJohn.Forte@Sun.COM "online the port, set FORCED_OFFLINE now"); 41277836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41287836SJohn.Forte@Sun.COM } 41297836SJohn.Forte@Sun.COM if (ilport->ilport_online_times > 0) { 41307836SJohn.Forte@Sun.COM if (ilport->ilport_online_times == 1) { 41317836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = ddi_get_lbolt() - 41327836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock; 41337836SJohn.Forte@Sun.COM } else { 41347836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 41357836SJohn.Forte@Sun.COM (ilport->ilport_avg_interval + 41367836SJohn.Forte@Sun.COM ddi_get_lbolt() - 41377836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock) >> 1; 41387836SJohn.Forte@Sun.COM } 41397836SJohn.Forte@Sun.COM } 41407836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock = ddi_get_lbolt(); 41417836SJohn.Forte@Sun.COM ilport->ilport_online_times++; 41427836SJohn.Forte@Sun.COM 41437836SJohn.Forte@Sun.COM /* 41447836SJohn.Forte@Sun.COM * Submit online service request 41457836SJohn.Forte@Sun.COM */ 41467836SJohn.Forte@Sun.COM ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE; 41477836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINING; 41487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41497836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 41507836SJohn.Forte@Sun.COM break; 41517836SJohn.Forte@Sun.COM 41527836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE_COMPLETE: 41537836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINING) { 41547836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41557836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41567836SJohn.Forte@Sun.COM } 41577836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 41587836SJohn.Forte@Sun.COM STMF_SUCCESS) { 41597836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 41607836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41617836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 41627836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 41637836SJohn.Forte@Sun.COM STMF_ACK_LPORT_ONLINE_COMPLETE, arg); 41647836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 41657836SJohn.Forte@Sun.COM } else { 41667836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 41677836SJohn.Forte@Sun.COM } 41687836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 41697836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41707836SJohn.Forte@Sun.COM 41717836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 41727836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) { 41737836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 41747836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41757836SJohn.Forte@Sun.COM } 41767836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 41777836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41787836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41797836SJohn.Forte@Sun.COM } 41807836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINING; 41817836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41827836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 41837836SJohn.Forte@Sun.COM break; 41847836SJohn.Forte@Sun.COM 41857836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE_COMPLETE: 41867836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 41877836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41887836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41897836SJohn.Forte@Sun.COM } 41907836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 41917836SJohn.Forte@Sun.COM STMF_SUCCESS) { 41927836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 41937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41947836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 41957836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 41967836SJohn.Forte@Sun.COM STMF_ACK_LPORT_OFFLINE_COMPLETE, arg); 41977836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 41987836SJohn.Forte@Sun.COM } else { 41997836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 42007836SJohn.Forte@Sun.COM } 42017836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42027836SJohn.Forte@Sun.COM break; 42037836SJohn.Forte@Sun.COM 42047836SJohn.Forte@Sun.COM default: 42057836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd); 42067836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 42077836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 42087836SJohn.Forte@Sun.COM } 42097836SJohn.Forte@Sun.COM 42107836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 42117836SJohn.Forte@Sun.COM 42127836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:; 42137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42147836SJohn.Forte@Sun.COM return (ret); 42157836SJohn.Forte@Sun.COM } 42167836SJohn.Forte@Sun.COM 42177836SJohn.Forte@Sun.COM /* ARGSUSED */ 42187836SJohn.Forte@Sun.COM stmf_status_t 42197836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 42207836SJohn.Forte@Sun.COM uint32_t *bufsizep) 42217836SJohn.Forte@Sun.COM { 42227836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 42237836SJohn.Forte@Sun.COM } 42247836SJohn.Forte@Sun.COM 42257836SJohn.Forte@Sun.COM /* ARGSUSED */ 42267836SJohn.Forte@Sun.COM stmf_status_t 42277836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 42287836SJohn.Forte@Sun.COM uint32_t *bufsizep) 42297836SJohn.Forte@Sun.COM { 42307836SJohn.Forte@Sun.COM uint32_t cl = SI_GET_CLASS(cmd); 42317836SJohn.Forte@Sun.COM 42327836SJohn.Forte@Sun.COM if (cl == SI_STMF) { 42337836SJohn.Forte@Sun.COM return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep)); 42347836SJohn.Forte@Sun.COM } 42357836SJohn.Forte@Sun.COM if (cl == SI_LPORT) { 42368662SJordan.Vaughan@Sun.com return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1, 42378662SJordan.Vaughan@Sun.com arg2, buf, bufsizep)); 42387836SJohn.Forte@Sun.COM } else if (cl == SI_LU) { 42398662SJordan.Vaughan@Sun.com return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf, 42408662SJordan.Vaughan@Sun.com bufsizep)); 42417836SJohn.Forte@Sun.COM } 42427836SJohn.Forte@Sun.COM 42437836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 42447836SJohn.Forte@Sun.COM } 42457836SJohn.Forte@Sun.COM 42467836SJohn.Forte@Sun.COM /* 42479857SPeter.Cudhea@Sun.COM * Used by port providers. pwwn is 8 byte wwn, sdid is the devid used by 42487836SJohn.Forte@Sun.COM * stmf to register local ports. The ident should have 20 bytes in buffer 42497836SJohn.Forte@Sun.COM * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string. 42507836SJohn.Forte@Sun.COM */ 42517836SJohn.Forte@Sun.COM void 42527836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn, 42537836SJohn.Forte@Sun.COM uint8_t protocol_id) 42547836SJohn.Forte@Sun.COM { 42559857SPeter.Cudhea@Sun.COM char wwn_str[20+1]; 42569857SPeter.Cudhea@Sun.COM 42577836SJohn.Forte@Sun.COM sdid->protocol_id = protocol_id; 42587836SJohn.Forte@Sun.COM sdid->piv = 1; 42597836SJohn.Forte@Sun.COM sdid->code_set = CODE_SET_ASCII; 42607836SJohn.Forte@Sun.COM sdid->association = ID_IS_TARGET_PORT; 42617836SJohn.Forte@Sun.COM sdid->ident_length = 20; 42629857SPeter.Cudhea@Sun.COM /* Convert wwn value to "wwn.XXXXXXXXXXXXXXXX" format */ 42639857SPeter.Cudhea@Sun.COM (void) snprintf(wwn_str, sizeof (wwn_str), 42647836SJohn.Forte@Sun.COM "wwn.%02X%02X%02X%02X%02X%02X%02X%02X", 42657836SJohn.Forte@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 42669857SPeter.Cudhea@Sun.COM bcopy(wwn_str, (char *)sdid->ident, 20); 42677836SJohn.Forte@Sun.COM } 42687836SJohn.Forte@Sun.COM 42699857SPeter.Cudhea@Sun.COM 42707836SJohn.Forte@Sun.COM stmf_xfer_data_t * 42717836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data() 42727836SJohn.Forte@Sun.COM { 42737836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 42747836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 42757836SJohn.Forte@Sun.COM uint8_t *p; 42767836SJohn.Forte@Sun.COM uint32_t sz, asz, nports; 42777836SJohn.Forte@Sun.COM 42787836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 42797836SJohn.Forte@Sun.COM /* The spec only allows for 255 ports to be reported */ 42807836SJohn.Forte@Sun.COM nports = min(stmf_state.stmf_nlports, 255); 42817836SJohn.Forte@Sun.COM sz = (nports * 4) + 12; 42827836SJohn.Forte@Sun.COM asz = sz + sizeof (*xd) - 4; 42837836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP); 42847836SJohn.Forte@Sun.COM if (xd == NULL) { 42857836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42867836SJohn.Forte@Sun.COM return (NULL); 42877836SJohn.Forte@Sun.COM } 42887836SJohn.Forte@Sun.COM xd->alloc_size = asz; 42897836SJohn.Forte@Sun.COM xd->size_left = sz; 42907836SJohn.Forte@Sun.COM 42917836SJohn.Forte@Sun.COM p = xd->buf; 42927836SJohn.Forte@Sun.COM 42937836SJohn.Forte@Sun.COM *((uint32_t *)p) = BE_32(sz - 4); 42947836SJohn.Forte@Sun.COM p += 4; 42957836SJohn.Forte@Sun.COM p[0] = 0x80; /* PREF */ 42967836SJohn.Forte@Sun.COM p[1] = 1; /* AO_SUP */ 42977836SJohn.Forte@Sun.COM p[7] = nports & 0xff; 42987836SJohn.Forte@Sun.COM p += 8; 42997836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport && nports; 43007836SJohn.Forte@Sun.COM nports++, ilport = ilport->ilport_next, p += 4) { 43017836SJohn.Forte@Sun.COM ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid); 43027836SJohn.Forte@Sun.COM } 43037836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 43047836SJohn.Forte@Sun.COM 43057836SJohn.Forte@Sun.COM return (xd); 43067836SJohn.Forte@Sun.COM } 43077836SJohn.Forte@Sun.COM 43089585STim.Szeto@Sun.COM struct scsi_devid_desc * 43099585STim.Szeto@Sun.COM stmf_scsilib_get_devid_desc(uint16_t rtpid) 43109585STim.Szeto@Sun.COM { 43119585STim.Szeto@Sun.COM scsi_devid_desc_t *devid = NULL; 43129585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 43139585STim.Szeto@Sun.COM 43149585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 43159585STim.Szeto@Sun.COM 43169585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 43179585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 43189585STim.Szeto@Sun.COM if (ilport->ilport_rtpid == rtpid) { 43199585STim.Szeto@Sun.COM scsi_devid_desc_t *id = ilport->ilport_lport->lport_id; 43209585STim.Szeto@Sun.COM uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 + 43219585STim.Szeto@Sun.COM id->ident_length; 43229585STim.Szeto@Sun.COM devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz, 43239585STim.Szeto@Sun.COM KM_NOSLEEP); 43249585STim.Szeto@Sun.COM if (devid != NULL) { 43259585STim.Szeto@Sun.COM bcopy(id, devid, id_sz); 43269585STim.Szeto@Sun.COM } 43279585STim.Szeto@Sun.COM break; 43289585STim.Szeto@Sun.COM } 43299585STim.Szeto@Sun.COM } 43309585STim.Szeto@Sun.COM 43319585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 43329585STim.Szeto@Sun.COM return (devid); 43339585STim.Szeto@Sun.COM } 43349585STim.Szeto@Sun.COM 43359585STim.Szeto@Sun.COM uint16_t 43369585STim.Szeto@Sun.COM stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid) 43379585STim.Szeto@Sun.COM { 43389585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 43399585STim.Szeto@Sun.COM scsi_devid_desc_t *id; 43409585STim.Szeto@Sun.COM uint16_t rtpid = 0; 43419585STim.Szeto@Sun.COM 43429585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 43439585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 43449585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 43459585STim.Szeto@Sun.COM id = ilport->ilport_lport->lport_id; 43469585STim.Szeto@Sun.COM if ((devid->ident_length == id->ident_length) && 43479585STim.Szeto@Sun.COM (memcmp(devid->ident, id->ident, id->ident_length) == 0)) { 43489585STim.Szeto@Sun.COM rtpid = ilport->ilport_rtpid; 43499585STim.Szeto@Sun.COM break; 43509585STim.Szeto@Sun.COM } 43519585STim.Szeto@Sun.COM } 43529585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 43539585STim.Szeto@Sun.COM return (rtpid); 43549585STim.Szeto@Sun.COM } 43557836SJohn.Forte@Sun.COM 43567836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0; 43577836SJohn.Forte@Sun.COM 43587836SJohn.Forte@Sun.COM stmf_status_t 43597836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id) 43607836SJohn.Forte@Sun.COM { 43617836SJohn.Forte@Sun.COM uint8_t *p; 43627836SJohn.Forte@Sun.COM struct timeval32 timestamp32; 43637836SJohn.Forte@Sun.COM uint32_t *t = (uint32_t *)×tamp32; 43647836SJohn.Forte@Sun.COM struct ether_addr mac; 43657836SJohn.Forte@Sun.COM uint8_t *e = (uint8_t *)&mac; 43667836SJohn.Forte@Sun.COM 43677836SJohn.Forte@Sun.COM if (company_id == COMPANY_ID_NONE) 43687836SJohn.Forte@Sun.COM company_id = COMPANY_ID_SUN; 43697836SJohn.Forte@Sun.COM 43707836SJohn.Forte@Sun.COM if (lu_id->ident_length != 0x10) 43717836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 43727836SJohn.Forte@Sun.COM 43737836SJohn.Forte@Sun.COM p = (uint8_t *)lu_id; 43747836SJohn.Forte@Sun.COM 43757836SJohn.Forte@Sun.COM atomic_add_16(&stmf_lu_id_gen_number, 1); 43767836SJohn.Forte@Sun.COM 43777836SJohn.Forte@Sun.COM p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10; 43787836SJohn.Forte@Sun.COM p[4] = ((company_id >> 20) & 0xf) | 0x60; 43797836SJohn.Forte@Sun.COM p[5] = (company_id >> 12) & 0xff; 43807836SJohn.Forte@Sun.COM p[6] = (company_id >> 4) & 0xff; 43817836SJohn.Forte@Sun.COM p[7] = (company_id << 4) & 0xf0; 43827836SJohn.Forte@Sun.COM if (!localetheraddr((struct ether_addr *)NULL, &mac)) { 43838662SJordan.Vaughan@Sun.com int hid = BE_32((int)zone_get_hostid(NULL)); 43847836SJohn.Forte@Sun.COM e[0] = (hid >> 24) & 0xff; 43857836SJohn.Forte@Sun.COM e[1] = (hid >> 16) & 0xff; 43867836SJohn.Forte@Sun.COM e[2] = (hid >> 8) & 0xff; 43877836SJohn.Forte@Sun.COM e[3] = hid & 0xff; 43887836SJohn.Forte@Sun.COM e[4] = e[5] = 0; 43897836SJohn.Forte@Sun.COM } 43907836SJohn.Forte@Sun.COM bcopy(e, p+8, 6); 43917836SJohn.Forte@Sun.COM uniqtime32(×tamp32); 43927836SJohn.Forte@Sun.COM *t = BE_32(*t); 43937836SJohn.Forte@Sun.COM bcopy(t, p+14, 4); 43947836SJohn.Forte@Sun.COM p[18] = (stmf_lu_id_gen_number >> 8) & 0xff; 43957836SJohn.Forte@Sun.COM p[19] = stmf_lu_id_gen_number & 0xff; 43967836SJohn.Forte@Sun.COM 43977836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 43987836SJohn.Forte@Sun.COM } 43997836SJohn.Forte@Sun.COM 44007836SJohn.Forte@Sun.COM /* 44017836SJohn.Forte@Sun.COM * saa is sense key, ASC, ASCQ 44027836SJohn.Forte@Sun.COM */ 44037836SJohn.Forte@Sun.COM void 44047836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa) 44057836SJohn.Forte@Sun.COM { 44067836SJohn.Forte@Sun.COM uint8_t sd[18]; 44077836SJohn.Forte@Sun.COM task->task_scsi_status = st; 44087836SJohn.Forte@Sun.COM if (st == 2) { 44097836SJohn.Forte@Sun.COM bzero(sd, 18); 44107836SJohn.Forte@Sun.COM sd[0] = 0x70; 44117836SJohn.Forte@Sun.COM sd[2] = (saa >> 16) & 0xf; 44127836SJohn.Forte@Sun.COM sd[7] = 10; 44137836SJohn.Forte@Sun.COM sd[12] = (saa >> 8) & 0xff; 44147836SJohn.Forte@Sun.COM sd[13] = saa & 0xff; 44157836SJohn.Forte@Sun.COM task->task_sense_data = sd; 44167836SJohn.Forte@Sun.COM task->task_sense_length = 18; 44177836SJohn.Forte@Sun.COM } else { 44187836SJohn.Forte@Sun.COM task->task_sense_data = NULL; 44197836SJohn.Forte@Sun.COM task->task_sense_length = 0; 44207836SJohn.Forte@Sun.COM } 44217836SJohn.Forte@Sun.COM (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE); 44227836SJohn.Forte@Sun.COM } 44237836SJohn.Forte@Sun.COM 44247836SJohn.Forte@Sun.COM uint32_t 44257836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page, 44267836SJohn.Forte@Sun.COM uint32_t page_len, uint8_t byte0, uint32_t vpd_mask) 44277836SJohn.Forte@Sun.COM { 44287836SJohn.Forte@Sun.COM uint8_t *p = NULL; 44297836SJohn.Forte@Sun.COM uint8_t small_buf[32]; 44307836SJohn.Forte@Sun.COM uint32_t sz = 0; 44317836SJohn.Forte@Sun.COM uint32_t n = 4; 44327836SJohn.Forte@Sun.COM uint32_t m = 0; 44337836SJohn.Forte@Sun.COM uint32_t last_bit = 0; 44347836SJohn.Forte@Sun.COM 44357836SJohn.Forte@Sun.COM if (page_len < 4) 44367836SJohn.Forte@Sun.COM return (0); 44377836SJohn.Forte@Sun.COM if (page_len > 65535) 44387836SJohn.Forte@Sun.COM page_len = 65535; 44397836SJohn.Forte@Sun.COM 44407836SJohn.Forte@Sun.COM page[0] = byte0; 44417836SJohn.Forte@Sun.COM page[1] = 0x83; 44427836SJohn.Forte@Sun.COM 44437836SJohn.Forte@Sun.COM /* CONSTCOND */ 44447836SJohn.Forte@Sun.COM while (1) { 44457836SJohn.Forte@Sun.COM m += sz; 44467836SJohn.Forte@Sun.COM if (sz && (page_len > n)) { 44477836SJohn.Forte@Sun.COM uint32_t copysz; 44487836SJohn.Forte@Sun.COM copysz = page_len > (n + sz) ? sz : page_len - n; 44497836SJohn.Forte@Sun.COM bcopy(p, page + n, copysz); 44507836SJohn.Forte@Sun.COM n += copysz; 44517836SJohn.Forte@Sun.COM } 44527836SJohn.Forte@Sun.COM vpd_mask &= ~last_bit; 44537836SJohn.Forte@Sun.COM if (vpd_mask == 0) 44547836SJohn.Forte@Sun.COM break; 44557836SJohn.Forte@Sun.COM 44567836SJohn.Forte@Sun.COM if (vpd_mask & STMF_VPD_LU_ID) { 44577836SJohn.Forte@Sun.COM last_bit = STMF_VPD_LU_ID; 44587836SJohn.Forte@Sun.COM sz = task->task_lu->lu_id->ident_length + 4; 44597836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lu->lu_id; 44607836SJohn.Forte@Sun.COM continue; 44617836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TARGET_ID) { 44627836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TARGET_ID; 44637836SJohn.Forte@Sun.COM sz = task->task_lport->lport_id->ident_length + 4; 44647836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lport->lport_id; 44657836SJohn.Forte@Sun.COM continue; 44667836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TP_GROUP) { 44677836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TP_GROUP; 44687836SJohn.Forte@Sun.COM p = small_buf; 44697836SJohn.Forte@Sun.COM bzero(p, 8); 44707836SJohn.Forte@Sun.COM p[0] = 1; 44717836SJohn.Forte@Sun.COM p[1] = 0x15; 44727836SJohn.Forte@Sun.COM p[3] = 4; 44737836SJohn.Forte@Sun.COM /* Group ID is always 0 */ 44747836SJohn.Forte@Sun.COM sz = 8; 44757836SJohn.Forte@Sun.COM continue; 44767836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) { 44777836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 44787836SJohn.Forte@Sun.COM 44797836SJohn.Forte@Sun.COM last_bit = STMF_VPD_RELATIVE_TP_ID; 44807836SJohn.Forte@Sun.COM p = small_buf; 44817836SJohn.Forte@Sun.COM bzero(p, 8); 44827836SJohn.Forte@Sun.COM p[0] = 1; 44837836SJohn.Forte@Sun.COM p[1] = 0x14; 44847836SJohn.Forte@Sun.COM p[3] = 4; 44857836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *) 44868662SJordan.Vaughan@Sun.com task->task_lport->lport_stmf_private; 44877836SJohn.Forte@Sun.COM p[6] = (ilport->ilport_rtpid >> 8) & 0xff; 44887836SJohn.Forte@Sun.COM p[7] = ilport->ilport_rtpid & 0xff; 44897836SJohn.Forte@Sun.COM sz = 8; 44907836SJohn.Forte@Sun.COM continue; 44917836SJohn.Forte@Sun.COM } else { 44927836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid vpd_mask"); 44937836SJohn.Forte@Sun.COM break; 44947836SJohn.Forte@Sun.COM } 44957836SJohn.Forte@Sun.COM } 44967836SJohn.Forte@Sun.COM 44977836SJohn.Forte@Sun.COM page[2] = (m >> 8) & 0xff; 44987836SJohn.Forte@Sun.COM page[3] = m & 0xff; 44997836SJohn.Forte@Sun.COM 45007836SJohn.Forte@Sun.COM return (n); 45017836SJohn.Forte@Sun.COM } 45027836SJohn.Forte@Sun.COM 45037836SJohn.Forte@Sun.COM void 45047836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf) 45057836SJohn.Forte@Sun.COM { 45067836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 45078662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 45087836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 45097836SJohn.Forte@Sun.COM uint32_t sz, minsz; 45107836SJohn.Forte@Sun.COM 45117836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING; 45127836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 45137836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 45147836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 45157836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 45167836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 45177836SJohn.Forte@Sun.COM 45187836SJohn.Forte@Sun.COM if (task->task_additional_flags & 45197836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 45207836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 45217836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 45227836SJohn.Forte@Sun.COM } 45237836SJohn.Forte@Sun.COM 4524*9962SWayne.Ihde@Sun.COM if (task->task_cmd_xfer_length == 0) { 4525*9962SWayne.Ihde@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 4526*9962SWayne.Ihde@Sun.COM return; 4527*9962SWayne.Ihde@Sun.COM } 4528*9962SWayne.Ihde@Sun.COM if (task->task_cmd_xfer_length < 4) { 45297836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 45308662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 45317836SJohn.Forte@Sun.COM return; 45327836SJohn.Forte@Sun.COM } 45337836SJohn.Forte@Sun.COM 45347836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 45357836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 45367836SJohn.Forte@Sun.COM 45377836SJohn.Forte@Sun.COM xd = stmf_prepare_tpgs_data(); 45387836SJohn.Forte@Sun.COM 45397836SJohn.Forte@Sun.COM if (xd == NULL) { 45407836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 45417836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 45427836SJohn.Forte@Sun.COM return; 45437836SJohn.Forte@Sun.COM } 45447836SJohn.Forte@Sun.COM 45457836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 45467836SJohn.Forte@Sun.COM xd->size_left = sz; 45477836SJohn.Forte@Sun.COM minsz = min(512, sz); 45487836SJohn.Forte@Sun.COM 45497836SJohn.Forte@Sun.COM if (dbuf == NULL) 45507836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 45517836SJohn.Forte@Sun.COM if (dbuf == NULL) { 45527836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 45537836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 45547836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 45557836SJohn.Forte@Sun.COM return; 45567836SJohn.Forte@Sun.COM } 45577836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 45587836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 45597836SJohn.Forte@Sun.COM 45607836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 45617836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 45627836SJohn.Forte@Sun.COM 45637836SJohn.Forte@Sun.COM } 45647836SJohn.Forte@Sun.COM 45657836SJohn.Forte@Sun.COM void 45667836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task) 45677836SJohn.Forte@Sun.COM { 45687836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 45697836SJohn.Forte@Sun.COM /* 45707836SJohn.Forte@Sun.COM * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET 45717836SJohn.Forte@Sun.COM * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state 45727836SJohn.Forte@Sun.COM * in these cases. This needs to be changed to abort only the required 45737836SJohn.Forte@Sun.COM * set. 45747836SJohn.Forte@Sun.COM */ 45757836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 45767836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 45777836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 45787836SJohn.Forte@Sun.COM case TM_LUN_RESET: 45797836SJohn.Forte@Sun.COM stmf_handle_lun_reset(task); 45807836SJohn.Forte@Sun.COM return; 45817836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 45827836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 45837836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 45847836SJohn.Forte@Sun.COM stmf_handle_target_reset(task); 45857836SJohn.Forte@Sun.COM return; 45867836SJohn.Forte@Sun.COM default: 45877836SJohn.Forte@Sun.COM /* We dont support this task mgmt function */ 45887836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 45897836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CMD_IU); 45907836SJohn.Forte@Sun.COM return; 45917836SJohn.Forte@Sun.COM } 45927836SJohn.Forte@Sun.COM } 45937836SJohn.Forte@Sun.COM 45947836SJohn.Forte@Sun.COM void 45957836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task) 45967836SJohn.Forte@Sun.COM { 45977836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 45987836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 45997836SJohn.Forte@Sun.COM 46007836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 46017836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 46027836SJohn.Forte@Sun.COM 46037836SJohn.Forte@Sun.COM /* 46047836SJohn.Forte@Sun.COM * To sync with target reset, grab this lock. The LU is not going 46057836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 46067836SJohn.Forte@Sun.COM */ 46077836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 46087836SJohn.Forte@Sun.COM 46097836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 46107836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46117836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46128662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46137836SJohn.Forte@Sun.COM return; 46147836SJohn.Forte@Sun.COM } 46157836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 46167836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46177836SJohn.Forte@Sun.COM 46187836SJohn.Forte@Sun.COM /* 46197836SJohn.Forte@Sun.COM * Mark this task as the one causing LU reset so that we know who 46207836SJohn.Forte@Sun.COM * was responsible for setting the ILU_RESET_ACTIVE. In case this 46217836SJohn.Forte@Sun.COM * task itself gets aborted, we will clear ILU_RESET_ACTIVE. 46227836SJohn.Forte@Sun.COM */ 46237836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET; 46247836SJohn.Forte@Sun.COM 46257836SJohn.Forte@Sun.COM /* Initiatiate abort on all commands on this LU except this one */ 46267836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu); 46277836SJohn.Forte@Sun.COM 46287836SJohn.Forte@Sun.COM /* Start polling on this task */ 46297836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 46307836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 46317836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 46328662SJordan.Vaughan@Sun.com NULL); 46337836SJohn.Forte@Sun.COM return; 46347836SJohn.Forte@Sun.COM } 46357836SJohn.Forte@Sun.COM } 46367836SJohn.Forte@Sun.COM 46377836SJohn.Forte@Sun.COM void 46387836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task) 46397836SJohn.Forte@Sun.COM { 46407836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 46417836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 46427836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 46437836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 46447836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 46457836SJohn.Forte@Sun.COM int i, lf; 46467836SJohn.Forte@Sun.COM 46477836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 46487836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private; 46497836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 46507836SJohn.Forte@Sun.COM 46517836SJohn.Forte@Sun.COM /* 46527836SJohn.Forte@Sun.COM * To sync with LUN reset, grab this lock. The session is not going 46537836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 46547836SJohn.Forte@Sun.COM */ 46557836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 46567979SSumit.Gupta@Sun.COM 46577979SSumit.Gupta@Sun.COM /* Grab the session lock as a writer to prevent any changes in it */ 46587979SSumit.Gupta@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 46597979SSumit.Gupta@Sun.COM 46607836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_RESET_ACTIVE) { 46617979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 46627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46637836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46648662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46657836SJohn.Forte@Sun.COM return; 46667836SJohn.Forte@Sun.COM } 46677836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE); 46687836SJohn.Forte@Sun.COM 46697836SJohn.Forte@Sun.COM /* 46707836SJohn.Forte@Sun.COM * Now go through each LUN in this session and make sure all of them 46717836SJohn.Forte@Sun.COM * can be reset. 46727836SJohn.Forte@Sun.COM */ 46737836SJohn.Forte@Sun.COM lm = iss->iss_sm; 46747836SJohn.Forte@Sun.COM for (i = 0, lf = 0; i < lm->lm_nentries; i++) { 46757836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 46767836SJohn.Forte@Sun.COM continue; 46777836SJohn.Forte@Sun.COM lf++; 46787836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 46797836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 46807836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 46817836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 46827979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 46837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46847836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46858662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46867836SJohn.Forte@Sun.COM return; 46877836SJohn.Forte@Sun.COM } 46887836SJohn.Forte@Sun.COM } 46897836SJohn.Forte@Sun.COM if (lf == 0) { 46907836SJohn.Forte@Sun.COM /* No luns in this session */ 46917836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 46927979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 46937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46947836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 46957836SJohn.Forte@Sun.COM return; 46967836SJohn.Forte@Sun.COM } 46977836SJohn.Forte@Sun.COM 46987836SJohn.Forte@Sun.COM /* ok, start the damage */ 46997836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | 47008662SJordan.Vaughan@Sun.com ITASK_CAUSING_TARGET_RESET; 47017836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 47027836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 47037836SJohn.Forte@Sun.COM continue; 47047836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 47057836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 47067836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 47077836SJohn.Forte@Sun.COM } 47087979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 47097836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 47107836SJohn.Forte@Sun.COM 47117836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 47127836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 47137836SJohn.Forte@Sun.COM continue; 47147836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 47157836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, 47168662SJordan.Vaughan@Sun.com lm_ent->ent_lu); 47177836SJohn.Forte@Sun.COM } 47187836SJohn.Forte@Sun.COM 47197836SJohn.Forte@Sun.COM /* Start polling on this task */ 47207836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 47217836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 47227836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 47238662SJordan.Vaughan@Sun.com NULL); 47247836SJohn.Forte@Sun.COM return; 47257836SJohn.Forte@Sun.COM } 47267836SJohn.Forte@Sun.COM } 47277836SJohn.Forte@Sun.COM 47287836SJohn.Forte@Sun.COM int 47297836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask) 47307836SJohn.Forte@Sun.COM { 47317836SJohn.Forte@Sun.COM scsi_task_t *task = itask->itask_task; 47327836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 47337836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 47347836SJohn.Forte@Sun.COM 47357836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 47367836SJohn.Forte@Sun.COM if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) || 47377836SJohn.Forte@Sun.COM (task->task_cdb[0] == SCMD_INQUIRY)) { 47387836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 47397836SJohn.Forte@Sun.COM return (0); 47407836SJohn.Forte@Sun.COM } 47417836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 47428662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 47437836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 47447836SJohn.Forte@Sun.COM 47457836SJohn.Forte@Sun.COM if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 47467836SJohn.Forte@Sun.COM return (0); 47477836SJohn.Forte@Sun.COM } 47487836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 47497836SJohn.Forte@Sun.COM STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED); 47507836SJohn.Forte@Sun.COM return (1); 47517836SJohn.Forte@Sun.COM } 47527836SJohn.Forte@Sun.COM 47537836SJohn.Forte@Sun.COM void 47547836SJohn.Forte@Sun.COM stmf_worker_init() 47557836SJohn.Forte@Sun.COM { 47567836SJohn.Forte@Sun.COM uint32_t i; 47577836SJohn.Forte@Sun.COM 47587836SJohn.Forte@Sun.COM /* Make local copy of global tunables */ 47597836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_max_nworkers; 47607836SJohn.Forte@Sun.COM stmf_i_min_nworkers = stmf_min_nworkers; 47617836SJohn.Forte@Sun.COM 47627836SJohn.Forte@Sun.COM ASSERT(stmf_workers == NULL); 47637836SJohn.Forte@Sun.COM if (stmf_i_min_nworkers < 4) { 47647836SJohn.Forte@Sun.COM stmf_i_min_nworkers = 4; 47657836SJohn.Forte@Sun.COM } 47667836SJohn.Forte@Sun.COM if (stmf_i_max_nworkers < stmf_i_min_nworkers) { 47677836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_i_min_nworkers; 47687836SJohn.Forte@Sun.COM } 47697836SJohn.Forte@Sun.COM stmf_workers = (stmf_worker_t *)kmem_zalloc( 47707836SJohn.Forte@Sun.COM sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP); 47717836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 47727836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 47737836SJohn.Forte@Sun.COM mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 47747836SJohn.Forte@Sun.COM cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 47757836SJohn.Forte@Sun.COM } 47767836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 47777836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 47787836SJohn.Forte@Sun.COM 47797836SJohn.Forte@Sun.COM /* Workers will be started by stmf_worker_mgmt() */ 47807836SJohn.Forte@Sun.COM 47817836SJohn.Forte@Sun.COM /* Lets wait for atleast one worker to start */ 47827836SJohn.Forte@Sun.COM while (stmf_nworkers_cur == 0) 47837836SJohn.Forte@Sun.COM delay(drv_usectohz(20 * 1000)); 47847836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000); 47857836SJohn.Forte@Sun.COM } 47867836SJohn.Forte@Sun.COM 47877836SJohn.Forte@Sun.COM stmf_status_t 47887836SJohn.Forte@Sun.COM stmf_worker_fini() 47897836SJohn.Forte@Sun.COM { 47907836SJohn.Forte@Sun.COM int i; 47917836SJohn.Forte@Sun.COM clock_t sb; 47927836SJohn.Forte@Sun.COM 47937836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) 47947836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 47957836SJohn.Forte@Sun.COM ASSERT(stmf_workers); 47967836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_DISABLED; 47977836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 47987836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 47997836SJohn.Forte@Sun.COM 48007836SJohn.Forte@Sun.COM sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000); 48017836SJohn.Forte@Sun.COM /* Wait for all the threads to die */ 48027836SJohn.Forte@Sun.COM while (stmf_nworkers_cur != 0) { 48037836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > sb) { 48047836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 48057836SJohn.Forte@Sun.COM return (STMF_BUSY); 48067836SJohn.Forte@Sun.COM } 48077836SJohn.Forte@Sun.COM delay(drv_usectohz(100 * 1000)); 48087836SJohn.Forte@Sun.COM } 48097836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 48107836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 48117836SJohn.Forte@Sun.COM mutex_destroy(&w->worker_lock); 48127836SJohn.Forte@Sun.COM cv_destroy(&w->worker_cv); 48137836SJohn.Forte@Sun.COM } 48147836SJohn.Forte@Sun.COM kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers); 48157836SJohn.Forte@Sun.COM stmf_workers = NULL; 48167836SJohn.Forte@Sun.COM 48177836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 48187836SJohn.Forte@Sun.COM } 48197836SJohn.Forte@Sun.COM 48207836SJohn.Forte@Sun.COM void 48217836SJohn.Forte@Sun.COM stmf_worker_task(void *arg) 48227836SJohn.Forte@Sun.COM { 48237836SJohn.Forte@Sun.COM stmf_worker_t *w; 48247836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 48257836SJohn.Forte@Sun.COM scsi_task_t *task; 48267836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 48277836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 48287836SJohn.Forte@Sun.COM stmf_lu_t *lu; 48297836SJohn.Forte@Sun.COM clock_t wait_timer = 0; 48307836SJohn.Forte@Sun.COM clock_t wait_ticks; 48317836SJohn.Forte@Sun.COM uint32_t old, new; 48327836SJohn.Forte@Sun.COM uint8_t curcmd; 48337836SJohn.Forte@Sun.COM uint8_t abort_free; 48347836SJohn.Forte@Sun.COM uint8_t wait_queue; 48357836SJohn.Forte@Sun.COM uint8_t dec_qdepth; 48367836SJohn.Forte@Sun.COM 48377836SJohn.Forte@Sun.COM w = (stmf_worker_t *)arg; 48387836SJohn.Forte@Sun.COM wait_ticks = drv_usectohz(10000); 48397836SJohn.Forte@Sun.COM 48407836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 48417836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE; 48427836SJohn.Forte@Sun.COM stmf_worker_loop:; 48437836SJohn.Forte@Sun.COM if ((w->worker_ref_count == 0) && 48447836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 48457836SJohn.Forte@Sun.COM w->worker_flags &= ~(STMF_WORKER_STARTED | 48467836SJohn.Forte@Sun.COM STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE); 48477836SJohn.Forte@Sun.COM w->worker_tid = NULL; 48487836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 48497836SJohn.Forte@Sun.COM thread_exit(); 48507836SJohn.Forte@Sun.COM } 48517836SJohn.Forte@Sun.COM /* CONSTCOND */ 48527836SJohn.Forte@Sun.COM while (1) { 48537836SJohn.Forte@Sun.COM dec_qdepth = 0; 48547836SJohn.Forte@Sun.COM if (wait_timer && (ddi_get_lbolt() >= wait_timer)) { 48557836SJohn.Forte@Sun.COM wait_timer = 0; 48567979SSumit.Gupta@Sun.COM if (w->worker_wait_head) { 48577979SSumit.Gupta@Sun.COM ASSERT(w->worker_wait_tail); 48587979SSumit.Gupta@Sun.COM if (w->worker_task_head == NULL) 48597979SSumit.Gupta@Sun.COM w->worker_task_head = 48607979SSumit.Gupta@Sun.COM w->worker_wait_head; 48617979SSumit.Gupta@Sun.COM else 48627979SSumit.Gupta@Sun.COM w->worker_task_tail->itask_worker_next = 48638662SJordan.Vaughan@Sun.com w->worker_wait_head; 48647979SSumit.Gupta@Sun.COM w->worker_task_tail = w->worker_wait_tail; 48657979SSumit.Gupta@Sun.COM w->worker_wait_head = w->worker_wait_tail = 48667979SSumit.Gupta@Sun.COM NULL; 48677979SSumit.Gupta@Sun.COM } 48687836SJohn.Forte@Sun.COM } 48697836SJohn.Forte@Sun.COM if ((itask = w->worker_task_head) == NULL) { 48707836SJohn.Forte@Sun.COM break; 48717836SJohn.Forte@Sun.COM } 48727836SJohn.Forte@Sun.COM task = itask->itask_task; 48737836SJohn.Forte@Sun.COM w->worker_task_head = itask->itask_worker_next; 48747836SJohn.Forte@Sun.COM if (w->worker_task_head == NULL) 48757836SJohn.Forte@Sun.COM w->worker_task_tail = NULL; 48767836SJohn.Forte@Sun.COM 48777836SJohn.Forte@Sun.COM wait_queue = 0; 48787836SJohn.Forte@Sun.COM abort_free = 0; 48797836SJohn.Forte@Sun.COM if (itask->itask_ncmds > 0) { 48807836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1]; 48817836SJohn.Forte@Sun.COM } else { 48827836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_BEING_ABORTED); 48837836SJohn.Forte@Sun.COM } 48847836SJohn.Forte@Sun.COM do { 48857836SJohn.Forte@Sun.COM old = itask->itask_flags; 48867836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 48877836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 48887836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[0] = 48897836SJohn.Forte@Sun.COM ITASK_CMD_ABORT; 48907836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 48917836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_MASK) == 48927836SJohn.Forte@Sun.COM ITASK_CMD_NEW_TASK) { 48937836SJohn.Forte@Sun.COM new = old | ITASK_KNOWN_TO_LU; 48947836SJohn.Forte@Sun.COM } else { 48957836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 48967836SJohn.Forte@Sun.COM } 48977836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 48987836SJohn.Forte@Sun.COM 48997836SJohn.Forte@Sun.COM out_itask_flag_loop: 49007836SJohn.Forte@Sun.COM 49017836SJohn.Forte@Sun.COM /* 49027836SJohn.Forte@Sun.COM * Decide if this task needs to go to a queue and/or if 49037836SJohn.Forte@Sun.COM * we can decrement the itask_cmd_stack. 49047836SJohn.Forte@Sun.COM */ 49057836SJohn.Forte@Sun.COM if (curcmd == ITASK_CMD_ABORT) { 49067836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_KNOWN_TO_LU | 49077836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT)) { 49087836SJohn.Forte@Sun.COM wait_queue = 1; 49097836SJohn.Forte@Sun.COM } else { 49107836SJohn.Forte@Sun.COM abort_free = 1; 49117836SJohn.Forte@Sun.COM } 49127836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_POLL) && 49137836SJohn.Forte@Sun.COM (itask->itask_poll_timeout > ddi_get_lbolt())) { 49147836SJohn.Forte@Sun.COM wait_queue = 1; 49157836SJohn.Forte@Sun.COM } 49167836SJohn.Forte@Sun.COM 49177836SJohn.Forte@Sun.COM if (wait_queue) { 49187836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 49197836SJohn.Forte@Sun.COM if (w->worker_wait_tail) { 49207836SJohn.Forte@Sun.COM w->worker_wait_tail->itask_worker_next = itask; 49217836SJohn.Forte@Sun.COM } else { 49227836SJohn.Forte@Sun.COM w->worker_wait_head = itask; 49237836SJohn.Forte@Sun.COM } 49247836SJohn.Forte@Sun.COM w->worker_wait_tail = itask; 49257836SJohn.Forte@Sun.COM if (wait_timer == 0) { 49267836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + wait_ticks; 49277836SJohn.Forte@Sun.COM } 49287836SJohn.Forte@Sun.COM } else if ((--(itask->itask_ncmds)) != 0) { 49297836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 49307836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 49317836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 49327836SJohn.Forte@Sun.COM } else { 49337836SJohn.Forte@Sun.COM w->worker_task_head = itask; 49347836SJohn.Forte@Sun.COM } 49357836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 49367836SJohn.Forte@Sun.COM } else { 49377836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 49387836SJohn.Forte@Sun.COM ~ITASK_IN_WORKER_QUEUE); 49397836SJohn.Forte@Sun.COM /* 49407836SJohn.Forte@Sun.COM * This is where the queue depth should go down by 49417836SJohn.Forte@Sun.COM * one but we delay that on purpose to account for 49427836SJohn.Forte@Sun.COM * the call into the provider. The actual decrement 49437836SJohn.Forte@Sun.COM * happens after the worker has done its job. 49447836SJohn.Forte@Sun.COM */ 49457836SJohn.Forte@Sun.COM dec_qdepth = 1; 49467836SJohn.Forte@Sun.COM } 49477836SJohn.Forte@Sun.COM 49487836SJohn.Forte@Sun.COM /* We made it here means we are going to call LU */ 49497836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) 49507836SJohn.Forte@Sun.COM lu = task->task_lu; 49517836SJohn.Forte@Sun.COM else 49527836SJohn.Forte@Sun.COM lu = dlun0; 49537836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)]; 49547836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 49557836SJohn.Forte@Sun.COM curcmd &= ITASK_CMD_MASK; 49567836SJohn.Forte@Sun.COM switch (curcmd) { 49577836SJohn.Forte@Sun.COM case ITASK_CMD_NEW_TASK: 49587836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 49597836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 49609435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_to_runq); 49619435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_to_runq); 49627836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) { 49637836SJohn.Forte@Sun.COM if (stmf_handle_cmd_during_ic(itask)) 49647836SJohn.Forte@Sun.COM break; 49657836SJohn.Forte@Sun.COM } 49667836SJohn.Forte@Sun.COM #ifdef DEBUG 49677836SJohn.Forte@Sun.COM if (stmf_drop_task_counter > 0) { 49687836SJohn.Forte@Sun.COM if (atomic_add_32_nv( 49697836SJohn.Forte@Sun.COM (uint32_t *)&stmf_drop_task_counter, 49707836SJohn.Forte@Sun.COM -1) == 1) { 49717836SJohn.Forte@Sun.COM break; 49727836SJohn.Forte@Sun.COM } 49737836SJohn.Forte@Sun.COM } 49747836SJohn.Forte@Sun.COM #endif 49758859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task); 49767836SJohn.Forte@Sun.COM lu->lu_new_task(task, dbuf); 49777836SJohn.Forte@Sun.COM break; 49787836SJohn.Forte@Sun.COM case ITASK_CMD_DATA_XFER_DONE: 49797836SJohn.Forte@Sun.COM lu->lu_dbuf_xfer_done(task, dbuf); 49807836SJohn.Forte@Sun.COM break; 49817836SJohn.Forte@Sun.COM case ITASK_CMD_STATUS_DONE: 49827836SJohn.Forte@Sun.COM lu->lu_send_status_done(task); 49837836SJohn.Forte@Sun.COM break; 49847836SJohn.Forte@Sun.COM case ITASK_CMD_ABORT: 49857836SJohn.Forte@Sun.COM if (abort_free) { 49867836SJohn.Forte@Sun.COM stmf_task_free(task); 49877836SJohn.Forte@Sun.COM } else { 49887836SJohn.Forte@Sun.COM stmf_do_task_abort(task); 49897836SJohn.Forte@Sun.COM } 49907836SJohn.Forte@Sun.COM break; 49917836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LU: 49927836SJohn.Forte@Sun.COM if (!wait_queue) { 49937836SJohn.Forte@Sun.COM lu->lu_task_poll(task); 49947836SJohn.Forte@Sun.COM } 49957836SJohn.Forte@Sun.COM break; 49967836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LPORT: 49977836SJohn.Forte@Sun.COM if (!wait_queue) 49987836SJohn.Forte@Sun.COM task->task_lport->lport_task_poll(task); 49997836SJohn.Forte@Sun.COM break; 50007836SJohn.Forte@Sun.COM case ITASK_CMD_SEND_STATUS: 50017836SJohn.Forte@Sun.COM /* case ITASK_CMD_XFER_DATA: */ 50027836SJohn.Forte@Sun.COM break; 50037836SJohn.Forte@Sun.COM } 50047836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 50057836SJohn.Forte@Sun.COM if (dec_qdepth) { 50067836SJohn.Forte@Sun.COM w->worker_queue_depth--; 50077836SJohn.Forte@Sun.COM } 50087836SJohn.Forte@Sun.COM } 50097836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) { 50107836SJohn.Forte@Sun.COM if (w->worker_ref_count == 0) 50117836SJohn.Forte@Sun.COM goto stmf_worker_loop; 50127836SJohn.Forte@Sun.COM else 50137836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + 1; 50147836SJohn.Forte@Sun.COM } 50157836SJohn.Forte@Sun.COM w->worker_flags &= ~STMF_WORKER_ACTIVE; 50167836SJohn.Forte@Sun.COM if (wait_timer) { 50177836SJohn.Forte@Sun.COM (void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer); 50187836SJohn.Forte@Sun.COM } else { 50197836SJohn.Forte@Sun.COM cv_wait(&w->worker_cv, &w->worker_lock); 50207836SJohn.Forte@Sun.COM } 50217836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_ACTIVE; 50227836SJohn.Forte@Sun.COM goto stmf_worker_loop; 50237836SJohn.Forte@Sun.COM } 50247836SJohn.Forte@Sun.COM 50257836SJohn.Forte@Sun.COM void 50267836SJohn.Forte@Sun.COM stmf_worker_mgmt() 50277836SJohn.Forte@Sun.COM { 50287836SJohn.Forte@Sun.COM int i; 50297836SJohn.Forte@Sun.COM int workers_needed; 50307836SJohn.Forte@Sun.COM uint32_t qd; 50317836SJohn.Forte@Sun.COM clock_t tps, d = 0; 50327836SJohn.Forte@Sun.COM uint32_t cur_max_ntasks = 0; 50337836SJohn.Forte@Sun.COM stmf_worker_t *w; 50347836SJohn.Forte@Sun.COM 50357836SJohn.Forte@Sun.COM /* Check if we are trying to increase the # of threads */ 50367836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) { 50377836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) { 50387836SJohn.Forte@Sun.COM stmf_nworkers_cur++; 50397836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds++; 50407836SJohn.Forte@Sun.COM } else { 50417836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 50427836SJohn.Forte@Sun.COM return; 50437836SJohn.Forte@Sun.COM } 50447836SJohn.Forte@Sun.COM } 50457836SJohn.Forte@Sun.COM /* Check if we are trying to decrease the # of workers */ 50467836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 50477836SJohn.Forte@Sun.COM if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) { 50487836SJohn.Forte@Sun.COM stmf_nworkers_cur--; 50497836SJohn.Forte@Sun.COM /* 50507836SJohn.Forte@Sun.COM * stmf_nworkers_accepting_cmds has already been 50517836SJohn.Forte@Sun.COM * updated by the request to reduce the # of workers. 50527836SJohn.Forte@Sun.COM */ 50537836SJohn.Forte@Sun.COM } else { 50547836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 50557836SJohn.Forte@Sun.COM return; 50567836SJohn.Forte@Sun.COM } 50577836SJohn.Forte@Sun.COM } 50587836SJohn.Forte@Sun.COM /* Check if we are being asked to quit */ 50597836SJohn.Forte@Sun.COM if (stmf_workers_state != STMF_WORKERS_ENABLED) { 50607836SJohn.Forte@Sun.COM if (stmf_nworkers_cur) { 50617836SJohn.Forte@Sun.COM workers_needed = 0; 50627836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 50637836SJohn.Forte@Sun.COM } 50647836SJohn.Forte@Sun.COM return; 50657836SJohn.Forte@Sun.COM } 50667836SJohn.Forte@Sun.COM /* Check if we are starting */ 50677836SJohn.Forte@Sun.COM if (stmf_nworkers_cur < stmf_i_min_nworkers) { 50687836SJohn.Forte@Sun.COM workers_needed = stmf_i_min_nworkers; 50697836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 50707836SJohn.Forte@Sun.COM } 50717836SJohn.Forte@Sun.COM 50727836SJohn.Forte@Sun.COM tps = drv_usectohz(1 * 1000 * 1000); 50737836SJohn.Forte@Sun.COM if ((stmf_wm_last != 0) && 50747836SJohn.Forte@Sun.COM ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) { 50757836SJohn.Forte@Sun.COM qd = 0; 50767836SJohn.Forte@Sun.COM for (i = 0; i < stmf_nworkers_accepting_cmds; i++) { 50777836SJohn.Forte@Sun.COM qd += stmf_workers[i].worker_max_qdepth_pu; 50787836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_qdepth_pu = 0; 50797836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_max_sys_qdepth_pu > 50807836SJohn.Forte@Sun.COM cur_max_ntasks) { 50817836SJohn.Forte@Sun.COM cur_max_ntasks = 50827836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu; 50837836SJohn.Forte@Sun.COM } 50847836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu = 0; 50857836SJohn.Forte@Sun.COM } 50867836SJohn.Forte@Sun.COM } 50877836SJohn.Forte@Sun.COM stmf_wm_last = ddi_get_lbolt(); 50887836SJohn.Forte@Sun.COM if (d <= tps) { 50897836SJohn.Forte@Sun.COM /* still ramping up */ 50907836SJohn.Forte@Sun.COM return; 50917836SJohn.Forte@Sun.COM } 50927836SJohn.Forte@Sun.COM /* max qdepth cannot be more than max tasks */ 50937836SJohn.Forte@Sun.COM if (qd > cur_max_ntasks) 50947836SJohn.Forte@Sun.COM qd = cur_max_ntasks; 50957836SJohn.Forte@Sun.COM 50967836SJohn.Forte@Sun.COM /* See if we have more workers */ 50977836SJohn.Forte@Sun.COM if (qd < stmf_nworkers_accepting_cmds) { 50987836SJohn.Forte@Sun.COM /* 50997836SJohn.Forte@Sun.COM * Since we dont reduce the worker count right away, monitor 51007836SJohn.Forte@Sun.COM * the highest load during the scale_down_delay. 51017836SJohn.Forte@Sun.COM */ 51027836SJohn.Forte@Sun.COM if (qd > stmf_worker_scale_down_qd) 51037836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = qd; 51047836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_timer == 0) { 51057836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = ddi_get_lbolt() + 51067836SJohn.Forte@Sun.COM drv_usectohz(stmf_worker_scale_down_delay * 51077836SJohn.Forte@Sun.COM 1000 * 1000); 51087836SJohn.Forte@Sun.COM return; 51097836SJohn.Forte@Sun.COM } 51107836SJohn.Forte@Sun.COM if (ddi_get_lbolt() < stmf_worker_scale_down_timer) { 51117836SJohn.Forte@Sun.COM return; 51127836SJohn.Forte@Sun.COM } 51137836SJohn.Forte@Sun.COM /* Its time to reduce the workers */ 51147836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd < stmf_i_min_nworkers) 51157836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_min_nworkers; 51167836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd > stmf_i_max_nworkers) 51177836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_max_nworkers; 51187836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd == stmf_nworkers_cur) 51197836SJohn.Forte@Sun.COM return; 51207836SJohn.Forte@Sun.COM workers_needed = stmf_worker_scale_down_qd; 51217836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 51227836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 51237836SJohn.Forte@Sun.COM } 51247836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 51257836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = 0; 51267836SJohn.Forte@Sun.COM if (qd > stmf_i_max_nworkers) 51277836SJohn.Forte@Sun.COM qd = stmf_i_max_nworkers; 51287836SJohn.Forte@Sun.COM if (qd < stmf_i_min_nworkers) 51297836SJohn.Forte@Sun.COM qd = stmf_i_min_nworkers; 51307836SJohn.Forte@Sun.COM if (qd == stmf_nworkers_cur) 51317836SJohn.Forte@Sun.COM return; 51327836SJohn.Forte@Sun.COM workers_needed = qd; 51337836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 51347836SJohn.Forte@Sun.COM 51357836SJohn.Forte@Sun.COM /* NOTREACHED */ 51367836SJohn.Forte@Sun.COM return; 51377836SJohn.Forte@Sun.COM 51387836SJohn.Forte@Sun.COM worker_mgmt_trigger_change: 51397836SJohn.Forte@Sun.COM ASSERT(workers_needed != stmf_nworkers_cur); 51407836SJohn.Forte@Sun.COM if (workers_needed > stmf_nworkers_cur) { 51417836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 51427836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < workers_needed; i++) { 51437836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 51447836SJohn.Forte@Sun.COM w->worker_tid = thread_create(NULL, 0, stmf_worker_task, 51457836SJohn.Forte@Sun.COM (void *)&stmf_workers[i], 0, &p0, TS_RUN, 51467836SJohn.Forte@Sun.COM minclsyspri); 51477836SJohn.Forte@Sun.COM } 51487836SJohn.Forte@Sun.COM return; 51497836SJohn.Forte@Sun.COM } 51507836SJohn.Forte@Sun.COM /* At this point we know that we are decreasing the # of workers */ 51517836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds = workers_needed; 51527836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 51537836SJohn.Forte@Sun.COM /* Signal the workers that its time to quit */ 51547836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 51557836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 51567836SJohn.Forte@Sun.COM ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED)); 51577836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 51587836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_TERMINATE; 51597836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 51607836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 51617836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 51627836SJohn.Forte@Sun.COM } 51637836SJohn.Forte@Sun.COM } 51647836SJohn.Forte@Sun.COM 51657836SJohn.Forte@Sun.COM /* 51667836SJohn.Forte@Sun.COM * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private). 51677836SJohn.Forte@Sun.COM * If all the data has been filled out, frees the xd and makes 51687836SJohn.Forte@Sun.COM * db_lu_private NULL. 51697836SJohn.Forte@Sun.COM */ 51707836SJohn.Forte@Sun.COM void 51717836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf) 51727836SJohn.Forte@Sun.COM { 51737836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 51747836SJohn.Forte@Sun.COM uint8_t *p; 51757836SJohn.Forte@Sun.COM int i; 51767836SJohn.Forte@Sun.COM uint32_t s; 51777836SJohn.Forte@Sun.COM 51787836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 51797836SJohn.Forte@Sun.COM dbuf->db_data_size = 0; 51807836SJohn.Forte@Sun.COM dbuf->db_relative_offset = xd->size_done; 51817836SJohn.Forte@Sun.COM for (i = 0; i < dbuf->db_sglist_length; i++) { 51827836SJohn.Forte@Sun.COM s = min(xd->size_left, dbuf->db_sglist[i].seg_length); 51837836SJohn.Forte@Sun.COM p = &xd->buf[xd->size_done]; 51847836SJohn.Forte@Sun.COM bcopy(p, dbuf->db_sglist[i].seg_addr, s); 51857836SJohn.Forte@Sun.COM xd->size_left -= s; 51867836SJohn.Forte@Sun.COM xd->size_done += s; 51877836SJohn.Forte@Sun.COM dbuf->db_data_size += s; 51887836SJohn.Forte@Sun.COM if (xd->size_left == 0) { 51897836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 51907836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 51917836SJohn.Forte@Sun.COM return; 51927836SJohn.Forte@Sun.COM } 51937836SJohn.Forte@Sun.COM } 51947836SJohn.Forte@Sun.COM } 51957836SJohn.Forte@Sun.COM 51967836SJohn.Forte@Sun.COM /* ARGSUSED */ 51977836SJohn.Forte@Sun.COM stmf_status_t 51987836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task) 51997836SJohn.Forte@Sun.COM { 52007836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 52017836SJohn.Forte@Sun.COM } 52027836SJohn.Forte@Sun.COM 52037836SJohn.Forte@Sun.COM void 52047836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 52057836SJohn.Forte@Sun.COM { 52067836SJohn.Forte@Sun.COM uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; 52077836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 52087836SJohn.Forte@Sun.COM uint32_t sz, minsz; 52097836SJohn.Forte@Sun.COM uint8_t *p; 52107836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 52117836SJohn.Forte@Sun.COM uint8_t inq_page_length = 31; 52127836SJohn.Forte@Sun.COM 52137836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 52147836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(task); 52157836SJohn.Forte@Sun.COM return; 52167836SJohn.Forte@Sun.COM } 52177836SJohn.Forte@Sun.COM 52187836SJohn.Forte@Sun.COM switch (cdbp[0]) { 52197836SJohn.Forte@Sun.COM case SCMD_INQUIRY: 52207836SJohn.Forte@Sun.COM /* 52217836SJohn.Forte@Sun.COM * Basic protocol checks. In addition, only reply to 52227836SJohn.Forte@Sun.COM * standard inquiry. Otherwise, the LU provider needs 52237836SJohn.Forte@Sun.COM * to respond. 52247836SJohn.Forte@Sun.COM */ 52257836SJohn.Forte@Sun.COM 52267836SJohn.Forte@Sun.COM if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) { 52277836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 52287836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 52297836SJohn.Forte@Sun.COM return; 52307836SJohn.Forte@Sun.COM } 52317836SJohn.Forte@Sun.COM 52327836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 52337836SJohn.Forte@Sun.COM (((uint32_t)cdbp[3]) << 8) | cdbp[4]; 52347836SJohn.Forte@Sun.COM 52357836SJohn.Forte@Sun.COM if (task->task_additional_flags & 52367836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 52377836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 52387836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 52397836SJohn.Forte@Sun.COM } 52407836SJohn.Forte@Sun.COM 52417836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 52427836SJohn.Forte@Sun.COM min(36, task->task_cmd_xfer_length)); 52437836SJohn.Forte@Sun.COM minsz = 36; 52447836SJohn.Forte@Sun.COM 52457836SJohn.Forte@Sun.COM if (sz == 0) { 52467836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 52477836SJohn.Forte@Sun.COM return; 52487836SJohn.Forte@Sun.COM } 52497836SJohn.Forte@Sun.COM 52507836SJohn.Forte@Sun.COM if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) { 52517836SJohn.Forte@Sun.COM /* 52527836SJohn.Forte@Sun.COM * Ignore any preallocated dbuf if the size is less 52537836SJohn.Forte@Sun.COM * than 36. It will be freed during the task_free. 52547836SJohn.Forte@Sun.COM */ 52557836SJohn.Forte@Sun.COM dbuf = NULL; 52567836SJohn.Forte@Sun.COM } 52577836SJohn.Forte@Sun.COM if (dbuf == NULL) 52587836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0); 52597836SJohn.Forte@Sun.COM if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) { 52607836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 52617836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 52627836SJohn.Forte@Sun.COM return; 52637836SJohn.Forte@Sun.COM } 52647836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 52657836SJohn.Forte@Sun.COM 52667836SJohn.Forte@Sun.COM p = dbuf->db_sglist[0].seg_addr; 52677836SJohn.Forte@Sun.COM 52687836SJohn.Forte@Sun.COM /* 52697836SJohn.Forte@Sun.COM * Standard inquiry handling only. 52707836SJohn.Forte@Sun.COM */ 52717836SJohn.Forte@Sun.COM 52727836SJohn.Forte@Sun.COM bzero(p, inq_page_length + 5); 52737836SJohn.Forte@Sun.COM 52747836SJohn.Forte@Sun.COM p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN; 52757836SJohn.Forte@Sun.COM p[2] = 5; 52767836SJohn.Forte@Sun.COM p[3] = 0x12; 52777836SJohn.Forte@Sun.COM p[4] = inq_page_length; 52787836SJohn.Forte@Sun.COM p[6] = 0x80; 52797836SJohn.Forte@Sun.COM 52807836SJohn.Forte@Sun.COM (void) strncpy((char *)p+8, "SUN ", 8); 52817836SJohn.Forte@Sun.COM (void) strncpy((char *)p+16, "COMSTAR ", 16); 52827836SJohn.Forte@Sun.COM (void) strncpy((char *)p+32, "1.0 ", 4); 52837836SJohn.Forte@Sun.COM 52847836SJohn.Forte@Sun.COM dbuf->db_data_size = sz; 52857836SJohn.Forte@Sun.COM dbuf->db_relative_offset = 0; 52867836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 52877836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 52887836SJohn.Forte@Sun.COM 52897836SJohn.Forte@Sun.COM return; 52907836SJohn.Forte@Sun.COM 52917836SJohn.Forte@Sun.COM case SCMD_REPORT_LUNS: 52927836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 52937836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 52947836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 52957836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 52967836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 52977836SJohn.Forte@Sun.COM 52987836SJohn.Forte@Sun.COM if (task->task_additional_flags & 52997836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 53007836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 53017836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 53027836SJohn.Forte@Sun.COM } 53037836SJohn.Forte@Sun.COM 53047836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 53057836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 53067836SJohn.Forte@Sun.COM 53077836SJohn.Forte@Sun.COM if (sz < 16) { 53087836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 53098662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 53107836SJohn.Forte@Sun.COM return; 53117836SJohn.Forte@Sun.COM } 53127836SJohn.Forte@Sun.COM 53137836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 53147836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 53157836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 53167836SJohn.Forte@Sun.COM xd = stmf_session_prepare_report_lun_data(iss->iss_sm); 53177836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 53187836SJohn.Forte@Sun.COM 53197836SJohn.Forte@Sun.COM if (xd == NULL) { 53207836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53217836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 53227836SJohn.Forte@Sun.COM return; 53237836SJohn.Forte@Sun.COM } 53247836SJohn.Forte@Sun.COM 53257836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 53267836SJohn.Forte@Sun.COM xd->size_left = sz; 53277836SJohn.Forte@Sun.COM minsz = min(512, sz); 53287836SJohn.Forte@Sun.COM 53297836SJohn.Forte@Sun.COM if (dbuf == NULL) 53307836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 53317836SJohn.Forte@Sun.COM if (dbuf == NULL) { 53327836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 53337836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53347836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 53357836SJohn.Forte@Sun.COM return; 53367836SJohn.Forte@Sun.COM } 53377836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 53387836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 53397836SJohn.Forte@Sun.COM 53407836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 53418662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 53427836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 53437836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 53447836SJohn.Forte@Sun.COM return; 53457836SJohn.Forte@Sun.COM } 53467836SJohn.Forte@Sun.COM 53477836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE); 53487836SJohn.Forte@Sun.COM } 53497836SJohn.Forte@Sun.COM 53507836SJohn.Forte@Sun.COM void 53517836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf) 53527836SJohn.Forte@Sun.COM { 53537836SJohn.Forte@Sun.COM if (dbuf->db_xfer_status != STMF_SUCCESS) { 53547836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53557836SJohn.Forte@Sun.COM dbuf->db_xfer_status, NULL); 53567836SJohn.Forte@Sun.COM return; 53577836SJohn.Forte@Sun.COM } 53587836SJohn.Forte@Sun.COM task->task_nbytes_transferred = dbuf->db_data_size; 53597836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 53607836SJohn.Forte@Sun.COM /* There is more */ 53617836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 53627836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 53637836SJohn.Forte@Sun.COM return; 53647836SJohn.Forte@Sun.COM } 53657836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 53667836SJohn.Forte@Sun.COM } 53677836SJohn.Forte@Sun.COM 53687836SJohn.Forte@Sun.COM /* ARGSUSED */ 53697836SJohn.Forte@Sun.COM void 53707836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task) 53717836SJohn.Forte@Sun.COM { 53727836SJohn.Forte@Sun.COM } 53737836SJohn.Forte@Sun.COM 53747836SJohn.Forte@Sun.COM /* ARGSUSED */ 53757836SJohn.Forte@Sun.COM void 53767836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task) 53777836SJohn.Forte@Sun.COM { 53787836SJohn.Forte@Sun.COM } 53797836SJohn.Forte@Sun.COM 53807836SJohn.Forte@Sun.COM /* ARGSUSED */ 53817836SJohn.Forte@Sun.COM stmf_status_t 53827836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags) 53837836SJohn.Forte@Sun.COM { 53847836SJohn.Forte@Sun.COM scsi_task_t *task = (scsi_task_t *)arg; 53857836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 53868662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 53877836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 53887836SJohn.Forte@Sun.COM int i; 53897836SJohn.Forte@Sun.COM uint8_t map; 53907836SJohn.Forte@Sun.COM 53917836SJohn.Forte@Sun.COM ASSERT(abort_cmd == STMF_LU_ABORT_TASK); 53927836SJohn.Forte@Sun.COM if ((task->task_mgmt_function) && (itask->itask_flags & 53937836SJohn.Forte@Sun.COM (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) { 53947836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 53957836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 53967836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 53977836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 53987836SJohn.Forte@Sun.COM case TM_LUN_RESET: 53997836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 54007836SJohn.Forte@Sun.COM break; 54017836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 54027836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 54037836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 54047836SJohn.Forte@Sun.COM stmf_abort_target_reset(task); 54057836SJohn.Forte@Sun.COM break; 54067836SJohn.Forte@Sun.COM } 54077836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 54087836SJohn.Forte@Sun.COM } 54097836SJohn.Forte@Sun.COM 54107836SJohn.Forte@Sun.COM /* 54117836SJohn.Forte@Sun.COM * OK so its not a task mgmt. Make sure we free any xd sitting 54127836SJohn.Forte@Sun.COM * inside any dbuf. 54137836SJohn.Forte@Sun.COM */ 54147836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 54157836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 54167836SJohn.Forte@Sun.COM if ((map & 1) && 54177836SJohn.Forte@Sun.COM ((itask->itask_dbufs[i])->db_lu_private)) { 54187836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 54197836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 54207836SJohn.Forte@Sun.COM 54217836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 54227836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 54237836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 54247836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 54257836SJohn.Forte@Sun.COM } 54267836SJohn.Forte@Sun.COM map >>= 1; 54277836SJohn.Forte@Sun.COM } 54287836SJohn.Forte@Sun.COM } 54297836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 54307836SJohn.Forte@Sun.COM } 54317836SJohn.Forte@Sun.COM 54327836SJohn.Forte@Sun.COM void 54337836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task) 54347836SJohn.Forte@Sun.COM { 54357836SJohn.Forte@Sun.COM /* Right now we only do this for handling task management functions */ 54367836SJohn.Forte@Sun.COM ASSERT(task->task_mgmt_function); 54377836SJohn.Forte@Sun.COM 54387836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 54397836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 54407836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 54417836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 54427836SJohn.Forte@Sun.COM case TM_LUN_RESET: 54437836SJohn.Forte@Sun.COM (void) stmf_lun_reset_poll(task->task_lu, task, 0); 54447836SJohn.Forte@Sun.COM return; 54457836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 54467836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 54477836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 54487836SJohn.Forte@Sun.COM stmf_target_reset_poll(task); 54497836SJohn.Forte@Sun.COM return; 54507836SJohn.Forte@Sun.COM } 54517836SJohn.Forte@Sun.COM } 54527836SJohn.Forte@Sun.COM 54537836SJohn.Forte@Sun.COM /* ARGSUSED */ 54547836SJohn.Forte@Sun.COM void 54557836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg) 54567836SJohn.Forte@Sun.COM { 54577836SJohn.Forte@Sun.COM /* This function will never be called */ 54587836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd); 54597836SJohn.Forte@Sun.COM } 54607836SJohn.Forte@Sun.COM 54617836SJohn.Forte@Sun.COM void 54627836SJohn.Forte@Sun.COM stmf_dlun_init() 54637836SJohn.Forte@Sun.COM { 54647836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 54657836SJohn.Forte@Sun.COM 54667836SJohn.Forte@Sun.COM dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0); 54677836SJohn.Forte@Sun.COM dlun0->lu_task_alloc = stmf_dlun0_task_alloc; 54687836SJohn.Forte@Sun.COM dlun0->lu_new_task = stmf_dlun0_new_task; 54697836SJohn.Forte@Sun.COM dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done; 54707836SJohn.Forte@Sun.COM dlun0->lu_send_status_done = stmf_dlun0_status_done; 54717836SJohn.Forte@Sun.COM dlun0->lu_task_free = stmf_dlun0_task_free; 54727836SJohn.Forte@Sun.COM dlun0->lu_abort = stmf_dlun0_abort; 54737836SJohn.Forte@Sun.COM dlun0->lu_task_poll = stmf_dlun0_task_poll; 54747836SJohn.Forte@Sun.COM dlun0->lu_ctl = stmf_dlun0_ctl; 54757836SJohn.Forte@Sun.COM 54767836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 54777836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 54787836SJohn.Forte@Sun.COM } 54797836SJohn.Forte@Sun.COM 54807836SJohn.Forte@Sun.COM stmf_status_t 54817836SJohn.Forte@Sun.COM stmf_dlun_fini() 54827836SJohn.Forte@Sun.COM { 54837836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 54847836SJohn.Forte@Sun.COM 54857836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 54867836SJohn.Forte@Sun.COM 54877836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 54887836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 54897836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 54907836SJohn.Forte@Sun.COM 54917836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 54927836SJohn.Forte@Sun.COM do { 54937836SJohn.Forte@Sun.COM itask = nitask; 54947836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 54957836SJohn.Forte@Sun.COM dlun0->lu_task_free(itask->itask_task); 54967836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 54977836SJohn.Forte@Sun.COM } while (nitask != NULL); 54987836SJohn.Forte@Sun.COM 54997836SJohn.Forte@Sun.COM } 55007836SJohn.Forte@Sun.COM stmf_free(dlun0); 55017836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55027836SJohn.Forte@Sun.COM } 55037836SJohn.Forte@Sun.COM 55047836SJohn.Forte@Sun.COM void 55057836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task) 55067836SJohn.Forte@Sun.COM { 55077836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 55088662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 55097836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 55107836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 55117836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 55127836SJohn.Forte@Sun.COM int i; 55137836SJohn.Forte@Sun.COM 55147836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 55157836SJohn.Forte@Sun.COM 55167836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 55177836SJohn.Forte@Sun.COM lm = iss->iss_sm; 55187836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 55197836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 55207836SJohn.Forte@Sun.COM continue; 55217836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 55227836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 55237836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 55247836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 55257836SJohn.Forte@Sun.COM } 55267836SJohn.Forte@Sun.COM } 55277836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 55287836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 55297836SJohn.Forte@Sun.COM } 55307836SJohn.Forte@Sun.COM 55317836SJohn.Forte@Sun.COM /* 55327836SJohn.Forte@Sun.COM * The return value is only used by function managing target reset. 55337836SJohn.Forte@Sun.COM */ 55347836SJohn.Forte@Sun.COM stmf_status_t 55357836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset) 55367836SJohn.Forte@Sun.COM { 55377836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 55387836SJohn.Forte@Sun.COM int ntasks_pending; 55397836SJohn.Forte@Sun.COM 55407836SJohn.Forte@Sun.COM ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free; 55417836SJohn.Forte@Sun.COM /* 55427836SJohn.Forte@Sun.COM * This function is also used during Target reset. The idea is that 55437836SJohn.Forte@Sun.COM * once all the commands are aborted, call the LU's reset entry 55447836SJohn.Forte@Sun.COM * point (abort entry point with a reset flag). But if this Task 55457836SJohn.Forte@Sun.COM * mgmt is running on this LU then all the tasks cannot be aborted. 55467836SJohn.Forte@Sun.COM * one task (this task) will still be running which is OK. 55477836SJohn.Forte@Sun.COM */ 55487836SJohn.Forte@Sun.COM if ((ntasks_pending == 0) || ((task->task_lu == lu) && 55497836SJohn.Forte@Sun.COM (ntasks_pending == 1))) { 55507836SJohn.Forte@Sun.COM stmf_status_t ret; 55517836SJohn.Forte@Sun.COM 55527836SJohn.Forte@Sun.COM if ((task->task_mgmt_function == TM_LUN_RESET) || 55537836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_RESET) || 55547836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_WARM_RESET) || 55557836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_COLD_RESET)) { 55567836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0); 55577836SJohn.Forte@Sun.COM } else { 55587836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 55597836SJohn.Forte@Sun.COM } 55607836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 55617836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 55627836SJohn.Forte@Sun.COM } 55637836SJohn.Forte@Sun.COM if (target_reset) { 55647836SJohn.Forte@Sun.COM return (ret); 55657836SJohn.Forte@Sun.COM } 55667836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 55677836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 55687836SJohn.Forte@Sun.COM return (ret); 55697836SJohn.Forte@Sun.COM } 55707836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 55717836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL); 55727836SJohn.Forte@Sun.COM return (ret); 55737836SJohn.Forte@Sun.COM } 55747836SJohn.Forte@Sun.COM } 55757836SJohn.Forte@Sun.COM 55767836SJohn.Forte@Sun.COM if (target_reset) { 55777836SJohn.Forte@Sun.COM /* Tell target reset polling code that we are not done */ 55787836SJohn.Forte@Sun.COM return (STMF_BUSY); 55797836SJohn.Forte@Sun.COM } 55807836SJohn.Forte@Sun.COM 55817836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 55827836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 55837836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 55847836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 55857836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55867836SJohn.Forte@Sun.COM } 55877836SJohn.Forte@Sun.COM 55887836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55897836SJohn.Forte@Sun.COM } 55907836SJohn.Forte@Sun.COM 55917836SJohn.Forte@Sun.COM void 55927836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task) 55937836SJohn.Forte@Sun.COM { 55947836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 55958662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 55967836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 55977836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 55987836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 55997836SJohn.Forte@Sun.COM stmf_status_t ret; 56007836SJohn.Forte@Sun.COM int i; 56017836SJohn.Forte@Sun.COM int not_done = 0; 56027836SJohn.Forte@Sun.COM 56037836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 56047836SJohn.Forte@Sun.COM 56057836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 56067836SJohn.Forte@Sun.COM lm = iss->iss_sm; 56077836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 56087836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 56097836SJohn.Forte@Sun.COM continue; 56107836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 56117836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 56127836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 56137836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56147836SJohn.Forte@Sun.COM ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1); 56157836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 56167836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) 56177836SJohn.Forte@Sun.COM continue; 56187836SJohn.Forte@Sun.COM not_done = 1; 56197836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 56207836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56217836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 56227836SJohn.Forte@Sun.COM STMF_ABORTED, NULL); 56237836SJohn.Forte@Sun.COM return; 56247836SJohn.Forte@Sun.COM } 56257836SJohn.Forte@Sun.COM } 56267836SJohn.Forte@Sun.COM } 56277836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56287836SJohn.Forte@Sun.COM 56297836SJohn.Forte@Sun.COM if (not_done) { 56307836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 56317836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 56327836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 56337836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 56347836SJohn.Forte@Sun.COM return; 56357836SJohn.Forte@Sun.COM } 56367836SJohn.Forte@Sun.COM return; 56377836SJohn.Forte@Sun.COM } 56387836SJohn.Forte@Sun.COM 56397836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 56407836SJohn.Forte@Sun.COM 56417836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 56427836SJohn.Forte@Sun.COM } 56437836SJohn.Forte@Sun.COM 56447836SJohn.Forte@Sun.COM stmf_status_t 56457836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid) 56467836SJohn.Forte@Sun.COM { 56477836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 56487836SJohn.Forte@Sun.COM 56497836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56507836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56517836SJohn.Forte@Sun.COM } 56527836SJohn.Forte@Sun.COM 56537836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid); 56547836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56557836SJohn.Forte@Sun.COM } 56567836SJohn.Forte@Sun.COM 56577836SJohn.Forte@Sun.COM stmf_status_t 56587836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid) 56597836SJohn.Forte@Sun.COM { 56607836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 56617836SJohn.Forte@Sun.COM 56627836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 56637836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl); 56647836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56657836SJohn.Forte@Sun.COM } 56667836SJohn.Forte@Sun.COM 56677836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56687836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56697836SJohn.Forte@Sun.COM } 56707836SJohn.Forte@Sun.COM 56717836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid); 56727836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56737836SJohn.Forte@Sun.COM } 56747836SJohn.Forte@Sun.COM 56757836SJohn.Forte@Sun.COM stmf_status_t 56767836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid) 56777836SJohn.Forte@Sun.COM { 56787836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 56798662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 56807836SJohn.Forte@Sun.COM 56817836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56827836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56837836SJohn.Forte@Sun.COM } 56847836SJohn.Forte@Sun.COM 56857836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid); 56867836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56877836SJohn.Forte@Sun.COM } 56887836SJohn.Forte@Sun.COM 56897836SJohn.Forte@Sun.COM stmf_status_t 56907836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid) 56917836SJohn.Forte@Sun.COM { 56927836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 56938662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 56947836SJohn.Forte@Sun.COM 56957836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 56967836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl); 56977836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56987836SJohn.Forte@Sun.COM } 56997836SJohn.Forte@Sun.COM 57007836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 57017836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 57027836SJohn.Forte@Sun.COM } 57037836SJohn.Forte@Sun.COM 57047836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid); 57057836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57067836SJohn.Forte@Sun.COM } 57077836SJohn.Forte@Sun.COM 57087836SJohn.Forte@Sun.COM void 57097836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags) 57107836SJohn.Forte@Sun.COM { 57117836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) && 57127836SJohn.Forte@Sun.COM (ilu->ilu_lu->lu_event_handler != NULL)) { 57137836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags); 57147836SJohn.Forte@Sun.COM } 57157836SJohn.Forte@Sun.COM } 57167836SJohn.Forte@Sun.COM 57177836SJohn.Forte@Sun.COM void 57187836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg, 57197836SJohn.Forte@Sun.COM uint32_t flags) 57207836SJohn.Forte@Sun.COM { 57217836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) && 57227836SJohn.Forte@Sun.COM (ilport->ilport_lport->lport_event_handler != NULL)) { 57237836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_event_handler( 57247836SJohn.Forte@Sun.COM ilport->ilport_lport, eventid, arg, flags); 57257836SJohn.Forte@Sun.COM } 57267836SJohn.Forte@Sun.COM } 57277836SJohn.Forte@Sun.COM 57287836SJohn.Forte@Sun.COM void 57297836SJohn.Forte@Sun.COM stmf_svc_init() 57307836SJohn.Forte@Sun.COM { 57317836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 57327836SJohn.Forte@Sun.COM return; 57337836SJohn.Forte@Sun.COM stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1, 57347836SJohn.Forte@Sun.COM TASKQ_DEFAULTPRI, 0); 57357836SJohn.Forte@Sun.COM (void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq, 57367836SJohn.Forte@Sun.COM stmf_svc, 0, DDI_SLEEP); 57377836SJohn.Forte@Sun.COM } 57387836SJohn.Forte@Sun.COM 57397836SJohn.Forte@Sun.COM stmf_status_t 57407836SJohn.Forte@Sun.COM stmf_svc_fini() 57417836SJohn.Forte@Sun.COM { 57427836SJohn.Forte@Sun.COM uint32_t i; 57437836SJohn.Forte@Sun.COM 57447836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 57457836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) { 57467836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE; 57477836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 57487836SJohn.Forte@Sun.COM } 57497836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 57507836SJohn.Forte@Sun.COM 57517836SJohn.Forte@Sun.COM /* Wait for 5 seconds */ 57527836SJohn.Forte@Sun.COM for (i = 0; i < 500; i++) { 57537836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 57547836SJohn.Forte@Sun.COM delay(drv_usectohz(10000)); 57557836SJohn.Forte@Sun.COM else 57567836SJohn.Forte@Sun.COM break; 57577836SJohn.Forte@Sun.COM } 57587836SJohn.Forte@Sun.COM if (i == 500) 57597836SJohn.Forte@Sun.COM return (STMF_BUSY); 57607836SJohn.Forte@Sun.COM 57617836SJohn.Forte@Sun.COM ddi_taskq_destroy(stmf_state.stmf_svc_taskq); 57627836SJohn.Forte@Sun.COM 57637836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57647836SJohn.Forte@Sun.COM } 57657836SJohn.Forte@Sun.COM 57667836SJohn.Forte@Sun.COM /* ARGSUSED */ 57677836SJohn.Forte@Sun.COM void 57687836SJohn.Forte@Sun.COM stmf_svc(void *arg) 57697836SJohn.Forte@Sun.COM { 57707836SJohn.Forte@Sun.COM stmf_svc_req_t *req, **preq; 57717836SJohn.Forte@Sun.COM clock_t td; 57727836SJohn.Forte@Sun.COM clock_t drain_start, drain_next = 0; 57737836SJohn.Forte@Sun.COM clock_t timing_start, timing_next = 0; 57747836SJohn.Forte@Sun.COM clock_t worker_delay = 0; 57757836SJohn.Forte@Sun.COM int deq; 57767836SJohn.Forte@Sun.COM stmf_lu_t *lu; 57777836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 57787836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 57797836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport, *next_ilport; 57807836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 57817836SJohn.Forte@Sun.COM 57827836SJohn.Forte@Sun.COM td = drv_usectohz(20000); 57837836SJohn.Forte@Sun.COM 57847836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 57857836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE; 57867836SJohn.Forte@Sun.COM 57877836SJohn.Forte@Sun.COM stmf_svc_loop: 57887836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) { 57897836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= 57907836SJohn.Forte@Sun.COM ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE); 57917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 57927836SJohn.Forte@Sun.COM return; 57937836SJohn.Forte@Sun.COM } 57947836SJohn.Forte@Sun.COM 57957836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) { 57967836SJohn.Forte@Sun.COM int waitq_add = 0; 57977836SJohn.Forte@Sun.COM req = stmf_state.stmf_svc_active; 57987836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req->svc_next; 57997836SJohn.Forte@Sun.COM 58007836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 58017836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 58027836SJohn.Forte@Sun.COM /* Fallthrough */ 58037836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 58047836SJohn.Forte@Sun.COM /* Fallthrough */ 58057836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 58067836SJohn.Forte@Sun.COM /* Nothing to do */ 58077836SJohn.Forte@Sun.COM waitq_add = 1; 58087836SJohn.Forte@Sun.COM break; 58097836SJohn.Forte@Sun.COM 58107836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 58117836SJohn.Forte@Sun.COM /* Remove all mappings of this LU */ 58127836SJohn.Forte@Sun.COM stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj); 58137836SJohn.Forte@Sun.COM /* Kill all the pending I/Os for this LU */ 58147836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 58157836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL, 58168662SJordan.Vaughan@Sun.com STMF_ABORTED); 58177836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 58187836SJohn.Forte@Sun.COM waitq_add = 1; 58197836SJohn.Forte@Sun.COM break; 58207836SJohn.Forte@Sun.COM default: 58217836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d", 58227836SJohn.Forte@Sun.COM req->svc_cmd); 58237836SJohn.Forte@Sun.COM } 58247836SJohn.Forte@Sun.COM 58257836SJohn.Forte@Sun.COM if (waitq_add) { 58267836SJohn.Forte@Sun.COM /* Put it in the wait queue */ 58277836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_waiting; 58287836SJohn.Forte@Sun.COM stmf_state.stmf_svc_waiting = req; 58297836SJohn.Forte@Sun.COM } 58307836SJohn.Forte@Sun.COM } 58317836SJohn.Forte@Sun.COM 58327836SJohn.Forte@Sun.COM /* The waiting list is not going to be modified by anybody else */ 58337836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 58347836SJohn.Forte@Sun.COM 58357836SJohn.Forte@Sun.COM for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) { 58367836SJohn.Forte@Sun.COM req = *preq; 58377836SJohn.Forte@Sun.COM deq = 0; 58387836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 58397836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 58407836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 58417836SJohn.Forte@Sun.COM deq = 1; 58427836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 58437836SJohn.Forte@Sun.COM break; 58447836SJohn.Forte@Sun.COM 58457836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 58467836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 58477836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 58487836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks != ilu->ilu_ntasks_free) 58497836SJohn.Forte@Sun.COM break; 58507836SJohn.Forte@Sun.COM deq = 1; 58517836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 58527836SJohn.Forte@Sun.COM break; 58537836SJohn.Forte@Sun.COM 58547836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 58557836SJohn.Forte@Sun.COM /* Fallthrough */ 58567836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 58577836SJohn.Forte@Sun.COM lport = (stmf_local_port_t *)req->svc_obj; 58587836SJohn.Forte@Sun.COM deq = 1; 58597836SJohn.Forte@Sun.COM lport->lport_ctl(lport, req->svc_cmd, &req->svc_info); 58607836SJohn.Forte@Sun.COM break; 58617836SJohn.Forte@Sun.COM } 58627836SJohn.Forte@Sun.COM if (deq) { 58637836SJohn.Forte@Sun.COM *preq = req->svc_next; 58647836SJohn.Forte@Sun.COM kmem_free(req, req->svc_req_alloc_size); 58657836SJohn.Forte@Sun.COM } else { 58667836SJohn.Forte@Sun.COM preq = &req->svc_next; 58677836SJohn.Forte@Sun.COM } 58687836SJohn.Forte@Sun.COM } 58697836SJohn.Forte@Sun.COM 58707836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 58717836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active == NULL) { 58727836SJohn.Forte@Sun.COM /* Do timeouts */ 58737836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 58747836SJohn.Forte@Sun.COM ((!timing_next) || (ddi_get_lbolt() >= timing_next))) { 58757836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 58767836SJohn.Forte@Sun.COM /* we are starting a new round */ 58777836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = 58787836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 58797836SJohn.Forte@Sun.COM timing_start = ddi_get_lbolt(); 58807836SJohn.Forte@Sun.COM } 58817836SJohn.Forte@Sun.COM stmf_check_ilu_timing(); 58827836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 58837836SJohn.Forte@Sun.COM /* we finished a complete round */ 58847836SJohn.Forte@Sun.COM timing_next = 58857836SJohn.Forte@Sun.COM timing_start + drv_usectohz(5*1000*1000); 58867836SJohn.Forte@Sun.COM } else { 58877836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 58887836SJohn.Forte@Sun.COM timing_next = 58897836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 58907836SJohn.Forte@Sun.COM } 58917836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 58927836SJohn.Forte@Sun.COM goto stmf_svc_loop; 58937836SJohn.Forte@Sun.COM } 58947836SJohn.Forte@Sun.COM /* Check if there are free tasks to clear */ 58957836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 58967836SJohn.Forte@Sun.COM ((!drain_next) || (ddi_get_lbolt() >= drain_next))) { 58977836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 58987836SJohn.Forte@Sun.COM /* we are starting a new round */ 58997836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = 59007836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 59017836SJohn.Forte@Sun.COM drain_start = ddi_get_lbolt(); 59027836SJohn.Forte@Sun.COM } 59037836SJohn.Forte@Sun.COM stmf_check_freetask(); 59047836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 59057836SJohn.Forte@Sun.COM /* we finished a complete round */ 59067836SJohn.Forte@Sun.COM drain_next = 59077836SJohn.Forte@Sun.COM drain_start + drv_usectohz(10*1000*1000); 59087836SJohn.Forte@Sun.COM } else { 59097836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 59107836SJohn.Forte@Sun.COM drain_next = 59117836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 59127836SJohn.Forte@Sun.COM } 59137836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 59147836SJohn.Forte@Sun.COM goto stmf_svc_loop; 59157836SJohn.Forte@Sun.COM } 59167836SJohn.Forte@Sun.COM 59177836SJohn.Forte@Sun.COM /* Check if we need to run worker_mgmt */ 59187836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > worker_delay) { 59197836SJohn.Forte@Sun.COM stmf_worker_mgmt(); 59207836SJohn.Forte@Sun.COM worker_delay = ddi_get_lbolt() + 59217836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay; 59227836SJohn.Forte@Sun.COM } 59237836SJohn.Forte@Sun.COM 59247836SJohn.Forte@Sun.COM /* Check if any active session got its 1st LUN */ 59257836SJohn.Forte@Sun.COM if (stmf_state.stmf_process_initial_luns) { 59267836SJohn.Forte@Sun.COM int stmf_level = 0; 59277836SJohn.Forte@Sun.COM int port_level; 59287836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 59297836SJohn.Forte@Sun.COM ilport = next_ilport) { 59307836SJohn.Forte@Sun.COM next_ilport = ilport->ilport_next; 59317836SJohn.Forte@Sun.COM if ((ilport->ilport_flags & 59327836SJohn.Forte@Sun.COM ILPORT_SS_GOT_INITIAL_LUNS) == 0) { 59337836SJohn.Forte@Sun.COM continue; 59347836SJohn.Forte@Sun.COM } 59357836SJohn.Forte@Sun.COM port_level = 0; 59367836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_READER); 59377836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss; 59387836SJohn.Forte@Sun.COM iss = iss->iss_next) { 59397836SJohn.Forte@Sun.COM if ((iss->iss_flags & 59407836SJohn.Forte@Sun.COM ISS_GOT_INITIAL_LUNS) == 0) { 59417836SJohn.Forte@Sun.COM continue; 59427836SJohn.Forte@Sun.COM } 59437836SJohn.Forte@Sun.COM port_level++; 59447836SJohn.Forte@Sun.COM stmf_level++; 59457836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 59468662SJordan.Vaughan@Sun.com ~ISS_GOT_INITIAL_LUNS); 59477836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, 59488662SJordan.Vaughan@Sun.com ISS_EVENT_ACTIVE); 59497836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 59507836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 59517836SJohn.Forte@Sun.COM stmf_generate_lport_event(ilport, 59527836SJohn.Forte@Sun.COM LPORT_EVENT_INITIAL_LUN_MAPPED, 59537836SJohn.Forte@Sun.COM iss->iss_ss, 0); 59547836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 59558662SJordan.Vaughan@Sun.com ~ISS_EVENT_ACTIVE); 59567836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 59577836SJohn.Forte@Sun.COM /* 59587836SJohn.Forte@Sun.COM * scan all the ilports again as the 59597836SJohn.Forte@Sun.COM * ilport list might have changed. 59607836SJohn.Forte@Sun.COM */ 59617836SJohn.Forte@Sun.COM next_ilport = 59628662SJordan.Vaughan@Sun.com stmf_state.stmf_ilportlist; 59637836SJohn.Forte@Sun.COM break; 59647836SJohn.Forte@Sun.COM } 59657836SJohn.Forte@Sun.COM if (port_level == 0) { 59667836SJohn.Forte@Sun.COM atomic_and_32(&ilport->ilport_flags, 59678662SJordan.Vaughan@Sun.com ~ILPORT_SS_GOT_INITIAL_LUNS); 59687836SJohn.Forte@Sun.COM } 59697836SJohn.Forte@Sun.COM /* drop the lock if we are holding it. */ 59707836SJohn.Forte@Sun.COM if (rw_lock_held(&ilport->ilport_lock)) 59717836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 59727836SJohn.Forte@Sun.COM 59737836SJohn.Forte@Sun.COM /* Max 4 session at a time */ 59747836SJohn.Forte@Sun.COM if (stmf_level >= 4) { 59757836SJohn.Forte@Sun.COM break; 59767836SJohn.Forte@Sun.COM } 59777836SJohn.Forte@Sun.COM } 59787836SJohn.Forte@Sun.COM if (stmf_level == 0) { 59797836SJohn.Forte@Sun.COM stmf_state.stmf_process_initial_luns = 0; 59807836SJohn.Forte@Sun.COM } 59817836SJohn.Forte@Sun.COM } 59827836SJohn.Forte@Sun.COM 59837836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE; 59847836SJohn.Forte@Sun.COM (void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock, 59857836SJohn.Forte@Sun.COM ddi_get_lbolt() + td); 59867836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE; 59877836SJohn.Forte@Sun.COM } 59887836SJohn.Forte@Sun.COM goto stmf_svc_loop; 59897836SJohn.Forte@Sun.COM } 59907836SJohn.Forte@Sun.COM 59917836SJohn.Forte@Sun.COM void 59927836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info) 59937836SJohn.Forte@Sun.COM { 59947836SJohn.Forte@Sun.COM stmf_svc_req_t *req; 59957836SJohn.Forte@Sun.COM int s; 59967836SJohn.Forte@Sun.COM 59977836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&stmf_state.stmf_lock)); 59987836SJohn.Forte@Sun.COM s = sizeof (stmf_svc_req_t); 59997836SJohn.Forte@Sun.COM if (info->st_additional_info) { 60007836SJohn.Forte@Sun.COM s += strlen(info->st_additional_info) + 1; 60017836SJohn.Forte@Sun.COM } 60027836SJohn.Forte@Sun.COM req = kmem_zalloc(s, KM_SLEEP); 60037836SJohn.Forte@Sun.COM 60047836SJohn.Forte@Sun.COM req->svc_cmd = cmd; 60057836SJohn.Forte@Sun.COM req->svc_obj = obj; 60067836SJohn.Forte@Sun.COM req->svc_info.st_rflags = info->st_rflags; 60077836SJohn.Forte@Sun.COM if (info->st_additional_info) { 60087836SJohn.Forte@Sun.COM req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req, 60097836SJohn.Forte@Sun.COM sizeof (stmf_svc_req_t))); 60107836SJohn.Forte@Sun.COM (void) strcpy(req->svc_info.st_additional_info, 60117836SJohn.Forte@Sun.COM info->st_additional_info); 60127836SJohn.Forte@Sun.COM } 60137836SJohn.Forte@Sun.COM req->svc_req_alloc_size = s; 60147836SJohn.Forte@Sun.COM 60157836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 60167836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_active; 60177836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req; 60187836SJohn.Forte@Sun.COM if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) { 60197836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 60207836SJohn.Forte@Sun.COM } 60217836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 60227836SJohn.Forte@Sun.COM } 60237836SJohn.Forte@Sun.COM 60247836SJohn.Forte@Sun.COM void 60257836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...) 60267836SJohn.Forte@Sun.COM { 60277836SJohn.Forte@Sun.COM va_list args; 60287836SJohn.Forte@Sun.COM char tbuf[160]; 60297836SJohn.Forte@Sun.COM int len; 60307836SJohn.Forte@Sun.COM 60317836SJohn.Forte@Sun.COM if (!stmf_trace_on) 60327836SJohn.Forte@Sun.COM return; 60337836SJohn.Forte@Sun.COM len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "", 60347836SJohn.Forte@Sun.COM ddi_get_lbolt()); 60357836SJohn.Forte@Sun.COM va_start(args, fmt); 60367836SJohn.Forte@Sun.COM len += vsnprintf(tbuf + len, 158 - len, fmt, args); 60377836SJohn.Forte@Sun.COM va_end(args); 60387836SJohn.Forte@Sun.COM 60397836SJohn.Forte@Sun.COM if (len > 158) { 60407836SJohn.Forte@Sun.COM len = 158; 60417836SJohn.Forte@Sun.COM } 60427836SJohn.Forte@Sun.COM tbuf[len++] = '\n'; 60437836SJohn.Forte@Sun.COM tbuf[len] = 0; 60447836SJohn.Forte@Sun.COM 60457836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 60467836SJohn.Forte@Sun.COM bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1); 60477836SJohn.Forte@Sun.COM trace_buf_curndx += len; 60487836SJohn.Forte@Sun.COM if (trace_buf_curndx > (trace_buf_size - 320)) 60497836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 60507836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 60517836SJohn.Forte@Sun.COM } 60527836SJohn.Forte@Sun.COM 60537836SJohn.Forte@Sun.COM void 60547836SJohn.Forte@Sun.COM stmf_trace_clear() 60557836SJohn.Forte@Sun.COM { 60567836SJohn.Forte@Sun.COM if (!stmf_trace_on) 60577836SJohn.Forte@Sun.COM return; 60587836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 60597836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 60607836SJohn.Forte@Sun.COM if (trace_buf_size > 0) 60617836SJohn.Forte@Sun.COM stmf_trace_buf[0] = 0; 60627836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 60637836SJohn.Forte@Sun.COM } 60647836SJohn.Forte@Sun.COM 60657836SJohn.Forte@Sun.COM static void 60667836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info) 60677836SJohn.Forte@Sun.COM { 60687836SJohn.Forte@Sun.COM stmf_state_change_info_t change_info; 60697836SJohn.Forte@Sun.COM void *ctl_private; 60707836SJohn.Forte@Sun.COM uint32_t ctl_cmd; 60717836SJohn.Forte@Sun.COM int msg = 0; 60727836SJohn.Forte@Sun.COM 60737836SJohn.Forte@Sun.COM stmf_trace("FROM STMF", "abort_task_offline called for %s: %s", 60747836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : "no additional info"); 60757836SJohn.Forte@Sun.COM change_info.st_additional_info = info; 60767836SJohn.Forte@Sun.COM if (offline_lu) { 60777836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 60787836SJohn.Forte@Sun.COM STMF_RFLAG_LU_ABORT; 60797836SJohn.Forte@Sun.COM ctl_private = task->task_lu; 60807836SJohn.Forte@Sun.COM if (((stmf_i_lu_t *) 60817836SJohn.Forte@Sun.COM task->task_lu->lu_stmf_private)->ilu_state == 60827836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 60837836SJohn.Forte@Sun.COM msg = 1; 60847836SJohn.Forte@Sun.COM } 60857836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LU_OFFLINE; 60867836SJohn.Forte@Sun.COM } else { 60877836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 60887836SJohn.Forte@Sun.COM STMF_RFLAG_LPORT_ABORT; 60897836SJohn.Forte@Sun.COM ctl_private = task->task_lport; 60907836SJohn.Forte@Sun.COM if (((stmf_i_local_port_t *) 60917836SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private)->ilport_state == 60927836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 60937836SJohn.Forte@Sun.COM msg = 1; 60947836SJohn.Forte@Sun.COM } 60957836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LPORT_OFFLINE; 60967836SJohn.Forte@Sun.COM } 60977836SJohn.Forte@Sun.COM 60987836SJohn.Forte@Sun.COM if (msg) { 60997836SJohn.Forte@Sun.COM stmf_trace(0, "Calling stmf_ctl to offline %s : %s", 61007836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : 61017836SJohn.Forte@Sun.COM "<no additional info>"); 61027836SJohn.Forte@Sun.COM } 61037836SJohn.Forte@Sun.COM (void) stmf_ctl(ctl_cmd, ctl_private, &change_info); 61047836SJohn.Forte@Sun.COM } 6105