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); 76*9585STim.Szeto@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 77*9585STim.Szeto@Sun.COM uint32_t *err_ret); 787836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi); 79*9585STim.Szeto@Sun.COM int stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 80*9585STim.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: 288*9585STim.Szeto@Sun.COM *result = 289*9585STim.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; 440*9585STim.Szeto@Sun.COM stmf_ppioctl_data_t *ppi, *ppi_out = NULL; 441*9585STim.Szeto@Sun.COM uint64_t *ppi_token = NULL; 442*9585STim.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: 473*9585STim.Szeto@Sun.COM /* retrieves both registered/unregistered */ 474*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 475*9585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 476*9585STim.Szeto@Sun.COM n = min(id_list->id_count, 477*9585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 478*9585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 479*9585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 480*9585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 481*9585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 482*9585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 483*9585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 484*9585STim.Szeto@Sun.COM } 485*9585STim.Szeto@Sun.COM 486*9585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (slist_lu_t); 487*9585STim.Szeto@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 488*9585STim.Szeto@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 489*9585STim.Szeto@Sun.COM if (stmf_lookup_id(id_list, 16, id + 4) == NULL) { 490*9585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 491*9585STim.Szeto@Sun.COM if (i < n) { 492*9585STim.Szeto@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 493*9585STim.Szeto@Sun.COM sizeof (slist_lu_t)); 494*9585STim.Szeto@Sun.COM i++; 495*9585STim.Szeto@Sun.COM } 496*9585STim.Szeto@Sun.COM } 497*9585STim.Szeto@Sun.COM } 498*9585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = i; 499*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 500*9585STim.Szeto@Sun.COM break; 501*9585STim.Szeto@Sun.COM 502*9585STim.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 519*9585STim.Szeto@Sun.COM case STMF_IOCTL_VE_LU_LIST: 520*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 521*9585STim.Szeto@Sun.COM id_list = &stmf_state.stmf_luid_list; 522*9585STim.Szeto@Sun.COM n = min(id_list->id_count, 523*9585STim.Szeto@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 524*9585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 525*9585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries = n; 526*9585STim.Szeto@Sun.COM luid_list = (slist_lu_t *)obuf; 527*9585STim.Szeto@Sun.COM id_entry = id_list->idl_head; 528*9585STim.Szeto@Sun.COM for (i = 0; i < n; i++) { 529*9585STim.Szeto@Sun.COM bcopy(id_entry->id_data, luid_list[i].lu_guid, 16); 530*9585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 531*9585STim.Szeto@Sun.COM } 532*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 533*9585STim.Szeto@Sun.COM break; 534*9585STim.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 if (idtype == STMF_ID_TYPE_TARGET && 7997836SJohn.Forte@Sun.COM stmf_state.stmf_service_running) { 8007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8017836SJohn.Forte@Sun.COM iocd->stmf_error = 8027836SJohn.Forte@Sun.COM STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE; 8037836SJohn.Forte@Sun.COM ret = EBUSY; 8047836SJohn.Forte@Sun.COM break; /* not allowed */ 8057836SJohn.Forte@Sun.COM } 8067836SJohn.Forte@Sun.COM ret = stmf_add_group_member(grp_entry->group.name, 8077836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8087836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8097836SJohn.Forte@Sun.COM grp_entry->ident[3], 8107836SJohn.Forte@Sun.COM idtype, 8117836SJohn.Forte@Sun.COM &iocd->stmf_error); 8127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8137836SJohn.Forte@Sun.COM break; 8147836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HG_ENTRY: 8157836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 8167836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8177836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TG_ENTRY: 8187836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8197836SJohn.Forte@Sun.COM ret = EACCES; 8207836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8217836SJohn.Forte@Sun.COM break; 8227836SJohn.Forte@Sun.COM } 8237836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) { 8247836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 8257836SJohn.Forte@Sun.COM } 8267836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 8277836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8287836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 8297836SJohn.Forte@Sun.COM ret = EINVAL; 8307836SJohn.Forte@Sun.COM break; 8317836SJohn.Forte@Sun.COM } 8327836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 8337836SJohn.Forte@Sun.COM ret = EINVAL; 8347836SJohn.Forte@Sun.COM break; /* not allowed */ 8357836SJohn.Forte@Sun.COM } 8367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8377836SJohn.Forte@Sun.COM if (idtype == STMF_ID_TYPE_TARGET && 8387836SJohn.Forte@Sun.COM stmf_state.stmf_service_running) { 8397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8407836SJohn.Forte@Sun.COM iocd->stmf_error = 8417836SJohn.Forte@Sun.COM STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE; 8427836SJohn.Forte@Sun.COM ret = EBUSY; 8437836SJohn.Forte@Sun.COM break; /* not allowed */ 8447836SJohn.Forte@Sun.COM } 8457836SJohn.Forte@Sun.COM ret = stmf_remove_group_member(grp_entry->group.name, 8467836SJohn.Forte@Sun.COM grp_entry->group.name_size, 8477836SJohn.Forte@Sun.COM grp_entry->ident + 4, 8487836SJohn.Forte@Sun.COM grp_entry->ident[3], 8497836SJohn.Forte@Sun.COM idtype, 8507836SJohn.Forte@Sun.COM &iocd->stmf_error); 8517836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8527836SJohn.Forte@Sun.COM break; 8537836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_HOST_GROUP: 8547836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8557836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8567836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_TARGET_GROUP: 8577836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8587836SJohn.Forte@Sun.COM ret = EACCES; 8597836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8607836SJohn.Forte@Sun.COM break; 8617836SJohn.Forte@Sun.COM } 8627836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8637836SJohn.Forte@Sun.COM 8647836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP) 8657836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8667836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8677836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8687836SJohn.Forte@Sun.COM ret = EINVAL; 8697836SJohn.Forte@Sun.COM break; 8707836SJohn.Forte@Sun.COM } 8717836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8727836SJohn.Forte@Sun.COM ret = EINVAL; 8737836SJohn.Forte@Sun.COM break; /* not allowed */ 8747836SJohn.Forte@Sun.COM } 8757836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8767836SJohn.Forte@Sun.COM ret = stmf_add_group(grpname->name, 8777836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 8787836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8797836SJohn.Forte@Sun.COM break; 8807836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HOST_GROUP: 8817836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8827836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8837836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TARGET_GROUP: 8847836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8857836SJohn.Forte@Sun.COM ret = EACCES; 8867836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8877836SJohn.Forte@Sun.COM break; 8887836SJohn.Forte@Sun.COM } 8897836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8907836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP) 8917836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8927836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8937836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8947836SJohn.Forte@Sun.COM ret = EINVAL; 8957836SJohn.Forte@Sun.COM break; 8967836SJohn.Forte@Sun.COM } 8977836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8987836SJohn.Forte@Sun.COM ret = EINVAL; 8997836SJohn.Forte@Sun.COM break; /* not allowed */ 9007836SJohn.Forte@Sun.COM } 9017836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9027836SJohn.Forte@Sun.COM ret = stmf_remove_group(grpname->name, 9037836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 9047836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9057836SJohn.Forte@Sun.COM break; 9067836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_VIEW_ENTRY: 9077836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9087836SJohn.Forte@Sun.COM ret = EACCES; 9097836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9107836SJohn.Forte@Sun.COM break; 9117836SJohn.Forte@Sun.COM } 9127836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 9137836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9147836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 9157836SJohn.Forte@Sun.COM ret = EINVAL; 9167836SJohn.Forte@Sun.COM break; 9177836SJohn.Forte@Sun.COM } 9187836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) 9197836SJohn.Forte@Sun.COM ve->ve_lu_nbr[2] = 0xFF; 9207836SJohn.Forte@Sun.COM if (ve->ve_all_hosts) { 9217836SJohn.Forte@Sun.COM ve->ve_host_group.name[0] = '*'; 9227836SJohn.Forte@Sun.COM ve->ve_host_group.name_size = 1; 9237836SJohn.Forte@Sun.COM } 9247836SJohn.Forte@Sun.COM if (ve->ve_all_targets) { 9257836SJohn.Forte@Sun.COM ve->ve_target_group.name[0] = '*'; 9267836SJohn.Forte@Sun.COM ve->ve_target_group.name_size = 1; 9277836SJohn.Forte@Sun.COM } 9287836SJohn.Forte@Sun.COM if (ve->ve_ndx_valid) 9297836SJohn.Forte@Sun.COM veid = ve->ve_ndx; 9307836SJohn.Forte@Sun.COM else 9317836SJohn.Forte@Sun.COM veid = 0xffffffff; 9327836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9337836SJohn.Forte@Sun.COM ret = stmf_add_ve(ve->ve_host_group.name, 9347836SJohn.Forte@Sun.COM ve->ve_host_group.name_size, 9357836SJohn.Forte@Sun.COM ve->ve_target_group.name, 9367836SJohn.Forte@Sun.COM ve->ve_target_group.name_size, 9377836SJohn.Forte@Sun.COM ve->ve_guid, 9387836SJohn.Forte@Sun.COM &veid, 9397836SJohn.Forte@Sun.COM ve->ve_lu_nbr, 9407836SJohn.Forte@Sun.COM &iocd->stmf_error); 9417836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9427836SJohn.Forte@Sun.COM if (ret == 0 && 9437836SJohn.Forte@Sun.COM (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) && 9447836SJohn.Forte@Sun.COM iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) { 9457836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve_ret = 9467836SJohn.Forte@Sun.COM (stmf_view_op_entry_t *)obuf; 9477836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = 1; 9487836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = 1; 9497836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9507836SJohn.Forte@Sun.COM ve_ret->ve_ndx = veid; 9517836SJohn.Forte@Sun.COM ve_ret->ve_ndx_valid = 1; 9527836SJohn.Forte@Sun.COM } 9537836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) { 9547836SJohn.Forte@Sun.COM ve_ret->ve_lu_number_valid = 1; 9557836SJohn.Forte@Sun.COM bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8); 9567836SJohn.Forte@Sun.COM } 9577836SJohn.Forte@Sun.COM } 9587836SJohn.Forte@Sun.COM break; 9597836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_VIEW_ENTRY: 9607836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9617836SJohn.Forte@Sun.COM ret = EACCES; 9627836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9637836SJohn.Forte@Sun.COM break; 9647836SJohn.Forte@Sun.COM } 9657836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 9667836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9677836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 9687836SJohn.Forte@Sun.COM ret = EINVAL; 9697836SJohn.Forte@Sun.COM break; 9707836SJohn.Forte@Sun.COM } 9717836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9727836SJohn.Forte@Sun.COM ret = EINVAL; 9737836SJohn.Forte@Sun.COM break; 9747836SJohn.Forte@Sun.COM } 9757836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9767836SJohn.Forte@Sun.COM ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx, 9777836SJohn.Forte@Sun.COM &iocd->stmf_error); 9787836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9797836SJohn.Forte@Sun.COM break; 9807836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_LIST: 9817836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 9827836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9837836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_LIST: 9847836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_LIST) 9857836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 9867836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9877836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 9887836SJohn.Forte@Sun.COM n = min(id_list->id_count, 9897836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t)); 9907836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 9917836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 9927836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)obuf; 9937836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 994*9585STim.Szeto@Sun.COM if (id_entry->id_data[0] == '*') { 995*9585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries > 0) { 996*9585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries--; 997*9585STim.Szeto@Sun.COM } 998*9585STim.Szeto@Sun.COM id_entry = id_entry->id_next; 999*9585STim.Szeto@Sun.COM continue; 1000*9585STim.Szeto@Sun.COM } 1001*9585STim.Szeto@Sun.COM grpname->name_size = id_entry->id_data_size; 1002*9585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grpname->name, 10037836SJohn.Forte@Sun.COM id_entry->id_data_size); 1004*9585STim.Szeto@Sun.COM grpname++; 10057836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 10067836SJohn.Forte@Sun.COM } 10077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10087836SJohn.Forte@Sun.COM break; 10097836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_ENTRIES: 10107836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 10117836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 10127836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_ENTRIES: 10137836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 10147836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 10157836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 10167836SJohn.Forte@Sun.COM ret = EINVAL; 10177836SJohn.Forte@Sun.COM break; 10187836SJohn.Forte@Sun.COM } 10197836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_ENTRIES) { 10207836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 10217836SJohn.Forte@Sun.COM } 10227836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10237836SJohn.Forte@Sun.COM id_entry = stmf_lookup_id(id_list, grpname->name_size, 10247836SJohn.Forte@Sun.COM grpname->name); 10257836SJohn.Forte@Sun.COM if (!id_entry) 10267836SJohn.Forte@Sun.COM ret = ENODEV; 10277836SJohn.Forte@Sun.COM else { 10287836SJohn.Forte@Sun.COM stmf_ge_ident_t *grp_entry; 10297836SJohn.Forte@Sun.COM id_list = (stmf_id_list_t *)id_entry->id_impl_specific; 10307836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 10317836SJohn.Forte@Sun.COM n = min(id_list->id_count, 10327836SJohn.Forte@Sun.COM iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t)); 10337836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 10347836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 10357836SJohn.Forte@Sun.COM grp_entry = (stmf_ge_ident_t *)obuf; 10367836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 1037*9585STim.Szeto@Sun.COM bcopy(id_entry->id_data, grp_entry->ident, 10387836SJohn.Forte@Sun.COM id_entry->id_data_size); 1039*9585STim.Szeto@Sun.COM grp_entry->ident_size = id_entry->id_data_size; 10407836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 1041*9585STim.Szeto@Sun.COM grp_entry++; 10427836SJohn.Forte@Sun.COM } 10437836SJohn.Forte@Sun.COM } 10447836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10457836SJohn.Forte@Sun.COM break; 1046*9585STim.Szeto@Sun.COM 10477836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_VE_LIST: 10487836SJohn.Forte@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 10497836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 10507836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 1051*9585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 1052*9585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 1053*9585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 1054*9585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 1055*9585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 1056*9585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 1057*9585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 1058*9585STim.Szeto@Sun.COM continue; 10597836SJohn.Forte@Sun.COM ve->ve_ndx_valid = 1; 10607836SJohn.Forte@Sun.COM ve->ve_ndx = view_entry->ve_id; 10617836SJohn.Forte@Sun.COM ve->ve_lu_number_valid = 1; 10627836SJohn.Forte@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 10637836SJohn.Forte@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 10647836SJohn.Forte@Sun.COM view_entry->ve_luid->id_data_size); 1065*9585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 10667836SJohn.Forte@Sun.COM ve->ve_all_hosts = 1; 1067*9585STim.Szeto@Sun.COM } else { 10687836SJohn.Forte@Sun.COM bcopy(view_entry->ve_hg->id_data, 10697836SJohn.Forte@Sun.COM ve->ve_host_group.name, 10707836SJohn.Forte@Sun.COM view_entry->ve_hg->id_data_size); 1071*9585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 1072*9585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 1073*9585STim.Szeto@Sun.COM } 1074*9585STim.Szeto@Sun.COM 1075*9585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 10767836SJohn.Forte@Sun.COM ve->ve_all_targets = 1; 1077*9585STim.Szeto@Sun.COM } else { 10787836SJohn.Forte@Sun.COM bcopy(view_entry->ve_tg->id_data, 10797836SJohn.Forte@Sun.COM ve->ve_target_group.name, 10807836SJohn.Forte@Sun.COM view_entry->ve_tg->id_data_size); 1081*9585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 1082*9585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 1083*9585STim.Szeto@Sun.COM } 1084*9585STim.Szeto@Sun.COM ve++; 10857836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries++; 10867836SJohn.Forte@Sun.COM } 10877836SJohn.Forte@Sun.COM } 10887836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10897836SJohn.Forte@Sun.COM break; 1090*9585STim.Szeto@Sun.COM 1091*9585STim.Szeto@Sun.COM case STMF_IOCTL_LU_VE_LIST: 1092*9585STim.Szeto@Sun.COM p_id = (uint8_t *)ibuf; 1093*9585STim.Szeto@Sun.COM if ((iocd->stmf_ibuf_size != 16) || 1094*9585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_view_op_entry_t))) { 1095*9585STim.Szeto@Sun.COM ret = EINVAL; 1096*9585STim.Szeto@Sun.COM break; 1097*9585STim.Szeto@Sun.COM } 1098*9585STim.Szeto@Sun.COM 1099*9585STim.Szeto@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 1100*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 1101*9585STim.Szeto@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 1102*9585STim.Szeto@Sun.COM for (id_entry = stmf_state.stmf_luid_list.idl_head; 1103*9585STim.Szeto@Sun.COM id_entry; id_entry = id_entry->id_next) { 1104*9585STim.Szeto@Sun.COM if (bcmp(id_entry->id_data, p_id, 16) != 0) 1105*9585STim.Szeto@Sun.COM continue; 1106*9585STim.Szeto@Sun.COM for (view_entry = (stmf_view_entry_t *) 1107*9585STim.Szeto@Sun.COM id_entry->id_impl_specific; view_entry; 1108*9585STim.Szeto@Sun.COM view_entry = view_entry->ve_next) { 1109*9585STim.Szeto@Sun.COM iocd->stmf_obuf_max_nentries++; 1110*9585STim.Szeto@Sun.COM if (iocd->stmf_obuf_nentries >= n) 1111*9585STim.Szeto@Sun.COM continue; 1112*9585STim.Szeto@Sun.COM ve->ve_ndx_valid = 1; 1113*9585STim.Szeto@Sun.COM ve->ve_ndx = view_entry->ve_id; 1114*9585STim.Szeto@Sun.COM ve->ve_lu_number_valid = 1; 1115*9585STim.Szeto@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 1116*9585STim.Szeto@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 1117*9585STim.Szeto@Sun.COM view_entry->ve_luid->id_data_size); 1118*9585STim.Szeto@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') { 1119*9585STim.Szeto@Sun.COM ve->ve_all_hosts = 1; 1120*9585STim.Szeto@Sun.COM } else { 1121*9585STim.Szeto@Sun.COM bcopy(view_entry->ve_hg->id_data, 1122*9585STim.Szeto@Sun.COM ve->ve_host_group.name, 1123*9585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size); 1124*9585STim.Szeto@Sun.COM ve->ve_host_group.name_size = 1125*9585STim.Szeto@Sun.COM view_entry->ve_hg->id_data_size; 1126*9585STim.Szeto@Sun.COM } 1127*9585STim.Szeto@Sun.COM 1128*9585STim.Szeto@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') { 1129*9585STim.Szeto@Sun.COM ve->ve_all_targets = 1; 1130*9585STim.Szeto@Sun.COM } else { 1131*9585STim.Szeto@Sun.COM bcopy(view_entry->ve_tg->id_data, 1132*9585STim.Szeto@Sun.COM ve->ve_target_group.name, 1133*9585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size); 1134*9585STim.Szeto@Sun.COM ve->ve_target_group.name_size = 1135*9585STim.Szeto@Sun.COM view_entry->ve_tg->id_data_size; 1136*9585STim.Szeto@Sun.COM } 1137*9585STim.Szeto@Sun.COM ve++; 1138*9585STim.Szeto@Sun.COM iocd->stmf_obuf_nentries++; 1139*9585STim.Szeto@Sun.COM } 1140*9585STim.Szeto@Sun.COM break; 1141*9585STim.Szeto@Sun.COM } 1142*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 1143*9585STim.Szeto@Sun.COM break; 1144*9585STim.Szeto@Sun.COM 11457836SJohn.Forte@Sun.COM case STMF_IOCTL_LOAD_PP_DATA: 11467836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11477836SJohn.Forte@Sun.COM ret = EACCES; 11487836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11497836SJohn.Forte@Sun.COM break; 11507836SJohn.Forte@Sun.COM } 11517836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11527836SJohn.Forte@Sun.COM if ((ppi == NULL) || 11537836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11547836SJohn.Forte@Sun.COM ret = EINVAL; 11557836SJohn.Forte@Sun.COM break; 11567836SJohn.Forte@Sun.COM } 1157*9585STim.Szeto@Sun.COM /* returned token */ 1158*9585STim.Szeto@Sun.COM ppi_token = (uint64_t *)obuf; 1159*9585STim.Szeto@Sun.COM if ((ppi_token == NULL) || 1160*9585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (uint64_t))) { 1161*9585STim.Szeto@Sun.COM ret = EINVAL; 1162*9585STim.Szeto@Sun.COM break; 1163*9585STim.Szeto@Sun.COM } 1164*9585STim.Szeto@Sun.COM ret = stmf_load_ppd_ioctl(ppi, ppi_token, &iocd->stmf_error); 1165*9585STim.Szeto@Sun.COM break; 1166*9585STim.Szeto@Sun.COM 1167*9585STim.Szeto@Sun.COM case STMF_IOCTL_GET_PP_DATA: 1168*9585STim.Szeto@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 1169*9585STim.Szeto@Sun.COM ret = EACCES; 1170*9585STim.Szeto@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 1171*9585STim.Szeto@Sun.COM break; 1172*9585STim.Szeto@Sun.COM } 1173*9585STim.Szeto@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 1174*9585STim.Szeto@Sun.COM if (ppi == NULL || 1175*9585STim.Szeto@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 1176*9585STim.Szeto@Sun.COM ret = EINVAL; 1177*9585STim.Szeto@Sun.COM break; 1178*9585STim.Szeto@Sun.COM } 1179*9585STim.Szeto@Sun.COM ppi_out = (stmf_ppioctl_data_t *)obuf; 1180*9585STim.Szeto@Sun.COM if ((ppi_out == NULL) || 1181*9585STim.Szeto@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_ppioctl_data_t))) { 1182*9585STim.Szeto@Sun.COM ret = EINVAL; 1183*9585STim.Szeto@Sun.COM break; 1184*9585STim.Szeto@Sun.COM } 1185*9585STim.Szeto@Sun.COM ret = stmf_get_ppd_ioctl(ppi, ppi_out, &iocd->stmf_error); 11867836SJohn.Forte@Sun.COM break; 11877836SJohn.Forte@Sun.COM 11887836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_PP_DATA: 11897836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 11907836SJohn.Forte@Sun.COM ret = EACCES; 11917836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 11927836SJohn.Forte@Sun.COM break; 11937836SJohn.Forte@Sun.COM } 11947836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 11957836SJohn.Forte@Sun.COM if ((ppi == NULL) || 11967836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 11977836SJohn.Forte@Sun.COM ret = EINVAL; 11987836SJohn.Forte@Sun.COM break; 11997836SJohn.Forte@Sun.COM } 12007836SJohn.Forte@Sun.COM ret = stmf_delete_ppd_ioctl(ppi); 12017836SJohn.Forte@Sun.COM break; 12027836SJohn.Forte@Sun.COM 12037836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_TRACE: 12047836SJohn.Forte@Sun.COM stmf_trace_clear(); 12057836SJohn.Forte@Sun.COM break; 12067836SJohn.Forte@Sun.COM 12077836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TRACE: 12087836SJohn.Forte@Sun.COM if (iocd->stmf_ibuf_size && ibuf) { 12097836SJohn.Forte@Sun.COM ((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0; 12107836SJohn.Forte@Sun.COM stmf_trace("\nstradm", "%s\n", ibuf); 12117836SJohn.Forte@Sun.COM } 12127836SJohn.Forte@Sun.COM break; 12137836SJohn.Forte@Sun.COM 12147836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE_POSITION: 12157836SJohn.Forte@Sun.COM if (obuf && (iocd->stmf_obuf_size > 3)) { 12167836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12177836SJohn.Forte@Sun.COM *((int *)obuf) = trace_buf_curndx; 12187836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12197836SJohn.Forte@Sun.COM } else { 12207836SJohn.Forte@Sun.COM ret = EINVAL; 12217836SJohn.Forte@Sun.COM } 12227836SJohn.Forte@Sun.COM break; 12237836SJohn.Forte@Sun.COM 12247836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE: 12257836SJohn.Forte@Sun.COM if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) { 12267836SJohn.Forte@Sun.COM ret = EINVAL; 12277836SJohn.Forte@Sun.COM break; 12287836SJohn.Forte@Sun.COM } 12297836SJohn.Forte@Sun.COM i = *((int *)ibuf); 12307836SJohn.Forte@Sun.COM if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) > 12317836SJohn.Forte@Sun.COM trace_buf_size)) { 12327836SJohn.Forte@Sun.COM ret = EINVAL; 12337836SJohn.Forte@Sun.COM break; 12347836SJohn.Forte@Sun.COM } 12357836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 12367836SJohn.Forte@Sun.COM bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size); 12377836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 12387836SJohn.Forte@Sun.COM break; 12397836SJohn.Forte@Sun.COM 12407836SJohn.Forte@Sun.COM default: 12417836SJohn.Forte@Sun.COM ret = ENOTTY; 12427836SJohn.Forte@Sun.COM } 12437836SJohn.Forte@Sun.COM 12447836SJohn.Forte@Sun.COM if (ret == 0) { 12457836SJohn.Forte@Sun.COM ret = stmf_copyout_iocdata(data, mode, iocd, obuf); 12467836SJohn.Forte@Sun.COM } else if (iocd->stmf_error) { 12477836SJohn.Forte@Sun.COM (void) stmf_copyout_iocdata(data, mode, iocd, obuf); 12487836SJohn.Forte@Sun.COM } 12497836SJohn.Forte@Sun.COM if (obuf) { 12507836SJohn.Forte@Sun.COM kmem_free(obuf, iocd->stmf_obuf_size); 12517836SJohn.Forte@Sun.COM obuf = NULL; 12527836SJohn.Forte@Sun.COM } 12537836SJohn.Forte@Sun.COM if (ibuf) { 12547836SJohn.Forte@Sun.COM kmem_free(ibuf, iocd->stmf_ibuf_size); 12557836SJohn.Forte@Sun.COM ibuf = NULL; 12567836SJohn.Forte@Sun.COM } 12577836SJohn.Forte@Sun.COM kmem_free(iocd, sizeof (stmf_iocdata_t)); 12587836SJohn.Forte@Sun.COM return (ret); 12597836SJohn.Forte@Sun.COM } 12607836SJohn.Forte@Sun.COM 12617836SJohn.Forte@Sun.COM static int 12627836SJohn.Forte@Sun.COM stmf_get_service_state() 12637836SJohn.Forte@Sun.COM { 12647836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 12657836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 12667836SJohn.Forte@Sun.COM int online = 0; 12677836SJohn.Forte@Sun.COM int offline = 0; 12687836SJohn.Forte@Sun.COM int onlining = 0; 12697836SJohn.Forte@Sun.COM int offlining = 0; 12707836SJohn.Forte@Sun.COM 12717836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 12727836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 12737836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 12747836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) 12757836SJohn.Forte@Sun.COM offline++; 12767836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINE) 12777836SJohn.Forte@Sun.COM online++; 12787836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINING) 12797836SJohn.Forte@Sun.COM onlining++; 12807836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_OFFLINING) 12817836SJohn.Forte@Sun.COM offlining++; 12827836SJohn.Forte@Sun.COM } 12837836SJohn.Forte@Sun.COM 12847836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 12857836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 12867836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) 12877836SJohn.Forte@Sun.COM offline++; 12887836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINE) 12897836SJohn.Forte@Sun.COM online++; 12907836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINING) 12917836SJohn.Forte@Sun.COM onlining++; 12927836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_OFFLINING) 12937836SJohn.Forte@Sun.COM offlining++; 12947836SJohn.Forte@Sun.COM } 12957836SJohn.Forte@Sun.COM 12967836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 12977836SJohn.Forte@Sun.COM if (onlining) 12987836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINING); 12997836SJohn.Forte@Sun.COM else 13007836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINE); 13017836SJohn.Forte@Sun.COM } 13027836SJohn.Forte@Sun.COM 13037836SJohn.Forte@Sun.COM if (offlining) { 13047836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINING); 13057836SJohn.Forte@Sun.COM } 13067836SJohn.Forte@Sun.COM 13077836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINE); 13087836SJohn.Forte@Sun.COM } 13097836SJohn.Forte@Sun.COM 13107836SJohn.Forte@Sun.COM static int 13117836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std) 13127836SJohn.Forte@Sun.COM { 13137836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 13147836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 13157836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 13167836SJohn.Forte@Sun.COM int svc_state; 13177836SJohn.Forte@Sun.COM 13187836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 13197836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 13207836SJohn.Forte@Sun.COM 13217836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 13227836SJohn.Forte@Sun.COM if (!stmf_state.stmf_exclusive_open) { 13237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13247836SJohn.Forte@Sun.COM return (EACCES); 13257836SJohn.Forte@Sun.COM } 13267836SJohn.Forte@Sun.COM 13277836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 13287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13297836SJohn.Forte@Sun.COM return (EBUSY); 13307836SJohn.Forte@Sun.COM } 13317836SJohn.Forte@Sun.COM 13327836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_ONLINE) && 13337836SJohn.Forte@Sun.COM (std->state != STMF_STATE_OFFLINE)) { 13347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13357836SJohn.Forte@Sun.COM return (EINVAL); 13367836SJohn.Forte@Sun.COM } 13377836SJohn.Forte@Sun.COM 13387836SJohn.Forte@Sun.COM svc_state = stmf_get_service_state(); 13397836SJohn.Forte@Sun.COM if ((svc_state == STMF_STATE_OFFLINING) || 13407836SJohn.Forte@Sun.COM (svc_state == STMF_STATE_ONLINING)) { 13417836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13427836SJohn.Forte@Sun.COM return (EBUSY); 13437836SJohn.Forte@Sun.COM } 13447836SJohn.Forte@Sun.COM 13457836SJohn.Forte@Sun.COM if (svc_state == STMF_STATE_OFFLINE) { 13467836SJohn.Forte@Sun.COM if (std->config_state == STMF_CONFIG_INIT) { 13477836SJohn.Forte@Sun.COM if (std->state != STMF_STATE_OFFLINE) { 13487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13497836SJohn.Forte@Sun.COM return (EINVAL); 13507836SJohn.Forte@Sun.COM } 13517836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT; 13527836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 13537836SJohn.Forte@Sun.COM stmf_view_clear_config(); 13547836SJohn.Forte@Sun.COM stmf_view_init(); 13557836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13567836SJohn.Forte@Sun.COM return (0); 13577836SJohn.Forte@Sun.COM } 13587836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 13597836SJohn.Forte@Sun.COM if (std->config_state != STMF_CONFIG_INIT_DONE) { 13607836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13617836SJohn.Forte@Sun.COM return (EINVAL); 13627836SJohn.Forte@Sun.COM } 13637836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE; 13647836SJohn.Forte@Sun.COM } 13657836SJohn.Forte@Sun.COM if (std->state == STMF_STATE_OFFLINE) { 13667836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13677836SJohn.Forte@Sun.COM return (0); 13687836SJohn.Forte@Sun.COM } 13697836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 13707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13717836SJohn.Forte@Sun.COM return (EINVAL); 13727836SJohn.Forte@Sun.COM } 13737836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 13747836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 1; 13757836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13767836SJohn.Forte@Sun.COM 13777836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 13787836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 13797836SJohn.Forte@Sun.COM if (ilport->ilport_prev_state != STMF_STATE_ONLINE) 13807836SJohn.Forte@Sun.COM continue; 13817836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, 13828662SJordan.Vaughan@Sun.com ilport->ilport_lport, &ssi); 13837836SJohn.Forte@Sun.COM } 13847836SJohn.Forte@Sun.COM 13857836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 13867836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 13877836SJohn.Forte@Sun.COM if (ilu->ilu_prev_state != STMF_STATE_ONLINE) 13887836SJohn.Forte@Sun.COM continue; 13897836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi); 13907836SJohn.Forte@Sun.COM } 13917836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 13927836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 13937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 13947836SJohn.Forte@Sun.COM return (0); 13957836SJohn.Forte@Sun.COM } 13967836SJohn.Forte@Sun.COM 13977836SJohn.Forte@Sun.COM /* svc_state is STMF_STATE_ONLINE here */ 13987836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_OFFLINE) || 13997836SJohn.Forte@Sun.COM (std->config_state == STMF_CONFIG_INIT)) { 14007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14017836SJohn.Forte@Sun.COM return (EACCES); 14027836SJohn.Forte@Sun.COM } 14037836SJohn.Forte@Sun.COM 14047836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 14057836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 14067836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 14077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14087836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 14097836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 14107836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) 14117836SJohn.Forte@Sun.COM continue; 14127836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, 14137836SJohn.Forte@Sun.COM ilport->ilport_lport, &ssi); 14147836SJohn.Forte@Sun.COM } 14157836SJohn.Forte@Sun.COM 14167836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 14177836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 14187836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) 14197836SJohn.Forte@Sun.COM continue; 14207836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi); 14217836SJohn.Forte@Sun.COM } 14227836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14237836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 14247836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14257836SJohn.Forte@Sun.COM return (0); 14267836SJohn.Forte@Sun.COM } 14277836SJohn.Forte@Sun.COM 14287836SJohn.Forte@Sun.COM static int 14297836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std) 14307836SJohn.Forte@Sun.COM { 14317836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14327836SJohn.Forte@Sun.COM std->state = stmf_get_service_state(); 14337836SJohn.Forte@Sun.COM std->config_state = stmf_state.stmf_config_state; 14347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14357836SJohn.Forte@Sun.COM 14367836SJohn.Forte@Sun.COM return (0); 14377836SJohn.Forte@Sun.COM } 14387836SJohn.Forte@Sun.COM 14397836SJohn.Forte@Sun.COM typedef struct { 14407836SJohn.Forte@Sun.COM void *bp; /* back pointer from internal struct to main struct */ 14417836SJohn.Forte@Sun.COM int alloc_size; 14427836SJohn.Forte@Sun.COM } __istmf_t; 14437836SJohn.Forte@Sun.COM 14447836SJohn.Forte@Sun.COM typedef struct { 14457836SJohn.Forte@Sun.COM __istmf_t *fp; /* Framework private */ 14467836SJohn.Forte@Sun.COM void *cp; /* Caller private */ 14477836SJohn.Forte@Sun.COM void *ss; /* struct specific */ 14487836SJohn.Forte@Sun.COM } __stmf_t; 14497836SJohn.Forte@Sun.COM 14507836SJohn.Forte@Sun.COM static struct { 14517836SJohn.Forte@Sun.COM int shared; 14527836SJohn.Forte@Sun.COM int fw_private; 14537836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 }, 14547836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_provider_t), 14557836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_provider_t) }, 14567836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_port_provider_t), 14577836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_port_provider_t) }, 14587836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_local_port_t), 14597836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_local_port_t) }, 14607836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_t), 14617836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_t) }, 14627836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_scsi_session_t), 14637836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_session_t) }, 14647836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(scsi_task_t), 14657836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_task_t) }, 14667836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_data_buf_t), 14677836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) }, 14687836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_dbuf_store_t), 14697836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) } 14707836SJohn.Forte@Sun.COM 14717836SJohn.Forte@Sun.COM }; 14727836SJohn.Forte@Sun.COM 14737836SJohn.Forte@Sun.COM void * 14747836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags) 14757836SJohn.Forte@Sun.COM { 14767836SJohn.Forte@Sun.COM int stmf_size; 14777836SJohn.Forte@Sun.COM int kmem_flag; 14787836SJohn.Forte@Sun.COM __stmf_t *sh; 14797836SJohn.Forte@Sun.COM 14807836SJohn.Forte@Sun.COM if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS)) 14817836SJohn.Forte@Sun.COM return (NULL); 14827836SJohn.Forte@Sun.COM 14837836SJohn.Forte@Sun.COM if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) { 14847836SJohn.Forte@Sun.COM kmem_flag = KM_NOSLEEP; 14857836SJohn.Forte@Sun.COM } else { 14867836SJohn.Forte@Sun.COM kmem_flag = KM_SLEEP; 14877836SJohn.Forte@Sun.COM } 14887836SJohn.Forte@Sun.COM 14897836SJohn.Forte@Sun.COM additional_size = (additional_size + 7) & (~7); 14907836SJohn.Forte@Sun.COM stmf_size = stmf_sizes[struct_id].shared + 14918662SJordan.Vaughan@Sun.com stmf_sizes[struct_id].fw_private + additional_size; 14927836SJohn.Forte@Sun.COM 14937836SJohn.Forte@Sun.COM sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag); 14947836SJohn.Forte@Sun.COM 14957836SJohn.Forte@Sun.COM if (sh == NULL) 14967836SJohn.Forte@Sun.COM return (NULL); 14977836SJohn.Forte@Sun.COM 14989087SZhong.Wang@Sun.COM /* 14999087SZhong.Wang@Sun.COM * In principle, the implementation inside stmf_alloc should not 15009087SZhong.Wang@Sun.COM * be changed anyway. But the original order of framework private 15019087SZhong.Wang@Sun.COM * data and caller private data does not support sglist in the caller 15029087SZhong.Wang@Sun.COM * private data. 15039087SZhong.Wang@Sun.COM * To work around this, the memory segments of framework private 15049087SZhong.Wang@Sun.COM * data and caller private data are re-ordered here. 15059087SZhong.Wang@Sun.COM * A better solution is to provide a specific interface to allocate 15069087SZhong.Wang@Sun.COM * the sglist, then we will not need this workaround any more. 15079087SZhong.Wang@Sun.COM * But before the new interface is available, the memory segment 15089087SZhong.Wang@Sun.COM * ordering should be kept as is. 15099087SZhong.Wang@Sun.COM */ 15109087SZhong.Wang@Sun.COM sh->cp = GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); 15119087SZhong.Wang@Sun.COM sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, 15129087SZhong.Wang@Sun.COM stmf_sizes[struct_id].shared + additional_size); 15137836SJohn.Forte@Sun.COM 15147836SJohn.Forte@Sun.COM sh->fp->bp = sh; 15157836SJohn.Forte@Sun.COM /* Just store the total size instead of storing additional size */ 15167836SJohn.Forte@Sun.COM sh->fp->alloc_size = stmf_size; 15177836SJohn.Forte@Sun.COM 15187836SJohn.Forte@Sun.COM return (sh); 15197836SJohn.Forte@Sun.COM } 15207836SJohn.Forte@Sun.COM 15217836SJohn.Forte@Sun.COM void 15227836SJohn.Forte@Sun.COM stmf_free(void *ptr) 15237836SJohn.Forte@Sun.COM { 15247836SJohn.Forte@Sun.COM __stmf_t *sh = (__stmf_t *)ptr; 15257836SJohn.Forte@Sun.COM 15267836SJohn.Forte@Sun.COM /* 15277836SJohn.Forte@Sun.COM * So far we dont need any struct specific processing. If such 15287836SJohn.Forte@Sun.COM * a need ever arises, then store the struct id in the framework 15297836SJohn.Forte@Sun.COM * private section and get it here as sh->fp->struct_id. 15307836SJohn.Forte@Sun.COM */ 15317836SJohn.Forte@Sun.COM kmem_free(ptr, sh->fp->alloc_size); 15327836SJohn.Forte@Sun.COM } 15337836SJohn.Forte@Sun.COM 15347836SJohn.Forte@Sun.COM /* 15357836SJohn.Forte@Sun.COM * Given a pointer to stmf_lu_t, verifies if this lu is registered with the 15367836SJohn.Forte@Sun.COM * framework and returns a pointer to framework private data for the lu. 15377836SJohn.Forte@Sun.COM * Returns NULL if the lu was not found. 15387836SJohn.Forte@Sun.COM */ 15397836SJohn.Forte@Sun.COM stmf_i_lu_t * 15407836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu) 15417836SJohn.Forte@Sun.COM { 15427836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 15437836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 15447836SJohn.Forte@Sun.COM 15457836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 15467836SJohn.Forte@Sun.COM if (ilu->ilu_lu == lu) 15477836SJohn.Forte@Sun.COM return (ilu); 15487836SJohn.Forte@Sun.COM } 15497836SJohn.Forte@Sun.COM return (NULL); 15507836SJohn.Forte@Sun.COM } 15517836SJohn.Forte@Sun.COM 15527836SJohn.Forte@Sun.COM /* 15538818STim.Szeto@Sun.COM * Given a pointer to stmf_local_port_t, verifies if this lport is registered 15548818STim.Szeto@Sun.COM * with the framework and returns a pointer to framework private data for 15558818STim.Szeto@Sun.COM * the lport. 15568818STim.Szeto@Sun.COM * Returns NULL if the lport was not found. 15577836SJohn.Forte@Sun.COM */ 15587836SJohn.Forte@Sun.COM stmf_i_local_port_t * 15597836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport) 15607836SJohn.Forte@Sun.COM { 15617836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 15627836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 15637836SJohn.Forte@Sun.COM 15647836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 15657836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 15667836SJohn.Forte@Sun.COM if (ilport->ilport_lport == lport) 15677836SJohn.Forte@Sun.COM return (ilport); 15687836SJohn.Forte@Sun.COM } 15697836SJohn.Forte@Sun.COM return (NULL); 15707836SJohn.Forte@Sun.COM } 15717836SJohn.Forte@Sun.COM 15727836SJohn.Forte@Sun.COM stmf_status_t 15737836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp) 15747836SJohn.Forte@Sun.COM { 15757836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 15767836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 15777836SJohn.Forte@Sun.COM uint32_t cb_flags; 15787836SJohn.Forte@Sun.COM 15797836SJohn.Forte@Sun.COM if (lp->lp_lpif_rev != LPIF_REV_1) 15807836SJohn.Forte@Sun.COM return (STMF_FAILURE); 15817836SJohn.Forte@Sun.COM 15827836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15837836SJohn.Forte@Sun.COM ilp->ilp_next = stmf_state.stmf_ilplist; 15847836SJohn.Forte@Sun.COM stmf_state.stmf_ilplist = ilp; 15857836SJohn.Forte@Sun.COM stmf_state.stmf_nlps++; 15867836SJohn.Forte@Sun.COM 15877836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 15887836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 15897836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, lp->lp_name) == 0) { 15907836SJohn.Forte@Sun.COM break; 15917836SJohn.Forte@Sun.COM } 15927836SJohn.Forte@Sun.COM } 15937836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 15947836SJohn.Forte@Sun.COM goto rlp_bail_out; 15957836SJohn.Forte@Sun.COM } 15967836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 15977836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 15987836SJohn.Forte@Sun.COM if (lp->lp_cb == NULL) 15997836SJohn.Forte@Sun.COM goto rlp_bail_out; 16007836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 16017836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 16027836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 16037836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 16047836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16057836SJohn.Forte@Sun.COM lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 16067836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16077836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 16087836SJohn.Forte@Sun.COM 16097836SJohn.Forte@Sun.COM rlp_bail_out: 16107836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16117836SJohn.Forte@Sun.COM 16127836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16137836SJohn.Forte@Sun.COM } 16147836SJohn.Forte@Sun.COM 16157836SJohn.Forte@Sun.COM stmf_status_t 16167836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp) 16177836SJohn.Forte@Sun.COM { 16187836SJohn.Forte@Sun.COM stmf_i_lu_provider_t **ppilp; 16197836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 16207836SJohn.Forte@Sun.COM 16217836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16227836SJohn.Forte@Sun.COM if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) { 16237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16247836SJohn.Forte@Sun.COM return (STMF_BUSY); 16257836SJohn.Forte@Sun.COM } 16267836SJohn.Forte@Sun.COM for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL; 16277836SJohn.Forte@Sun.COM ppilp = &((*ppilp)->ilp_next)) { 16287836SJohn.Forte@Sun.COM if (*ppilp == ilp) { 16297836SJohn.Forte@Sun.COM *ppilp = ilp->ilp_next; 16307836SJohn.Forte@Sun.COM stmf_state.stmf_nlps--; 16317836SJohn.Forte@Sun.COM if (ilp->ilp_ppd) { 16327836SJohn.Forte@Sun.COM ilp->ilp_ppd->ppd_provider = NULL; 16337836SJohn.Forte@Sun.COM ilp->ilp_ppd = NULL; 16347836SJohn.Forte@Sun.COM } 16357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16367836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16377836SJohn.Forte@Sun.COM } 16387836SJohn.Forte@Sun.COM } 16397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16407836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 16417836SJohn.Forte@Sun.COM } 16427836SJohn.Forte@Sun.COM 16437836SJohn.Forte@Sun.COM stmf_status_t 16447836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp) 16457836SJohn.Forte@Sun.COM { 16467836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 16477836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 16487836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 16497836SJohn.Forte@Sun.COM uint32_t cb_flags; 16507836SJohn.Forte@Sun.COM 16517836SJohn.Forte@Sun.COM if (pp->pp_portif_rev != PORTIF_REV_1) 16527836SJohn.Forte@Sun.COM return (STMF_FAILURE); 16537836SJohn.Forte@Sun.COM 16547836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16557836SJohn.Forte@Sun.COM ipp->ipp_next = stmf_state.stmf_ipplist; 16567836SJohn.Forte@Sun.COM stmf_state.stmf_ipplist = ipp; 16577836SJohn.Forte@Sun.COM stmf_state.stmf_npps++; 16587836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 16597836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 16607836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, pp->pp_name) == 0) { 16617836SJohn.Forte@Sun.COM break; 16627836SJohn.Forte@Sun.COM } 16637836SJohn.Forte@Sun.COM } 16647836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 16657836SJohn.Forte@Sun.COM goto rpp_bail_out; 16667836SJohn.Forte@Sun.COM } 16677836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 16687836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 16697836SJohn.Forte@Sun.COM if (pp->pp_cb == NULL) 16707836SJohn.Forte@Sun.COM goto rpp_bail_out; 16717836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 16727836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 16737836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 16747836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 16757836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16767836SJohn.Forte@Sun.COM pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 16777836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16787836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 16797836SJohn.Forte@Sun.COM 16807836SJohn.Forte@Sun.COM rpp_bail_out: 16817836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16827836SJohn.Forte@Sun.COM 16837836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 16847836SJohn.Forte@Sun.COM } 16857836SJohn.Forte@Sun.COM 16867836SJohn.Forte@Sun.COM stmf_status_t 16877836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp) 16887836SJohn.Forte@Sun.COM { 16897836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 16907836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 16917836SJohn.Forte@Sun.COM stmf_i_port_provider_t **ppipp; 16927836SJohn.Forte@Sun.COM 16937836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16947836SJohn.Forte@Sun.COM if (ipp->ipp_npps || ipp->ipp_cb_in_progress) { 16957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16967836SJohn.Forte@Sun.COM return (STMF_BUSY); 16977836SJohn.Forte@Sun.COM } 16987836SJohn.Forte@Sun.COM for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL; 16997836SJohn.Forte@Sun.COM ppipp = &((*ppipp)->ipp_next)) { 17007836SJohn.Forte@Sun.COM if (*ppipp == ipp) { 17017836SJohn.Forte@Sun.COM *ppipp = ipp->ipp_next; 17027836SJohn.Forte@Sun.COM stmf_state.stmf_npps--; 17037836SJohn.Forte@Sun.COM if (ipp->ipp_ppd) { 17047836SJohn.Forte@Sun.COM ipp->ipp_ppd->ppd_provider = NULL; 17057836SJohn.Forte@Sun.COM ipp->ipp_ppd = NULL; 17067836SJohn.Forte@Sun.COM } 17077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17087836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 17097836SJohn.Forte@Sun.COM } 17107836SJohn.Forte@Sun.COM } 17117836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17127836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 17137836SJohn.Forte@Sun.COM } 17147836SJohn.Forte@Sun.COM 17157836SJohn.Forte@Sun.COM int 1716*9585STim.Szeto@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi, uint64_t *ppi_token, 1717*9585STim.Szeto@Sun.COM uint32_t *err_ret) 17187836SJohn.Forte@Sun.COM { 17197836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp; 17207836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 17217836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 17227836SJohn.Forte@Sun.COM nvlist_t *nv; 17237836SJohn.Forte@Sun.COM int s; 17247836SJohn.Forte@Sun.COM int ret; 17257836SJohn.Forte@Sun.COM 1726*9585STim.Szeto@Sun.COM *err_ret = 0; 1727*9585STim.Szeto@Sun.COM 17287836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 17297836SJohn.Forte@Sun.COM return (EINVAL); 17307836SJohn.Forte@Sun.COM } 17317836SJohn.Forte@Sun.COM 17327836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 17337836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 17347836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 17357836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 17367836SJohn.Forte@Sun.COM continue; 17377836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 17387836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 17397836SJohn.Forte@Sun.COM continue; 17407836SJohn.Forte@Sun.COM } 17417836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 17427836SJohn.Forte@Sun.COM break; 17437836SJohn.Forte@Sun.COM } 17447836SJohn.Forte@Sun.COM 17457836SJohn.Forte@Sun.COM if (ppd == NULL) { 17467836SJohn.Forte@Sun.COM /* New provider */ 17477836SJohn.Forte@Sun.COM s = strlen(ppi->ppi_name); 17487836SJohn.Forte@Sun.COM if (s > 254) { 17497836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17507836SJohn.Forte@Sun.COM return (EINVAL); 17517836SJohn.Forte@Sun.COM } 17527836SJohn.Forte@Sun.COM s += sizeof (stmf_pp_data_t) - 7; 17537836SJohn.Forte@Sun.COM 17547836SJohn.Forte@Sun.COM ppd = kmem_zalloc(s, KM_NOSLEEP); 17557836SJohn.Forte@Sun.COM if (ppd == NULL) { 17567836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17577836SJohn.Forte@Sun.COM return (ENOMEM); 17587836SJohn.Forte@Sun.COM } 17597836SJohn.Forte@Sun.COM ppd->ppd_alloc_size = s; 17607836SJohn.Forte@Sun.COM (void) strcpy(ppd->ppd_name, ppi->ppi_name); 17617836SJohn.Forte@Sun.COM 17627836SJohn.Forte@Sun.COM /* See if this provider already exists */ 17637836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 17647836SJohn.Forte@Sun.COM ppd->ppd_lu_provider = 1; 17657836SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; 17667836SJohn.Forte@Sun.COM ilp = ilp->ilp_next) { 17677836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 17687836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 17697836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 17707836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 17717836SJohn.Forte@Sun.COM break; 17727836SJohn.Forte@Sun.COM } 17737836SJohn.Forte@Sun.COM } 17747836SJohn.Forte@Sun.COM } else { 17757836SJohn.Forte@Sun.COM ppd->ppd_port_provider = 1; 17767836SJohn.Forte@Sun.COM for (ipp = stmf_state.stmf_ipplist; ipp != NULL; 17777836SJohn.Forte@Sun.COM ipp = ipp->ipp_next) { 17787836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 17797836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_name) == 0) { 17807836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 17817836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 17827836SJohn.Forte@Sun.COM break; 17837836SJohn.Forte@Sun.COM } 17847836SJohn.Forte@Sun.COM } 17857836SJohn.Forte@Sun.COM } 17867836SJohn.Forte@Sun.COM 17877836SJohn.Forte@Sun.COM /* Link this ppd in */ 17887836SJohn.Forte@Sun.COM ppd->ppd_next = stmf_state.stmf_ppdlist; 17897836SJohn.Forte@Sun.COM stmf_state.stmf_ppdlist = ppd; 17907836SJohn.Forte@Sun.COM } 17917836SJohn.Forte@Sun.COM 1792*9585STim.Szeto@Sun.COM /* 1793*9585STim.Szeto@Sun.COM * User is requesting that the token be checked. 1794*9585STim.Szeto@Sun.COM * If there was another set after the user's get 1795*9585STim.Szeto@Sun.COM * it's an error 1796*9585STim.Szeto@Sun.COM */ 1797*9585STim.Szeto@Sun.COM if (ppi->ppi_token_valid) { 1798*9585STim.Szeto@Sun.COM if (ppi->ppi_token != ppd->ppd_token) { 1799*9585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_PPD_UPDATED; 1800*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 1801*9585STim.Szeto@Sun.COM return (EINVAL); 1802*9585STim.Szeto@Sun.COM } 1803*9585STim.Szeto@Sun.COM } 1804*9585STim.Szeto@Sun.COM 18057836SJohn.Forte@Sun.COM if ((ret = nvlist_unpack((char *)ppi->ppi_data, 18067836SJohn.Forte@Sun.COM (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) { 18077836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18087836SJohn.Forte@Sun.COM return (ret); 18097836SJohn.Forte@Sun.COM } 18107836SJohn.Forte@Sun.COM 18117836SJohn.Forte@Sun.COM /* Free any existing lists and add this one to the ppd */ 18127836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 18137836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 18147836SJohn.Forte@Sun.COM ppd->ppd_nv = nv; 18157836SJohn.Forte@Sun.COM 1816*9585STim.Szeto@Sun.COM /* set the token for writes */ 1817*9585STim.Szeto@Sun.COM ppd->ppd_token++; 1818*9585STim.Szeto@Sun.COM /* return token to caller */ 1819*9585STim.Szeto@Sun.COM if (ppi_token) { 1820*9585STim.Szeto@Sun.COM *ppi_token = ppd->ppd_token; 1821*9585STim.Szeto@Sun.COM } 1822*9585STim.Szeto@Sun.COM 18237836SJohn.Forte@Sun.COM /* If there is a provider registered, do the notifications */ 18247836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 18257836SJohn.Forte@Sun.COM uint32_t cb_flags = 0; 18267836SJohn.Forte@Sun.COM 18277836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 18287836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 18297836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 18307836SJohn.Forte@Sun.COM ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider; 18317836SJohn.Forte@Sun.COM if (ilp->ilp_lp->lp_cb == NULL) 18327836SJohn.Forte@Sun.COM goto bail_out; 18337836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 18347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18357836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_cb(ilp->ilp_lp, 18367836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 18377836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18387836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 18397836SJohn.Forte@Sun.COM } else { 18407836SJohn.Forte@Sun.COM ipp = (stmf_i_port_provider_t *)ppd->ppd_provider; 18417836SJohn.Forte@Sun.COM if (ipp->ipp_pp->pp_cb == NULL) 18427836SJohn.Forte@Sun.COM goto bail_out; 18437836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 18447836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18457836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_cb(ipp->ipp_pp, 18467836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 18477836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18487836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 18497836SJohn.Forte@Sun.COM } 18507836SJohn.Forte@Sun.COM } 18517836SJohn.Forte@Sun.COM 18527836SJohn.Forte@Sun.COM bail_out: 18537836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18547836SJohn.Forte@Sun.COM 18557836SJohn.Forte@Sun.COM return (0); 18567836SJohn.Forte@Sun.COM } 18577836SJohn.Forte@Sun.COM 18587836SJohn.Forte@Sun.COM void 18597836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd) 18607836SJohn.Forte@Sun.COM { 18617836SJohn.Forte@Sun.COM stmf_pp_data_t **pppd; 18627836SJohn.Forte@Sun.COM 18637836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 18647836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 18657836SJohn.Forte@Sun.COM if (ppd->ppd_lu_provider) { 18667836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 18677836SJohn.Forte@Sun.COM ppd->ppd_provider)->ilp_ppd = NULL; 18687836SJohn.Forte@Sun.COM } else { 18697836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 18707836SJohn.Forte@Sun.COM ppd->ppd_provider)->ipp_ppd = NULL; 18717836SJohn.Forte@Sun.COM } 18727836SJohn.Forte@Sun.COM ppd->ppd_provider = NULL; 18737836SJohn.Forte@Sun.COM } 18747836SJohn.Forte@Sun.COM 18757836SJohn.Forte@Sun.COM for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL; 18768662SJordan.Vaughan@Sun.com pppd = &((*pppd)->ppd_next)) { 18777836SJohn.Forte@Sun.COM if (*pppd == ppd) 18787836SJohn.Forte@Sun.COM break; 18797836SJohn.Forte@Sun.COM } 18807836SJohn.Forte@Sun.COM 18817836SJohn.Forte@Sun.COM if (*pppd == NULL) 18827836SJohn.Forte@Sun.COM return; 18837836SJohn.Forte@Sun.COM 18847836SJohn.Forte@Sun.COM *pppd = ppd->ppd_next; 18857836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 18867836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 18877836SJohn.Forte@Sun.COM 18887836SJohn.Forte@Sun.COM kmem_free(ppd, ppd->ppd_alloc_size); 18897836SJohn.Forte@Sun.COM } 18907836SJohn.Forte@Sun.COM 18917836SJohn.Forte@Sun.COM int 18927836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi) 18937836SJohn.Forte@Sun.COM { 18947836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 18957836SJohn.Forte@Sun.COM int ret = ENOENT; 18967836SJohn.Forte@Sun.COM 18977836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 18987836SJohn.Forte@Sun.COM return (EINVAL); 18997836SJohn.Forte@Sun.COM } 19007836SJohn.Forte@Sun.COM 19017836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 19027836SJohn.Forte@Sun.COM 19037836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 19047836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 19057836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 19067836SJohn.Forte@Sun.COM continue; 19077836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 19087836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 19097836SJohn.Forte@Sun.COM continue; 19107836SJohn.Forte@Sun.COM } 19117836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 19127836SJohn.Forte@Sun.COM break; 19137836SJohn.Forte@Sun.COM } 19147836SJohn.Forte@Sun.COM 19157836SJohn.Forte@Sun.COM if (ppd) { 19167836SJohn.Forte@Sun.COM ret = 0; 19177836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 19187836SJohn.Forte@Sun.COM } 19197836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19207836SJohn.Forte@Sun.COM 19217836SJohn.Forte@Sun.COM return (ret); 19227836SJohn.Forte@Sun.COM } 19237836SJohn.Forte@Sun.COM 1924*9585STim.Szeto@Sun.COM int 1925*9585STim.Szeto@Sun.COM stmf_get_ppd_ioctl(stmf_ppioctl_data_t *ppi, stmf_ppioctl_data_t *ppi_out, 1926*9585STim.Szeto@Sun.COM uint32_t *err_ret) 1927*9585STim.Szeto@Sun.COM { 1928*9585STim.Szeto@Sun.COM stmf_pp_data_t *ppd; 1929*9585STim.Szeto@Sun.COM size_t req_size; 1930*9585STim.Szeto@Sun.COM int ret = ENOENT; 1931*9585STim.Szeto@Sun.COM char *bufp = (char *)ppi_out->ppi_data; 1932*9585STim.Szeto@Sun.COM 1933*9585STim.Szeto@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 1934*9585STim.Szeto@Sun.COM return (EINVAL); 1935*9585STim.Szeto@Sun.COM } 1936*9585STim.Szeto@Sun.COM 1937*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 1938*9585STim.Szeto@Sun.COM 1939*9585STim.Szeto@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 1940*9585STim.Szeto@Sun.COM if (ppi->ppi_lu_provider) { 1941*9585STim.Szeto@Sun.COM if (!ppd->ppd_lu_provider) 1942*9585STim.Szeto@Sun.COM continue; 1943*9585STim.Szeto@Sun.COM } else if (ppi->ppi_port_provider) { 1944*9585STim.Szeto@Sun.COM if (!ppd->ppd_port_provider) 1945*9585STim.Szeto@Sun.COM continue; 1946*9585STim.Szeto@Sun.COM } 1947*9585STim.Szeto@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 1948*9585STim.Szeto@Sun.COM break; 1949*9585STim.Szeto@Sun.COM } 1950*9585STim.Szeto@Sun.COM 1951*9585STim.Szeto@Sun.COM if (ppd && ppd->ppd_nv) { 1952*9585STim.Szeto@Sun.COM ppi_out->ppi_token = ppd->ppd_token; 1953*9585STim.Szeto@Sun.COM if ((ret = nvlist_size(ppd->ppd_nv, &req_size, 1954*9585STim.Szeto@Sun.COM NV_ENCODE_XDR)) != 0) { 1955*9585STim.Szeto@Sun.COM goto done; 1956*9585STim.Szeto@Sun.COM } 1957*9585STim.Szeto@Sun.COM ppi_out->ppi_data_size = req_size; 1958*9585STim.Szeto@Sun.COM if (req_size > ppi->ppi_data_size) { 1959*9585STim.Szeto@Sun.COM *err_ret = STMF_IOCERR_INSUFFICIENT_BUF; 1960*9585STim.Szeto@Sun.COM ret = EINVAL; 1961*9585STim.Szeto@Sun.COM goto done; 1962*9585STim.Szeto@Sun.COM } 1963*9585STim.Szeto@Sun.COM 1964*9585STim.Szeto@Sun.COM if ((ret = nvlist_pack(ppd->ppd_nv, &bufp, &req_size, 1965*9585STim.Szeto@Sun.COM NV_ENCODE_XDR, 0)) != 0) { 1966*9585STim.Szeto@Sun.COM goto done; 1967*9585STim.Szeto@Sun.COM } 1968*9585STim.Szeto@Sun.COM ret = 0; 1969*9585STim.Szeto@Sun.COM } 1970*9585STim.Szeto@Sun.COM 1971*9585STim.Szeto@Sun.COM done: 1972*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 1973*9585STim.Szeto@Sun.COM 1974*9585STim.Szeto@Sun.COM return (ret); 1975*9585STim.Szeto@Sun.COM } 1976*9585STim.Szeto@Sun.COM 19777836SJohn.Forte@Sun.COM void 19787836SJohn.Forte@Sun.COM stmf_delete_all_ppds() 19797836SJohn.Forte@Sun.COM { 19807836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd, *nppd; 19817836SJohn.Forte@Sun.COM 19827836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 19837836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) { 19847836SJohn.Forte@Sun.COM nppd = ppd->ppd_next; 19857836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 19867836SJohn.Forte@Sun.COM } 19877836SJohn.Forte@Sun.COM } 19887836SJohn.Forte@Sun.COM 19899435STim.Szeto@Sun.COM /* 19909435STim.Szeto@Sun.COM * 16 is the max string length of a protocol_ident, increase 19919435STim.Szeto@Sun.COM * the size if needed. 19929435STim.Szeto@Sun.COM */ 19939435STim.Szeto@Sun.COM #define STMF_KSTAT_LU_SZ (STMF_GUID_INPUT + 1 + 256) 19949435STim.Szeto@Sun.COM #define STMF_KSTAT_TGT_SZ (256 * 2 + 16) 19959435STim.Szeto@Sun.COM 19969435STim.Szeto@Sun.COM typedef struct stmf_kstat_lu_info { 19979435STim.Szeto@Sun.COM kstat_named_t i_lun_guid; 19989435STim.Szeto@Sun.COM kstat_named_t i_lun_alias; 19999435STim.Szeto@Sun.COM } stmf_kstat_lu_info_t; 20009435STim.Szeto@Sun.COM 20019435STim.Szeto@Sun.COM typedef struct stmf_kstat_tgt_info { 20029435STim.Szeto@Sun.COM kstat_named_t i_tgt_name; 20039435STim.Szeto@Sun.COM kstat_named_t i_tgt_alias; 20049435STim.Szeto@Sun.COM kstat_named_t i_protocol; 20059435STim.Szeto@Sun.COM } stmf_kstat_tgt_info_t; 20069435STim.Szeto@Sun.COM 20079435STim.Szeto@Sun.COM /* 20089435STim.Szeto@Sun.COM * This array matches the Protocol Identifier in stmf_ioctl.h 20099435STim.Szeto@Sun.COM */ 20109435STim.Szeto@Sun.COM char *protocol_ident[PROTOCOL_ANY] = { 20119435STim.Szeto@Sun.COM "Fibre Channel", 20129435STim.Szeto@Sun.COM "Parallel SCSI", 20139435STim.Szeto@Sun.COM "SSA", 20149435STim.Szeto@Sun.COM "IEEE_1394", 20159435STim.Szeto@Sun.COM "SRP", 20169435STim.Szeto@Sun.COM "iSCSI", 20179435STim.Szeto@Sun.COM "SAS", 20189435STim.Szeto@Sun.COM "ADT", 20199435STim.Szeto@Sun.COM "ATAPI", 20209435STim.Szeto@Sun.COM "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN" 20219435STim.Szeto@Sun.COM }; 20229435STim.Szeto@Sun.COM 20239435STim.Szeto@Sun.COM /* 20249435STim.Szeto@Sun.COM * Update the lun wait/run queue count 20259435STim.Szeto@Sun.COM */ 20269435STim.Szeto@Sun.COM static void 20279435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(scsi_task_t *task, void func()) 20289435STim.Szeto@Sun.COM { 20299435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 20309435STim.Szeto@Sun.COM kstat_io_t *kip; 20319435STim.Szeto@Sun.COM 20329435STim.Szeto@Sun.COM if (task->task_lu == dlun0) 20339435STim.Szeto@Sun.COM return; 20349435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 20359435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 20369435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 20379435STim.Szeto@Sun.COM if (kip != NULL) { 20389435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 20399435STim.Szeto@Sun.COM func(kip); 20409435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 20419435STim.Szeto@Sun.COM } 20429435STim.Szeto@Sun.COM } 20439435STim.Szeto@Sun.COM } 20449435STim.Szeto@Sun.COM 20459435STim.Szeto@Sun.COM /* 20469435STim.Szeto@Sun.COM * Update the target(lport) wait/run queue count 20479435STim.Szeto@Sun.COM */ 20489435STim.Szeto@Sun.COM static void 20499435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(scsi_task_t *task, void func()) 20509435STim.Szeto@Sun.COM { 20519435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 20529435STim.Szeto@Sun.COM kstat_io_t *kip; 20539435STim.Szeto@Sun.COM 20549435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 20559435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 20569435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 20579435STim.Szeto@Sun.COM if (kip != NULL) { 20589435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 20599435STim.Szeto@Sun.COM func(kip); 20609435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 20619435STim.Szeto@Sun.COM } 20629435STim.Szeto@Sun.COM } 20639435STim.Szeto@Sun.COM } 20649435STim.Szeto@Sun.COM 20659435STim.Szeto@Sun.COM static void 20669435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 20679435STim.Szeto@Sun.COM { 20689435STim.Szeto@Sun.COM stmf_i_local_port_t *ilp; 20699435STim.Szeto@Sun.COM kstat_io_t *kip; 20709435STim.Szeto@Sun.COM 20719435STim.Szeto@Sun.COM ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private; 20729435STim.Szeto@Sun.COM if (ilp != NULL && ilp->ilport_kstat_io != NULL) { 20739435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilp->ilport_kstat_io); 20749435STim.Szeto@Sun.COM if (kip != NULL) { 20759435STim.Szeto@Sun.COM mutex_enter(ilp->ilport_kstat_io->ks_lock); 20769435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 20779435STim.Szeto@Sun.COM mutex_exit(ilp->ilport_kstat_io->ks_lock); 20789435STim.Szeto@Sun.COM } 20799435STim.Szeto@Sun.COM } 20809435STim.Szeto@Sun.COM } 20819435STim.Szeto@Sun.COM 20829435STim.Szeto@Sun.COM static void 20839435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(scsi_task_t *task, stmf_data_buf_t *dbuf) 20849435STim.Szeto@Sun.COM { 20859435STim.Szeto@Sun.COM stmf_i_lu_t *ilu; 20869435STim.Szeto@Sun.COM kstat_io_t *kip; 20879435STim.Szeto@Sun.COM 20889435STim.Szeto@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 20899435STim.Szeto@Sun.COM if (ilu != NULL && ilu->ilu_kstat_io != NULL) { 20909435STim.Szeto@Sun.COM kip = KSTAT_IO_PTR(ilu->ilu_kstat_io); 20919435STim.Szeto@Sun.COM if (kip != NULL) { 20929435STim.Szeto@Sun.COM mutex_enter(ilu->ilu_kstat_io->ks_lock); 20939435STim.Szeto@Sun.COM STMF_UPDATE_KSTAT_IO(kip, dbuf); 20949435STim.Szeto@Sun.COM mutex_exit(ilu->ilu_kstat_io->ks_lock); 20959435STim.Szeto@Sun.COM } 20969435STim.Szeto@Sun.COM } 20979435STim.Szeto@Sun.COM } 20989435STim.Szeto@Sun.COM 20999435STim.Szeto@Sun.COM static void 21009435STim.Szeto@Sun.COM stmf_create_kstat_lu(stmf_i_lu_t *ilu) 21019435STim.Szeto@Sun.COM { 21029435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 21039435STim.Szeto@Sun.COM stmf_kstat_lu_info_t *ks_lu; 21049435STim.Szeto@Sun.COM 21059435STim.Szeto@Sun.COM /* create kstat lun info */ 21069435STim.Szeto@Sun.COM ks_lu = (stmf_kstat_lu_info_t *)kmem_zalloc(STMF_KSTAT_LU_SZ, 21079435STim.Szeto@Sun.COM KM_NOSLEEP); 21089435STim.Szeto@Sun.COM if (ks_lu == NULL) { 21099435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 21109435STim.Szeto@Sun.COM return; 21119435STim.Szeto@Sun.COM } 21129435STim.Szeto@Sun.COM 21139435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21149435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_%"PRIxPTR"", (uintptr_t)ilu); 21159435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_info = kstat_create(STMF_MODULE_NAME, 0, 21169435STim.Szeto@Sun.COM ks_nm, "misc", KSTAT_TYPE_NAMED, 21179435STim.Szeto@Sun.COM sizeof (stmf_kstat_lu_info_t) / sizeof (kstat_named_t), 21189435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 21199435STim.Szeto@Sun.COM kmem_free(ks_lu, STMF_KSTAT_LU_SZ); 21209435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu failed"); 21219435STim.Szeto@Sun.COM return; 21229435STim.Szeto@Sun.COM } 21239435STim.Szeto@Sun.COM 21249435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data_size = STMF_KSTAT_LU_SZ; 21259435STim.Szeto@Sun.COM ilu->ilu_kstat_info->ks_data = ks_lu; 21269435STim.Szeto@Sun.COM 21279435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_guid, "lun-guid", 21289435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21299435STim.Szeto@Sun.COM kstat_named_init(&ks_lu->i_lun_alias, "lun-alias", 21309435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21319435STim.Szeto@Sun.COM 21329435STim.Szeto@Sun.COM /* convert guid to hex string */ 21339435STim.Szeto@Sun.COM int i; 21349435STim.Szeto@Sun.COM uint8_t *p = ilu->ilu_lu->lu_id->ident; 21359435STim.Szeto@Sun.COM bzero(ilu->ilu_ascii_hex_guid, sizeof (ilu->ilu_ascii_hex_guid)); 21369435STim.Szeto@Sun.COM for (i = 0; i < STMF_GUID_INPUT / 2; i++) { 21379435STim.Szeto@Sun.COM (void) sprintf(&ilu->ilu_ascii_hex_guid[i * 2], "%02x", p[i]); 21389435STim.Szeto@Sun.COM } 21399435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_guid, 21409435STim.Szeto@Sun.COM (const char *)ilu->ilu_ascii_hex_guid); 21419435STim.Szeto@Sun.COM kstat_named_setstr(&ks_lu->i_lun_alias, 21429435STim.Szeto@Sun.COM (const char *)ilu->ilu_lu->lu_alias); 21439435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_info); 21449435STim.Szeto@Sun.COM 21459435STim.Szeto@Sun.COM /* create kstat lun io */ 21469435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21479435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_lu_io_%"PRIxPTR"", (uintptr_t)ilu); 21489435STim.Szeto@Sun.COM if ((ilu->ilu_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 21499435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 21509435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create lu_io failed"); 21519435STim.Szeto@Sun.COM return; 21529435STim.Szeto@Sun.COM } 21539435STim.Szeto@Sun.COM mutex_init(&ilu->ilu_kstat_lock, NULL, MUTEX_DRIVER, 0); 21549435STim.Szeto@Sun.COM ilu->ilu_kstat_io->ks_lock = &ilu->ilu_kstat_lock; 21559435STim.Szeto@Sun.COM kstat_install(ilu->ilu_kstat_io); 21569435STim.Szeto@Sun.COM } 21579435STim.Szeto@Sun.COM 21589435STim.Szeto@Sun.COM static void 21599435STim.Szeto@Sun.COM stmf_create_kstat_lport(stmf_i_local_port_t *ilport) 21609435STim.Szeto@Sun.COM { 21619435STim.Szeto@Sun.COM char ks_nm[KSTAT_STRLEN]; 21629435STim.Szeto@Sun.COM stmf_kstat_tgt_info_t *ks_tgt; 21639435STim.Szeto@Sun.COM int id, len; 21649435STim.Szeto@Sun.COM 21659435STim.Szeto@Sun.COM /* create kstat lport info */ 21669435STim.Szeto@Sun.COM ks_tgt = (stmf_kstat_tgt_info_t *)kmem_zalloc(STMF_KSTAT_TGT_SZ, 21679435STim.Szeto@Sun.COM KM_NOSLEEP); 21689435STim.Szeto@Sun.COM if (ks_tgt == NULL) { 21699435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kmem_zalloc failed"); 21709435STim.Szeto@Sun.COM return; 21719435STim.Szeto@Sun.COM } 21729435STim.Szeto@Sun.COM 21739435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 21749435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_%"PRIxPTR"", (uintptr_t)ilport); 21759435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_info = kstat_create(STMF_MODULE_NAME, 21769435STim.Szeto@Sun.COM 0, ks_nm, "misc", KSTAT_TYPE_NAMED, 21779435STim.Szeto@Sun.COM sizeof (stmf_kstat_tgt_info_t) / sizeof (kstat_named_t), 21789435STim.Szeto@Sun.COM KSTAT_FLAG_VIRTUAL)) == NULL) { 21799435STim.Szeto@Sun.COM kmem_free(ks_tgt, STMF_KSTAT_TGT_SZ); 21809435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target failed"); 21819435STim.Szeto@Sun.COM return; 21829435STim.Szeto@Sun.COM } 21839435STim.Szeto@Sun.COM 21849435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data_size = STMF_KSTAT_TGT_SZ; 21859435STim.Szeto@Sun.COM ilport->ilport_kstat_info->ks_data = ks_tgt; 21869435STim.Szeto@Sun.COM 21879435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_name, "target-name", 21889435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21899435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_tgt_alias, "target-alias", 21909435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21919435STim.Szeto@Sun.COM kstat_named_init(&ks_tgt->i_protocol, "protocol", 21929435STim.Szeto@Sun.COM KSTAT_DATA_STRING); 21939435STim.Szeto@Sun.COM 21949435STim.Szeto@Sun.COM /* ident might not be null terminated */ 21959435STim.Szeto@Sun.COM len = ilport->ilport_lport->lport_id->ident_length; 21969435STim.Szeto@Sun.COM bcopy(ilport->ilport_lport->lport_id->ident, 21979435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name, len); 21989435STim.Szeto@Sun.COM ilport->ilport_kstat_tgt_name[len + 1] = NULL; 21999435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_name, 22009435STim.Szeto@Sun.COM (const char *)ilport->ilport_kstat_tgt_name); 22019435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_tgt_alias, 22029435STim.Szeto@Sun.COM (const char *)ilport->ilport_lport->lport_alias); 22039435STim.Szeto@Sun.COM /* protocol */ 22049435STim.Szeto@Sun.COM if ((id = ilport->ilport_lport->lport_id->protocol_id) > PROTOCOL_ANY) { 22059435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: protocol_id out of bound"); 22069435STim.Szeto@Sun.COM id = PROTOCOL_ANY; 22079435STim.Szeto@Sun.COM } 22089435STim.Szeto@Sun.COM kstat_named_setstr(&ks_tgt->i_protocol, protocol_ident[id]); 22099435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_info); 22109435STim.Szeto@Sun.COM 22119435STim.Szeto@Sun.COM /* create kstat lport io */ 22129435STim.Szeto@Sun.COM bzero(ks_nm, sizeof (ks_nm)); 22139435STim.Szeto@Sun.COM (void) sprintf(ks_nm, "stmf_tgt_io_%"PRIxPTR"", (uintptr_t)ilport); 22149435STim.Szeto@Sun.COM if ((ilport->ilport_kstat_io = kstat_create(STMF_MODULE_NAME, 0, 22159435STim.Szeto@Sun.COM ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) { 22169435STim.Szeto@Sun.COM cmn_err(CE_WARN, "STMF: kstat_create target_io failed"); 22179435STim.Szeto@Sun.COM return; 22189435STim.Szeto@Sun.COM } 22199435STim.Szeto@Sun.COM mutex_init(&ilport->ilport_kstat_lock, NULL, MUTEX_DRIVER, 0); 22209435STim.Szeto@Sun.COM ilport->ilport_kstat_io->ks_lock = &ilport->ilport_kstat_lock; 22219435STim.Szeto@Sun.COM kstat_install(ilport->ilport_kstat_io); 22229435STim.Szeto@Sun.COM } 22239435STim.Szeto@Sun.COM 22247836SJohn.Forte@Sun.COM stmf_status_t 22257836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu) 22267836SJohn.Forte@Sun.COM { 22277836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 22287836SJohn.Forte@Sun.COM uint8_t *p1, *p2; 22297836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 22307836SJohn.Forte@Sun.COM stmf_id_data_t *luid; 22317836SJohn.Forte@Sun.COM 22327836SJohn.Forte@Sun.COM if ((lu->lu_id->ident_type != ID_TYPE_NAA) || 22337836SJohn.Forte@Sun.COM (lu->lu_id->ident_length != 16) || 22347836SJohn.Forte@Sun.COM ((lu->lu_id->ident[0] & 0xf0) != 0x60)) { 22357836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 22367836SJohn.Forte@Sun.COM } 22377836SJohn.Forte@Sun.COM p1 = &lu->lu_id->ident[0]; 22387836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22397836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 22407836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22417836SJohn.Forte@Sun.COM return (STMF_BUSY); 22427836SJohn.Forte@Sun.COM } 22437836SJohn.Forte@Sun.COM 22447836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 22457836SJohn.Forte@Sun.COM p2 = &ilu->ilu_lu->lu_id->ident[0]; 22467836SJohn.Forte@Sun.COM if (bcmp(p1, p2, 16) == 0) { 22477836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22487836SJohn.Forte@Sun.COM return (STMF_ALREADY); 22497836SJohn.Forte@Sun.COM } 22507836SJohn.Forte@Sun.COM } 22517836SJohn.Forte@Sun.COM 22527836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 22537836SJohn.Forte@Sun.COM luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 22547836SJohn.Forte@Sun.COM lu->lu_id->ident_length, lu->lu_id->ident); 22557836SJohn.Forte@Sun.COM if (luid) { 22567836SJohn.Forte@Sun.COM luid->id_pt_to_object = (void *)ilu; 22577836SJohn.Forte@Sun.COM ilu->ilu_luid = luid; 22587836SJohn.Forte@Sun.COM } 22597836SJohn.Forte@Sun.COM ilu->ilu_alias = NULL; 22607836SJohn.Forte@Sun.COM 22617836SJohn.Forte@Sun.COM ilu->ilu_next = stmf_state.stmf_ilulist; 22627836SJohn.Forte@Sun.COM ilu->ilu_prev = NULL; 22637836SJohn.Forte@Sun.COM if (ilu->ilu_next) 22647836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu; 22657836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu; 22667836SJohn.Forte@Sun.COM stmf_state.stmf_nlus++; 22677836SJohn.Forte@Sun.COM if (lu->lu_lp) { 22687836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 22697836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus++; 22707836SJohn.Forte@Sun.COM } 22717836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 22727836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl); 22739435STim.Szeto@Sun.COM stmf_create_kstat_lu(ilu); 22747836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22757836SJohn.Forte@Sun.COM 22767836SJohn.Forte@Sun.COM /* XXX we should probably check if this lu can be brought online */ 22777836SJohn.Forte@Sun.COM ilu->ilu_prev_state = STMF_STATE_ONLINE; 22787836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 22797836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 22807836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 22817836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci); 22827836SJohn.Forte@Sun.COM } 22837836SJohn.Forte@Sun.COM 22847836SJohn.Forte@Sun.COM /* XXX: Generate event */ 22857836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22867836SJohn.Forte@Sun.COM } 22877836SJohn.Forte@Sun.COM 22887836SJohn.Forte@Sun.COM stmf_status_t 22897836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu) 22907836SJohn.Forte@Sun.COM { 22917836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 22927836SJohn.Forte@Sun.COM 22937836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 22947836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 22957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22967836SJohn.Forte@Sun.COM return (STMF_BUSY); 22977836SJohn.Forte@Sun.COM } 22987836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu(lu); 22997836SJohn.Forte@Sun.COM if (ilu == NULL) { 23007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23017836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 23027836SJohn.Forte@Sun.COM } 23037836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 23047836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 23057836SJohn.Forte@Sun.COM while (ilu->ilu_flags & ILU_STALL_DEREGISTER) { 23067836SJohn.Forte@Sun.COM cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock); 23077836SJohn.Forte@Sun.COM } 23087836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 23097836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 23107836SJohn.Forte@Sun.COM 23117836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 23127836SJohn.Forte@Sun.COM do { 23137836SJohn.Forte@Sun.COM itask = nitask; 23147836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 23157836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 23167836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 23177836SJohn.Forte@Sun.COM } while (nitask != NULL); 23187836SJohn.Forte@Sun.COM 23197836SJohn.Forte@Sun.COM ilu->ilu_tasks = ilu->ilu_free_tasks = NULL; 23207836SJohn.Forte@Sun.COM ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0; 23217836SJohn.Forte@Sun.COM } 23227836SJohn.Forte@Sun.COM 23237836SJohn.Forte@Sun.COM if (ilu->ilu_next) 23247836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu->ilu_prev; 23257836SJohn.Forte@Sun.COM if (ilu->ilu_prev) 23267836SJohn.Forte@Sun.COM ilu->ilu_prev->ilu_next = ilu->ilu_next; 23277836SJohn.Forte@Sun.COM else 23287836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu->ilu_next; 23297836SJohn.Forte@Sun.COM stmf_state.stmf_nlus--; 23307836SJohn.Forte@Sun.COM 23317836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_draining) { 23327836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 23337836SJohn.Forte@Sun.COM } 23347836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_timing) { 23357836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 23367836SJohn.Forte@Sun.COM } 23377836SJohn.Forte@Sun.COM if (lu->lu_lp) { 23387836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 23397836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus--; 23407836SJohn.Forte@Sun.COM } 23417836SJohn.Forte@Sun.COM if (ilu->ilu_luid) { 23427836SJohn.Forte@Sun.COM ((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object = 23437836SJohn.Forte@Sun.COM NULL; 23447836SJohn.Forte@Sun.COM ilu->ilu_luid = NULL; 23457836SJohn.Forte@Sun.COM } 23467836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl); 23477836SJohn.Forte@Sun.COM } else { 23487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23497836SJohn.Forte@Sun.COM return (STMF_BUSY); 23507836SJohn.Forte@Sun.COM } 23519435STim.Szeto@Sun.COM if (ilu->ilu_kstat_info) { 23529435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_info); 23539435STim.Szeto@Sun.COM } 23549435STim.Szeto@Sun.COM if (ilu->ilu_kstat_io) { 23559435STim.Szeto@Sun.COM kstat_delete(ilu->ilu_kstat_io); 23569435STim.Szeto@Sun.COM mutex_destroy(&ilu->ilu_kstat_lock); 23579435STim.Szeto@Sun.COM } 23587836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23597836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 23607836SJohn.Forte@Sun.COM } 23617836SJohn.Forte@Sun.COM 23627836SJohn.Forte@Sun.COM stmf_status_t 23637836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport) 23647836SJohn.Forte@Sun.COM { 23657836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 23667836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 23677836SJohn.Forte@Sun.COM int start_workers = 0; 23687836SJohn.Forte@Sun.COM 23697836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 23707836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 23717836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23727836SJohn.Forte@Sun.COM return (STMF_BUSY); 23737836SJohn.Forte@Sun.COM } 23747836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 23757836SJohn.Forte@Sun.COM rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL); 23767836SJohn.Forte@Sun.COM 23777836SJohn.Forte@Sun.COM ilport->ilport_next = stmf_state.stmf_ilportlist; 23787836SJohn.Forte@Sun.COM ilport->ilport_prev = NULL; 23797836SJohn.Forte@Sun.COM if (ilport->ilport_next) 23807836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport; 23817836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport; 23827836SJohn.Forte@Sun.COM stmf_state.stmf_nlports++; 23837836SJohn.Forte@Sun.COM if (lport->lport_pp) { 23847836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 23857836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps++; 23867836SJohn.Forte@Sun.COM } 23877836SJohn.Forte@Sun.COM ilport->ilport_tg = 23887836SJohn.Forte@Sun.COM stmf_lookup_group_for_target(lport->lport_id->ident, 23898662SJordan.Vaughan@Sun.com lport->lport_id->ident_length); 23907836SJohn.Forte@Sun.COM ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1); 23917836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl); 23929435STim.Szeto@Sun.COM stmf_create_kstat_lport(ilport); 23937836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) { 23947836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLING; 23957836SJohn.Forte@Sun.COM start_workers = 1; 23967836SJohn.Forte@Sun.COM } 23977836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 23987836SJohn.Forte@Sun.COM 23997836SJohn.Forte@Sun.COM if (start_workers) 24007836SJohn.Forte@Sun.COM stmf_worker_init(); 24017836SJohn.Forte@Sun.COM 24027836SJohn.Forte@Sun.COM /* XXX we should probably check if this lport can be brought online */ 24037836SJohn.Forte@Sun.COM ilport->ilport_prev_state = STMF_STATE_ONLINE; 24047836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 24057836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 24067836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 24077836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci); 24087836SJohn.Forte@Sun.COM } 24097836SJohn.Forte@Sun.COM 24107836SJohn.Forte@Sun.COM /* XXX: Generate event */ 24117836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 24127836SJohn.Forte@Sun.COM } 24137836SJohn.Forte@Sun.COM 24147836SJohn.Forte@Sun.COM stmf_status_t 24157836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport) 24167836SJohn.Forte@Sun.COM { 24177836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 24187836SJohn.Forte@Sun.COM 24197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 24207836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 24217836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24227836SJohn.Forte@Sun.COM return (STMF_BUSY); 24237836SJohn.Forte@Sun.COM } 24247836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 24257836SJohn.Forte@Sun.COM if (ilport->ilport_nsessions == 0) { 24267836SJohn.Forte@Sun.COM if (ilport->ilport_next) 24277836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport->ilport_prev; 24287836SJohn.Forte@Sun.COM if (ilport->ilport_prev) 24297836SJohn.Forte@Sun.COM ilport->ilport_prev->ilport_next = ilport->ilport_next; 24307836SJohn.Forte@Sun.COM else 24317836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport->ilport_next; 24327836SJohn.Forte@Sun.COM rw_destroy(&ilport->ilport_lock); 24337836SJohn.Forte@Sun.COM stmf_state.stmf_nlports--; 24347836SJohn.Forte@Sun.COM if (lport->lport_pp) { 24357836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 24367836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps--; 24377836SJohn.Forte@Sun.COM } 24387836SJohn.Forte@Sun.COM ilport->ilport_tg = NULL; 24397836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl); 24407836SJohn.Forte@Sun.COM } else { 24417836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24427836SJohn.Forte@Sun.COM return (STMF_BUSY); 24437836SJohn.Forte@Sun.COM } 24449435STim.Szeto@Sun.COM if (ilport->ilport_kstat_info) { 24459435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_info); 24469435STim.Szeto@Sun.COM } 24479435STim.Szeto@Sun.COM if (ilport->ilport_kstat_io) { 24489435STim.Szeto@Sun.COM kstat_delete(ilport->ilport_kstat_io); 24499435STim.Szeto@Sun.COM mutex_destroy(&ilport->ilport_kstat_lock); 24509435STim.Szeto@Sun.COM } 24517836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 24527836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 24537836SJohn.Forte@Sun.COM } 24547836SJohn.Forte@Sun.COM 24557836SJohn.Forte@Sun.COM /* 24567836SJohn.Forte@Sun.COM * Port provider has to make sure that register/deregister session and 24577836SJohn.Forte@Sun.COM * port are serialized calls. 24587836SJohn.Forte@Sun.COM */ 24597836SJohn.Forte@Sun.COM stmf_status_t 24607836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 24617836SJohn.Forte@Sun.COM { 24627836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 24637836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 24647836SJohn.Forte@Sun.COM lport->lport_stmf_private; 24657836SJohn.Forte@Sun.COM uint8_t lun[8]; 24667836SJohn.Forte@Sun.COM 24677836SJohn.Forte@Sun.COM /* 24687836SJohn.Forte@Sun.COM * Port state has to be online to register a scsi session. It is 24697836SJohn.Forte@Sun.COM * possible that we started an offline operation and a new SCSI 24707836SJohn.Forte@Sun.COM * session started at the same time (in that case also we are going 24717836SJohn.Forte@Sun.COM * to fail the registeration). But any other state is simply 24727836SJohn.Forte@Sun.COM * a bad port provider implementation. 24737836SJohn.Forte@Sun.COM */ 24747836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 24757836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 24767836SJohn.Forte@Sun.COM stmf_trace(lport->lport_alias, "Port is trying to " 24777836SJohn.Forte@Sun.COM "register a session while the state is neither " 24787836SJohn.Forte@Sun.COM "online nor offlining"); 24797836SJohn.Forte@Sun.COM } 24807836SJohn.Forte@Sun.COM return (STMF_FAILURE); 24817836SJohn.Forte@Sun.COM } 24827836SJohn.Forte@Sun.COM bzero(lun, 8); 24837836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 24847836SJohn.Forte@Sun.COM iss->iss_flags |= ISS_BEING_CREATED; 24857836SJohn.Forte@Sun.COM 24867836SJohn.Forte@Sun.COM /* sessions use the ilport_lock. No separate lock is required */ 24877836SJohn.Forte@Sun.COM iss->iss_lockp = &ilport->ilport_lock; 24887836SJohn.Forte@Sun.COM (void) stmf_session_create_lun_map(ilport, iss); 24897836SJohn.Forte@Sun.COM 24907836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 24917836SJohn.Forte@Sun.COM ilport->ilport_nsessions++; 24927836SJohn.Forte@Sun.COM iss->iss_next = ilport->ilport_ss_list; 24937836SJohn.Forte@Sun.COM ilport->ilport_ss_list = iss; 24947836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 24957836SJohn.Forte@Sun.COM 24967836SJohn.Forte@Sun.COM iss->iss_creation_time = ddi_get_time(); 24977836SJohn.Forte@Sun.COM ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1); 24987836SJohn.Forte@Sun.COM iss->iss_flags &= ~ISS_BEING_CREATED; 24998859STim.Szeto@Sun.COM DTRACE_PROBE2(session__online, stmf_local_port_t *, lport, 25008859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 25017836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 25027836SJohn.Forte@Sun.COM } 25037836SJohn.Forte@Sun.COM 25047836SJohn.Forte@Sun.COM void 25057836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 25067836SJohn.Forte@Sun.COM { 25077836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 25088662SJordan.Vaughan@Sun.com lport->lport_stmf_private; 25097836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss, **ppss; 25107836SJohn.Forte@Sun.COM int found = 0; 25117836SJohn.Forte@Sun.COM 25128859STim.Szeto@Sun.COM DTRACE_PROBE2(session__offline, stmf_local_port_t *, lport, 25138859STim.Szeto@Sun.COM stmf_scsi_session_t *, ss); 25148859STim.Szeto@Sun.COM 25157836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 25167836SJohn.Forte@Sun.COM if (ss->ss_rport_alias) { 25177836SJohn.Forte@Sun.COM ss->ss_rport_alias = NULL; 25187836SJohn.Forte@Sun.COM } 25197836SJohn.Forte@Sun.COM 25207836SJohn.Forte@Sun.COM try_dereg_ss_again: 25217836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 25227836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 25238662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 25247836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_EVENT_ACTIVE) { 25257836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25267836SJohn.Forte@Sun.COM delay(1); 25277836SJohn.Forte@Sun.COM goto try_dereg_ss_again; 25287836SJohn.Forte@Sun.COM } 25297836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25307836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 25317836SJohn.Forte@Sun.COM for (ppss = &ilport->ilport_ss_list; *ppss != NULL; 25327836SJohn.Forte@Sun.COM ppss = &((*ppss)->iss_next)) { 25337836SJohn.Forte@Sun.COM if (iss == (*ppss)) { 25347836SJohn.Forte@Sun.COM *ppss = (*ppss)->iss_next; 25357836SJohn.Forte@Sun.COM found = 1; 25367836SJohn.Forte@Sun.COM break; 25377836SJohn.Forte@Sun.COM } 25387836SJohn.Forte@Sun.COM } 25397836SJohn.Forte@Sun.COM if (!found) { 25407836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "Deregister session called for non existent" 25417836SJohn.Forte@Sun.COM " session"); 25427836SJohn.Forte@Sun.COM } 25437836SJohn.Forte@Sun.COM ilport->ilport_nsessions--; 25447836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25457836SJohn.Forte@Sun.COM 25467836SJohn.Forte@Sun.COM (void) stmf_session_destroy_lun_map(ilport, iss); 25477836SJohn.Forte@Sun.COM } 25487836SJohn.Forte@Sun.COM 25497836SJohn.Forte@Sun.COM stmf_i_scsi_session_t * 25507836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked) 25517836SJohn.Forte@Sun.COM { 25527836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 25537836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 25547836SJohn.Forte@Sun.COM 25557836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 25567836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 25578662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 25587836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 25597836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 25608662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 25617836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_session_id == session_id) { 25627836SJohn.Forte@Sun.COM if (!stay_locked) 25637836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25657836SJohn.Forte@Sun.COM return (iss); 25667836SJohn.Forte@Sun.COM } 25677836SJohn.Forte@Sun.COM } 25687836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 25697836SJohn.Forte@Sun.COM } 25707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 25717836SJohn.Forte@Sun.COM return (NULL); 25727836SJohn.Forte@Sun.COM } 25737836SJohn.Forte@Sun.COM 25747836SJohn.Forte@Sun.COM void 25757836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl) 25767836SJohn.Forte@Sun.COM { 25777836SJohn.Forte@Sun.COM stmf_itl_data_t **itlpp; 25787836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 25797836SJohn.Forte@Sun.COM 25807836SJohn.Forte@Sun.COM ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED); 25817836SJohn.Forte@Sun.COM 25827836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 25837836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25847836SJohn.Forte@Sun.COM for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL; 25858662SJordan.Vaughan@Sun.com itlpp = &(*itlpp)->itl_next) { 25867836SJohn.Forte@Sun.COM if ((*itlpp) == itl) 25877836SJohn.Forte@Sun.COM break; 25887836SJohn.Forte@Sun.COM } 25897836SJohn.Forte@Sun.COM ASSERT((*itlpp) != NULL); 25907836SJohn.Forte@Sun.COM *itlpp = itl->itl_next; 25917836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25927836SJohn.Forte@Sun.COM lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle, 25938662SJordan.Vaughan@Sun.com (uint32_t)itl->itl_hdlrm_reason); 25947836SJohn.Forte@Sun.COM kmem_free(itl, sizeof (*itl)); 25957836SJohn.Forte@Sun.COM } 25967836SJohn.Forte@Sun.COM 25977836SJohn.Forte@Sun.COM stmf_status_t 25987836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun, 25997836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 26007836SJohn.Forte@Sun.COM { 26017836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 26027836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 26037836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 26047836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 26057836SJohn.Forte@Sun.COM uint16_t n; 26067836SJohn.Forte@Sun.COM 26077836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 26087836SJohn.Forte@Sun.COM if (ss == NULL) { 26097836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 26107836SJohn.Forte@Sun.COM if (iss == NULL) 26117836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 26127836SJohn.Forte@Sun.COM } else { 26137836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 26147836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 26157836SJohn.Forte@Sun.COM } 26167836SJohn.Forte@Sun.COM 26177836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 26187836SJohn.Forte@Sun.COM lun_map_ent = (stmf_lun_map_ent_t *) 26198662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 26207836SJohn.Forte@Sun.COM if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) { 26217836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26227836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 26237836SJohn.Forte@Sun.COM } 26247836SJohn.Forte@Sun.COM if (lun_map_ent->ent_itl_datap != NULL) { 26257836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26267836SJohn.Forte@Sun.COM return (STMF_ALREADY); 26277836SJohn.Forte@Sun.COM } 26287836SJohn.Forte@Sun.COM 26297836SJohn.Forte@Sun.COM itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP); 26307836SJohn.Forte@Sun.COM if (itl == NULL) { 26317836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26327836SJohn.Forte@Sun.COM return (STMF_ALLOC_FAILURE); 26337836SJohn.Forte@Sun.COM } 26347836SJohn.Forte@Sun.COM 26357836SJohn.Forte@Sun.COM itl->itl_counter = 1; 26367836SJohn.Forte@Sun.COM itl->itl_lun = n; 26377836SJohn.Forte@Sun.COM itl->itl_handle = itl_handle; 26387836SJohn.Forte@Sun.COM itl->itl_session = iss; 26397836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 26407836SJohn.Forte@Sun.COM itl->itl_next = ilu->ilu_itl_list; 26417836SJohn.Forte@Sun.COM ilu->ilu_itl_list = itl; 26427836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 26437836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap = itl; 26447836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 26457836SJohn.Forte@Sun.COM 26467836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 26477836SJohn.Forte@Sun.COM } 26487836SJohn.Forte@Sun.COM 26497836SJohn.Forte@Sun.COM void 26507836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason) 26517836SJohn.Forte@Sun.COM { 26527836SJohn.Forte@Sun.COM uint8_t old, new; 26537836SJohn.Forte@Sun.COM 26547836SJohn.Forte@Sun.COM do { 26557836SJohn.Forte@Sun.COM old = new = itl->itl_flags; 26567836SJohn.Forte@Sun.COM if (old & STMF_ITL_BEING_TERMINATED) 26577836SJohn.Forte@Sun.COM return; 26587836SJohn.Forte@Sun.COM new |= STMF_ITL_BEING_TERMINATED; 26597836SJohn.Forte@Sun.COM } while (atomic_cas_8(&itl->itl_flags, old, new) != old); 26607836SJohn.Forte@Sun.COM itl->itl_hdlrm_reason = hdlrm_reason; 26617836SJohn.Forte@Sun.COM 26627836SJohn.Forte@Sun.COM ASSERT(itl->itl_counter); 26637836SJohn.Forte@Sun.COM 26647836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itl->itl_counter, -1)) 26657836SJohn.Forte@Sun.COM return; 26667836SJohn.Forte@Sun.COM 26677836SJohn.Forte@Sun.COM drv_usecwait(10); 26687836SJohn.Forte@Sun.COM if (itl->itl_counter) 26697836SJohn.Forte@Sun.COM return; 26707836SJohn.Forte@Sun.COM 26717836SJohn.Forte@Sun.COM stmf_release_itl_handle(lu, itl); 26727836SJohn.Forte@Sun.COM } 26737836SJohn.Forte@Sun.COM 26747836SJohn.Forte@Sun.COM stmf_status_t 26757836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu) 26767836SJohn.Forte@Sun.COM { 26777836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 26787836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 26797836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 26807836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 26817836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 26827836SJohn.Forte@Sun.COM uint32_t nmaps, nu; 26837836SJohn.Forte@Sun.COM stmf_itl_data_t **itl_list; 26847836SJohn.Forte@Sun.COM int i; 26857836SJohn.Forte@Sun.COM 26867836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 26877836SJohn.Forte@Sun.COM 26887836SJohn.Forte@Sun.COM dereg_itl_start:; 26897836SJohn.Forte@Sun.COM nmaps = ilu->ilu_ref_cnt; 26907836SJohn.Forte@Sun.COM if (nmaps == 0) 26917836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 26927836SJohn.Forte@Sun.COM itl_list = (stmf_itl_data_t **)kmem_zalloc( 26938662SJordan.Vaughan@Sun.com nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP); 26947836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 26957836SJohn.Forte@Sun.COM if (nmaps != ilu->ilu_ref_cnt) { 26967836SJohn.Forte@Sun.COM /* Something changed, start all over */ 26977836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 26987836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 26997836SJohn.Forte@Sun.COM goto dereg_itl_start; 27007836SJohn.Forte@Sun.COM } 27017836SJohn.Forte@Sun.COM nu = 0; 27027836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 27038662SJordan.Vaughan@Sun.com ilport = ilport->ilport_next) { 27047836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 27057836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 27068662SJordan.Vaughan@Sun.com iss = iss->iss_next) { 27077836SJohn.Forte@Sun.COM lm = iss->iss_sm; 27087836SJohn.Forte@Sun.COM if (!lm) 27097836SJohn.Forte@Sun.COM continue; 27107836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 27117836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 27127836SJohn.Forte@Sun.COM continue; 27137836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 27147836SJohn.Forte@Sun.COM if ((ent->ent_lu == lu) && 27158662SJordan.Vaughan@Sun.com (ent->ent_itl_datap)) { 27167836SJohn.Forte@Sun.COM itl_list[nu++] = ent->ent_itl_datap; 27177836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 27187836SJohn.Forte@Sun.COM if (nu == nmaps) { 27197836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 27207836SJohn.Forte@Sun.COM goto dai_scan_done; 27217836SJohn.Forte@Sun.COM } 27227836SJohn.Forte@Sun.COM } 27237836SJohn.Forte@Sun.COM } /* lun table for a session */ 27247836SJohn.Forte@Sun.COM } /* sessions */ 27257836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 27267836SJohn.Forte@Sun.COM } /* ports */ 27277836SJohn.Forte@Sun.COM 27287836SJohn.Forte@Sun.COM dai_scan_done: 27297836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 27307836SJohn.Forte@Sun.COM 27317836SJohn.Forte@Sun.COM for (i = 0; i < nu; i++) { 27327836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl_list[i], 27338662SJordan.Vaughan@Sun.com STMF_ITL_REASON_DEREG_REQUEST); 27347836SJohn.Forte@Sun.COM } 27357836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 27367836SJohn.Forte@Sun.COM 27377836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 27387836SJohn.Forte@Sun.COM } 27397836SJohn.Forte@Sun.COM 27407836SJohn.Forte@Sun.COM stmf_status_t 27417836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun, 27427836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 27437836SJohn.Forte@Sun.COM { 27447836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 27457836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 27467836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 27477836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 27487836SJohn.Forte@Sun.COM int i; 27497836SJohn.Forte@Sun.COM uint16_t n; 27507836SJohn.Forte@Sun.COM 27517836SJohn.Forte@Sun.COM if (ss == NULL) { 27527836SJohn.Forte@Sun.COM if (session_id == STMF_SESSION_ID_NONE) 27537836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 27547836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 27557836SJohn.Forte@Sun.COM if (iss == NULL) 27567836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27577836SJohn.Forte@Sun.COM } else { 27587836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 27597836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 27607836SJohn.Forte@Sun.COM } 27617836SJohn.Forte@Sun.COM lm = iss->iss_sm; 27627836SJohn.Forte@Sun.COM if (lm == NULL) { 27637836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27647836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27657836SJohn.Forte@Sun.COM } 27667836SJohn.Forte@Sun.COM 27677836SJohn.Forte@Sun.COM if (lun) { 27687836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 27697836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 27708662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 27717836SJohn.Forte@Sun.COM } else { 27727836SJohn.Forte@Sun.COM if (itl_handle == NULL) { 27737836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27747836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 27757836SJohn.Forte@Sun.COM } 27767836SJohn.Forte@Sun.COM ent = NULL; 27777836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 27787836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 27797836SJohn.Forte@Sun.COM continue; 27807836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 27817836SJohn.Forte@Sun.COM if (ent->ent_itl_datap && 27827836SJohn.Forte@Sun.COM (ent->ent_itl_datap->itl_handle == itl_handle)) { 27837836SJohn.Forte@Sun.COM break; 27847836SJohn.Forte@Sun.COM } 27857836SJohn.Forte@Sun.COM } 27867836SJohn.Forte@Sun.COM } 27877836SJohn.Forte@Sun.COM if ((ent == NULL) || (ent->ent_lu != lu) || 27888662SJordan.Vaughan@Sun.com (ent->ent_itl_datap == NULL)) { 27897836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27907836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 27917836SJohn.Forte@Sun.COM } 27927836SJohn.Forte@Sun.COM itl = ent->ent_itl_datap; 27937836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 27947836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 27957836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST); 27967836SJohn.Forte@Sun.COM 27977836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 27987836SJohn.Forte@Sun.COM } 27997836SJohn.Forte@Sun.COM 28007836SJohn.Forte@Sun.COM stmf_status_t 28017836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss, 28027836SJohn.Forte@Sun.COM uint64_t session_id, void **itl_handle_retp) 28037836SJohn.Forte@Sun.COM { 28047836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 28057836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 28067836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 28077836SJohn.Forte@Sun.COM stmf_status_t ret; 28087836SJohn.Forte@Sun.COM int i; 28097836SJohn.Forte@Sun.COM uint16_t n; 28107836SJohn.Forte@Sun.COM 28117836SJohn.Forte@Sun.COM if (ss == NULL) { 28127836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 28137836SJohn.Forte@Sun.COM if (iss == NULL) 28147836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 28157836SJohn.Forte@Sun.COM } else { 28167836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 28177836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 28187836SJohn.Forte@Sun.COM } 28197836SJohn.Forte@Sun.COM 28207836SJohn.Forte@Sun.COM ent = NULL; 28217836SJohn.Forte@Sun.COM if (lun == NULL) { 28227836SJohn.Forte@Sun.COM lm = iss->iss_sm; 28237836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 28247836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 28257836SJohn.Forte@Sun.COM continue; 28267836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 28277836SJohn.Forte@Sun.COM if (ent->ent_lu == lu) 28287836SJohn.Forte@Sun.COM break; 28297836SJohn.Forte@Sun.COM } 28307836SJohn.Forte@Sun.COM } else { 28317836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 28327836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 28338662SJordan.Vaughan@Sun.com stmf_get_ent_from_map(iss->iss_sm, n); 28347836SJohn.Forte@Sun.COM if (lu && (ent->ent_lu != lu)) 28357836SJohn.Forte@Sun.COM ent = NULL; 28367836SJohn.Forte@Sun.COM } 28377836SJohn.Forte@Sun.COM if (ent && ent->ent_itl_datap) { 28387836SJohn.Forte@Sun.COM *itl_handle_retp = ent->ent_itl_datap->itl_handle; 28397836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 28407836SJohn.Forte@Sun.COM } else { 28417836SJohn.Forte@Sun.COM ret = STMF_NOT_FOUND; 28427836SJohn.Forte@Sun.COM } 28437836SJohn.Forte@Sun.COM 28447836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 28457836SJohn.Forte@Sun.COM return (ret); 28467836SJohn.Forte@Sun.COM } 28477836SJohn.Forte@Sun.COM 28487836SJohn.Forte@Sun.COM stmf_data_buf_t * 28497836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 28507836SJohn.Forte@Sun.COM uint32_t flags) 28517836SJohn.Forte@Sun.COM { 28527836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 28537836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 28547836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 28557836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 28567836SJohn.Forte@Sun.COM uint8_t ndx; 28577836SJohn.Forte@Sun.COM 28587836SJohn.Forte@Sun.COM ndx = stmf_first_zero[itask->itask_allocated_buf_map]; 28597836SJohn.Forte@Sun.COM if (ndx == 0xff) 28607836SJohn.Forte@Sun.COM return (NULL); 28617836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf( 28627836SJohn.Forte@Sun.COM task, size, pminsize, flags); 28637836SJohn.Forte@Sun.COM if (dbuf) { 28647836SJohn.Forte@Sun.COM task->task_cur_nbufs++; 28657836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map |= (1 << ndx); 28667836SJohn.Forte@Sun.COM dbuf->db_handle = ndx; 28677836SJohn.Forte@Sun.COM return (dbuf); 28687836SJohn.Forte@Sun.COM } 28697836SJohn.Forte@Sun.COM 28707836SJohn.Forte@Sun.COM return (NULL); 28717836SJohn.Forte@Sun.COM } 28727836SJohn.Forte@Sun.COM 28737836SJohn.Forte@Sun.COM void 28747836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf) 28757836SJohn.Forte@Sun.COM { 28767836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 28777836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 28787836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 28797836SJohn.Forte@Sun.COM 28807836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle); 28817836SJohn.Forte@Sun.COM task->task_cur_nbufs--; 28827836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf); 28837836SJohn.Forte@Sun.COM } 28847836SJohn.Forte@Sun.COM 28857836SJohn.Forte@Sun.COM stmf_data_buf_t * 28867836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h) 28877836SJohn.Forte@Sun.COM { 28887836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 28897836SJohn.Forte@Sun.COM 28907836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 28917836SJohn.Forte@Sun.COM if (h > 3) 28927836SJohn.Forte@Sun.COM return (NULL); 28937836SJohn.Forte@Sun.COM return (itask->itask_dbufs[h]); 28947836SJohn.Forte@Sun.COM } 28957836SJohn.Forte@Sun.COM 28967836SJohn.Forte@Sun.COM /* ARGSUSED */ 28977836SJohn.Forte@Sun.COM struct scsi_task * 28987836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss, 28997836SJohn.Forte@Sun.COM uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id) 29007836SJohn.Forte@Sun.COM { 29017836SJohn.Forte@Sun.COM stmf_lu_t *lu; 29027836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 29037836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 29047836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 29057836SJohn.Forte@Sun.COM stmf_i_scsi_task_t **ppitask; 29067836SJohn.Forte@Sun.COM scsi_task_t *task; 29077836SJohn.Forte@Sun.COM uint64_t *p; 29087836SJohn.Forte@Sun.COM uint8_t *l; 29097836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 29107836SJohn.Forte@Sun.COM uint16_t cdb_length; 29117836SJohn.Forte@Sun.COM uint16_t luNbr; 29127836SJohn.Forte@Sun.COM uint8_t new_task = 0; 29137836SJohn.Forte@Sun.COM 29147836SJohn.Forte@Sun.COM /* 29157836SJohn.Forte@Sun.COM * We allocate 7 extra bytes for CDB to provide a cdb pointer which 29167836SJohn.Forte@Sun.COM * is guaranteed to be 8 byte aligned. Some LU providers like OSD 29177836SJohn.Forte@Sun.COM * depend upon this alignment. 29187836SJohn.Forte@Sun.COM */ 29197836SJohn.Forte@Sun.COM if (cdb_length_in >= 16) 29207836SJohn.Forte@Sun.COM cdb_length = cdb_length_in + 7; 29217836SJohn.Forte@Sun.COM else 29227836SJohn.Forte@Sun.COM cdb_length = 16 + 7; 29237836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 29247836SJohn.Forte@Sun.COM luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 29257836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 29267836SJohn.Forte@Sun.COM lun_map_ent = 29277836SJohn.Forte@Sun.COM (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr); 29287836SJohn.Forte@Sun.COM if (!lun_map_ent) { 29297836SJohn.Forte@Sun.COM lu = dlun0; 29307836SJohn.Forte@Sun.COM } else { 29317836SJohn.Forte@Sun.COM lu = lun_map_ent->ent_lu; 29327836SJohn.Forte@Sun.COM } 29337836SJohn.Forte@Sun.COM ilu = lu->lu_stmf_private; 29347836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 29357836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29367836SJohn.Forte@Sun.COM return (NULL); 29377836SJohn.Forte@Sun.COM } 29387836SJohn.Forte@Sun.COM do { 29397836SJohn.Forte@Sun.COM if (ilu->ilu_free_tasks == NULL) { 29407836SJohn.Forte@Sun.COM new_task = 1; 29417836SJohn.Forte@Sun.COM break; 29427836SJohn.Forte@Sun.COM } 29437836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 29447836SJohn.Forte@Sun.COM for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) && 29457836SJohn.Forte@Sun.COM ((*ppitask)->itask_cdb_buf_size < cdb_length); 29468662SJordan.Vaughan@Sun.com ppitask = &((*ppitask)->itask_lu_free_next)) 29478662SJordan.Vaughan@Sun.com ; 29487836SJohn.Forte@Sun.COM if (*ppitask) { 29497836SJohn.Forte@Sun.COM itask = *ppitask; 29507836SJohn.Forte@Sun.COM *ppitask = (*ppitask)->itask_lu_free_next; 29517836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 29527836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free) 29537836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 29547836SJohn.Forte@Sun.COM } else { 29557836SJohn.Forte@Sun.COM new_task = 1; 29567836SJohn.Forte@Sun.COM } 29577836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 29587836SJohn.Forte@Sun.COM /* CONSTCOND */ 29597836SJohn.Forte@Sun.COM } while (0); 29607836SJohn.Forte@Sun.COM 29617836SJohn.Forte@Sun.COM if (!new_task) { 29627836SJohn.Forte@Sun.COM task = itask->itask_task; 29637836SJohn.Forte@Sun.COM task->task_timeout = 0; 29647836SJohn.Forte@Sun.COM p = (uint64_t *)&task->task_flags; 29657836SJohn.Forte@Sun.COM *p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0; 29667836SJohn.Forte@Sun.COM itask->itask_ncmds = 0; 29677836SJohn.Forte@Sun.COM } else { 29687836SJohn.Forte@Sun.COM task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK, 29697836SJohn.Forte@Sun.COM cdb_length, AF_FORCE_NOSLEEP); 29707836SJohn.Forte@Sun.COM if (task == NULL) { 29717836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 29727836SJohn.Forte@Sun.COM return (NULL); 29737836SJohn.Forte@Sun.COM } 29747836SJohn.Forte@Sun.COM task->task_lu = lu; 29757836SJohn.Forte@Sun.COM l = task->task_lun_no; 29767836SJohn.Forte@Sun.COM l[0] = lun[0]; 29777836SJohn.Forte@Sun.COM l[1] = lun[1]; 29787836SJohn.Forte@Sun.COM l[2] = lun[2]; 29797836SJohn.Forte@Sun.COM l[3] = lun[3]; 29807836SJohn.Forte@Sun.COM l[4] = lun[4]; 29817836SJohn.Forte@Sun.COM l[5] = lun[5]; 29827836SJohn.Forte@Sun.COM l[6] = lun[6]; 29837836SJohn.Forte@Sun.COM l[7] = lun[7]; 29847836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)task->task_port_private; 29857836SJohn.Forte@Sun.COM if ((ulong_t)(task->task_cdb) & 7ul) { 29867836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)(((ulong_t) 29877836SJohn.Forte@Sun.COM (task->task_cdb) + 7ul) & ~(7ul)); 29887836SJohn.Forte@Sun.COM } 29897836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 29907836SJohn.Forte@Sun.COM itask->itask_cdb_buf_size = cdb_length; 29917836SJohn.Forte@Sun.COM } 29927836SJohn.Forte@Sun.COM task->task_session = ss; 29937836SJohn.Forte@Sun.COM task->task_lport = lport; 29947836SJohn.Forte@Sun.COM task->task_cdb_length = cdb_length_in; 29957836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_TRANSITION; 29967836SJohn.Forte@Sun.COM 29977836SJohn.Forte@Sun.COM if (new_task) { 29987836SJohn.Forte@Sun.COM if (lu->lu_task_alloc(task) != STMF_SUCCESS) { 29997836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30007836SJohn.Forte@Sun.COM stmf_free(task); 30017836SJohn.Forte@Sun.COM return (NULL); 30027836SJohn.Forte@Sun.COM } 30037836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30047836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 30057836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30067836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30077836SJohn.Forte@Sun.COM stmf_free(task); 30087836SJohn.Forte@Sun.COM return (NULL); 30097836SJohn.Forte@Sun.COM } 30107836SJohn.Forte@Sun.COM itask->itask_lu_next = ilu->ilu_tasks; 30117836SJohn.Forte@Sun.COM if (ilu->ilu_tasks) 30127836SJohn.Forte@Sun.COM ilu->ilu_tasks->itask_lu_prev = itask; 30137836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask; 30147836SJohn.Forte@Sun.COM /* kmem_zalloc automatically makes itask->itask_lu_prev NULL */ 30157836SJohn.Forte@Sun.COM ilu->ilu_ntasks++; 30167836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30177836SJohn.Forte@Sun.COM } 30187836SJohn.Forte@Sun.COM 30197836SJohn.Forte@Sun.COM itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr; 30207836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, 1); 30217836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 30227836SJohn.Forte@Sun.COM 30237836SJohn.Forte@Sun.COM if ((lun_map_ent != NULL) && ((itask->itask_itl_datap = 30247836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap) != NULL)) { 30257836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_itl_datap->itl_counter, 1); 30267836SJohn.Forte@Sun.COM task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle; 30277836SJohn.Forte@Sun.COM } else { 30287836SJohn.Forte@Sun.COM itask->itask_itl_datap = NULL; 30297836SJohn.Forte@Sun.COM task->task_lu_itl_handle = NULL; 30307836SJohn.Forte@Sun.COM } 30317836SJohn.Forte@Sun.COM 30327836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30337836SJohn.Forte@Sun.COM return (task); 30347836SJohn.Forte@Sun.COM } 30357836SJohn.Forte@Sun.COM 30367836SJohn.Forte@Sun.COM void 30377836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task) 30387836SJohn.Forte@Sun.COM { 30397836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 30407836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 30417836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 30427836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 30437836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 30447836SJohn.Forte@Sun.COM 30457836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 30467836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_FREE_LIST; 30477836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30487836SJohn.Forte@Sun.COM itask->itask_lu_free_next = ilu->ilu_free_tasks; 30497836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask; 30507836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free++; 30517836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30527836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, -1); 30537836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 30547836SJohn.Forte@Sun.COM } 30557836SJohn.Forte@Sun.COM 30567836SJohn.Forte@Sun.COM void 30577836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu) 30587836SJohn.Forte@Sun.COM { 30597836SJohn.Forte@Sun.COM uint32_t num_to_release, ndx; 30607836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 30617836SJohn.Forte@Sun.COM stmf_lu_t *lu = ilu->ilu_lu; 30627836SJohn.Forte@Sun.COM 30637836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free); 30647836SJohn.Forte@Sun.COM 30657836SJohn.Forte@Sun.COM /* free half of the minimal free of the free tasks */ 30667836SJohn.Forte@Sun.COM num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2; 30677836SJohn.Forte@Sun.COM if (!num_to_release) { 30687836SJohn.Forte@Sun.COM return; 30697836SJohn.Forte@Sun.COM } 30707836SJohn.Forte@Sun.COM for (ndx = 0; ndx < num_to_release; ndx++) { 30717836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30727836SJohn.Forte@Sun.COM itask = ilu->ilu_free_tasks; 30737836SJohn.Forte@Sun.COM if (itask == NULL) { 30747836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30757836SJohn.Forte@Sun.COM break; 30767836SJohn.Forte@Sun.COM } 30777836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask->itask_lu_free_next; 30787836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 30797836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30807836SJohn.Forte@Sun.COM 30817836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 30827836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 30837836SJohn.Forte@Sun.COM if (itask->itask_lu_next) 30847836SJohn.Forte@Sun.COM itask->itask_lu_next->itask_lu_prev = 30857836SJohn.Forte@Sun.COM itask->itask_lu_prev; 30867836SJohn.Forte@Sun.COM if (itask->itask_lu_prev) 30877836SJohn.Forte@Sun.COM itask->itask_lu_prev->itask_lu_next = 30887836SJohn.Forte@Sun.COM itask->itask_lu_next; 30897836SJohn.Forte@Sun.COM else 30907836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask->itask_lu_next; 30917836SJohn.Forte@Sun.COM 30927836SJohn.Forte@Sun.COM ilu->ilu_ntasks--; 30937836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 30947836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 30957836SJohn.Forte@Sun.COM } 30967836SJohn.Forte@Sun.COM } 30977836SJohn.Forte@Sun.COM 30987836SJohn.Forte@Sun.COM /* 30997836SJohn.Forte@Sun.COM * Called with stmf_lock held 31007836SJohn.Forte@Sun.COM */ 31017836SJohn.Forte@Sun.COM void 31027836SJohn.Forte@Sun.COM stmf_check_freetask() 31037836SJohn.Forte@Sun.COM { 31047836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 31057836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 31067836SJohn.Forte@Sun.COM 31077836SJohn.Forte@Sun.COM /* stmf_svc_ilu_draining may get changed after stmf_lock is released */ 31087836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) { 31097836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 31107836SJohn.Forte@Sun.COM if (!ilu->ilu_ntasks_min_free) { 31117836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 31127836SJohn.Forte@Sun.COM continue; 31137836SJohn.Forte@Sun.COM } 31147836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 31157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31167836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(ilu); 31177836SJohn.Forte@Sun.COM /* 31187836SJohn.Forte@Sun.COM * we do not care about the accuracy of 31197836SJohn.Forte@Sun.COM * ilu_ntasks_min_free, so we don't lock here 31207836SJohn.Forte@Sun.COM */ 31217836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 31227836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 31237836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 31247836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 31257836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 31267836SJohn.Forte@Sun.COM break; 31277836SJohn.Forte@Sun.COM } 31287836SJohn.Forte@Sun.COM } 31297836SJohn.Forte@Sun.COM 31307836SJohn.Forte@Sun.COM void 31317836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu) 31327836SJohn.Forte@Sun.COM { 31337836SJohn.Forte@Sun.COM clock_t l = ddi_get_lbolt(); 31347836SJohn.Forte@Sun.COM clock_t ps = drv_usectohz(1000000); 31357836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 31367836SJohn.Forte@Sun.COM scsi_task_t *task; 31377836SJohn.Forte@Sun.COM uint32_t to; 31387836SJohn.Forte@Sun.COM 31397836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 31407836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 31417836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 31427836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_IN_FREE_LIST | 31437836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) { 31447836SJohn.Forte@Sun.COM continue; 31457836SJohn.Forte@Sun.COM } 31467836SJohn.Forte@Sun.COM task = itask->itask_task; 31477836SJohn.Forte@Sun.COM if (task->task_timeout == 0) 31487836SJohn.Forte@Sun.COM to = stmf_default_task_timeout; 31497836SJohn.Forte@Sun.COM else 31507836SJohn.Forte@Sun.COM to = task->task_timeout; 31517836SJohn.Forte@Sun.COM if ((itask->itask_start_time + (to * ps)) > l) 31527836SJohn.Forte@Sun.COM continue; 31537836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 31547836SJohn.Forte@Sun.COM STMF_TIMEOUT, NULL); 31557836SJohn.Forte@Sun.COM } 31567836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 31577836SJohn.Forte@Sun.COM } 31587836SJohn.Forte@Sun.COM 31597836SJohn.Forte@Sun.COM /* 31607836SJohn.Forte@Sun.COM * Called with stmf_lock held 31617836SJohn.Forte@Sun.COM */ 31627836SJohn.Forte@Sun.COM void 31637836SJohn.Forte@Sun.COM stmf_check_ilu_timing() 31647836SJohn.Forte@Sun.COM { 31657836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 31667836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 31677836SJohn.Forte@Sun.COM 31687836SJohn.Forte@Sun.COM /* stmf_svc_ilu_timing may get changed after stmf_lock is released */ 31697836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) { 31707836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 31717836SJohn.Forte@Sun.COM if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) { 31727836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr2 == 0) { 31737836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2; 31747836SJohn.Forte@Sun.COM continue; 31757836SJohn.Forte@Sun.COM } 31767836SJohn.Forte@Sun.COM } else { 31777836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr1 == 0) { 31787836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 31797836SJohn.Forte@Sun.COM continue; 31807836SJohn.Forte@Sun.COM } 31817836SJohn.Forte@Sun.COM } 31827836SJohn.Forte@Sun.COM /* 31837836SJohn.Forte@Sun.COM * If we are here then it means that there is some slowdown 31847836SJohn.Forte@Sun.COM * in tasks on this lu. We need to check. 31857836SJohn.Forte@Sun.COM */ 31867836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 31877836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 31887836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(ilu); 31897836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 31907836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 31917836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 31927836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 31937836SJohn.Forte@Sun.COM break; 31947836SJohn.Forte@Sun.COM } 31957836SJohn.Forte@Sun.COM } 31967836SJohn.Forte@Sun.COM 31977836SJohn.Forte@Sun.COM /* 31987836SJohn.Forte@Sun.COM * Kills all tasks on a lu except tm_task 31997836SJohn.Forte@Sun.COM */ 32007836SJohn.Forte@Sun.COM void 32017836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s) 32027836SJohn.Forte@Sun.COM { 32037836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 32047836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 32057836SJohn.Forte@Sun.COM 32067836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 32077836SJohn.Forte@Sun.COM 32087836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 32097836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 32107836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_FREE_LIST) 32117836SJohn.Forte@Sun.COM continue; 32127836SJohn.Forte@Sun.COM if (itask->itask_task == tm_task) 32137836SJohn.Forte@Sun.COM continue; 32147836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL); 32157836SJohn.Forte@Sun.COM } 32167836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 32177836SJohn.Forte@Sun.COM } 32187836SJohn.Forte@Sun.COM 32197836SJohn.Forte@Sun.COM void 32207836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport) 32217836SJohn.Forte@Sun.COM { 32227836SJohn.Forte@Sun.COM int i; 32237836SJohn.Forte@Sun.COM uint8_t map; 32247836SJohn.Forte@Sun.COM 32257836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 32267836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 32277836SJohn.Forte@Sun.COM if (map & 1) { 32287836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 32297836SJohn.Forte@Sun.COM 32307836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 32317836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 32327836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 32337836SJohn.Forte@Sun.COM } 32347836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf( 32357836SJohn.Forte@Sun.COM lport->lport_ds, dbuf); 32367836SJohn.Forte@Sun.COM } 32377836SJohn.Forte@Sun.COM map >>= 1; 32387836SJohn.Forte@Sun.COM } 32397836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 32407836SJohn.Forte@Sun.COM } 32417836SJohn.Forte@Sun.COM } 32427836SJohn.Forte@Sun.COM 32437836SJohn.Forte@Sun.COM void 32447836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task) 32457836SJohn.Forte@Sun.COM { 32467836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 32477836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 32488662SJordan.Vaughan@Sun.com task->task_stmf_private; 32497836SJohn.Forte@Sun.COM 32508859STim.Szeto@Sun.COM DTRACE_PROBE1(stmf__task__end, scsi_task_t *, task); 32517836SJohn.Forte@Sun.COM stmf_free_task_bufs(itask, lport); 32527836SJohn.Forte@Sun.COM if (itask->itask_itl_datap) { 32537836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter, 32547836SJohn.Forte@Sun.COM -1) == 0) { 32557836SJohn.Forte@Sun.COM stmf_release_itl_handle(task->task_lu, 32568662SJordan.Vaughan@Sun.com itask->itask_itl_datap); 32577836SJohn.Forte@Sun.COM } 32587836SJohn.Forte@Sun.COM } 32597836SJohn.Forte@Sun.COM lport->lport_task_free(task); 32607836SJohn.Forte@Sun.COM if (itask->itask_worker) { 32617836SJohn.Forte@Sun.COM atomic_add_32(&stmf_cur_ntasks, -1); 32627836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_worker->worker_ref_count, -1); 32637836SJohn.Forte@Sun.COM } 32647836SJohn.Forte@Sun.COM /* 32657836SJohn.Forte@Sun.COM * After calling stmf_task_lu_free, the task pointer can no longer 32667836SJohn.Forte@Sun.COM * be trusted. 32677836SJohn.Forte@Sun.COM */ 32687836SJohn.Forte@Sun.COM stmf_task_lu_free(task); 32697836SJohn.Forte@Sun.COM } 32707836SJohn.Forte@Sun.COM 32717836SJohn.Forte@Sun.COM void 32727836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 32737836SJohn.Forte@Sun.COM { 32747836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 32757836SJohn.Forte@Sun.COM task->task_stmf_private; 32767836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 32777836SJohn.Forte@Sun.COM int nv; 32787836SJohn.Forte@Sun.COM uint32_t old, new; 32797836SJohn.Forte@Sun.COM uint32_t ct; 32807836SJohn.Forte@Sun.COM stmf_worker_t *w, *w1; 32817836SJohn.Forte@Sun.COM uint8_t tm; 32827836SJohn.Forte@Sun.COM 32837836SJohn.Forte@Sun.COM if (task->task_max_nbufs > 4) 32847836SJohn.Forte@Sun.COM task->task_max_nbufs = 4; 32857836SJohn.Forte@Sun.COM task->task_cur_nbufs = 0; 32867836SJohn.Forte@Sun.COM /* Latest value of currently running tasks */ 32877836SJohn.Forte@Sun.COM ct = atomic_add_32_nv(&stmf_cur_ntasks, 1); 32887836SJohn.Forte@Sun.COM 32897836SJohn.Forte@Sun.COM /* Select the next worker using round robin */ 32907836SJohn.Forte@Sun.COM nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1); 32917836SJohn.Forte@Sun.COM if (nv >= stmf_nworkers_accepting_cmds) { 32927836SJohn.Forte@Sun.COM int s = nv; 32937836SJohn.Forte@Sun.COM do { 32947836SJohn.Forte@Sun.COM nv -= stmf_nworkers_accepting_cmds; 32957836SJohn.Forte@Sun.COM } while (nv >= stmf_nworkers_accepting_cmds); 32967836SJohn.Forte@Sun.COM if (nv < 0) 32977836SJohn.Forte@Sun.COM nv = 0; 32987836SJohn.Forte@Sun.COM /* Its ok if this cas fails */ 32997836SJohn.Forte@Sun.COM (void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter, 33007836SJohn.Forte@Sun.COM s, nv); 33017836SJohn.Forte@Sun.COM } 33027836SJohn.Forte@Sun.COM w = &stmf_workers[nv]; 33037836SJohn.Forte@Sun.COM 33047836SJohn.Forte@Sun.COM /* 33057836SJohn.Forte@Sun.COM * A worker can be pinned by interrupt. So select the next one 33067836SJohn.Forte@Sun.COM * if it has lower load. 33077836SJohn.Forte@Sun.COM */ 33087836SJohn.Forte@Sun.COM if ((nv + 1) >= stmf_nworkers_accepting_cmds) { 33097836SJohn.Forte@Sun.COM w1 = stmf_workers; 33107836SJohn.Forte@Sun.COM } else { 33117836SJohn.Forte@Sun.COM w1 = &stmf_workers[nv + 1]; 33127836SJohn.Forte@Sun.COM } 33137836SJohn.Forte@Sun.COM if (w1->worker_queue_depth < w->worker_queue_depth) 33147836SJohn.Forte@Sun.COM w = w1; 33159435STim.Szeto@Sun.COM 33167836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33177836SJohn.Forte@Sun.COM if (((w->worker_flags & STMF_WORKER_STARTED) == 0) || 33187836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 33197836SJohn.Forte@Sun.COM /* 33207836SJohn.Forte@Sun.COM * Maybe we are in the middle of a change. Just go to 33217836SJohn.Forte@Sun.COM * the 1st worker. 33227836SJohn.Forte@Sun.COM */ 33237836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33247836SJohn.Forte@Sun.COM w = stmf_workers; 33257836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33267836SJohn.Forte@Sun.COM } 33277836SJohn.Forte@Sun.COM itask->itask_worker = w; 33287836SJohn.Forte@Sun.COM /* 33297836SJohn.Forte@Sun.COM * Track max system load inside the worker as we already have the 33307836SJohn.Forte@Sun.COM * worker lock (no point implementing another lock). The service 33317836SJohn.Forte@Sun.COM * thread will do the comparisons and figure out the max overall 33327836SJohn.Forte@Sun.COM * system load. 33337836SJohn.Forte@Sun.COM */ 33347836SJohn.Forte@Sun.COM if (w->worker_max_sys_qdepth_pu < ct) 33357836SJohn.Forte@Sun.COM w->worker_max_sys_qdepth_pu = ct; 33367836SJohn.Forte@Sun.COM 33377836SJohn.Forte@Sun.COM do { 33387836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 33397836SJohn.Forte@Sun.COM new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE; 33407836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 33417836SJohn.Forte@Sun.COM tm = task->task_mgmt_function; 33427836SJohn.Forte@Sun.COM if ((tm == TM_TARGET_RESET) || 33437836SJohn.Forte@Sun.COM (tm == TM_TARGET_COLD_RESET) || 33447836SJohn.Forte@Sun.COM (tm == TM_TARGET_WARM_RESET)) { 33457836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 33467836SJohn.Forte@Sun.COM } 33477836SJohn.Forte@Sun.COM } else if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 33487836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 33497836SJohn.Forte@Sun.COM } 33507836SJohn.Forte@Sun.COM new &= ~ITASK_IN_TRANSITION; 33517836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 33527836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 33537836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 33547836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 33557836SJohn.Forte@Sun.COM } else { 33567836SJohn.Forte@Sun.COM w->worker_task_head = itask; 33577836SJohn.Forte@Sun.COM } 33587836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 33597836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 33607836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 33617836SJohn.Forte@Sun.COM } 33627836SJohn.Forte@Sun.COM atomic_add_32(&w->worker_ref_count, 1); 33637836SJohn.Forte@Sun.COM itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK; 33647836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 33657836SJohn.Forte@Sun.COM if (dbuf) { 33667836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 1; 33677836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = dbuf; 33687836SJohn.Forte@Sun.COM dbuf->db_handle = 0; 33697836SJohn.Forte@Sun.COM } else { 33707836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 33717836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = NULL; 33727836SJohn.Forte@Sun.COM } 33739435STim.Szeto@Sun.COM 33749435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_enter); 33759435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_enter); 33769435STim.Szeto@Sun.COM 33777836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 33787836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 33797836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33807836SJohn.Forte@Sun.COM 33817836SJohn.Forte@Sun.COM /* 33827836SJohn.Forte@Sun.COM * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE 33837836SJohn.Forte@Sun.COM * was set between checking of ILU_RESET_ACTIVE and clearing of the 33847836SJohn.Forte@Sun.COM * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here. 33857836SJohn.Forte@Sun.COM */ 33867836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 33877836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL); 33887836SJohn.Forte@Sun.COM } 33897836SJohn.Forte@Sun.COM } 33907836SJohn.Forte@Sun.COM 33917836SJohn.Forte@Sun.COM /* 33927836SJohn.Forte@Sun.COM * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++ 33937836SJohn.Forte@Sun.COM * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already 33947836SJohn.Forte@Sun.COM * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot 33957836SJohn.Forte@Sun.COM * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course 33967836SJohn.Forte@Sun.COM * the LU will make this call only if we call the LU's abort entry point. 33977836SJohn.Forte@Sun.COM * we will only call that entry point if ITASK_KNOWN_TO_LU was set. 33987836SJohn.Forte@Sun.COM * 33997836SJohn.Forte@Sun.COM * Same logic applies for the port. 34007836SJohn.Forte@Sun.COM * 34017836SJohn.Forte@Sun.COM * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU 34027836SJohn.Forte@Sun.COM * and KNOWN_TO_TGT_PORT are reset. 34037836SJohn.Forte@Sun.COM * 34047836SJohn.Forte@Sun.COM * +++++++++++++++++++++++++++++++++++++++++++++++ 34057836SJohn.Forte@Sun.COM */ 34067836SJohn.Forte@Sun.COM 34077836SJohn.Forte@Sun.COM stmf_status_t 34087836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) 34097836SJohn.Forte@Sun.COM { 34108859STim.Szeto@Sun.COM stmf_status_t ret; 34118859STim.Szeto@Sun.COM 34127836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 34137836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 34147836SJohn.Forte@Sun.COM 34157836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 34167836SJohn.Forte@Sun.COM uint32_t new, old; 34177836SJohn.Forte@Sun.COM do { 34187836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 34197836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 34207836SJohn.Forte@Sun.COM return (STMF_ABORTED); 34217836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 34227836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34237836SJohn.Forte@Sun.COM } 34247836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 34257836SJohn.Forte@Sun.COM return (STMF_ABORTED); 34267836SJohn.Forte@Sun.COM #ifdef DEBUG 34277836SJohn.Forte@Sun.COM if (stmf_drop_buf_counter > 0) { 34288662SJordan.Vaughan@Sun.com if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, -1) == 34298662SJordan.Vaughan@Sun.com 1) 34307836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 34317836SJohn.Forte@Sun.COM } 34327836SJohn.Forte@Sun.COM #endif 34339435STim.Szeto@Sun.COM 34349435STim.Szeto@Sun.COM stmf_update_kstat_lu_io(task, dbuf); 34359435STim.Szeto@Sun.COM stmf_update_kstat_lport_io(task, dbuf); 34369435STim.Szeto@Sun.COM 34378859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__start, scsi_task_t *, task, 34388859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 34398859STim.Szeto@Sun.COM ret = task->task_lport->lport_xfer_data(task, dbuf, ioflags); 34408859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__xfer__end, scsi_task_t *, task, 34418859STim.Szeto@Sun.COM stmf_data_buf_t *, dbuf); 34428859STim.Szeto@Sun.COM return (ret); 34437836SJohn.Forte@Sun.COM } 34447836SJohn.Forte@Sun.COM 34457836SJohn.Forte@Sun.COM void 34467836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof) 34477836SJohn.Forte@Sun.COM { 34487836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 34497836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 34507836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 34517836SJohn.Forte@Sun.COM uint32_t new, old; 34527836SJohn.Forte@Sun.COM uint8_t update_queue_flags, free_it, queue_it; 34537836SJohn.Forte@Sun.COM 34547836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 34557836SJohn.Forte@Sun.COM do { 34567836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 34577836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 34587836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 34597836SJohn.Forte@Sun.COM return; 34607836SJohn.Forte@Sun.COM } 34617836SJohn.Forte@Sun.COM free_it = 0; 34627836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 34637836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 34647836SJohn.Forte@Sun.COM task->task_completion_status = dbuf->db_xfer_status; 34657836SJohn.Forte@Sun.COM free_it = 1; 34667836SJohn.Forte@Sun.COM } 34677836SJohn.Forte@Sun.COM /* 34687836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 34697836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 34707836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 34717836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 34727836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 34737836SJohn.Forte@Sun.COM * free this task. 34747836SJohn.Forte@Sun.COM */ 34757836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 34767836SJohn.Forte@Sun.COM free_it = 0; 34777836SJohn.Forte@Sun.COM update_queue_flags = 1; 34787836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 34797836SJohn.Forte@Sun.COM queue_it = 0; 34807836SJohn.Forte@Sun.COM } else { 34817836SJohn.Forte@Sun.COM queue_it = 1; 34827836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 34837836SJohn.Forte@Sun.COM } 34847836SJohn.Forte@Sun.COM } else { 34857836SJohn.Forte@Sun.COM update_queue_flags = 0; 34867836SJohn.Forte@Sun.COM queue_it = 0; 34877836SJohn.Forte@Sun.COM } 34887836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34897836SJohn.Forte@Sun.COM 34907836SJohn.Forte@Sun.COM if (update_queue_flags) { 34917836SJohn.Forte@Sun.COM uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE; 34927836SJohn.Forte@Sun.COM 34937836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 34947836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = cmd; 34957836SJohn.Forte@Sun.COM if (queue_it) { 34967836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 34977836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 34987836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 34997836SJohn.Forte@Sun.COM } else { 35007836SJohn.Forte@Sun.COM w->worker_task_head = itask; 35017836SJohn.Forte@Sun.COM } 35027836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 35037836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > 35047836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu) { 35057836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 35067836SJohn.Forte@Sun.COM } 35077836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 35087836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 35097836SJohn.Forte@Sun.COM } 35107836SJohn.Forte@Sun.COM } 35117836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 35127836SJohn.Forte@Sun.COM 35137836SJohn.Forte@Sun.COM if (free_it) { 35147836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 35157836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 35167836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 35179435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 35189435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 35197836SJohn.Forte@Sun.COM stmf_task_free(task); 35207836SJohn.Forte@Sun.COM } 35217836SJohn.Forte@Sun.COM } 35227836SJohn.Forte@Sun.COM } 35237836SJohn.Forte@Sun.COM 35247836SJohn.Forte@Sun.COM stmf_status_t 35257836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 35267836SJohn.Forte@Sun.COM { 35278859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__send__status, scsi_task_t *, task); 35288859STim.Szeto@Sun.COM 35297836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 35308662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 35317836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 35327836SJohn.Forte@Sun.COM uint32_t new, old; 35337836SJohn.Forte@Sun.COM do { 35347836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 35357836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 35367836SJohn.Forte@Sun.COM return (STMF_ABORTED); 35377836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 35387836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 35397836SJohn.Forte@Sun.COM } 35407836SJohn.Forte@Sun.COM 35417836SJohn.Forte@Sun.COM if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) { 35427836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 35437836SJohn.Forte@Sun.COM } 35447836SJohn.Forte@Sun.COM 35457836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 35467836SJohn.Forte@Sun.COM return (STMF_ABORTED); 35477836SJohn.Forte@Sun.COM 35487836SJohn.Forte@Sun.COM if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) { 35497836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 35507836SJohn.Forte@Sun.COM task->task_resid = 0; 35517836SJohn.Forte@Sun.COM } else if (task->task_cmd_xfer_length > 35527836SJohn.Forte@Sun.COM task->task_expected_xfer_length) { 35537836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_OVER; 35547836SJohn.Forte@Sun.COM task->task_resid = task->task_cmd_xfer_length - 35558662SJordan.Vaughan@Sun.com task->task_expected_xfer_length; 35567836SJohn.Forte@Sun.COM } else if (task->task_nbytes_transferred < 35578662SJordan.Vaughan@Sun.com task->task_expected_xfer_length) { 35587836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_UNDER; 35597836SJohn.Forte@Sun.COM task->task_resid = task->task_expected_xfer_length - 35608662SJordan.Vaughan@Sun.com task->task_nbytes_transferred; 35617836SJohn.Forte@Sun.COM } else { 35627836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 35637836SJohn.Forte@Sun.COM task->task_resid = 0; 35647836SJohn.Forte@Sun.COM } 35657836SJohn.Forte@Sun.COM return (task->task_lport->lport_send_status(task, ioflags)); 35667836SJohn.Forte@Sun.COM } 35677836SJohn.Forte@Sun.COM 35687836SJohn.Forte@Sun.COM void 35697836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof) 35707836SJohn.Forte@Sun.COM { 35717836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 35727836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 35737836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 35747836SJohn.Forte@Sun.COM uint32_t new, old; 35757836SJohn.Forte@Sun.COM uint8_t free_it, queue_it; 35767836SJohn.Forte@Sun.COM 35777836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 35787836SJohn.Forte@Sun.COM do { 35797836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 35807836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 35817836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 35827836SJohn.Forte@Sun.COM return; 35837836SJohn.Forte@Sun.COM } 35847836SJohn.Forte@Sun.COM free_it = 0; 35857836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 35867836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 35877836SJohn.Forte@Sun.COM free_it = 1; 35887836SJohn.Forte@Sun.COM } 35897836SJohn.Forte@Sun.COM /* 35907836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 35917836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 35927836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 35937836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 35947836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 35957836SJohn.Forte@Sun.COM * free this task. 35967836SJohn.Forte@Sun.COM */ 35977836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 35987836SJohn.Forte@Sun.COM free_it = 0; 35997836SJohn.Forte@Sun.COM queue_it = 1; 36007836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 36017836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "status completion received" 36027836SJohn.Forte@Sun.COM " when task is already in worker queue " 36037836SJohn.Forte@Sun.COM " task = %p", (void *)task); 36047836SJohn.Forte@Sun.COM } 36057836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 36067836SJohn.Forte@Sun.COM } else { 36077836SJohn.Forte@Sun.COM queue_it = 0; 36087836SJohn.Forte@Sun.COM } 36097836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 36107836SJohn.Forte@Sun.COM task->task_completion_status = s; 36117836SJohn.Forte@Sun.COM 36129435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_runq_exit); 36139435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_runq_exit); 36149435STim.Szeto@Sun.COM 36157836SJohn.Forte@Sun.COM if (queue_it) { 36167836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 36177836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = 36187836SJohn.Forte@Sun.COM ITASK_CMD_STATUS_DONE; 36197836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 36207836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 36217836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 36227836SJohn.Forte@Sun.COM } else { 36237836SJohn.Forte@Sun.COM w->worker_task_head = itask; 36247836SJohn.Forte@Sun.COM } 36257836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 36267836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 36277836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 36287836SJohn.Forte@Sun.COM } 36297836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 36307836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 36317836SJohn.Forte@Sun.COM } 36327836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36337836SJohn.Forte@Sun.COM 36347836SJohn.Forte@Sun.COM if (free_it) { 36357836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 36367836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 36377836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 36387836SJohn.Forte@Sun.COM stmf_task_free(task); 36397836SJohn.Forte@Sun.COM } else { 36407836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "LU is done with the task but LPORT " 36417836SJohn.Forte@Sun.COM " is not done, itask %p", (void *)itask); 36427836SJohn.Forte@Sun.COM } 36437836SJohn.Forte@Sun.COM } 36447836SJohn.Forte@Sun.COM } 36457836SJohn.Forte@Sun.COM 36467836SJohn.Forte@Sun.COM void 36477836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task) 36487836SJohn.Forte@Sun.COM { 36497836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36508662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 36517836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 36527836SJohn.Forte@Sun.COM uint32_t new, old; 36537836SJohn.Forte@Sun.COM 36547836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 36557836SJohn.Forte@Sun.COM do { 36567836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 36577836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 36587836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36597836SJohn.Forte@Sun.COM return; 36607836SJohn.Forte@Sun.COM } 36617836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 36627836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "task_lu_done received" 36637836SJohn.Forte@Sun.COM " when task is in worker queue " 36647836SJohn.Forte@Sun.COM " task = %p", (void *)task); 36657836SJohn.Forte@Sun.COM } 36667836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 36677836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 36687836SJohn.Forte@Sun.COM 36697836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 36707836SJohn.Forte@Sun.COM 36717836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 36727836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 36737836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 36747836SJohn.Forte@Sun.COM stmf_task_free(task); 36757836SJohn.Forte@Sun.COM } else { 36767836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but " 36777836SJohn.Forte@Sun.COM " the task is still not done, task = %p", (void *)task); 36787836SJohn.Forte@Sun.COM } 36797836SJohn.Forte@Sun.COM } 36807836SJohn.Forte@Sun.COM 36817836SJohn.Forte@Sun.COM void 36827836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s) 36837836SJohn.Forte@Sun.COM { 36847836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 36857836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 36867836SJohn.Forte@Sun.COM stmf_worker_t *w; 36877836SJohn.Forte@Sun.COM uint32_t old, new; 36887836SJohn.Forte@Sun.COM 36897836SJohn.Forte@Sun.COM do { 36907836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 36917836SJohn.Forte@Sun.COM if ((old & ITASK_BEING_ABORTED) || 36927836SJohn.Forte@Sun.COM ((old & (ITASK_KNOWN_TO_TGT_PORT | 36937836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU)) == 0)) { 36947836SJohn.Forte@Sun.COM return; 36957836SJohn.Forte@Sun.COM } 36967836SJohn.Forte@Sun.COM new |= ITASK_BEING_ABORTED; 36977836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 36987836SJohn.Forte@Sun.COM task->task_completion_status = s; 36997836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 37007836SJohn.Forte@Sun.COM 37017836SJohn.Forte@Sun.COM if (((w = itask->itask_worker) == NULL) || 37027836SJohn.Forte@Sun.COM (itask->itask_flags & ITASK_IN_TRANSITION)) { 37037836SJohn.Forte@Sun.COM return; 37047836SJohn.Forte@Sun.COM } 37057836SJohn.Forte@Sun.COM 37067836SJohn.Forte@Sun.COM /* Queue it and get out */ 37077836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 37087836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) { 37097836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 37107836SJohn.Forte@Sun.COM return; 37117836SJohn.Forte@Sun.COM } 37127836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 37137836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 37147836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 37157836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 37167836SJohn.Forte@Sun.COM } else { 37177836SJohn.Forte@Sun.COM w->worker_task_head = itask; 37187836SJohn.Forte@Sun.COM } 37197836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 37207836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 37217836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 37227836SJohn.Forte@Sun.COM } 37237836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 37247836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 37257836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 37267836SJohn.Forte@Sun.COM } 37277836SJohn.Forte@Sun.COM 37287836SJohn.Forte@Sun.COM void 37297836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg) 37307836SJohn.Forte@Sun.COM { 37317836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = NULL; 37327836SJohn.Forte@Sun.COM uint32_t old, new, f, rf; 37337836SJohn.Forte@Sun.COM 37348859STim.Szeto@Sun.COM DTRACE_PROBE2(scsi__task__abort, scsi_task_t *, task, 37358859STim.Szeto@Sun.COM stmf_status_t, s); 37368859STim.Szeto@Sun.COM 37377836SJohn.Forte@Sun.COM switch (abort_cmd) { 37387836SJohn.Forte@Sun.COM case STMF_QUEUE_ABORT_LU: 37397836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)arg, task, s); 37407836SJohn.Forte@Sun.COM return; 37417836SJohn.Forte@Sun.COM case STMF_QUEUE_TASK_ABORT: 37427836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(task, s); 37437836SJohn.Forte@Sun.COM return; 37447836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LPORT: 37457836SJohn.Forte@Sun.COM rf = ITASK_TGT_PORT_ABORT_CALLED; 37467836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_TGT_PORT; 37477836SJohn.Forte@Sun.COM break; 37487836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LU: 37497836SJohn.Forte@Sun.COM rf = ITASK_LU_ABORT_CALLED; 37507836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_LU; 37517836SJohn.Forte@Sun.COM break; 37527836SJohn.Forte@Sun.COM default: 37537836SJohn.Forte@Sun.COM return; 37547836SJohn.Forte@Sun.COM } 37557836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 37567836SJohn.Forte@Sun.COM f |= ITASK_BEING_ABORTED | rf; 37577836SJohn.Forte@Sun.COM do { 37587836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 37597836SJohn.Forte@Sun.COM if ((old & f) != f) { 37607836SJohn.Forte@Sun.COM return; 37617836SJohn.Forte@Sun.COM } 37627836SJohn.Forte@Sun.COM new &= ~rf; 37637836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 37647836SJohn.Forte@Sun.COM } 37657836SJohn.Forte@Sun.COM 37667836SJohn.Forte@Sun.COM void 37677836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 37687836SJohn.Forte@Sun.COM { 37697836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 37707836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 37717836SJohn.Forte@Sun.COM unsigned long long st; 37727836SJohn.Forte@Sun.COM 37737836SJohn.Forte@Sun.COM st = s; /* gcc fix */ 37747836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 37757836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37767836SJohn.Forte@Sun.COM "task %p, lu failed to abort ret=%llx", (void *)task, st); 37777836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LU_DONE) == 0) { 37787836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 37797836SJohn.Forte@Sun.COM "Task aborted but LU is not finished, task =" 37807836SJohn.Forte@Sun.COM "%p, s=%llx, iof=%x", (void *)task, st, iof); 37817836SJohn.Forte@Sun.COM } else { 37827836SJohn.Forte@Sun.COM /* 37837836SJohn.Forte@Sun.COM * LU abort successfully 37847836SJohn.Forte@Sun.COM */ 37857836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU); 37867836SJohn.Forte@Sun.COM return; 37877836SJohn.Forte@Sun.COM } 37887836SJohn.Forte@Sun.COM 37897836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 37907836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 37917836SJohn.Forte@Sun.COM } 37927836SJohn.Forte@Sun.COM 37937836SJohn.Forte@Sun.COM void 37947836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 37957836SJohn.Forte@Sun.COM { 37967836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 37977836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 37987836SJohn.Forte@Sun.COM unsigned long long st; 37997836SJohn.Forte@Sun.COM 38007836SJohn.Forte@Sun.COM st = s; 38017836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 38027836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 38037836SJohn.Forte@Sun.COM "task %p, tgt port failed to abort ret=%llx", (void *)task, 38047836SJohn.Forte@Sun.COM st); 38057836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LPORT_DONE) == 0) { 38067836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 38077836SJohn.Forte@Sun.COM "Task aborted but tgt port is not finished, " 38087836SJohn.Forte@Sun.COM "task=%p, s=%llx, iof=%x", (void *)task, st, iof); 38097836SJohn.Forte@Sun.COM } else { 38107836SJohn.Forte@Sun.COM /* 38117836SJohn.Forte@Sun.COM * LU abort successfully 38127836SJohn.Forte@Sun.COM */ 38137836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT); 38147836SJohn.Forte@Sun.COM return; 38157836SJohn.Forte@Sun.COM } 38167836SJohn.Forte@Sun.COM 38177836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 38187836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 38197836SJohn.Forte@Sun.COM } 38207836SJohn.Forte@Sun.COM 38217836SJohn.Forte@Sun.COM stmf_status_t 38227836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout) 38237836SJohn.Forte@Sun.COM { 38247836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 38257836SJohn.Forte@Sun.COM task->task_stmf_private; 38267836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 38277836SJohn.Forte@Sun.COM int i; 38287836SJohn.Forte@Sun.COM 38297836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU); 38307836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 38317836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 38327836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38337836SJohn.Forte@Sun.COM return (STMF_BUSY); 38347836SJohn.Forte@Sun.COM } 38357836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 38367836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) { 38377836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38387836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38397836SJohn.Forte@Sun.COM } 38407836SJohn.Forte@Sun.COM } 38417836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU; 38427836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 38437836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 38447836SJohn.Forte@Sun.COM } else { 38457836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 38467836SJohn.Forte@Sun.COM if (t == 0) 38477836SJohn.Forte@Sun.COM t = 1; 38487836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 38497836SJohn.Forte@Sun.COM } 38507836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 38517836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 38527836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 38537836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 38547836SJohn.Forte@Sun.COM } else { 38557836SJohn.Forte@Sun.COM w->worker_task_head = itask; 38567836SJohn.Forte@Sun.COM } 38577836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 38587836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 38597836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 38607836SJohn.Forte@Sun.COM } 38617836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 38627836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 38637836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 38647836SJohn.Forte@Sun.COM } 38657836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38667836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38677836SJohn.Forte@Sun.COM } 38687836SJohn.Forte@Sun.COM 38697836SJohn.Forte@Sun.COM stmf_status_t 38707836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout) 38717836SJohn.Forte@Sun.COM { 38727836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 38737836SJohn.Forte@Sun.COM task->task_stmf_private; 38747836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 38757836SJohn.Forte@Sun.COM int i; 38767836SJohn.Forte@Sun.COM 38777836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT); 38787836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 38797836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 38807836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38817836SJohn.Forte@Sun.COM return (STMF_BUSY); 38827836SJohn.Forte@Sun.COM } 38837836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 38847836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) { 38857836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 38867836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38877836SJohn.Forte@Sun.COM } 38887836SJohn.Forte@Sun.COM } 38897836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT; 38907836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 38917836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 38927836SJohn.Forte@Sun.COM } else { 38937836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 38947836SJohn.Forte@Sun.COM if (t == 0) 38957836SJohn.Forte@Sun.COM t = 1; 38967836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 38977836SJohn.Forte@Sun.COM } 38987836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 38997836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 39007836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 39017836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 39027836SJohn.Forte@Sun.COM } else { 39037836SJohn.Forte@Sun.COM w->worker_task_head = itask; 39047836SJohn.Forte@Sun.COM } 39057836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 39067836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 39077836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 39087836SJohn.Forte@Sun.COM } 39097836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 39107836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 39117836SJohn.Forte@Sun.COM } 39127836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 39137836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 39147836SJohn.Forte@Sun.COM } 39157836SJohn.Forte@Sun.COM 39167836SJohn.Forte@Sun.COM void 39177836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task) 39187836SJohn.Forte@Sun.COM { 39197836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 39207836SJohn.Forte@Sun.COM stmf_lu_t *lu; 39217836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 39227836SJohn.Forte@Sun.COM unsigned long long ret; 39237836SJohn.Forte@Sun.COM uint32_t old, new; 39247836SJohn.Forte@Sun.COM uint8_t call_lu_abort, call_port_abort; 39257836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 39267836SJohn.Forte@Sun.COM 39277836SJohn.Forte@Sun.COM lu = task->task_lu; 39287836SJohn.Forte@Sun.COM lport = task->task_lport; 39297836SJohn.Forte@Sun.COM do { 39307836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 39317836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) == 39327836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU) { 39337836SJohn.Forte@Sun.COM new |= ITASK_LU_ABORT_CALLED; 39347836SJohn.Forte@Sun.COM call_lu_abort = 1; 39357836SJohn.Forte@Sun.COM } else { 39367836SJohn.Forte@Sun.COM call_lu_abort = 0; 39377836SJohn.Forte@Sun.COM } 39387836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 39397836SJohn.Forte@Sun.COM 39407836SJohn.Forte@Sun.COM if (call_lu_abort) { 39417836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) { 39427836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 39437836SJohn.Forte@Sun.COM } else { 39447836SJohn.Forte@Sun.COM ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 39457836SJohn.Forte@Sun.COM } 39467836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 39477836SJohn.Forte@Sun.COM stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE); 39487836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 39497836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 39507836SJohn.Forte@Sun.COM ~ITASK_LU_ABORT_CALLED); 39517836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 39527836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39537836SJohn.Forte@Sun.COM "Abort failed by LU %p, ret %llx", (void *)lu, ret); 39547836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39557836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 39567836SJohn.Forte@Sun.COM } 39577836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_LU) { 39587836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 39597836SJohn.Forte@Sun.COM STMF_SEC2TICK(lu->lu_abort_timeout? 39607836SJohn.Forte@Sun.COM lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) { 39617836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39627836SJohn.Forte@Sun.COM "lu abort timed out"); 39637836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39647836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 1, info); 39657836SJohn.Forte@Sun.COM } 39667836SJohn.Forte@Sun.COM } 39677836SJohn.Forte@Sun.COM 39687836SJohn.Forte@Sun.COM do { 39697836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 39707836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_TGT_PORT | 39717836SJohn.Forte@Sun.COM ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) { 39727836SJohn.Forte@Sun.COM new |= ITASK_TGT_PORT_ABORT_CALLED; 39737836SJohn.Forte@Sun.COM call_port_abort = 1; 39747836SJohn.Forte@Sun.COM } else { 39757836SJohn.Forte@Sun.COM call_port_abort = 0; 39767836SJohn.Forte@Sun.COM } 39777836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 39787836SJohn.Forte@Sun.COM if (call_port_abort) { 39798662SJordan.Vaughan@Sun.com ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, task, 0); 39807836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 39817836SJohn.Forte@Sun.COM stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE); 39827836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 39837836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 39847836SJohn.Forte@Sun.COM ~ITASK_TGT_PORT_ABORT_CALLED); 39857836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 39867836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39877836SJohn.Forte@Sun.COM "Abort failed by tgt port %p ret %llx", 39887836SJohn.Forte@Sun.COM (void *)lport, ret); 39897836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 39907836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 39917836SJohn.Forte@Sun.COM } 39927836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) { 39937836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 39947836SJohn.Forte@Sun.COM STMF_SEC2TICK(lport->lport_abort_timeout? 39957836SJohn.Forte@Sun.COM lport->lport_abort_timeout : 39967836SJohn.Forte@Sun.COM ITASK_DEFAULT_ABORT_TIMEOUT))) { 39977836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 39987836SJohn.Forte@Sun.COM "lport abort timed out"); 39997836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 40007836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 0, info); 40017836SJohn.Forte@Sun.COM } 40027836SJohn.Forte@Sun.COM } 40037836SJohn.Forte@Sun.COM } 40047836SJohn.Forte@Sun.COM 40057836SJohn.Forte@Sun.COM stmf_status_t 40067836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg) 40077836SJohn.Forte@Sun.COM { 40087836SJohn.Forte@Sun.COM stmf_status_t ret; 40097836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 40107836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 40117836SJohn.Forte@Sun.COM stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; 40127836SJohn.Forte@Sun.COM 40137836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40147836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40157836SJohn.Forte@Sun.COM if (cmd & STMF_CMD_LU_OP) { 40167836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu((stmf_lu_t *)obj); 40177836SJohn.Forte@Sun.COM if (ilu == NULL) { 40187836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40197836SJohn.Forte@Sun.COM } 40208859STim.Szeto@Sun.COM DTRACE_PROBE3(lu__state__change, 40218859STim.Szeto@Sun.COM stmf_lu_t *, ilu->ilu_lu, 40228859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 40237836SJohn.Forte@Sun.COM } else if (cmd & STMF_CMD_LPORT_OP) { 40247836SJohn.Forte@Sun.COM ilport = stmf_lookup_lport((stmf_local_port_t *)obj); 40257836SJohn.Forte@Sun.COM if (ilport == NULL) { 40267836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40277836SJohn.Forte@Sun.COM } 40288859STim.Szeto@Sun.COM DTRACE_PROBE3(lport__state__change, 40298859STim.Szeto@Sun.COM stmf_local_port_t *, ilport->ilport_lport, 40308859STim.Szeto@Sun.COM int, cmd, stmf_state_change_info_t *, ssci); 40317836SJohn.Forte@Sun.COM } else { 40327836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40337836SJohn.Forte@Sun.COM } 40347836SJohn.Forte@Sun.COM 40357836SJohn.Forte@Sun.COM switch (cmd) { 40367836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 40377836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_ONLINE) { 40387836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 40397836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40407836SJohn.Forte@Sun.COM } 40417836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINE) { 40427836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40437836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40447836SJohn.Forte@Sun.COM } 40457836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINING; 40467836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40477836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 40487836SJohn.Forte@Sun.COM break; 40497836SJohn.Forte@Sun.COM 40507836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE_COMPLETE: 40517836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINING) { 40527836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40537836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40547836SJohn.Forte@Sun.COM } 40557836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 40567836SJohn.Forte@Sun.COM STMF_SUCCESS) { 40577836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 40587836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40597836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 40607836SJohn.Forte@Sun.COM STMF_ACK_LU_ONLINE_COMPLETE, arg); 40617836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40627836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 40637836SJohn.Forte@Sun.COM } else { 40647836SJohn.Forte@Sun.COM /* XXX: should throw a meesage an record more data */ 40657836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 40667836SJohn.Forte@Sun.COM } 40677836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 40687836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40697836SJohn.Forte@Sun.COM 40707836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 40717836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 40727836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 40737836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40747836SJohn.Forte@Sun.COM } 40757836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) { 40767836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40777836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40787836SJohn.Forte@Sun.COM } 40797836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINING; 40807836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40817836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 40827836SJohn.Forte@Sun.COM break; 40837836SJohn.Forte@Sun.COM 40847836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE_COMPLETE: 40857836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINING) { 40867836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 40877836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 40887836SJohn.Forte@Sun.COM } 40897836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 40907836SJohn.Forte@Sun.COM STMF_SUCCESS) { 40917836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 40927836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40937836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 40947836SJohn.Forte@Sun.COM STMF_ACK_LU_OFFLINE_COMPLETE, arg); 40957836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40967836SJohn.Forte@Sun.COM } else { 40977836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 40987836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 40997836SJohn.Forte@Sun.COM } 41007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41017836SJohn.Forte@Sun.COM break; 41027836SJohn.Forte@Sun.COM 41037836SJohn.Forte@Sun.COM /* 41047836SJohn.Forte@Sun.COM * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online. 41057836SJohn.Forte@Sun.COM * It's related with hardware disable/enable. 41067836SJohn.Forte@Sun.COM */ 41077836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 41087836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_ONLINE) { 41097836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 41107836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41117836SJohn.Forte@Sun.COM } 41127836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINE) { 41137836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41147836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41157836SJohn.Forte@Sun.COM } 41167836SJohn.Forte@Sun.COM 41177836SJohn.Forte@Sun.COM /* 41187836SJohn.Forte@Sun.COM * Only user request can recover the port from the 41197836SJohn.Forte@Sun.COM * FORCED_OFFLINE state 41207836SJohn.Forte@Sun.COM */ 41217836SJohn.Forte@Sun.COM if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) { 41227836SJohn.Forte@Sun.COM if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { 41237836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 41247836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41257836SJohn.Forte@Sun.COM } 41267836SJohn.Forte@Sun.COM } 41277836SJohn.Forte@Sun.COM 41287836SJohn.Forte@Sun.COM /* 41297836SJohn.Forte@Sun.COM * Avoid too frequent request to online 41307836SJohn.Forte@Sun.COM */ 41317836SJohn.Forte@Sun.COM if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) { 41327836SJohn.Forte@Sun.COM ilport->ilport_online_times = 0; 41337836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 0; 41347836SJohn.Forte@Sun.COM } 41357836SJohn.Forte@Sun.COM if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) && 41367836SJohn.Forte@Sun.COM (ilport->ilport_online_times >= 4)) { 41377836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 41387836SJohn.Forte@Sun.COM ilport->ilport_flags |= ILPORT_FORCED_OFFLINE; 41397836SJohn.Forte@Sun.COM stmf_trace(NULL, "stmf_ctl: too frequent request to " 41407836SJohn.Forte@Sun.COM "online the port"); 41417836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_ctl: too frequent request to " 41427836SJohn.Forte@Sun.COM "online the port, set FORCED_OFFLINE now"); 41437836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41447836SJohn.Forte@Sun.COM } 41457836SJohn.Forte@Sun.COM if (ilport->ilport_online_times > 0) { 41467836SJohn.Forte@Sun.COM if (ilport->ilport_online_times == 1) { 41477836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = ddi_get_lbolt() - 41487836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock; 41497836SJohn.Forte@Sun.COM } else { 41507836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 41517836SJohn.Forte@Sun.COM (ilport->ilport_avg_interval + 41527836SJohn.Forte@Sun.COM ddi_get_lbolt() - 41537836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock) >> 1; 41547836SJohn.Forte@Sun.COM } 41557836SJohn.Forte@Sun.COM } 41567836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock = ddi_get_lbolt(); 41577836SJohn.Forte@Sun.COM ilport->ilport_online_times++; 41587836SJohn.Forte@Sun.COM 41597836SJohn.Forte@Sun.COM /* 41607836SJohn.Forte@Sun.COM * Submit online service request 41617836SJohn.Forte@Sun.COM */ 41627836SJohn.Forte@Sun.COM ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE; 41637836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINING; 41647836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41657836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 41667836SJohn.Forte@Sun.COM break; 41677836SJohn.Forte@Sun.COM 41687836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE_COMPLETE: 41697836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINING) { 41707836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41717836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41727836SJohn.Forte@Sun.COM } 41737836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 41747836SJohn.Forte@Sun.COM STMF_SUCCESS) { 41757836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 41767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41777836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 41787836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 41797836SJohn.Forte@Sun.COM STMF_ACK_LPORT_ONLINE_COMPLETE, arg); 41807836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 41817836SJohn.Forte@Sun.COM } else { 41827836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 41837836SJohn.Forte@Sun.COM } 41847836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 41857836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41867836SJohn.Forte@Sun.COM 41877836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 41887836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) { 41897836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 41907836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41917836SJohn.Forte@Sun.COM } 41927836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 41937836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 41947836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 41957836SJohn.Forte@Sun.COM } 41967836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINING; 41977836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41987836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 41997836SJohn.Forte@Sun.COM break; 42007836SJohn.Forte@Sun.COM 42017836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE_COMPLETE: 42027836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 42037836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 42047836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 42057836SJohn.Forte@Sun.COM } 42067836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 42077836SJohn.Forte@Sun.COM STMF_SUCCESS) { 42087836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 42097836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42107836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 42117836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 42127836SJohn.Forte@Sun.COM STMF_ACK_LPORT_OFFLINE_COMPLETE, arg); 42137836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 42147836SJohn.Forte@Sun.COM } else { 42157836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 42167836SJohn.Forte@Sun.COM } 42177836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42187836SJohn.Forte@Sun.COM break; 42197836SJohn.Forte@Sun.COM 42207836SJohn.Forte@Sun.COM default: 42217836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd); 42227836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 42237836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 42247836SJohn.Forte@Sun.COM } 42257836SJohn.Forte@Sun.COM 42267836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 42277836SJohn.Forte@Sun.COM 42287836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:; 42297836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42307836SJohn.Forte@Sun.COM return (ret); 42317836SJohn.Forte@Sun.COM } 42327836SJohn.Forte@Sun.COM 42337836SJohn.Forte@Sun.COM /* ARGSUSED */ 42347836SJohn.Forte@Sun.COM stmf_status_t 42357836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 42367836SJohn.Forte@Sun.COM uint32_t *bufsizep) 42377836SJohn.Forte@Sun.COM { 42387836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 42397836SJohn.Forte@Sun.COM } 42407836SJohn.Forte@Sun.COM 42417836SJohn.Forte@Sun.COM /* ARGSUSED */ 42427836SJohn.Forte@Sun.COM stmf_status_t 42437836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 42447836SJohn.Forte@Sun.COM uint32_t *bufsizep) 42457836SJohn.Forte@Sun.COM { 42467836SJohn.Forte@Sun.COM uint32_t cl = SI_GET_CLASS(cmd); 42477836SJohn.Forte@Sun.COM 42487836SJohn.Forte@Sun.COM if (cl == SI_STMF) { 42497836SJohn.Forte@Sun.COM return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep)); 42507836SJohn.Forte@Sun.COM } 42517836SJohn.Forte@Sun.COM if (cl == SI_LPORT) { 42528662SJordan.Vaughan@Sun.com return (((stmf_local_port_t *)arg1)->lport_info(cmd, arg1, 42538662SJordan.Vaughan@Sun.com arg2, buf, bufsizep)); 42547836SJohn.Forte@Sun.COM } else if (cl == SI_LU) { 42558662SJordan.Vaughan@Sun.com return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, buf, 42568662SJordan.Vaughan@Sun.com bufsizep)); 42577836SJohn.Forte@Sun.COM } 42587836SJohn.Forte@Sun.COM 42597836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 42607836SJohn.Forte@Sun.COM } 42617836SJohn.Forte@Sun.COM 42627836SJohn.Forte@Sun.COM /* 42637836SJohn.Forte@Sun.COM * Used by port providers. pwwn is 8 byte wwn, sdid is th devid used by 42647836SJohn.Forte@Sun.COM * stmf to register local ports. The ident should have 20 bytes in buffer 42657836SJohn.Forte@Sun.COM * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string. 42667836SJohn.Forte@Sun.COM */ 42677836SJohn.Forte@Sun.COM void 42687836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn, 42697836SJohn.Forte@Sun.COM uint8_t protocol_id) 42707836SJohn.Forte@Sun.COM { 42717836SJohn.Forte@Sun.COM sdid->protocol_id = protocol_id; 42727836SJohn.Forte@Sun.COM sdid->piv = 1; 42737836SJohn.Forte@Sun.COM sdid->code_set = CODE_SET_ASCII; 42747836SJohn.Forte@Sun.COM sdid->association = ID_IS_TARGET_PORT; 42757836SJohn.Forte@Sun.COM sdid->ident_length = 20; 42767836SJohn.Forte@Sun.COM (void) sprintf((char *)sdid->ident, 42777836SJohn.Forte@Sun.COM "wwn.%02X%02X%02X%02X%02X%02X%02X%02X", 42787836SJohn.Forte@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 42797836SJohn.Forte@Sun.COM } 42807836SJohn.Forte@Sun.COM 42817836SJohn.Forte@Sun.COM stmf_xfer_data_t * 42827836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data() 42837836SJohn.Forte@Sun.COM { 42847836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 42857836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 42867836SJohn.Forte@Sun.COM uint8_t *p; 42877836SJohn.Forte@Sun.COM uint32_t sz, asz, nports; 42887836SJohn.Forte@Sun.COM 42897836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 42907836SJohn.Forte@Sun.COM /* The spec only allows for 255 ports to be reported */ 42917836SJohn.Forte@Sun.COM nports = min(stmf_state.stmf_nlports, 255); 42927836SJohn.Forte@Sun.COM sz = (nports * 4) + 12; 42937836SJohn.Forte@Sun.COM asz = sz + sizeof (*xd) - 4; 42947836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP); 42957836SJohn.Forte@Sun.COM if (xd == NULL) { 42967836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 42977836SJohn.Forte@Sun.COM return (NULL); 42987836SJohn.Forte@Sun.COM } 42997836SJohn.Forte@Sun.COM xd->alloc_size = asz; 43007836SJohn.Forte@Sun.COM xd->size_left = sz; 43017836SJohn.Forte@Sun.COM 43027836SJohn.Forte@Sun.COM p = xd->buf; 43037836SJohn.Forte@Sun.COM 43047836SJohn.Forte@Sun.COM *((uint32_t *)p) = BE_32(sz - 4); 43057836SJohn.Forte@Sun.COM p += 4; 43067836SJohn.Forte@Sun.COM p[0] = 0x80; /* PREF */ 43077836SJohn.Forte@Sun.COM p[1] = 1; /* AO_SUP */ 43087836SJohn.Forte@Sun.COM p[7] = nports & 0xff; 43097836SJohn.Forte@Sun.COM p += 8; 43107836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport && nports; 43117836SJohn.Forte@Sun.COM nports++, ilport = ilport->ilport_next, p += 4) { 43127836SJohn.Forte@Sun.COM ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid); 43137836SJohn.Forte@Sun.COM } 43147836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 43157836SJohn.Forte@Sun.COM 43167836SJohn.Forte@Sun.COM return (xd); 43177836SJohn.Forte@Sun.COM } 43187836SJohn.Forte@Sun.COM 4319*9585STim.Szeto@Sun.COM struct scsi_devid_desc * 4320*9585STim.Szeto@Sun.COM stmf_scsilib_get_devid_desc(uint16_t rtpid) 4321*9585STim.Szeto@Sun.COM { 4322*9585STim.Szeto@Sun.COM scsi_devid_desc_t *devid = NULL; 4323*9585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 4324*9585STim.Szeto@Sun.COM 4325*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4326*9585STim.Szeto@Sun.COM 4327*9585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 4328*9585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 4329*9585STim.Szeto@Sun.COM if (ilport->ilport_rtpid == rtpid) { 4330*9585STim.Szeto@Sun.COM scsi_devid_desc_t *id = ilport->ilport_lport->lport_id; 4331*9585STim.Szeto@Sun.COM uint32_t id_sz = sizeof (scsi_devid_desc_t) - 1 + 4332*9585STim.Szeto@Sun.COM id->ident_length; 4333*9585STim.Szeto@Sun.COM devid = (scsi_devid_desc_t *)kmem_zalloc(id_sz, 4334*9585STim.Szeto@Sun.COM KM_NOSLEEP); 4335*9585STim.Szeto@Sun.COM if (devid != NULL) { 4336*9585STim.Szeto@Sun.COM bcopy(id, devid, id_sz); 4337*9585STim.Szeto@Sun.COM } 4338*9585STim.Szeto@Sun.COM break; 4339*9585STim.Szeto@Sun.COM } 4340*9585STim.Szeto@Sun.COM } 4341*9585STim.Szeto@Sun.COM 4342*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 4343*9585STim.Szeto@Sun.COM return (devid); 4344*9585STim.Szeto@Sun.COM } 4345*9585STim.Szeto@Sun.COM 4346*9585STim.Szeto@Sun.COM uint16_t 4347*9585STim.Szeto@Sun.COM stmf_scsilib_get_lport_rtid(struct scsi_devid_desc *devid) 4348*9585STim.Szeto@Sun.COM { 4349*9585STim.Szeto@Sun.COM stmf_i_local_port_t *ilport; 4350*9585STim.Szeto@Sun.COM scsi_devid_desc_t *id; 4351*9585STim.Szeto@Sun.COM uint16_t rtpid = 0; 4352*9585STim.Szeto@Sun.COM 4353*9585STim.Szeto@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4354*9585STim.Szeto@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 4355*9585STim.Szeto@Sun.COM ilport = ilport->ilport_next) { 4356*9585STim.Szeto@Sun.COM id = ilport->ilport_lport->lport_id; 4357*9585STim.Szeto@Sun.COM if ((devid->ident_length == id->ident_length) && 4358*9585STim.Szeto@Sun.COM (memcmp(devid->ident, id->ident, id->ident_length) == 0)) { 4359*9585STim.Szeto@Sun.COM rtpid = ilport->ilport_rtpid; 4360*9585STim.Szeto@Sun.COM break; 4361*9585STim.Szeto@Sun.COM } 4362*9585STim.Szeto@Sun.COM } 4363*9585STim.Szeto@Sun.COM mutex_exit(&stmf_state.stmf_lock); 4364*9585STim.Szeto@Sun.COM return (rtpid); 4365*9585STim.Szeto@Sun.COM } 43667836SJohn.Forte@Sun.COM 43677836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0; 43687836SJohn.Forte@Sun.COM 43697836SJohn.Forte@Sun.COM stmf_status_t 43707836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id) 43717836SJohn.Forte@Sun.COM { 43727836SJohn.Forte@Sun.COM uint8_t *p; 43737836SJohn.Forte@Sun.COM struct timeval32 timestamp32; 43747836SJohn.Forte@Sun.COM uint32_t *t = (uint32_t *)×tamp32; 43757836SJohn.Forte@Sun.COM struct ether_addr mac; 43767836SJohn.Forte@Sun.COM uint8_t *e = (uint8_t *)&mac; 43777836SJohn.Forte@Sun.COM 43787836SJohn.Forte@Sun.COM if (company_id == COMPANY_ID_NONE) 43797836SJohn.Forte@Sun.COM company_id = COMPANY_ID_SUN; 43807836SJohn.Forte@Sun.COM 43817836SJohn.Forte@Sun.COM if (lu_id->ident_length != 0x10) 43827836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 43837836SJohn.Forte@Sun.COM 43847836SJohn.Forte@Sun.COM p = (uint8_t *)lu_id; 43857836SJohn.Forte@Sun.COM 43867836SJohn.Forte@Sun.COM atomic_add_16(&stmf_lu_id_gen_number, 1); 43877836SJohn.Forte@Sun.COM 43887836SJohn.Forte@Sun.COM p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10; 43897836SJohn.Forte@Sun.COM p[4] = ((company_id >> 20) & 0xf) | 0x60; 43907836SJohn.Forte@Sun.COM p[5] = (company_id >> 12) & 0xff; 43917836SJohn.Forte@Sun.COM p[6] = (company_id >> 4) & 0xff; 43927836SJohn.Forte@Sun.COM p[7] = (company_id << 4) & 0xf0; 43937836SJohn.Forte@Sun.COM if (!localetheraddr((struct ether_addr *)NULL, &mac)) { 43948662SJordan.Vaughan@Sun.com int hid = BE_32((int)zone_get_hostid(NULL)); 43957836SJohn.Forte@Sun.COM e[0] = (hid >> 24) & 0xff; 43967836SJohn.Forte@Sun.COM e[1] = (hid >> 16) & 0xff; 43977836SJohn.Forte@Sun.COM e[2] = (hid >> 8) & 0xff; 43987836SJohn.Forte@Sun.COM e[3] = hid & 0xff; 43997836SJohn.Forte@Sun.COM e[4] = e[5] = 0; 44007836SJohn.Forte@Sun.COM } 44017836SJohn.Forte@Sun.COM bcopy(e, p+8, 6); 44027836SJohn.Forte@Sun.COM uniqtime32(×tamp32); 44037836SJohn.Forte@Sun.COM *t = BE_32(*t); 44047836SJohn.Forte@Sun.COM bcopy(t, p+14, 4); 44057836SJohn.Forte@Sun.COM p[18] = (stmf_lu_id_gen_number >> 8) & 0xff; 44067836SJohn.Forte@Sun.COM p[19] = stmf_lu_id_gen_number & 0xff; 44077836SJohn.Forte@Sun.COM 44087836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 44097836SJohn.Forte@Sun.COM } 44107836SJohn.Forte@Sun.COM 44117836SJohn.Forte@Sun.COM /* 44127836SJohn.Forte@Sun.COM * saa is sense key, ASC, ASCQ 44137836SJohn.Forte@Sun.COM */ 44147836SJohn.Forte@Sun.COM void 44157836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa) 44167836SJohn.Forte@Sun.COM { 44177836SJohn.Forte@Sun.COM uint8_t sd[18]; 44187836SJohn.Forte@Sun.COM task->task_scsi_status = st; 44197836SJohn.Forte@Sun.COM if (st == 2) { 44207836SJohn.Forte@Sun.COM bzero(sd, 18); 44217836SJohn.Forte@Sun.COM sd[0] = 0x70; 44227836SJohn.Forte@Sun.COM sd[2] = (saa >> 16) & 0xf; 44237836SJohn.Forte@Sun.COM sd[7] = 10; 44247836SJohn.Forte@Sun.COM sd[12] = (saa >> 8) & 0xff; 44257836SJohn.Forte@Sun.COM sd[13] = saa & 0xff; 44267836SJohn.Forte@Sun.COM task->task_sense_data = sd; 44277836SJohn.Forte@Sun.COM task->task_sense_length = 18; 44287836SJohn.Forte@Sun.COM } else { 44297836SJohn.Forte@Sun.COM task->task_sense_data = NULL; 44307836SJohn.Forte@Sun.COM task->task_sense_length = 0; 44317836SJohn.Forte@Sun.COM } 44327836SJohn.Forte@Sun.COM (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE); 44337836SJohn.Forte@Sun.COM } 44347836SJohn.Forte@Sun.COM 44357836SJohn.Forte@Sun.COM uint32_t 44367836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page, 44377836SJohn.Forte@Sun.COM uint32_t page_len, uint8_t byte0, uint32_t vpd_mask) 44387836SJohn.Forte@Sun.COM { 44397836SJohn.Forte@Sun.COM uint8_t *p = NULL; 44407836SJohn.Forte@Sun.COM uint8_t small_buf[32]; 44417836SJohn.Forte@Sun.COM uint32_t sz = 0; 44427836SJohn.Forte@Sun.COM uint32_t n = 4; 44437836SJohn.Forte@Sun.COM uint32_t m = 0; 44447836SJohn.Forte@Sun.COM uint32_t last_bit = 0; 44457836SJohn.Forte@Sun.COM 44467836SJohn.Forte@Sun.COM if (page_len < 4) 44477836SJohn.Forte@Sun.COM return (0); 44487836SJohn.Forte@Sun.COM if (page_len > 65535) 44497836SJohn.Forte@Sun.COM page_len = 65535; 44507836SJohn.Forte@Sun.COM 44517836SJohn.Forte@Sun.COM page[0] = byte0; 44527836SJohn.Forte@Sun.COM page[1] = 0x83; 44537836SJohn.Forte@Sun.COM 44547836SJohn.Forte@Sun.COM /* CONSTCOND */ 44557836SJohn.Forte@Sun.COM while (1) { 44567836SJohn.Forte@Sun.COM m += sz; 44577836SJohn.Forte@Sun.COM if (sz && (page_len > n)) { 44587836SJohn.Forte@Sun.COM uint32_t copysz; 44597836SJohn.Forte@Sun.COM copysz = page_len > (n + sz) ? sz : page_len - n; 44607836SJohn.Forte@Sun.COM bcopy(p, page + n, copysz); 44617836SJohn.Forte@Sun.COM n += copysz; 44627836SJohn.Forte@Sun.COM } 44637836SJohn.Forte@Sun.COM vpd_mask &= ~last_bit; 44647836SJohn.Forte@Sun.COM if (vpd_mask == 0) 44657836SJohn.Forte@Sun.COM break; 44667836SJohn.Forte@Sun.COM 44677836SJohn.Forte@Sun.COM if (vpd_mask & STMF_VPD_LU_ID) { 44687836SJohn.Forte@Sun.COM last_bit = STMF_VPD_LU_ID; 44697836SJohn.Forte@Sun.COM sz = task->task_lu->lu_id->ident_length + 4; 44707836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lu->lu_id; 44717836SJohn.Forte@Sun.COM continue; 44727836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TARGET_ID) { 44737836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TARGET_ID; 44747836SJohn.Forte@Sun.COM sz = task->task_lport->lport_id->ident_length + 4; 44757836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lport->lport_id; 44767836SJohn.Forte@Sun.COM continue; 44777836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TP_GROUP) { 44787836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TP_GROUP; 44797836SJohn.Forte@Sun.COM p = small_buf; 44807836SJohn.Forte@Sun.COM bzero(p, 8); 44817836SJohn.Forte@Sun.COM p[0] = 1; 44827836SJohn.Forte@Sun.COM p[1] = 0x15; 44837836SJohn.Forte@Sun.COM p[3] = 4; 44847836SJohn.Forte@Sun.COM /* Group ID is always 0 */ 44857836SJohn.Forte@Sun.COM sz = 8; 44867836SJohn.Forte@Sun.COM continue; 44877836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) { 44887836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 44897836SJohn.Forte@Sun.COM 44907836SJohn.Forte@Sun.COM last_bit = STMF_VPD_RELATIVE_TP_ID; 44917836SJohn.Forte@Sun.COM p = small_buf; 44927836SJohn.Forte@Sun.COM bzero(p, 8); 44937836SJohn.Forte@Sun.COM p[0] = 1; 44947836SJohn.Forte@Sun.COM p[1] = 0x14; 44957836SJohn.Forte@Sun.COM p[3] = 4; 44967836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *) 44978662SJordan.Vaughan@Sun.com task->task_lport->lport_stmf_private; 44987836SJohn.Forte@Sun.COM p[6] = (ilport->ilport_rtpid >> 8) & 0xff; 44997836SJohn.Forte@Sun.COM p[7] = ilport->ilport_rtpid & 0xff; 45007836SJohn.Forte@Sun.COM sz = 8; 45017836SJohn.Forte@Sun.COM continue; 45027836SJohn.Forte@Sun.COM } else { 45037836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid vpd_mask"); 45047836SJohn.Forte@Sun.COM break; 45057836SJohn.Forte@Sun.COM } 45067836SJohn.Forte@Sun.COM } 45077836SJohn.Forte@Sun.COM 45087836SJohn.Forte@Sun.COM page[2] = (m >> 8) & 0xff; 45097836SJohn.Forte@Sun.COM page[3] = m & 0xff; 45107836SJohn.Forte@Sun.COM 45117836SJohn.Forte@Sun.COM return (n); 45127836SJohn.Forte@Sun.COM } 45137836SJohn.Forte@Sun.COM 45147836SJohn.Forte@Sun.COM void 45157836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf) 45167836SJohn.Forte@Sun.COM { 45177836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 45188662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 45197836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 45207836SJohn.Forte@Sun.COM uint32_t sz, minsz; 45217836SJohn.Forte@Sun.COM 45227836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING; 45237836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 45247836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 45257836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 45267836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 45277836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 45287836SJohn.Forte@Sun.COM 45297836SJohn.Forte@Sun.COM if (task->task_additional_flags & 45307836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 45317836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 45327836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 45337836SJohn.Forte@Sun.COM } 45347836SJohn.Forte@Sun.COM 45357836SJohn.Forte@Sun.COM if (task->task_cmd_xfer_length < 16) { 45367836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 45378662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 45387836SJohn.Forte@Sun.COM return; 45397836SJohn.Forte@Sun.COM } 45407836SJohn.Forte@Sun.COM 45417836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 45427836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 45437836SJohn.Forte@Sun.COM 45447836SJohn.Forte@Sun.COM xd = stmf_prepare_tpgs_data(); 45457836SJohn.Forte@Sun.COM 45467836SJohn.Forte@Sun.COM if (xd == NULL) { 45477836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 45487836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 45497836SJohn.Forte@Sun.COM return; 45507836SJohn.Forte@Sun.COM } 45517836SJohn.Forte@Sun.COM 45527836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 45537836SJohn.Forte@Sun.COM xd->size_left = sz; 45547836SJohn.Forte@Sun.COM minsz = min(512, sz); 45557836SJohn.Forte@Sun.COM 45567836SJohn.Forte@Sun.COM if (dbuf == NULL) 45577836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 45587836SJohn.Forte@Sun.COM if (dbuf == NULL) { 45597836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 45607836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 45617836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 45627836SJohn.Forte@Sun.COM return; 45637836SJohn.Forte@Sun.COM } 45647836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 45657836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 45667836SJohn.Forte@Sun.COM 45677836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 45687836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 45697836SJohn.Forte@Sun.COM 45707836SJohn.Forte@Sun.COM } 45717836SJohn.Forte@Sun.COM 45727836SJohn.Forte@Sun.COM void 45737836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task) 45747836SJohn.Forte@Sun.COM { 45757836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 45767836SJohn.Forte@Sun.COM /* 45777836SJohn.Forte@Sun.COM * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET 45787836SJohn.Forte@Sun.COM * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state 45797836SJohn.Forte@Sun.COM * in these cases. This needs to be changed to abort only the required 45807836SJohn.Forte@Sun.COM * set. 45817836SJohn.Forte@Sun.COM */ 45827836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 45837836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 45847836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 45857836SJohn.Forte@Sun.COM case TM_LUN_RESET: 45867836SJohn.Forte@Sun.COM stmf_handle_lun_reset(task); 45877836SJohn.Forte@Sun.COM return; 45887836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 45897836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 45907836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 45917836SJohn.Forte@Sun.COM stmf_handle_target_reset(task); 45927836SJohn.Forte@Sun.COM return; 45937836SJohn.Forte@Sun.COM default: 45947836SJohn.Forte@Sun.COM /* We dont support this task mgmt function */ 45957836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 45967836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CMD_IU); 45977836SJohn.Forte@Sun.COM return; 45987836SJohn.Forte@Sun.COM } 45997836SJohn.Forte@Sun.COM } 46007836SJohn.Forte@Sun.COM 46017836SJohn.Forte@Sun.COM void 46027836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task) 46037836SJohn.Forte@Sun.COM { 46047836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 46057836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 46067836SJohn.Forte@Sun.COM 46077836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 46087836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 46097836SJohn.Forte@Sun.COM 46107836SJohn.Forte@Sun.COM /* 46117836SJohn.Forte@Sun.COM * To sync with target reset, grab this lock. The LU is not going 46127836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 46137836SJohn.Forte@Sun.COM */ 46147836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 46157836SJohn.Forte@Sun.COM 46167836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 46177836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46187836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46198662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46207836SJohn.Forte@Sun.COM return; 46217836SJohn.Forte@Sun.COM } 46227836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 46237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46247836SJohn.Forte@Sun.COM 46257836SJohn.Forte@Sun.COM /* 46267836SJohn.Forte@Sun.COM * Mark this task as the one causing LU reset so that we know who 46277836SJohn.Forte@Sun.COM * was responsible for setting the ILU_RESET_ACTIVE. In case this 46287836SJohn.Forte@Sun.COM * task itself gets aborted, we will clear ILU_RESET_ACTIVE. 46297836SJohn.Forte@Sun.COM */ 46307836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET; 46317836SJohn.Forte@Sun.COM 46327836SJohn.Forte@Sun.COM /* Initiatiate abort on all commands on this LU except this one */ 46337836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu); 46347836SJohn.Forte@Sun.COM 46357836SJohn.Forte@Sun.COM /* Start polling on this task */ 46367836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 46377836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 46387836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 46398662SJordan.Vaughan@Sun.com NULL); 46407836SJohn.Forte@Sun.COM return; 46417836SJohn.Forte@Sun.COM } 46427836SJohn.Forte@Sun.COM } 46437836SJohn.Forte@Sun.COM 46447836SJohn.Forte@Sun.COM void 46457836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task) 46467836SJohn.Forte@Sun.COM { 46477836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 46487836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 46497836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 46507836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 46517836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 46527836SJohn.Forte@Sun.COM int i, lf; 46537836SJohn.Forte@Sun.COM 46547836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 46557836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private; 46567836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 46577836SJohn.Forte@Sun.COM 46587836SJohn.Forte@Sun.COM /* 46597836SJohn.Forte@Sun.COM * To sync with LUN reset, grab this lock. The session is not going 46607836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 46617836SJohn.Forte@Sun.COM */ 46627836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 46637979SSumit.Gupta@Sun.COM 46647979SSumit.Gupta@Sun.COM /* Grab the session lock as a writer to prevent any changes in it */ 46657979SSumit.Gupta@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 46667979SSumit.Gupta@Sun.COM 46677836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_RESET_ACTIVE) { 46687979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 46697836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46707836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46718662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46727836SJohn.Forte@Sun.COM return; 46737836SJohn.Forte@Sun.COM } 46747836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE); 46757836SJohn.Forte@Sun.COM 46767836SJohn.Forte@Sun.COM /* 46777836SJohn.Forte@Sun.COM * Now go through each LUN in this session and make sure all of them 46787836SJohn.Forte@Sun.COM * can be reset. 46797836SJohn.Forte@Sun.COM */ 46807836SJohn.Forte@Sun.COM lm = iss->iss_sm; 46817836SJohn.Forte@Sun.COM for (i = 0, lf = 0; i < lm->lm_nentries; i++) { 46827836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 46837836SJohn.Forte@Sun.COM continue; 46847836SJohn.Forte@Sun.COM lf++; 46857836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 46867836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 46877836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 46887836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 46897979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 46907836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 46917836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46928662SJordan.Vaughan@Sun.com STMF_SAA_OPERATION_IN_PROGRESS); 46937836SJohn.Forte@Sun.COM return; 46947836SJohn.Forte@Sun.COM } 46957836SJohn.Forte@Sun.COM } 46967836SJohn.Forte@Sun.COM if (lf == 0) { 46977836SJohn.Forte@Sun.COM /* No luns in this session */ 46987836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 46997979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 47007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 47017836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 47027836SJohn.Forte@Sun.COM return; 47037836SJohn.Forte@Sun.COM } 47047836SJohn.Forte@Sun.COM 47057836SJohn.Forte@Sun.COM /* ok, start the damage */ 47067836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | 47078662SJordan.Vaughan@Sun.com ITASK_CAUSING_TARGET_RESET; 47087836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 47097836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 47107836SJohn.Forte@Sun.COM continue; 47117836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 47127836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 47137836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 47147836SJohn.Forte@Sun.COM } 47157979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 47167836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 47177836SJohn.Forte@Sun.COM 47187836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 47197836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 47207836SJohn.Forte@Sun.COM continue; 47217836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 47227836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, 47238662SJordan.Vaughan@Sun.com lm_ent->ent_lu); 47247836SJohn.Forte@Sun.COM } 47257836SJohn.Forte@Sun.COM 47267836SJohn.Forte@Sun.COM /* Start polling on this task */ 47277836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 47287836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 47297836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 47308662SJordan.Vaughan@Sun.com NULL); 47317836SJohn.Forte@Sun.COM return; 47327836SJohn.Forte@Sun.COM } 47337836SJohn.Forte@Sun.COM } 47347836SJohn.Forte@Sun.COM 47357836SJohn.Forte@Sun.COM int 47367836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask) 47377836SJohn.Forte@Sun.COM { 47387836SJohn.Forte@Sun.COM scsi_task_t *task = itask->itask_task; 47397836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 47407836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 47417836SJohn.Forte@Sun.COM 47427836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 47437836SJohn.Forte@Sun.COM if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) || 47447836SJohn.Forte@Sun.COM (task->task_cdb[0] == SCMD_INQUIRY)) { 47457836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 47467836SJohn.Forte@Sun.COM return (0); 47477836SJohn.Forte@Sun.COM } 47487836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 47498662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 47507836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 47517836SJohn.Forte@Sun.COM 47527836SJohn.Forte@Sun.COM if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 47537836SJohn.Forte@Sun.COM return (0); 47547836SJohn.Forte@Sun.COM } 47557836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 47567836SJohn.Forte@Sun.COM STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED); 47577836SJohn.Forte@Sun.COM return (1); 47587836SJohn.Forte@Sun.COM } 47597836SJohn.Forte@Sun.COM 47607836SJohn.Forte@Sun.COM void 47617836SJohn.Forte@Sun.COM stmf_worker_init() 47627836SJohn.Forte@Sun.COM { 47637836SJohn.Forte@Sun.COM uint32_t i; 47647836SJohn.Forte@Sun.COM 47657836SJohn.Forte@Sun.COM /* Make local copy of global tunables */ 47667836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_max_nworkers; 47677836SJohn.Forte@Sun.COM stmf_i_min_nworkers = stmf_min_nworkers; 47687836SJohn.Forte@Sun.COM 47697836SJohn.Forte@Sun.COM ASSERT(stmf_workers == NULL); 47707836SJohn.Forte@Sun.COM if (stmf_i_min_nworkers < 4) { 47717836SJohn.Forte@Sun.COM stmf_i_min_nworkers = 4; 47727836SJohn.Forte@Sun.COM } 47737836SJohn.Forte@Sun.COM if (stmf_i_max_nworkers < stmf_i_min_nworkers) { 47747836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_i_min_nworkers; 47757836SJohn.Forte@Sun.COM } 47767836SJohn.Forte@Sun.COM stmf_workers = (stmf_worker_t *)kmem_zalloc( 47777836SJohn.Forte@Sun.COM sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP); 47787836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 47797836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 47807836SJohn.Forte@Sun.COM mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 47817836SJohn.Forte@Sun.COM cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 47827836SJohn.Forte@Sun.COM } 47837836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 47847836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 47857836SJohn.Forte@Sun.COM 47867836SJohn.Forte@Sun.COM /* Workers will be started by stmf_worker_mgmt() */ 47877836SJohn.Forte@Sun.COM 47887836SJohn.Forte@Sun.COM /* Lets wait for atleast one worker to start */ 47897836SJohn.Forte@Sun.COM while (stmf_nworkers_cur == 0) 47907836SJohn.Forte@Sun.COM delay(drv_usectohz(20 * 1000)); 47917836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000); 47927836SJohn.Forte@Sun.COM } 47937836SJohn.Forte@Sun.COM 47947836SJohn.Forte@Sun.COM stmf_status_t 47957836SJohn.Forte@Sun.COM stmf_worker_fini() 47967836SJohn.Forte@Sun.COM { 47977836SJohn.Forte@Sun.COM int i; 47987836SJohn.Forte@Sun.COM clock_t sb; 47997836SJohn.Forte@Sun.COM 48007836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) 48017836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 48027836SJohn.Forte@Sun.COM ASSERT(stmf_workers); 48037836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_DISABLED; 48047836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 48057836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 48067836SJohn.Forte@Sun.COM 48077836SJohn.Forte@Sun.COM sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000); 48087836SJohn.Forte@Sun.COM /* Wait for all the threads to die */ 48097836SJohn.Forte@Sun.COM while (stmf_nworkers_cur != 0) { 48107836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > sb) { 48117836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 48127836SJohn.Forte@Sun.COM return (STMF_BUSY); 48137836SJohn.Forte@Sun.COM } 48147836SJohn.Forte@Sun.COM delay(drv_usectohz(100 * 1000)); 48157836SJohn.Forte@Sun.COM } 48167836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 48177836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 48187836SJohn.Forte@Sun.COM mutex_destroy(&w->worker_lock); 48197836SJohn.Forte@Sun.COM cv_destroy(&w->worker_cv); 48207836SJohn.Forte@Sun.COM } 48217836SJohn.Forte@Sun.COM kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers); 48227836SJohn.Forte@Sun.COM stmf_workers = NULL; 48237836SJohn.Forte@Sun.COM 48247836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 48257836SJohn.Forte@Sun.COM } 48267836SJohn.Forte@Sun.COM 48277836SJohn.Forte@Sun.COM void 48287836SJohn.Forte@Sun.COM stmf_worker_task(void *arg) 48297836SJohn.Forte@Sun.COM { 48307836SJohn.Forte@Sun.COM stmf_worker_t *w; 48317836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 48327836SJohn.Forte@Sun.COM scsi_task_t *task; 48337836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 48347836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 48357836SJohn.Forte@Sun.COM stmf_lu_t *lu; 48367836SJohn.Forte@Sun.COM clock_t wait_timer = 0; 48377836SJohn.Forte@Sun.COM clock_t wait_ticks; 48387836SJohn.Forte@Sun.COM uint32_t old, new; 48397836SJohn.Forte@Sun.COM uint8_t curcmd; 48407836SJohn.Forte@Sun.COM uint8_t abort_free; 48417836SJohn.Forte@Sun.COM uint8_t wait_queue; 48427836SJohn.Forte@Sun.COM uint8_t dec_qdepth; 48437836SJohn.Forte@Sun.COM 48447836SJohn.Forte@Sun.COM w = (stmf_worker_t *)arg; 48457836SJohn.Forte@Sun.COM wait_ticks = drv_usectohz(10000); 48467836SJohn.Forte@Sun.COM 48477836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 48487836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE; 48497836SJohn.Forte@Sun.COM stmf_worker_loop:; 48507836SJohn.Forte@Sun.COM if ((w->worker_ref_count == 0) && 48517836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 48527836SJohn.Forte@Sun.COM w->worker_flags &= ~(STMF_WORKER_STARTED | 48537836SJohn.Forte@Sun.COM STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE); 48547836SJohn.Forte@Sun.COM w->worker_tid = NULL; 48557836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 48567836SJohn.Forte@Sun.COM thread_exit(); 48577836SJohn.Forte@Sun.COM } 48587836SJohn.Forte@Sun.COM /* CONSTCOND */ 48597836SJohn.Forte@Sun.COM while (1) { 48607836SJohn.Forte@Sun.COM dec_qdepth = 0; 48617836SJohn.Forte@Sun.COM if (wait_timer && (ddi_get_lbolt() >= wait_timer)) { 48627836SJohn.Forte@Sun.COM wait_timer = 0; 48637979SSumit.Gupta@Sun.COM if (w->worker_wait_head) { 48647979SSumit.Gupta@Sun.COM ASSERT(w->worker_wait_tail); 48657979SSumit.Gupta@Sun.COM if (w->worker_task_head == NULL) 48667979SSumit.Gupta@Sun.COM w->worker_task_head = 48677979SSumit.Gupta@Sun.COM w->worker_wait_head; 48687979SSumit.Gupta@Sun.COM else 48697979SSumit.Gupta@Sun.COM w->worker_task_tail->itask_worker_next = 48708662SJordan.Vaughan@Sun.com w->worker_wait_head; 48717979SSumit.Gupta@Sun.COM w->worker_task_tail = w->worker_wait_tail; 48727979SSumit.Gupta@Sun.COM w->worker_wait_head = w->worker_wait_tail = 48737979SSumit.Gupta@Sun.COM NULL; 48747979SSumit.Gupta@Sun.COM } 48757836SJohn.Forte@Sun.COM } 48767836SJohn.Forte@Sun.COM if ((itask = w->worker_task_head) == NULL) { 48777836SJohn.Forte@Sun.COM break; 48787836SJohn.Forte@Sun.COM } 48797836SJohn.Forte@Sun.COM task = itask->itask_task; 48807836SJohn.Forte@Sun.COM w->worker_task_head = itask->itask_worker_next; 48817836SJohn.Forte@Sun.COM if (w->worker_task_head == NULL) 48827836SJohn.Forte@Sun.COM w->worker_task_tail = NULL; 48837836SJohn.Forte@Sun.COM 48847836SJohn.Forte@Sun.COM wait_queue = 0; 48857836SJohn.Forte@Sun.COM abort_free = 0; 48867836SJohn.Forte@Sun.COM if (itask->itask_ncmds > 0) { 48877836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1]; 48887836SJohn.Forte@Sun.COM } else { 48897836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_BEING_ABORTED); 48907836SJohn.Forte@Sun.COM } 48917836SJohn.Forte@Sun.COM do { 48927836SJohn.Forte@Sun.COM old = itask->itask_flags; 48937836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 48947836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 48957836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[0] = 48967836SJohn.Forte@Sun.COM ITASK_CMD_ABORT; 48977836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 48987836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_MASK) == 48997836SJohn.Forte@Sun.COM ITASK_CMD_NEW_TASK) { 49007836SJohn.Forte@Sun.COM new = old | ITASK_KNOWN_TO_LU; 49017836SJohn.Forte@Sun.COM } else { 49027836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 49037836SJohn.Forte@Sun.COM } 49047836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 49057836SJohn.Forte@Sun.COM 49067836SJohn.Forte@Sun.COM out_itask_flag_loop: 49077836SJohn.Forte@Sun.COM 49087836SJohn.Forte@Sun.COM /* 49097836SJohn.Forte@Sun.COM * Decide if this task needs to go to a queue and/or if 49107836SJohn.Forte@Sun.COM * we can decrement the itask_cmd_stack. 49117836SJohn.Forte@Sun.COM */ 49127836SJohn.Forte@Sun.COM if (curcmd == ITASK_CMD_ABORT) { 49137836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_KNOWN_TO_LU | 49147836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT)) { 49157836SJohn.Forte@Sun.COM wait_queue = 1; 49167836SJohn.Forte@Sun.COM } else { 49177836SJohn.Forte@Sun.COM abort_free = 1; 49187836SJohn.Forte@Sun.COM } 49197836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_POLL) && 49207836SJohn.Forte@Sun.COM (itask->itask_poll_timeout > ddi_get_lbolt())) { 49217836SJohn.Forte@Sun.COM wait_queue = 1; 49227836SJohn.Forte@Sun.COM } 49237836SJohn.Forte@Sun.COM 49247836SJohn.Forte@Sun.COM if (wait_queue) { 49257836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 49267836SJohn.Forte@Sun.COM if (w->worker_wait_tail) { 49277836SJohn.Forte@Sun.COM w->worker_wait_tail->itask_worker_next = itask; 49287836SJohn.Forte@Sun.COM } else { 49297836SJohn.Forte@Sun.COM w->worker_wait_head = itask; 49307836SJohn.Forte@Sun.COM } 49317836SJohn.Forte@Sun.COM w->worker_wait_tail = itask; 49327836SJohn.Forte@Sun.COM if (wait_timer == 0) { 49337836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + wait_ticks; 49347836SJohn.Forte@Sun.COM } 49357836SJohn.Forte@Sun.COM } else if ((--(itask->itask_ncmds)) != 0) { 49367836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 49377836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 49387836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 49397836SJohn.Forte@Sun.COM } else { 49407836SJohn.Forte@Sun.COM w->worker_task_head = itask; 49417836SJohn.Forte@Sun.COM } 49427836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 49437836SJohn.Forte@Sun.COM } else { 49447836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 49457836SJohn.Forte@Sun.COM ~ITASK_IN_WORKER_QUEUE); 49467836SJohn.Forte@Sun.COM /* 49477836SJohn.Forte@Sun.COM * This is where the queue depth should go down by 49487836SJohn.Forte@Sun.COM * one but we delay that on purpose to account for 49497836SJohn.Forte@Sun.COM * the call into the provider. The actual decrement 49507836SJohn.Forte@Sun.COM * happens after the worker has done its job. 49517836SJohn.Forte@Sun.COM */ 49527836SJohn.Forte@Sun.COM dec_qdepth = 1; 49537836SJohn.Forte@Sun.COM } 49547836SJohn.Forte@Sun.COM 49557836SJohn.Forte@Sun.COM /* We made it here means we are going to call LU */ 49567836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) 49577836SJohn.Forte@Sun.COM lu = task->task_lu; 49587836SJohn.Forte@Sun.COM else 49597836SJohn.Forte@Sun.COM lu = dlun0; 49607836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)]; 49617836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 49627836SJohn.Forte@Sun.COM curcmd &= ITASK_CMD_MASK; 49637836SJohn.Forte@Sun.COM switch (curcmd) { 49647836SJohn.Forte@Sun.COM case ITASK_CMD_NEW_TASK: 49657836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 49667836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 49679435STim.Szeto@Sun.COM stmf_update_kstat_lu_q(task, kstat_waitq_to_runq); 49689435STim.Szeto@Sun.COM stmf_update_kstat_lport_q(task, kstat_waitq_to_runq); 49697836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) { 49707836SJohn.Forte@Sun.COM if (stmf_handle_cmd_during_ic(itask)) 49717836SJohn.Forte@Sun.COM break; 49727836SJohn.Forte@Sun.COM } 49737836SJohn.Forte@Sun.COM #ifdef DEBUG 49747836SJohn.Forte@Sun.COM if (stmf_drop_task_counter > 0) { 49757836SJohn.Forte@Sun.COM if (atomic_add_32_nv( 49767836SJohn.Forte@Sun.COM (uint32_t *)&stmf_drop_task_counter, 49777836SJohn.Forte@Sun.COM -1) == 1) { 49787836SJohn.Forte@Sun.COM break; 49797836SJohn.Forte@Sun.COM } 49807836SJohn.Forte@Sun.COM } 49817836SJohn.Forte@Sun.COM #endif 49828859STim.Szeto@Sun.COM DTRACE_PROBE1(scsi__task__start, scsi_task_t *, task); 49837836SJohn.Forte@Sun.COM lu->lu_new_task(task, dbuf); 49847836SJohn.Forte@Sun.COM break; 49857836SJohn.Forte@Sun.COM case ITASK_CMD_DATA_XFER_DONE: 49867836SJohn.Forte@Sun.COM lu->lu_dbuf_xfer_done(task, dbuf); 49877836SJohn.Forte@Sun.COM break; 49887836SJohn.Forte@Sun.COM case ITASK_CMD_STATUS_DONE: 49897836SJohn.Forte@Sun.COM lu->lu_send_status_done(task); 49907836SJohn.Forte@Sun.COM break; 49917836SJohn.Forte@Sun.COM case ITASK_CMD_ABORT: 49927836SJohn.Forte@Sun.COM if (abort_free) { 49937836SJohn.Forte@Sun.COM stmf_task_free(task); 49947836SJohn.Forte@Sun.COM } else { 49957836SJohn.Forte@Sun.COM stmf_do_task_abort(task); 49967836SJohn.Forte@Sun.COM } 49977836SJohn.Forte@Sun.COM break; 49987836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LU: 49997836SJohn.Forte@Sun.COM if (!wait_queue) { 50007836SJohn.Forte@Sun.COM lu->lu_task_poll(task); 50017836SJohn.Forte@Sun.COM } 50027836SJohn.Forte@Sun.COM break; 50037836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LPORT: 50047836SJohn.Forte@Sun.COM if (!wait_queue) 50057836SJohn.Forte@Sun.COM task->task_lport->lport_task_poll(task); 50067836SJohn.Forte@Sun.COM break; 50077836SJohn.Forte@Sun.COM case ITASK_CMD_SEND_STATUS: 50087836SJohn.Forte@Sun.COM /* case ITASK_CMD_XFER_DATA: */ 50097836SJohn.Forte@Sun.COM break; 50107836SJohn.Forte@Sun.COM } 50117836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 50127836SJohn.Forte@Sun.COM if (dec_qdepth) { 50137836SJohn.Forte@Sun.COM w->worker_queue_depth--; 50147836SJohn.Forte@Sun.COM } 50157836SJohn.Forte@Sun.COM } 50167836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) { 50177836SJohn.Forte@Sun.COM if (w->worker_ref_count == 0) 50187836SJohn.Forte@Sun.COM goto stmf_worker_loop; 50197836SJohn.Forte@Sun.COM else 50207836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + 1; 50217836SJohn.Forte@Sun.COM } 50227836SJohn.Forte@Sun.COM w->worker_flags &= ~STMF_WORKER_ACTIVE; 50237836SJohn.Forte@Sun.COM if (wait_timer) { 50247836SJohn.Forte@Sun.COM (void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer); 50257836SJohn.Forte@Sun.COM } else { 50267836SJohn.Forte@Sun.COM cv_wait(&w->worker_cv, &w->worker_lock); 50277836SJohn.Forte@Sun.COM } 50287836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_ACTIVE; 50297836SJohn.Forte@Sun.COM goto stmf_worker_loop; 50307836SJohn.Forte@Sun.COM } 50317836SJohn.Forte@Sun.COM 50327836SJohn.Forte@Sun.COM void 50337836SJohn.Forte@Sun.COM stmf_worker_mgmt() 50347836SJohn.Forte@Sun.COM { 50357836SJohn.Forte@Sun.COM int i; 50367836SJohn.Forte@Sun.COM int workers_needed; 50377836SJohn.Forte@Sun.COM uint32_t qd; 50387836SJohn.Forte@Sun.COM clock_t tps, d = 0; 50397836SJohn.Forte@Sun.COM uint32_t cur_max_ntasks = 0; 50407836SJohn.Forte@Sun.COM stmf_worker_t *w; 50417836SJohn.Forte@Sun.COM 50427836SJohn.Forte@Sun.COM /* Check if we are trying to increase the # of threads */ 50437836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) { 50447836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) { 50457836SJohn.Forte@Sun.COM stmf_nworkers_cur++; 50467836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds++; 50477836SJohn.Forte@Sun.COM } else { 50487836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 50497836SJohn.Forte@Sun.COM return; 50507836SJohn.Forte@Sun.COM } 50517836SJohn.Forte@Sun.COM } 50527836SJohn.Forte@Sun.COM /* Check if we are trying to decrease the # of workers */ 50537836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 50547836SJohn.Forte@Sun.COM if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) { 50557836SJohn.Forte@Sun.COM stmf_nworkers_cur--; 50567836SJohn.Forte@Sun.COM /* 50577836SJohn.Forte@Sun.COM * stmf_nworkers_accepting_cmds has already been 50587836SJohn.Forte@Sun.COM * updated by the request to reduce the # of workers. 50597836SJohn.Forte@Sun.COM */ 50607836SJohn.Forte@Sun.COM } else { 50617836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 50627836SJohn.Forte@Sun.COM return; 50637836SJohn.Forte@Sun.COM } 50647836SJohn.Forte@Sun.COM } 50657836SJohn.Forte@Sun.COM /* Check if we are being asked to quit */ 50667836SJohn.Forte@Sun.COM if (stmf_workers_state != STMF_WORKERS_ENABLED) { 50677836SJohn.Forte@Sun.COM if (stmf_nworkers_cur) { 50687836SJohn.Forte@Sun.COM workers_needed = 0; 50697836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 50707836SJohn.Forte@Sun.COM } 50717836SJohn.Forte@Sun.COM return; 50727836SJohn.Forte@Sun.COM } 50737836SJohn.Forte@Sun.COM /* Check if we are starting */ 50747836SJohn.Forte@Sun.COM if (stmf_nworkers_cur < stmf_i_min_nworkers) { 50757836SJohn.Forte@Sun.COM workers_needed = stmf_i_min_nworkers; 50767836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 50777836SJohn.Forte@Sun.COM } 50787836SJohn.Forte@Sun.COM 50797836SJohn.Forte@Sun.COM tps = drv_usectohz(1 * 1000 * 1000); 50807836SJohn.Forte@Sun.COM if ((stmf_wm_last != 0) && 50817836SJohn.Forte@Sun.COM ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) { 50827836SJohn.Forte@Sun.COM qd = 0; 50837836SJohn.Forte@Sun.COM for (i = 0; i < stmf_nworkers_accepting_cmds; i++) { 50847836SJohn.Forte@Sun.COM qd += stmf_workers[i].worker_max_qdepth_pu; 50857836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_qdepth_pu = 0; 50867836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_max_sys_qdepth_pu > 50877836SJohn.Forte@Sun.COM cur_max_ntasks) { 50887836SJohn.Forte@Sun.COM cur_max_ntasks = 50897836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu; 50907836SJohn.Forte@Sun.COM } 50917836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu = 0; 50927836SJohn.Forte@Sun.COM } 50937836SJohn.Forte@Sun.COM } 50947836SJohn.Forte@Sun.COM stmf_wm_last = ddi_get_lbolt(); 50957836SJohn.Forte@Sun.COM if (d <= tps) { 50967836SJohn.Forte@Sun.COM /* still ramping up */ 50977836SJohn.Forte@Sun.COM return; 50987836SJohn.Forte@Sun.COM } 50997836SJohn.Forte@Sun.COM /* max qdepth cannot be more than max tasks */ 51007836SJohn.Forte@Sun.COM if (qd > cur_max_ntasks) 51017836SJohn.Forte@Sun.COM qd = cur_max_ntasks; 51027836SJohn.Forte@Sun.COM 51037836SJohn.Forte@Sun.COM /* See if we have more workers */ 51047836SJohn.Forte@Sun.COM if (qd < stmf_nworkers_accepting_cmds) { 51057836SJohn.Forte@Sun.COM /* 51067836SJohn.Forte@Sun.COM * Since we dont reduce the worker count right away, monitor 51077836SJohn.Forte@Sun.COM * the highest load during the scale_down_delay. 51087836SJohn.Forte@Sun.COM */ 51097836SJohn.Forte@Sun.COM if (qd > stmf_worker_scale_down_qd) 51107836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = qd; 51117836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_timer == 0) { 51127836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = ddi_get_lbolt() + 51137836SJohn.Forte@Sun.COM drv_usectohz(stmf_worker_scale_down_delay * 51147836SJohn.Forte@Sun.COM 1000 * 1000); 51157836SJohn.Forte@Sun.COM return; 51167836SJohn.Forte@Sun.COM } 51177836SJohn.Forte@Sun.COM if (ddi_get_lbolt() < stmf_worker_scale_down_timer) { 51187836SJohn.Forte@Sun.COM return; 51197836SJohn.Forte@Sun.COM } 51207836SJohn.Forte@Sun.COM /* Its time to reduce the workers */ 51217836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd < stmf_i_min_nworkers) 51227836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_min_nworkers; 51237836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd > stmf_i_max_nworkers) 51247836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_max_nworkers; 51257836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd == stmf_nworkers_cur) 51267836SJohn.Forte@Sun.COM return; 51277836SJohn.Forte@Sun.COM workers_needed = stmf_worker_scale_down_qd; 51287836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 51297836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 51307836SJohn.Forte@Sun.COM } 51317836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 51327836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = 0; 51337836SJohn.Forte@Sun.COM if (qd > stmf_i_max_nworkers) 51347836SJohn.Forte@Sun.COM qd = stmf_i_max_nworkers; 51357836SJohn.Forte@Sun.COM if (qd < stmf_i_min_nworkers) 51367836SJohn.Forte@Sun.COM qd = stmf_i_min_nworkers; 51377836SJohn.Forte@Sun.COM if (qd == stmf_nworkers_cur) 51387836SJohn.Forte@Sun.COM return; 51397836SJohn.Forte@Sun.COM workers_needed = qd; 51407836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 51417836SJohn.Forte@Sun.COM 51427836SJohn.Forte@Sun.COM /* NOTREACHED */ 51437836SJohn.Forte@Sun.COM return; 51447836SJohn.Forte@Sun.COM 51457836SJohn.Forte@Sun.COM worker_mgmt_trigger_change: 51467836SJohn.Forte@Sun.COM ASSERT(workers_needed != stmf_nworkers_cur); 51477836SJohn.Forte@Sun.COM if (workers_needed > stmf_nworkers_cur) { 51487836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 51497836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < workers_needed; i++) { 51507836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 51517836SJohn.Forte@Sun.COM w->worker_tid = thread_create(NULL, 0, stmf_worker_task, 51527836SJohn.Forte@Sun.COM (void *)&stmf_workers[i], 0, &p0, TS_RUN, 51537836SJohn.Forte@Sun.COM minclsyspri); 51547836SJohn.Forte@Sun.COM } 51557836SJohn.Forte@Sun.COM return; 51567836SJohn.Forte@Sun.COM } 51577836SJohn.Forte@Sun.COM /* At this point we know that we are decreasing the # of workers */ 51587836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds = workers_needed; 51597836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 51607836SJohn.Forte@Sun.COM /* Signal the workers that its time to quit */ 51617836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 51627836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 51637836SJohn.Forte@Sun.COM ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED)); 51647836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 51657836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_TERMINATE; 51667836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 51677836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 51687836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 51697836SJohn.Forte@Sun.COM } 51707836SJohn.Forte@Sun.COM } 51717836SJohn.Forte@Sun.COM 51727836SJohn.Forte@Sun.COM /* 51737836SJohn.Forte@Sun.COM * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private). 51747836SJohn.Forte@Sun.COM * If all the data has been filled out, frees the xd and makes 51757836SJohn.Forte@Sun.COM * db_lu_private NULL. 51767836SJohn.Forte@Sun.COM */ 51777836SJohn.Forte@Sun.COM void 51787836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf) 51797836SJohn.Forte@Sun.COM { 51807836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 51817836SJohn.Forte@Sun.COM uint8_t *p; 51827836SJohn.Forte@Sun.COM int i; 51837836SJohn.Forte@Sun.COM uint32_t s; 51847836SJohn.Forte@Sun.COM 51857836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 51867836SJohn.Forte@Sun.COM dbuf->db_data_size = 0; 51877836SJohn.Forte@Sun.COM dbuf->db_relative_offset = xd->size_done; 51887836SJohn.Forte@Sun.COM for (i = 0; i < dbuf->db_sglist_length; i++) { 51897836SJohn.Forte@Sun.COM s = min(xd->size_left, dbuf->db_sglist[i].seg_length); 51907836SJohn.Forte@Sun.COM p = &xd->buf[xd->size_done]; 51917836SJohn.Forte@Sun.COM bcopy(p, dbuf->db_sglist[i].seg_addr, s); 51927836SJohn.Forte@Sun.COM xd->size_left -= s; 51937836SJohn.Forte@Sun.COM xd->size_done += s; 51947836SJohn.Forte@Sun.COM dbuf->db_data_size += s; 51957836SJohn.Forte@Sun.COM if (xd->size_left == 0) { 51967836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 51977836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 51987836SJohn.Forte@Sun.COM return; 51997836SJohn.Forte@Sun.COM } 52007836SJohn.Forte@Sun.COM } 52017836SJohn.Forte@Sun.COM } 52027836SJohn.Forte@Sun.COM 52037836SJohn.Forte@Sun.COM /* ARGSUSED */ 52047836SJohn.Forte@Sun.COM stmf_status_t 52057836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task) 52067836SJohn.Forte@Sun.COM { 52077836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 52087836SJohn.Forte@Sun.COM } 52097836SJohn.Forte@Sun.COM 52107836SJohn.Forte@Sun.COM void 52117836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 52127836SJohn.Forte@Sun.COM { 52137836SJohn.Forte@Sun.COM uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; 52147836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 52157836SJohn.Forte@Sun.COM uint32_t sz, minsz; 52167836SJohn.Forte@Sun.COM uint8_t *p; 52177836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 52187836SJohn.Forte@Sun.COM uint8_t inq_page_length = 31; 52197836SJohn.Forte@Sun.COM 52207836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 52217836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(task); 52227836SJohn.Forte@Sun.COM return; 52237836SJohn.Forte@Sun.COM } 52247836SJohn.Forte@Sun.COM 52257836SJohn.Forte@Sun.COM switch (cdbp[0]) { 52267836SJohn.Forte@Sun.COM case SCMD_INQUIRY: 52277836SJohn.Forte@Sun.COM /* 52287836SJohn.Forte@Sun.COM * Basic protocol checks. In addition, only reply to 52297836SJohn.Forte@Sun.COM * standard inquiry. Otherwise, the LU provider needs 52307836SJohn.Forte@Sun.COM * to respond. 52317836SJohn.Forte@Sun.COM */ 52327836SJohn.Forte@Sun.COM 52337836SJohn.Forte@Sun.COM if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) { 52347836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 52357836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 52367836SJohn.Forte@Sun.COM return; 52377836SJohn.Forte@Sun.COM } 52387836SJohn.Forte@Sun.COM 52397836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 52407836SJohn.Forte@Sun.COM (((uint32_t)cdbp[3]) << 8) | cdbp[4]; 52417836SJohn.Forte@Sun.COM 52427836SJohn.Forte@Sun.COM if (task->task_additional_flags & 52437836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 52447836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 52457836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 52467836SJohn.Forte@Sun.COM } 52477836SJohn.Forte@Sun.COM 52487836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 52497836SJohn.Forte@Sun.COM min(36, task->task_cmd_xfer_length)); 52507836SJohn.Forte@Sun.COM minsz = 36; 52517836SJohn.Forte@Sun.COM 52527836SJohn.Forte@Sun.COM if (sz == 0) { 52537836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 52547836SJohn.Forte@Sun.COM return; 52557836SJohn.Forte@Sun.COM } 52567836SJohn.Forte@Sun.COM 52577836SJohn.Forte@Sun.COM if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) { 52587836SJohn.Forte@Sun.COM /* 52597836SJohn.Forte@Sun.COM * Ignore any preallocated dbuf if the size is less 52607836SJohn.Forte@Sun.COM * than 36. It will be freed during the task_free. 52617836SJohn.Forte@Sun.COM */ 52627836SJohn.Forte@Sun.COM dbuf = NULL; 52637836SJohn.Forte@Sun.COM } 52647836SJohn.Forte@Sun.COM if (dbuf == NULL) 52657836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0); 52667836SJohn.Forte@Sun.COM if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) { 52677836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 52687836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 52697836SJohn.Forte@Sun.COM return; 52707836SJohn.Forte@Sun.COM } 52717836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 52727836SJohn.Forte@Sun.COM 52737836SJohn.Forte@Sun.COM p = dbuf->db_sglist[0].seg_addr; 52747836SJohn.Forte@Sun.COM 52757836SJohn.Forte@Sun.COM /* 52767836SJohn.Forte@Sun.COM * Standard inquiry handling only. 52777836SJohn.Forte@Sun.COM */ 52787836SJohn.Forte@Sun.COM 52797836SJohn.Forte@Sun.COM bzero(p, inq_page_length + 5); 52807836SJohn.Forte@Sun.COM 52817836SJohn.Forte@Sun.COM p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN; 52827836SJohn.Forte@Sun.COM p[2] = 5; 52837836SJohn.Forte@Sun.COM p[3] = 0x12; 52847836SJohn.Forte@Sun.COM p[4] = inq_page_length; 52857836SJohn.Forte@Sun.COM p[6] = 0x80; 52867836SJohn.Forte@Sun.COM 52877836SJohn.Forte@Sun.COM (void) strncpy((char *)p+8, "SUN ", 8); 52887836SJohn.Forte@Sun.COM (void) strncpy((char *)p+16, "COMSTAR ", 16); 52897836SJohn.Forte@Sun.COM (void) strncpy((char *)p+32, "1.0 ", 4); 52907836SJohn.Forte@Sun.COM 52917836SJohn.Forte@Sun.COM dbuf->db_data_size = sz; 52927836SJohn.Forte@Sun.COM dbuf->db_relative_offset = 0; 52937836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 52947836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 52957836SJohn.Forte@Sun.COM 52967836SJohn.Forte@Sun.COM return; 52977836SJohn.Forte@Sun.COM 52987836SJohn.Forte@Sun.COM case SCMD_REPORT_LUNS: 52997836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 53007836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 53017836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 53027836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 53037836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 53047836SJohn.Forte@Sun.COM 53057836SJohn.Forte@Sun.COM if (task->task_additional_flags & 53067836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 53077836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 53087836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 53097836SJohn.Forte@Sun.COM } 53107836SJohn.Forte@Sun.COM 53117836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 53127836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 53137836SJohn.Forte@Sun.COM 53147836SJohn.Forte@Sun.COM if (sz < 16) { 53157836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 53168662SJordan.Vaughan@Sun.com STMF_SAA_INVALID_FIELD_IN_CDB); 53177836SJohn.Forte@Sun.COM return; 53187836SJohn.Forte@Sun.COM } 53197836SJohn.Forte@Sun.COM 53207836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 53217836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 53227836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 53237836SJohn.Forte@Sun.COM xd = stmf_session_prepare_report_lun_data(iss->iss_sm); 53247836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 53257836SJohn.Forte@Sun.COM 53267836SJohn.Forte@Sun.COM if (xd == NULL) { 53277836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53287836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 53297836SJohn.Forte@Sun.COM return; 53307836SJohn.Forte@Sun.COM } 53317836SJohn.Forte@Sun.COM 53327836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 53337836SJohn.Forte@Sun.COM xd->size_left = sz; 53347836SJohn.Forte@Sun.COM minsz = min(512, sz); 53357836SJohn.Forte@Sun.COM 53367836SJohn.Forte@Sun.COM if (dbuf == NULL) 53377836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 53387836SJohn.Forte@Sun.COM if (dbuf == NULL) { 53397836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 53407836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53417836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 53427836SJohn.Forte@Sun.COM return; 53437836SJohn.Forte@Sun.COM } 53447836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 53457836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 53467836SJohn.Forte@Sun.COM 53477836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 53488662SJordan.Vaughan@Sun.com ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 53497836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 53507836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 53517836SJohn.Forte@Sun.COM return; 53527836SJohn.Forte@Sun.COM } 53537836SJohn.Forte@Sun.COM 53547836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE); 53557836SJohn.Forte@Sun.COM } 53567836SJohn.Forte@Sun.COM 53577836SJohn.Forte@Sun.COM void 53587836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf) 53597836SJohn.Forte@Sun.COM { 53607836SJohn.Forte@Sun.COM if (dbuf->db_xfer_status != STMF_SUCCESS) { 53617836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 53627836SJohn.Forte@Sun.COM dbuf->db_xfer_status, NULL); 53637836SJohn.Forte@Sun.COM return; 53647836SJohn.Forte@Sun.COM } 53657836SJohn.Forte@Sun.COM task->task_nbytes_transferred = dbuf->db_data_size; 53667836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 53677836SJohn.Forte@Sun.COM /* There is more */ 53687836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 53697836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 53707836SJohn.Forte@Sun.COM return; 53717836SJohn.Forte@Sun.COM } 53727836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 53737836SJohn.Forte@Sun.COM } 53747836SJohn.Forte@Sun.COM 53757836SJohn.Forte@Sun.COM /* ARGSUSED */ 53767836SJohn.Forte@Sun.COM void 53777836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task) 53787836SJohn.Forte@Sun.COM { 53797836SJohn.Forte@Sun.COM } 53807836SJohn.Forte@Sun.COM 53817836SJohn.Forte@Sun.COM /* ARGSUSED */ 53827836SJohn.Forte@Sun.COM void 53837836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task) 53847836SJohn.Forte@Sun.COM { 53857836SJohn.Forte@Sun.COM } 53867836SJohn.Forte@Sun.COM 53877836SJohn.Forte@Sun.COM /* ARGSUSED */ 53887836SJohn.Forte@Sun.COM stmf_status_t 53897836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags) 53907836SJohn.Forte@Sun.COM { 53917836SJohn.Forte@Sun.COM scsi_task_t *task = (scsi_task_t *)arg; 53927836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 53938662SJordan.Vaughan@Sun.com (stmf_i_scsi_task_t *)task->task_stmf_private; 53947836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 53957836SJohn.Forte@Sun.COM int i; 53967836SJohn.Forte@Sun.COM uint8_t map; 53977836SJohn.Forte@Sun.COM 53987836SJohn.Forte@Sun.COM ASSERT(abort_cmd == STMF_LU_ABORT_TASK); 53997836SJohn.Forte@Sun.COM if ((task->task_mgmt_function) && (itask->itask_flags & 54007836SJohn.Forte@Sun.COM (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) { 54017836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 54027836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 54037836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 54047836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 54057836SJohn.Forte@Sun.COM case TM_LUN_RESET: 54067836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 54077836SJohn.Forte@Sun.COM break; 54087836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 54097836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 54107836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 54117836SJohn.Forte@Sun.COM stmf_abort_target_reset(task); 54127836SJohn.Forte@Sun.COM break; 54137836SJohn.Forte@Sun.COM } 54147836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 54157836SJohn.Forte@Sun.COM } 54167836SJohn.Forte@Sun.COM 54177836SJohn.Forte@Sun.COM /* 54187836SJohn.Forte@Sun.COM * OK so its not a task mgmt. Make sure we free any xd sitting 54197836SJohn.Forte@Sun.COM * inside any dbuf. 54207836SJohn.Forte@Sun.COM */ 54217836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 54227836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 54237836SJohn.Forte@Sun.COM if ((map & 1) && 54247836SJohn.Forte@Sun.COM ((itask->itask_dbufs[i])->db_lu_private)) { 54257836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 54267836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 54277836SJohn.Forte@Sun.COM 54287836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 54297836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 54307836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 54317836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 54327836SJohn.Forte@Sun.COM } 54337836SJohn.Forte@Sun.COM map >>= 1; 54347836SJohn.Forte@Sun.COM } 54357836SJohn.Forte@Sun.COM } 54367836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 54377836SJohn.Forte@Sun.COM } 54387836SJohn.Forte@Sun.COM 54397836SJohn.Forte@Sun.COM void 54407836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task) 54417836SJohn.Forte@Sun.COM { 54427836SJohn.Forte@Sun.COM /* Right now we only do this for handling task management functions */ 54437836SJohn.Forte@Sun.COM ASSERT(task->task_mgmt_function); 54447836SJohn.Forte@Sun.COM 54457836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 54467836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 54477836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 54487836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 54497836SJohn.Forte@Sun.COM case TM_LUN_RESET: 54507836SJohn.Forte@Sun.COM (void) stmf_lun_reset_poll(task->task_lu, task, 0); 54517836SJohn.Forte@Sun.COM return; 54527836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 54537836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 54547836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 54557836SJohn.Forte@Sun.COM stmf_target_reset_poll(task); 54567836SJohn.Forte@Sun.COM return; 54577836SJohn.Forte@Sun.COM } 54587836SJohn.Forte@Sun.COM } 54597836SJohn.Forte@Sun.COM 54607836SJohn.Forte@Sun.COM /* ARGSUSED */ 54617836SJohn.Forte@Sun.COM void 54627836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg) 54637836SJohn.Forte@Sun.COM { 54647836SJohn.Forte@Sun.COM /* This function will never be called */ 54657836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd); 54667836SJohn.Forte@Sun.COM } 54677836SJohn.Forte@Sun.COM 54687836SJohn.Forte@Sun.COM void 54697836SJohn.Forte@Sun.COM stmf_dlun_init() 54707836SJohn.Forte@Sun.COM { 54717836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 54727836SJohn.Forte@Sun.COM 54737836SJohn.Forte@Sun.COM dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0); 54747836SJohn.Forte@Sun.COM dlun0->lu_task_alloc = stmf_dlun0_task_alloc; 54757836SJohn.Forte@Sun.COM dlun0->lu_new_task = stmf_dlun0_new_task; 54767836SJohn.Forte@Sun.COM dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done; 54777836SJohn.Forte@Sun.COM dlun0->lu_send_status_done = stmf_dlun0_status_done; 54787836SJohn.Forte@Sun.COM dlun0->lu_task_free = stmf_dlun0_task_free; 54797836SJohn.Forte@Sun.COM dlun0->lu_abort = stmf_dlun0_abort; 54807836SJohn.Forte@Sun.COM dlun0->lu_task_poll = stmf_dlun0_task_poll; 54817836SJohn.Forte@Sun.COM dlun0->lu_ctl = stmf_dlun0_ctl; 54827836SJohn.Forte@Sun.COM 54837836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 54847836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 54857836SJohn.Forte@Sun.COM } 54867836SJohn.Forte@Sun.COM 54877836SJohn.Forte@Sun.COM stmf_status_t 54887836SJohn.Forte@Sun.COM stmf_dlun_fini() 54897836SJohn.Forte@Sun.COM { 54907836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 54917836SJohn.Forte@Sun.COM 54927836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 54937836SJohn.Forte@Sun.COM 54947836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 54957836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 54967836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 54977836SJohn.Forte@Sun.COM 54987836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 54997836SJohn.Forte@Sun.COM do { 55007836SJohn.Forte@Sun.COM itask = nitask; 55017836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 55027836SJohn.Forte@Sun.COM dlun0->lu_task_free(itask->itask_task); 55037836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 55047836SJohn.Forte@Sun.COM } while (nitask != NULL); 55057836SJohn.Forte@Sun.COM 55067836SJohn.Forte@Sun.COM } 55077836SJohn.Forte@Sun.COM stmf_free(dlun0); 55087836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55097836SJohn.Forte@Sun.COM } 55107836SJohn.Forte@Sun.COM 55117836SJohn.Forte@Sun.COM void 55127836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task) 55137836SJohn.Forte@Sun.COM { 55147836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 55158662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 55167836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 55177836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 55187836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 55197836SJohn.Forte@Sun.COM int i; 55207836SJohn.Forte@Sun.COM 55217836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 55227836SJohn.Forte@Sun.COM 55237836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 55247836SJohn.Forte@Sun.COM lm = iss->iss_sm; 55257836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 55267836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 55277836SJohn.Forte@Sun.COM continue; 55287836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 55297836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 55307836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 55317836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 55327836SJohn.Forte@Sun.COM } 55337836SJohn.Forte@Sun.COM } 55347836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 55357836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 55367836SJohn.Forte@Sun.COM } 55377836SJohn.Forte@Sun.COM 55387836SJohn.Forte@Sun.COM /* 55397836SJohn.Forte@Sun.COM * The return value is only used by function managing target reset. 55407836SJohn.Forte@Sun.COM */ 55417836SJohn.Forte@Sun.COM stmf_status_t 55427836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset) 55437836SJohn.Forte@Sun.COM { 55447836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 55457836SJohn.Forte@Sun.COM int ntasks_pending; 55467836SJohn.Forte@Sun.COM 55477836SJohn.Forte@Sun.COM ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free; 55487836SJohn.Forte@Sun.COM /* 55497836SJohn.Forte@Sun.COM * This function is also used during Target reset. The idea is that 55507836SJohn.Forte@Sun.COM * once all the commands are aborted, call the LU's reset entry 55517836SJohn.Forte@Sun.COM * point (abort entry point with a reset flag). But if this Task 55527836SJohn.Forte@Sun.COM * mgmt is running on this LU then all the tasks cannot be aborted. 55537836SJohn.Forte@Sun.COM * one task (this task) will still be running which is OK. 55547836SJohn.Forte@Sun.COM */ 55557836SJohn.Forte@Sun.COM if ((ntasks_pending == 0) || ((task->task_lu == lu) && 55567836SJohn.Forte@Sun.COM (ntasks_pending == 1))) { 55577836SJohn.Forte@Sun.COM stmf_status_t ret; 55587836SJohn.Forte@Sun.COM 55597836SJohn.Forte@Sun.COM if ((task->task_mgmt_function == TM_LUN_RESET) || 55607836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_RESET) || 55617836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_WARM_RESET) || 55627836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_COLD_RESET)) { 55637836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0); 55647836SJohn.Forte@Sun.COM } else { 55657836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 55667836SJohn.Forte@Sun.COM } 55677836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 55687836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 55697836SJohn.Forte@Sun.COM } 55707836SJohn.Forte@Sun.COM if (target_reset) { 55717836SJohn.Forte@Sun.COM return (ret); 55727836SJohn.Forte@Sun.COM } 55737836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 55747836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 55757836SJohn.Forte@Sun.COM return (ret); 55767836SJohn.Forte@Sun.COM } 55777836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 55787836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL); 55797836SJohn.Forte@Sun.COM return (ret); 55807836SJohn.Forte@Sun.COM } 55817836SJohn.Forte@Sun.COM } 55827836SJohn.Forte@Sun.COM 55837836SJohn.Forte@Sun.COM if (target_reset) { 55847836SJohn.Forte@Sun.COM /* Tell target reset polling code that we are not done */ 55857836SJohn.Forte@Sun.COM return (STMF_BUSY); 55867836SJohn.Forte@Sun.COM } 55877836SJohn.Forte@Sun.COM 55887836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 55897836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 55907836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 55917836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 55927836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55937836SJohn.Forte@Sun.COM } 55947836SJohn.Forte@Sun.COM 55957836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 55967836SJohn.Forte@Sun.COM } 55977836SJohn.Forte@Sun.COM 55987836SJohn.Forte@Sun.COM void 55997836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task) 56007836SJohn.Forte@Sun.COM { 56017836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 56028662SJordan.Vaughan@Sun.com task->task_session->ss_stmf_private; 56037836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 56047836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 56057836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 56067836SJohn.Forte@Sun.COM stmf_status_t ret; 56077836SJohn.Forte@Sun.COM int i; 56087836SJohn.Forte@Sun.COM int not_done = 0; 56097836SJohn.Forte@Sun.COM 56107836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 56117836SJohn.Forte@Sun.COM 56127836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 56137836SJohn.Forte@Sun.COM lm = iss->iss_sm; 56147836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 56157836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 56167836SJohn.Forte@Sun.COM continue; 56177836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 56187836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 56197836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 56207836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56217836SJohn.Forte@Sun.COM ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1); 56227836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 56237836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) 56247836SJohn.Forte@Sun.COM continue; 56257836SJohn.Forte@Sun.COM not_done = 1; 56267836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 56277836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56287836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 56297836SJohn.Forte@Sun.COM STMF_ABORTED, NULL); 56307836SJohn.Forte@Sun.COM return; 56317836SJohn.Forte@Sun.COM } 56327836SJohn.Forte@Sun.COM } 56337836SJohn.Forte@Sun.COM } 56347836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 56357836SJohn.Forte@Sun.COM 56367836SJohn.Forte@Sun.COM if (not_done) { 56377836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 56387836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 56397836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 56407836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 56417836SJohn.Forte@Sun.COM return; 56427836SJohn.Forte@Sun.COM } 56437836SJohn.Forte@Sun.COM return; 56447836SJohn.Forte@Sun.COM } 56457836SJohn.Forte@Sun.COM 56467836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 56477836SJohn.Forte@Sun.COM 56487836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 56497836SJohn.Forte@Sun.COM } 56507836SJohn.Forte@Sun.COM 56517836SJohn.Forte@Sun.COM stmf_status_t 56527836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid) 56537836SJohn.Forte@Sun.COM { 56547836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 56557836SJohn.Forte@Sun.COM 56567836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56577836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56587836SJohn.Forte@Sun.COM } 56597836SJohn.Forte@Sun.COM 56607836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid); 56617836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56627836SJohn.Forte@Sun.COM } 56637836SJohn.Forte@Sun.COM 56647836SJohn.Forte@Sun.COM stmf_status_t 56657836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid) 56667836SJohn.Forte@Sun.COM { 56677836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 56687836SJohn.Forte@Sun.COM 56697836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 56707836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl); 56717836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56727836SJohn.Forte@Sun.COM } 56737836SJohn.Forte@Sun.COM 56747836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56757836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56767836SJohn.Forte@Sun.COM } 56777836SJohn.Forte@Sun.COM 56787836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid); 56797836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56807836SJohn.Forte@Sun.COM } 56817836SJohn.Forte@Sun.COM 56827836SJohn.Forte@Sun.COM stmf_status_t 56837836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid) 56847836SJohn.Forte@Sun.COM { 56857836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 56868662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 56877836SJohn.Forte@Sun.COM 56887836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 56897836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 56907836SJohn.Forte@Sun.COM } 56917836SJohn.Forte@Sun.COM 56927836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid); 56937836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 56947836SJohn.Forte@Sun.COM } 56957836SJohn.Forte@Sun.COM 56967836SJohn.Forte@Sun.COM stmf_status_t 56977836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid) 56987836SJohn.Forte@Sun.COM { 56997836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 57008662SJordan.Vaughan@Sun.com (stmf_i_local_port_t *)lport->lport_stmf_private; 57017836SJohn.Forte@Sun.COM 57027836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 57037836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl); 57047836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57057836SJohn.Forte@Sun.COM } 57067836SJohn.Forte@Sun.COM 57077836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 57087836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 57097836SJohn.Forte@Sun.COM } 57107836SJohn.Forte@Sun.COM 57117836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid); 57127836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57137836SJohn.Forte@Sun.COM } 57147836SJohn.Forte@Sun.COM 57157836SJohn.Forte@Sun.COM void 57167836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags) 57177836SJohn.Forte@Sun.COM { 57187836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) && 57197836SJohn.Forte@Sun.COM (ilu->ilu_lu->lu_event_handler != NULL)) { 57207836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags); 57217836SJohn.Forte@Sun.COM } 57227836SJohn.Forte@Sun.COM } 57237836SJohn.Forte@Sun.COM 57247836SJohn.Forte@Sun.COM void 57257836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg, 57267836SJohn.Forte@Sun.COM uint32_t flags) 57277836SJohn.Forte@Sun.COM { 57287836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) && 57297836SJohn.Forte@Sun.COM (ilport->ilport_lport->lport_event_handler != NULL)) { 57307836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_event_handler( 57317836SJohn.Forte@Sun.COM ilport->ilport_lport, eventid, arg, flags); 57327836SJohn.Forte@Sun.COM } 57337836SJohn.Forte@Sun.COM } 57347836SJohn.Forte@Sun.COM 57357836SJohn.Forte@Sun.COM void 57367836SJohn.Forte@Sun.COM stmf_svc_init() 57377836SJohn.Forte@Sun.COM { 57387836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 57397836SJohn.Forte@Sun.COM return; 57407836SJohn.Forte@Sun.COM stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1, 57417836SJohn.Forte@Sun.COM TASKQ_DEFAULTPRI, 0); 57427836SJohn.Forte@Sun.COM (void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq, 57437836SJohn.Forte@Sun.COM stmf_svc, 0, DDI_SLEEP); 57447836SJohn.Forte@Sun.COM } 57457836SJohn.Forte@Sun.COM 57467836SJohn.Forte@Sun.COM stmf_status_t 57477836SJohn.Forte@Sun.COM stmf_svc_fini() 57487836SJohn.Forte@Sun.COM { 57497836SJohn.Forte@Sun.COM uint32_t i; 57507836SJohn.Forte@Sun.COM 57517836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 57527836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) { 57537836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE; 57547836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 57557836SJohn.Forte@Sun.COM } 57567836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 57577836SJohn.Forte@Sun.COM 57587836SJohn.Forte@Sun.COM /* Wait for 5 seconds */ 57597836SJohn.Forte@Sun.COM for (i = 0; i < 500; i++) { 57607836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 57617836SJohn.Forte@Sun.COM delay(drv_usectohz(10000)); 57627836SJohn.Forte@Sun.COM else 57637836SJohn.Forte@Sun.COM break; 57647836SJohn.Forte@Sun.COM } 57657836SJohn.Forte@Sun.COM if (i == 500) 57667836SJohn.Forte@Sun.COM return (STMF_BUSY); 57677836SJohn.Forte@Sun.COM 57687836SJohn.Forte@Sun.COM ddi_taskq_destroy(stmf_state.stmf_svc_taskq); 57697836SJohn.Forte@Sun.COM 57707836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 57717836SJohn.Forte@Sun.COM } 57727836SJohn.Forte@Sun.COM 57737836SJohn.Forte@Sun.COM /* ARGSUSED */ 57747836SJohn.Forte@Sun.COM void 57757836SJohn.Forte@Sun.COM stmf_svc(void *arg) 57767836SJohn.Forte@Sun.COM { 57777836SJohn.Forte@Sun.COM stmf_svc_req_t *req, **preq; 57787836SJohn.Forte@Sun.COM clock_t td; 57797836SJohn.Forte@Sun.COM clock_t drain_start, drain_next = 0; 57807836SJohn.Forte@Sun.COM clock_t timing_start, timing_next = 0; 57817836SJohn.Forte@Sun.COM clock_t worker_delay = 0; 57827836SJohn.Forte@Sun.COM int deq; 57837836SJohn.Forte@Sun.COM stmf_lu_t *lu; 57847836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 57857836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 57867836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport, *next_ilport; 57877836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 57887836SJohn.Forte@Sun.COM 57897836SJohn.Forte@Sun.COM td = drv_usectohz(20000); 57907836SJohn.Forte@Sun.COM 57917836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 57927836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE; 57937836SJohn.Forte@Sun.COM 57947836SJohn.Forte@Sun.COM stmf_svc_loop: 57957836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) { 57967836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= 57977836SJohn.Forte@Sun.COM ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE); 57987836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 57997836SJohn.Forte@Sun.COM return; 58007836SJohn.Forte@Sun.COM } 58017836SJohn.Forte@Sun.COM 58027836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) { 58037836SJohn.Forte@Sun.COM int waitq_add = 0; 58047836SJohn.Forte@Sun.COM req = stmf_state.stmf_svc_active; 58057836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req->svc_next; 58067836SJohn.Forte@Sun.COM 58077836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 58087836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 58097836SJohn.Forte@Sun.COM /* Fallthrough */ 58107836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 58117836SJohn.Forte@Sun.COM /* Fallthrough */ 58127836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 58137836SJohn.Forte@Sun.COM /* Nothing to do */ 58147836SJohn.Forte@Sun.COM waitq_add = 1; 58157836SJohn.Forte@Sun.COM break; 58167836SJohn.Forte@Sun.COM 58177836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 58187836SJohn.Forte@Sun.COM /* Remove all mappings of this LU */ 58197836SJohn.Forte@Sun.COM stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj); 58207836SJohn.Forte@Sun.COM /* Kill all the pending I/Os for this LU */ 58217836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 58227836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL, 58238662SJordan.Vaughan@Sun.com STMF_ABORTED); 58247836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 58257836SJohn.Forte@Sun.COM waitq_add = 1; 58267836SJohn.Forte@Sun.COM break; 58277836SJohn.Forte@Sun.COM default: 58287836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d", 58297836SJohn.Forte@Sun.COM req->svc_cmd); 58307836SJohn.Forte@Sun.COM } 58317836SJohn.Forte@Sun.COM 58327836SJohn.Forte@Sun.COM if (waitq_add) { 58337836SJohn.Forte@Sun.COM /* Put it in the wait queue */ 58347836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_waiting; 58357836SJohn.Forte@Sun.COM stmf_state.stmf_svc_waiting = req; 58367836SJohn.Forte@Sun.COM } 58377836SJohn.Forte@Sun.COM } 58387836SJohn.Forte@Sun.COM 58397836SJohn.Forte@Sun.COM /* The waiting list is not going to be modified by anybody else */ 58407836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 58417836SJohn.Forte@Sun.COM 58427836SJohn.Forte@Sun.COM for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) { 58437836SJohn.Forte@Sun.COM req = *preq; 58447836SJohn.Forte@Sun.COM deq = 0; 58457836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 58467836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 58477836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 58487836SJohn.Forte@Sun.COM deq = 1; 58497836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 58507836SJohn.Forte@Sun.COM break; 58517836SJohn.Forte@Sun.COM 58527836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 58537836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 58547836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 58557836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks != ilu->ilu_ntasks_free) 58567836SJohn.Forte@Sun.COM break; 58577836SJohn.Forte@Sun.COM deq = 1; 58587836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 58597836SJohn.Forte@Sun.COM break; 58607836SJohn.Forte@Sun.COM 58617836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 58627836SJohn.Forte@Sun.COM /* Fallthrough */ 58637836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 58647836SJohn.Forte@Sun.COM lport = (stmf_local_port_t *)req->svc_obj; 58657836SJohn.Forte@Sun.COM deq = 1; 58667836SJohn.Forte@Sun.COM lport->lport_ctl(lport, req->svc_cmd, &req->svc_info); 58677836SJohn.Forte@Sun.COM break; 58687836SJohn.Forte@Sun.COM } 58697836SJohn.Forte@Sun.COM if (deq) { 58707836SJohn.Forte@Sun.COM *preq = req->svc_next; 58717836SJohn.Forte@Sun.COM kmem_free(req, req->svc_req_alloc_size); 58727836SJohn.Forte@Sun.COM } else { 58737836SJohn.Forte@Sun.COM preq = &req->svc_next; 58747836SJohn.Forte@Sun.COM } 58757836SJohn.Forte@Sun.COM } 58767836SJohn.Forte@Sun.COM 58777836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 58787836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active == NULL) { 58797836SJohn.Forte@Sun.COM /* Do timeouts */ 58807836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 58817836SJohn.Forte@Sun.COM ((!timing_next) || (ddi_get_lbolt() >= timing_next))) { 58827836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 58837836SJohn.Forte@Sun.COM /* we are starting a new round */ 58847836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = 58857836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 58867836SJohn.Forte@Sun.COM timing_start = ddi_get_lbolt(); 58877836SJohn.Forte@Sun.COM } 58887836SJohn.Forte@Sun.COM stmf_check_ilu_timing(); 58897836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 58907836SJohn.Forte@Sun.COM /* we finished a complete round */ 58917836SJohn.Forte@Sun.COM timing_next = 58927836SJohn.Forte@Sun.COM timing_start + drv_usectohz(5*1000*1000); 58937836SJohn.Forte@Sun.COM } else { 58947836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 58957836SJohn.Forte@Sun.COM timing_next = 58967836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 58977836SJohn.Forte@Sun.COM } 58987836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 58997836SJohn.Forte@Sun.COM goto stmf_svc_loop; 59007836SJohn.Forte@Sun.COM } 59017836SJohn.Forte@Sun.COM /* Check if there are free tasks to clear */ 59027836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 59037836SJohn.Forte@Sun.COM ((!drain_next) || (ddi_get_lbolt() >= drain_next))) { 59047836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 59057836SJohn.Forte@Sun.COM /* we are starting a new round */ 59067836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = 59077836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 59087836SJohn.Forte@Sun.COM drain_start = ddi_get_lbolt(); 59097836SJohn.Forte@Sun.COM } 59107836SJohn.Forte@Sun.COM stmf_check_freetask(); 59117836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 59127836SJohn.Forte@Sun.COM /* we finished a complete round */ 59137836SJohn.Forte@Sun.COM drain_next = 59147836SJohn.Forte@Sun.COM drain_start + drv_usectohz(10*1000*1000); 59157836SJohn.Forte@Sun.COM } else { 59167836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 59177836SJohn.Forte@Sun.COM drain_next = 59187836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 59197836SJohn.Forte@Sun.COM } 59207836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 59217836SJohn.Forte@Sun.COM goto stmf_svc_loop; 59227836SJohn.Forte@Sun.COM } 59237836SJohn.Forte@Sun.COM 59247836SJohn.Forte@Sun.COM /* Check if we need to run worker_mgmt */ 59257836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > worker_delay) { 59267836SJohn.Forte@Sun.COM stmf_worker_mgmt(); 59277836SJohn.Forte@Sun.COM worker_delay = ddi_get_lbolt() + 59287836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay; 59297836SJohn.Forte@Sun.COM } 59307836SJohn.Forte@Sun.COM 59317836SJohn.Forte@Sun.COM /* Check if any active session got its 1st LUN */ 59327836SJohn.Forte@Sun.COM if (stmf_state.stmf_process_initial_luns) { 59337836SJohn.Forte@Sun.COM int stmf_level = 0; 59347836SJohn.Forte@Sun.COM int port_level; 59357836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 59367836SJohn.Forte@Sun.COM ilport = next_ilport) { 59377836SJohn.Forte@Sun.COM next_ilport = ilport->ilport_next; 59387836SJohn.Forte@Sun.COM if ((ilport->ilport_flags & 59397836SJohn.Forte@Sun.COM ILPORT_SS_GOT_INITIAL_LUNS) == 0) { 59407836SJohn.Forte@Sun.COM continue; 59417836SJohn.Forte@Sun.COM } 59427836SJohn.Forte@Sun.COM port_level = 0; 59437836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_READER); 59447836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss; 59457836SJohn.Forte@Sun.COM iss = iss->iss_next) { 59467836SJohn.Forte@Sun.COM if ((iss->iss_flags & 59477836SJohn.Forte@Sun.COM ISS_GOT_INITIAL_LUNS) == 0) { 59487836SJohn.Forte@Sun.COM continue; 59497836SJohn.Forte@Sun.COM } 59507836SJohn.Forte@Sun.COM port_level++; 59517836SJohn.Forte@Sun.COM stmf_level++; 59527836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 59538662SJordan.Vaughan@Sun.com ~ISS_GOT_INITIAL_LUNS); 59547836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, 59558662SJordan.Vaughan@Sun.com ISS_EVENT_ACTIVE); 59567836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 59577836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 59587836SJohn.Forte@Sun.COM stmf_generate_lport_event(ilport, 59597836SJohn.Forte@Sun.COM LPORT_EVENT_INITIAL_LUN_MAPPED, 59607836SJohn.Forte@Sun.COM iss->iss_ss, 0); 59617836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 59628662SJordan.Vaughan@Sun.com ~ISS_EVENT_ACTIVE); 59637836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 59647836SJohn.Forte@Sun.COM /* 59657836SJohn.Forte@Sun.COM * scan all the ilports again as the 59667836SJohn.Forte@Sun.COM * ilport list might have changed. 59677836SJohn.Forte@Sun.COM */ 59687836SJohn.Forte@Sun.COM next_ilport = 59698662SJordan.Vaughan@Sun.com stmf_state.stmf_ilportlist; 59707836SJohn.Forte@Sun.COM break; 59717836SJohn.Forte@Sun.COM } 59727836SJohn.Forte@Sun.COM if (port_level == 0) { 59737836SJohn.Forte@Sun.COM atomic_and_32(&ilport->ilport_flags, 59748662SJordan.Vaughan@Sun.com ~ILPORT_SS_GOT_INITIAL_LUNS); 59757836SJohn.Forte@Sun.COM } 59767836SJohn.Forte@Sun.COM /* drop the lock if we are holding it. */ 59777836SJohn.Forte@Sun.COM if (rw_lock_held(&ilport->ilport_lock)) 59787836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 59797836SJohn.Forte@Sun.COM 59807836SJohn.Forte@Sun.COM /* Max 4 session at a time */ 59817836SJohn.Forte@Sun.COM if (stmf_level >= 4) { 59827836SJohn.Forte@Sun.COM break; 59837836SJohn.Forte@Sun.COM } 59847836SJohn.Forte@Sun.COM } 59857836SJohn.Forte@Sun.COM if (stmf_level == 0) { 59867836SJohn.Forte@Sun.COM stmf_state.stmf_process_initial_luns = 0; 59877836SJohn.Forte@Sun.COM } 59887836SJohn.Forte@Sun.COM } 59897836SJohn.Forte@Sun.COM 59907836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE; 59917836SJohn.Forte@Sun.COM (void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock, 59927836SJohn.Forte@Sun.COM ddi_get_lbolt() + td); 59937836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE; 59947836SJohn.Forte@Sun.COM } 59957836SJohn.Forte@Sun.COM goto stmf_svc_loop; 59967836SJohn.Forte@Sun.COM } 59977836SJohn.Forte@Sun.COM 59987836SJohn.Forte@Sun.COM void 59997836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info) 60007836SJohn.Forte@Sun.COM { 60017836SJohn.Forte@Sun.COM stmf_svc_req_t *req; 60027836SJohn.Forte@Sun.COM int s; 60037836SJohn.Forte@Sun.COM 60047836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&stmf_state.stmf_lock)); 60057836SJohn.Forte@Sun.COM s = sizeof (stmf_svc_req_t); 60067836SJohn.Forte@Sun.COM if (info->st_additional_info) { 60077836SJohn.Forte@Sun.COM s += strlen(info->st_additional_info) + 1; 60087836SJohn.Forte@Sun.COM } 60097836SJohn.Forte@Sun.COM req = kmem_zalloc(s, KM_SLEEP); 60107836SJohn.Forte@Sun.COM 60117836SJohn.Forte@Sun.COM req->svc_cmd = cmd; 60127836SJohn.Forte@Sun.COM req->svc_obj = obj; 60137836SJohn.Forte@Sun.COM req->svc_info.st_rflags = info->st_rflags; 60147836SJohn.Forte@Sun.COM if (info->st_additional_info) { 60157836SJohn.Forte@Sun.COM req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req, 60167836SJohn.Forte@Sun.COM sizeof (stmf_svc_req_t))); 60177836SJohn.Forte@Sun.COM (void) strcpy(req->svc_info.st_additional_info, 60187836SJohn.Forte@Sun.COM info->st_additional_info); 60197836SJohn.Forte@Sun.COM } 60207836SJohn.Forte@Sun.COM req->svc_req_alloc_size = s; 60217836SJohn.Forte@Sun.COM 60227836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 60237836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_active; 60247836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req; 60257836SJohn.Forte@Sun.COM if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) { 60267836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 60277836SJohn.Forte@Sun.COM } 60287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 60297836SJohn.Forte@Sun.COM } 60307836SJohn.Forte@Sun.COM 60317836SJohn.Forte@Sun.COM void 60327836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...) 60337836SJohn.Forte@Sun.COM { 60347836SJohn.Forte@Sun.COM va_list args; 60357836SJohn.Forte@Sun.COM char tbuf[160]; 60367836SJohn.Forte@Sun.COM int len; 60377836SJohn.Forte@Sun.COM 60387836SJohn.Forte@Sun.COM if (!stmf_trace_on) 60397836SJohn.Forte@Sun.COM return; 60407836SJohn.Forte@Sun.COM len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "", 60417836SJohn.Forte@Sun.COM ddi_get_lbolt()); 60427836SJohn.Forte@Sun.COM va_start(args, fmt); 60437836SJohn.Forte@Sun.COM len += vsnprintf(tbuf + len, 158 - len, fmt, args); 60447836SJohn.Forte@Sun.COM va_end(args); 60457836SJohn.Forte@Sun.COM 60467836SJohn.Forte@Sun.COM if (len > 158) { 60477836SJohn.Forte@Sun.COM len = 158; 60487836SJohn.Forte@Sun.COM } 60497836SJohn.Forte@Sun.COM tbuf[len++] = '\n'; 60507836SJohn.Forte@Sun.COM tbuf[len] = 0; 60517836SJohn.Forte@Sun.COM 60527836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 60537836SJohn.Forte@Sun.COM bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1); 60547836SJohn.Forte@Sun.COM trace_buf_curndx += len; 60557836SJohn.Forte@Sun.COM if (trace_buf_curndx > (trace_buf_size - 320)) 60567836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 60577836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 60587836SJohn.Forte@Sun.COM } 60597836SJohn.Forte@Sun.COM 60607836SJohn.Forte@Sun.COM void 60617836SJohn.Forte@Sun.COM stmf_trace_clear() 60627836SJohn.Forte@Sun.COM { 60637836SJohn.Forte@Sun.COM if (!stmf_trace_on) 60647836SJohn.Forte@Sun.COM return; 60657836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 60667836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 60677836SJohn.Forte@Sun.COM if (trace_buf_size > 0) 60687836SJohn.Forte@Sun.COM stmf_trace_buf[0] = 0; 60697836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 60707836SJohn.Forte@Sun.COM } 60717836SJohn.Forte@Sun.COM 60727836SJohn.Forte@Sun.COM static void 60737836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info) 60747836SJohn.Forte@Sun.COM { 60757836SJohn.Forte@Sun.COM stmf_state_change_info_t change_info; 60767836SJohn.Forte@Sun.COM void *ctl_private; 60777836SJohn.Forte@Sun.COM uint32_t ctl_cmd; 60787836SJohn.Forte@Sun.COM int msg = 0; 60797836SJohn.Forte@Sun.COM 60807836SJohn.Forte@Sun.COM stmf_trace("FROM STMF", "abort_task_offline called for %s: %s", 60817836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : "no additional info"); 60827836SJohn.Forte@Sun.COM change_info.st_additional_info = info; 60837836SJohn.Forte@Sun.COM if (offline_lu) { 60847836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 60857836SJohn.Forte@Sun.COM STMF_RFLAG_LU_ABORT; 60867836SJohn.Forte@Sun.COM ctl_private = task->task_lu; 60877836SJohn.Forte@Sun.COM if (((stmf_i_lu_t *) 60887836SJohn.Forte@Sun.COM task->task_lu->lu_stmf_private)->ilu_state == 60897836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 60907836SJohn.Forte@Sun.COM msg = 1; 60917836SJohn.Forte@Sun.COM } 60927836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LU_OFFLINE; 60937836SJohn.Forte@Sun.COM } else { 60947836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 60957836SJohn.Forte@Sun.COM STMF_RFLAG_LPORT_ABORT; 60967836SJohn.Forte@Sun.COM ctl_private = task->task_lport; 60977836SJohn.Forte@Sun.COM if (((stmf_i_local_port_t *) 60987836SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private)->ilport_state == 60997836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 61007836SJohn.Forte@Sun.COM msg = 1; 61017836SJohn.Forte@Sun.COM } 61027836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LPORT_OFFLINE; 61037836SJohn.Forte@Sun.COM } 61047836SJohn.Forte@Sun.COM 61057836SJohn.Forte@Sun.COM if (msg) { 61067836SJohn.Forte@Sun.COM stmf_trace(0, "Calling stmf_ctl to offline %s : %s", 61077836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : 61087836SJohn.Forte@Sun.COM "<no additional info>"); 61097836SJohn.Forte@Sun.COM } 61107836SJohn.Forte@Sun.COM (void) stmf_ctl(ctl_cmd, ctl_private, &change_info); 61117836SJohn.Forte@Sun.COM } 6112