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 /* 227836SJohn.Forte@Sun.COM * Copyright 2008 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> 397836SJohn.Forte@Sun.COM 407836SJohn.Forte@Sun.COM #include <stmf.h> 417836SJohn.Forte@Sun.COM #include <lpif.h> 427836SJohn.Forte@Sun.COM #include <portif.h> 437836SJohn.Forte@Sun.COM #include <stmf_ioctl.h> 447836SJohn.Forte@Sun.COM #include <stmf_impl.h> 457836SJohn.Forte@Sun.COM #include <lun_map.h> 467836SJohn.Forte@Sun.COM #include <stmf_state.h> 477836SJohn.Forte@Sun.COM 487836SJohn.Forte@Sun.COM static uint64_t stmf_session_counter = 0; 497836SJohn.Forte@Sun.COM static uint16_t stmf_rtpid_counter = 0; 507836SJohn.Forte@Sun.COM 517836SJohn.Forte@Sun.COM static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 527836SJohn.Forte@Sun.COM static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 537836SJohn.Forte@Sun.COM static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 547836SJohn.Forte@Sun.COM void **result); 557836SJohn.Forte@Sun.COM static int stmf_open(dev_t *devp, int flag, int otype, cred_t *credp); 567836SJohn.Forte@Sun.COM static int stmf_close(dev_t dev, int flag, int otype, cred_t *credp); 577836SJohn.Forte@Sun.COM static int stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 587836SJohn.Forte@Sun.COM cred_t *credp, int *rval); 597836SJohn.Forte@Sun.COM static int stmf_get_stmf_state(stmf_state_desc_t *std); 607836SJohn.Forte@Sun.COM static int stmf_set_stmf_state(stmf_state_desc_t *std); 617836SJohn.Forte@Sun.COM static void stmf_abort_task_offline(scsi_task_t *task, int offline_lu, 627836SJohn.Forte@Sun.COM char *info); 637836SJohn.Forte@Sun.COM void stmf_svc_init(); 647836SJohn.Forte@Sun.COM stmf_status_t stmf_svc_fini(); 657836SJohn.Forte@Sun.COM void stmf_svc(void *arg); 667836SJohn.Forte@Sun.COM void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info); 677836SJohn.Forte@Sun.COM void stmf_check_freetask(); 687836SJohn.Forte@Sun.COM void stmf_abort_target_reset(scsi_task_t *task); 697836SJohn.Forte@Sun.COM stmf_status_t stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, 707836SJohn.Forte@Sun.COM int target_reset); 717836SJohn.Forte@Sun.COM void stmf_target_reset_poll(struct scsi_task *task); 727836SJohn.Forte@Sun.COM void stmf_handle_lun_reset(scsi_task_t *task); 737836SJohn.Forte@Sun.COM void stmf_handle_target_reset(scsi_task_t *task); 747836SJohn.Forte@Sun.COM void stmf_xd_to_dbuf(stmf_data_buf_t *dbuf); 757836SJohn.Forte@Sun.COM int stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi); 767836SJohn.Forte@Sun.COM int stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi); 777836SJohn.Forte@Sun.COM void stmf_delete_ppd(stmf_pp_data_t *ppd); 787836SJohn.Forte@Sun.COM void stmf_delete_all_ppds(); 797836SJohn.Forte@Sun.COM void stmf_trace_clear(); 807836SJohn.Forte@Sun.COM void stmf_worker_init(); 817836SJohn.Forte@Sun.COM stmf_status_t stmf_worker_fini(); 827836SJohn.Forte@Sun.COM void stmf_worker_mgmt(); 837836SJohn.Forte@Sun.COM void stmf_worker_task(void *arg); 847836SJohn.Forte@Sun.COM 857836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops; 867836SJohn.Forte@Sun.COM 877836SJohn.Forte@Sun.COM /* =====[ Tunables ]===== */ 887836SJohn.Forte@Sun.COM /* Internal tracing */ 897836SJohn.Forte@Sun.COM volatile int stmf_trace_on = 1; 907836SJohn.Forte@Sun.COM volatile int stmf_trace_buf_size = (1 * 1024 * 1024); 917836SJohn.Forte@Sun.COM /* 927836SJohn.Forte@Sun.COM * The reason default task timeout is 75 is because we want the 937836SJohn.Forte@Sun.COM * host to timeout 1st and mostly host timeout is 60 seconds. 947836SJohn.Forte@Sun.COM */ 957836SJohn.Forte@Sun.COM volatile int stmf_default_task_timeout = 75; 967836SJohn.Forte@Sun.COM /* 977836SJohn.Forte@Sun.COM * Setting this to one means, you are responsible for config load and keeping 987836SJohn.Forte@Sun.COM * things in sync with persistent database. 997836SJohn.Forte@Sun.COM */ 1007836SJohn.Forte@Sun.COM volatile int stmf_allow_modunload = 0; 1017836SJohn.Forte@Sun.COM 1027836SJohn.Forte@Sun.COM volatile int stmf_max_nworkers = 256; 1037836SJohn.Forte@Sun.COM volatile int stmf_min_nworkers = 4; 1047836SJohn.Forte@Sun.COM volatile int stmf_worker_scale_down_delay = 20; 1057836SJohn.Forte@Sun.COM 1067836SJohn.Forte@Sun.COM /* === [ Debugging and fault injection ] === */ 1077836SJohn.Forte@Sun.COM #ifdef DEBUG 1087836SJohn.Forte@Sun.COM volatile int stmf_drop_task_counter = 0; 1097836SJohn.Forte@Sun.COM volatile int stmf_drop_buf_counter = 0; 1107836SJohn.Forte@Sun.COM 1117836SJohn.Forte@Sun.COM #endif 1127836SJohn.Forte@Sun.COM 1137836SJohn.Forte@Sun.COM stmf_state_t stmf_state; 1147836SJohn.Forte@Sun.COM static stmf_lu_t *dlun0; 1157836SJohn.Forte@Sun.COM 1167836SJohn.Forte@Sun.COM static uint8_t stmf_first_zero[] = 1177836SJohn.Forte@Sun.COM { 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 0xff }; 1187836SJohn.Forte@Sun.COM static uint8_t stmf_first_one[] = 1197836SJohn.Forte@Sun.COM { 0xff, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; 1207836SJohn.Forte@Sun.COM 1217836SJohn.Forte@Sun.COM static kmutex_t trace_buf_lock; 1227836SJohn.Forte@Sun.COM static int trace_buf_size; 1237836SJohn.Forte@Sun.COM static int trace_buf_curndx; 1247836SJohn.Forte@Sun.COM caddr_t stmf_trace_buf; 1257836SJohn.Forte@Sun.COM 1267836SJohn.Forte@Sun.COM static enum { 1277836SJohn.Forte@Sun.COM STMF_WORKERS_DISABLED = 0, 1287836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLING, 1297836SJohn.Forte@Sun.COM STMF_WORKERS_ENABLED 1307836SJohn.Forte@Sun.COM } stmf_workers_state = STMF_WORKERS_DISABLED; 1317836SJohn.Forte@Sun.COM static int stmf_i_max_nworkers; 1327836SJohn.Forte@Sun.COM static int stmf_i_min_nworkers; 1337836SJohn.Forte@Sun.COM static int stmf_nworkers_cur; /* # of workers currently running */ 1347836SJohn.Forte@Sun.COM static int stmf_nworkers_needed; /* # of workers need to be running */ 1357836SJohn.Forte@Sun.COM static int stmf_worker_sel_counter = 0; 1367836SJohn.Forte@Sun.COM static uint32_t stmf_cur_ntasks = 0; 1377836SJohn.Forte@Sun.COM static clock_t stmf_wm_last = 0; 1387836SJohn.Forte@Sun.COM /* 1397836SJohn.Forte@Sun.COM * This is equal to stmf_nworkers_cur while we are increasing # workers and 1407836SJohn.Forte@Sun.COM * stmf_nworkers_needed while we are decreasing the worker count. 1417836SJohn.Forte@Sun.COM */ 1427836SJohn.Forte@Sun.COM static int stmf_nworkers_accepting_cmds; 1437836SJohn.Forte@Sun.COM static stmf_worker_t *stmf_workers = NULL; 1447836SJohn.Forte@Sun.COM static clock_t stmf_worker_mgmt_delay = 2; 1457836SJohn.Forte@Sun.COM static clock_t stmf_worker_scale_down_timer = 0; 1467836SJohn.Forte@Sun.COM static int stmf_worker_scale_down_qd = 0; 1477836SJohn.Forte@Sun.COM 1487836SJohn.Forte@Sun.COM static struct cb_ops stmf_cb_ops = { 1497836SJohn.Forte@Sun.COM stmf_open, /* open */ 1507836SJohn.Forte@Sun.COM stmf_close, /* close */ 1517836SJohn.Forte@Sun.COM nodev, /* strategy */ 1527836SJohn.Forte@Sun.COM nodev, /* print */ 1537836SJohn.Forte@Sun.COM nodev, /* dump */ 1547836SJohn.Forte@Sun.COM nodev, /* read */ 1557836SJohn.Forte@Sun.COM nodev, /* write */ 1567836SJohn.Forte@Sun.COM stmf_ioctl, /* ioctl */ 1577836SJohn.Forte@Sun.COM nodev, /* devmap */ 1587836SJohn.Forte@Sun.COM nodev, /* mmap */ 1597836SJohn.Forte@Sun.COM nodev, /* segmap */ 1607836SJohn.Forte@Sun.COM nochpoll, /* chpoll */ 1617836SJohn.Forte@Sun.COM ddi_prop_op, /* cb_prop_op */ 1627836SJohn.Forte@Sun.COM 0, /* streamtab */ 1637836SJohn.Forte@Sun.COM D_NEW | D_MP, /* cb_flag */ 1647836SJohn.Forte@Sun.COM CB_REV, /* rev */ 1657836SJohn.Forte@Sun.COM nodev, /* aread */ 1667836SJohn.Forte@Sun.COM nodev /* awrite */ 1677836SJohn.Forte@Sun.COM }; 1687836SJohn.Forte@Sun.COM 1697836SJohn.Forte@Sun.COM static struct dev_ops stmf_ops = { 1707836SJohn.Forte@Sun.COM DEVO_REV, 1717836SJohn.Forte@Sun.COM 0, 1727836SJohn.Forte@Sun.COM stmf_getinfo, 1737836SJohn.Forte@Sun.COM nulldev, /* identify */ 1747836SJohn.Forte@Sun.COM nulldev, /* probe */ 1757836SJohn.Forte@Sun.COM stmf_attach, 1767836SJohn.Forte@Sun.COM stmf_detach, 1777836SJohn.Forte@Sun.COM nodev, /* reset */ 1787836SJohn.Forte@Sun.COM &stmf_cb_ops, 1797836SJohn.Forte@Sun.COM NULL, /* bus_ops */ 1807836SJohn.Forte@Sun.COM NULL /* power */ 1817836SJohn.Forte@Sun.COM }; 1827836SJohn.Forte@Sun.COM 1837836SJohn.Forte@Sun.COM #define STMF_NAME "COMSTAR STMF" 1847836SJohn.Forte@Sun.COM 1857836SJohn.Forte@Sun.COM static struct modldrv modldrv = { 1867836SJohn.Forte@Sun.COM &mod_driverops, 1877836SJohn.Forte@Sun.COM STMF_NAME, 1887836SJohn.Forte@Sun.COM &stmf_ops 1897836SJohn.Forte@Sun.COM }; 1907836SJohn.Forte@Sun.COM 1917836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = { 1927836SJohn.Forte@Sun.COM MODREV_1, 1937836SJohn.Forte@Sun.COM &modldrv, 1947836SJohn.Forte@Sun.COM NULL 1957836SJohn.Forte@Sun.COM }; 1967836SJohn.Forte@Sun.COM 1977836SJohn.Forte@Sun.COM int 1987836SJohn.Forte@Sun.COM _init(void) 1997836SJohn.Forte@Sun.COM { 2007836SJohn.Forte@Sun.COM int ret; 2017836SJohn.Forte@Sun.COM 2027836SJohn.Forte@Sun.COM ret = mod_install(&modlinkage); 2037836SJohn.Forte@Sun.COM if (ret) 2047836SJohn.Forte@Sun.COM return (ret); 2057836SJohn.Forte@Sun.COM stmf_trace_buf = kmem_zalloc(stmf_trace_buf_size, KM_SLEEP); 2067836SJohn.Forte@Sun.COM trace_buf_size = stmf_trace_buf_size; 2077836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 2087836SJohn.Forte@Sun.COM mutex_init(&trace_buf_lock, NULL, MUTEX_DRIVER, 0); 2097836SJohn.Forte@Sun.COM bzero(&stmf_state, sizeof (stmf_state_t)); 2107836SJohn.Forte@Sun.COM /* STMF service is off by default */ 2117836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 2127836SJohn.Forte@Sun.COM mutex_init(&stmf_state.stmf_lock, NULL, MUTEX_DRIVER, NULL); 2137836SJohn.Forte@Sun.COM cv_init(&stmf_state.stmf_cv, NULL, CV_DRIVER, NULL); 2147836SJohn.Forte@Sun.COM stmf_session_counter = (uint64_t)ddi_get_lbolt(); 2157836SJohn.Forte@Sun.COM stmf_view_init(); 2167836SJohn.Forte@Sun.COM stmf_svc_init(); 2177836SJohn.Forte@Sun.COM stmf_dlun_init(); 2187836SJohn.Forte@Sun.COM return (ret); 2197836SJohn.Forte@Sun.COM } 2207836SJohn.Forte@Sun.COM 2217836SJohn.Forte@Sun.COM int 2227836SJohn.Forte@Sun.COM _fini(void) 2237836SJohn.Forte@Sun.COM { 2247836SJohn.Forte@Sun.COM int ret; 2257836SJohn.Forte@Sun.COM 2267836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) 2277836SJohn.Forte@Sun.COM return (EBUSY); 2287836SJohn.Forte@Sun.COM if ((!stmf_allow_modunload) && 2297836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_NONE)) { 2307836SJohn.Forte@Sun.COM return (EBUSY); 2317836SJohn.Forte@Sun.COM } 2327836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlps || stmf_state.stmf_npps) { 2337836SJohn.Forte@Sun.COM return (EBUSY); 2347836SJohn.Forte@Sun.COM } 2357836SJohn.Forte@Sun.COM if (stmf_dlun_fini() != STMF_SUCCESS) 2367836SJohn.Forte@Sun.COM return (EBUSY); 2377836SJohn.Forte@Sun.COM if (stmf_worker_fini() != STMF_SUCCESS) { 2387836SJohn.Forte@Sun.COM stmf_dlun_init(); 2397836SJohn.Forte@Sun.COM return (EBUSY); 2407836SJohn.Forte@Sun.COM } 2417836SJohn.Forte@Sun.COM if (stmf_svc_fini() != STMF_SUCCESS) { 2427836SJohn.Forte@Sun.COM stmf_dlun_init(); 2437836SJohn.Forte@Sun.COM stmf_worker_init(); 2447836SJohn.Forte@Sun.COM return (EBUSY); 2457836SJohn.Forte@Sun.COM } 2467836SJohn.Forte@Sun.COM 2477836SJohn.Forte@Sun.COM ret = mod_remove(&modlinkage); 2487836SJohn.Forte@Sun.COM if (ret) { 2497836SJohn.Forte@Sun.COM stmf_svc_init(); 2507836SJohn.Forte@Sun.COM stmf_dlun_init(); 2517836SJohn.Forte@Sun.COM stmf_worker_init(); 2527836SJohn.Forte@Sun.COM return (ret); 2537836SJohn.Forte@Sun.COM } 2547836SJohn.Forte@Sun.COM 2557836SJohn.Forte@Sun.COM stmf_view_clear_config(); 2567836SJohn.Forte@Sun.COM kmem_free(stmf_trace_buf, stmf_trace_buf_size); 2577836SJohn.Forte@Sun.COM mutex_destroy(&trace_buf_lock); 2587836SJohn.Forte@Sun.COM mutex_destroy(&stmf_state.stmf_lock); 2597836SJohn.Forte@Sun.COM cv_destroy(&stmf_state.stmf_cv); 2607836SJohn.Forte@Sun.COM return (ret); 2617836SJohn.Forte@Sun.COM } 2627836SJohn.Forte@Sun.COM 2637836SJohn.Forte@Sun.COM int 2647836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop) 2657836SJohn.Forte@Sun.COM { 2667836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfop)); 2677836SJohn.Forte@Sun.COM } 2687836SJohn.Forte@Sun.COM 2697836SJohn.Forte@Sun.COM /* ARGSUSED */ 2707836SJohn.Forte@Sun.COM static int 2717836SJohn.Forte@Sun.COM stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 2727836SJohn.Forte@Sun.COM { 2737836SJohn.Forte@Sun.COM switch (cmd) { 2747836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2DEVINFO: 2757836SJohn.Forte@Sun.COM *result = stmf_state.stmf_dip; 2767836SJohn.Forte@Sun.COM break; 2777836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2INSTANCE: 2787836SJohn.Forte@Sun.COM *result = (void *)(uintptr_t)ddi_get_instance(dip); 2797836SJohn.Forte@Sun.COM break; 2807836SJohn.Forte@Sun.COM default: 2817836SJohn.Forte@Sun.COM return (DDI_FAILURE); 2827836SJohn.Forte@Sun.COM } 2837836SJohn.Forte@Sun.COM 2847836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 2857836SJohn.Forte@Sun.COM } 2867836SJohn.Forte@Sun.COM 2877836SJohn.Forte@Sun.COM static int 2887836SJohn.Forte@Sun.COM stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2897836SJohn.Forte@Sun.COM { 2907836SJohn.Forte@Sun.COM switch (cmd) { 2917836SJohn.Forte@Sun.COM case DDI_ATTACH: 2927836SJohn.Forte@Sun.COM stmf_state.stmf_dip = dip; 2937836SJohn.Forte@Sun.COM 2947836SJohn.Forte@Sun.COM if (ddi_create_minor_node(dip, "admin", S_IFCHR, 0, 2957836SJohn.Forte@Sun.COM DDI_NT_STMF, 0) != DDI_SUCCESS) { 2967836SJohn.Forte@Sun.COM break; 2977836SJohn.Forte@Sun.COM } 2987836SJohn.Forte@Sun.COM ddi_report_dev(dip); 2997836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3007836SJohn.Forte@Sun.COM } 3017836SJohn.Forte@Sun.COM 3027836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3037836SJohn.Forte@Sun.COM } 3047836SJohn.Forte@Sun.COM 3057836SJohn.Forte@Sun.COM static int 3067836SJohn.Forte@Sun.COM stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 3077836SJohn.Forte@Sun.COM { 3087836SJohn.Forte@Sun.COM switch (cmd) { 3097836SJohn.Forte@Sun.COM case DDI_DETACH: 3107836SJohn.Forte@Sun.COM ddi_remove_minor_node(dip, 0); 3117836SJohn.Forte@Sun.COM return (DDI_SUCCESS); 3127836SJohn.Forte@Sun.COM } 3137836SJohn.Forte@Sun.COM 3147836SJohn.Forte@Sun.COM return (DDI_FAILURE); 3157836SJohn.Forte@Sun.COM } 3167836SJohn.Forte@Sun.COM 3177836SJohn.Forte@Sun.COM /* ARGSUSED */ 3187836SJohn.Forte@Sun.COM static int 3197836SJohn.Forte@Sun.COM stmf_open(dev_t *devp, int flag, int otype, cred_t *credp) 3207836SJohn.Forte@Sun.COM { 3217836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3227836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open) { 3237836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3247836SJohn.Forte@Sun.COM return (EBUSY); 3257836SJohn.Forte@Sun.COM } 3267836SJohn.Forte@Sun.COM if (flag & FEXCL) { 3277836SJohn.Forte@Sun.COM if (stmf_state.stmf_opened) { 3287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3297836SJohn.Forte@Sun.COM return (EBUSY); 3307836SJohn.Forte@Sun.COM } 3317836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 1; 3327836SJohn.Forte@Sun.COM } 3337836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 1; 3347836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3357836SJohn.Forte@Sun.COM return (0); 3367836SJohn.Forte@Sun.COM } 3377836SJohn.Forte@Sun.COM 3387836SJohn.Forte@Sun.COM /* ARGSUSED */ 3397836SJohn.Forte@Sun.COM static int 3407836SJohn.Forte@Sun.COM stmf_close(dev_t dev, int flag, int otype, cred_t *credp) 3417836SJohn.Forte@Sun.COM { 3427836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 3437836SJohn.Forte@Sun.COM stmf_state.stmf_opened = 0; 3447836SJohn.Forte@Sun.COM if (stmf_state.stmf_exclusive_open && 3457836SJohn.Forte@Sun.COM (stmf_state.stmf_config_state != STMF_CONFIG_INIT_DONE)) { 3467836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_NONE; 3477836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 3487836SJohn.Forte@Sun.COM stmf_view_clear_config(); 3497836SJohn.Forte@Sun.COM stmf_view_init(); 3507836SJohn.Forte@Sun.COM } 3517836SJohn.Forte@Sun.COM stmf_state.stmf_exclusive_open = 0; 3527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 3537836SJohn.Forte@Sun.COM return (0); 3547836SJohn.Forte@Sun.COM } 3557836SJohn.Forte@Sun.COM 3567836SJohn.Forte@Sun.COM int 3577836SJohn.Forte@Sun.COM stmf_copyin_iocdata(intptr_t data, int mode, stmf_iocdata_t **iocd, 3587836SJohn.Forte@Sun.COM void **ibuf, void **obuf) 3597836SJohn.Forte@Sun.COM { 3607836SJohn.Forte@Sun.COM int ret; 3617836SJohn.Forte@Sun.COM 3627836SJohn.Forte@Sun.COM *ibuf = NULL; 3637836SJohn.Forte@Sun.COM *obuf = NULL; 3647836SJohn.Forte@Sun.COM *iocd = kmem_zalloc(sizeof (stmf_iocdata_t), KM_SLEEP); 3657836SJohn.Forte@Sun.COM 3667836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)data, *iocd, sizeof (stmf_iocdata_t), mode); 3677836SJohn.Forte@Sun.COM if (ret) 3687836SJohn.Forte@Sun.COM return (EFAULT); 3697836SJohn.Forte@Sun.COM if ((*iocd)->stmf_version != STMF_VERSION_1) { 3707836SJohn.Forte@Sun.COM ret = EINVAL; 3717836SJohn.Forte@Sun.COM goto copyin_iocdata_done; 3727836SJohn.Forte@Sun.COM } 3737836SJohn.Forte@Sun.COM if ((*iocd)->stmf_ibuf_size) { 3747836SJohn.Forte@Sun.COM *ibuf = kmem_zalloc((*iocd)->stmf_ibuf_size, KM_SLEEP); 3757836SJohn.Forte@Sun.COM ret = ddi_copyin((void *)((unsigned long)(*iocd)->stmf_ibuf), 3767836SJohn.Forte@Sun.COM *ibuf, (*iocd)->stmf_ibuf_size, mode); 3777836SJohn.Forte@Sun.COM } 3787836SJohn.Forte@Sun.COM if ((*iocd)->stmf_obuf_size) 3797836SJohn.Forte@Sun.COM *obuf = kmem_zalloc((*iocd)->stmf_obuf_size, KM_SLEEP); 3807836SJohn.Forte@Sun.COM 3817836SJohn.Forte@Sun.COM if (ret == 0) 3827836SJohn.Forte@Sun.COM return (0); 3837836SJohn.Forte@Sun.COM ret = EFAULT; 3847836SJohn.Forte@Sun.COM copyin_iocdata_done:; 3857836SJohn.Forte@Sun.COM if (*obuf) { 3867836SJohn.Forte@Sun.COM kmem_free(*obuf, (*iocd)->stmf_obuf_size); 3877836SJohn.Forte@Sun.COM *obuf = NULL; 3887836SJohn.Forte@Sun.COM } 3897836SJohn.Forte@Sun.COM if (*ibuf) { 3907836SJohn.Forte@Sun.COM kmem_free(*ibuf, (*iocd)->stmf_ibuf_size); 3917836SJohn.Forte@Sun.COM *ibuf = NULL; 3927836SJohn.Forte@Sun.COM } 3937836SJohn.Forte@Sun.COM kmem_free(*iocd, sizeof (stmf_iocdata_t)); 3947836SJohn.Forte@Sun.COM return (ret); 3957836SJohn.Forte@Sun.COM } 3967836SJohn.Forte@Sun.COM 3977836SJohn.Forte@Sun.COM int 3987836SJohn.Forte@Sun.COM stmf_copyout_iocdata(intptr_t data, int mode, stmf_iocdata_t *iocd, void *obuf) 3997836SJohn.Forte@Sun.COM { 4007836SJohn.Forte@Sun.COM int ret; 4017836SJohn.Forte@Sun.COM 4027836SJohn.Forte@Sun.COM if (iocd->stmf_obuf_size) { 4037836SJohn.Forte@Sun.COM ret = ddi_copyout(obuf, (void *)(unsigned long)iocd->stmf_obuf, 4047836SJohn.Forte@Sun.COM iocd->stmf_obuf_size, mode); 4057836SJohn.Forte@Sun.COM if (ret) 4067836SJohn.Forte@Sun.COM return (EFAULT); 4077836SJohn.Forte@Sun.COM } 4087836SJohn.Forte@Sun.COM ret = ddi_copyout(iocd, (void *)data, sizeof (stmf_iocdata_t), mode); 4097836SJohn.Forte@Sun.COM if (ret) 4107836SJohn.Forte@Sun.COM return (EFAULT); 4117836SJohn.Forte@Sun.COM return (0); 4127836SJohn.Forte@Sun.COM } 4137836SJohn.Forte@Sun.COM 4147836SJohn.Forte@Sun.COM /* ARGSUSED */ 4157836SJohn.Forte@Sun.COM static int 4167836SJohn.Forte@Sun.COM stmf_ioctl(dev_t dev, int cmd, intptr_t data, int mode, 4177836SJohn.Forte@Sun.COM cred_t *credp, int *rval) 4187836SJohn.Forte@Sun.COM { 4197836SJohn.Forte@Sun.COM stmf_iocdata_t *iocd; 4207836SJohn.Forte@Sun.COM void *ibuf = NULL, *obuf = NULL; 4217836SJohn.Forte@Sun.COM slist_lu_t *luid_list; 4227836SJohn.Forte@Sun.COM slist_target_port_t *lportid_list; 4237836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 4247836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 4257836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 4267836SJohn.Forte@Sun.COM slist_scsi_session_t *iss_list; 4277836SJohn.Forte@Sun.COM sioc_lu_props_t *lup; 4287836SJohn.Forte@Sun.COM sioc_target_port_props_t *lportp; 4297836SJohn.Forte@Sun.COM stmf_ppioctl_data_t *ppi; 4307836SJohn.Forte@Sun.COM uint8_t *p_id; 4317836SJohn.Forte@Sun.COM stmf_state_desc_t *std; 4327836SJohn.Forte@Sun.COM stmf_status_t ctl_ret; 4337836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 4347836SJohn.Forte@Sun.COM int ret = 0; 4357836SJohn.Forte@Sun.COM uint32_t n; 4367836SJohn.Forte@Sun.COM int i; 4377836SJohn.Forte@Sun.COM stmf_group_op_data_t *grp_entry; 4387836SJohn.Forte@Sun.COM stmf_group_name_t *grpname; 4397836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve; 4407836SJohn.Forte@Sun.COM stmf_id_type_t idtype; 4417836SJohn.Forte@Sun.COM #if 0 4427836SJohn.Forte@Sun.COM stmf_id_data_t *id_entry; 4437836SJohn.Forte@Sun.COM stmf_id_list_t *id_list; 4447836SJohn.Forte@Sun.COM stmf_view_entry_t *view_entry; 4457836SJohn.Forte@Sun.COM #endif 4467836SJohn.Forte@Sun.COM uint32_t veid; 4477836SJohn.Forte@Sun.COM 4487836SJohn.Forte@Sun.COM if ((cmd & 0xff000000) != STMF_IOCTL) { 4497836SJohn.Forte@Sun.COM return (ENOTTY); 4507836SJohn.Forte@Sun.COM } 4517836SJohn.Forte@Sun.COM 4527836SJohn.Forte@Sun.COM if (drv_priv(credp) != 0) { 4537836SJohn.Forte@Sun.COM return (EPERM); 4547836SJohn.Forte@Sun.COM } 4557836SJohn.Forte@Sun.COM 4567836SJohn.Forte@Sun.COM ret = stmf_copyin_iocdata(data, mode, &iocd, &ibuf, &obuf); 4577836SJohn.Forte@Sun.COM if (ret) 4587836SJohn.Forte@Sun.COM return (ret); 4597836SJohn.Forte@Sun.COM iocd->stmf_error = 0; 4607836SJohn.Forte@Sun.COM 4617836SJohn.Forte@Sun.COM switch (cmd) { 4627836SJohn.Forte@Sun.COM case STMF_IOCTL_LU_LIST: 4637836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4647836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlus; 4657836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlus, 4667836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_lu_t)); 4677836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 4687836SJohn.Forte@Sun.COM ilu = stmf_state.stmf_ilulist; 4697836SJohn.Forte@Sun.COM luid_list = (slist_lu_t *)obuf; 4707836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 4717836SJohn.Forte@Sun.COM uint8_t *id; 4727836SJohn.Forte@Sun.COM id = (uint8_t *)ilu->ilu_lu->lu_id; 4737836SJohn.Forte@Sun.COM bcopy(id + 4, luid_list[i].lu_guid, 16); 4747836SJohn.Forte@Sun.COM ilu = ilu->ilu_next; 4757836SJohn.Forte@Sun.COM } 4767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 4777836SJohn.Forte@Sun.COM break; 4787836SJohn.Forte@Sun.COM 4797836SJohn.Forte@Sun.COM case STMF_IOCTL_TARGET_PORT_LIST: 4807836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4817836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = stmf_state.stmf_nlports; 4827836SJohn.Forte@Sun.COM n = min(stmf_state.stmf_nlports, 4837836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_target_port_t)); 4847836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 4857836SJohn.Forte@Sun.COM ilport = stmf_state.stmf_ilportlist; 4867836SJohn.Forte@Sun.COM lportid_list = (slist_target_port_t *)obuf; 4877836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 4887836SJohn.Forte@Sun.COM uint8_t *id; 4897836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 4907836SJohn.Forte@Sun.COM bcopy(id, lportid_list[i].target, id[3] + 4); 4917836SJohn.Forte@Sun.COM ilport = ilport->ilport_next; 4927836SJohn.Forte@Sun.COM } 4937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 4947836SJohn.Forte@Sun.COM break; 4957836SJohn.Forte@Sun.COM 4967836SJohn.Forte@Sun.COM case STMF_IOCTL_SESSION_LIST: 4977836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 4987836SJohn.Forte@Sun.COM if ((p_id == NULL) || (iocd->stmf_ibuf_size < 4) || 4997836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4))) { 5007836SJohn.Forte@Sun.COM ret = EINVAL; 5017836SJohn.Forte@Sun.COM break; 5027836SJohn.Forte@Sun.COM } 5037836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5047836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; ilport = 5057836SJohn.Forte@Sun.COM ilport->ilport_next) { 5067836SJohn.Forte@Sun.COM uint8_t *id; 5077836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5087836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 5097836SJohn.Forte@Sun.COM (bcmp(p_id + 4, id + 4, id[3]) == 0)) { 5107836SJohn.Forte@Sun.COM break; 5117836SJohn.Forte@Sun.COM } 5127836SJohn.Forte@Sun.COM } 5137836SJohn.Forte@Sun.COM if (ilport == NULL) { 5147836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5157836SJohn.Forte@Sun.COM ret = ENOENT; 5167836SJohn.Forte@Sun.COM break; 5177836SJohn.Forte@Sun.COM } 5187836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = ilport->ilport_nsessions; 5197836SJohn.Forte@Sun.COM n = min(ilport->ilport_nsessions, 5207836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (slist_scsi_session_t)); 5217836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 5227836SJohn.Forte@Sun.COM iss = ilport->ilport_ss_list; 5237836SJohn.Forte@Sun.COM iss_list = (slist_scsi_session_t *)obuf; 5247836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 5257836SJohn.Forte@Sun.COM uint8_t *id; 5267836SJohn.Forte@Sun.COM id = (uint8_t *)iss->iss_ss->ss_rport_id; 5277836SJohn.Forte@Sun.COM bcopy(id, iss_list[i].initiator, id[3] + 4); 5287836SJohn.Forte@Sun.COM iss_list[i].creation_time = (uint32_t) 5297836SJohn.Forte@Sun.COM iss->iss_creation_time; 5307836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_rport_alias) { 5317836SJohn.Forte@Sun.COM (void) strncpy(iss_list[i].alias, 5327836SJohn.Forte@Sun.COM iss->iss_ss->ss_rport_alias, 255); 5337836SJohn.Forte@Sun.COM iss_list[i].alias[255] = 0; 5347836SJohn.Forte@Sun.COM } else { 5357836SJohn.Forte@Sun.COM iss_list[i].alias[0] = 0; 5367836SJohn.Forte@Sun.COM } 5377836SJohn.Forte@Sun.COM iss = iss->iss_next; 5387836SJohn.Forte@Sun.COM } 5397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5407836SJohn.Forte@Sun.COM break; 5417836SJohn.Forte@Sun.COM 5427836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_LU_PROPERTIES: 5437836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 5447836SJohn.Forte@Sun.COM if ((iocd->stmf_ibuf_size < 16) || 5457836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (sioc_lu_props_t)) || 5467836SJohn.Forte@Sun.COM (p_id[0] == 0)) { 5477836SJohn.Forte@Sun.COM ret = EINVAL; 5487836SJohn.Forte@Sun.COM break; 5497836SJohn.Forte@Sun.COM } 5507836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5517836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 5527836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 5537836SJohn.Forte@Sun.COM break; 5547836SJohn.Forte@Sun.COM } 5557836SJohn.Forte@Sun.COM if (ilu == NULL) { 5567836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5577836SJohn.Forte@Sun.COM ret = ENOENT; 5587836SJohn.Forte@Sun.COM break; 5597836SJohn.Forte@Sun.COM } 5607836SJohn.Forte@Sun.COM lup = (sioc_lu_props_t *)obuf; 5617836SJohn.Forte@Sun.COM bcopy(ilu->ilu_lu->lu_id->ident, lup->lu_guid, 16); 5627836SJohn.Forte@Sun.COM lup->lu_state = ilu->ilu_state & 0x0f; 5637836SJohn.Forte@Sun.COM lup->lu_present = 1; /* XXX */ 5647836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_provider_name, 5657836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_lp->lp_name, 255); 5667836SJohn.Forte@Sun.COM lup->lu_provider_name[254] = 0; 5677836SJohn.Forte@Sun.COM if (ilu->ilu_lu->lu_alias) { 5687836SJohn.Forte@Sun.COM (void) strncpy(lup->lu_alias, 5697836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_alias, 255); 5707836SJohn.Forte@Sun.COM lup->lu_alias[255] = 0; 5717836SJohn.Forte@Sun.COM } else { 5727836SJohn.Forte@Sun.COM lup->lu_alias[0] = 0; 5737836SJohn.Forte@Sun.COM } 5747836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5757836SJohn.Forte@Sun.COM break; 5767836SJohn.Forte@Sun.COM 5777836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TARGET_PORT_PROPERTIES: 5787836SJohn.Forte@Sun.COM p_id = (uint8_t *)ibuf; 5797836SJohn.Forte@Sun.COM if ((p_id == NULL) || 5807836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < (p_id[3] + 4)) || 5817836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < 5827836SJohn.Forte@Sun.COM sizeof (sioc_target_port_props_t))) { 5837836SJohn.Forte@Sun.COM ret = EINVAL; 5847836SJohn.Forte@Sun.COM break; 5857836SJohn.Forte@Sun.COM } 5867836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 5877836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 5887836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 5897836SJohn.Forte@Sun.COM uint8_t *id; 5907836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 5917836SJohn.Forte@Sun.COM if ((p_id[3] == id[3]) && 5927836SJohn.Forte@Sun.COM (bcmp(p_id+4, id+4, id[3]) == 0)) 5937836SJohn.Forte@Sun.COM break; 5947836SJohn.Forte@Sun.COM } 5957836SJohn.Forte@Sun.COM if (ilport == NULL) { 5967836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 5977836SJohn.Forte@Sun.COM ret = ENOENT; 5987836SJohn.Forte@Sun.COM break; 5997836SJohn.Forte@Sun.COM } 6007836SJohn.Forte@Sun.COM lportp = (sioc_target_port_props_t *)obuf; 6017836SJohn.Forte@Sun.COM bcopy(ilport->ilport_lport->lport_id, lportp->tgt_id, 6027836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_id->ident_length + 4); 6037836SJohn.Forte@Sun.COM lportp->tgt_state = ilport->ilport_state & 0x0f; 6047836SJohn.Forte@Sun.COM lportp->tgt_present = 1; /* XXX */ 6057836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_provider_name, 6067836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_pp->pp_name, 255); 6077836SJohn.Forte@Sun.COM lportp->tgt_provider_name[254] = 0; 6087836SJohn.Forte@Sun.COM if (ilport->ilport_lport->lport_alias) { 6097836SJohn.Forte@Sun.COM (void) strncpy(lportp->tgt_alias, 6107836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_alias, 255); 6117836SJohn.Forte@Sun.COM lportp->tgt_alias[255] = 0; 6127836SJohn.Forte@Sun.COM } else { 6137836SJohn.Forte@Sun.COM lportp->tgt_alias[0] = 0; 6147836SJohn.Forte@Sun.COM } 6157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6167836SJohn.Forte@Sun.COM break; 6177836SJohn.Forte@Sun.COM 6187836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_STMF_STATE: 6197836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 6207836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 6217836SJohn.Forte@Sun.COM ret = EINVAL; 6227836SJohn.Forte@Sun.COM break; 6237836SJohn.Forte@Sun.COM } 6247836SJohn.Forte@Sun.COM ret = stmf_set_stmf_state((stmf_state_desc_t *)ibuf); 6257836SJohn.Forte@Sun.COM break; 6267836SJohn.Forte@Sun.COM 6277836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_STMF_STATE: 6287836SJohn.Forte@Sun.COM if ((obuf == NULL) || 6297836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size < sizeof (stmf_state_desc_t))) { 6307836SJohn.Forte@Sun.COM ret = EINVAL; 6317836SJohn.Forte@Sun.COM break; 6327836SJohn.Forte@Sun.COM } 6337836SJohn.Forte@Sun.COM ret = stmf_get_stmf_state((stmf_state_desc_t *)obuf); 6347836SJohn.Forte@Sun.COM break; 6357836SJohn.Forte@Sun.COM 6367836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_LU_STATE: 6377836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 6387836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 6397836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 6407836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 6417836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 6427836SJohn.Forte@Sun.COM ret = EINVAL; 6437836SJohn.Forte@Sun.COM break; 6447836SJohn.Forte@Sun.COM } 6457836SJohn.Forte@Sun.COM p_id = std->ident; 6467836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6477836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 6487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6497836SJohn.Forte@Sun.COM ret = EBUSY; 6507836SJohn.Forte@Sun.COM break; 6517836SJohn.Forte@Sun.COM } 6527836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu; ilu = ilu->ilu_next) { 6537836SJohn.Forte@Sun.COM if (bcmp(p_id, ilu->ilu_lu->lu_id->ident, 16) == 0) 6547836SJohn.Forte@Sun.COM break; 6557836SJohn.Forte@Sun.COM } 6567836SJohn.Forte@Sun.COM if (ilu == NULL) { 6577836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6587836SJohn.Forte@Sun.COM ret = ENOENT; 6597836SJohn.Forte@Sun.COM break; 6607836SJohn.Forte@Sun.COM } 6617836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 6627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6637836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? STMF_CMD_LU_ONLINE : 6647836SJohn.Forte@Sun.COM STMF_CMD_LU_OFFLINE; 6657836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilu->ilu_lu, &ssi); 6667836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 6677836SJohn.Forte@Sun.COM ret = 0; 6687836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 6697836SJohn.Forte@Sun.COM ret = EIO; 6707836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6717836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 6727836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6737836SJohn.Forte@Sun.COM break; 6747836SJohn.Forte@Sun.COM 6757836SJohn.Forte@Sun.COM case STMF_IOCTL_SET_TARGET_PORT_STATE: 6767836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 6777836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 6787836SJohn.Forte@Sun.COM std = (stmf_state_desc_t *)ibuf; 6797836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 6807836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_state_desc_t))) { 6817836SJohn.Forte@Sun.COM ret = EINVAL; 6827836SJohn.Forte@Sun.COM break; 6837836SJohn.Forte@Sun.COM } 6847836SJohn.Forte@Sun.COM p_id = std->ident; 6857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 6867836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 6877836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 6887836SJohn.Forte@Sun.COM ret = EBUSY; 6897836SJohn.Forte@Sun.COM break; 6907836SJohn.Forte@Sun.COM } 6917836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 6927836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 6937836SJohn.Forte@Sun.COM uint8_t *id; 6947836SJohn.Forte@Sun.COM id = (uint8_t *)ilport->ilport_lport->lport_id; 6957836SJohn.Forte@Sun.COM if ((id[3] == p_id[3]) && 6967836SJohn.Forte@Sun.COM (bcmp(id+4, p_id+4, id[3]) == 0)) { 6977836SJohn.Forte@Sun.COM break; 6987836SJohn.Forte@Sun.COM } 6997836SJohn.Forte@Sun.COM } 7007836SJohn.Forte@Sun.COM if (ilport == NULL) { 7017836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7027836SJohn.Forte@Sun.COM ret = ENOENT; 7037836SJohn.Forte@Sun.COM break; 7047836SJohn.Forte@Sun.COM } 7057836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 7067836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7077836SJohn.Forte@Sun.COM cmd = (std->state == STMF_STATE_ONLINE) ? 7087836SJohn.Forte@Sun.COM STMF_CMD_LPORT_ONLINE : STMF_CMD_LPORT_OFFLINE; 7097836SJohn.Forte@Sun.COM ctl_ret = stmf_ctl(cmd, (void *)ilport->ilport_lport, &ssi); 7107836SJohn.Forte@Sun.COM if (ctl_ret == STMF_ALREADY) 7117836SJohn.Forte@Sun.COM ret = 0; 7127836SJohn.Forte@Sun.COM else if (ctl_ret != STMF_SUCCESS) 7137836SJohn.Forte@Sun.COM ret = EIO; 7147836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7157836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 7167836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7177836SJohn.Forte@Sun.COM break; 7187836SJohn.Forte@Sun.COM 7197836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_HG_ENTRY: 7207836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 7217836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 7227836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TG_ENTRY: 7237836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 7247836SJohn.Forte@Sun.COM ret = EACCES; 7257836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 7267836SJohn.Forte@Sun.COM break; 7277836SJohn.Forte@Sun.COM } 7287836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_ADD_TG_ENTRY) { 7297836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 7307836SJohn.Forte@Sun.COM } 7317836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 7327836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7337836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 7347836SJohn.Forte@Sun.COM ret = EINVAL; 7357836SJohn.Forte@Sun.COM break; 7367836SJohn.Forte@Sun.COM } 7377836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 7387836SJohn.Forte@Sun.COM ret = EINVAL; 7397836SJohn.Forte@Sun.COM break; /* not allowed */ 7407836SJohn.Forte@Sun.COM } 7417836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7427836SJohn.Forte@Sun.COM if (idtype == STMF_ID_TYPE_TARGET && 7437836SJohn.Forte@Sun.COM stmf_state.stmf_service_running) { 7447836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7457836SJohn.Forte@Sun.COM iocd->stmf_error = 7467836SJohn.Forte@Sun.COM STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE; 7477836SJohn.Forte@Sun.COM ret = EBUSY; 7487836SJohn.Forte@Sun.COM break; /* not allowed */ 7497836SJohn.Forte@Sun.COM } 7507836SJohn.Forte@Sun.COM ret = stmf_add_group_member(grp_entry->group.name, 7517836SJohn.Forte@Sun.COM grp_entry->group.name_size, 7527836SJohn.Forte@Sun.COM grp_entry->ident + 4, 7537836SJohn.Forte@Sun.COM grp_entry->ident[3], 7547836SJohn.Forte@Sun.COM idtype, 7557836SJohn.Forte@Sun.COM &iocd->stmf_error); 7567836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7577836SJohn.Forte@Sun.COM break; 7587836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HG_ENTRY: 7597836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST; 7607836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 7617836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TG_ENTRY: 7627836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 7637836SJohn.Forte@Sun.COM ret = EACCES; 7647836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 7657836SJohn.Forte@Sun.COM break; 7667836SJohn.Forte@Sun.COM } 7677836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TG_ENTRY) { 7687836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET; 7697836SJohn.Forte@Sun.COM } 7707836SJohn.Forte@Sun.COM grp_entry = (stmf_group_op_data_t *)ibuf; 7717836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 7727836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_op_data_t))) { 7737836SJohn.Forte@Sun.COM ret = EINVAL; 7747836SJohn.Forte@Sun.COM break; 7757836SJohn.Forte@Sun.COM } 7767836SJohn.Forte@Sun.COM if (grp_entry->group.name[0] == '*') { 7777836SJohn.Forte@Sun.COM ret = EINVAL; 7787836SJohn.Forte@Sun.COM break; /* not allowed */ 7797836SJohn.Forte@Sun.COM } 7807836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 7817836SJohn.Forte@Sun.COM if (idtype == STMF_ID_TYPE_TARGET && 7827836SJohn.Forte@Sun.COM stmf_state.stmf_service_running) { 7837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7847836SJohn.Forte@Sun.COM iocd->stmf_error = 7857836SJohn.Forte@Sun.COM STMF_IOCERR_TG_UPDATE_NEED_SVC_OFFLINE; 7867836SJohn.Forte@Sun.COM ret = EBUSY; 7877836SJohn.Forte@Sun.COM break; /* not allowed */ 7887836SJohn.Forte@Sun.COM } 7897836SJohn.Forte@Sun.COM ret = stmf_remove_group_member(grp_entry->group.name, 7907836SJohn.Forte@Sun.COM grp_entry->group.name_size, 7917836SJohn.Forte@Sun.COM grp_entry->ident + 4, 7927836SJohn.Forte@Sun.COM grp_entry->ident[3], 7937836SJohn.Forte@Sun.COM idtype, 7947836SJohn.Forte@Sun.COM &iocd->stmf_error); 7957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 7967836SJohn.Forte@Sun.COM break; 7977836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_HOST_GROUP: 7987836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 7997836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8007836SJohn.Forte@Sun.COM case STMF_IOCTL_CREATE_TARGET_GROUP: 8017836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8027836SJohn.Forte@Sun.COM ret = EACCES; 8037836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8047836SJohn.Forte@Sun.COM break; 8057836SJohn.Forte@Sun.COM } 8067836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8077836SJohn.Forte@Sun.COM 8087836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_CREATE_TARGET_GROUP) 8097836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8107836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8117836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8127836SJohn.Forte@Sun.COM ret = EINVAL; 8137836SJohn.Forte@Sun.COM break; 8147836SJohn.Forte@Sun.COM } 8157836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8167836SJohn.Forte@Sun.COM ret = EINVAL; 8177836SJohn.Forte@Sun.COM break; /* not allowed */ 8187836SJohn.Forte@Sun.COM } 8197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8207836SJohn.Forte@Sun.COM ret = stmf_add_group(grpname->name, 8217836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 8227836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8237836SJohn.Forte@Sun.COM break; 8247836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_HOST_GROUP: 8257836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_HOST_GROUP; 8267836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 8277836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_TARGET_GROUP: 8287836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8297836SJohn.Forte@Sun.COM ret = EACCES; 8307836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8317836SJohn.Forte@Sun.COM break; 8327836SJohn.Forte@Sun.COM } 8337836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 8347836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_REMOVE_TARGET_GROUP) 8357836SJohn.Forte@Sun.COM idtype = STMF_ID_TYPE_TARGET_GROUP; 8367836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8377836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 8387836SJohn.Forte@Sun.COM ret = EINVAL; 8397836SJohn.Forte@Sun.COM break; 8407836SJohn.Forte@Sun.COM } 8417836SJohn.Forte@Sun.COM if (grpname->name[0] == '*') { 8427836SJohn.Forte@Sun.COM ret = EINVAL; 8437836SJohn.Forte@Sun.COM break; /* not allowed */ 8447836SJohn.Forte@Sun.COM } 8457836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8467836SJohn.Forte@Sun.COM ret = stmf_remove_group(grpname->name, 8477836SJohn.Forte@Sun.COM grpname->name_size, idtype, &iocd->stmf_error); 8487836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8497836SJohn.Forte@Sun.COM break; 8507836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_VIEW_ENTRY: 8517836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 8527836SJohn.Forte@Sun.COM ret = EACCES; 8537836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 8547836SJohn.Forte@Sun.COM break; 8557836SJohn.Forte@Sun.COM } 8567836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 8577836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 8587836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 8597836SJohn.Forte@Sun.COM ret = EINVAL; 8607836SJohn.Forte@Sun.COM break; 8617836SJohn.Forte@Sun.COM } 8627836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) 8637836SJohn.Forte@Sun.COM ve->ve_lu_nbr[2] = 0xFF; 8647836SJohn.Forte@Sun.COM if (ve->ve_all_hosts) { 8657836SJohn.Forte@Sun.COM ve->ve_host_group.name[0] = '*'; 8667836SJohn.Forte@Sun.COM ve->ve_host_group.name_size = 1; 8677836SJohn.Forte@Sun.COM } 8687836SJohn.Forte@Sun.COM if (ve->ve_all_targets) { 8697836SJohn.Forte@Sun.COM ve->ve_target_group.name[0] = '*'; 8707836SJohn.Forte@Sun.COM ve->ve_target_group.name_size = 1; 8717836SJohn.Forte@Sun.COM } 8727836SJohn.Forte@Sun.COM if (ve->ve_ndx_valid) 8737836SJohn.Forte@Sun.COM veid = ve->ve_ndx; 8747836SJohn.Forte@Sun.COM else 8757836SJohn.Forte@Sun.COM veid = 0xffffffff; 8767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 8777836SJohn.Forte@Sun.COM ret = stmf_add_ve(ve->ve_host_group.name, 8787836SJohn.Forte@Sun.COM ve->ve_host_group.name_size, 8797836SJohn.Forte@Sun.COM ve->ve_target_group.name, 8807836SJohn.Forte@Sun.COM ve->ve_target_group.name_size, 8817836SJohn.Forte@Sun.COM ve->ve_guid, 8827836SJohn.Forte@Sun.COM &veid, 8837836SJohn.Forte@Sun.COM ve->ve_lu_nbr, 8847836SJohn.Forte@Sun.COM &iocd->stmf_error); 8857836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 8867836SJohn.Forte@Sun.COM if (ret == 0 && 8877836SJohn.Forte@Sun.COM (!ve->ve_ndx_valid || !ve->ve_lu_number_valid) && 8887836SJohn.Forte@Sun.COM iocd->stmf_obuf_size >= sizeof (stmf_view_op_entry_t)) { 8897836SJohn.Forte@Sun.COM stmf_view_op_entry_t *ve_ret = 8907836SJohn.Forte@Sun.COM (stmf_view_op_entry_t *)obuf; 8917836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = 1; 8927836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = 1; 8937836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 8947836SJohn.Forte@Sun.COM ve_ret->ve_ndx = veid; 8957836SJohn.Forte@Sun.COM ve_ret->ve_ndx_valid = 1; 8967836SJohn.Forte@Sun.COM } 8977836SJohn.Forte@Sun.COM if (!ve->ve_lu_number_valid) { 8987836SJohn.Forte@Sun.COM ve_ret->ve_lu_number_valid = 1; 8997836SJohn.Forte@Sun.COM bcopy(ve->ve_lu_nbr, ve_ret->ve_lu_nbr, 8); 9007836SJohn.Forte@Sun.COM } 9017836SJohn.Forte@Sun.COM } 9027836SJohn.Forte@Sun.COM break; 9037836SJohn.Forte@Sun.COM case STMF_IOCTL_REMOVE_VIEW_ENTRY: 9047836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 9057836SJohn.Forte@Sun.COM ret = EACCES; 9067836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 9077836SJohn.Forte@Sun.COM break; 9087836SJohn.Forte@Sun.COM } 9097836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)ibuf; 9107836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9117836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_view_op_entry_t))) { 9127836SJohn.Forte@Sun.COM ret = EINVAL; 9137836SJohn.Forte@Sun.COM break; 9147836SJohn.Forte@Sun.COM } 9157836SJohn.Forte@Sun.COM if (!ve->ve_ndx_valid) { 9167836SJohn.Forte@Sun.COM ret = EINVAL; 9177836SJohn.Forte@Sun.COM break; 9187836SJohn.Forte@Sun.COM } 9197836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9207836SJohn.Forte@Sun.COM ret = stmf_remove_ve_by_id(ve->ve_guid, ve->ve_ndx, 9217836SJohn.Forte@Sun.COM &iocd->stmf_error); 9227836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9237836SJohn.Forte@Sun.COM break; 9247836SJohn.Forte@Sun.COM #if 0 9257836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_LIST: 9267836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 9277836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9287836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_LIST: 9297836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_LIST) 9307836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 9317836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9327836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 9337836SJohn.Forte@Sun.COM n = min(id_list->id_count, 9347836SJohn.Forte@Sun.COM (iocd->stmf_obuf_size)/sizeof (stmf_group_name_t)); 9357836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 9367836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 9377836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)obuf; 9387836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 9397836SJohn.Forte@Sun.COM grpname[i].name_size = id_entry->id_data_size; 9407836SJohn.Forte@Sun.COM bcopy(id_entry->id_data, grpname[i].name, 9417836SJohn.Forte@Sun.COM id_entry->id_data_size); 9427836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 9437836SJohn.Forte@Sun.COM } 9447836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9457836SJohn.Forte@Sun.COM break; 9467836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_HG_ENTRIES: 9477836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_hg_list; 9487836SJohn.Forte@Sun.COM /* FALLTHROUGH */ 9497836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TG_ENTRIES: 9507836SJohn.Forte@Sun.COM grpname = (stmf_group_name_t *)ibuf; 9517836SJohn.Forte@Sun.COM if ((ibuf == NULL) || 9527836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_group_name_t))) { 9537836SJohn.Forte@Sun.COM ret = EINVAL; 9547836SJohn.Forte@Sun.COM break; 9557836SJohn.Forte@Sun.COM } 9567836SJohn.Forte@Sun.COM if (cmd == STMF_IOCTL_GET_TG_ENTRIES) { 9577836SJohn.Forte@Sun.COM id_list = &stmf_state.stmf_tg_list; 9587836SJohn.Forte@Sun.COM } 9597836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9607836SJohn.Forte@Sun.COM id_entry = stmf_lookup_id(id_list, grpname->name_size, 9617836SJohn.Forte@Sun.COM grpname->name); 9627836SJohn.Forte@Sun.COM if (!id_entry) 9637836SJohn.Forte@Sun.COM ret = ENODEV; 9647836SJohn.Forte@Sun.COM else { 9657836SJohn.Forte@Sun.COM stmf_ge_ident_t *grp_entry; 9667836SJohn.Forte@Sun.COM id_list = (stmf_id_list_t *)id_entry->id_impl_specific; 9677836SJohn.Forte@Sun.COM iocd->stmf_obuf_max_nentries = id_list->id_count; 9687836SJohn.Forte@Sun.COM n = min(id_list->id_count, 9697836SJohn.Forte@Sun.COM iocd->stmf_obuf_size/sizeof (stmf_ge_ident_t)); 9707836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries = n; 9717836SJohn.Forte@Sun.COM id_entry = id_list->idl_head; 9727836SJohn.Forte@Sun.COM grp_entry = (stmf_ge_ident_t *)obuf; 9737836SJohn.Forte@Sun.COM for (i = 0; i < n; i++) { 9747836SJohn.Forte@Sun.COM bcopy(id_entry->id_data, grp_entry, 9757836SJohn.Forte@Sun.COM id_entry->id_data_size); 9767836SJohn.Forte@Sun.COM id_entry = id_entry->id_next; 9777836SJohn.Forte@Sun.COM } 9787836SJohn.Forte@Sun.COM } 9797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 9807836SJohn.Forte@Sun.COM break; 9817836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_VE_LIST: 9827836SJohn.Forte@Sun.COM n = iocd->stmf_obuf_size/sizeof (stmf_view_op_entry_t); 9837836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 9847836SJohn.Forte@Sun.COM id_entry = stmf_state.stmf_luid_list.idl_head; 9857836SJohn.Forte@Sun.COM ve = (stmf_view_op_entry_t *)obuf; 9867836SJohn.Forte@Sun.COM while (id_entry) { 9877836SJohn.Forte@Sun.COM view_entry = 9887836SJohn.Forte@Sun.COM (stmf_view_entry_t *)id_entry->id_impl_specific; 9897836SJohn.Forte@Sun.COM for (; view_entry; view_entry = view_entry->ve_next) { 9907836SJohn.Forte@Sun.COM ve->ve_ndx_valid = 1; 9917836SJohn.Forte@Sun.COM ve->ve_ndx = view_entry->ve_id; 9927836SJohn.Forte@Sun.COM ve->ve_lu_number_valid = 1; 9937836SJohn.Forte@Sun.COM bcopy(view_entry->ve_lun, ve->ve_lu_nbr, 8); 9947836SJohn.Forte@Sun.COM bcopy(view_entry->ve_luid->id_data, ve->ve_guid, 9957836SJohn.Forte@Sun.COM view_entry->ve_luid->id_data_size); 9967836SJohn.Forte@Sun.COM if (view_entry->ve_hg->id_data[0] == '*') 9977836SJohn.Forte@Sun.COM ve->ve_all_hosts = 1; 9987836SJohn.Forte@Sun.COM else 9997836SJohn.Forte@Sun.COM bcopy(view_entry->ve_hg->id_data, 10007836SJohn.Forte@Sun.COM ve->ve_host_group.name, 10017836SJohn.Forte@Sun.COM view_entry->ve_hg->id_data_size); 10027836SJohn.Forte@Sun.COM if (view_entry->ve_tg->id_data[0] == '*') 10037836SJohn.Forte@Sun.COM ve->ve_all_targets = 1; 10047836SJohn.Forte@Sun.COM else 10057836SJohn.Forte@Sun.COM bcopy(view_entry->ve_tg->id_data, 10067836SJohn.Forte@Sun.COM ve->ve_target_group.name, 10077836SJohn.Forte@Sun.COM view_entry->ve_tg->id_data_size); 10087836SJohn.Forte@Sun.COM iocd->stmf_obuf_nentries++; 10097836SJohn.Forte@Sun.COM if (iocd->stmf_obuf_nentries >= n) 10107836SJohn.Forte@Sun.COM break; 10117836SJohn.Forte@Sun.COM } 10127836SJohn.Forte@Sun.COM if (iocd->stmf_obuf_nentries >= n) 10137836SJohn.Forte@Sun.COM break; 10147836SJohn.Forte@Sun.COM } 10157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 10167836SJohn.Forte@Sun.COM break; 10177836SJohn.Forte@Sun.COM #endif 10187836SJohn.Forte@Sun.COM case STMF_IOCTL_LOAD_PP_DATA: 10197836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 10207836SJohn.Forte@Sun.COM ret = EACCES; 10217836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 10227836SJohn.Forte@Sun.COM break; 10237836SJohn.Forte@Sun.COM } 10247836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 10257836SJohn.Forte@Sun.COM if ((ppi == NULL) || 10267836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 10277836SJohn.Forte@Sun.COM ret = EINVAL; 10287836SJohn.Forte@Sun.COM break; 10297836SJohn.Forte@Sun.COM } 10307836SJohn.Forte@Sun.COM ret = stmf_load_ppd_ioctl(ppi); 10317836SJohn.Forte@Sun.COM break; 10327836SJohn.Forte@Sun.COM 10337836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_PP_DATA: 10347836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_NONE) { 10357836SJohn.Forte@Sun.COM ret = EACCES; 10367836SJohn.Forte@Sun.COM iocd->stmf_error = STMF_IOCERR_UPDATE_NEED_CFG_INIT; 10377836SJohn.Forte@Sun.COM break; 10387836SJohn.Forte@Sun.COM } 10397836SJohn.Forte@Sun.COM ppi = (stmf_ppioctl_data_t *)ibuf; 10407836SJohn.Forte@Sun.COM if ((ppi == NULL) || 10417836SJohn.Forte@Sun.COM (iocd->stmf_ibuf_size < sizeof (stmf_ppioctl_data_t))) { 10427836SJohn.Forte@Sun.COM ret = EINVAL; 10437836SJohn.Forte@Sun.COM break; 10447836SJohn.Forte@Sun.COM } 10457836SJohn.Forte@Sun.COM ret = stmf_delete_ppd_ioctl(ppi); 10467836SJohn.Forte@Sun.COM break; 10477836SJohn.Forte@Sun.COM 10487836SJohn.Forte@Sun.COM case STMF_IOCTL_CLEAR_TRACE: 10497836SJohn.Forte@Sun.COM stmf_trace_clear(); 10507836SJohn.Forte@Sun.COM break; 10517836SJohn.Forte@Sun.COM 10527836SJohn.Forte@Sun.COM case STMF_IOCTL_ADD_TRACE: 10537836SJohn.Forte@Sun.COM if (iocd->stmf_ibuf_size && ibuf) { 10547836SJohn.Forte@Sun.COM ((uint8_t *)ibuf)[iocd->stmf_ibuf_size - 1] = 0; 10557836SJohn.Forte@Sun.COM stmf_trace("\nstradm", "%s\n", ibuf); 10567836SJohn.Forte@Sun.COM } 10577836SJohn.Forte@Sun.COM break; 10587836SJohn.Forte@Sun.COM 10597836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE_POSITION: 10607836SJohn.Forte@Sun.COM if (obuf && (iocd->stmf_obuf_size > 3)) { 10617836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 10627836SJohn.Forte@Sun.COM *((int *)obuf) = trace_buf_curndx; 10637836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 10647836SJohn.Forte@Sun.COM } else { 10657836SJohn.Forte@Sun.COM ret = EINVAL; 10667836SJohn.Forte@Sun.COM } 10677836SJohn.Forte@Sun.COM break; 10687836SJohn.Forte@Sun.COM 10697836SJohn.Forte@Sun.COM case STMF_IOCTL_GET_TRACE: 10707836SJohn.Forte@Sun.COM if ((iocd->stmf_obuf_size == 0) || (iocd->stmf_ibuf_size < 4)) { 10717836SJohn.Forte@Sun.COM ret = EINVAL; 10727836SJohn.Forte@Sun.COM break; 10737836SJohn.Forte@Sun.COM } 10747836SJohn.Forte@Sun.COM i = *((int *)ibuf); 10757836SJohn.Forte@Sun.COM if ((i > trace_buf_size) || ((i + iocd->stmf_obuf_size) > 10767836SJohn.Forte@Sun.COM trace_buf_size)) { 10777836SJohn.Forte@Sun.COM ret = EINVAL; 10787836SJohn.Forte@Sun.COM break; 10797836SJohn.Forte@Sun.COM } 10807836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 10817836SJohn.Forte@Sun.COM bcopy(stmf_trace_buf + i, obuf, iocd->stmf_obuf_size); 10827836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 10837836SJohn.Forte@Sun.COM break; 10847836SJohn.Forte@Sun.COM 10857836SJohn.Forte@Sun.COM default: 10867836SJohn.Forte@Sun.COM ret = ENOTTY; 10877836SJohn.Forte@Sun.COM } 10887836SJohn.Forte@Sun.COM 10897836SJohn.Forte@Sun.COM if (ret == 0) { 10907836SJohn.Forte@Sun.COM ret = stmf_copyout_iocdata(data, mode, iocd, obuf); 10917836SJohn.Forte@Sun.COM } else if (iocd->stmf_error) { 10927836SJohn.Forte@Sun.COM (void) stmf_copyout_iocdata(data, mode, iocd, obuf); 10937836SJohn.Forte@Sun.COM } 10947836SJohn.Forte@Sun.COM if (obuf) { 10957836SJohn.Forte@Sun.COM kmem_free(obuf, iocd->stmf_obuf_size); 10967836SJohn.Forte@Sun.COM obuf = NULL; 10977836SJohn.Forte@Sun.COM } 10987836SJohn.Forte@Sun.COM if (ibuf) { 10997836SJohn.Forte@Sun.COM kmem_free(ibuf, iocd->stmf_ibuf_size); 11007836SJohn.Forte@Sun.COM ibuf = NULL; 11017836SJohn.Forte@Sun.COM } 11027836SJohn.Forte@Sun.COM kmem_free(iocd, sizeof (stmf_iocdata_t)); 11037836SJohn.Forte@Sun.COM return (ret); 11047836SJohn.Forte@Sun.COM } 11057836SJohn.Forte@Sun.COM 11067836SJohn.Forte@Sun.COM static int 11077836SJohn.Forte@Sun.COM stmf_get_service_state() 11087836SJohn.Forte@Sun.COM { 11097836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 11107836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 11117836SJohn.Forte@Sun.COM int online = 0; 11127836SJohn.Forte@Sun.COM int offline = 0; 11137836SJohn.Forte@Sun.COM int onlining = 0; 11147836SJohn.Forte@Sun.COM int offlining = 0; 11157836SJohn.Forte@Sun.COM 11167836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 11177836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 11187836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 11197836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) 11207836SJohn.Forte@Sun.COM offline++; 11217836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINE) 11227836SJohn.Forte@Sun.COM online++; 11237836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_ONLINING) 11247836SJohn.Forte@Sun.COM onlining++; 11257836SJohn.Forte@Sun.COM else if (ilport->ilport_state == STMF_STATE_OFFLINING) 11267836SJohn.Forte@Sun.COM offlining++; 11277836SJohn.Forte@Sun.COM } 11287836SJohn.Forte@Sun.COM 11297836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 11307836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 11317836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) 11327836SJohn.Forte@Sun.COM offline++; 11337836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINE) 11347836SJohn.Forte@Sun.COM online++; 11357836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_ONLINING) 11367836SJohn.Forte@Sun.COM onlining++; 11377836SJohn.Forte@Sun.COM else if (ilu->ilu_state == STMF_STATE_OFFLINING) 11387836SJohn.Forte@Sun.COM offlining++; 11397836SJohn.Forte@Sun.COM } 11407836SJohn.Forte@Sun.COM 11417836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 11427836SJohn.Forte@Sun.COM if (onlining) 11437836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINING); 11447836SJohn.Forte@Sun.COM else 11457836SJohn.Forte@Sun.COM return (STMF_STATE_ONLINE); 11467836SJohn.Forte@Sun.COM } 11477836SJohn.Forte@Sun.COM 11487836SJohn.Forte@Sun.COM if (offlining) { 11497836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINING); 11507836SJohn.Forte@Sun.COM } 11517836SJohn.Forte@Sun.COM 11527836SJohn.Forte@Sun.COM return (STMF_STATE_OFFLINE); 11537836SJohn.Forte@Sun.COM } 11547836SJohn.Forte@Sun.COM 11557836SJohn.Forte@Sun.COM static int 11567836SJohn.Forte@Sun.COM stmf_set_stmf_state(stmf_state_desc_t *std) 11577836SJohn.Forte@Sun.COM { 11587836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 11597836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 11607836SJohn.Forte@Sun.COM stmf_state_change_info_t ssi; 11617836SJohn.Forte@Sun.COM int svc_state; 11627836SJohn.Forte@Sun.COM 11637836SJohn.Forte@Sun.COM ssi.st_rflags = STMF_RFLAG_USER_REQUEST; 11647836SJohn.Forte@Sun.COM ssi.st_additional_info = NULL; 11657836SJohn.Forte@Sun.COM 11667836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 11677836SJohn.Forte@Sun.COM if (!stmf_state.stmf_exclusive_open) { 11687836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11697836SJohn.Forte@Sun.COM return (EACCES); 11707836SJohn.Forte@Sun.COM } 11717836SJohn.Forte@Sun.COM 11727836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 11737836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11747836SJohn.Forte@Sun.COM return (EBUSY); 11757836SJohn.Forte@Sun.COM } 11767836SJohn.Forte@Sun.COM 11777836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_ONLINE) && 11787836SJohn.Forte@Sun.COM (std->state != STMF_STATE_OFFLINE)) { 11797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11807836SJohn.Forte@Sun.COM return (EINVAL); 11817836SJohn.Forte@Sun.COM } 11827836SJohn.Forte@Sun.COM 11837836SJohn.Forte@Sun.COM svc_state = stmf_get_service_state(); 11847836SJohn.Forte@Sun.COM if ((svc_state == STMF_STATE_OFFLINING) || 11857836SJohn.Forte@Sun.COM (svc_state == STMF_STATE_ONLINING)) { 11867836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11877836SJohn.Forte@Sun.COM return (EBUSY); 11887836SJohn.Forte@Sun.COM } 11897836SJohn.Forte@Sun.COM 11907836SJohn.Forte@Sun.COM if (svc_state == STMF_STATE_OFFLINE) { 11917836SJohn.Forte@Sun.COM if (std->config_state == STMF_CONFIG_INIT) { 11927836SJohn.Forte@Sun.COM if (std->state != STMF_STATE_OFFLINE) { 11937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 11947836SJohn.Forte@Sun.COM return (EINVAL); 11957836SJohn.Forte@Sun.COM } 11967836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT; 11977836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 11987836SJohn.Forte@Sun.COM stmf_view_clear_config(); 11997836SJohn.Forte@Sun.COM stmf_view_init(); 12007836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12017836SJohn.Forte@Sun.COM return (0); 12027836SJohn.Forte@Sun.COM } 12037836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 12047836SJohn.Forte@Sun.COM if (std->config_state != STMF_CONFIG_INIT_DONE) { 12057836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12067836SJohn.Forte@Sun.COM return (EINVAL); 12077836SJohn.Forte@Sun.COM } 12087836SJohn.Forte@Sun.COM stmf_state.stmf_config_state = STMF_CONFIG_INIT_DONE; 12097836SJohn.Forte@Sun.COM } 12107836SJohn.Forte@Sun.COM if (std->state == STMF_STATE_OFFLINE) { 12117836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12127836SJohn.Forte@Sun.COM return (0); 12137836SJohn.Forte@Sun.COM } 12147836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) { 12157836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12167836SJohn.Forte@Sun.COM return (EINVAL); 12177836SJohn.Forte@Sun.COM } 12187836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 12197836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 1; 12207836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12217836SJohn.Forte@Sun.COM 12227836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 12237836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 12247836SJohn.Forte@Sun.COM if (ilport->ilport_prev_state != STMF_STATE_ONLINE) 12257836SJohn.Forte@Sun.COM continue; 12267836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, 12277836SJohn.Forte@Sun.COM ilport->ilport_lport, &ssi); 12287836SJohn.Forte@Sun.COM } 12297836SJohn.Forte@Sun.COM 12307836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 12317836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 12327836SJohn.Forte@Sun.COM if (ilu->ilu_prev_state != STMF_STATE_ONLINE) 12337836SJohn.Forte@Sun.COM continue; 12347836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, ilu->ilu_lu, &ssi); 12357836SJohn.Forte@Sun.COM } 12367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 12377836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 12387836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12397836SJohn.Forte@Sun.COM return (0); 12407836SJohn.Forte@Sun.COM } 12417836SJohn.Forte@Sun.COM 12427836SJohn.Forte@Sun.COM /* svc_state is STMF_STATE_ONLINE here */ 12437836SJohn.Forte@Sun.COM if ((std->state != STMF_STATE_OFFLINE) || 12447836SJohn.Forte@Sun.COM (std->config_state == STMF_CONFIG_INIT)) { 12457836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12467836SJohn.Forte@Sun.COM return (EACCES); 12477836SJohn.Forte@Sun.COM } 12487836SJohn.Forte@Sun.COM 12497836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 1; 12507836SJohn.Forte@Sun.COM stmf_state.stmf_service_running = 0; 12517836SJohn.Forte@Sun.COM stmf_delete_all_ppds(); 12527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12537836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 12547836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 12557836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) 12567836SJohn.Forte@Sun.COM continue; 12577836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_OFFLINE, 12587836SJohn.Forte@Sun.COM ilport->ilport_lport, &ssi); 12597836SJohn.Forte@Sun.COM } 12607836SJohn.Forte@Sun.COM 12617836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; 12627836SJohn.Forte@Sun.COM ilu = ilu->ilu_next) { 12637836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) 12647836SJohn.Forte@Sun.COM continue; 12657836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_OFFLINE, ilu->ilu_lu, &ssi); 12667836SJohn.Forte@Sun.COM } 12677836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 12687836SJohn.Forte@Sun.COM stmf_state.stmf_inventory_locked = 0; 12697836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12707836SJohn.Forte@Sun.COM return (0); 12717836SJohn.Forte@Sun.COM } 12727836SJohn.Forte@Sun.COM 12737836SJohn.Forte@Sun.COM static int 12747836SJohn.Forte@Sun.COM stmf_get_stmf_state(stmf_state_desc_t *std) 12757836SJohn.Forte@Sun.COM { 12767836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 12777836SJohn.Forte@Sun.COM std->state = stmf_get_service_state(); 12787836SJohn.Forte@Sun.COM std->config_state = stmf_state.stmf_config_state; 12797836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 12807836SJohn.Forte@Sun.COM 12817836SJohn.Forte@Sun.COM return (0); 12827836SJohn.Forte@Sun.COM } 12837836SJohn.Forte@Sun.COM 12847836SJohn.Forte@Sun.COM typedef struct { 12857836SJohn.Forte@Sun.COM void *bp; /* back pointer from internal struct to main struct */ 12867836SJohn.Forte@Sun.COM int alloc_size; 12877836SJohn.Forte@Sun.COM } __istmf_t; 12887836SJohn.Forte@Sun.COM 12897836SJohn.Forte@Sun.COM typedef struct { 12907836SJohn.Forte@Sun.COM __istmf_t *fp; /* Framework private */ 12917836SJohn.Forte@Sun.COM void *cp; /* Caller private */ 12927836SJohn.Forte@Sun.COM void *ss; /* struct specific */ 12937836SJohn.Forte@Sun.COM } __stmf_t; 12947836SJohn.Forte@Sun.COM 12957836SJohn.Forte@Sun.COM static struct { 12967836SJohn.Forte@Sun.COM int shared; 12977836SJohn.Forte@Sun.COM int fw_private; 12987836SJohn.Forte@Sun.COM } stmf_sizes[] = { { 0, 0 }, 12997836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_provider_t), 13007836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_provider_t) }, 13017836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_port_provider_t), 13027836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_port_provider_t) }, 13037836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_local_port_t), 13047836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_local_port_t) }, 13057836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_lu_t), 13067836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_lu_t) }, 13077836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_scsi_session_t), 13087836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_session_t) }, 13097836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(scsi_task_t), 13107836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(stmf_i_scsi_task_t) }, 13117836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_data_buf_t), 13127836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) }, 13137836SJohn.Forte@Sun.COM { GET_STRUCT_SIZE(stmf_dbuf_store_t), 13147836SJohn.Forte@Sun.COM GET_STRUCT_SIZE(__istmf_t) } 13157836SJohn.Forte@Sun.COM 13167836SJohn.Forte@Sun.COM }; 13177836SJohn.Forte@Sun.COM 13187836SJohn.Forte@Sun.COM void * 13197836SJohn.Forte@Sun.COM stmf_alloc(stmf_struct_id_t struct_id, int additional_size, int flags) 13207836SJohn.Forte@Sun.COM { 13217836SJohn.Forte@Sun.COM int stmf_size; 13227836SJohn.Forte@Sun.COM int kmem_flag; 13237836SJohn.Forte@Sun.COM __stmf_t *sh; 13247836SJohn.Forte@Sun.COM 13257836SJohn.Forte@Sun.COM if ((struct_id == 0) || (struct_id >= STMF_MAX_STRUCT_IDS)) 13267836SJohn.Forte@Sun.COM return (NULL); 13277836SJohn.Forte@Sun.COM 13287836SJohn.Forte@Sun.COM if ((curthread->t_flag & T_INTR_THREAD) || (flags & AF_FORCE_NOSLEEP)) { 13297836SJohn.Forte@Sun.COM kmem_flag = KM_NOSLEEP; 13307836SJohn.Forte@Sun.COM } else { 13317836SJohn.Forte@Sun.COM kmem_flag = KM_SLEEP; 13327836SJohn.Forte@Sun.COM } 13337836SJohn.Forte@Sun.COM 13347836SJohn.Forte@Sun.COM additional_size = (additional_size + 7) & (~7); 13357836SJohn.Forte@Sun.COM stmf_size = stmf_sizes[struct_id].shared + 13367836SJohn.Forte@Sun.COM stmf_sizes[struct_id].fw_private + additional_size; 13377836SJohn.Forte@Sun.COM 13387836SJohn.Forte@Sun.COM sh = (__stmf_t *)kmem_zalloc(stmf_size, kmem_flag); 13397836SJohn.Forte@Sun.COM 13407836SJohn.Forte@Sun.COM if (sh == NULL) 13417836SJohn.Forte@Sun.COM return (NULL); 13427836SJohn.Forte@Sun.COM 13437836SJohn.Forte@Sun.COM sh->fp = (__istmf_t *)GET_BYTE_OFFSET(sh, stmf_sizes[struct_id].shared); 13447836SJohn.Forte@Sun.COM sh->cp = GET_BYTE_OFFSET(sh->fp, stmf_sizes[struct_id].fw_private); 13457836SJohn.Forte@Sun.COM 13467836SJohn.Forte@Sun.COM sh->fp->bp = sh; 13477836SJohn.Forte@Sun.COM /* Just store the total size instead of storing additional size */ 13487836SJohn.Forte@Sun.COM sh->fp->alloc_size = stmf_size; 13497836SJohn.Forte@Sun.COM 13507836SJohn.Forte@Sun.COM return (sh); 13517836SJohn.Forte@Sun.COM } 13527836SJohn.Forte@Sun.COM 13537836SJohn.Forte@Sun.COM void 13547836SJohn.Forte@Sun.COM stmf_free(void *ptr) 13557836SJohn.Forte@Sun.COM { 13567836SJohn.Forte@Sun.COM __stmf_t *sh = (__stmf_t *)ptr; 13577836SJohn.Forte@Sun.COM 13587836SJohn.Forte@Sun.COM /* 13597836SJohn.Forte@Sun.COM * So far we dont need any struct specific processing. If such 13607836SJohn.Forte@Sun.COM * a need ever arises, then store the struct id in the framework 13617836SJohn.Forte@Sun.COM * private section and get it here as sh->fp->struct_id. 13627836SJohn.Forte@Sun.COM */ 13637836SJohn.Forte@Sun.COM kmem_free(ptr, sh->fp->alloc_size); 13647836SJohn.Forte@Sun.COM } 13657836SJohn.Forte@Sun.COM 13667836SJohn.Forte@Sun.COM /* 13677836SJohn.Forte@Sun.COM * Given a pointer to stmf_lu_t, verifies if this lu is registered with the 13687836SJohn.Forte@Sun.COM * framework and returns a pointer to framework private data for the lu. 13697836SJohn.Forte@Sun.COM * Returns NULL if the lu was not found. 13707836SJohn.Forte@Sun.COM */ 13717836SJohn.Forte@Sun.COM stmf_i_lu_t * 13727836SJohn.Forte@Sun.COM stmf_lookup_lu(stmf_lu_t *lu) 13737836SJohn.Forte@Sun.COM { 13747836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 13757836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 13767836SJohn.Forte@Sun.COM 13777836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 13787836SJohn.Forte@Sun.COM if (ilu->ilu_lu == lu) 13797836SJohn.Forte@Sun.COM return (ilu); 13807836SJohn.Forte@Sun.COM } 13817836SJohn.Forte@Sun.COM return (NULL); 13827836SJohn.Forte@Sun.COM } 13837836SJohn.Forte@Sun.COM 13847836SJohn.Forte@Sun.COM /* 13857836SJohn.Forte@Sun.COM * Given a pointer to stmf_lu_t, verifies if this lu is registered with the 13867836SJohn.Forte@Sun.COM * framework and returns a pointer to framework private data for the lu. 13877836SJohn.Forte@Sun.COM * Returns NULL if the lu was not found. 13887836SJohn.Forte@Sun.COM */ 13897836SJohn.Forte@Sun.COM stmf_i_local_port_t * 13907836SJohn.Forte@Sun.COM stmf_lookup_lport(stmf_local_port_t *lport) 13917836SJohn.Forte@Sun.COM { 13927836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 13937836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 13947836SJohn.Forte@Sun.COM 13957836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 13967836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 13977836SJohn.Forte@Sun.COM if (ilport->ilport_lport == lport) 13987836SJohn.Forte@Sun.COM return (ilport); 13997836SJohn.Forte@Sun.COM } 14007836SJohn.Forte@Sun.COM return (NULL); 14017836SJohn.Forte@Sun.COM } 14027836SJohn.Forte@Sun.COM 14037836SJohn.Forte@Sun.COM stmf_status_t 14047836SJohn.Forte@Sun.COM stmf_register_lu_provider(stmf_lu_provider_t *lp) 14057836SJohn.Forte@Sun.COM { 14067836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 14077836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 14087836SJohn.Forte@Sun.COM uint32_t cb_flags; 14097836SJohn.Forte@Sun.COM 14107836SJohn.Forte@Sun.COM if (lp->lp_lpif_rev != LPIF_REV_1) 14117836SJohn.Forte@Sun.COM return (STMF_FAILURE); 14127836SJohn.Forte@Sun.COM 14137836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14147836SJohn.Forte@Sun.COM ilp->ilp_next = stmf_state.stmf_ilplist; 14157836SJohn.Forte@Sun.COM stmf_state.stmf_ilplist = ilp; 14167836SJohn.Forte@Sun.COM stmf_state.stmf_nlps++; 14177836SJohn.Forte@Sun.COM 14187836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 14197836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 14207836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, lp->lp_name) == 0) { 14217836SJohn.Forte@Sun.COM break; 14227836SJohn.Forte@Sun.COM } 14237836SJohn.Forte@Sun.COM } 14247836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 14257836SJohn.Forte@Sun.COM goto rlp_bail_out; 14267836SJohn.Forte@Sun.COM } 14277836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 14287836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 14297836SJohn.Forte@Sun.COM if (lp->lp_cb == NULL) 14307836SJohn.Forte@Sun.COM goto rlp_bail_out; 14317836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 14327836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 14337836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 14347836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 14357836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14367836SJohn.Forte@Sun.COM lp->lp_cb(lp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 14377836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14387836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 14397836SJohn.Forte@Sun.COM 14407836SJohn.Forte@Sun.COM rlp_bail_out: 14417836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14427836SJohn.Forte@Sun.COM 14437836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 14447836SJohn.Forte@Sun.COM } 14457836SJohn.Forte@Sun.COM 14467836SJohn.Forte@Sun.COM stmf_status_t 14477836SJohn.Forte@Sun.COM stmf_deregister_lu_provider(stmf_lu_provider_t *lp) 14487836SJohn.Forte@Sun.COM { 14497836SJohn.Forte@Sun.COM stmf_i_lu_provider_t **ppilp; 14507836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp = (stmf_i_lu_provider_t *)lp->lp_stmf_private; 14517836SJohn.Forte@Sun.COM 14527836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14537836SJohn.Forte@Sun.COM if (ilp->ilp_nlus || ilp->ilp_cb_in_progress) { 14547836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14557836SJohn.Forte@Sun.COM return (STMF_BUSY); 14567836SJohn.Forte@Sun.COM } 14577836SJohn.Forte@Sun.COM for (ppilp = &stmf_state.stmf_ilplist; *ppilp != NULL; 14587836SJohn.Forte@Sun.COM ppilp = &((*ppilp)->ilp_next)) { 14597836SJohn.Forte@Sun.COM if (*ppilp == ilp) { 14607836SJohn.Forte@Sun.COM *ppilp = ilp->ilp_next; 14617836SJohn.Forte@Sun.COM stmf_state.stmf_nlps--; 14627836SJohn.Forte@Sun.COM if (ilp->ilp_ppd) { 14637836SJohn.Forte@Sun.COM ilp->ilp_ppd->ppd_provider = NULL; 14647836SJohn.Forte@Sun.COM ilp->ilp_ppd = NULL; 14657836SJohn.Forte@Sun.COM } 14667836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14677836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 14687836SJohn.Forte@Sun.COM } 14697836SJohn.Forte@Sun.COM } 14707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 14717836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 14727836SJohn.Forte@Sun.COM } 14737836SJohn.Forte@Sun.COM 14747836SJohn.Forte@Sun.COM stmf_status_t 14757836SJohn.Forte@Sun.COM stmf_register_port_provider(stmf_port_provider_t *pp) 14767836SJohn.Forte@Sun.COM { 14777836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 14787836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 14797836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 14807836SJohn.Forte@Sun.COM uint32_t cb_flags; 14817836SJohn.Forte@Sun.COM 14827836SJohn.Forte@Sun.COM if (pp->pp_portif_rev != PORTIF_REV_1) 14837836SJohn.Forte@Sun.COM return (STMF_FAILURE); 14847836SJohn.Forte@Sun.COM 14857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 14867836SJohn.Forte@Sun.COM ipp->ipp_next = stmf_state.stmf_ipplist; 14877836SJohn.Forte@Sun.COM stmf_state.stmf_ipplist = ipp; 14887836SJohn.Forte@Sun.COM stmf_state.stmf_npps++; 14897836SJohn.Forte@Sun.COM /* See if we need to do a callback */ 14907836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 14917836SJohn.Forte@Sun.COM if (strcmp(ppd->ppd_name, pp->pp_name) == 0) { 14927836SJohn.Forte@Sun.COM break; 14937836SJohn.Forte@Sun.COM } 14947836SJohn.Forte@Sun.COM } 14957836SJohn.Forte@Sun.COM if ((ppd == NULL) || (ppd->ppd_nv == NULL)) { 14967836SJohn.Forte@Sun.COM goto rpp_bail_out; 14977836SJohn.Forte@Sun.COM } 14987836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 14997836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 15007836SJohn.Forte@Sun.COM if (pp->pp_cb == NULL) 15017836SJohn.Forte@Sun.COM goto rpp_bail_out; 15027836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 15037836SJohn.Forte@Sun.COM cb_flags = STMF_PCB_PREG_COMPLETE; 15047836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 15057836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 15067836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15077836SJohn.Forte@Sun.COM pp->pp_cb(pp, STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 15087836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15097836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 15107836SJohn.Forte@Sun.COM 15117836SJohn.Forte@Sun.COM rpp_bail_out: 15127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15137836SJohn.Forte@Sun.COM 15147836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 15157836SJohn.Forte@Sun.COM } 15167836SJohn.Forte@Sun.COM 15177836SJohn.Forte@Sun.COM stmf_status_t 15187836SJohn.Forte@Sun.COM stmf_deregister_port_provider(stmf_port_provider_t *pp) 15197836SJohn.Forte@Sun.COM { 15207836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp = 15217836SJohn.Forte@Sun.COM (stmf_i_port_provider_t *)pp->pp_stmf_private; 15227836SJohn.Forte@Sun.COM stmf_i_port_provider_t **ppipp; 15237836SJohn.Forte@Sun.COM 15247836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15257836SJohn.Forte@Sun.COM if (ipp->ipp_npps || ipp->ipp_cb_in_progress) { 15267836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15277836SJohn.Forte@Sun.COM return (STMF_BUSY); 15287836SJohn.Forte@Sun.COM } 15297836SJohn.Forte@Sun.COM for (ppipp = &stmf_state.stmf_ipplist; *ppipp != NULL; 15307836SJohn.Forte@Sun.COM ppipp = &((*ppipp)->ipp_next)) { 15317836SJohn.Forte@Sun.COM if (*ppipp == ipp) { 15327836SJohn.Forte@Sun.COM *ppipp = ipp->ipp_next; 15337836SJohn.Forte@Sun.COM stmf_state.stmf_npps--; 15347836SJohn.Forte@Sun.COM if (ipp->ipp_ppd) { 15357836SJohn.Forte@Sun.COM ipp->ipp_ppd->ppd_provider = NULL; 15367836SJohn.Forte@Sun.COM ipp->ipp_ppd = NULL; 15377836SJohn.Forte@Sun.COM } 15387836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15397836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 15407836SJohn.Forte@Sun.COM } 15417836SJohn.Forte@Sun.COM } 15427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15437836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 15447836SJohn.Forte@Sun.COM } 15457836SJohn.Forte@Sun.COM 15467836SJohn.Forte@Sun.COM int 15477836SJohn.Forte@Sun.COM stmf_load_ppd_ioctl(stmf_ppioctl_data_t *ppi) 15487836SJohn.Forte@Sun.COM { 15497836SJohn.Forte@Sun.COM stmf_i_port_provider_t *ipp; 15507836SJohn.Forte@Sun.COM stmf_i_lu_provider_t *ilp; 15517836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 15527836SJohn.Forte@Sun.COM nvlist_t *nv; 15537836SJohn.Forte@Sun.COM int s; 15547836SJohn.Forte@Sun.COM int ret; 15557836SJohn.Forte@Sun.COM 15567836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 15577836SJohn.Forte@Sun.COM return (EINVAL); 15587836SJohn.Forte@Sun.COM } 15597836SJohn.Forte@Sun.COM 15607836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 15617836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 15627836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 15637836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 15647836SJohn.Forte@Sun.COM continue; 15657836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 15667836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 15677836SJohn.Forte@Sun.COM continue; 15687836SJohn.Forte@Sun.COM } 15697836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 15707836SJohn.Forte@Sun.COM break; 15717836SJohn.Forte@Sun.COM } 15727836SJohn.Forte@Sun.COM 15737836SJohn.Forte@Sun.COM if (ppd == NULL) { 15747836SJohn.Forte@Sun.COM /* New provider */ 15757836SJohn.Forte@Sun.COM s = strlen(ppi->ppi_name); 15767836SJohn.Forte@Sun.COM if (s > 254) { 15777836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15787836SJohn.Forte@Sun.COM return (EINVAL); 15797836SJohn.Forte@Sun.COM } 15807836SJohn.Forte@Sun.COM s += sizeof (stmf_pp_data_t) - 7; 15817836SJohn.Forte@Sun.COM 15827836SJohn.Forte@Sun.COM ppd = kmem_zalloc(s, KM_NOSLEEP); 15837836SJohn.Forte@Sun.COM if (ppd == NULL) { 15847836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 15857836SJohn.Forte@Sun.COM return (ENOMEM); 15867836SJohn.Forte@Sun.COM } 15877836SJohn.Forte@Sun.COM ppd->ppd_alloc_size = s; 15887836SJohn.Forte@Sun.COM (void) strcpy(ppd->ppd_name, ppi->ppi_name); 15897836SJohn.Forte@Sun.COM 15907836SJohn.Forte@Sun.COM /* See if this provider already exists */ 15917836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 15927836SJohn.Forte@Sun.COM ppd->ppd_lu_provider = 1; 15937836SJohn.Forte@Sun.COM for (ilp = stmf_state.stmf_ilplist; ilp != NULL; 15947836SJohn.Forte@Sun.COM ilp = ilp->ilp_next) { 15957836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 15967836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_name) == 0) { 15977836SJohn.Forte@Sun.COM ppd->ppd_provider = ilp; 15987836SJohn.Forte@Sun.COM ilp->ilp_ppd = ppd; 15997836SJohn.Forte@Sun.COM break; 16007836SJohn.Forte@Sun.COM } 16017836SJohn.Forte@Sun.COM } 16027836SJohn.Forte@Sun.COM } else { 16037836SJohn.Forte@Sun.COM ppd->ppd_port_provider = 1; 16047836SJohn.Forte@Sun.COM for (ipp = stmf_state.stmf_ipplist; ipp != NULL; 16057836SJohn.Forte@Sun.COM ipp = ipp->ipp_next) { 16067836SJohn.Forte@Sun.COM if (strcmp(ppi->ppi_name, 16077836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_name) == 0) { 16087836SJohn.Forte@Sun.COM ppd->ppd_provider = ipp; 16097836SJohn.Forte@Sun.COM ipp->ipp_ppd = ppd; 16107836SJohn.Forte@Sun.COM break; 16117836SJohn.Forte@Sun.COM } 16127836SJohn.Forte@Sun.COM } 16137836SJohn.Forte@Sun.COM } 16147836SJohn.Forte@Sun.COM 16157836SJohn.Forte@Sun.COM /* Link this ppd in */ 16167836SJohn.Forte@Sun.COM ppd->ppd_next = stmf_state.stmf_ppdlist; 16177836SJohn.Forte@Sun.COM stmf_state.stmf_ppdlist = ppd; 16187836SJohn.Forte@Sun.COM } 16197836SJohn.Forte@Sun.COM 16207836SJohn.Forte@Sun.COM if ((ret = nvlist_unpack((char *)ppi->ppi_data, 16217836SJohn.Forte@Sun.COM (size_t)ppi->ppi_data_size, &nv, KM_NOSLEEP)) != 0) { 16227836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16237836SJohn.Forte@Sun.COM return (ret); 16247836SJohn.Forte@Sun.COM } 16257836SJohn.Forte@Sun.COM 16267836SJohn.Forte@Sun.COM /* Free any existing lists and add this one to the ppd */ 16277836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 16287836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 16297836SJohn.Forte@Sun.COM ppd->ppd_nv = nv; 16307836SJohn.Forte@Sun.COM 16317836SJohn.Forte@Sun.COM /* If there is a provider registered, do the notifications */ 16327836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 16337836SJohn.Forte@Sun.COM uint32_t cb_flags = 0; 16347836SJohn.Forte@Sun.COM 16357836SJohn.Forte@Sun.COM if (stmf_state.stmf_config_state == STMF_CONFIG_INIT) 16367836SJohn.Forte@Sun.COM cb_flags |= STMF_PCB_STMF_ONLINING; 16377836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 16387836SJohn.Forte@Sun.COM ilp = (stmf_i_lu_provider_t *)ppd->ppd_provider; 16397836SJohn.Forte@Sun.COM if (ilp->ilp_lp->lp_cb == NULL) 16407836SJohn.Forte@Sun.COM goto bail_out; 16417836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 1; 16427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16437836SJohn.Forte@Sun.COM ilp->ilp_lp->lp_cb(ilp->ilp_lp, 16447836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 16457836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16467836SJohn.Forte@Sun.COM ilp->ilp_cb_in_progress = 0; 16477836SJohn.Forte@Sun.COM } else { 16487836SJohn.Forte@Sun.COM ipp = (stmf_i_port_provider_t *)ppd->ppd_provider; 16497836SJohn.Forte@Sun.COM if (ipp->ipp_pp->pp_cb == NULL) 16507836SJohn.Forte@Sun.COM goto bail_out; 16517836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 1; 16527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16537836SJohn.Forte@Sun.COM ipp->ipp_pp->pp_cb(ipp->ipp_pp, 16547836SJohn.Forte@Sun.COM STMF_PROVIDER_DATA_UPDATED, ppd->ppd_nv, cb_flags); 16557836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 16567836SJohn.Forte@Sun.COM ipp->ipp_cb_in_progress = 0; 16577836SJohn.Forte@Sun.COM } 16587836SJohn.Forte@Sun.COM } 16597836SJohn.Forte@Sun.COM 16607836SJohn.Forte@Sun.COM bail_out: 16617836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 16627836SJohn.Forte@Sun.COM 16637836SJohn.Forte@Sun.COM return (0); 16647836SJohn.Forte@Sun.COM } 16657836SJohn.Forte@Sun.COM 16667836SJohn.Forte@Sun.COM void 16677836SJohn.Forte@Sun.COM stmf_delete_ppd(stmf_pp_data_t *ppd) 16687836SJohn.Forte@Sun.COM { 16697836SJohn.Forte@Sun.COM stmf_pp_data_t **pppd; 16707836SJohn.Forte@Sun.COM 16717836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 16727836SJohn.Forte@Sun.COM if (ppd->ppd_provider) { 16737836SJohn.Forte@Sun.COM if (ppd->ppd_lu_provider) { 16747836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 16757836SJohn.Forte@Sun.COM ppd->ppd_provider)->ilp_ppd = NULL; 16767836SJohn.Forte@Sun.COM } else { 16777836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 16787836SJohn.Forte@Sun.COM ppd->ppd_provider)->ipp_ppd = NULL; 16797836SJohn.Forte@Sun.COM } 16807836SJohn.Forte@Sun.COM ppd->ppd_provider = NULL; 16817836SJohn.Forte@Sun.COM } 16827836SJohn.Forte@Sun.COM 16837836SJohn.Forte@Sun.COM for (pppd = &stmf_state.stmf_ppdlist; *pppd != NULL; 16847836SJohn.Forte@Sun.COM pppd = &((*pppd)->ppd_next)) { 16857836SJohn.Forte@Sun.COM if (*pppd == ppd) 16867836SJohn.Forte@Sun.COM break; 16877836SJohn.Forte@Sun.COM } 16887836SJohn.Forte@Sun.COM 16897836SJohn.Forte@Sun.COM if (*pppd == NULL) 16907836SJohn.Forte@Sun.COM return; 16917836SJohn.Forte@Sun.COM 16927836SJohn.Forte@Sun.COM *pppd = ppd->ppd_next; 16937836SJohn.Forte@Sun.COM if (ppd->ppd_nv) 16947836SJohn.Forte@Sun.COM nvlist_free(ppd->ppd_nv); 16957836SJohn.Forte@Sun.COM 16967836SJohn.Forte@Sun.COM kmem_free(ppd, ppd->ppd_alloc_size); 16977836SJohn.Forte@Sun.COM } 16987836SJohn.Forte@Sun.COM 16997836SJohn.Forte@Sun.COM int 17007836SJohn.Forte@Sun.COM stmf_delete_ppd_ioctl(stmf_ppioctl_data_t *ppi) 17017836SJohn.Forte@Sun.COM { 17027836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd; 17037836SJohn.Forte@Sun.COM int ret = ENOENT; 17047836SJohn.Forte@Sun.COM 17057836SJohn.Forte@Sun.COM if ((ppi->ppi_lu_provider + ppi->ppi_port_provider) != 1) { 17067836SJohn.Forte@Sun.COM return (EINVAL); 17077836SJohn.Forte@Sun.COM } 17087836SJohn.Forte@Sun.COM 17097836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 17107836SJohn.Forte@Sun.COM 17117836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = ppd->ppd_next) { 17127836SJohn.Forte@Sun.COM if (ppi->ppi_lu_provider) { 17137836SJohn.Forte@Sun.COM if (!ppd->ppd_lu_provider) 17147836SJohn.Forte@Sun.COM continue; 17157836SJohn.Forte@Sun.COM } else if (ppi->ppi_port_provider) { 17167836SJohn.Forte@Sun.COM if (!ppd->ppd_port_provider) 17177836SJohn.Forte@Sun.COM continue; 17187836SJohn.Forte@Sun.COM } 17197836SJohn.Forte@Sun.COM if (strncmp(ppi->ppi_name, ppd->ppd_name, 254) == 0) 17207836SJohn.Forte@Sun.COM break; 17217836SJohn.Forte@Sun.COM } 17227836SJohn.Forte@Sun.COM 17237836SJohn.Forte@Sun.COM if (ppd) { 17247836SJohn.Forte@Sun.COM ret = 0; 17257836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 17267836SJohn.Forte@Sun.COM } 17277836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17287836SJohn.Forte@Sun.COM 17297836SJohn.Forte@Sun.COM return (ret); 17307836SJohn.Forte@Sun.COM } 17317836SJohn.Forte@Sun.COM 17327836SJohn.Forte@Sun.COM void 17337836SJohn.Forte@Sun.COM stmf_delete_all_ppds() 17347836SJohn.Forte@Sun.COM { 17357836SJohn.Forte@Sun.COM stmf_pp_data_t *ppd, *nppd; 17367836SJohn.Forte@Sun.COM 17377836SJohn.Forte@Sun.COM ASSERT(mutex_owned(&stmf_state.stmf_lock)); 17387836SJohn.Forte@Sun.COM for (ppd = stmf_state.stmf_ppdlist; ppd != NULL; ppd = nppd) { 17397836SJohn.Forte@Sun.COM nppd = ppd->ppd_next; 17407836SJohn.Forte@Sun.COM stmf_delete_ppd(ppd); 17417836SJohn.Forte@Sun.COM } 17427836SJohn.Forte@Sun.COM } 17437836SJohn.Forte@Sun.COM 17447836SJohn.Forte@Sun.COM stmf_status_t 17457836SJohn.Forte@Sun.COM stmf_register_lu(stmf_lu_t *lu) 17467836SJohn.Forte@Sun.COM { 17477836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 17487836SJohn.Forte@Sun.COM uint8_t *p1, *p2; 17497836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 17507836SJohn.Forte@Sun.COM stmf_id_data_t *luid; 17517836SJohn.Forte@Sun.COM 17527836SJohn.Forte@Sun.COM if ((lu->lu_id->ident_type != ID_TYPE_NAA) || 17537836SJohn.Forte@Sun.COM (lu->lu_id->ident_length != 16) || 17547836SJohn.Forte@Sun.COM ((lu->lu_id->ident[0] & 0xf0) != 0x60)) { 17557836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 17567836SJohn.Forte@Sun.COM } 17577836SJohn.Forte@Sun.COM p1 = &lu->lu_id->ident[0]; 17587836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 17597836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 17607836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17617836SJohn.Forte@Sun.COM return (STMF_BUSY); 17627836SJohn.Forte@Sun.COM } 17637836SJohn.Forte@Sun.COM 17647836SJohn.Forte@Sun.COM for (ilu = stmf_state.stmf_ilulist; ilu != NULL; ilu = ilu->ilu_next) { 17657836SJohn.Forte@Sun.COM p2 = &ilu->ilu_lu->lu_id->ident[0]; 17667836SJohn.Forte@Sun.COM if (bcmp(p1, p2, 16) == 0) { 17677836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17687836SJohn.Forte@Sun.COM return (STMF_ALREADY); 17697836SJohn.Forte@Sun.COM } 17707836SJohn.Forte@Sun.COM } 17717836SJohn.Forte@Sun.COM 17727836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 17737836SJohn.Forte@Sun.COM luid = stmf_lookup_id(&stmf_state.stmf_luid_list, 17747836SJohn.Forte@Sun.COM lu->lu_id->ident_length, lu->lu_id->ident); 17757836SJohn.Forte@Sun.COM if (luid) { 17767836SJohn.Forte@Sun.COM luid->id_pt_to_object = (void *)ilu; 17777836SJohn.Forte@Sun.COM ilu->ilu_luid = luid; 17787836SJohn.Forte@Sun.COM } 17797836SJohn.Forte@Sun.COM ilu->ilu_alias = NULL; 17807836SJohn.Forte@Sun.COM 17817836SJohn.Forte@Sun.COM ilu->ilu_next = stmf_state.stmf_ilulist; 17827836SJohn.Forte@Sun.COM ilu->ilu_prev = NULL; 17837836SJohn.Forte@Sun.COM if (ilu->ilu_next) 17847836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu; 17857836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu; 17867836SJohn.Forte@Sun.COM stmf_state.stmf_nlus++; 17877836SJohn.Forte@Sun.COM if (lu->lu_lp) { 17887836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 17897836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus++; 17907836SJohn.Forte@Sun.COM } 17917836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 17927836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl); 17937836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 17947836SJohn.Forte@Sun.COM 17957836SJohn.Forte@Sun.COM /* XXX we should probably check if this lu can be brought online */ 17967836SJohn.Forte@Sun.COM ilu->ilu_prev_state = STMF_STATE_ONLINE; 17977836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 17987836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 17997836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 18007836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LU_ONLINE, lu, &ssci); 18017836SJohn.Forte@Sun.COM } 18027836SJohn.Forte@Sun.COM 18037836SJohn.Forte@Sun.COM /* XXX: Generate event */ 18047836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 18057836SJohn.Forte@Sun.COM } 18067836SJohn.Forte@Sun.COM 18077836SJohn.Forte@Sun.COM stmf_status_t 18087836SJohn.Forte@Sun.COM stmf_deregister_lu(stmf_lu_t *lu) 18097836SJohn.Forte@Sun.COM { 18107836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 18117836SJohn.Forte@Sun.COM 18127836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18137836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 18147836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18157836SJohn.Forte@Sun.COM return (STMF_BUSY); 18167836SJohn.Forte@Sun.COM } 18177836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu(lu); 18187836SJohn.Forte@Sun.COM if (ilu == NULL) { 18197836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18207836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 18217836SJohn.Forte@Sun.COM } 18227836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 18237836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 18247836SJohn.Forte@Sun.COM while (ilu->ilu_flags & ILU_STALL_DEREGISTER) { 18257836SJohn.Forte@Sun.COM cv_wait(&stmf_state.stmf_cv, &stmf_state.stmf_lock); 18267836SJohn.Forte@Sun.COM } 18277836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 18287836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 18297836SJohn.Forte@Sun.COM 18307836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 18317836SJohn.Forte@Sun.COM do { 18327836SJohn.Forte@Sun.COM itask = nitask; 18337836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 18347836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 18357836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 18367836SJohn.Forte@Sun.COM } while (nitask != NULL); 18377836SJohn.Forte@Sun.COM 18387836SJohn.Forte@Sun.COM ilu->ilu_tasks = ilu->ilu_free_tasks = NULL; 18397836SJohn.Forte@Sun.COM ilu->ilu_ntasks = ilu->ilu_ntasks_free = 0; 18407836SJohn.Forte@Sun.COM } 18417836SJohn.Forte@Sun.COM 18427836SJohn.Forte@Sun.COM if (ilu->ilu_next) 18437836SJohn.Forte@Sun.COM ilu->ilu_next->ilu_prev = ilu->ilu_prev; 18447836SJohn.Forte@Sun.COM if (ilu->ilu_prev) 18457836SJohn.Forte@Sun.COM ilu->ilu_prev->ilu_next = ilu->ilu_next; 18467836SJohn.Forte@Sun.COM else 18477836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist = ilu->ilu_next; 18487836SJohn.Forte@Sun.COM stmf_state.stmf_nlus--; 18497836SJohn.Forte@Sun.COM 18507836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_draining) { 18517836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 18527836SJohn.Forte@Sun.COM } 18537836SJohn.Forte@Sun.COM if (ilu == stmf_state.stmf_svc_ilu_timing) { 18547836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 18557836SJohn.Forte@Sun.COM } 18567836SJohn.Forte@Sun.COM if (lu->lu_lp) { 18577836SJohn.Forte@Sun.COM ((stmf_i_lu_provider_t *) 18587836SJohn.Forte@Sun.COM (lu->lu_lp->lp_stmf_private))->ilp_nlus--; 18597836SJohn.Forte@Sun.COM } 18607836SJohn.Forte@Sun.COM if (ilu->ilu_luid) { 18617836SJohn.Forte@Sun.COM ((stmf_id_data_t *)ilu->ilu_luid)->id_pt_to_object = 18627836SJohn.Forte@Sun.COM NULL; 18637836SJohn.Forte@Sun.COM ilu->ilu_luid = NULL; 18647836SJohn.Forte@Sun.COM } 18657836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilu->ilu_event_hdl); 18667836SJohn.Forte@Sun.COM } else { 18677836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18687836SJohn.Forte@Sun.COM return (STMF_BUSY); 18697836SJohn.Forte@Sun.COM } 18707836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18717836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 18727836SJohn.Forte@Sun.COM } 18737836SJohn.Forte@Sun.COM 18747836SJohn.Forte@Sun.COM stmf_status_t 18757836SJohn.Forte@Sun.COM stmf_register_local_port(stmf_local_port_t *lport) 18767836SJohn.Forte@Sun.COM { 18777836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 18787836SJohn.Forte@Sun.COM stmf_state_change_info_t ssci; 18797836SJohn.Forte@Sun.COM int start_workers = 0; 18807836SJohn.Forte@Sun.COM 18817836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 18827836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 18837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 18847836SJohn.Forte@Sun.COM return (STMF_BUSY); 18857836SJohn.Forte@Sun.COM } 18867836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 18877836SJohn.Forte@Sun.COM rw_init(&ilport->ilport_lock, NULL, RW_DRIVER, NULL); 18887836SJohn.Forte@Sun.COM 18897836SJohn.Forte@Sun.COM ilport->ilport_next = stmf_state.stmf_ilportlist; 18907836SJohn.Forte@Sun.COM ilport->ilport_prev = NULL; 18917836SJohn.Forte@Sun.COM if (ilport->ilport_next) 18927836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport; 18937836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport; 18947836SJohn.Forte@Sun.COM stmf_state.stmf_nlports++; 18957836SJohn.Forte@Sun.COM if (lport->lport_pp) { 18967836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 18977836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps++; 18987836SJohn.Forte@Sun.COM } 18997836SJohn.Forte@Sun.COM ilport->ilport_tg = 19007836SJohn.Forte@Sun.COM stmf_lookup_group_for_target(lport->lport_id->ident, 19017836SJohn.Forte@Sun.COM lport->lport_id->ident_length); 19027836SJohn.Forte@Sun.COM ilport->ilport_rtpid = atomic_add_16_nv(&stmf_rtpid_counter, 1); 19037836SJohn.Forte@Sun.COM STMF_EVENT_ALLOC_HANDLE(ilport->ilport_event_hdl); 19047836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) { 19057836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLING; 19067836SJohn.Forte@Sun.COM start_workers = 1; 19077836SJohn.Forte@Sun.COM } 19087836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19097836SJohn.Forte@Sun.COM 19107836SJohn.Forte@Sun.COM if (start_workers) 19117836SJohn.Forte@Sun.COM stmf_worker_init(); 19127836SJohn.Forte@Sun.COM 19137836SJohn.Forte@Sun.COM /* XXX we should probably check if this lport can be brought online */ 19147836SJohn.Forte@Sun.COM ilport->ilport_prev_state = STMF_STATE_ONLINE; 19157836SJohn.Forte@Sun.COM if (stmf_state.stmf_service_running) { 19167836SJohn.Forte@Sun.COM ssci.st_rflags = 0; 19177836SJohn.Forte@Sun.COM ssci.st_additional_info = NULL; 19187836SJohn.Forte@Sun.COM (void) stmf_ctl(STMF_CMD_LPORT_ONLINE, lport, &ssci); 19197836SJohn.Forte@Sun.COM } 19207836SJohn.Forte@Sun.COM 19217836SJohn.Forte@Sun.COM /* XXX: Generate event */ 19227836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 19237836SJohn.Forte@Sun.COM } 19247836SJohn.Forte@Sun.COM 19257836SJohn.Forte@Sun.COM stmf_status_t 19267836SJohn.Forte@Sun.COM stmf_deregister_local_port(stmf_local_port_t *lport) 19277836SJohn.Forte@Sun.COM { 19287836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 19297836SJohn.Forte@Sun.COM 19307836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 19317836SJohn.Forte@Sun.COM if (stmf_state.stmf_inventory_locked) { 19327836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19337836SJohn.Forte@Sun.COM return (STMF_BUSY); 19347836SJohn.Forte@Sun.COM } 19357836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *)lport->lport_stmf_private; 19367836SJohn.Forte@Sun.COM if (ilport->ilport_nsessions == 0) { 19377836SJohn.Forte@Sun.COM if (ilport->ilport_next) 19387836SJohn.Forte@Sun.COM ilport->ilport_next->ilport_prev = ilport->ilport_prev; 19397836SJohn.Forte@Sun.COM if (ilport->ilport_prev) 19407836SJohn.Forte@Sun.COM ilport->ilport_prev->ilport_next = ilport->ilport_next; 19417836SJohn.Forte@Sun.COM else 19427836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist = ilport->ilport_next; 19437836SJohn.Forte@Sun.COM rw_destroy(&ilport->ilport_lock); 19447836SJohn.Forte@Sun.COM stmf_state.stmf_nlports--; 19457836SJohn.Forte@Sun.COM if (lport->lport_pp) { 19467836SJohn.Forte@Sun.COM ((stmf_i_port_provider_t *) 19477836SJohn.Forte@Sun.COM (lport->lport_pp->pp_stmf_private))->ipp_npps--; 19487836SJohn.Forte@Sun.COM } 19497836SJohn.Forte@Sun.COM ilport->ilport_tg = NULL; 19507836SJohn.Forte@Sun.COM STMF_EVENT_FREE_HANDLE(ilport->ilport_event_hdl); 19517836SJohn.Forte@Sun.COM } else { 19527836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19537836SJohn.Forte@Sun.COM return (STMF_BUSY); 19547836SJohn.Forte@Sun.COM } 19557836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 19567836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 19577836SJohn.Forte@Sun.COM } 19587836SJohn.Forte@Sun.COM 19597836SJohn.Forte@Sun.COM /* 19607836SJohn.Forte@Sun.COM * Port provider has to make sure that register/deregister session and 19617836SJohn.Forte@Sun.COM * port are serialized calls. 19627836SJohn.Forte@Sun.COM */ 19637836SJohn.Forte@Sun.COM stmf_status_t 19647836SJohn.Forte@Sun.COM stmf_register_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 19657836SJohn.Forte@Sun.COM { 19667836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 19677836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 19687836SJohn.Forte@Sun.COM lport->lport_stmf_private; 19697836SJohn.Forte@Sun.COM uint8_t lun[8]; 19707836SJohn.Forte@Sun.COM 19717836SJohn.Forte@Sun.COM /* 19727836SJohn.Forte@Sun.COM * Port state has to be online to register a scsi session. It is 19737836SJohn.Forte@Sun.COM * possible that we started an offline operation and a new SCSI 19747836SJohn.Forte@Sun.COM * session started at the same time (in that case also we are going 19757836SJohn.Forte@Sun.COM * to fail the registeration). But any other state is simply 19767836SJohn.Forte@Sun.COM * a bad port provider implementation. 19777836SJohn.Forte@Sun.COM */ 19787836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 19797836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 19807836SJohn.Forte@Sun.COM stmf_trace(lport->lport_alias, "Port is trying to " 19817836SJohn.Forte@Sun.COM "register a session while the state is neither " 19827836SJohn.Forte@Sun.COM "online nor offlining"); 19837836SJohn.Forte@Sun.COM } 19847836SJohn.Forte@Sun.COM return (STMF_FAILURE); 19857836SJohn.Forte@Sun.COM } 19867836SJohn.Forte@Sun.COM bzero(lun, 8); 19877836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 19887836SJohn.Forte@Sun.COM iss->iss_flags |= ISS_BEING_CREATED; 19897836SJohn.Forte@Sun.COM 19907836SJohn.Forte@Sun.COM /* sessions use the ilport_lock. No separate lock is required */ 19917836SJohn.Forte@Sun.COM iss->iss_lockp = &ilport->ilport_lock; 19927836SJohn.Forte@Sun.COM (void) stmf_session_create_lun_map(ilport, iss); 19937836SJohn.Forte@Sun.COM 19947836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 19957836SJohn.Forte@Sun.COM ilport->ilport_nsessions++; 19967836SJohn.Forte@Sun.COM iss->iss_next = ilport->ilport_ss_list; 19977836SJohn.Forte@Sun.COM ilport->ilport_ss_list = iss; 19987836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 19997836SJohn.Forte@Sun.COM 20007836SJohn.Forte@Sun.COM iss->iss_creation_time = ddi_get_time(); 20017836SJohn.Forte@Sun.COM ss->ss_session_id = atomic_add_64_nv(&stmf_session_counter, 1); 20027836SJohn.Forte@Sun.COM iss->iss_flags &= ~ISS_BEING_CREATED; 20037836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 20047836SJohn.Forte@Sun.COM } 20057836SJohn.Forte@Sun.COM 20067836SJohn.Forte@Sun.COM void 20077836SJohn.Forte@Sun.COM stmf_deregister_scsi_session(stmf_local_port_t *lport, stmf_scsi_session_t *ss) 20087836SJohn.Forte@Sun.COM { 20097836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = (stmf_i_local_port_t *) 20107836SJohn.Forte@Sun.COM lport->lport_stmf_private; 20117836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss, **ppss; 20127836SJohn.Forte@Sun.COM int found = 0; 20137836SJohn.Forte@Sun.COM 20147836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 20157836SJohn.Forte@Sun.COM if (ss->ss_rport_alias) { 20167836SJohn.Forte@Sun.COM ss->ss_rport_alias = NULL; 20177836SJohn.Forte@Sun.COM } 20187836SJohn.Forte@Sun.COM 20197836SJohn.Forte@Sun.COM try_dereg_ss_again: 20207836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 20217836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 20227836SJohn.Forte@Sun.COM ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 20237836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_EVENT_ACTIVE) { 20247836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 20257836SJohn.Forte@Sun.COM delay(1); 20267836SJohn.Forte@Sun.COM goto try_dereg_ss_again; 20277836SJohn.Forte@Sun.COM } 20287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 20297836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 20307836SJohn.Forte@Sun.COM for (ppss = &ilport->ilport_ss_list; *ppss != NULL; 20317836SJohn.Forte@Sun.COM ppss = &((*ppss)->iss_next)) { 20327836SJohn.Forte@Sun.COM if (iss == (*ppss)) { 20337836SJohn.Forte@Sun.COM *ppss = (*ppss)->iss_next; 20347836SJohn.Forte@Sun.COM found = 1; 20357836SJohn.Forte@Sun.COM break; 20367836SJohn.Forte@Sun.COM } 20377836SJohn.Forte@Sun.COM } 20387836SJohn.Forte@Sun.COM if (!found) { 20397836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "Deregister session called for non existent" 20407836SJohn.Forte@Sun.COM " session"); 20417836SJohn.Forte@Sun.COM } 20427836SJohn.Forte@Sun.COM ilport->ilport_nsessions--; 20437836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 20447836SJohn.Forte@Sun.COM 20457836SJohn.Forte@Sun.COM (void) stmf_session_destroy_lun_map(ilport, iss); 20467836SJohn.Forte@Sun.COM } 20477836SJohn.Forte@Sun.COM 20487836SJohn.Forte@Sun.COM stmf_i_scsi_session_t * 20497836SJohn.Forte@Sun.COM stmf_session_id_to_issptr(uint64_t session_id, int stay_locked) 20507836SJohn.Forte@Sun.COM { 20517836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 20527836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 20537836SJohn.Forte@Sun.COM 20547836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 20557836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 20567836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 20577836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 20587836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 20597836SJohn.Forte@Sun.COM iss = iss->iss_next) { 20607836SJohn.Forte@Sun.COM if (iss->iss_ss->ss_session_id == session_id) { 20617836SJohn.Forte@Sun.COM if (!stay_locked) 20627836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 20637836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 20647836SJohn.Forte@Sun.COM return (iss); 20657836SJohn.Forte@Sun.COM } 20667836SJohn.Forte@Sun.COM } 20677836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 20687836SJohn.Forte@Sun.COM } 20697836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 20707836SJohn.Forte@Sun.COM return (NULL); 20717836SJohn.Forte@Sun.COM } 20727836SJohn.Forte@Sun.COM 20737836SJohn.Forte@Sun.COM void 20747836SJohn.Forte@Sun.COM stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl) 20757836SJohn.Forte@Sun.COM { 20767836SJohn.Forte@Sun.COM stmf_itl_data_t **itlpp; 20777836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 20787836SJohn.Forte@Sun.COM 20797836SJohn.Forte@Sun.COM ASSERT(itl->itl_flags & STMF_ITL_BEING_TERMINATED); 20807836SJohn.Forte@Sun.COM 20817836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 20827836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 20837836SJohn.Forte@Sun.COM for (itlpp = &ilu->ilu_itl_list; (*itlpp) != NULL; 20847836SJohn.Forte@Sun.COM itlpp = &(*itlpp)->itl_next) { 20857836SJohn.Forte@Sun.COM if ((*itlpp) == itl) 20867836SJohn.Forte@Sun.COM break; 20877836SJohn.Forte@Sun.COM } 20887836SJohn.Forte@Sun.COM ASSERT((*itlpp) != NULL); 20897836SJohn.Forte@Sun.COM *itlpp = itl->itl_next; 20907836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 20917836SJohn.Forte@Sun.COM lu->lu_abort(lu, STMF_LU_ITL_HANDLE_REMOVED, itl->itl_handle, 20927836SJohn.Forte@Sun.COM (uint32_t)itl->itl_hdlrm_reason); 20937836SJohn.Forte@Sun.COM kmem_free(itl, sizeof (*itl)); 20947836SJohn.Forte@Sun.COM } 20957836SJohn.Forte@Sun.COM 20967836SJohn.Forte@Sun.COM stmf_status_t 20977836SJohn.Forte@Sun.COM stmf_register_itl_handle(stmf_lu_t *lu, uint8_t *lun, 20987836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 20997836SJohn.Forte@Sun.COM { 21007836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 21017836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 21027836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 21037836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 21047836SJohn.Forte@Sun.COM uint16_t n; 21057836SJohn.Forte@Sun.COM 21067836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 21077836SJohn.Forte@Sun.COM if (ss == NULL) { 21087836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 21097836SJohn.Forte@Sun.COM if (iss == NULL) 21107836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 21117836SJohn.Forte@Sun.COM } else { 21127836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 21137836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 21147836SJohn.Forte@Sun.COM } 21157836SJohn.Forte@Sun.COM 21167836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 21177836SJohn.Forte@Sun.COM lun_map_ent = (stmf_lun_map_ent_t *) 21187836SJohn.Forte@Sun.COM stmf_get_ent_from_map(iss->iss_sm, n); 21197836SJohn.Forte@Sun.COM if ((lun_map_ent == NULL) || (lun_map_ent->ent_lu != lu)) { 21207836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 21217836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 21227836SJohn.Forte@Sun.COM } 21237836SJohn.Forte@Sun.COM if (lun_map_ent->ent_itl_datap != NULL) { 21247836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 21257836SJohn.Forte@Sun.COM return (STMF_ALREADY); 21267836SJohn.Forte@Sun.COM } 21277836SJohn.Forte@Sun.COM 21287836SJohn.Forte@Sun.COM itl = (stmf_itl_data_t *)kmem_zalloc(sizeof (*itl), KM_NOSLEEP); 21297836SJohn.Forte@Sun.COM if (itl == NULL) { 21307836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 21317836SJohn.Forte@Sun.COM return (STMF_ALLOC_FAILURE); 21327836SJohn.Forte@Sun.COM } 21337836SJohn.Forte@Sun.COM 21347836SJohn.Forte@Sun.COM itl->itl_counter = 1; 21357836SJohn.Forte@Sun.COM itl->itl_lun = n; 21367836SJohn.Forte@Sun.COM itl->itl_handle = itl_handle; 21377836SJohn.Forte@Sun.COM itl->itl_session = iss; 21387836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 21397836SJohn.Forte@Sun.COM itl->itl_next = ilu->ilu_itl_list; 21407836SJohn.Forte@Sun.COM ilu->ilu_itl_list = itl; 21417836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 21427836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap = itl; 21437836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 21447836SJohn.Forte@Sun.COM 21457836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 21467836SJohn.Forte@Sun.COM } 21477836SJohn.Forte@Sun.COM 21487836SJohn.Forte@Sun.COM void 21497836SJohn.Forte@Sun.COM stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl, uint8_t hdlrm_reason) 21507836SJohn.Forte@Sun.COM { 21517836SJohn.Forte@Sun.COM uint8_t old, new; 21527836SJohn.Forte@Sun.COM 21537836SJohn.Forte@Sun.COM do { 21547836SJohn.Forte@Sun.COM old = new = itl->itl_flags; 21557836SJohn.Forte@Sun.COM if (old & STMF_ITL_BEING_TERMINATED) 21567836SJohn.Forte@Sun.COM return; 21577836SJohn.Forte@Sun.COM new |= STMF_ITL_BEING_TERMINATED; 21587836SJohn.Forte@Sun.COM } while (atomic_cas_8(&itl->itl_flags, old, new) != old); 21597836SJohn.Forte@Sun.COM itl->itl_hdlrm_reason = hdlrm_reason; 21607836SJohn.Forte@Sun.COM 21617836SJohn.Forte@Sun.COM ASSERT(itl->itl_counter); 21627836SJohn.Forte@Sun.COM 21637836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itl->itl_counter, -1)) 21647836SJohn.Forte@Sun.COM return; 21657836SJohn.Forte@Sun.COM 21667836SJohn.Forte@Sun.COM drv_usecwait(10); 21677836SJohn.Forte@Sun.COM if (itl->itl_counter) 21687836SJohn.Forte@Sun.COM return; 21697836SJohn.Forte@Sun.COM 21707836SJohn.Forte@Sun.COM stmf_release_itl_handle(lu, itl); 21717836SJohn.Forte@Sun.COM } 21727836SJohn.Forte@Sun.COM 21737836SJohn.Forte@Sun.COM stmf_status_t 21747836SJohn.Forte@Sun.COM stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu) 21757836SJohn.Forte@Sun.COM { 21767836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 21777836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 21787836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 21797836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 21807836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 21817836SJohn.Forte@Sun.COM uint32_t nmaps, nu; 21827836SJohn.Forte@Sun.COM stmf_itl_data_t **itl_list; 21837836SJohn.Forte@Sun.COM int i; 21847836SJohn.Forte@Sun.COM 21857836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 21867836SJohn.Forte@Sun.COM 21877836SJohn.Forte@Sun.COM dereg_itl_start:; 21887836SJohn.Forte@Sun.COM nmaps = ilu->ilu_ref_cnt; 21897836SJohn.Forte@Sun.COM if (nmaps == 0) 21907836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 21917836SJohn.Forte@Sun.COM itl_list = (stmf_itl_data_t **)kmem_zalloc( 21927836SJohn.Forte@Sun.COM nmaps * sizeof (stmf_itl_data_t *), KM_SLEEP); 21937836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 21947836SJohn.Forte@Sun.COM if (nmaps != ilu->ilu_ref_cnt) { 21957836SJohn.Forte@Sun.COM /* Something changed, start all over */ 21967836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 21977836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 21987836SJohn.Forte@Sun.COM goto dereg_itl_start; 21997836SJohn.Forte@Sun.COM } 22007836SJohn.Forte@Sun.COM nu = 0; 22017836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport != NULL; 22027836SJohn.Forte@Sun.COM ilport = ilport->ilport_next) { 22037836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_WRITER); 22047836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss != NULL; 22057836SJohn.Forte@Sun.COM iss = iss->iss_next) { 22067836SJohn.Forte@Sun.COM lm = iss->iss_sm; 22077836SJohn.Forte@Sun.COM if (!lm) 22087836SJohn.Forte@Sun.COM continue; 22097836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 22107836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 22117836SJohn.Forte@Sun.COM continue; 22127836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 22137836SJohn.Forte@Sun.COM if ((ent->ent_lu == lu) && 22147836SJohn.Forte@Sun.COM (ent->ent_itl_datap)) { 22157836SJohn.Forte@Sun.COM itl_list[nu++] = ent->ent_itl_datap; 22167836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 22177836SJohn.Forte@Sun.COM if (nu == nmaps) { 22187836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 22197836SJohn.Forte@Sun.COM goto dai_scan_done; 22207836SJohn.Forte@Sun.COM } 22217836SJohn.Forte@Sun.COM } 22227836SJohn.Forte@Sun.COM } /* lun table for a session */ 22237836SJohn.Forte@Sun.COM } /* sessions */ 22247836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 22257836SJohn.Forte@Sun.COM } /* ports */ 22267836SJohn.Forte@Sun.COM 22277836SJohn.Forte@Sun.COM dai_scan_done: 22287836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 22297836SJohn.Forte@Sun.COM 22307836SJohn.Forte@Sun.COM for (i = 0; i < nu; i++) { 22317836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl_list[i], 22327836SJohn.Forte@Sun.COM STMF_ITL_REASON_DEREG_REQUEST); 22337836SJohn.Forte@Sun.COM } 22347836SJohn.Forte@Sun.COM kmem_free(itl_list, nmaps * sizeof (stmf_itl_data_t *)); 22357836SJohn.Forte@Sun.COM 22367836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22377836SJohn.Forte@Sun.COM } 22387836SJohn.Forte@Sun.COM 22397836SJohn.Forte@Sun.COM stmf_status_t 22407836SJohn.Forte@Sun.COM stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun, 22417836SJohn.Forte@Sun.COM stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle) 22427836SJohn.Forte@Sun.COM { 22437836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 22447836SJohn.Forte@Sun.COM stmf_itl_data_t *itl; 22457836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 22467836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 22477836SJohn.Forte@Sun.COM int i; 22487836SJohn.Forte@Sun.COM uint16_t n; 22497836SJohn.Forte@Sun.COM 22507836SJohn.Forte@Sun.COM if (ss == NULL) { 22517836SJohn.Forte@Sun.COM if (session_id == STMF_SESSION_ID_NONE) 22527836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 22537836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 22547836SJohn.Forte@Sun.COM if (iss == NULL) 22557836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 22567836SJohn.Forte@Sun.COM } else { 22577836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 22587836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 22597836SJohn.Forte@Sun.COM } 22607836SJohn.Forte@Sun.COM lm = iss->iss_sm; 22617836SJohn.Forte@Sun.COM if (lm == NULL) { 22627836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 22637836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 22647836SJohn.Forte@Sun.COM } 22657836SJohn.Forte@Sun.COM 22667836SJohn.Forte@Sun.COM if (lun) { 22677836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 22687836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 22697836SJohn.Forte@Sun.COM stmf_get_ent_from_map(iss->iss_sm, n); 22707836SJohn.Forte@Sun.COM } else { 22717836SJohn.Forte@Sun.COM if (itl_handle == NULL) { 22727836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 22737836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 22747836SJohn.Forte@Sun.COM } 22757836SJohn.Forte@Sun.COM ent = NULL; 22767836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 22777836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 22787836SJohn.Forte@Sun.COM continue; 22797836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 22807836SJohn.Forte@Sun.COM if (ent->ent_itl_datap && 22817836SJohn.Forte@Sun.COM (ent->ent_itl_datap->itl_handle == itl_handle)) { 22827836SJohn.Forte@Sun.COM break; 22837836SJohn.Forte@Sun.COM } 22847836SJohn.Forte@Sun.COM } 22857836SJohn.Forte@Sun.COM } 22867836SJohn.Forte@Sun.COM if ((ent == NULL) || (ent->ent_lu != lu) || 22877836SJohn.Forte@Sun.COM (ent->ent_itl_datap == NULL)) { 22887836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 22897836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 22907836SJohn.Forte@Sun.COM } 22917836SJohn.Forte@Sun.COM itl = ent->ent_itl_datap; 22927836SJohn.Forte@Sun.COM ent->ent_itl_datap = NULL; 22937836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 22947836SJohn.Forte@Sun.COM stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST); 22957836SJohn.Forte@Sun.COM 22967836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 22977836SJohn.Forte@Sun.COM } 22987836SJohn.Forte@Sun.COM 22997836SJohn.Forte@Sun.COM stmf_status_t 23007836SJohn.Forte@Sun.COM stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss, 23017836SJohn.Forte@Sun.COM uint64_t session_id, void **itl_handle_retp) 23027836SJohn.Forte@Sun.COM { 23037836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 23047836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *ent; 23057836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 23067836SJohn.Forte@Sun.COM stmf_status_t ret; 23077836SJohn.Forte@Sun.COM int i; 23087836SJohn.Forte@Sun.COM uint16_t n; 23097836SJohn.Forte@Sun.COM 23107836SJohn.Forte@Sun.COM if (ss == NULL) { 23117836SJohn.Forte@Sun.COM iss = stmf_session_id_to_issptr(session_id, 1); 23127836SJohn.Forte@Sun.COM if (iss == NULL) 23137836SJohn.Forte@Sun.COM return (STMF_NOT_FOUND); 23147836SJohn.Forte@Sun.COM } else { 23157836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 23167836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 23177836SJohn.Forte@Sun.COM } 23187836SJohn.Forte@Sun.COM 23197836SJohn.Forte@Sun.COM ent = NULL; 23207836SJohn.Forte@Sun.COM if (lun == NULL) { 23217836SJohn.Forte@Sun.COM lm = iss->iss_sm; 23227836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 23237836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 23247836SJohn.Forte@Sun.COM continue; 23257836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 23267836SJohn.Forte@Sun.COM if (ent->ent_lu == lu) 23277836SJohn.Forte@Sun.COM break; 23287836SJohn.Forte@Sun.COM } 23297836SJohn.Forte@Sun.COM } else { 23307836SJohn.Forte@Sun.COM n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 23317836SJohn.Forte@Sun.COM ent = (stmf_lun_map_ent_t *) 23327836SJohn.Forte@Sun.COM stmf_get_ent_from_map(iss->iss_sm, n); 23337836SJohn.Forte@Sun.COM if (lu && (ent->ent_lu != lu)) 23347836SJohn.Forte@Sun.COM ent = NULL; 23357836SJohn.Forte@Sun.COM } 23367836SJohn.Forte@Sun.COM if (ent && ent->ent_itl_datap) { 23377836SJohn.Forte@Sun.COM *itl_handle_retp = ent->ent_itl_datap->itl_handle; 23387836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 23397836SJohn.Forte@Sun.COM } else { 23407836SJohn.Forte@Sun.COM ret = STMF_NOT_FOUND; 23417836SJohn.Forte@Sun.COM } 23427836SJohn.Forte@Sun.COM 23437836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 23447836SJohn.Forte@Sun.COM return (ret); 23457836SJohn.Forte@Sun.COM } 23467836SJohn.Forte@Sun.COM 23477836SJohn.Forte@Sun.COM stmf_data_buf_t * 23487836SJohn.Forte@Sun.COM stmf_alloc_dbuf(scsi_task_t *task, uint32_t size, uint32_t *pminsize, 23497836SJohn.Forte@Sun.COM uint32_t flags) 23507836SJohn.Forte@Sun.COM { 23517836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 23527836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 23537836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 23547836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 23557836SJohn.Forte@Sun.COM uint8_t ndx; 23567836SJohn.Forte@Sun.COM 23577836SJohn.Forte@Sun.COM ndx = stmf_first_zero[itask->itask_allocated_buf_map]; 23587836SJohn.Forte@Sun.COM if (ndx == 0xff) 23597836SJohn.Forte@Sun.COM return (NULL); 23607836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ndx] = lport->lport_ds->ds_alloc_data_buf( 23617836SJohn.Forte@Sun.COM task, size, pminsize, flags); 23627836SJohn.Forte@Sun.COM if (dbuf) { 23637836SJohn.Forte@Sun.COM task->task_cur_nbufs++; 23647836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map |= (1 << ndx); 23657836SJohn.Forte@Sun.COM dbuf->db_handle = ndx; 23667836SJohn.Forte@Sun.COM return (dbuf); 23677836SJohn.Forte@Sun.COM } 23687836SJohn.Forte@Sun.COM 23697836SJohn.Forte@Sun.COM return (NULL); 23707836SJohn.Forte@Sun.COM } 23717836SJohn.Forte@Sun.COM 23727836SJohn.Forte@Sun.COM void 23737836SJohn.Forte@Sun.COM stmf_free_dbuf(scsi_task_t *task, stmf_data_buf_t *dbuf) 23747836SJohn.Forte@Sun.COM { 23757836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 23767836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 23777836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 23787836SJohn.Forte@Sun.COM 23797836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map &= ~(1 << dbuf->db_handle); 23807836SJohn.Forte@Sun.COM task->task_cur_nbufs--; 23817836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf(lport->lport_ds, dbuf); 23827836SJohn.Forte@Sun.COM } 23837836SJohn.Forte@Sun.COM 23847836SJohn.Forte@Sun.COM stmf_data_buf_t * 23857836SJohn.Forte@Sun.COM stmf_handle_to_buf(scsi_task_t *task, uint8_t h) 23867836SJohn.Forte@Sun.COM { 23877836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 23887836SJohn.Forte@Sun.COM 23897836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 23907836SJohn.Forte@Sun.COM if (h > 3) 23917836SJohn.Forte@Sun.COM return (NULL); 23927836SJohn.Forte@Sun.COM return (itask->itask_dbufs[h]); 23937836SJohn.Forte@Sun.COM } 23947836SJohn.Forte@Sun.COM 23957836SJohn.Forte@Sun.COM /* ARGSUSED */ 23967836SJohn.Forte@Sun.COM struct scsi_task * 23977836SJohn.Forte@Sun.COM stmf_task_alloc(struct stmf_local_port *lport, stmf_scsi_session_t *ss, 23987836SJohn.Forte@Sun.COM uint8_t *lun, uint16_t cdb_length_in, uint16_t ext_id) 23997836SJohn.Forte@Sun.COM { 24007836SJohn.Forte@Sun.COM stmf_lu_t *lu; 24017836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 24027836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 24037836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 24047836SJohn.Forte@Sun.COM stmf_i_scsi_task_t **ppitask; 24057836SJohn.Forte@Sun.COM scsi_task_t *task; 24067836SJohn.Forte@Sun.COM uint64_t *p; 24077836SJohn.Forte@Sun.COM uint8_t *l; 24087836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lun_map_ent; 24097836SJohn.Forte@Sun.COM uint16_t cdb_length; 24107836SJohn.Forte@Sun.COM uint16_t luNbr; 24117836SJohn.Forte@Sun.COM uint8_t new_task = 0; 24127836SJohn.Forte@Sun.COM 24137836SJohn.Forte@Sun.COM /* 24147836SJohn.Forte@Sun.COM * We allocate 7 extra bytes for CDB to provide a cdb pointer which 24157836SJohn.Forte@Sun.COM * is guaranteed to be 8 byte aligned. Some LU providers like OSD 24167836SJohn.Forte@Sun.COM * depend upon this alignment. 24177836SJohn.Forte@Sun.COM */ 24187836SJohn.Forte@Sun.COM if (cdb_length_in >= 16) 24197836SJohn.Forte@Sun.COM cdb_length = cdb_length_in + 7; 24207836SJohn.Forte@Sun.COM else 24217836SJohn.Forte@Sun.COM cdb_length = 16 + 7; 24227836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private; 24237836SJohn.Forte@Sun.COM luNbr = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8)); 24247836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 24257836SJohn.Forte@Sun.COM lun_map_ent = 24267836SJohn.Forte@Sun.COM (stmf_lun_map_ent_t *)stmf_get_ent_from_map(iss->iss_sm, luNbr); 24277836SJohn.Forte@Sun.COM if (!lun_map_ent) { 24287836SJohn.Forte@Sun.COM lu = dlun0; 24297836SJohn.Forte@Sun.COM } else { 24307836SJohn.Forte@Sun.COM lu = lun_map_ent->ent_lu; 24317836SJohn.Forte@Sun.COM } 24327836SJohn.Forte@Sun.COM ilu = lu->lu_stmf_private; 24337836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 24347836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 24357836SJohn.Forte@Sun.COM return (NULL); 24367836SJohn.Forte@Sun.COM } 24377836SJohn.Forte@Sun.COM do { 24387836SJohn.Forte@Sun.COM if (ilu->ilu_free_tasks == NULL) { 24397836SJohn.Forte@Sun.COM new_task = 1; 24407836SJohn.Forte@Sun.COM break; 24417836SJohn.Forte@Sun.COM } 24427836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 24437836SJohn.Forte@Sun.COM for (ppitask = &ilu->ilu_free_tasks; (*ppitask != NULL) && 24447836SJohn.Forte@Sun.COM ((*ppitask)->itask_cdb_buf_size < cdb_length); 24457836SJohn.Forte@Sun.COM ppitask = &((*ppitask)->itask_lu_free_next)); 24467836SJohn.Forte@Sun.COM if (*ppitask) { 24477836SJohn.Forte@Sun.COM itask = *ppitask; 24487836SJohn.Forte@Sun.COM *ppitask = (*ppitask)->itask_lu_free_next; 24497836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 24507836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks_free < ilu->ilu_ntasks_min_free) 24517836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 24527836SJohn.Forte@Sun.COM } else { 24537836SJohn.Forte@Sun.COM new_task = 1; 24547836SJohn.Forte@Sun.COM } 24557836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 24567836SJohn.Forte@Sun.COM /* CONSTCOND */ 24577836SJohn.Forte@Sun.COM } while (0); 24587836SJohn.Forte@Sun.COM 24597836SJohn.Forte@Sun.COM if (!new_task) { 24607836SJohn.Forte@Sun.COM task = itask->itask_task; 24617836SJohn.Forte@Sun.COM task->task_timeout = 0; 24627836SJohn.Forte@Sun.COM p = (uint64_t *)&task->task_flags; 24637836SJohn.Forte@Sun.COM *p++ = 0; *p++ = 0; p++; p++; *p++ = 0; *p++ = 0; *p = 0; 24647836SJohn.Forte@Sun.COM itask->itask_ncmds = 0; 24657836SJohn.Forte@Sun.COM } else { 24667836SJohn.Forte@Sun.COM task = (scsi_task_t *)stmf_alloc(STMF_STRUCT_SCSI_TASK, 24677836SJohn.Forte@Sun.COM cdb_length, AF_FORCE_NOSLEEP); 24687836SJohn.Forte@Sun.COM if (task == NULL) { 24697836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 24707836SJohn.Forte@Sun.COM return (NULL); 24717836SJohn.Forte@Sun.COM } 24727836SJohn.Forte@Sun.COM task->task_lu = lu; 24737836SJohn.Forte@Sun.COM l = task->task_lun_no; 24747836SJohn.Forte@Sun.COM l[0] = lun[0]; 24757836SJohn.Forte@Sun.COM l[1] = lun[1]; 24767836SJohn.Forte@Sun.COM l[2] = lun[2]; 24777836SJohn.Forte@Sun.COM l[3] = lun[3]; 24787836SJohn.Forte@Sun.COM l[4] = lun[4]; 24797836SJohn.Forte@Sun.COM l[5] = lun[5]; 24807836SJohn.Forte@Sun.COM l[6] = lun[6]; 24817836SJohn.Forte@Sun.COM l[7] = lun[7]; 24827836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)task->task_port_private; 24837836SJohn.Forte@Sun.COM if ((ulong_t)(task->task_cdb) & 7ul) { 24847836SJohn.Forte@Sun.COM task->task_cdb = (uint8_t *)(((ulong_t) 24857836SJohn.Forte@Sun.COM (task->task_cdb) + 7ul) & ~(7ul)); 24867836SJohn.Forte@Sun.COM } 24877836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 24887836SJohn.Forte@Sun.COM itask->itask_cdb_buf_size = cdb_length; 24897836SJohn.Forte@Sun.COM } 24907836SJohn.Forte@Sun.COM task->task_session = ss; 24917836SJohn.Forte@Sun.COM task->task_lport = lport; 24927836SJohn.Forte@Sun.COM task->task_cdb_length = cdb_length_in; 24937836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_TRANSITION; 24947836SJohn.Forte@Sun.COM 24957836SJohn.Forte@Sun.COM if (new_task) { 24967836SJohn.Forte@Sun.COM if (lu->lu_task_alloc(task) != STMF_SUCCESS) { 24977836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 24987836SJohn.Forte@Sun.COM stmf_free(task); 24997836SJohn.Forte@Sun.COM return (NULL); 25007836SJohn.Forte@Sun.COM } 25017836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25027836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 25037836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25047836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 25057836SJohn.Forte@Sun.COM stmf_free(task); 25067836SJohn.Forte@Sun.COM return (NULL); 25077836SJohn.Forte@Sun.COM } 25087836SJohn.Forte@Sun.COM itask->itask_lu_next = ilu->ilu_tasks; 25097836SJohn.Forte@Sun.COM if (ilu->ilu_tasks) 25107836SJohn.Forte@Sun.COM ilu->ilu_tasks->itask_lu_prev = itask; 25117836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask; 25127836SJohn.Forte@Sun.COM /* kmem_zalloc automatically makes itask->itask_lu_prev NULL */ 25137836SJohn.Forte@Sun.COM ilu->ilu_ntasks++; 25147836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25157836SJohn.Forte@Sun.COM } 25167836SJohn.Forte@Sun.COM 25177836SJohn.Forte@Sun.COM itask->itask_ilu_task_cntr = ilu->ilu_cur_task_cntr; 25187836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, 1); 25197836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 25207836SJohn.Forte@Sun.COM 25217836SJohn.Forte@Sun.COM if ((lun_map_ent != NULL) && ((itask->itask_itl_datap = 25227836SJohn.Forte@Sun.COM lun_map_ent->ent_itl_datap) != NULL)) { 25237836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_itl_datap->itl_counter, 1); 25247836SJohn.Forte@Sun.COM task->task_lu_itl_handle = itask->itask_itl_datap->itl_handle; 25257836SJohn.Forte@Sun.COM } else { 25267836SJohn.Forte@Sun.COM itask->itask_itl_datap = NULL; 25277836SJohn.Forte@Sun.COM task->task_lu_itl_handle = NULL; 25287836SJohn.Forte@Sun.COM } 25297836SJohn.Forte@Sun.COM 25307836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 25317836SJohn.Forte@Sun.COM return (task); 25327836SJohn.Forte@Sun.COM } 25337836SJohn.Forte@Sun.COM 25347836SJohn.Forte@Sun.COM void 25357836SJohn.Forte@Sun.COM stmf_task_lu_free(scsi_task_t *task) 25367836SJohn.Forte@Sun.COM { 25377836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 25387836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 25397836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 25407836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 25417836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 25427836SJohn.Forte@Sun.COM 25437836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 25447836SJohn.Forte@Sun.COM itask->itask_flags = ITASK_IN_FREE_LIST; 25457836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25467836SJohn.Forte@Sun.COM itask->itask_lu_free_next = ilu->ilu_free_tasks; 25477836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask; 25487836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free++; 25497836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25507836SJohn.Forte@Sun.COM atomic_add_32(itask->itask_ilu_task_cntr, -1); 25517836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 25527836SJohn.Forte@Sun.COM } 25537836SJohn.Forte@Sun.COM 25547836SJohn.Forte@Sun.COM void 25557836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(stmf_i_lu_t *ilu) 25567836SJohn.Forte@Sun.COM { 25577836SJohn.Forte@Sun.COM uint32_t num_to_release, ndx; 25587836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 25597836SJohn.Forte@Sun.COM stmf_lu_t *lu = ilu->ilu_lu; 25607836SJohn.Forte@Sun.COM 25617836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks_min_free <= ilu->ilu_ntasks_free); 25627836SJohn.Forte@Sun.COM 25637836SJohn.Forte@Sun.COM /* free half of the minimal free of the free tasks */ 25647836SJohn.Forte@Sun.COM num_to_release = (ilu->ilu_ntasks_min_free + 1) / 2; 25657836SJohn.Forte@Sun.COM if (!num_to_release) { 25667836SJohn.Forte@Sun.COM return; 25677836SJohn.Forte@Sun.COM } 25687836SJohn.Forte@Sun.COM for (ndx = 0; ndx < num_to_release; ndx++) { 25697836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25707836SJohn.Forte@Sun.COM itask = ilu->ilu_free_tasks; 25717836SJohn.Forte@Sun.COM if (itask == NULL) { 25727836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25737836SJohn.Forte@Sun.COM break; 25747836SJohn.Forte@Sun.COM } 25757836SJohn.Forte@Sun.COM ilu->ilu_free_tasks = itask->itask_lu_free_next; 25767836SJohn.Forte@Sun.COM ilu->ilu_ntasks_free--; 25777836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25787836SJohn.Forte@Sun.COM 25797836SJohn.Forte@Sun.COM lu->lu_task_free(itask->itask_task); 25807836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 25817836SJohn.Forte@Sun.COM if (itask->itask_lu_next) 25827836SJohn.Forte@Sun.COM itask->itask_lu_next->itask_lu_prev = 25837836SJohn.Forte@Sun.COM itask->itask_lu_prev; 25847836SJohn.Forte@Sun.COM if (itask->itask_lu_prev) 25857836SJohn.Forte@Sun.COM itask->itask_lu_prev->itask_lu_next = 25867836SJohn.Forte@Sun.COM itask->itask_lu_next; 25877836SJohn.Forte@Sun.COM else 25887836SJohn.Forte@Sun.COM ilu->ilu_tasks = itask->itask_lu_next; 25897836SJohn.Forte@Sun.COM 25907836SJohn.Forte@Sun.COM ilu->ilu_ntasks--; 25917836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 25927836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 25937836SJohn.Forte@Sun.COM } 25947836SJohn.Forte@Sun.COM } 25957836SJohn.Forte@Sun.COM 25967836SJohn.Forte@Sun.COM /* 25977836SJohn.Forte@Sun.COM * Called with stmf_lock held 25987836SJohn.Forte@Sun.COM */ 25997836SJohn.Forte@Sun.COM void 26007836SJohn.Forte@Sun.COM stmf_check_freetask() 26017836SJohn.Forte@Sun.COM { 26027836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 26037836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 26047836SJohn.Forte@Sun.COM 26057836SJohn.Forte@Sun.COM /* stmf_svc_ilu_draining may get changed after stmf_lock is released */ 26067836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_draining) != NULL) { 26077836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = ilu->ilu_next; 26087836SJohn.Forte@Sun.COM if (!ilu->ilu_ntasks_min_free) { 26097836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 26107836SJohn.Forte@Sun.COM continue; 26117836SJohn.Forte@Sun.COM } 26127836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 26137836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 26147836SJohn.Forte@Sun.COM stmf_task_lu_check_freelist(ilu); 26157836SJohn.Forte@Sun.COM /* 26167836SJohn.Forte@Sun.COM * we do not care about the accuracy of 26177836SJohn.Forte@Sun.COM * ilu_ntasks_min_free, so we don't lock here 26187836SJohn.Forte@Sun.COM */ 26197836SJohn.Forte@Sun.COM ilu->ilu_ntasks_min_free = ilu->ilu_ntasks_free; 26207836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 26217836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 26227836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 26237836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 26247836SJohn.Forte@Sun.COM break; 26257836SJohn.Forte@Sun.COM } 26267836SJohn.Forte@Sun.COM } 26277836SJohn.Forte@Sun.COM 26287836SJohn.Forte@Sun.COM void 26297836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(stmf_i_lu_t *ilu) 26307836SJohn.Forte@Sun.COM { 26317836SJohn.Forte@Sun.COM clock_t l = ddi_get_lbolt(); 26327836SJohn.Forte@Sun.COM clock_t ps = drv_usectohz(1000000); 26337836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 26347836SJohn.Forte@Sun.COM scsi_task_t *task; 26357836SJohn.Forte@Sun.COM uint32_t to; 26367836SJohn.Forte@Sun.COM 26377836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 26387836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 26397836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 26407836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_IN_FREE_LIST | 26417836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) { 26427836SJohn.Forte@Sun.COM continue; 26437836SJohn.Forte@Sun.COM } 26447836SJohn.Forte@Sun.COM task = itask->itask_task; 26457836SJohn.Forte@Sun.COM if (task->task_timeout == 0) 26467836SJohn.Forte@Sun.COM to = stmf_default_task_timeout; 26477836SJohn.Forte@Sun.COM else 26487836SJohn.Forte@Sun.COM to = task->task_timeout; 26497836SJohn.Forte@Sun.COM if ((itask->itask_start_time + (to * ps)) > l) 26507836SJohn.Forte@Sun.COM continue; 26517836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 26527836SJohn.Forte@Sun.COM STMF_TIMEOUT, NULL); 26537836SJohn.Forte@Sun.COM } 26547836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 26557836SJohn.Forte@Sun.COM } 26567836SJohn.Forte@Sun.COM 26577836SJohn.Forte@Sun.COM /* 26587836SJohn.Forte@Sun.COM * Called with stmf_lock held 26597836SJohn.Forte@Sun.COM */ 26607836SJohn.Forte@Sun.COM void 26617836SJohn.Forte@Sun.COM stmf_check_ilu_timing() 26627836SJohn.Forte@Sun.COM { 26637836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 26647836SJohn.Forte@Sun.COM clock_t endtime = ddi_get_lbolt() + drv_usectohz(10000); 26657836SJohn.Forte@Sun.COM 26667836SJohn.Forte@Sun.COM /* stmf_svc_ilu_timing may get changed after stmf_lock is released */ 26677836SJohn.Forte@Sun.COM while ((ilu = stmf_state.stmf_svc_ilu_timing) != NULL) { 26687836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = ilu->ilu_next; 26697836SJohn.Forte@Sun.COM if (ilu->ilu_cur_task_cntr == (&ilu->ilu_task_cntr1)) { 26707836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr2 == 0) { 26717836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr2; 26727836SJohn.Forte@Sun.COM continue; 26737836SJohn.Forte@Sun.COM } 26747836SJohn.Forte@Sun.COM } else { 26757836SJohn.Forte@Sun.COM if (ilu->ilu_task_cntr1 == 0) { 26767836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 26777836SJohn.Forte@Sun.COM continue; 26787836SJohn.Forte@Sun.COM } 26797836SJohn.Forte@Sun.COM } 26807836SJohn.Forte@Sun.COM /* 26817836SJohn.Forte@Sun.COM * If we are here then it means that there is some slowdown 26827836SJohn.Forte@Sun.COM * in tasks on this lu. We need to check. 26837836SJohn.Forte@Sun.COM */ 26847836SJohn.Forte@Sun.COM ilu->ilu_flags |= ILU_STALL_DEREGISTER; 26857836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 26867836SJohn.Forte@Sun.COM stmf_do_ilu_timeouts(ilu); 26877836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 26887836SJohn.Forte@Sun.COM ilu->ilu_flags &= ~ILU_STALL_DEREGISTER; 26897836SJohn.Forte@Sun.COM cv_broadcast(&stmf_state.stmf_cv); 26907836SJohn.Forte@Sun.COM if (ddi_get_lbolt() >= endtime) 26917836SJohn.Forte@Sun.COM break; 26927836SJohn.Forte@Sun.COM } 26937836SJohn.Forte@Sun.COM } 26947836SJohn.Forte@Sun.COM 26957836SJohn.Forte@Sun.COM /* 26967836SJohn.Forte@Sun.COM * Kills all tasks on a lu except tm_task 26977836SJohn.Forte@Sun.COM */ 26987836SJohn.Forte@Sun.COM void 26997836SJohn.Forte@Sun.COM stmf_task_lu_killall(stmf_lu_t *lu, scsi_task_t *tm_task, stmf_status_t s) 27007836SJohn.Forte@Sun.COM { 27017836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 27027836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 27037836SJohn.Forte@Sun.COM 27047836SJohn.Forte@Sun.COM mutex_enter(&ilu->ilu_task_lock); 27057836SJohn.Forte@Sun.COM 27067836SJohn.Forte@Sun.COM for (itask = ilu->ilu_tasks; itask != NULL; 27077836SJohn.Forte@Sun.COM itask = itask->itask_lu_next) { 27087836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_FREE_LIST) 27097836SJohn.Forte@Sun.COM continue; 27107836SJohn.Forte@Sun.COM if (itask->itask_task == tm_task) 27117836SJohn.Forte@Sun.COM continue; 27127836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, itask->itask_task, s, NULL); 27137836SJohn.Forte@Sun.COM } 27147836SJohn.Forte@Sun.COM mutex_exit(&ilu->ilu_task_lock); 27157836SJohn.Forte@Sun.COM } 27167836SJohn.Forte@Sun.COM 27177836SJohn.Forte@Sun.COM void 27187836SJohn.Forte@Sun.COM stmf_free_task_bufs(stmf_i_scsi_task_t *itask, stmf_local_port_t *lport) 27197836SJohn.Forte@Sun.COM { 27207836SJohn.Forte@Sun.COM int i; 27217836SJohn.Forte@Sun.COM uint8_t map; 27227836SJohn.Forte@Sun.COM 27237836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 27247836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 27257836SJohn.Forte@Sun.COM if (map & 1) { 27267836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 27277836SJohn.Forte@Sun.COM 27287836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 27297836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 27307836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 27317836SJohn.Forte@Sun.COM } 27327836SJohn.Forte@Sun.COM lport->lport_ds->ds_free_data_buf( 27337836SJohn.Forte@Sun.COM lport->lport_ds, dbuf); 27347836SJohn.Forte@Sun.COM } 27357836SJohn.Forte@Sun.COM map >>= 1; 27367836SJohn.Forte@Sun.COM } 27377836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 27387836SJohn.Forte@Sun.COM } 27397836SJohn.Forte@Sun.COM } 27407836SJohn.Forte@Sun.COM 27417836SJohn.Forte@Sun.COM void 27427836SJohn.Forte@Sun.COM stmf_task_free(scsi_task_t *task) 27437836SJohn.Forte@Sun.COM { 27447836SJohn.Forte@Sun.COM stmf_local_port_t *lport = task->task_lport; 27457836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 27467836SJohn.Forte@Sun.COM task->task_stmf_private; 27477836SJohn.Forte@Sun.COM 27487836SJohn.Forte@Sun.COM stmf_free_task_bufs(itask, lport); 27497836SJohn.Forte@Sun.COM if (itask->itask_itl_datap) { 27507836SJohn.Forte@Sun.COM if (atomic_add_32_nv(&itask->itask_itl_datap->itl_counter, 27517836SJohn.Forte@Sun.COM -1) == 0) { 27527836SJohn.Forte@Sun.COM stmf_release_itl_handle(task->task_lu, 27537836SJohn.Forte@Sun.COM itask->itask_itl_datap); 27547836SJohn.Forte@Sun.COM } 27557836SJohn.Forte@Sun.COM } 27567836SJohn.Forte@Sun.COM lport->lport_task_free(task); 27577836SJohn.Forte@Sun.COM if (itask->itask_worker) { 27587836SJohn.Forte@Sun.COM atomic_add_32(&stmf_cur_ntasks, -1); 27597836SJohn.Forte@Sun.COM atomic_add_32(&itask->itask_worker->worker_ref_count, -1); 27607836SJohn.Forte@Sun.COM } 27617836SJohn.Forte@Sun.COM /* 27627836SJohn.Forte@Sun.COM * After calling stmf_task_lu_free, the task pointer can no longer 27637836SJohn.Forte@Sun.COM * be trusted. 27647836SJohn.Forte@Sun.COM */ 27657836SJohn.Forte@Sun.COM stmf_task_lu_free(task); 27667836SJohn.Forte@Sun.COM } 27677836SJohn.Forte@Sun.COM 27687836SJohn.Forte@Sun.COM void 27697836SJohn.Forte@Sun.COM stmf_post_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 27707836SJohn.Forte@Sun.COM { 27717836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 27727836SJohn.Forte@Sun.COM task->task_stmf_private; 27737836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 27747836SJohn.Forte@Sun.COM int nv; 27757836SJohn.Forte@Sun.COM uint32_t old, new; 27767836SJohn.Forte@Sun.COM uint32_t ct; 27777836SJohn.Forte@Sun.COM stmf_worker_t *w, *w1; 27787836SJohn.Forte@Sun.COM uint8_t tm; 27797836SJohn.Forte@Sun.COM 27807836SJohn.Forte@Sun.COM if (task->task_max_nbufs > 4) 27817836SJohn.Forte@Sun.COM task->task_max_nbufs = 4; 27827836SJohn.Forte@Sun.COM task->task_cur_nbufs = 0; 27837836SJohn.Forte@Sun.COM /* Latest value of currently running tasks */ 27847836SJohn.Forte@Sun.COM ct = atomic_add_32_nv(&stmf_cur_ntasks, 1); 27857836SJohn.Forte@Sun.COM 27867836SJohn.Forte@Sun.COM /* Select the next worker using round robin */ 27877836SJohn.Forte@Sun.COM nv = (int)atomic_add_32_nv((uint32_t *)&stmf_worker_sel_counter, 1); 27887836SJohn.Forte@Sun.COM if (nv >= stmf_nworkers_accepting_cmds) { 27897836SJohn.Forte@Sun.COM int s = nv; 27907836SJohn.Forte@Sun.COM do { 27917836SJohn.Forte@Sun.COM nv -= stmf_nworkers_accepting_cmds; 27927836SJohn.Forte@Sun.COM } while (nv >= stmf_nworkers_accepting_cmds); 27937836SJohn.Forte@Sun.COM if (nv < 0) 27947836SJohn.Forte@Sun.COM nv = 0; 27957836SJohn.Forte@Sun.COM /* Its ok if this cas fails */ 27967836SJohn.Forte@Sun.COM (void) atomic_cas_32((uint32_t *)&stmf_worker_sel_counter, 27977836SJohn.Forte@Sun.COM s, nv); 27987836SJohn.Forte@Sun.COM } 27997836SJohn.Forte@Sun.COM w = &stmf_workers[nv]; 28007836SJohn.Forte@Sun.COM 28017836SJohn.Forte@Sun.COM /* 28027836SJohn.Forte@Sun.COM * A worker can be pinned by interrupt. So select the next one 28037836SJohn.Forte@Sun.COM * if it has lower load. 28047836SJohn.Forte@Sun.COM */ 28057836SJohn.Forte@Sun.COM if ((nv + 1) >= stmf_nworkers_accepting_cmds) { 28067836SJohn.Forte@Sun.COM w1 = stmf_workers; 28077836SJohn.Forte@Sun.COM } else { 28087836SJohn.Forte@Sun.COM w1 = &stmf_workers[nv + 1]; 28097836SJohn.Forte@Sun.COM } 28107836SJohn.Forte@Sun.COM if (w1->worker_queue_depth < w->worker_queue_depth) 28117836SJohn.Forte@Sun.COM w = w1; 28127836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 28137836SJohn.Forte@Sun.COM if (((w->worker_flags & STMF_WORKER_STARTED) == 0) || 28147836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 28157836SJohn.Forte@Sun.COM /* 28167836SJohn.Forte@Sun.COM * Maybe we are in the middle of a change. Just go to 28177836SJohn.Forte@Sun.COM * the 1st worker. 28187836SJohn.Forte@Sun.COM */ 28197836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 28207836SJohn.Forte@Sun.COM w = stmf_workers; 28217836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 28227836SJohn.Forte@Sun.COM } 28237836SJohn.Forte@Sun.COM itask->itask_worker = w; 28247836SJohn.Forte@Sun.COM /* 28257836SJohn.Forte@Sun.COM * Track max system load inside the worker as we already have the 28267836SJohn.Forte@Sun.COM * worker lock (no point implementing another lock). The service 28277836SJohn.Forte@Sun.COM * thread will do the comparisons and figure out the max overall 28287836SJohn.Forte@Sun.COM * system load. 28297836SJohn.Forte@Sun.COM */ 28307836SJohn.Forte@Sun.COM if (w->worker_max_sys_qdepth_pu < ct) 28317836SJohn.Forte@Sun.COM w->worker_max_sys_qdepth_pu = ct; 28327836SJohn.Forte@Sun.COM 28337836SJohn.Forte@Sun.COM do { 28347836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 28357836SJohn.Forte@Sun.COM new |= ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE; 28367836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 28377836SJohn.Forte@Sun.COM tm = task->task_mgmt_function; 28387836SJohn.Forte@Sun.COM if ((tm == TM_TARGET_RESET) || 28397836SJohn.Forte@Sun.COM (tm == TM_TARGET_COLD_RESET) || 28407836SJohn.Forte@Sun.COM (tm == TM_TARGET_WARM_RESET)) { 28417836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 28427836SJohn.Forte@Sun.COM } 28437836SJohn.Forte@Sun.COM } else if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 28447836SJohn.Forte@Sun.COM new |= ITASK_DEFAULT_HANDLING; 28457836SJohn.Forte@Sun.COM } 28467836SJohn.Forte@Sun.COM new &= ~ITASK_IN_TRANSITION; 28477836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 28487836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 28497836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 28507836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 28517836SJohn.Forte@Sun.COM } else { 28527836SJohn.Forte@Sun.COM w->worker_task_head = itask; 28537836SJohn.Forte@Sun.COM } 28547836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 28557836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 28567836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 28577836SJohn.Forte@Sun.COM } 28587836SJohn.Forte@Sun.COM atomic_add_32(&w->worker_ref_count, 1); 28597836SJohn.Forte@Sun.COM itask->itask_cmd_stack[0] = ITASK_CMD_NEW_TASK; 28607836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 28617836SJohn.Forte@Sun.COM if (dbuf) { 28627836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 1; 28637836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = dbuf; 28647836SJohn.Forte@Sun.COM dbuf->db_handle = 0; 28657836SJohn.Forte@Sun.COM } else { 28667836SJohn.Forte@Sun.COM itask->itask_allocated_buf_map = 0; 28677836SJohn.Forte@Sun.COM itask->itask_dbufs[0] = NULL; 28687836SJohn.Forte@Sun.COM } 28697836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 28707836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 28717836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 28727836SJohn.Forte@Sun.COM 28737836SJohn.Forte@Sun.COM /* 28747836SJohn.Forte@Sun.COM * This can only happen if during stmf_task_alloc(), ILU_RESET_ACTIVE 28757836SJohn.Forte@Sun.COM * was set between checking of ILU_RESET_ACTIVE and clearing of the 28767836SJohn.Forte@Sun.COM * ITASK_IN_FREE_LIST flag. Take care of these "sneaked-in" tasks here. 28777836SJohn.Forte@Sun.COM */ 28787836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 28797836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ABORTED, NULL); 28807836SJohn.Forte@Sun.COM } 28817836SJohn.Forte@Sun.COM } 28827836SJohn.Forte@Sun.COM 28837836SJohn.Forte@Sun.COM /* 28847836SJohn.Forte@Sun.COM * ++++++++++++++ ABORT LOGIC ++++++++++++++++++++ 28857836SJohn.Forte@Sun.COM * Once ITASK_BEING_ABORTED is set, ITASK_KNOWN_TO_LU can be reset already 28867836SJohn.Forte@Sun.COM * i.e. before ITASK_BEING_ABORTED being set. But if it was not, it cannot 28877836SJohn.Forte@Sun.COM * be reset until the LU explicitly calls stmf_task_lu_aborted(). Of course 28887836SJohn.Forte@Sun.COM * the LU will make this call only if we call the LU's abort entry point. 28897836SJohn.Forte@Sun.COM * we will only call that entry point if ITASK_KNOWN_TO_LU was set. 28907836SJohn.Forte@Sun.COM * 28917836SJohn.Forte@Sun.COM * Same logic applies for the port. 28927836SJohn.Forte@Sun.COM * 28937836SJohn.Forte@Sun.COM * Also ITASK_BEING_ABORTED will not be allowed to set if both KNOWN_TO_LU 28947836SJohn.Forte@Sun.COM * and KNOWN_TO_TGT_PORT are reset. 28957836SJohn.Forte@Sun.COM * 28967836SJohn.Forte@Sun.COM * +++++++++++++++++++++++++++++++++++++++++++++++ 28977836SJohn.Forte@Sun.COM */ 28987836SJohn.Forte@Sun.COM 28997836SJohn.Forte@Sun.COM stmf_status_t 29007836SJohn.Forte@Sun.COM stmf_xfer_data(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t ioflags) 29017836SJohn.Forte@Sun.COM { 29027836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 29037836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 29047836SJohn.Forte@Sun.COM 29057836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 29067836SJohn.Forte@Sun.COM uint32_t new, old; 29077836SJohn.Forte@Sun.COM do { 29087836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 29097836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 29107836SJohn.Forte@Sun.COM return (STMF_ABORTED); 29117836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 29127836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 29137836SJohn.Forte@Sun.COM } 29147836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 29157836SJohn.Forte@Sun.COM return (STMF_ABORTED); 29167836SJohn.Forte@Sun.COM #ifdef DEBUG 29177836SJohn.Forte@Sun.COM if (stmf_drop_buf_counter > 0) { 29187836SJohn.Forte@Sun.COM if (atomic_add_32_nv((uint32_t *)&stmf_drop_buf_counter, 29197836SJohn.Forte@Sun.COM -1) == 1) 29207836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 29217836SJohn.Forte@Sun.COM } 29227836SJohn.Forte@Sun.COM #endif 29237836SJohn.Forte@Sun.COM return (task->task_lport->lport_xfer_data(task, dbuf, ioflags)); 29247836SJohn.Forte@Sun.COM } 29257836SJohn.Forte@Sun.COM 29267836SJohn.Forte@Sun.COM void 29277836SJohn.Forte@Sun.COM stmf_data_xfer_done(scsi_task_t *task, stmf_data_buf_t *dbuf, uint32_t iof) 29287836SJohn.Forte@Sun.COM { 29297836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 29307836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 29317836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 29327836SJohn.Forte@Sun.COM uint32_t new, old; 29337836SJohn.Forte@Sun.COM uint8_t update_queue_flags, free_it, queue_it; 29347836SJohn.Forte@Sun.COM 29357836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 29367836SJohn.Forte@Sun.COM do { 29377836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 29387836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 29397836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 29407836SJohn.Forte@Sun.COM return; 29417836SJohn.Forte@Sun.COM } 29427836SJohn.Forte@Sun.COM free_it = 0; 29437836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 29447836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 29457836SJohn.Forte@Sun.COM task->task_completion_status = dbuf->db_xfer_status; 29467836SJohn.Forte@Sun.COM free_it = 1; 29477836SJohn.Forte@Sun.COM } 29487836SJohn.Forte@Sun.COM /* 29497836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 29507836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 29517836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 29527836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 29537836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 29547836SJohn.Forte@Sun.COM * free this task. 29557836SJohn.Forte@Sun.COM */ 29567836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 29577836SJohn.Forte@Sun.COM free_it = 0; 29587836SJohn.Forte@Sun.COM update_queue_flags = 1; 29597836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 29607836SJohn.Forte@Sun.COM queue_it = 0; 29617836SJohn.Forte@Sun.COM } else { 29627836SJohn.Forte@Sun.COM queue_it = 1; 29637836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 29647836SJohn.Forte@Sun.COM } 29657836SJohn.Forte@Sun.COM } else { 29667836SJohn.Forte@Sun.COM update_queue_flags = 0; 29677836SJohn.Forte@Sun.COM queue_it = 0; 29687836SJohn.Forte@Sun.COM } 29697836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 29707836SJohn.Forte@Sun.COM 29717836SJohn.Forte@Sun.COM if (update_queue_flags) { 29727836SJohn.Forte@Sun.COM uint8_t cmd = (dbuf->db_handle << 5) | ITASK_CMD_DATA_XFER_DONE; 29737836SJohn.Forte@Sun.COM 29747836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 29757836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = cmd; 29767836SJohn.Forte@Sun.COM if (queue_it) { 29777836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 29787836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 29797836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 29807836SJohn.Forte@Sun.COM } else { 29817836SJohn.Forte@Sun.COM w->worker_task_head = itask; 29827836SJohn.Forte@Sun.COM } 29837836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 29847836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > 29857836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu) { 29867836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 29877836SJohn.Forte@Sun.COM } 29887836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 29897836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 29907836SJohn.Forte@Sun.COM } 29917836SJohn.Forte@Sun.COM } 29927836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 29937836SJohn.Forte@Sun.COM 29947836SJohn.Forte@Sun.COM if (free_it) { 29957836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 29967836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 29977836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 29987836SJohn.Forte@Sun.COM stmf_task_free(task); 29997836SJohn.Forte@Sun.COM } 30007836SJohn.Forte@Sun.COM } 30017836SJohn.Forte@Sun.COM } 30027836SJohn.Forte@Sun.COM 30037836SJohn.Forte@Sun.COM stmf_status_t 30047836SJohn.Forte@Sun.COM stmf_send_scsi_status(scsi_task_t *task, uint32_t ioflags) 30057836SJohn.Forte@Sun.COM { 30067836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 30077836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 30087836SJohn.Forte@Sun.COM if (ioflags & STMF_IOF_LU_DONE) { 30097836SJohn.Forte@Sun.COM uint32_t new, old; 30107836SJohn.Forte@Sun.COM do { 30117836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 30127836SJohn.Forte@Sun.COM if (new & ITASK_BEING_ABORTED) 30137836SJohn.Forte@Sun.COM return (STMF_ABORTED); 30147836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 30157836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 30167836SJohn.Forte@Sun.COM } 30177836SJohn.Forte@Sun.COM 30187836SJohn.Forte@Sun.COM if (!(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT)) { 30197836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 30207836SJohn.Forte@Sun.COM } 30217836SJohn.Forte@Sun.COM 30227836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_BEING_ABORTED) 30237836SJohn.Forte@Sun.COM return (STMF_ABORTED); 30247836SJohn.Forte@Sun.COM 30257836SJohn.Forte@Sun.COM if (task->task_additional_flags & TASK_AF_NO_EXPECTED_XFER_LENGTH) { 30267836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 30277836SJohn.Forte@Sun.COM task->task_resid = 0; 30287836SJohn.Forte@Sun.COM } else if (task->task_cmd_xfer_length > 30297836SJohn.Forte@Sun.COM task->task_expected_xfer_length) { 30307836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_OVER; 30317836SJohn.Forte@Sun.COM task->task_resid = task->task_cmd_xfer_length - 30327836SJohn.Forte@Sun.COM task->task_expected_xfer_length; 30337836SJohn.Forte@Sun.COM } else if (task->task_nbytes_transferred < 30347836SJohn.Forte@Sun.COM task->task_expected_xfer_length) { 30357836SJohn.Forte@Sun.COM task->task_status_ctrl = TASK_SCTRL_UNDER; 30367836SJohn.Forte@Sun.COM task->task_resid = task->task_expected_xfer_length - 30377836SJohn.Forte@Sun.COM task->task_nbytes_transferred; 30387836SJohn.Forte@Sun.COM } else { 30397836SJohn.Forte@Sun.COM task->task_status_ctrl = 0; 30407836SJohn.Forte@Sun.COM task->task_resid = 0; 30417836SJohn.Forte@Sun.COM } 30427836SJohn.Forte@Sun.COM return (task->task_lport->lport_send_status(task, ioflags)); 30437836SJohn.Forte@Sun.COM } 30447836SJohn.Forte@Sun.COM 30457836SJohn.Forte@Sun.COM void 30467836SJohn.Forte@Sun.COM stmf_send_status_done(scsi_task_t *task, stmf_status_t s, uint32_t iof) 30477836SJohn.Forte@Sun.COM { 30487836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 30497836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 30507836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 30517836SJohn.Forte@Sun.COM uint32_t new, old; 30527836SJohn.Forte@Sun.COM uint8_t free_it, queue_it; 30537836SJohn.Forte@Sun.COM 30547836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 30557836SJohn.Forte@Sun.COM do { 30567836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 30577836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 30587836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 30597836SJohn.Forte@Sun.COM return; 30607836SJohn.Forte@Sun.COM } 30617836SJohn.Forte@Sun.COM free_it = 0; 30627836SJohn.Forte@Sun.COM if (iof & STMF_IOF_LPORT_DONE) { 30637836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_TGT_PORT; 30647836SJohn.Forte@Sun.COM free_it = 1; 30657836SJohn.Forte@Sun.COM } 30667836SJohn.Forte@Sun.COM /* 30677836SJohn.Forte@Sun.COM * If the task is known to LU then queue it. But if 30687836SJohn.Forte@Sun.COM * it is already queued (multiple completions) then 30697836SJohn.Forte@Sun.COM * just update the buffer information by grabbing the 30707836SJohn.Forte@Sun.COM * worker lock. If the task is not known to LU, 30717836SJohn.Forte@Sun.COM * completed/aborted, then see if we need to 30727836SJohn.Forte@Sun.COM * free this task. 30737836SJohn.Forte@Sun.COM */ 30747836SJohn.Forte@Sun.COM if (old & ITASK_KNOWN_TO_LU) { 30757836SJohn.Forte@Sun.COM free_it = 0; 30767836SJohn.Forte@Sun.COM queue_it = 1; 30777836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 30787836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "status completion received" 30797836SJohn.Forte@Sun.COM " when task is already in worker queue " 30807836SJohn.Forte@Sun.COM " task = %p", (void *)task); 30817836SJohn.Forte@Sun.COM } 30827836SJohn.Forte@Sun.COM new |= ITASK_IN_WORKER_QUEUE; 30837836SJohn.Forte@Sun.COM } else { 30847836SJohn.Forte@Sun.COM queue_it = 0; 30857836SJohn.Forte@Sun.COM } 30867836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 30877836SJohn.Forte@Sun.COM task->task_completion_status = s; 30887836SJohn.Forte@Sun.COM 30897836SJohn.Forte@Sun.COM if (queue_it) { 30907836SJohn.Forte@Sun.COM ASSERT(itask->itask_ncmds < ITASK_MAX_NCMDS); 30917836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = 30927836SJohn.Forte@Sun.COM ITASK_CMD_STATUS_DONE; 30937836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 30947836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 30957836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 30967836SJohn.Forte@Sun.COM } else { 30977836SJohn.Forte@Sun.COM w->worker_task_head = itask; 30987836SJohn.Forte@Sun.COM } 30997836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 31007836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 31017836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 31027836SJohn.Forte@Sun.COM } 31037836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 31047836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 31057836SJohn.Forte@Sun.COM } 31067836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 31077836SJohn.Forte@Sun.COM 31087836SJohn.Forte@Sun.COM if (free_it) { 31097836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 31107836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 31117836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 31127836SJohn.Forte@Sun.COM stmf_task_free(task); 31137836SJohn.Forte@Sun.COM } else { 31147836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "LU is done with the task but LPORT " 31157836SJohn.Forte@Sun.COM " is not done, itask %p", (void *)itask); 31167836SJohn.Forte@Sun.COM } 31177836SJohn.Forte@Sun.COM } 31187836SJohn.Forte@Sun.COM } 31197836SJohn.Forte@Sun.COM 31207836SJohn.Forte@Sun.COM void 31217836SJohn.Forte@Sun.COM stmf_task_lu_done(scsi_task_t *task) 31227836SJohn.Forte@Sun.COM { 31237836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 31247836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 31257836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 31267836SJohn.Forte@Sun.COM uint32_t new, old; 31277836SJohn.Forte@Sun.COM 31287836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 31297836SJohn.Forte@Sun.COM do { 31307836SJohn.Forte@Sun.COM new = old = itask->itask_flags; 31317836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 31327836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 31337836SJohn.Forte@Sun.COM return; 31347836SJohn.Forte@Sun.COM } 31357836SJohn.Forte@Sun.COM if (old & ITASK_IN_WORKER_QUEUE) { 31367836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "task_lu_done received" 31377836SJohn.Forte@Sun.COM " when task is in worker queue " 31387836SJohn.Forte@Sun.COM " task = %p", (void *)task); 31397836SJohn.Forte@Sun.COM } 31407836SJohn.Forte@Sun.COM new &= ~ITASK_KNOWN_TO_LU; 31417836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 31427836SJohn.Forte@Sun.COM 31437836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 31447836SJohn.Forte@Sun.COM 31457836SJohn.Forte@Sun.COM if ((itask->itask_flags & (ITASK_KNOWN_TO_LU | 31467836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT | ITASK_IN_WORKER_QUEUE | 31477836SJohn.Forte@Sun.COM ITASK_BEING_ABORTED)) == 0) { 31487836SJohn.Forte@Sun.COM stmf_task_free(task); 31497836SJohn.Forte@Sun.COM } else { 31507836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_lu_done should be the last stage but " 31517836SJohn.Forte@Sun.COM " the task is still not done, task = %p", (void *)task); 31527836SJohn.Forte@Sun.COM } 31537836SJohn.Forte@Sun.COM } 31547836SJohn.Forte@Sun.COM 31557836SJohn.Forte@Sun.COM void 31567836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(scsi_task_t *task, stmf_status_t s) 31577836SJohn.Forte@Sun.COM { 31587836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 31597836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 31607836SJohn.Forte@Sun.COM stmf_worker_t *w; 31617836SJohn.Forte@Sun.COM uint32_t old, new; 31627836SJohn.Forte@Sun.COM 31637836SJohn.Forte@Sun.COM do { 31647836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 31657836SJohn.Forte@Sun.COM if ((old & ITASK_BEING_ABORTED) || 31667836SJohn.Forte@Sun.COM ((old & (ITASK_KNOWN_TO_TGT_PORT | 31677836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU)) == 0)) { 31687836SJohn.Forte@Sun.COM return; 31697836SJohn.Forte@Sun.COM } 31707836SJohn.Forte@Sun.COM new |= ITASK_BEING_ABORTED; 31717836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 31727836SJohn.Forte@Sun.COM task->task_completion_status = s; 31737836SJohn.Forte@Sun.COM itask->itask_start_time = ddi_get_lbolt(); 31747836SJohn.Forte@Sun.COM 31757836SJohn.Forte@Sun.COM if (((w = itask->itask_worker) == NULL) || 31767836SJohn.Forte@Sun.COM (itask->itask_flags & ITASK_IN_TRANSITION)) { 31777836SJohn.Forte@Sun.COM return; 31787836SJohn.Forte@Sun.COM } 31797836SJohn.Forte@Sun.COM 31807836SJohn.Forte@Sun.COM /* Queue it and get out */ 31817836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 31827836SJohn.Forte@Sun.COM if (itask->itask_flags & ITASK_IN_WORKER_QUEUE) { 31837836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 31847836SJohn.Forte@Sun.COM return; 31857836SJohn.Forte@Sun.COM } 31867836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 31877836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 31887836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 31897836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 31907836SJohn.Forte@Sun.COM } else { 31917836SJohn.Forte@Sun.COM w->worker_task_head = itask; 31927836SJohn.Forte@Sun.COM } 31937836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 31947836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 31957836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 31967836SJohn.Forte@Sun.COM } 31977836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 31987836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 31997836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 32007836SJohn.Forte@Sun.COM } 32017836SJohn.Forte@Sun.COM 32027836SJohn.Forte@Sun.COM void 32037836SJohn.Forte@Sun.COM stmf_abort(int abort_cmd, scsi_task_t *task, stmf_status_t s, void *arg) 32047836SJohn.Forte@Sun.COM { 32057836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = NULL; 32067836SJohn.Forte@Sun.COM uint32_t old, new, f, rf; 32077836SJohn.Forte@Sun.COM 32087836SJohn.Forte@Sun.COM switch (abort_cmd) { 32097836SJohn.Forte@Sun.COM case STMF_QUEUE_ABORT_LU: 32107836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)arg, task, s); 32117836SJohn.Forte@Sun.COM return; 32127836SJohn.Forte@Sun.COM case STMF_QUEUE_TASK_ABORT: 32137836SJohn.Forte@Sun.COM stmf_queue_task_for_abort(task, s); 32147836SJohn.Forte@Sun.COM return; 32157836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LPORT: 32167836SJohn.Forte@Sun.COM rf = ITASK_TGT_PORT_ABORT_CALLED; 32177836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_TGT_PORT; 32187836SJohn.Forte@Sun.COM break; 32197836SJohn.Forte@Sun.COM case STMF_REQUEUE_TASK_ABORT_LU: 32207836SJohn.Forte@Sun.COM rf = ITASK_LU_ABORT_CALLED; 32217836SJohn.Forte@Sun.COM f = ITASK_KNOWN_TO_LU; 32227836SJohn.Forte@Sun.COM break; 32237836SJohn.Forte@Sun.COM default: 32247836SJohn.Forte@Sun.COM return; 32257836SJohn.Forte@Sun.COM } 32267836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 32277836SJohn.Forte@Sun.COM f |= ITASK_BEING_ABORTED | rf; 32287836SJohn.Forte@Sun.COM do { 32297836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 32307836SJohn.Forte@Sun.COM if ((old & f) != f) { 32317836SJohn.Forte@Sun.COM return; 32327836SJohn.Forte@Sun.COM } 32337836SJohn.Forte@Sun.COM new &= ~rf; 32347836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 32357836SJohn.Forte@Sun.COM } 32367836SJohn.Forte@Sun.COM 32377836SJohn.Forte@Sun.COM void 32387836SJohn.Forte@Sun.COM stmf_task_lu_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 32397836SJohn.Forte@Sun.COM { 32407836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 32417836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 32427836SJohn.Forte@Sun.COM unsigned long long st; 32437836SJohn.Forte@Sun.COM 32447836SJohn.Forte@Sun.COM st = s; /* gcc fix */ 32457836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 32467836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 32477836SJohn.Forte@Sun.COM "task %p, lu failed to abort ret=%llx", (void *)task, st); 32487836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LU_DONE) == 0) { 32497836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 32507836SJohn.Forte@Sun.COM "Task aborted but LU is not finished, task =" 32517836SJohn.Forte@Sun.COM "%p, s=%llx, iof=%x", (void *)task, st, iof); 32527836SJohn.Forte@Sun.COM } else { 32537836SJohn.Forte@Sun.COM /* 32547836SJohn.Forte@Sun.COM * LU abort successfully 32557836SJohn.Forte@Sun.COM */ 32567836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_LU); 32577836SJohn.Forte@Sun.COM return; 32587836SJohn.Forte@Sun.COM } 32597836SJohn.Forte@Sun.COM 32607836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 32617836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 32627836SJohn.Forte@Sun.COM } 32637836SJohn.Forte@Sun.COM 32647836SJohn.Forte@Sun.COM void 32657836SJohn.Forte@Sun.COM stmf_task_lport_aborted(scsi_task_t *task, stmf_status_t s, uint32_t iof) 32667836SJohn.Forte@Sun.COM { 32677836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 32687836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 32697836SJohn.Forte@Sun.COM unsigned long long st; 32707836SJohn.Forte@Sun.COM 32717836SJohn.Forte@Sun.COM st = s; 32727836SJohn.Forte@Sun.COM if ((s != STMF_ABORT_SUCCESS) && (s != STMF_NOT_FOUND)) { 32737836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 32747836SJohn.Forte@Sun.COM "task %p, tgt port failed to abort ret=%llx", (void *)task, 32757836SJohn.Forte@Sun.COM st); 32767836SJohn.Forte@Sun.COM } else if ((iof & STMF_IOF_LPORT_DONE) == 0) { 32777836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 32787836SJohn.Forte@Sun.COM "Task aborted but tgt port is not finished, " 32797836SJohn.Forte@Sun.COM "task=%p, s=%llx, iof=%x", (void *)task, st, iof); 32807836SJohn.Forte@Sun.COM } else { 32817836SJohn.Forte@Sun.COM /* 32827836SJohn.Forte@Sun.COM * LU abort successfully 32837836SJohn.Forte@Sun.COM */ 32847836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, ~ITASK_KNOWN_TO_TGT_PORT); 32857836SJohn.Forte@Sun.COM return; 32867836SJohn.Forte@Sun.COM } 32877836SJohn.Forte@Sun.COM 32887836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 32897836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 32907836SJohn.Forte@Sun.COM } 32917836SJohn.Forte@Sun.COM 32927836SJohn.Forte@Sun.COM stmf_status_t 32937836SJohn.Forte@Sun.COM stmf_task_poll_lu(scsi_task_t *task, uint32_t timeout) 32947836SJohn.Forte@Sun.COM { 32957836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 32967836SJohn.Forte@Sun.COM task->task_stmf_private; 32977836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 32987836SJohn.Forte@Sun.COM int i; 32997836SJohn.Forte@Sun.COM 33007836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_LU); 33017836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33027836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 33037836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33047836SJohn.Forte@Sun.COM return (STMF_BUSY); 33057836SJohn.Forte@Sun.COM } 33067836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 33077836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LU) { 33087836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33097836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 33107836SJohn.Forte@Sun.COM } 33117836SJohn.Forte@Sun.COM } 33127836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LU; 33137836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 33147836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 33157836SJohn.Forte@Sun.COM } else { 33167836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 33177836SJohn.Forte@Sun.COM if (t == 0) 33187836SJohn.Forte@Sun.COM t = 1; 33197836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 33207836SJohn.Forte@Sun.COM } 33217836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 33227836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 33237836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 33247836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 33257836SJohn.Forte@Sun.COM } else { 33267836SJohn.Forte@Sun.COM w->worker_task_head = itask; 33277836SJohn.Forte@Sun.COM } 33287836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 33297836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 33307836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 33317836SJohn.Forte@Sun.COM } 33327836SJohn.Forte@Sun.COM atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); 33337836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 33347836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 33357836SJohn.Forte@Sun.COM } 33367836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33377836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 33387836SJohn.Forte@Sun.COM } 33397836SJohn.Forte@Sun.COM 33407836SJohn.Forte@Sun.COM stmf_status_t 33417836SJohn.Forte@Sun.COM stmf_task_poll_lport(scsi_task_t *task, uint32_t timeout) 33427836SJohn.Forte@Sun.COM { 33437836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = (stmf_i_scsi_task_t *) 33447836SJohn.Forte@Sun.COM task->task_stmf_private; 33457836SJohn.Forte@Sun.COM stmf_worker_t *w = itask->itask_worker; 33467836SJohn.Forte@Sun.COM int i; 33477836SJohn.Forte@Sun.COM 33487836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT); 33497836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 33507836SJohn.Forte@Sun.COM if (itask->itask_ncmds >= ITASK_MAX_NCMDS) { 33517836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33527836SJohn.Forte@Sun.COM return (STMF_BUSY); 33537836SJohn.Forte@Sun.COM } 33547836SJohn.Forte@Sun.COM for (i = 0; i < itask->itask_ncmds; i++) { 33557836SJohn.Forte@Sun.COM if (itask->itask_cmd_stack[i] == ITASK_CMD_POLL_LPORT) { 33567836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33577836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 33587836SJohn.Forte@Sun.COM } 33597836SJohn.Forte@Sun.COM } 33607836SJohn.Forte@Sun.COM itask->itask_cmd_stack[itask->itask_ncmds++] = ITASK_CMD_POLL_LPORT; 33617836SJohn.Forte@Sun.COM if (timeout == ITASK_DEFAULT_POLL_TIMEOUT) { 33627836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + 1; 33637836SJohn.Forte@Sun.COM } else { 33647836SJohn.Forte@Sun.COM clock_t t = drv_usectohz(timeout * 1000); 33657836SJohn.Forte@Sun.COM if (t == 0) 33667836SJohn.Forte@Sun.COM t = 1; 33677836SJohn.Forte@Sun.COM itask->itask_poll_timeout = ddi_get_lbolt() + t; 33687836SJohn.Forte@Sun.COM } 33697836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_IN_WORKER_QUEUE) == 0) { 33707836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 33717836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 33727836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 33737836SJohn.Forte@Sun.COM } else { 33747836SJohn.Forte@Sun.COM w->worker_task_head = itask; 33757836SJohn.Forte@Sun.COM } 33767836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 33777836SJohn.Forte@Sun.COM if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { 33787836SJohn.Forte@Sun.COM w->worker_max_qdepth_pu = w->worker_queue_depth; 33797836SJohn.Forte@Sun.COM } 33807836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 33817836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 33827836SJohn.Forte@Sun.COM } 33837836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 33847836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 33857836SJohn.Forte@Sun.COM } 33867836SJohn.Forte@Sun.COM 33877836SJohn.Forte@Sun.COM void 33887836SJohn.Forte@Sun.COM stmf_do_task_abort(scsi_task_t *task) 33897836SJohn.Forte@Sun.COM { 33907836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = TASK_TO_ITASK(task); 33917836SJohn.Forte@Sun.COM stmf_lu_t *lu; 33927836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 33937836SJohn.Forte@Sun.COM unsigned long long ret; 33947836SJohn.Forte@Sun.COM uint32_t old, new; 33957836SJohn.Forte@Sun.COM uint8_t call_lu_abort, call_port_abort; 33967836SJohn.Forte@Sun.COM char info[STMF_CHANGE_INFO_LEN]; 33977836SJohn.Forte@Sun.COM 33987836SJohn.Forte@Sun.COM lu = task->task_lu; 33997836SJohn.Forte@Sun.COM lport = task->task_lport; 34007836SJohn.Forte@Sun.COM do { 34017836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 34027836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_LU | ITASK_LU_ABORT_CALLED)) == 34037836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_LU) { 34047836SJohn.Forte@Sun.COM new |= ITASK_LU_ABORT_CALLED; 34057836SJohn.Forte@Sun.COM call_lu_abort = 1; 34067836SJohn.Forte@Sun.COM } else { 34077836SJohn.Forte@Sun.COM call_lu_abort = 0; 34087836SJohn.Forte@Sun.COM } 34097836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34107836SJohn.Forte@Sun.COM 34117836SJohn.Forte@Sun.COM if (call_lu_abort) { 34127836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) { 34137836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 34147836SJohn.Forte@Sun.COM } else { 34157836SJohn.Forte@Sun.COM ret = dlun0->lu_abort(lu, STMF_LU_ABORT_TASK, task, 0); 34167836SJohn.Forte@Sun.COM } 34177836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 34187836SJohn.Forte@Sun.COM stmf_task_lu_aborted(task, ret, STMF_IOF_LU_DONE); 34197836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 34207836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 34217836SJohn.Forte@Sun.COM ~ITASK_LU_ABORT_CALLED); 34227836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 34237836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 34247836SJohn.Forte@Sun.COM "Abort failed by LU %p, ret %llx", (void *)lu, ret); 34257836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 34267836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 1, info); 34277836SJohn.Forte@Sun.COM } 34287836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_LU) { 34297836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 34307836SJohn.Forte@Sun.COM STMF_SEC2TICK(lu->lu_abort_timeout? 34317836SJohn.Forte@Sun.COM lu->lu_abort_timeout : ITASK_DEFAULT_ABORT_TIMEOUT))) { 34327836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 34337836SJohn.Forte@Sun.COM "lu abort timed out"); 34347836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 34357836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 1, info); 34367836SJohn.Forte@Sun.COM } 34377836SJohn.Forte@Sun.COM } 34387836SJohn.Forte@Sun.COM 34397836SJohn.Forte@Sun.COM do { 34407836SJohn.Forte@Sun.COM old = new = itask->itask_flags; 34417836SJohn.Forte@Sun.COM if ((old & (ITASK_KNOWN_TO_TGT_PORT | 34427836SJohn.Forte@Sun.COM ITASK_TGT_PORT_ABORT_CALLED)) == ITASK_KNOWN_TO_TGT_PORT) { 34437836SJohn.Forte@Sun.COM new |= ITASK_TGT_PORT_ABORT_CALLED; 34447836SJohn.Forte@Sun.COM call_port_abort = 1; 34457836SJohn.Forte@Sun.COM } else { 34467836SJohn.Forte@Sun.COM call_port_abort = 0; 34477836SJohn.Forte@Sun.COM } 34487836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 34497836SJohn.Forte@Sun.COM if (call_port_abort) { 34507836SJohn.Forte@Sun.COM ret = lport->lport_abort(lport, STMF_LPORT_ABORT_TASK, 34517836SJohn.Forte@Sun.COM task, 0); 34527836SJohn.Forte@Sun.COM if ((ret == STMF_ABORT_SUCCESS) || (ret == STMF_NOT_FOUND)) { 34537836SJohn.Forte@Sun.COM stmf_task_lport_aborted(task, ret, STMF_IOF_LPORT_DONE); 34547836SJohn.Forte@Sun.COM } else if (ret == STMF_BUSY) { 34557836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 34567836SJohn.Forte@Sun.COM ~ITASK_TGT_PORT_ABORT_CALLED); 34577836SJohn.Forte@Sun.COM } else if (ret != STMF_SUCCESS) { 34587836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 34597836SJohn.Forte@Sun.COM "Abort failed by tgt port %p ret %llx", 34607836SJohn.Forte@Sun.COM (void *)lport, ret); 34617836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 34627836SJohn.Forte@Sun.COM stmf_abort_task_offline(task, 0, info); 34637836SJohn.Forte@Sun.COM } 34647836SJohn.Forte@Sun.COM } else if (itask->itask_flags & ITASK_KNOWN_TO_TGT_PORT) { 34657836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > (itask->itask_start_time + 34667836SJohn.Forte@Sun.COM STMF_SEC2TICK(lport->lport_abort_timeout? 34677836SJohn.Forte@Sun.COM lport->lport_abort_timeout : 34687836SJohn.Forte@Sun.COM ITASK_DEFAULT_ABORT_TIMEOUT))) { 34697836SJohn.Forte@Sun.COM (void) snprintf(info, STMF_CHANGE_INFO_LEN, 34707836SJohn.Forte@Sun.COM "lport abort timed out"); 34717836SJohn.Forte@Sun.COM info[STMF_CHANGE_INFO_LEN - 1] = 0; 34727836SJohn.Forte@Sun.COM stmf_abort_task_offline(itask->itask_task, 0, info); 34737836SJohn.Forte@Sun.COM } 34747836SJohn.Forte@Sun.COM } 34757836SJohn.Forte@Sun.COM } 34767836SJohn.Forte@Sun.COM 34777836SJohn.Forte@Sun.COM stmf_status_t 34787836SJohn.Forte@Sun.COM stmf_ctl(int cmd, void *obj, void *arg) 34797836SJohn.Forte@Sun.COM { 34807836SJohn.Forte@Sun.COM stmf_status_t ret; 34817836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 34827836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 34837836SJohn.Forte@Sun.COM stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; 34847836SJohn.Forte@Sun.COM 34857836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 34867836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 34877836SJohn.Forte@Sun.COM if (cmd & STMF_CMD_LU_OP) { 34887836SJohn.Forte@Sun.COM ilu = stmf_lookup_lu((stmf_lu_t *)obj); 34897836SJohn.Forte@Sun.COM if (ilu == NULL) { 34907836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 34917836SJohn.Forte@Sun.COM } 34927836SJohn.Forte@Sun.COM } else if (cmd & STMF_CMD_LPORT_OP) { 34937836SJohn.Forte@Sun.COM ilport = stmf_lookup_lport((stmf_local_port_t *)obj); 34947836SJohn.Forte@Sun.COM if (ilport == NULL) { 34957836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 34967836SJohn.Forte@Sun.COM } 34977836SJohn.Forte@Sun.COM } else { 34987836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 34997836SJohn.Forte@Sun.COM } 35007836SJohn.Forte@Sun.COM 35017836SJohn.Forte@Sun.COM switch (cmd) { 35027836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 35037836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_ONLINE) { 35047836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 35057836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35067836SJohn.Forte@Sun.COM } 35077836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINE) { 35087836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 35097836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35107836SJohn.Forte@Sun.COM } 35117836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINING; 35127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35137836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 35147836SJohn.Forte@Sun.COM break; 35157836SJohn.Forte@Sun.COM 35167836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE_COMPLETE: 35177836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINING) { 35187836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 35197836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35207836SJohn.Forte@Sun.COM } 35217836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 35227836SJohn.Forte@Sun.COM STMF_SUCCESS) { 35237836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 35247836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35257836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 35267836SJohn.Forte@Sun.COM STMF_ACK_LU_ONLINE_COMPLETE, arg); 35277836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 35287836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 35297836SJohn.Forte@Sun.COM } else { 35307836SJohn.Forte@Sun.COM /* XXX: should throw a meesage an record more data */ 35317836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 35327836SJohn.Forte@Sun.COM } 35337836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 35347836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35357836SJohn.Forte@Sun.COM 35367836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 35377836SJohn.Forte@Sun.COM if (ilu->ilu_state == STMF_STATE_OFFLINE) { 35387836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 35397836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35407836SJohn.Forte@Sun.COM } 35417836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_ONLINE) { 35427836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 35437836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35447836SJohn.Forte@Sun.COM } 35457836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINING; 35467836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35477836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 35487836SJohn.Forte@Sun.COM break; 35497836SJohn.Forte@Sun.COM 35507836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE_COMPLETE: 35517836SJohn.Forte@Sun.COM if (ilu->ilu_state != STMF_STATE_OFFLINING) { 35527836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 35537836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35547836SJohn.Forte@Sun.COM } 35557836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 35567836SJohn.Forte@Sun.COM STMF_SUCCESS) { 35577836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_OFFLINE; 35587836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35597836SJohn.Forte@Sun.COM ((stmf_lu_t *)obj)->lu_ctl((stmf_lu_t *)obj, 35607836SJohn.Forte@Sun.COM STMF_ACK_LU_OFFLINE_COMPLETE, arg); 35617836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 35627836SJohn.Forte@Sun.COM } else { 35637836SJohn.Forte@Sun.COM ilu->ilu_state = STMF_STATE_ONLINE; 35647836SJohn.Forte@Sun.COM stmf_add_lu_to_active_sessions((stmf_lu_t *)obj); 35657836SJohn.Forte@Sun.COM } 35667836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 35677836SJohn.Forte@Sun.COM break; 35687836SJohn.Forte@Sun.COM 35697836SJohn.Forte@Sun.COM /* 35707836SJohn.Forte@Sun.COM * LPORT_ONLINE/OFFLINE has nothing to do with link offline/online. 35717836SJohn.Forte@Sun.COM * It's related with hardware disable/enable. 35727836SJohn.Forte@Sun.COM */ 35737836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 35747836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_ONLINE) { 35757836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 35767836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35777836SJohn.Forte@Sun.COM } 35787836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINE) { 35797836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 35807836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35817836SJohn.Forte@Sun.COM } 35827836SJohn.Forte@Sun.COM 35837836SJohn.Forte@Sun.COM /* 35847836SJohn.Forte@Sun.COM * Only user request can recover the port from the 35857836SJohn.Forte@Sun.COM * FORCED_OFFLINE state 35867836SJohn.Forte@Sun.COM */ 35877836SJohn.Forte@Sun.COM if (ilport->ilport_flags & ILPORT_FORCED_OFFLINE) { 35887836SJohn.Forte@Sun.COM if (!(ssci->st_rflags & STMF_RFLAG_USER_REQUEST)) { 35897836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 35907836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 35917836SJohn.Forte@Sun.COM } 35927836SJohn.Forte@Sun.COM } 35937836SJohn.Forte@Sun.COM 35947836SJohn.Forte@Sun.COM /* 35957836SJohn.Forte@Sun.COM * Avoid too frequent request to online 35967836SJohn.Forte@Sun.COM */ 35977836SJohn.Forte@Sun.COM if (ssci->st_rflags & STMF_RFLAG_USER_REQUEST) { 35987836SJohn.Forte@Sun.COM ilport->ilport_online_times = 0; 35997836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 0; 36007836SJohn.Forte@Sun.COM } 36017836SJohn.Forte@Sun.COM if ((ilport->ilport_avg_interval < STMF_AVG_ONLINE_INTERVAL) && 36027836SJohn.Forte@Sun.COM (ilport->ilport_online_times >= 4)) { 36037836SJohn.Forte@Sun.COM ret = STMF_FAILURE; 36047836SJohn.Forte@Sun.COM ilport->ilport_flags |= ILPORT_FORCED_OFFLINE; 36057836SJohn.Forte@Sun.COM stmf_trace(NULL, "stmf_ctl: too frequent request to " 36067836SJohn.Forte@Sun.COM "online the port"); 36077836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_ctl: too frequent request to " 36087836SJohn.Forte@Sun.COM "online the port, set FORCED_OFFLINE now"); 36097836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36107836SJohn.Forte@Sun.COM } 36117836SJohn.Forte@Sun.COM if (ilport->ilport_online_times > 0) { 36127836SJohn.Forte@Sun.COM if (ilport->ilport_online_times == 1) { 36137836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = ddi_get_lbolt() - 36147836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock; 36157836SJohn.Forte@Sun.COM } else { 36167836SJohn.Forte@Sun.COM ilport->ilport_avg_interval = 36177836SJohn.Forte@Sun.COM (ilport->ilport_avg_interval + 36187836SJohn.Forte@Sun.COM ddi_get_lbolt() - 36197836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock) >> 1; 36207836SJohn.Forte@Sun.COM } 36217836SJohn.Forte@Sun.COM } 36227836SJohn.Forte@Sun.COM ilport->ilport_last_online_clock = ddi_get_lbolt(); 36237836SJohn.Forte@Sun.COM ilport->ilport_online_times++; 36247836SJohn.Forte@Sun.COM 36257836SJohn.Forte@Sun.COM /* 36267836SJohn.Forte@Sun.COM * Submit online service request 36277836SJohn.Forte@Sun.COM */ 36287836SJohn.Forte@Sun.COM ilport->ilport_flags &= ~ILPORT_FORCED_OFFLINE; 36297836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINING; 36307836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36317836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 36327836SJohn.Forte@Sun.COM break; 36337836SJohn.Forte@Sun.COM 36347836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE_COMPLETE: 36357836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINING) { 36367836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 36377836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36387836SJohn.Forte@Sun.COM } 36397836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 36407836SJohn.Forte@Sun.COM STMF_SUCCESS) { 36417836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 36427836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36437836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 36447836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 36457836SJohn.Forte@Sun.COM STMF_ACK_LPORT_ONLINE_COMPLETE, arg); 36467836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 36477836SJohn.Forte@Sun.COM } else { 36487836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 36497836SJohn.Forte@Sun.COM } 36507836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 36517836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36527836SJohn.Forte@Sun.COM 36537836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 36547836SJohn.Forte@Sun.COM if (ilport->ilport_state == STMF_STATE_OFFLINE) { 36557836SJohn.Forte@Sun.COM ret = STMF_ALREADY; 36567836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36577836SJohn.Forte@Sun.COM } 36587836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_ONLINE) { 36597836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 36607836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36617836SJohn.Forte@Sun.COM } 36627836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINING; 36637836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36647836SJohn.Forte@Sun.COM stmf_svc_queue(cmd, obj, (stmf_state_change_info_t *)arg); 36657836SJohn.Forte@Sun.COM break; 36667836SJohn.Forte@Sun.COM 36677836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE_COMPLETE: 36687836SJohn.Forte@Sun.COM if (ilport->ilport_state != STMF_STATE_OFFLINING) { 36697836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 36707836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36717836SJohn.Forte@Sun.COM } 36727836SJohn.Forte@Sun.COM if (((stmf_change_status_t *)arg)->st_completion_status == 36737836SJohn.Forte@Sun.COM STMF_SUCCESS) { 36747836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_OFFLINE; 36757836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36767836SJohn.Forte@Sun.COM ((stmf_local_port_t *)obj)->lport_ctl( 36777836SJohn.Forte@Sun.COM (stmf_local_port_t *)obj, 36787836SJohn.Forte@Sun.COM STMF_ACK_LPORT_OFFLINE_COMPLETE, arg); 36797836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 36807836SJohn.Forte@Sun.COM } else { 36817836SJohn.Forte@Sun.COM ilport->ilport_state = STMF_STATE_ONLINE; 36827836SJohn.Forte@Sun.COM } 36837836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36847836SJohn.Forte@Sun.COM break; 36857836SJohn.Forte@Sun.COM 36867836SJohn.Forte@Sun.COM default: 36877836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid ctl cmd received %x", cmd); 36887836SJohn.Forte@Sun.COM ret = STMF_INVALID_ARG; 36897836SJohn.Forte@Sun.COM goto stmf_ctl_lock_exit; 36907836SJohn.Forte@Sun.COM } 36917836SJohn.Forte@Sun.COM 36927836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 36937836SJohn.Forte@Sun.COM 36947836SJohn.Forte@Sun.COM stmf_ctl_lock_exit:; 36957836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 36967836SJohn.Forte@Sun.COM return (ret); 36977836SJohn.Forte@Sun.COM } 36987836SJohn.Forte@Sun.COM 36997836SJohn.Forte@Sun.COM /* ARGSUSED */ 37007836SJohn.Forte@Sun.COM stmf_status_t 37017836SJohn.Forte@Sun.COM stmf_info_impl(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 37027836SJohn.Forte@Sun.COM uint32_t *bufsizep) 37037836SJohn.Forte@Sun.COM { 37047836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 37057836SJohn.Forte@Sun.COM } 37067836SJohn.Forte@Sun.COM 37077836SJohn.Forte@Sun.COM /* ARGSUSED */ 37087836SJohn.Forte@Sun.COM stmf_status_t 37097836SJohn.Forte@Sun.COM stmf_info(uint32_t cmd, void *arg1, void *arg2, uint8_t *buf, 37107836SJohn.Forte@Sun.COM uint32_t *bufsizep) 37117836SJohn.Forte@Sun.COM { 37127836SJohn.Forte@Sun.COM uint32_t cl = SI_GET_CLASS(cmd); 37137836SJohn.Forte@Sun.COM 37147836SJohn.Forte@Sun.COM if (cl == SI_STMF) { 37157836SJohn.Forte@Sun.COM return (stmf_info_impl(cmd, arg1, arg2, buf, bufsizep)); 37167836SJohn.Forte@Sun.COM } 37177836SJohn.Forte@Sun.COM if (cl == SI_LPORT) { 37187836SJohn.Forte@Sun.COM return (((stmf_local_port_t *)arg1)->lport_info(cmd, 37197836SJohn.Forte@Sun.COM arg1, arg2, buf, bufsizep)); 37207836SJohn.Forte@Sun.COM } else if (cl == SI_LU) { 37217836SJohn.Forte@Sun.COM return (((stmf_lu_t *)arg1)->lu_info(cmd, arg1, arg2, 37227836SJohn.Forte@Sun.COM buf, bufsizep)); 37237836SJohn.Forte@Sun.COM } 37247836SJohn.Forte@Sun.COM 37257836SJohn.Forte@Sun.COM return (STMF_NOT_SUPPORTED); 37267836SJohn.Forte@Sun.COM } 37277836SJohn.Forte@Sun.COM 37287836SJohn.Forte@Sun.COM /* 37297836SJohn.Forte@Sun.COM * Used by port providers. pwwn is 8 byte wwn, sdid is th devid used by 37307836SJohn.Forte@Sun.COM * stmf to register local ports. The ident should have 20 bytes in buffer 37317836SJohn.Forte@Sun.COM * space to convert the wwn to "wwn.xxxxxxxxxxxxxxxx" string. 37327836SJohn.Forte@Sun.COM */ 37337836SJohn.Forte@Sun.COM void 37347836SJohn.Forte@Sun.COM stmf_wwn_to_devid_desc(scsi_devid_desc_t *sdid, uint8_t *wwn, 37357836SJohn.Forte@Sun.COM uint8_t protocol_id) 37367836SJohn.Forte@Sun.COM { 37377836SJohn.Forte@Sun.COM sdid->protocol_id = protocol_id; 37387836SJohn.Forte@Sun.COM sdid->piv = 1; 37397836SJohn.Forte@Sun.COM sdid->code_set = CODE_SET_ASCII; 37407836SJohn.Forte@Sun.COM sdid->association = ID_IS_TARGET_PORT; 37417836SJohn.Forte@Sun.COM sdid->ident_length = 20; 37427836SJohn.Forte@Sun.COM (void) sprintf((char *)sdid->ident, 37437836SJohn.Forte@Sun.COM "wwn.%02X%02X%02X%02X%02X%02X%02X%02X", 37447836SJohn.Forte@Sun.COM wwn[0], wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]); 37457836SJohn.Forte@Sun.COM } 37467836SJohn.Forte@Sun.COM 37477836SJohn.Forte@Sun.COM stmf_xfer_data_t * 37487836SJohn.Forte@Sun.COM stmf_prepare_tpgs_data() 37497836SJohn.Forte@Sun.COM { 37507836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 37517836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 37527836SJohn.Forte@Sun.COM uint8_t *p; 37537836SJohn.Forte@Sun.COM uint32_t sz, asz, nports; 37547836SJohn.Forte@Sun.COM 37557836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 37567836SJohn.Forte@Sun.COM /* The spec only allows for 255 ports to be reported */ 37577836SJohn.Forte@Sun.COM nports = min(stmf_state.stmf_nlports, 255); 37587836SJohn.Forte@Sun.COM sz = (nports * 4) + 12; 37597836SJohn.Forte@Sun.COM asz = sz + sizeof (*xd) - 4; 37607836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)kmem_zalloc(asz, KM_NOSLEEP); 37617836SJohn.Forte@Sun.COM if (xd == NULL) { 37627836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 37637836SJohn.Forte@Sun.COM return (NULL); 37647836SJohn.Forte@Sun.COM } 37657836SJohn.Forte@Sun.COM xd->alloc_size = asz; 37667836SJohn.Forte@Sun.COM xd->size_left = sz; 37677836SJohn.Forte@Sun.COM 37687836SJohn.Forte@Sun.COM p = xd->buf; 37697836SJohn.Forte@Sun.COM 37707836SJohn.Forte@Sun.COM *((uint32_t *)p) = BE_32(sz - 4); 37717836SJohn.Forte@Sun.COM p += 4; 37727836SJohn.Forte@Sun.COM p[0] = 0x80; /* PREF */ 37737836SJohn.Forte@Sun.COM p[1] = 1; /* AO_SUP */ 37747836SJohn.Forte@Sun.COM p[7] = nports & 0xff; 37757836SJohn.Forte@Sun.COM p += 8; 37767836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport && nports; 37777836SJohn.Forte@Sun.COM nports++, ilport = ilport->ilport_next, p += 4) { 37787836SJohn.Forte@Sun.COM ((uint16_t *)p)[1] = BE_16(ilport->ilport_rtpid); 37797836SJohn.Forte@Sun.COM } 37807836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 37817836SJohn.Forte@Sun.COM 37827836SJohn.Forte@Sun.COM return (xd); 37837836SJohn.Forte@Sun.COM } 37847836SJohn.Forte@Sun.COM 37857836SJohn.Forte@Sun.COM 37867836SJohn.Forte@Sun.COM static uint16_t stmf_lu_id_gen_number = 0; 37877836SJohn.Forte@Sun.COM extern char hw_serial[]; 37887836SJohn.Forte@Sun.COM 37897836SJohn.Forte@Sun.COM stmf_status_t 37907836SJohn.Forte@Sun.COM stmf_scsilib_uniq_lu_id(uint32_t company_id, scsi_devid_desc_t *lu_id) 37917836SJohn.Forte@Sun.COM { 37927836SJohn.Forte@Sun.COM uint8_t *p; 37937836SJohn.Forte@Sun.COM struct timeval32 timestamp32; 37947836SJohn.Forte@Sun.COM uint32_t *t = (uint32_t *)×tamp32; 37957836SJohn.Forte@Sun.COM struct ether_addr mac; 37967836SJohn.Forte@Sun.COM uint8_t *e = (uint8_t *)&mac; 37977836SJohn.Forte@Sun.COM 37987836SJohn.Forte@Sun.COM if (company_id == COMPANY_ID_NONE) 37997836SJohn.Forte@Sun.COM company_id = COMPANY_ID_SUN; 38007836SJohn.Forte@Sun.COM 38017836SJohn.Forte@Sun.COM if (lu_id->ident_length != 0x10) 38027836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 38037836SJohn.Forte@Sun.COM 38047836SJohn.Forte@Sun.COM p = (uint8_t *)lu_id; 38057836SJohn.Forte@Sun.COM 38067836SJohn.Forte@Sun.COM atomic_add_16(&stmf_lu_id_gen_number, 1); 38077836SJohn.Forte@Sun.COM 38087836SJohn.Forte@Sun.COM p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10; 38097836SJohn.Forte@Sun.COM p[4] = ((company_id >> 20) & 0xf) | 0x60; 38107836SJohn.Forte@Sun.COM p[5] = (company_id >> 12) & 0xff; 38117836SJohn.Forte@Sun.COM p[6] = (company_id >> 4) & 0xff; 38127836SJohn.Forte@Sun.COM p[7] = (company_id << 4) & 0xf0; 38137836SJohn.Forte@Sun.COM if (!localetheraddr((struct ether_addr *)NULL, &mac)) { 38147836SJohn.Forte@Sun.COM char *hp = &hw_serial[0]; 38157836SJohn.Forte@Sun.COM int hid = BE_32(stoi(&hp)); 38167836SJohn.Forte@Sun.COM 38177836SJohn.Forte@Sun.COM e[0] = (hid >> 24) & 0xff; 38187836SJohn.Forte@Sun.COM e[1] = (hid >> 16) & 0xff; 38197836SJohn.Forte@Sun.COM e[2] = (hid >> 8) & 0xff; 38207836SJohn.Forte@Sun.COM e[3] = hid & 0xff; 38217836SJohn.Forte@Sun.COM e[4] = e[5] = 0; 38227836SJohn.Forte@Sun.COM } 38237836SJohn.Forte@Sun.COM bcopy(e, p+8, 6); 38247836SJohn.Forte@Sun.COM uniqtime32(×tamp32); 38257836SJohn.Forte@Sun.COM *t = BE_32(*t); 38267836SJohn.Forte@Sun.COM bcopy(t, p+14, 4); 38277836SJohn.Forte@Sun.COM p[18] = (stmf_lu_id_gen_number >> 8) & 0xff; 38287836SJohn.Forte@Sun.COM p[19] = stmf_lu_id_gen_number & 0xff; 38297836SJohn.Forte@Sun.COM 38307836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 38317836SJohn.Forte@Sun.COM } 38327836SJohn.Forte@Sun.COM 38337836SJohn.Forte@Sun.COM /* 38347836SJohn.Forte@Sun.COM * saa is sense key, ASC, ASCQ 38357836SJohn.Forte@Sun.COM */ 38367836SJohn.Forte@Sun.COM void 38377836SJohn.Forte@Sun.COM stmf_scsilib_send_status(scsi_task_t *task, uint8_t st, uint32_t saa) 38387836SJohn.Forte@Sun.COM { 38397836SJohn.Forte@Sun.COM uint8_t sd[18]; 38407836SJohn.Forte@Sun.COM task->task_scsi_status = st; 38417836SJohn.Forte@Sun.COM if (st == 2) { 38427836SJohn.Forte@Sun.COM bzero(sd, 18); 38437836SJohn.Forte@Sun.COM sd[0] = 0x70; 38447836SJohn.Forte@Sun.COM sd[2] = (saa >> 16) & 0xf; 38457836SJohn.Forte@Sun.COM sd[7] = 10; 38467836SJohn.Forte@Sun.COM sd[12] = (saa >> 8) & 0xff; 38477836SJohn.Forte@Sun.COM sd[13] = saa & 0xff; 38487836SJohn.Forte@Sun.COM task->task_sense_data = sd; 38497836SJohn.Forte@Sun.COM task->task_sense_length = 18; 38507836SJohn.Forte@Sun.COM } else { 38517836SJohn.Forte@Sun.COM task->task_sense_data = NULL; 38527836SJohn.Forte@Sun.COM task->task_sense_length = 0; 38537836SJohn.Forte@Sun.COM } 38547836SJohn.Forte@Sun.COM (void) stmf_send_scsi_status(task, STMF_IOF_LU_DONE); 38557836SJohn.Forte@Sun.COM } 38567836SJohn.Forte@Sun.COM 38577836SJohn.Forte@Sun.COM uint32_t 38587836SJohn.Forte@Sun.COM stmf_scsilib_prepare_vpd_page83(scsi_task_t *task, uint8_t *page, 38597836SJohn.Forte@Sun.COM uint32_t page_len, uint8_t byte0, uint32_t vpd_mask) 38607836SJohn.Forte@Sun.COM { 38617836SJohn.Forte@Sun.COM uint8_t *p = NULL; 38627836SJohn.Forte@Sun.COM uint8_t small_buf[32]; 38637836SJohn.Forte@Sun.COM uint32_t sz = 0; 38647836SJohn.Forte@Sun.COM uint32_t n = 4; 38657836SJohn.Forte@Sun.COM uint32_t m = 0; 38667836SJohn.Forte@Sun.COM uint32_t last_bit = 0; 38677836SJohn.Forte@Sun.COM 38687836SJohn.Forte@Sun.COM if (page_len < 4) 38697836SJohn.Forte@Sun.COM return (0); 38707836SJohn.Forte@Sun.COM if (page_len > 65535) 38717836SJohn.Forte@Sun.COM page_len = 65535; 38727836SJohn.Forte@Sun.COM 38737836SJohn.Forte@Sun.COM page[0] = byte0; 38747836SJohn.Forte@Sun.COM page[1] = 0x83; 38757836SJohn.Forte@Sun.COM 38767836SJohn.Forte@Sun.COM /* CONSTCOND */ 38777836SJohn.Forte@Sun.COM while (1) { 38787836SJohn.Forte@Sun.COM m += sz; 38797836SJohn.Forte@Sun.COM if (sz && (page_len > n)) { 38807836SJohn.Forte@Sun.COM uint32_t copysz; 38817836SJohn.Forte@Sun.COM copysz = page_len > (n + sz) ? sz : page_len - n; 38827836SJohn.Forte@Sun.COM bcopy(p, page + n, copysz); 38837836SJohn.Forte@Sun.COM n += copysz; 38847836SJohn.Forte@Sun.COM } 38857836SJohn.Forte@Sun.COM vpd_mask &= ~last_bit; 38867836SJohn.Forte@Sun.COM if (vpd_mask == 0) 38877836SJohn.Forte@Sun.COM break; 38887836SJohn.Forte@Sun.COM 38897836SJohn.Forte@Sun.COM if (vpd_mask & STMF_VPD_LU_ID) { 38907836SJohn.Forte@Sun.COM last_bit = STMF_VPD_LU_ID; 38917836SJohn.Forte@Sun.COM sz = task->task_lu->lu_id->ident_length + 4; 38927836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lu->lu_id; 38937836SJohn.Forte@Sun.COM continue; 38947836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TARGET_ID) { 38957836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TARGET_ID; 38967836SJohn.Forte@Sun.COM sz = task->task_lport->lport_id->ident_length + 4; 38977836SJohn.Forte@Sun.COM p = (uint8_t *)task->task_lport->lport_id; 38987836SJohn.Forte@Sun.COM continue; 38997836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_TP_GROUP) { 39007836SJohn.Forte@Sun.COM last_bit = STMF_VPD_TP_GROUP; 39017836SJohn.Forte@Sun.COM p = small_buf; 39027836SJohn.Forte@Sun.COM bzero(p, 8); 39037836SJohn.Forte@Sun.COM p[0] = 1; 39047836SJohn.Forte@Sun.COM p[1] = 0x15; 39057836SJohn.Forte@Sun.COM p[3] = 4; 39067836SJohn.Forte@Sun.COM /* Group ID is always 0 */ 39077836SJohn.Forte@Sun.COM sz = 8; 39087836SJohn.Forte@Sun.COM continue; 39097836SJohn.Forte@Sun.COM } else if (vpd_mask & STMF_VPD_RELATIVE_TP_ID) { 39107836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport; 39117836SJohn.Forte@Sun.COM 39127836SJohn.Forte@Sun.COM last_bit = STMF_VPD_RELATIVE_TP_ID; 39137836SJohn.Forte@Sun.COM p = small_buf; 39147836SJohn.Forte@Sun.COM bzero(p, 8); 39157836SJohn.Forte@Sun.COM p[0] = 1; 39167836SJohn.Forte@Sun.COM p[1] = 0x14; 39177836SJohn.Forte@Sun.COM p[3] = 4; 39187836SJohn.Forte@Sun.COM ilport = (stmf_i_local_port_t *) 39197836SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private; 39207836SJohn.Forte@Sun.COM p[6] = (ilport->ilport_rtpid >> 8) & 0xff; 39217836SJohn.Forte@Sun.COM p[7] = ilport->ilport_rtpid & 0xff; 39227836SJohn.Forte@Sun.COM sz = 8; 39237836SJohn.Forte@Sun.COM continue; 39247836SJohn.Forte@Sun.COM } else { 39257836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "Invalid vpd_mask"); 39267836SJohn.Forte@Sun.COM break; 39277836SJohn.Forte@Sun.COM } 39287836SJohn.Forte@Sun.COM } 39297836SJohn.Forte@Sun.COM 39307836SJohn.Forte@Sun.COM page[2] = (m >> 8) & 0xff; 39317836SJohn.Forte@Sun.COM page[3] = m & 0xff; 39327836SJohn.Forte@Sun.COM 39337836SJohn.Forte@Sun.COM return (n); 39347836SJohn.Forte@Sun.COM } 39357836SJohn.Forte@Sun.COM 39367836SJohn.Forte@Sun.COM void 39377836SJohn.Forte@Sun.COM stmf_scsilib_handle_report_tpgs(scsi_task_t *task, stmf_data_buf_t *dbuf) 39387836SJohn.Forte@Sun.COM { 39397836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 39407836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 39417836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 39427836SJohn.Forte@Sun.COM uint32_t sz, minsz; 39437836SJohn.Forte@Sun.COM 39447836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING; 39457836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 39467836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 39477836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 39487836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 39497836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 39507836SJohn.Forte@Sun.COM 39517836SJohn.Forte@Sun.COM if (task->task_additional_flags & 39527836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 39537836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 39547836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 39557836SJohn.Forte@Sun.COM } 39567836SJohn.Forte@Sun.COM 39577836SJohn.Forte@Sun.COM if (task->task_cmd_xfer_length < 16) { 39587836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 39597836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 39607836SJohn.Forte@Sun.COM return; 39617836SJohn.Forte@Sun.COM } 39627836SJohn.Forte@Sun.COM 39637836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 39647836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 39657836SJohn.Forte@Sun.COM 39667836SJohn.Forte@Sun.COM xd = stmf_prepare_tpgs_data(); 39677836SJohn.Forte@Sun.COM 39687836SJohn.Forte@Sun.COM if (xd == NULL) { 39697836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 39707836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 39717836SJohn.Forte@Sun.COM return; 39727836SJohn.Forte@Sun.COM } 39737836SJohn.Forte@Sun.COM 39747836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 39757836SJohn.Forte@Sun.COM xd->size_left = sz; 39767836SJohn.Forte@Sun.COM minsz = min(512, sz); 39777836SJohn.Forte@Sun.COM 39787836SJohn.Forte@Sun.COM if (dbuf == NULL) 39797836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 39807836SJohn.Forte@Sun.COM if (dbuf == NULL) { 39817836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 39827836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 39837836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 39847836SJohn.Forte@Sun.COM return; 39857836SJohn.Forte@Sun.COM } 39867836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 39877836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 39887836SJohn.Forte@Sun.COM 39897836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 39907836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 39917836SJohn.Forte@Sun.COM 39927836SJohn.Forte@Sun.COM } 39937836SJohn.Forte@Sun.COM 39947836SJohn.Forte@Sun.COM void 39957836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(scsi_task_t *task) 39967836SJohn.Forte@Sun.COM { 39977836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 39987836SJohn.Forte@Sun.COM /* 39997836SJohn.Forte@Sun.COM * For now we will abort all I/Os on the LU in case of ABORT_TASK_SET 40007836SJohn.Forte@Sun.COM * and ABORT_TASK. But unlike LUN_RESET we will not reset LU state 40017836SJohn.Forte@Sun.COM * in these cases. This needs to be changed to abort only the required 40027836SJohn.Forte@Sun.COM * set. 40037836SJohn.Forte@Sun.COM */ 40047836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 40057836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 40067836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 40077836SJohn.Forte@Sun.COM case TM_LUN_RESET: 40087836SJohn.Forte@Sun.COM stmf_handle_lun_reset(task); 40097836SJohn.Forte@Sun.COM return; 40107836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 40117836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 40127836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 40137836SJohn.Forte@Sun.COM stmf_handle_target_reset(task); 40147836SJohn.Forte@Sun.COM return; 40157836SJohn.Forte@Sun.COM default: 40167836SJohn.Forte@Sun.COM /* We dont support this task mgmt function */ 40177836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 40187836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CMD_IU); 40197836SJohn.Forte@Sun.COM return; 40207836SJohn.Forte@Sun.COM } 40217836SJohn.Forte@Sun.COM } 40227836SJohn.Forte@Sun.COM 40237836SJohn.Forte@Sun.COM void 40247836SJohn.Forte@Sun.COM stmf_handle_lun_reset(scsi_task_t *task) 40257836SJohn.Forte@Sun.COM { 40267836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 40277836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 40287836SJohn.Forte@Sun.COM 40297836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 40307836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 40317836SJohn.Forte@Sun.COM 40327836SJohn.Forte@Sun.COM /* 40337836SJohn.Forte@Sun.COM * To sync with target reset, grab this lock. The LU is not going 40347836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 40357836SJohn.Forte@Sun.COM */ 40367836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 40377836SJohn.Forte@Sun.COM 40387836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 40397836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40407836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 40417836SJohn.Forte@Sun.COM STMF_SAA_OPERATION_IN_PROGRESS); 40427836SJohn.Forte@Sun.COM return; 40437836SJohn.Forte@Sun.COM } 40447836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 40457836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40467836SJohn.Forte@Sun.COM 40477836SJohn.Forte@Sun.COM /* 40487836SJohn.Forte@Sun.COM * Mark this task as the one causing LU reset so that we know who 40497836SJohn.Forte@Sun.COM * was responsible for setting the ILU_RESET_ACTIVE. In case this 40507836SJohn.Forte@Sun.COM * task itself gets aborted, we will clear ILU_RESET_ACTIVE. 40517836SJohn.Forte@Sun.COM */ 40527836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | ITASK_CAUSING_LU_RESET; 40537836SJohn.Forte@Sun.COM 40547836SJohn.Forte@Sun.COM /* Initiatiate abort on all commands on this LU except this one */ 40557836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, task->task_lu); 40567836SJohn.Forte@Sun.COM 40577836SJohn.Forte@Sun.COM /* Start polling on this task */ 40587836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 40597836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 40607836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 40617836SJohn.Forte@Sun.COM NULL); 40627836SJohn.Forte@Sun.COM return; 40637836SJohn.Forte@Sun.COM } 40647836SJohn.Forte@Sun.COM } 40657836SJohn.Forte@Sun.COM 40667836SJohn.Forte@Sun.COM void 40677836SJohn.Forte@Sun.COM stmf_handle_target_reset(scsi_task_t *task) 40687836SJohn.Forte@Sun.COM { 40697836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 40707836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 40717836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 40727836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 40737836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 40747836SJohn.Forte@Sun.COM int i, lf; 40757836SJohn.Forte@Sun.COM 40767836SJohn.Forte@Sun.COM itask = (stmf_i_scsi_task_t *)task->task_stmf_private; 40777836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *)task->task_session->ss_stmf_private; 40787836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 40797836SJohn.Forte@Sun.COM 40807836SJohn.Forte@Sun.COM /* 40817836SJohn.Forte@Sun.COM * To sync with LUN reset, grab this lock. The session is not going 40827836SJohn.Forte@Sun.COM * anywhere as there is atleast one task pending (this task). 40837836SJohn.Forte@Sun.COM */ 40847836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 4085*7979SSumit.Gupta@Sun.COM 4086*7979SSumit.Gupta@Sun.COM /* Grab the session lock as a writer to prevent any changes in it */ 4087*7979SSumit.Gupta@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 4088*7979SSumit.Gupta@Sun.COM 40897836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_RESET_ACTIVE) { 4090*7979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 40917836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 40927836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 40937836SJohn.Forte@Sun.COM STMF_SAA_OPERATION_IN_PROGRESS); 40947836SJohn.Forte@Sun.COM return; 40957836SJohn.Forte@Sun.COM } 40967836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, ISS_RESET_ACTIVE); 40977836SJohn.Forte@Sun.COM 40987836SJohn.Forte@Sun.COM /* 40997836SJohn.Forte@Sun.COM * Now go through each LUN in this session and make sure all of them 41007836SJohn.Forte@Sun.COM * can be reset. 41017836SJohn.Forte@Sun.COM */ 41027836SJohn.Forte@Sun.COM lm = iss->iss_sm; 41037836SJohn.Forte@Sun.COM for (i = 0, lf = 0; i < lm->lm_nentries; i++) { 41047836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 41057836SJohn.Forte@Sun.COM continue; 41067836SJohn.Forte@Sun.COM lf++; 41077836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 41087836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 41097836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 41107836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 4111*7979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 41127836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41137836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 41147836SJohn.Forte@Sun.COM STMF_SAA_OPERATION_IN_PROGRESS); 41157836SJohn.Forte@Sun.COM return; 41167836SJohn.Forte@Sun.COM } 41177836SJohn.Forte@Sun.COM } 41187836SJohn.Forte@Sun.COM if (lf == 0) { 41197836SJohn.Forte@Sun.COM /* No luns in this session */ 41207836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 4121*7979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 41227836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41237836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 41247836SJohn.Forte@Sun.COM return; 41257836SJohn.Forte@Sun.COM } 41267836SJohn.Forte@Sun.COM 41277836SJohn.Forte@Sun.COM /* ok, start the damage */ 41287836SJohn.Forte@Sun.COM itask->itask_flags |= ITASK_DEFAULT_HANDLING | 41297836SJohn.Forte@Sun.COM ITASK_CAUSING_TARGET_RESET; 41307836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 41317836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 41327836SJohn.Forte@Sun.COM continue; 41337836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 41347836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)(lm_ent->ent_lu->lu_stmf_private); 41357836SJohn.Forte@Sun.COM atomic_or_32(&ilu->ilu_flags, ILU_RESET_ACTIVE); 41367836SJohn.Forte@Sun.COM } 4137*7979SSumit.Gupta@Sun.COM rw_exit(iss->iss_lockp); 41387836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 41397836SJohn.Forte@Sun.COM 41407836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 41417836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 41427836SJohn.Forte@Sun.COM continue; 41437836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 41447836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_ABORT_LU, task, STMF_ABORTED, 41457836SJohn.Forte@Sun.COM lm_ent->ent_lu); 41467836SJohn.Forte@Sun.COM } 41477836SJohn.Forte@Sun.COM 41487836SJohn.Forte@Sun.COM /* Start polling on this task */ 41497836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 41507836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 41517836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, STMF_ALLOC_FAILURE, 41527836SJohn.Forte@Sun.COM NULL); 41537836SJohn.Forte@Sun.COM return; 41547836SJohn.Forte@Sun.COM } 41557836SJohn.Forte@Sun.COM } 41567836SJohn.Forte@Sun.COM 41577836SJohn.Forte@Sun.COM int 41587836SJohn.Forte@Sun.COM stmf_handle_cmd_during_ic(stmf_i_scsi_task_t *itask) 41597836SJohn.Forte@Sun.COM { 41607836SJohn.Forte@Sun.COM scsi_task_t *task = itask->itask_task; 41617836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 41627836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 41637836SJohn.Forte@Sun.COM 41647836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 41657836SJohn.Forte@Sun.COM if (((iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) == 0) || 41667836SJohn.Forte@Sun.COM (task->task_cdb[0] == SCMD_INQUIRY)) { 41677836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 41687836SJohn.Forte@Sun.COM return (0); 41697836SJohn.Forte@Sun.COM } 41707836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 41717836SJohn.Forte@Sun.COM ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 41727836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 41737836SJohn.Forte@Sun.COM 41747836SJohn.Forte@Sun.COM if (task->task_cdb[0] == SCMD_REPORT_LUNS) { 41757836SJohn.Forte@Sun.COM return (0); 41767836SJohn.Forte@Sun.COM } 41777836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 41787836SJohn.Forte@Sun.COM STMF_SAA_REPORT_LUN_DATA_HAS_CHANGED); 41797836SJohn.Forte@Sun.COM return (1); 41807836SJohn.Forte@Sun.COM } 41817836SJohn.Forte@Sun.COM 41827836SJohn.Forte@Sun.COM void 41837836SJohn.Forte@Sun.COM stmf_worker_init() 41847836SJohn.Forte@Sun.COM { 41857836SJohn.Forte@Sun.COM uint32_t i; 41867836SJohn.Forte@Sun.COM 41877836SJohn.Forte@Sun.COM /* Make local copy of global tunables */ 41887836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_max_nworkers; 41897836SJohn.Forte@Sun.COM stmf_i_min_nworkers = stmf_min_nworkers; 41907836SJohn.Forte@Sun.COM 41917836SJohn.Forte@Sun.COM ASSERT(stmf_workers == NULL); 41927836SJohn.Forte@Sun.COM if (stmf_i_min_nworkers < 4) { 41937836SJohn.Forte@Sun.COM stmf_i_min_nworkers = 4; 41947836SJohn.Forte@Sun.COM } 41957836SJohn.Forte@Sun.COM if (stmf_i_max_nworkers < stmf_i_min_nworkers) { 41967836SJohn.Forte@Sun.COM stmf_i_max_nworkers = stmf_i_min_nworkers; 41977836SJohn.Forte@Sun.COM } 41987836SJohn.Forte@Sun.COM stmf_workers = (stmf_worker_t *)kmem_zalloc( 41997836SJohn.Forte@Sun.COM sizeof (stmf_worker_t) * stmf_i_max_nworkers, KM_SLEEP); 42007836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 42017836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 42027836SJohn.Forte@Sun.COM mutex_init(&w->worker_lock, NULL, MUTEX_DRIVER, NULL); 42037836SJohn.Forte@Sun.COM cv_init(&w->worker_cv, NULL, CV_DRIVER, NULL); 42047836SJohn.Forte@Sun.COM } 42057836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 42067836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 42077836SJohn.Forte@Sun.COM 42087836SJohn.Forte@Sun.COM /* Workers will be started by stmf_worker_mgmt() */ 42097836SJohn.Forte@Sun.COM 42107836SJohn.Forte@Sun.COM /* Lets wait for atleast one worker to start */ 42117836SJohn.Forte@Sun.COM while (stmf_nworkers_cur == 0) 42127836SJohn.Forte@Sun.COM delay(drv_usectohz(20 * 1000)); 42137836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(3 * 1000 * 1000); 42147836SJohn.Forte@Sun.COM } 42157836SJohn.Forte@Sun.COM 42167836SJohn.Forte@Sun.COM stmf_status_t 42177836SJohn.Forte@Sun.COM stmf_worker_fini() 42187836SJohn.Forte@Sun.COM { 42197836SJohn.Forte@Sun.COM int i; 42207836SJohn.Forte@Sun.COM clock_t sb; 42217836SJohn.Forte@Sun.COM 42227836SJohn.Forte@Sun.COM if (stmf_workers_state == STMF_WORKERS_DISABLED) 42237836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 42247836SJohn.Forte@Sun.COM ASSERT(stmf_workers); 42257836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_DISABLED; 42267836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay = drv_usectohz(20 * 1000); 42277836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 42287836SJohn.Forte@Sun.COM 42297836SJohn.Forte@Sun.COM sb = ddi_get_lbolt() + drv_usectohz(10 * 1000 * 1000); 42307836SJohn.Forte@Sun.COM /* Wait for all the threads to die */ 42317836SJohn.Forte@Sun.COM while (stmf_nworkers_cur != 0) { 42327836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > sb) { 42337836SJohn.Forte@Sun.COM stmf_workers_state = STMF_WORKERS_ENABLED; 42347836SJohn.Forte@Sun.COM return (STMF_BUSY); 42357836SJohn.Forte@Sun.COM } 42367836SJohn.Forte@Sun.COM delay(drv_usectohz(100 * 1000)); 42377836SJohn.Forte@Sun.COM } 42387836SJohn.Forte@Sun.COM for (i = 0; i < stmf_i_max_nworkers; i++) { 42397836SJohn.Forte@Sun.COM stmf_worker_t *w = &stmf_workers[i]; 42407836SJohn.Forte@Sun.COM mutex_destroy(&w->worker_lock); 42417836SJohn.Forte@Sun.COM cv_destroy(&w->worker_cv); 42427836SJohn.Forte@Sun.COM } 42437836SJohn.Forte@Sun.COM kmem_free(stmf_workers, sizeof (stmf_worker_t) * stmf_i_max_nworkers); 42447836SJohn.Forte@Sun.COM stmf_workers = NULL; 42457836SJohn.Forte@Sun.COM 42467836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 42477836SJohn.Forte@Sun.COM } 42487836SJohn.Forte@Sun.COM 42497836SJohn.Forte@Sun.COM void 42507836SJohn.Forte@Sun.COM stmf_worker_task(void *arg) 42517836SJohn.Forte@Sun.COM { 42527836SJohn.Forte@Sun.COM stmf_worker_t *w; 42537836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 42547836SJohn.Forte@Sun.COM scsi_task_t *task; 42557836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask; 42567836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 42577836SJohn.Forte@Sun.COM stmf_lu_t *lu; 42587836SJohn.Forte@Sun.COM clock_t wait_timer = 0; 42597836SJohn.Forte@Sun.COM clock_t wait_ticks; 42607836SJohn.Forte@Sun.COM uint32_t old, new; 42617836SJohn.Forte@Sun.COM uint8_t curcmd; 42627836SJohn.Forte@Sun.COM uint8_t abort_free; 42637836SJohn.Forte@Sun.COM uint8_t wait_queue; 42647836SJohn.Forte@Sun.COM uint8_t dec_qdepth; 42657836SJohn.Forte@Sun.COM 42667836SJohn.Forte@Sun.COM w = (stmf_worker_t *)arg; 42677836SJohn.Forte@Sun.COM wait_ticks = drv_usectohz(10000); 42687836SJohn.Forte@Sun.COM 42697836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 42707836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_STARTED | STMF_WORKER_ACTIVE; 42717836SJohn.Forte@Sun.COM stmf_worker_loop:; 42727836SJohn.Forte@Sun.COM if ((w->worker_ref_count == 0) && 42737836SJohn.Forte@Sun.COM (w->worker_flags & STMF_WORKER_TERMINATE)) { 42747836SJohn.Forte@Sun.COM w->worker_flags &= ~(STMF_WORKER_STARTED | 42757836SJohn.Forte@Sun.COM STMF_WORKER_ACTIVE | STMF_WORKER_TERMINATE); 42767836SJohn.Forte@Sun.COM w->worker_tid = NULL; 42777836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 42787836SJohn.Forte@Sun.COM thread_exit(); 42797836SJohn.Forte@Sun.COM } 42807836SJohn.Forte@Sun.COM /* CONSTCOND */ 42817836SJohn.Forte@Sun.COM while (1) { 42827836SJohn.Forte@Sun.COM dec_qdepth = 0; 42837836SJohn.Forte@Sun.COM if (wait_timer && (ddi_get_lbolt() >= wait_timer)) { 42847836SJohn.Forte@Sun.COM wait_timer = 0; 4285*7979SSumit.Gupta@Sun.COM if (w->worker_wait_head) { 4286*7979SSumit.Gupta@Sun.COM ASSERT(w->worker_wait_tail); 4287*7979SSumit.Gupta@Sun.COM if (w->worker_task_head == NULL) 4288*7979SSumit.Gupta@Sun.COM w->worker_task_head = 4289*7979SSumit.Gupta@Sun.COM w->worker_wait_head; 4290*7979SSumit.Gupta@Sun.COM else 4291*7979SSumit.Gupta@Sun.COM w->worker_task_tail->itask_worker_next = 4292*7979SSumit.Gupta@Sun.COM w->worker_wait_head; 4293*7979SSumit.Gupta@Sun.COM w->worker_task_tail = w->worker_wait_tail; 4294*7979SSumit.Gupta@Sun.COM w->worker_wait_head = w->worker_wait_tail = 4295*7979SSumit.Gupta@Sun.COM NULL; 4296*7979SSumit.Gupta@Sun.COM } 42977836SJohn.Forte@Sun.COM } 42987836SJohn.Forte@Sun.COM if ((itask = w->worker_task_head) == NULL) { 42997836SJohn.Forte@Sun.COM break; 43007836SJohn.Forte@Sun.COM } 43017836SJohn.Forte@Sun.COM task = itask->itask_task; 43027836SJohn.Forte@Sun.COM w->worker_task_head = itask->itask_worker_next; 43037836SJohn.Forte@Sun.COM if (w->worker_task_head == NULL) 43047836SJohn.Forte@Sun.COM w->worker_task_tail = NULL; 43057836SJohn.Forte@Sun.COM 43067836SJohn.Forte@Sun.COM wait_queue = 0; 43077836SJohn.Forte@Sun.COM abort_free = 0; 43087836SJohn.Forte@Sun.COM if (itask->itask_ncmds > 0) { 43097836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[itask->itask_ncmds - 1]; 43107836SJohn.Forte@Sun.COM } else { 43117836SJohn.Forte@Sun.COM ASSERT(itask->itask_flags & ITASK_BEING_ABORTED); 43127836SJohn.Forte@Sun.COM } 43137836SJohn.Forte@Sun.COM do { 43147836SJohn.Forte@Sun.COM old = itask->itask_flags; 43157836SJohn.Forte@Sun.COM if (old & ITASK_BEING_ABORTED) { 43167836SJohn.Forte@Sun.COM itask->itask_ncmds = 1; 43177836SJohn.Forte@Sun.COM curcmd = itask->itask_cmd_stack[0] = 43187836SJohn.Forte@Sun.COM ITASK_CMD_ABORT; 43197836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 43207836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_MASK) == 43217836SJohn.Forte@Sun.COM ITASK_CMD_NEW_TASK) { 43227836SJohn.Forte@Sun.COM new = old | ITASK_KNOWN_TO_LU; 43237836SJohn.Forte@Sun.COM } else { 43247836SJohn.Forte@Sun.COM goto out_itask_flag_loop; 43257836SJohn.Forte@Sun.COM } 43267836SJohn.Forte@Sun.COM } while (atomic_cas_32(&itask->itask_flags, old, new) != old); 43277836SJohn.Forte@Sun.COM 43287836SJohn.Forte@Sun.COM out_itask_flag_loop: 43297836SJohn.Forte@Sun.COM 43307836SJohn.Forte@Sun.COM /* 43317836SJohn.Forte@Sun.COM * Decide if this task needs to go to a queue and/or if 43327836SJohn.Forte@Sun.COM * we can decrement the itask_cmd_stack. 43337836SJohn.Forte@Sun.COM */ 43347836SJohn.Forte@Sun.COM if (curcmd == ITASK_CMD_ABORT) { 43357836SJohn.Forte@Sun.COM if (itask->itask_flags & (ITASK_KNOWN_TO_LU | 43367836SJohn.Forte@Sun.COM ITASK_KNOWN_TO_TGT_PORT)) { 43377836SJohn.Forte@Sun.COM wait_queue = 1; 43387836SJohn.Forte@Sun.COM } else { 43397836SJohn.Forte@Sun.COM abort_free = 1; 43407836SJohn.Forte@Sun.COM } 43417836SJohn.Forte@Sun.COM } else if ((curcmd & ITASK_CMD_POLL) && 43427836SJohn.Forte@Sun.COM (itask->itask_poll_timeout > ddi_get_lbolt())) { 43437836SJohn.Forte@Sun.COM wait_queue = 1; 43447836SJohn.Forte@Sun.COM } 43457836SJohn.Forte@Sun.COM 43467836SJohn.Forte@Sun.COM if (wait_queue) { 43477836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 43487836SJohn.Forte@Sun.COM if (w->worker_wait_tail) { 43497836SJohn.Forte@Sun.COM w->worker_wait_tail->itask_worker_next = itask; 43507836SJohn.Forte@Sun.COM } else { 43517836SJohn.Forte@Sun.COM w->worker_wait_head = itask; 43527836SJohn.Forte@Sun.COM } 43537836SJohn.Forte@Sun.COM w->worker_wait_tail = itask; 43547836SJohn.Forte@Sun.COM if (wait_timer == 0) { 43557836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + wait_ticks; 43567836SJohn.Forte@Sun.COM } 43577836SJohn.Forte@Sun.COM } else if ((--(itask->itask_ncmds)) != 0) { 43587836SJohn.Forte@Sun.COM itask->itask_worker_next = NULL; 43597836SJohn.Forte@Sun.COM if (w->worker_task_tail) { 43607836SJohn.Forte@Sun.COM w->worker_task_tail->itask_worker_next = itask; 43617836SJohn.Forte@Sun.COM } else { 43627836SJohn.Forte@Sun.COM w->worker_task_head = itask; 43637836SJohn.Forte@Sun.COM } 43647836SJohn.Forte@Sun.COM w->worker_task_tail = itask; 43657836SJohn.Forte@Sun.COM } else { 43667836SJohn.Forte@Sun.COM atomic_and_32(&itask->itask_flags, 43677836SJohn.Forte@Sun.COM ~ITASK_IN_WORKER_QUEUE); 43687836SJohn.Forte@Sun.COM /* 43697836SJohn.Forte@Sun.COM * This is where the queue depth should go down by 43707836SJohn.Forte@Sun.COM * one but we delay that on purpose to account for 43717836SJohn.Forte@Sun.COM * the call into the provider. The actual decrement 43727836SJohn.Forte@Sun.COM * happens after the worker has done its job. 43737836SJohn.Forte@Sun.COM */ 43747836SJohn.Forte@Sun.COM dec_qdepth = 1; 43757836SJohn.Forte@Sun.COM } 43767836SJohn.Forte@Sun.COM 43777836SJohn.Forte@Sun.COM /* We made it here means we are going to call LU */ 43787836SJohn.Forte@Sun.COM if ((itask->itask_flags & ITASK_DEFAULT_HANDLING) == 0) 43797836SJohn.Forte@Sun.COM lu = task->task_lu; 43807836SJohn.Forte@Sun.COM else 43817836SJohn.Forte@Sun.COM lu = dlun0; 43827836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[ITASK_CMD_BUF_NDX(curcmd)]; 43837836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 43847836SJohn.Forte@Sun.COM curcmd &= ITASK_CMD_MASK; 43857836SJohn.Forte@Sun.COM switch (curcmd) { 43867836SJohn.Forte@Sun.COM case ITASK_CMD_NEW_TASK: 43877836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 43887836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 43897836SJohn.Forte@Sun.COM if (iss->iss_flags & ISS_LUN_INVENTORY_CHANGED) { 43907836SJohn.Forte@Sun.COM if (stmf_handle_cmd_during_ic(itask)) 43917836SJohn.Forte@Sun.COM break; 43927836SJohn.Forte@Sun.COM } 43937836SJohn.Forte@Sun.COM #ifdef DEBUG 43947836SJohn.Forte@Sun.COM if (stmf_drop_task_counter > 0) { 43957836SJohn.Forte@Sun.COM if (atomic_add_32_nv( 43967836SJohn.Forte@Sun.COM (uint32_t *)&stmf_drop_task_counter, 43977836SJohn.Forte@Sun.COM -1) == 1) { 43987836SJohn.Forte@Sun.COM break; 43997836SJohn.Forte@Sun.COM } 44007836SJohn.Forte@Sun.COM } 44017836SJohn.Forte@Sun.COM #endif 44027836SJohn.Forte@Sun.COM lu->lu_new_task(task, dbuf); 44037836SJohn.Forte@Sun.COM break; 44047836SJohn.Forte@Sun.COM case ITASK_CMD_DATA_XFER_DONE: 44057836SJohn.Forte@Sun.COM lu->lu_dbuf_xfer_done(task, dbuf); 44067836SJohn.Forte@Sun.COM break; 44077836SJohn.Forte@Sun.COM case ITASK_CMD_STATUS_DONE: 44087836SJohn.Forte@Sun.COM lu->lu_send_status_done(task); 44097836SJohn.Forte@Sun.COM break; 44107836SJohn.Forte@Sun.COM case ITASK_CMD_ABORT: 44117836SJohn.Forte@Sun.COM if (abort_free) { 44127836SJohn.Forte@Sun.COM stmf_task_free(task); 44137836SJohn.Forte@Sun.COM } else { 44147836SJohn.Forte@Sun.COM stmf_do_task_abort(task); 44157836SJohn.Forte@Sun.COM } 44167836SJohn.Forte@Sun.COM break; 44177836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LU: 44187836SJohn.Forte@Sun.COM if (!wait_queue) { 44197836SJohn.Forte@Sun.COM lu->lu_task_poll(task); 44207836SJohn.Forte@Sun.COM } 44217836SJohn.Forte@Sun.COM break; 44227836SJohn.Forte@Sun.COM case ITASK_CMD_POLL_LPORT: 44237836SJohn.Forte@Sun.COM if (!wait_queue) 44247836SJohn.Forte@Sun.COM task->task_lport->lport_task_poll(task); 44257836SJohn.Forte@Sun.COM break; 44267836SJohn.Forte@Sun.COM case ITASK_CMD_SEND_STATUS: 44277836SJohn.Forte@Sun.COM /* case ITASK_CMD_XFER_DATA: */ 44287836SJohn.Forte@Sun.COM break; 44297836SJohn.Forte@Sun.COM } 44307836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 44317836SJohn.Forte@Sun.COM if (dec_qdepth) { 44327836SJohn.Forte@Sun.COM w->worker_queue_depth--; 44337836SJohn.Forte@Sun.COM } 44347836SJohn.Forte@Sun.COM } 44357836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_TERMINATE) && (wait_timer == 0)) { 44367836SJohn.Forte@Sun.COM if (w->worker_ref_count == 0) 44377836SJohn.Forte@Sun.COM goto stmf_worker_loop; 44387836SJohn.Forte@Sun.COM else 44397836SJohn.Forte@Sun.COM wait_timer = ddi_get_lbolt() + 1; 44407836SJohn.Forte@Sun.COM } 44417836SJohn.Forte@Sun.COM w->worker_flags &= ~STMF_WORKER_ACTIVE; 44427836SJohn.Forte@Sun.COM if (wait_timer) { 44437836SJohn.Forte@Sun.COM (void) cv_timedwait(&w->worker_cv, &w->worker_lock, wait_timer); 44447836SJohn.Forte@Sun.COM } else { 44457836SJohn.Forte@Sun.COM cv_wait(&w->worker_cv, &w->worker_lock); 44467836SJohn.Forte@Sun.COM } 44477836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_ACTIVE; 44487836SJohn.Forte@Sun.COM goto stmf_worker_loop; 44497836SJohn.Forte@Sun.COM } 44507836SJohn.Forte@Sun.COM 44517836SJohn.Forte@Sun.COM void 44527836SJohn.Forte@Sun.COM stmf_worker_mgmt() 44537836SJohn.Forte@Sun.COM { 44547836SJohn.Forte@Sun.COM int i; 44557836SJohn.Forte@Sun.COM int workers_needed; 44567836SJohn.Forte@Sun.COM uint32_t qd; 44577836SJohn.Forte@Sun.COM clock_t tps, d = 0; 44587836SJohn.Forte@Sun.COM uint32_t cur_max_ntasks = 0; 44597836SJohn.Forte@Sun.COM stmf_worker_t *w; 44607836SJohn.Forte@Sun.COM 44617836SJohn.Forte@Sun.COM /* Check if we are trying to increase the # of threads */ 44627836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < stmf_nworkers_needed; i++) { 44637836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_flags & STMF_WORKER_STARTED) { 44647836SJohn.Forte@Sun.COM stmf_nworkers_cur++; 44657836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds++; 44667836SJohn.Forte@Sun.COM } else { 44677836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 44687836SJohn.Forte@Sun.COM return; 44697836SJohn.Forte@Sun.COM } 44707836SJohn.Forte@Sun.COM } 44717836SJohn.Forte@Sun.COM /* Check if we are trying to decrease the # of workers */ 44727836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 44737836SJohn.Forte@Sun.COM if ((stmf_workers[i].worker_flags & STMF_WORKER_STARTED) == 0) { 44747836SJohn.Forte@Sun.COM stmf_nworkers_cur--; 44757836SJohn.Forte@Sun.COM /* 44767836SJohn.Forte@Sun.COM * stmf_nworkers_accepting_cmds has already been 44777836SJohn.Forte@Sun.COM * updated by the request to reduce the # of workers. 44787836SJohn.Forte@Sun.COM */ 44797836SJohn.Forte@Sun.COM } else { 44807836SJohn.Forte@Sun.COM /* Wait for transition to complete */ 44817836SJohn.Forte@Sun.COM return; 44827836SJohn.Forte@Sun.COM } 44837836SJohn.Forte@Sun.COM } 44847836SJohn.Forte@Sun.COM /* Check if we are being asked to quit */ 44857836SJohn.Forte@Sun.COM if (stmf_workers_state != STMF_WORKERS_ENABLED) { 44867836SJohn.Forte@Sun.COM if (stmf_nworkers_cur) { 44877836SJohn.Forte@Sun.COM workers_needed = 0; 44887836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 44897836SJohn.Forte@Sun.COM } 44907836SJohn.Forte@Sun.COM return; 44917836SJohn.Forte@Sun.COM } 44927836SJohn.Forte@Sun.COM /* Check if we are starting */ 44937836SJohn.Forte@Sun.COM if (stmf_nworkers_cur < stmf_i_min_nworkers) { 44947836SJohn.Forte@Sun.COM workers_needed = stmf_i_min_nworkers; 44957836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 44967836SJohn.Forte@Sun.COM } 44977836SJohn.Forte@Sun.COM 44987836SJohn.Forte@Sun.COM tps = drv_usectohz(1 * 1000 * 1000); 44997836SJohn.Forte@Sun.COM if ((stmf_wm_last != 0) && 45007836SJohn.Forte@Sun.COM ((d = ddi_get_lbolt() - stmf_wm_last) > tps)) { 45017836SJohn.Forte@Sun.COM qd = 0; 45027836SJohn.Forte@Sun.COM for (i = 0; i < stmf_nworkers_accepting_cmds; i++) { 45037836SJohn.Forte@Sun.COM qd += stmf_workers[i].worker_max_qdepth_pu; 45047836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_qdepth_pu = 0; 45057836SJohn.Forte@Sun.COM if (stmf_workers[i].worker_max_sys_qdepth_pu > 45067836SJohn.Forte@Sun.COM cur_max_ntasks) { 45077836SJohn.Forte@Sun.COM cur_max_ntasks = 45087836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu; 45097836SJohn.Forte@Sun.COM } 45107836SJohn.Forte@Sun.COM stmf_workers[i].worker_max_sys_qdepth_pu = 0; 45117836SJohn.Forte@Sun.COM } 45127836SJohn.Forte@Sun.COM } 45137836SJohn.Forte@Sun.COM stmf_wm_last = ddi_get_lbolt(); 45147836SJohn.Forte@Sun.COM if (d <= tps) { 45157836SJohn.Forte@Sun.COM /* still ramping up */ 45167836SJohn.Forte@Sun.COM return; 45177836SJohn.Forte@Sun.COM } 45187836SJohn.Forte@Sun.COM /* max qdepth cannot be more than max tasks */ 45197836SJohn.Forte@Sun.COM if (qd > cur_max_ntasks) 45207836SJohn.Forte@Sun.COM qd = cur_max_ntasks; 45217836SJohn.Forte@Sun.COM 45227836SJohn.Forte@Sun.COM /* See if we have more workers */ 45237836SJohn.Forte@Sun.COM if (qd < stmf_nworkers_accepting_cmds) { 45247836SJohn.Forte@Sun.COM /* 45257836SJohn.Forte@Sun.COM * Since we dont reduce the worker count right away, monitor 45267836SJohn.Forte@Sun.COM * the highest load during the scale_down_delay. 45277836SJohn.Forte@Sun.COM */ 45287836SJohn.Forte@Sun.COM if (qd > stmf_worker_scale_down_qd) 45297836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = qd; 45307836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_timer == 0) { 45317836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = ddi_get_lbolt() + 45327836SJohn.Forte@Sun.COM drv_usectohz(stmf_worker_scale_down_delay * 45337836SJohn.Forte@Sun.COM 1000 * 1000); 45347836SJohn.Forte@Sun.COM return; 45357836SJohn.Forte@Sun.COM } 45367836SJohn.Forte@Sun.COM if (ddi_get_lbolt() < stmf_worker_scale_down_timer) { 45377836SJohn.Forte@Sun.COM return; 45387836SJohn.Forte@Sun.COM } 45397836SJohn.Forte@Sun.COM /* Its time to reduce the workers */ 45407836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd < stmf_i_min_nworkers) 45417836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_min_nworkers; 45427836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd > stmf_i_max_nworkers) 45437836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = stmf_i_max_nworkers; 45447836SJohn.Forte@Sun.COM if (stmf_worker_scale_down_qd == stmf_nworkers_cur) 45457836SJohn.Forte@Sun.COM return; 45467836SJohn.Forte@Sun.COM workers_needed = stmf_worker_scale_down_qd; 45477836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 45487836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 45497836SJohn.Forte@Sun.COM } 45507836SJohn.Forte@Sun.COM stmf_worker_scale_down_qd = 0; 45517836SJohn.Forte@Sun.COM stmf_worker_scale_down_timer = 0; 45527836SJohn.Forte@Sun.COM if (qd > stmf_i_max_nworkers) 45537836SJohn.Forte@Sun.COM qd = stmf_i_max_nworkers; 45547836SJohn.Forte@Sun.COM if (qd < stmf_i_min_nworkers) 45557836SJohn.Forte@Sun.COM qd = stmf_i_min_nworkers; 45567836SJohn.Forte@Sun.COM if (qd == stmf_nworkers_cur) 45577836SJohn.Forte@Sun.COM return; 45587836SJohn.Forte@Sun.COM workers_needed = qd; 45597836SJohn.Forte@Sun.COM goto worker_mgmt_trigger_change; 45607836SJohn.Forte@Sun.COM 45617836SJohn.Forte@Sun.COM /* NOTREACHED */ 45627836SJohn.Forte@Sun.COM return; 45637836SJohn.Forte@Sun.COM 45647836SJohn.Forte@Sun.COM worker_mgmt_trigger_change: 45657836SJohn.Forte@Sun.COM ASSERT(workers_needed != stmf_nworkers_cur); 45667836SJohn.Forte@Sun.COM if (workers_needed > stmf_nworkers_cur) { 45677836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 45687836SJohn.Forte@Sun.COM for (i = stmf_nworkers_cur; i < workers_needed; i++) { 45697836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 45707836SJohn.Forte@Sun.COM w->worker_tid = thread_create(NULL, 0, stmf_worker_task, 45717836SJohn.Forte@Sun.COM (void *)&stmf_workers[i], 0, &p0, TS_RUN, 45727836SJohn.Forte@Sun.COM minclsyspri); 45737836SJohn.Forte@Sun.COM } 45747836SJohn.Forte@Sun.COM return; 45757836SJohn.Forte@Sun.COM } 45767836SJohn.Forte@Sun.COM /* At this point we know that we are decreasing the # of workers */ 45777836SJohn.Forte@Sun.COM stmf_nworkers_accepting_cmds = workers_needed; 45787836SJohn.Forte@Sun.COM stmf_nworkers_needed = workers_needed; 45797836SJohn.Forte@Sun.COM /* Signal the workers that its time to quit */ 45807836SJohn.Forte@Sun.COM for (i = (stmf_nworkers_cur - 1); i >= stmf_nworkers_needed; i--) { 45817836SJohn.Forte@Sun.COM w = &stmf_workers[i]; 45827836SJohn.Forte@Sun.COM ASSERT(w && (w->worker_flags & STMF_WORKER_STARTED)); 45837836SJohn.Forte@Sun.COM mutex_enter(&w->worker_lock); 45847836SJohn.Forte@Sun.COM w->worker_flags |= STMF_WORKER_TERMINATE; 45857836SJohn.Forte@Sun.COM if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) 45867836SJohn.Forte@Sun.COM cv_signal(&w->worker_cv); 45877836SJohn.Forte@Sun.COM mutex_exit(&w->worker_lock); 45887836SJohn.Forte@Sun.COM } 45897836SJohn.Forte@Sun.COM } 45907836SJohn.Forte@Sun.COM 45917836SJohn.Forte@Sun.COM /* 45927836SJohn.Forte@Sun.COM * Fills out a dbuf from stmf_xfer_data_t (contained in the db_lu_private). 45937836SJohn.Forte@Sun.COM * If all the data has been filled out, frees the xd and makes 45947836SJohn.Forte@Sun.COM * db_lu_private NULL. 45957836SJohn.Forte@Sun.COM */ 45967836SJohn.Forte@Sun.COM void 45977836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(stmf_data_buf_t *dbuf) 45987836SJohn.Forte@Sun.COM { 45997836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 46007836SJohn.Forte@Sun.COM uint8_t *p; 46017836SJohn.Forte@Sun.COM int i; 46027836SJohn.Forte@Sun.COM uint32_t s; 46037836SJohn.Forte@Sun.COM 46047836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 46057836SJohn.Forte@Sun.COM dbuf->db_data_size = 0; 46067836SJohn.Forte@Sun.COM dbuf->db_relative_offset = xd->size_done; 46077836SJohn.Forte@Sun.COM for (i = 0; i < dbuf->db_sglist_length; i++) { 46087836SJohn.Forte@Sun.COM s = min(xd->size_left, dbuf->db_sglist[i].seg_length); 46097836SJohn.Forte@Sun.COM p = &xd->buf[xd->size_done]; 46107836SJohn.Forte@Sun.COM bcopy(p, dbuf->db_sglist[i].seg_addr, s); 46117836SJohn.Forte@Sun.COM xd->size_left -= s; 46127836SJohn.Forte@Sun.COM xd->size_done += s; 46137836SJohn.Forte@Sun.COM dbuf->db_data_size += s; 46147836SJohn.Forte@Sun.COM if (xd->size_left == 0) { 46157836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 46167836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 46177836SJohn.Forte@Sun.COM return; 46187836SJohn.Forte@Sun.COM } 46197836SJohn.Forte@Sun.COM } 46207836SJohn.Forte@Sun.COM } 46217836SJohn.Forte@Sun.COM 46227836SJohn.Forte@Sun.COM /* ARGSUSED */ 46237836SJohn.Forte@Sun.COM stmf_status_t 46247836SJohn.Forte@Sun.COM stmf_dlun0_task_alloc(scsi_task_t *task) 46257836SJohn.Forte@Sun.COM { 46267836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 46277836SJohn.Forte@Sun.COM } 46287836SJohn.Forte@Sun.COM 46297836SJohn.Forte@Sun.COM void 46307836SJohn.Forte@Sun.COM stmf_dlun0_new_task(scsi_task_t *task, stmf_data_buf_t *dbuf) 46317836SJohn.Forte@Sun.COM { 46327836SJohn.Forte@Sun.COM uint8_t *cdbp = (uint8_t *)&task->task_cdb[0]; 46337836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 46347836SJohn.Forte@Sun.COM uint32_t sz, minsz; 46357836SJohn.Forte@Sun.COM uint8_t *p; 46367836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 46377836SJohn.Forte@Sun.COM uint8_t inq_page_length = 31; 46387836SJohn.Forte@Sun.COM 46397836SJohn.Forte@Sun.COM if (task->task_mgmt_function) { 46407836SJohn.Forte@Sun.COM stmf_scsilib_handle_task_mgmt(task); 46417836SJohn.Forte@Sun.COM return; 46427836SJohn.Forte@Sun.COM } 46437836SJohn.Forte@Sun.COM 46447836SJohn.Forte@Sun.COM switch (cdbp[0]) { 46457836SJohn.Forte@Sun.COM case SCMD_INQUIRY: 46467836SJohn.Forte@Sun.COM /* 46477836SJohn.Forte@Sun.COM * Basic protocol checks. In addition, only reply to 46487836SJohn.Forte@Sun.COM * standard inquiry. Otherwise, the LU provider needs 46497836SJohn.Forte@Sun.COM * to respond. 46507836SJohn.Forte@Sun.COM */ 46517836SJohn.Forte@Sun.COM 46527836SJohn.Forte@Sun.COM if (cdbp[2] || (cdbp[1] & 1) || cdbp[5]) { 46537836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 46547836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 46557836SJohn.Forte@Sun.COM return; 46567836SJohn.Forte@Sun.COM } 46577836SJohn.Forte@Sun.COM 46587836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 46597836SJohn.Forte@Sun.COM (((uint32_t)cdbp[3]) << 8) | cdbp[4]; 46607836SJohn.Forte@Sun.COM 46617836SJohn.Forte@Sun.COM if (task->task_additional_flags & 46627836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 46637836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 46647836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 46657836SJohn.Forte@Sun.COM } 46667836SJohn.Forte@Sun.COM 46677836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 46687836SJohn.Forte@Sun.COM min(36, task->task_cmd_xfer_length)); 46697836SJohn.Forte@Sun.COM minsz = 36; 46707836SJohn.Forte@Sun.COM 46717836SJohn.Forte@Sun.COM if (sz == 0) { 46727836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 46737836SJohn.Forte@Sun.COM return; 46747836SJohn.Forte@Sun.COM } 46757836SJohn.Forte@Sun.COM 46767836SJohn.Forte@Sun.COM if (dbuf && (dbuf->db_sglist[0].seg_length < 36)) { 46777836SJohn.Forte@Sun.COM /* 46787836SJohn.Forte@Sun.COM * Ignore any preallocated dbuf if the size is less 46797836SJohn.Forte@Sun.COM * than 36. It will be freed during the task_free. 46807836SJohn.Forte@Sun.COM */ 46817836SJohn.Forte@Sun.COM dbuf = NULL; 46827836SJohn.Forte@Sun.COM } 46837836SJohn.Forte@Sun.COM if (dbuf == NULL) 46847836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, minsz, &minsz, 0); 46857836SJohn.Forte@Sun.COM if ((dbuf == NULL) || (dbuf->db_sglist[0].seg_length < sz)) { 46867836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 46877836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 46887836SJohn.Forte@Sun.COM return; 46897836SJohn.Forte@Sun.COM } 46907836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 46917836SJohn.Forte@Sun.COM 46927836SJohn.Forte@Sun.COM p = dbuf->db_sglist[0].seg_addr; 46937836SJohn.Forte@Sun.COM 46947836SJohn.Forte@Sun.COM /* 46957836SJohn.Forte@Sun.COM * Standard inquiry handling only. 46967836SJohn.Forte@Sun.COM */ 46977836SJohn.Forte@Sun.COM 46987836SJohn.Forte@Sun.COM bzero(p, inq_page_length + 5); 46997836SJohn.Forte@Sun.COM 47007836SJohn.Forte@Sun.COM p[0] = DPQ_SUPPORTED | DTYPE_UNKNOWN; 47017836SJohn.Forte@Sun.COM p[2] = 5; 47027836SJohn.Forte@Sun.COM p[3] = 0x12; 47037836SJohn.Forte@Sun.COM p[4] = inq_page_length; 47047836SJohn.Forte@Sun.COM p[6] = 0x80; 47057836SJohn.Forte@Sun.COM 47067836SJohn.Forte@Sun.COM (void) strncpy((char *)p+8, "SUN ", 8); 47077836SJohn.Forte@Sun.COM (void) strncpy((char *)p+16, "COMSTAR ", 16); 47087836SJohn.Forte@Sun.COM (void) strncpy((char *)p+32, "1.0 ", 4); 47097836SJohn.Forte@Sun.COM 47107836SJohn.Forte@Sun.COM dbuf->db_data_size = sz; 47117836SJohn.Forte@Sun.COM dbuf->db_relative_offset = 0; 47127836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 47137836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 47147836SJohn.Forte@Sun.COM 47157836SJohn.Forte@Sun.COM return; 47167836SJohn.Forte@Sun.COM 47177836SJohn.Forte@Sun.COM case SCMD_REPORT_LUNS: 47187836SJohn.Forte@Sun.COM task->task_cmd_xfer_length = 47197836SJohn.Forte@Sun.COM ((((uint32_t)task->task_cdb[6]) << 24) | 47207836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[7]) << 16) | 47217836SJohn.Forte@Sun.COM (((uint32_t)task->task_cdb[8]) << 8) | 47227836SJohn.Forte@Sun.COM ((uint32_t)task->task_cdb[9])); 47237836SJohn.Forte@Sun.COM 47247836SJohn.Forte@Sun.COM if (task->task_additional_flags & 47257836SJohn.Forte@Sun.COM TASK_AF_NO_EXPECTED_XFER_LENGTH) { 47267836SJohn.Forte@Sun.COM task->task_expected_xfer_length = 47277836SJohn.Forte@Sun.COM task->task_cmd_xfer_length; 47287836SJohn.Forte@Sun.COM } 47297836SJohn.Forte@Sun.COM 47307836SJohn.Forte@Sun.COM sz = min(task->task_expected_xfer_length, 47317836SJohn.Forte@Sun.COM task->task_cmd_xfer_length); 47327836SJohn.Forte@Sun.COM 47337836SJohn.Forte@Sun.COM if (sz < 16) { 47347836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, 47357836SJohn.Forte@Sun.COM STMF_SAA_INVALID_FIELD_IN_CDB); 47367836SJohn.Forte@Sun.COM return; 47377836SJohn.Forte@Sun.COM } 47387836SJohn.Forte@Sun.COM 47397836SJohn.Forte@Sun.COM iss = (stmf_i_scsi_session_t *) 47407836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 47417836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_WRITER); 47427836SJohn.Forte@Sun.COM xd = stmf_session_prepare_report_lun_data(iss->iss_sm); 47437836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 47447836SJohn.Forte@Sun.COM 47457836SJohn.Forte@Sun.COM if (xd == NULL) { 47467836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 47477836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 47487836SJohn.Forte@Sun.COM return; 47497836SJohn.Forte@Sun.COM } 47507836SJohn.Forte@Sun.COM 47517836SJohn.Forte@Sun.COM sz = min(sz, xd->size_left); 47527836SJohn.Forte@Sun.COM xd->size_left = sz; 47537836SJohn.Forte@Sun.COM minsz = min(512, sz); 47547836SJohn.Forte@Sun.COM 47557836SJohn.Forte@Sun.COM if (dbuf == NULL) 47567836SJohn.Forte@Sun.COM dbuf = stmf_alloc_dbuf(task, sz, &minsz, 0); 47577836SJohn.Forte@Sun.COM if (dbuf == NULL) { 47587836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 47597836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 47607836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 47617836SJohn.Forte@Sun.COM return; 47627836SJohn.Forte@Sun.COM } 47637836SJohn.Forte@Sun.COM dbuf->db_lu_private = xd; 47647836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 47657836SJohn.Forte@Sun.COM 47667836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 47677836SJohn.Forte@Sun.COM ~(ISS_LUN_INVENTORY_CHANGED | ISS_GOT_INITIAL_LUNS)); 47687836SJohn.Forte@Sun.COM dbuf->db_flags = DB_DIRECTION_TO_RPORT; 47697836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 47707836SJohn.Forte@Sun.COM return; 47717836SJohn.Forte@Sun.COM } 47727836SJohn.Forte@Sun.COM 47737836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_CHECK, STMF_SAA_INVALID_OPCODE); 47747836SJohn.Forte@Sun.COM } 47757836SJohn.Forte@Sun.COM 47767836SJohn.Forte@Sun.COM void 47777836SJohn.Forte@Sun.COM stmf_dlun0_dbuf_done(scsi_task_t *task, stmf_data_buf_t *dbuf) 47787836SJohn.Forte@Sun.COM { 47797836SJohn.Forte@Sun.COM if (dbuf->db_xfer_status != STMF_SUCCESS) { 47807836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 47817836SJohn.Forte@Sun.COM dbuf->db_xfer_status, NULL); 47827836SJohn.Forte@Sun.COM return; 47837836SJohn.Forte@Sun.COM } 47847836SJohn.Forte@Sun.COM task->task_nbytes_transferred = dbuf->db_data_size; 47857836SJohn.Forte@Sun.COM if (dbuf->db_lu_private) { 47867836SJohn.Forte@Sun.COM /* There is more */ 47877836SJohn.Forte@Sun.COM stmf_xd_to_dbuf(dbuf); 47887836SJohn.Forte@Sun.COM (void) stmf_xfer_data(task, dbuf, 0); 47897836SJohn.Forte@Sun.COM return; 47907836SJohn.Forte@Sun.COM } 47917836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 47927836SJohn.Forte@Sun.COM } 47937836SJohn.Forte@Sun.COM 47947836SJohn.Forte@Sun.COM /* ARGSUSED */ 47957836SJohn.Forte@Sun.COM void 47967836SJohn.Forte@Sun.COM stmf_dlun0_status_done(scsi_task_t *task) 47977836SJohn.Forte@Sun.COM { 47987836SJohn.Forte@Sun.COM } 47997836SJohn.Forte@Sun.COM 48007836SJohn.Forte@Sun.COM /* ARGSUSED */ 48017836SJohn.Forte@Sun.COM void 48027836SJohn.Forte@Sun.COM stmf_dlun0_task_free(scsi_task_t *task) 48037836SJohn.Forte@Sun.COM { 48047836SJohn.Forte@Sun.COM } 48057836SJohn.Forte@Sun.COM 48067836SJohn.Forte@Sun.COM /* ARGSUSED */ 48077836SJohn.Forte@Sun.COM stmf_status_t 48087836SJohn.Forte@Sun.COM stmf_dlun0_abort(struct stmf_lu *lu, int abort_cmd, void *arg, uint32_t flags) 48097836SJohn.Forte@Sun.COM { 48107836SJohn.Forte@Sun.COM scsi_task_t *task = (scsi_task_t *)arg; 48117836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask = 48127836SJohn.Forte@Sun.COM (stmf_i_scsi_task_t *)task->task_stmf_private; 48137836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private; 48147836SJohn.Forte@Sun.COM int i; 48157836SJohn.Forte@Sun.COM uint8_t map; 48167836SJohn.Forte@Sun.COM 48177836SJohn.Forte@Sun.COM ASSERT(abort_cmd == STMF_LU_ABORT_TASK); 48187836SJohn.Forte@Sun.COM if ((task->task_mgmt_function) && (itask->itask_flags & 48197836SJohn.Forte@Sun.COM (ITASK_CAUSING_LU_RESET | ITASK_CAUSING_TARGET_RESET))) { 48207836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 48217836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 48227836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 48237836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 48247836SJohn.Forte@Sun.COM case TM_LUN_RESET: 48257836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 48267836SJohn.Forte@Sun.COM break; 48277836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 48287836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 48297836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 48307836SJohn.Forte@Sun.COM stmf_abort_target_reset(task); 48317836SJohn.Forte@Sun.COM break; 48327836SJohn.Forte@Sun.COM } 48337836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 48347836SJohn.Forte@Sun.COM } 48357836SJohn.Forte@Sun.COM 48367836SJohn.Forte@Sun.COM /* 48377836SJohn.Forte@Sun.COM * OK so its not a task mgmt. Make sure we free any xd sitting 48387836SJohn.Forte@Sun.COM * inside any dbuf. 48397836SJohn.Forte@Sun.COM */ 48407836SJohn.Forte@Sun.COM if ((map = itask->itask_allocated_buf_map) != 0) { 48417836SJohn.Forte@Sun.COM for (i = 0; i < 4; i++) { 48427836SJohn.Forte@Sun.COM if ((map & 1) && 48437836SJohn.Forte@Sun.COM ((itask->itask_dbufs[i])->db_lu_private)) { 48447836SJohn.Forte@Sun.COM stmf_xfer_data_t *xd; 48457836SJohn.Forte@Sun.COM stmf_data_buf_t *dbuf; 48467836SJohn.Forte@Sun.COM 48477836SJohn.Forte@Sun.COM dbuf = itask->itask_dbufs[i]; 48487836SJohn.Forte@Sun.COM xd = (stmf_xfer_data_t *)dbuf->db_lu_private; 48497836SJohn.Forte@Sun.COM dbuf->db_lu_private = NULL; 48507836SJohn.Forte@Sun.COM kmem_free(xd, xd->alloc_size); 48517836SJohn.Forte@Sun.COM } 48527836SJohn.Forte@Sun.COM map >>= 1; 48537836SJohn.Forte@Sun.COM } 48547836SJohn.Forte@Sun.COM } 48557836SJohn.Forte@Sun.COM return (STMF_ABORT_SUCCESS); 48567836SJohn.Forte@Sun.COM } 48577836SJohn.Forte@Sun.COM 48587836SJohn.Forte@Sun.COM void 48597836SJohn.Forte@Sun.COM stmf_dlun0_task_poll(struct scsi_task *task) 48607836SJohn.Forte@Sun.COM { 48617836SJohn.Forte@Sun.COM /* Right now we only do this for handling task management functions */ 48627836SJohn.Forte@Sun.COM ASSERT(task->task_mgmt_function); 48637836SJohn.Forte@Sun.COM 48647836SJohn.Forte@Sun.COM switch (task->task_mgmt_function) { 48657836SJohn.Forte@Sun.COM case TM_ABORT_TASK: 48667836SJohn.Forte@Sun.COM case TM_ABORT_TASK_SET: 48677836SJohn.Forte@Sun.COM case TM_CLEAR_TASK_SET: 48687836SJohn.Forte@Sun.COM case TM_LUN_RESET: 48697836SJohn.Forte@Sun.COM (void) stmf_lun_reset_poll(task->task_lu, task, 0); 48707836SJohn.Forte@Sun.COM return; 48717836SJohn.Forte@Sun.COM case TM_TARGET_RESET: 48727836SJohn.Forte@Sun.COM case TM_TARGET_COLD_RESET: 48737836SJohn.Forte@Sun.COM case TM_TARGET_WARM_RESET: 48747836SJohn.Forte@Sun.COM stmf_target_reset_poll(task); 48757836SJohn.Forte@Sun.COM return; 48767836SJohn.Forte@Sun.COM } 48777836SJohn.Forte@Sun.COM } 48787836SJohn.Forte@Sun.COM 48797836SJohn.Forte@Sun.COM /* ARGSUSED */ 48807836SJohn.Forte@Sun.COM void 48817836SJohn.Forte@Sun.COM stmf_dlun0_ctl(struct stmf_lu *lu, int cmd, void *arg) 48827836SJohn.Forte@Sun.COM { 48837836SJohn.Forte@Sun.COM /* This function will never be called */ 48847836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "stmf_dlun0_ctl called with cmd %x", cmd); 48857836SJohn.Forte@Sun.COM } 48867836SJohn.Forte@Sun.COM 48877836SJohn.Forte@Sun.COM void 48887836SJohn.Forte@Sun.COM stmf_dlun_init() 48897836SJohn.Forte@Sun.COM { 48907836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 48917836SJohn.Forte@Sun.COM 48927836SJohn.Forte@Sun.COM dlun0 = stmf_alloc(STMF_STRUCT_STMF_LU, 0, 0); 48937836SJohn.Forte@Sun.COM dlun0->lu_task_alloc = stmf_dlun0_task_alloc; 48947836SJohn.Forte@Sun.COM dlun0->lu_new_task = stmf_dlun0_new_task; 48957836SJohn.Forte@Sun.COM dlun0->lu_dbuf_xfer_done = stmf_dlun0_dbuf_done; 48967836SJohn.Forte@Sun.COM dlun0->lu_send_status_done = stmf_dlun0_status_done; 48977836SJohn.Forte@Sun.COM dlun0->lu_task_free = stmf_dlun0_task_free; 48987836SJohn.Forte@Sun.COM dlun0->lu_abort = stmf_dlun0_abort; 48997836SJohn.Forte@Sun.COM dlun0->lu_task_poll = stmf_dlun0_task_poll; 49007836SJohn.Forte@Sun.COM dlun0->lu_ctl = stmf_dlun0_ctl; 49017836SJohn.Forte@Sun.COM 49027836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 49037836SJohn.Forte@Sun.COM ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1; 49047836SJohn.Forte@Sun.COM } 49057836SJohn.Forte@Sun.COM 49067836SJohn.Forte@Sun.COM stmf_status_t 49077836SJohn.Forte@Sun.COM stmf_dlun_fini() 49087836SJohn.Forte@Sun.COM { 49097836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 49107836SJohn.Forte@Sun.COM 49117836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)dlun0->lu_stmf_private; 49127836SJohn.Forte@Sun.COM 49137836SJohn.Forte@Sun.COM ASSERT(ilu->ilu_ntasks == ilu->ilu_ntasks_free); 49147836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks) { 49157836SJohn.Forte@Sun.COM stmf_i_scsi_task_t *itask, *nitask; 49167836SJohn.Forte@Sun.COM 49177836SJohn.Forte@Sun.COM nitask = ilu->ilu_tasks; 49187836SJohn.Forte@Sun.COM do { 49197836SJohn.Forte@Sun.COM itask = nitask; 49207836SJohn.Forte@Sun.COM nitask = itask->itask_lu_next; 49217836SJohn.Forte@Sun.COM dlun0->lu_task_free(itask->itask_task); 49227836SJohn.Forte@Sun.COM stmf_free(itask->itask_task); 49237836SJohn.Forte@Sun.COM } while (nitask != NULL); 49247836SJohn.Forte@Sun.COM 49257836SJohn.Forte@Sun.COM } 49267836SJohn.Forte@Sun.COM stmf_free(dlun0); 49277836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 49287836SJohn.Forte@Sun.COM } 49297836SJohn.Forte@Sun.COM 49307836SJohn.Forte@Sun.COM void 49317836SJohn.Forte@Sun.COM stmf_abort_target_reset(scsi_task_t *task) 49327836SJohn.Forte@Sun.COM { 49337836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 49347836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 49357836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 49367836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 49377836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 49387836SJohn.Forte@Sun.COM int i; 49397836SJohn.Forte@Sun.COM 49407836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 49417836SJohn.Forte@Sun.COM 49427836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 49437836SJohn.Forte@Sun.COM lm = iss->iss_sm; 49447836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 49457836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 49467836SJohn.Forte@Sun.COM continue; 49477836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 49487836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 49497836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 49507836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 49517836SJohn.Forte@Sun.COM } 49527836SJohn.Forte@Sun.COM } 49537836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 49547836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 49557836SJohn.Forte@Sun.COM } 49567836SJohn.Forte@Sun.COM 49577836SJohn.Forte@Sun.COM /* 49587836SJohn.Forte@Sun.COM * The return value is only used by function managing target reset. 49597836SJohn.Forte@Sun.COM */ 49607836SJohn.Forte@Sun.COM stmf_status_t 49617836SJohn.Forte@Sun.COM stmf_lun_reset_poll(stmf_lu_t *lu, struct scsi_task *task, int target_reset) 49627836SJohn.Forte@Sun.COM { 49637836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 49647836SJohn.Forte@Sun.COM int ntasks_pending; 49657836SJohn.Forte@Sun.COM 49667836SJohn.Forte@Sun.COM ntasks_pending = ilu->ilu_ntasks - ilu->ilu_ntasks_free; 49677836SJohn.Forte@Sun.COM /* 49687836SJohn.Forte@Sun.COM * This function is also used during Target reset. The idea is that 49697836SJohn.Forte@Sun.COM * once all the commands are aborted, call the LU's reset entry 49707836SJohn.Forte@Sun.COM * point (abort entry point with a reset flag). But if this Task 49717836SJohn.Forte@Sun.COM * mgmt is running on this LU then all the tasks cannot be aborted. 49727836SJohn.Forte@Sun.COM * one task (this task) will still be running which is OK. 49737836SJohn.Forte@Sun.COM */ 49747836SJohn.Forte@Sun.COM if ((ntasks_pending == 0) || ((task->task_lu == lu) && 49757836SJohn.Forte@Sun.COM (ntasks_pending == 1))) { 49767836SJohn.Forte@Sun.COM stmf_status_t ret; 49777836SJohn.Forte@Sun.COM 49787836SJohn.Forte@Sun.COM if ((task->task_mgmt_function == TM_LUN_RESET) || 49797836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_RESET) || 49807836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_WARM_RESET) || 49817836SJohn.Forte@Sun.COM (task->task_mgmt_function == TM_TARGET_COLD_RESET)) { 49827836SJohn.Forte@Sun.COM ret = lu->lu_abort(lu, STMF_LU_RESET_STATE, task, 0); 49837836SJohn.Forte@Sun.COM } else { 49847836SJohn.Forte@Sun.COM ret = STMF_SUCCESS; 49857836SJohn.Forte@Sun.COM } 49867836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 49877836SJohn.Forte@Sun.COM atomic_and_32(&ilu->ilu_flags, ~ILU_RESET_ACTIVE); 49887836SJohn.Forte@Sun.COM } 49897836SJohn.Forte@Sun.COM if (target_reset) { 49907836SJohn.Forte@Sun.COM return (ret); 49917836SJohn.Forte@Sun.COM } 49927836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) { 49937836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 49947836SJohn.Forte@Sun.COM return (ret); 49957836SJohn.Forte@Sun.COM } 49967836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 49977836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, ret, NULL); 49987836SJohn.Forte@Sun.COM return (ret); 49997836SJohn.Forte@Sun.COM } 50007836SJohn.Forte@Sun.COM } 50017836SJohn.Forte@Sun.COM 50027836SJohn.Forte@Sun.COM if (target_reset) { 50037836SJohn.Forte@Sun.COM /* Tell target reset polling code that we are not done */ 50047836SJohn.Forte@Sun.COM return (STMF_BUSY); 50057836SJohn.Forte@Sun.COM } 50067836SJohn.Forte@Sun.COM 50077836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 50087836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 50097836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 50107836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 50117836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50127836SJohn.Forte@Sun.COM } 50137836SJohn.Forte@Sun.COM 50147836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50157836SJohn.Forte@Sun.COM } 50167836SJohn.Forte@Sun.COM 50177836SJohn.Forte@Sun.COM void 50187836SJohn.Forte@Sun.COM stmf_target_reset_poll(struct scsi_task *task) 50197836SJohn.Forte@Sun.COM { 50207836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss = (stmf_i_scsi_session_t *) 50217836SJohn.Forte@Sun.COM task->task_session->ss_stmf_private; 50227836SJohn.Forte@Sun.COM stmf_lun_map_t *lm; 50237836SJohn.Forte@Sun.COM stmf_lun_map_ent_t *lm_ent; 50247836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 50257836SJohn.Forte@Sun.COM stmf_status_t ret; 50267836SJohn.Forte@Sun.COM int i; 50277836SJohn.Forte@Sun.COM int not_done = 0; 50287836SJohn.Forte@Sun.COM 50297836SJohn.Forte@Sun.COM ASSERT(iss->iss_flags & ISS_RESET_ACTIVE); 50307836SJohn.Forte@Sun.COM 50317836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 50327836SJohn.Forte@Sun.COM lm = iss->iss_sm; 50337836SJohn.Forte@Sun.COM for (i = 0; i < lm->lm_nentries; i++) { 50347836SJohn.Forte@Sun.COM if (lm->lm_plus[i] == NULL) 50357836SJohn.Forte@Sun.COM continue; 50367836SJohn.Forte@Sun.COM lm_ent = (stmf_lun_map_ent_t *)lm->lm_plus[i]; 50377836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lm_ent->ent_lu->lu_stmf_private; 50387836SJohn.Forte@Sun.COM if (ilu->ilu_flags & ILU_RESET_ACTIVE) { 50397836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 50407836SJohn.Forte@Sun.COM ret = stmf_lun_reset_poll(lm_ent->ent_lu, task, 1); 50417836SJohn.Forte@Sun.COM rw_enter(iss->iss_lockp, RW_READER); 50427836SJohn.Forte@Sun.COM if (ret == STMF_SUCCESS) 50437836SJohn.Forte@Sun.COM continue; 50447836SJohn.Forte@Sun.COM not_done = 1; 50457836SJohn.Forte@Sun.COM if (ret != STMF_BUSY) { 50467836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 50477836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 50487836SJohn.Forte@Sun.COM STMF_ABORTED, NULL); 50497836SJohn.Forte@Sun.COM return; 50507836SJohn.Forte@Sun.COM } 50517836SJohn.Forte@Sun.COM } 50527836SJohn.Forte@Sun.COM } 50537836SJohn.Forte@Sun.COM rw_exit(iss->iss_lockp); 50547836SJohn.Forte@Sun.COM 50557836SJohn.Forte@Sun.COM if (not_done) { 50567836SJohn.Forte@Sun.COM if (stmf_task_poll_lu(task, ITASK_DEFAULT_POLL_TIMEOUT) 50577836SJohn.Forte@Sun.COM != STMF_SUCCESS) { 50587836SJohn.Forte@Sun.COM stmf_abort(STMF_QUEUE_TASK_ABORT, task, 50597836SJohn.Forte@Sun.COM STMF_ALLOC_FAILURE, NULL); 50607836SJohn.Forte@Sun.COM return; 50617836SJohn.Forte@Sun.COM } 50627836SJohn.Forte@Sun.COM return; 50637836SJohn.Forte@Sun.COM } 50647836SJohn.Forte@Sun.COM 50657836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, ~ISS_RESET_ACTIVE); 50667836SJohn.Forte@Sun.COM 50677836SJohn.Forte@Sun.COM stmf_scsilib_send_status(task, STATUS_GOOD, 0); 50687836SJohn.Forte@Sun.COM } 50697836SJohn.Forte@Sun.COM 50707836SJohn.Forte@Sun.COM stmf_status_t 50717836SJohn.Forte@Sun.COM stmf_lu_add_event(stmf_lu_t *lu, int eventid) 50727836SJohn.Forte@Sun.COM { 50737836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 50747836SJohn.Forte@Sun.COM 50757836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 50767836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 50777836SJohn.Forte@Sun.COM } 50787836SJohn.Forte@Sun.COM 50797836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilu->ilu_event_hdl, eventid); 50807836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50817836SJohn.Forte@Sun.COM } 50827836SJohn.Forte@Sun.COM 50837836SJohn.Forte@Sun.COM stmf_status_t 50847836SJohn.Forte@Sun.COM stmf_lu_remove_event(stmf_lu_t *lu, int eventid) 50857836SJohn.Forte@Sun.COM { 50867836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 50877836SJohn.Forte@Sun.COM 50887836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 50897836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilu->ilu_event_hdl); 50907836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50917836SJohn.Forte@Sun.COM } 50927836SJohn.Forte@Sun.COM 50937836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 50947836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 50957836SJohn.Forte@Sun.COM } 50967836SJohn.Forte@Sun.COM 50977836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilu->ilu_event_hdl, eventid); 50987836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 50997836SJohn.Forte@Sun.COM } 51007836SJohn.Forte@Sun.COM 51017836SJohn.Forte@Sun.COM stmf_status_t 51027836SJohn.Forte@Sun.COM stmf_lport_add_event(stmf_local_port_t *lport, int eventid) 51037836SJohn.Forte@Sun.COM { 51047836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 51057836SJohn.Forte@Sun.COM (stmf_i_local_port_t *)lport->lport_stmf_private; 51067836SJohn.Forte@Sun.COM 51077836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 51087836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 51097836SJohn.Forte@Sun.COM } 51107836SJohn.Forte@Sun.COM 51117836SJohn.Forte@Sun.COM STMF_EVENT_ADD(ilport->ilport_event_hdl, eventid); 51127836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 51137836SJohn.Forte@Sun.COM } 51147836SJohn.Forte@Sun.COM 51157836SJohn.Forte@Sun.COM stmf_status_t 51167836SJohn.Forte@Sun.COM stmf_lport_remove_event(stmf_local_port_t *lport, int eventid) 51177836SJohn.Forte@Sun.COM { 51187836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport = 51197836SJohn.Forte@Sun.COM (stmf_i_local_port_t *)lport->lport_stmf_private; 51207836SJohn.Forte@Sun.COM 51217836SJohn.Forte@Sun.COM if (eventid == STMF_EVENT_ALL) { 51227836SJohn.Forte@Sun.COM STMF_EVENT_CLEAR_ALL(ilport->ilport_event_hdl); 51237836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 51247836SJohn.Forte@Sun.COM } 51257836SJohn.Forte@Sun.COM 51267836SJohn.Forte@Sun.COM if ((eventid < 0) || (eventid >= STMF_MAX_NUM_EVENTS)) { 51277836SJohn.Forte@Sun.COM return (STMF_INVALID_ARG); 51287836SJohn.Forte@Sun.COM } 51297836SJohn.Forte@Sun.COM 51307836SJohn.Forte@Sun.COM STMF_EVENT_REMOVE(ilport->ilport_event_hdl, eventid); 51317836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 51327836SJohn.Forte@Sun.COM } 51337836SJohn.Forte@Sun.COM 51347836SJohn.Forte@Sun.COM void 51357836SJohn.Forte@Sun.COM stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid, void *arg, uint32_t flags) 51367836SJohn.Forte@Sun.COM { 51377836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilu->ilu_event_hdl, eventid) && 51387836SJohn.Forte@Sun.COM (ilu->ilu_lu->lu_event_handler != NULL)) { 51397836SJohn.Forte@Sun.COM ilu->ilu_lu->lu_event_handler(ilu->ilu_lu, eventid, arg, flags); 51407836SJohn.Forte@Sun.COM } 51417836SJohn.Forte@Sun.COM } 51427836SJohn.Forte@Sun.COM 51437836SJohn.Forte@Sun.COM void 51447836SJohn.Forte@Sun.COM stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid, void *arg, 51457836SJohn.Forte@Sun.COM uint32_t flags) 51467836SJohn.Forte@Sun.COM { 51477836SJohn.Forte@Sun.COM if (STMF_EVENT_ENABLED(ilport->ilport_event_hdl, eventid) && 51487836SJohn.Forte@Sun.COM (ilport->ilport_lport->lport_event_handler != NULL)) { 51497836SJohn.Forte@Sun.COM ilport->ilport_lport->lport_event_handler( 51507836SJohn.Forte@Sun.COM ilport->ilport_lport, eventid, arg, flags); 51517836SJohn.Forte@Sun.COM } 51527836SJohn.Forte@Sun.COM } 51537836SJohn.Forte@Sun.COM 51547836SJohn.Forte@Sun.COM void 51557836SJohn.Forte@Sun.COM stmf_svc_init() 51567836SJohn.Forte@Sun.COM { 51577836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 51587836SJohn.Forte@Sun.COM return; 51597836SJohn.Forte@Sun.COM stmf_state.stmf_svc_taskq = ddi_taskq_create(0, "STMF_SVC_TASKQ", 1, 51607836SJohn.Forte@Sun.COM TASKQ_DEFAULTPRI, 0); 51617836SJohn.Forte@Sun.COM (void) ddi_taskq_dispatch(stmf_state.stmf_svc_taskq, 51627836SJohn.Forte@Sun.COM stmf_svc, 0, DDI_SLEEP); 51637836SJohn.Forte@Sun.COM } 51647836SJohn.Forte@Sun.COM 51657836SJohn.Forte@Sun.COM stmf_status_t 51667836SJohn.Forte@Sun.COM stmf_svc_fini() 51677836SJohn.Forte@Sun.COM { 51687836SJohn.Forte@Sun.COM uint32_t i; 51697836SJohn.Forte@Sun.COM 51707836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 51717836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) { 51727836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_TERMINATE; 51737836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 51747836SJohn.Forte@Sun.COM } 51757836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 51767836SJohn.Forte@Sun.COM 51777836SJohn.Forte@Sun.COM /* Wait for 5 seconds */ 51787836SJohn.Forte@Sun.COM for (i = 0; i < 500; i++) { 51797836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_STARTED) 51807836SJohn.Forte@Sun.COM delay(drv_usectohz(10000)); 51817836SJohn.Forte@Sun.COM else 51827836SJohn.Forte@Sun.COM break; 51837836SJohn.Forte@Sun.COM } 51847836SJohn.Forte@Sun.COM if (i == 500) 51857836SJohn.Forte@Sun.COM return (STMF_BUSY); 51867836SJohn.Forte@Sun.COM 51877836SJohn.Forte@Sun.COM ddi_taskq_destroy(stmf_state.stmf_svc_taskq); 51887836SJohn.Forte@Sun.COM 51897836SJohn.Forte@Sun.COM return (STMF_SUCCESS); 51907836SJohn.Forte@Sun.COM } 51917836SJohn.Forte@Sun.COM 51927836SJohn.Forte@Sun.COM /* ARGSUSED */ 51937836SJohn.Forte@Sun.COM void 51947836SJohn.Forte@Sun.COM stmf_svc(void *arg) 51957836SJohn.Forte@Sun.COM { 51967836SJohn.Forte@Sun.COM stmf_svc_req_t *req, **preq; 51977836SJohn.Forte@Sun.COM clock_t td; 51987836SJohn.Forte@Sun.COM clock_t drain_start, drain_next = 0; 51997836SJohn.Forte@Sun.COM clock_t timing_start, timing_next = 0; 52007836SJohn.Forte@Sun.COM clock_t worker_delay = 0; 52017836SJohn.Forte@Sun.COM int deq; 52027836SJohn.Forte@Sun.COM stmf_lu_t *lu; 52037836SJohn.Forte@Sun.COM stmf_i_lu_t *ilu; 52047836SJohn.Forte@Sun.COM stmf_local_port_t *lport; 52057836SJohn.Forte@Sun.COM stmf_i_local_port_t *ilport, *next_ilport; 52067836SJohn.Forte@Sun.COM stmf_i_scsi_session_t *iss; 52077836SJohn.Forte@Sun.COM 52087836SJohn.Forte@Sun.COM td = drv_usectohz(20000); 52097836SJohn.Forte@Sun.COM 52107836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 52117836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_STARTED | STMF_SVC_ACTIVE; 52127836SJohn.Forte@Sun.COM 52137836SJohn.Forte@Sun.COM stmf_svc_loop: 52147836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_flags & STMF_SVC_TERMINATE) { 52157836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= 52167836SJohn.Forte@Sun.COM ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE); 52177836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 52187836SJohn.Forte@Sun.COM return; 52197836SJohn.Forte@Sun.COM } 52207836SJohn.Forte@Sun.COM 52217836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) { 52227836SJohn.Forte@Sun.COM int waitq_add = 0; 52237836SJohn.Forte@Sun.COM req = stmf_state.stmf_svc_active; 52247836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req->svc_next; 52257836SJohn.Forte@Sun.COM 52267836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 52277836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 52287836SJohn.Forte@Sun.COM /* Fallthrough */ 52297836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 52307836SJohn.Forte@Sun.COM /* Fallthrough */ 52317836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 52327836SJohn.Forte@Sun.COM /* Nothing to do */ 52337836SJohn.Forte@Sun.COM waitq_add = 1; 52347836SJohn.Forte@Sun.COM break; 52357836SJohn.Forte@Sun.COM 52367836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 52377836SJohn.Forte@Sun.COM /* Remove all mappings of this LU */ 52387836SJohn.Forte@Sun.COM stmf_session_lu_unmapall((stmf_lu_t *)req->svc_obj); 52397836SJohn.Forte@Sun.COM /* Kill all the pending I/Os for this LU */ 52407836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 52417836SJohn.Forte@Sun.COM stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL, 52427836SJohn.Forte@Sun.COM STMF_ABORTED); 52437836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 52447836SJohn.Forte@Sun.COM waitq_add = 1; 52457836SJohn.Forte@Sun.COM break; 52467836SJohn.Forte@Sun.COM default: 52477836SJohn.Forte@Sun.COM cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d", 52487836SJohn.Forte@Sun.COM req->svc_cmd); 52497836SJohn.Forte@Sun.COM } 52507836SJohn.Forte@Sun.COM 52517836SJohn.Forte@Sun.COM if (waitq_add) { 52527836SJohn.Forte@Sun.COM /* Put it in the wait queue */ 52537836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_waiting; 52547836SJohn.Forte@Sun.COM stmf_state.stmf_svc_waiting = req; 52557836SJohn.Forte@Sun.COM } 52567836SJohn.Forte@Sun.COM } 52577836SJohn.Forte@Sun.COM 52587836SJohn.Forte@Sun.COM /* The waiting list is not going to be modified by anybody else */ 52597836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 52607836SJohn.Forte@Sun.COM 52617836SJohn.Forte@Sun.COM for (preq = &stmf_state.stmf_svc_waiting; (*preq) != NULL; ) { 52627836SJohn.Forte@Sun.COM req = *preq; 52637836SJohn.Forte@Sun.COM deq = 0; 52647836SJohn.Forte@Sun.COM switch (req->svc_cmd) { 52657836SJohn.Forte@Sun.COM case STMF_CMD_LU_ONLINE: 52667836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 52677836SJohn.Forte@Sun.COM deq = 1; 52687836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 52697836SJohn.Forte@Sun.COM break; 52707836SJohn.Forte@Sun.COM 52717836SJohn.Forte@Sun.COM case STMF_CMD_LU_OFFLINE: 52727836SJohn.Forte@Sun.COM lu = (stmf_lu_t *)req->svc_obj; 52737836SJohn.Forte@Sun.COM ilu = (stmf_i_lu_t *)lu->lu_stmf_private; 52747836SJohn.Forte@Sun.COM if (ilu->ilu_ntasks != ilu->ilu_ntasks_free) 52757836SJohn.Forte@Sun.COM break; 52767836SJohn.Forte@Sun.COM deq = 1; 52777836SJohn.Forte@Sun.COM lu->lu_ctl(lu, req->svc_cmd, &req->svc_info); 52787836SJohn.Forte@Sun.COM break; 52797836SJohn.Forte@Sun.COM 52807836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_OFFLINE: 52817836SJohn.Forte@Sun.COM /* Fallthrough */ 52827836SJohn.Forte@Sun.COM case STMF_CMD_LPORT_ONLINE: 52837836SJohn.Forte@Sun.COM lport = (stmf_local_port_t *)req->svc_obj; 52847836SJohn.Forte@Sun.COM deq = 1; 52857836SJohn.Forte@Sun.COM lport->lport_ctl(lport, req->svc_cmd, &req->svc_info); 52867836SJohn.Forte@Sun.COM break; 52877836SJohn.Forte@Sun.COM } 52887836SJohn.Forte@Sun.COM if (deq) { 52897836SJohn.Forte@Sun.COM *preq = req->svc_next; 52907836SJohn.Forte@Sun.COM kmem_free(req, req->svc_req_alloc_size); 52917836SJohn.Forte@Sun.COM } else { 52927836SJohn.Forte@Sun.COM preq = &req->svc_next; 52937836SJohn.Forte@Sun.COM } 52947836SJohn.Forte@Sun.COM } 52957836SJohn.Forte@Sun.COM 52967836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 52977836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active == NULL) { 52987836SJohn.Forte@Sun.COM /* Do timeouts */ 52997836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 53007836SJohn.Forte@Sun.COM ((!timing_next) || (ddi_get_lbolt() >= timing_next))) { 53017836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 53027836SJohn.Forte@Sun.COM /* we are starting a new round */ 53037836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_timing = 53047836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 53057836SJohn.Forte@Sun.COM timing_start = ddi_get_lbolt(); 53067836SJohn.Forte@Sun.COM } 53077836SJohn.Forte@Sun.COM stmf_check_ilu_timing(); 53087836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_timing) { 53097836SJohn.Forte@Sun.COM /* we finished a complete round */ 53107836SJohn.Forte@Sun.COM timing_next = 53117836SJohn.Forte@Sun.COM timing_start + drv_usectohz(5*1000*1000); 53127836SJohn.Forte@Sun.COM } else { 53137836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 53147836SJohn.Forte@Sun.COM timing_next = 53157836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 53167836SJohn.Forte@Sun.COM } 53177836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 53187836SJohn.Forte@Sun.COM goto stmf_svc_loop; 53197836SJohn.Forte@Sun.COM } 53207836SJohn.Forte@Sun.COM /* Check if there are free tasks to clear */ 53217836SJohn.Forte@Sun.COM if (stmf_state.stmf_nlus && 53227836SJohn.Forte@Sun.COM ((!drain_next) || (ddi_get_lbolt() >= drain_next))) { 53237836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 53247836SJohn.Forte@Sun.COM /* we are starting a new round */ 53257836SJohn.Forte@Sun.COM stmf_state.stmf_svc_ilu_draining = 53267836SJohn.Forte@Sun.COM stmf_state.stmf_ilulist; 53277836SJohn.Forte@Sun.COM drain_start = ddi_get_lbolt(); 53287836SJohn.Forte@Sun.COM } 53297836SJohn.Forte@Sun.COM stmf_check_freetask(); 53307836SJohn.Forte@Sun.COM if (!stmf_state.stmf_svc_ilu_draining) { 53317836SJohn.Forte@Sun.COM /* we finished a complete round */ 53327836SJohn.Forte@Sun.COM drain_next = 53337836SJohn.Forte@Sun.COM drain_start + drv_usectohz(10*1000*1000); 53347836SJohn.Forte@Sun.COM } else { 53357836SJohn.Forte@Sun.COM /* we still have some ilu items to check */ 53367836SJohn.Forte@Sun.COM drain_next = 53377836SJohn.Forte@Sun.COM ddi_get_lbolt() + drv_usectohz(1*1000*1000); 53387836SJohn.Forte@Sun.COM } 53397836SJohn.Forte@Sun.COM if (stmf_state.stmf_svc_active) 53407836SJohn.Forte@Sun.COM goto stmf_svc_loop; 53417836SJohn.Forte@Sun.COM } 53427836SJohn.Forte@Sun.COM 53437836SJohn.Forte@Sun.COM /* Check if we need to run worker_mgmt */ 53447836SJohn.Forte@Sun.COM if (ddi_get_lbolt() > worker_delay) { 53457836SJohn.Forte@Sun.COM stmf_worker_mgmt(); 53467836SJohn.Forte@Sun.COM worker_delay = ddi_get_lbolt() + 53477836SJohn.Forte@Sun.COM stmf_worker_mgmt_delay; 53487836SJohn.Forte@Sun.COM } 53497836SJohn.Forte@Sun.COM 53507836SJohn.Forte@Sun.COM /* Check if any active session got its 1st LUN */ 53517836SJohn.Forte@Sun.COM if (stmf_state.stmf_process_initial_luns) { 53527836SJohn.Forte@Sun.COM int stmf_level = 0; 53537836SJohn.Forte@Sun.COM int port_level; 53547836SJohn.Forte@Sun.COM for (ilport = stmf_state.stmf_ilportlist; ilport; 53557836SJohn.Forte@Sun.COM ilport = next_ilport) { 53567836SJohn.Forte@Sun.COM next_ilport = ilport->ilport_next; 53577836SJohn.Forte@Sun.COM if ((ilport->ilport_flags & 53587836SJohn.Forte@Sun.COM ILPORT_SS_GOT_INITIAL_LUNS) == 0) { 53597836SJohn.Forte@Sun.COM continue; 53607836SJohn.Forte@Sun.COM } 53617836SJohn.Forte@Sun.COM port_level = 0; 53627836SJohn.Forte@Sun.COM rw_enter(&ilport->ilport_lock, RW_READER); 53637836SJohn.Forte@Sun.COM for (iss = ilport->ilport_ss_list; iss; 53647836SJohn.Forte@Sun.COM iss = iss->iss_next) { 53657836SJohn.Forte@Sun.COM if ((iss->iss_flags & 53667836SJohn.Forte@Sun.COM ISS_GOT_INITIAL_LUNS) == 0) { 53677836SJohn.Forte@Sun.COM continue; 53687836SJohn.Forte@Sun.COM } 53697836SJohn.Forte@Sun.COM port_level++; 53707836SJohn.Forte@Sun.COM stmf_level++; 53717836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 53727836SJohn.Forte@Sun.COM ~ISS_GOT_INITIAL_LUNS); 53737836SJohn.Forte@Sun.COM atomic_or_32(&iss->iss_flags, 53747836SJohn.Forte@Sun.COM ISS_EVENT_ACTIVE); 53757836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 53767836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 53777836SJohn.Forte@Sun.COM stmf_generate_lport_event(ilport, 53787836SJohn.Forte@Sun.COM LPORT_EVENT_INITIAL_LUN_MAPPED, 53797836SJohn.Forte@Sun.COM iss->iss_ss, 0); 53807836SJohn.Forte@Sun.COM atomic_and_32(&iss->iss_flags, 53817836SJohn.Forte@Sun.COM ~ISS_EVENT_ACTIVE); 53827836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 53837836SJohn.Forte@Sun.COM /* 53847836SJohn.Forte@Sun.COM * scan all the ilports again as the 53857836SJohn.Forte@Sun.COM * ilport list might have changed. 53867836SJohn.Forte@Sun.COM */ 53877836SJohn.Forte@Sun.COM next_ilport = 53887836SJohn.Forte@Sun.COM stmf_state.stmf_ilportlist; 53897836SJohn.Forte@Sun.COM break; 53907836SJohn.Forte@Sun.COM } 53917836SJohn.Forte@Sun.COM if (port_level == 0) { 53927836SJohn.Forte@Sun.COM atomic_and_32(&ilport->ilport_flags, 53937836SJohn.Forte@Sun.COM ~ILPORT_SS_GOT_INITIAL_LUNS); 53947836SJohn.Forte@Sun.COM } 53957836SJohn.Forte@Sun.COM /* drop the lock if we are holding it. */ 53967836SJohn.Forte@Sun.COM if (rw_lock_held(&ilport->ilport_lock)) 53977836SJohn.Forte@Sun.COM rw_exit(&ilport->ilport_lock); 53987836SJohn.Forte@Sun.COM 53997836SJohn.Forte@Sun.COM /* Max 4 session at a time */ 54007836SJohn.Forte@Sun.COM if (stmf_level >= 4) { 54017836SJohn.Forte@Sun.COM break; 54027836SJohn.Forte@Sun.COM } 54037836SJohn.Forte@Sun.COM } 54047836SJohn.Forte@Sun.COM if (stmf_level == 0) { 54057836SJohn.Forte@Sun.COM stmf_state.stmf_process_initial_luns = 0; 54067836SJohn.Forte@Sun.COM } 54077836SJohn.Forte@Sun.COM } 54087836SJohn.Forte@Sun.COM 54097836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags &= ~STMF_SVC_ACTIVE; 54107836SJohn.Forte@Sun.COM (void) cv_timedwait(&stmf_state.stmf_cv, &stmf_state.stmf_lock, 54117836SJohn.Forte@Sun.COM ddi_get_lbolt() + td); 54127836SJohn.Forte@Sun.COM stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE; 54137836SJohn.Forte@Sun.COM } 54147836SJohn.Forte@Sun.COM goto stmf_svc_loop; 54157836SJohn.Forte@Sun.COM } 54167836SJohn.Forte@Sun.COM 54177836SJohn.Forte@Sun.COM void 54187836SJohn.Forte@Sun.COM stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info) 54197836SJohn.Forte@Sun.COM { 54207836SJohn.Forte@Sun.COM stmf_svc_req_t *req; 54217836SJohn.Forte@Sun.COM int s; 54227836SJohn.Forte@Sun.COM 54237836SJohn.Forte@Sun.COM ASSERT(!mutex_owned(&stmf_state.stmf_lock)); 54247836SJohn.Forte@Sun.COM s = sizeof (stmf_svc_req_t); 54257836SJohn.Forte@Sun.COM if (info->st_additional_info) { 54267836SJohn.Forte@Sun.COM s += strlen(info->st_additional_info) + 1; 54277836SJohn.Forte@Sun.COM } 54287836SJohn.Forte@Sun.COM req = kmem_zalloc(s, KM_SLEEP); 54297836SJohn.Forte@Sun.COM 54307836SJohn.Forte@Sun.COM req->svc_cmd = cmd; 54317836SJohn.Forte@Sun.COM req->svc_obj = obj; 54327836SJohn.Forte@Sun.COM req->svc_info.st_rflags = info->st_rflags; 54337836SJohn.Forte@Sun.COM if (info->st_additional_info) { 54347836SJohn.Forte@Sun.COM req->svc_info.st_additional_info = (char *)(GET_BYTE_OFFSET(req, 54357836SJohn.Forte@Sun.COM sizeof (stmf_svc_req_t))); 54367836SJohn.Forte@Sun.COM (void) strcpy(req->svc_info.st_additional_info, 54377836SJohn.Forte@Sun.COM info->st_additional_info); 54387836SJohn.Forte@Sun.COM } 54397836SJohn.Forte@Sun.COM req->svc_req_alloc_size = s; 54407836SJohn.Forte@Sun.COM 54417836SJohn.Forte@Sun.COM mutex_enter(&stmf_state.stmf_lock); 54427836SJohn.Forte@Sun.COM req->svc_next = stmf_state.stmf_svc_active; 54437836SJohn.Forte@Sun.COM stmf_state.stmf_svc_active = req; 54447836SJohn.Forte@Sun.COM if ((stmf_state.stmf_svc_flags & STMF_SVC_ACTIVE) == 0) { 54457836SJohn.Forte@Sun.COM cv_signal(&stmf_state.stmf_cv); 54467836SJohn.Forte@Sun.COM } 54477836SJohn.Forte@Sun.COM mutex_exit(&stmf_state.stmf_lock); 54487836SJohn.Forte@Sun.COM } 54497836SJohn.Forte@Sun.COM 54507836SJohn.Forte@Sun.COM void 54517836SJohn.Forte@Sun.COM stmf_trace(caddr_t ident, const char *fmt, ...) 54527836SJohn.Forte@Sun.COM { 54537836SJohn.Forte@Sun.COM va_list args; 54547836SJohn.Forte@Sun.COM char tbuf[160]; 54557836SJohn.Forte@Sun.COM int len; 54567836SJohn.Forte@Sun.COM 54577836SJohn.Forte@Sun.COM if (!stmf_trace_on) 54587836SJohn.Forte@Sun.COM return; 54597836SJohn.Forte@Sun.COM len = snprintf(tbuf, 158, "%s:%07lu: ", ident ? ident : "", 54607836SJohn.Forte@Sun.COM ddi_get_lbolt()); 54617836SJohn.Forte@Sun.COM va_start(args, fmt); 54627836SJohn.Forte@Sun.COM len += vsnprintf(tbuf + len, 158 - len, fmt, args); 54637836SJohn.Forte@Sun.COM va_end(args); 54647836SJohn.Forte@Sun.COM 54657836SJohn.Forte@Sun.COM if (len > 158) { 54667836SJohn.Forte@Sun.COM len = 158; 54677836SJohn.Forte@Sun.COM } 54687836SJohn.Forte@Sun.COM tbuf[len++] = '\n'; 54697836SJohn.Forte@Sun.COM tbuf[len] = 0; 54707836SJohn.Forte@Sun.COM 54717836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 54727836SJohn.Forte@Sun.COM bcopy(tbuf, &stmf_trace_buf[trace_buf_curndx], len+1); 54737836SJohn.Forte@Sun.COM trace_buf_curndx += len; 54747836SJohn.Forte@Sun.COM if (trace_buf_curndx > (trace_buf_size - 320)) 54757836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 54767836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 54777836SJohn.Forte@Sun.COM } 54787836SJohn.Forte@Sun.COM 54797836SJohn.Forte@Sun.COM void 54807836SJohn.Forte@Sun.COM stmf_trace_clear() 54817836SJohn.Forte@Sun.COM { 54827836SJohn.Forte@Sun.COM if (!stmf_trace_on) 54837836SJohn.Forte@Sun.COM return; 54847836SJohn.Forte@Sun.COM mutex_enter(&trace_buf_lock); 54857836SJohn.Forte@Sun.COM trace_buf_curndx = 0; 54867836SJohn.Forte@Sun.COM if (trace_buf_size > 0) 54877836SJohn.Forte@Sun.COM stmf_trace_buf[0] = 0; 54887836SJohn.Forte@Sun.COM mutex_exit(&trace_buf_lock); 54897836SJohn.Forte@Sun.COM } 54907836SJohn.Forte@Sun.COM 54917836SJohn.Forte@Sun.COM static void 54927836SJohn.Forte@Sun.COM stmf_abort_task_offline(scsi_task_t *task, int offline_lu, char *info) 54937836SJohn.Forte@Sun.COM { 54947836SJohn.Forte@Sun.COM stmf_state_change_info_t change_info; 54957836SJohn.Forte@Sun.COM void *ctl_private; 54967836SJohn.Forte@Sun.COM uint32_t ctl_cmd; 54977836SJohn.Forte@Sun.COM int msg = 0; 54987836SJohn.Forte@Sun.COM 54997836SJohn.Forte@Sun.COM stmf_trace("FROM STMF", "abort_task_offline called for %s: %s", 55007836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : "no additional info"); 55017836SJohn.Forte@Sun.COM change_info.st_additional_info = info; 55027836SJohn.Forte@Sun.COM if (offline_lu) { 55037836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 55047836SJohn.Forte@Sun.COM STMF_RFLAG_LU_ABORT; 55057836SJohn.Forte@Sun.COM ctl_private = task->task_lu; 55067836SJohn.Forte@Sun.COM if (((stmf_i_lu_t *) 55077836SJohn.Forte@Sun.COM task->task_lu->lu_stmf_private)->ilu_state == 55087836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 55097836SJohn.Forte@Sun.COM msg = 1; 55107836SJohn.Forte@Sun.COM } 55117836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LU_OFFLINE; 55127836SJohn.Forte@Sun.COM } else { 55137836SJohn.Forte@Sun.COM change_info.st_rflags = STMF_RFLAG_RESET | 55147836SJohn.Forte@Sun.COM STMF_RFLAG_LPORT_ABORT; 55157836SJohn.Forte@Sun.COM ctl_private = task->task_lport; 55167836SJohn.Forte@Sun.COM if (((stmf_i_local_port_t *) 55177836SJohn.Forte@Sun.COM task->task_lport->lport_stmf_private)->ilport_state == 55187836SJohn.Forte@Sun.COM STMF_STATE_ONLINE) { 55197836SJohn.Forte@Sun.COM msg = 1; 55207836SJohn.Forte@Sun.COM } 55217836SJohn.Forte@Sun.COM ctl_cmd = STMF_CMD_LPORT_OFFLINE; 55227836SJohn.Forte@Sun.COM } 55237836SJohn.Forte@Sun.COM 55247836SJohn.Forte@Sun.COM if (msg) { 55257836SJohn.Forte@Sun.COM stmf_trace(0, "Calling stmf_ctl to offline %s : %s", 55267836SJohn.Forte@Sun.COM offline_lu ? "LU" : "LPORT", info ? info : 55277836SJohn.Forte@Sun.COM "<no additional info>"); 55287836SJohn.Forte@Sun.COM } 55297836SJohn.Forte@Sun.COM (void) stmf_ctl(ctl_cmd, ctl_private, &change_info); 55307836SJohn.Forte@Sun.COM } 5531