Print this page
3866 panic in idm module
3867 stmfCreateLu failed: GUID_IN_USE
3868 iscsi target not accepting any new connections
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Jeremy Jones <jeremy@delphix.com>
Reviewed by: Eric Diven <eric.diven@delphix.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Reviewed by: T Nguyen <truongqnguien@gmail.com>
Approved by: Gordon Ross <gwr@nexenta.com>
3862 stmf + kstat = kernel panic
3863 stmf_itl_task_start() must check for ilu->ilu_kstat_io is non-null
3864 memory leak in the iSCSI code
Reviewed by: Adam Leventhal <ahl@delphix.com>
Reviewed by: Jeremy Jones <jeremy@delphix.com>
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Dan McDonald <danmcd@nexenta.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Richard Elling <richard.elling@gmail.com>
Approved by: Gordon Ross <gwr@nexenta.com>
3621 ZFS LU stuck in the offlining state
Reviewed by: Sebastien Roy <sebastien.roy@delphix.com>
Reviewed by: Jeff Biseda <jeff.biseda@delphix.com>
Reviewed by: Dan McDonald <danmcd@nexenta.com>
Approved by: Christopher Siden <christopher.siden@delphix.com>

@@ -21,10 +21,12 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Copyright 2012, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2013 by Delphix. All rights reserved.
+ * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  */
 
 #include <sys/conf.h>
 #include <sys/file.h>
 #include <sys/ddi.h>

@@ -63,10 +65,19 @@
 /* start messages at 1 */
 static uint64_t stmf_proxy_msg_id = 1;
 #define MSG_ID_TM_BIT   0x8000000000000000
 #define ALIGNED_TO_8BYTE_BOUNDARY(i)    (((i) + 7) & ~7)
 
+/*
+ * When stmf_io_deadman_enabled is set to B_TRUE, we check that finishing up
+ * I/O operations on an offlining LU doesn't take longer than stmf_io_deadman
+ * seconds. If it does, we trigger a panic to inform the user of hung I/O
+ * blocking us for too long.
+ */
+boolean_t stmf_io_deadman_enabled = B_TRUE;
+int stmf_io_deadman = 1000;                     /* seconds */
+
 struct stmf_svc_clocks;
 
 static int stmf_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 static int stmf_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
 static int stmf_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,

@@ -89,10 +100,11 @@
 static char stmf_ctoi(char c);
 stmf_xfer_data_t *stmf_prepare_tpgs_data(uint8_t ilu_alua);
 void stmf_svc_init();
 stmf_status_t stmf_svc_fini();
 void stmf_svc(void *arg);
+static void stmf_wait_ilu_tasks_finish(stmf_i_lu_t *ilu);
 void stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info);
 static void stmf_svc_kill_obj_requests(void *obj);
 static void stmf_svc_timeout(struct stmf_svc_clocks *);
 void stmf_check_freetask();
 void stmf_abort_target_reset(scsi_task_t *task);

@@ -161,18 +173,10 @@
     scsi_devid_desc_t *rport_devid);
 static stmf_i_remote_port_t *stmf_irport_lookup_locked(
     scsi_devid_desc_t *rport_devid);
 static void stmf_irport_deregister(stmf_i_remote_port_t *irport);
 
-static void stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks);
-static void stmf_delete_itl_kstat_by_lport(char *);
-static void stmf_delete_itl_kstat_by_guid(char *);
-static int stmf_itl_kstat_compare(const void*, const void*);
-static stmf_i_itl_kstat_t *stmf_itl_kstat_lookup(char *kstat_nm);
-static stmf_i_itl_kstat_t *stmf_itl_kstat_create(stmf_itl_data_t *itl,
-    char *nm, scsi_devid_desc_t *lport, scsi_devid_desc_t *lun);
-
 extern struct mod_ops mod_driverops;
 
 /* =====[ Tunables ]===== */
 /* Internal tracing */
 volatile int    stmf_trace_on = 1;

@@ -310,13 +314,10 @@
             offsetof(stmf_i_remote_port_t, irport_ln));
         stmf_state.stmf_ilport_inst_space =
             id_space_create("lport-instances", 0, MAX_ILPORT);
         stmf_state.stmf_irport_inst_space =
             id_space_create("rport-instances", 0, MAX_IRPORT);
-        avl_create(&stmf_state.stmf_itl_kstat_list,
-            stmf_itl_kstat_compare, sizeof (stmf_i_itl_kstat_t),
-            offsetof(stmf_i_itl_kstat_t, iitl_kstat_ln));
         stmf_view_init();
         stmf_svc_init();
         stmf_dlun_init();
         return (ret);
 }

@@ -324,11 +325,10 @@
 int
 _fini(void)
 {
         int ret;
         stmf_i_remote_port_t    *irport;
-        stmf_i_itl_kstat_t      *ks_itl;
         void                    *avl_dest_cookie = NULL;
 
         if (stmf_state.stmf_service_running)
                 return (EBUSY);
         if ((!stmf_allow_modunload) &&

@@ -365,18 +365,10 @@
                 stmf_irport_destroy(irport);
         avl_destroy(&stmf_state.stmf_irportlist);
         id_space_destroy(stmf_state.stmf_ilport_inst_space);
         id_space_destroy(stmf_state.stmf_irport_inst_space);
 
-        avl_dest_cookie = NULL;
-        while ((ks_itl = avl_destroy_nodes(&stmf_state.stmf_itl_kstat_list,
-            &avl_dest_cookie)) != NULL) {
-                stmf_teardown_itl_kstats(ks_itl);
-                kmem_free(ks_itl, sizeof (ks_itl));
-        }
-        avl_destroy(&stmf_state.stmf_itl_kstat_list);
-
         kmem_free(stmf_trace_buf, stmf_trace_buf_size);
         mutex_destroy(&trace_buf_lock);
         mutex_destroy(&stmf_state.stmf_lock);
         cv_destroy(&stmf_state.stmf_cv);
         return (ret);

@@ -1590,10 +1582,11 @@
         std->config_state = stmf_state.stmf_config_state;
         mutex_exit(&stmf_state.stmf_lock);
 
         return (0);
 }
+
 /*
  * handles registration message from pppt for a logical unit
  */
 stmf_status_t
 stmf_ic_lu_reg(stmf_ic_reg_dereg_lun_msg_t *msg, uint32_t type)

@@ -3057,10 +3050,11 @@
                 ((stmf_i_lu_provider_t *)
                     (lu->lu_lp->lp_stmf_private))->ilp_nlus++;
         }
         ilu->ilu_cur_task_cntr = &ilu->ilu_task_cntr1;
         STMF_EVENT_ALLOC_HANDLE(ilu->ilu_event_hdl);
+        cv_init(&ilu->ilu_offline_pending_cv, NULL, CV_DRIVER, NULL);
         stmf_create_kstat_lu(ilu);
         /*
          * register with proxy module if available and logical unit
          * is in active state
          */

@@ -3194,11 +3188,11 @@
         }
         if (ilu->ilu_kstat_io) {
                 kstat_delete(ilu->ilu_kstat_io);
                 mutex_destroy(&ilu->ilu_kstat_lock);
         }
-        stmf_delete_itl_kstat_by_guid(ilu->ilu_ascii_hex_guid);
+        cv_destroy(&ilu->ilu_offline_pending_cv);
         mutex_exit(&stmf_state.stmf_lock);
         return (STMF_SUCCESS);
 }
 
 void

@@ -3372,11 +3366,10 @@
         }
         if (ilport->ilport_kstat_io) {
                 kstat_delete(ilport->ilport_kstat_io);
                 mutex_destroy(&ilport->ilport_kstat_lock);
         }
-        stmf_delete_itl_kstat_by_lport(ilport->ilport_kstat_tgt_name);
         mutex_exit(&stmf_state.stmf_lock);
         return (STMF_SUCCESS);
 }
 
 /*

@@ -3701,324 +3694,10 @@
         }
         mutex_exit(&stmf_state.stmf_lock);
         return (NULL);
 }
 
-#define MAX_ALIAS               128
-
-static int
-stmf_itl_kstat_compare(const void *itl_kstat_1, const void *itl_kstat_2)
-{
-        const   stmf_i_itl_kstat_t      *kstat_nm1 = itl_kstat_1;
-        const   stmf_i_itl_kstat_t      *kstat_nm2 = itl_kstat_2;
-        int     ret;
-
-        ret = strcmp(kstat_nm1->iitl_kstat_nm, kstat_nm2->iitl_kstat_nm);
-        if (ret < 0) {
-                return (-1);
-        } else if (ret > 0) {
-                return (1);
-        }
-        return (0);
-}
-
-static stmf_i_itl_kstat_t *
-stmf_itl_kstat_lookup(char *kstat_nm)
-{
-        stmf_i_itl_kstat_t      tmp;
-        stmf_i_itl_kstat_t      *itl_kstat;
-
-        ASSERT(mutex_owned(&stmf_state.stmf_lock));
-        (void) strcpy(tmp.iitl_kstat_nm, kstat_nm);
-        itl_kstat = avl_find(&stmf_state.stmf_itl_kstat_list, &tmp, NULL);
-        return (itl_kstat);
-}
-
-static void
-stmf_delete_itl_kstat_by_lport(char *tgt)
-{
-        stmf_i_itl_kstat_t      *ks_itl, *next;
-
-        ASSERT(mutex_owned(&stmf_state.stmf_lock));
-        ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
-        for (; ks_itl != NULL; ks_itl = next) {
-                next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
-                if (strcmp(ks_itl->iitl_kstat_lport, tgt) == 0) {
-                        stmf_teardown_itl_kstats(ks_itl);
-                        avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
-                        kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
-                }
-        }
-}
-
-static void
-stmf_delete_itl_kstat_by_guid(char *guid)
-{
-        stmf_i_itl_kstat_t      *ks_itl, *next;
-
-        ASSERT(mutex_owned(&stmf_state.stmf_lock));
-        ks_itl = avl_first(&stmf_state.stmf_itl_kstat_list);
-        for (; ks_itl != NULL; ks_itl = next) {
-                next = AVL_NEXT(&stmf_state.stmf_itl_kstat_list, ks_itl);
-                if (strcmp(ks_itl->iitl_kstat_guid, guid) == 0) {
-                        stmf_teardown_itl_kstats(ks_itl);
-                        avl_remove(&stmf_state.stmf_itl_kstat_list, ks_itl);
-                        kmem_free(ks_itl, sizeof (stmf_i_itl_kstat_t));
-                }
-        }
-}
-
-static stmf_i_itl_kstat_t *
-stmf_itl_kstat_create(stmf_itl_data_t *itl, char *nm,
-    scsi_devid_desc_t *lport, scsi_devid_desc_t *lun)
-{
-        stmf_i_itl_kstat_t      *ks_itl;
-        int                     i, len;
-
-        ASSERT(mutex_owned(&stmf_state.stmf_lock));
-        if ((ks_itl = stmf_itl_kstat_lookup(nm)) != NULL)
-                return (ks_itl);
-
-        len = sizeof (stmf_i_itl_kstat_t);
-        ks_itl = kmem_zalloc(len, KM_NOSLEEP);
-        if (ks_itl == NULL)
-                return (NULL);
-
-        (void) strcpy(ks_itl->iitl_kstat_nm, nm);
-        bcopy(lport->ident, ks_itl->iitl_kstat_lport, lport->ident_length);
-        ks_itl->iitl_kstat_lport[lport->ident_length] = '\0';
-        for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
-                (void) sprintf(&ks_itl->iitl_kstat_guid[i * 2], "%02x",
-                    lun->ident[i]);
-        }
-        ks_itl->iitl_kstat_strbuf = itl->itl_kstat_strbuf;
-        ks_itl->iitl_kstat_strbuflen = itl->itl_kstat_strbuflen;
-        ks_itl->iitl_kstat_info = itl->itl_kstat_info;
-        ks_itl->iitl_kstat_taskq = itl->itl_kstat_taskq;
-        ks_itl->iitl_kstat_lu_xfer = itl->itl_kstat_lu_xfer;
-        ks_itl->iitl_kstat_lport_xfer = itl->itl_kstat_lport_xfer;
-        avl_add(&stmf_state.stmf_itl_kstat_list, ks_itl);
-
-        return (ks_itl);
-}
-
-stmf_status_t
-stmf_setup_itl_kstats(stmf_itl_data_t *itl)
-{
-        char                            ks_itl_id[32];
-        char                            ks_nm[KSTAT_STRLEN];
-        char                            ks_itl_nm[KSTAT_STRLEN];
-        stmf_kstat_itl_info_t           *ks_itl;
-        stmf_scsi_session_t             *ss;
-        stmf_i_scsi_session_t           *iss;
-        stmf_i_local_port_t             *ilport;
-        char                            *strbuf;
-        int                             id, len, i;
-        char                            *rport_alias;
-        char                            *lport_alias;
-        char                            *lu_alias;
-        stmf_i_itl_kstat_t              *tmp_kstat;
-
-        /*
-         * Allocate enough memory in the ITL to hold the relevant
-         * identifiers.
-         * rport and lport identifiers come from the stmf_scsi_session_t.
-         * ident might not be null terminated.
-         */
-        ss = itl->itl_session->iss_ss;
-        iss = ss->ss_stmf_private;
-        ilport = ss->ss_lport->lport_stmf_private;
-        (void) snprintf(ks_itl_id, 32, "%d.%d.%d",
-            iss->iss_irport->irport_instance, ilport->ilport_instance,
-            itl->itl_lun);
-
-        (void) snprintf(ks_itl_nm, KSTAT_STRLEN, "itl_%s", ks_itl_id);
-        /*
-         * let's verify this itl_kstat already exist
-         */
-        if ((tmp_kstat = stmf_itl_kstat_lookup(ks_itl_nm)) != NULL) {
-                itl->itl_kstat_strbuf = tmp_kstat->iitl_kstat_strbuf;
-                itl->itl_kstat_strbuflen = tmp_kstat->iitl_kstat_strbuflen;
-                itl->itl_kstat_info = tmp_kstat->iitl_kstat_info;
-                itl->itl_kstat_taskq = tmp_kstat->iitl_kstat_taskq;
-                itl->itl_kstat_lu_xfer = tmp_kstat->iitl_kstat_lu_xfer;
-                itl->itl_kstat_lport_xfer = tmp_kstat->iitl_kstat_lport_xfer;
-                return (STMF_SUCCESS);
-        }
-
-        /* New itl_kstat */
-        rport_alias = (ss->ss_rport_alias == NULL) ?
-            "" : ss->ss_rport_alias;
-        lport_alias = (ss->ss_lport->lport_alias == NULL) ?
-            "" : ss->ss_lport->lport_alias;
-        lu_alias = (itl->itl_ilu->ilu_lu->lu_alias == NULL) ?
-            "" : itl->itl_ilu->ilu_lu->lu_alias;
-
-        itl->itl_kstat_strbuflen = (ss->ss_rport_id->ident_length + 1) +
-            (strnlen(rport_alias, MAX_ALIAS) + 1) +
-            (ss->ss_lport->lport_id->ident_length + 1) +
-            (strnlen(lport_alias, MAX_ALIAS) + 1) +
-            (STMF_GUID_INPUT + 1) +
-            (strnlen(lu_alias, MAX_ALIAS) + 1) +
-            MAX_PROTO_STR_LEN;
-        itl->itl_kstat_strbuf = kmem_zalloc(itl->itl_kstat_strbuflen,
-            KM_NOSLEEP);
-        if (itl->itl_kstat_strbuf == NULL) {
-                return (STMF_ALLOC_FAILURE);
-        }
-
-        ks_itl = (stmf_kstat_itl_info_t *)kmem_zalloc(sizeof (*ks_itl),
-            KM_NOSLEEP);
-        if (ks_itl == NULL) {
-                kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
-                return (STMF_ALLOC_FAILURE);
-        }
-
-        if ((itl->itl_kstat_info = kstat_create(STMF_MODULE_NAME,
-            0, ks_itl_nm, "misc", KSTAT_TYPE_NAMED,
-            sizeof (stmf_kstat_itl_info_t) / sizeof (kstat_named_t),
-            KSTAT_FLAG_VIRTUAL)) == NULL) {
-                goto itl_kstat_cleanup;
-        }
-
-        itl->itl_kstat_info->ks_data_size += itl->itl_kstat_strbuflen;
-        itl->itl_kstat_info->ks_data = ks_itl;
-
-        kstat_named_init(&ks_itl->i_rport_name, "rport-name",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_rport_alias, "rport-alias",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_lport_name, "lport-name",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_lport_alias, "lport-alias",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_protocol, "protocol",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_lu_guid, "lu-guid",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_lu_alias, "lu-alias",
-            KSTAT_DATA_STRING);
-        kstat_named_init(&ks_itl->i_lu_number, "lu-number",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_task_waitq_elapsed, "task-waitq-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_task_read_elapsed, "task-read-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_task_write_elapsed, "task-write-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_lu_read_elapsed, "lu-read-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_lu_write_elapsed, "lu-write-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_lport_read_elapsed, "lport-read-elapsed",
-            KSTAT_DATA_UINT64);
-        kstat_named_init(&ks_itl->i_lport_write_elapsed, "lport-write-elapsed",
-            KSTAT_DATA_UINT64);
-
-        strbuf = itl->itl_kstat_strbuf;
-
-        /* Rport */
-        len = ss->ss_rport_id->ident_length;
-        bcopy(ss->ss_rport_id->ident, strbuf, len);
-        strbuf += len;
-        *strbuf = '\0';
-        kstat_named_setstr(&ks_itl->i_rport_name, strbuf - len);
-        strbuf++;
-
-        len = strnlen(rport_alias, MAX_ALIAS);
-        (void) strncpy(strbuf, rport_alias, len + 1);
-        kstat_named_setstr(&ks_itl->i_rport_alias, strbuf);
-        strbuf += len + 1;
-
-        /* Lport */
-        len = ss->ss_lport->lport_id->ident_length;
-        bcopy(ss->ss_lport->lport_id->ident, strbuf, len);
-        strbuf += len;
-        *strbuf = '\0';
-        kstat_named_setstr(&ks_itl->i_lport_name, strbuf - len);
-        strbuf++;
-
-        len = strnlen(lport_alias, MAX_ALIAS);
-        (void) strncpy(strbuf, lport_alias, len + 1);
-        kstat_named_setstr(&ks_itl->i_lport_alias, strbuf);
-        strbuf += len + 1;
-
-        id = (ss->ss_lport->lport_id->protocol_id > PROTOCOL_ANY) ?
-            PROTOCOL_ANY : ss->ss_lport->lport_id->protocol_id;
-        kstat_named_setstr(&ks_itl->i_protocol, protocol_ident[id]);
-
-        /* LU */
-        for (i = 0; i < STMF_GUID_INPUT / 2; i++) {
-                (void) sprintf(&strbuf[i * 2], "%02x",
-                    itl->itl_ilu->ilu_lu->lu_id->ident[i]);
-        }
-        kstat_named_setstr(&ks_itl->i_lu_guid, strbuf);
-        strbuf += STMF_GUID_INPUT + 1;
-
-        len = strnlen(lu_alias, MAX_ALIAS);
-        (void) strncpy(strbuf, lu_alias, len + 1);
-        kstat_named_setstr(&ks_itl->i_lu_alias, strbuf);
-        strbuf += len + 1;
-
-        ks_itl->i_lu_number.value.ui64 = itl->itl_lun;
-
-        /* Now create the I/O kstats */
-        (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_tasks_%s",  ks_itl_id);
-        if ((itl->itl_kstat_taskq = kstat_create(STMF_MODULE_NAME, 0,
-            ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-                goto itl_kstat_cleanup;
-        }
-
-        (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lu_%s",  ks_itl_id);
-        if ((itl->itl_kstat_lu_xfer = kstat_create(STMF_MODULE_NAME, 0,
-            ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-                goto itl_kstat_cleanup;
-        }
-
-        (void) snprintf(ks_nm, KSTAT_STRLEN, "itl_lport_%s",  ks_itl_id);
-        if ((itl->itl_kstat_lport_xfer = kstat_create(STMF_MODULE_NAME, 0,
-            ks_nm, "io", KSTAT_TYPE_IO, 1, 0)) == NULL) {
-                goto itl_kstat_cleanup;
-        }
-
-        /* Install all the kstats */
-        kstat_install(itl->itl_kstat_info);
-        kstat_install(itl->itl_kstat_taskq);
-        kstat_install(itl->itl_kstat_lu_xfer);
-        kstat_install(itl->itl_kstat_lport_xfer);
-
-        /* Add new itl_kstat to stmf_itl_kstat_list */
-        if (stmf_itl_kstat_create(itl, ks_itl_nm, ss->ss_lport->lport_id,
-            itl->itl_ilu->ilu_lu->lu_id) != NULL)
-                return (STMF_SUCCESS);
-
-itl_kstat_cleanup:
-        if (itl->itl_kstat_taskq)
-                kstat_delete(itl->itl_kstat_taskq);
-        if (itl->itl_kstat_lu_xfer)
-                kstat_delete(itl->itl_kstat_lu_xfer);
-        if (itl->itl_kstat_lport_xfer)
-                kstat_delete(itl->itl_kstat_lport_xfer);
-        if (itl->itl_kstat_info)
-                kstat_delete(itl->itl_kstat_info);
-        kmem_free(ks_itl, sizeof (*ks_itl));
-        kmem_free(itl->itl_kstat_strbuf, itl->itl_kstat_strbuflen);
-        cmn_err(CE_WARN, "STMF: kstat_create itl failed");
-        return (STMF_ALLOC_FAILURE);
-}
-
-static void
-stmf_teardown_itl_kstats(stmf_i_itl_kstat_t *ks)
-{
-        kstat_delete(ks->iitl_kstat_lport_xfer);
-        kstat_delete(ks->iitl_kstat_lu_xfer);
-        kstat_delete(ks->iitl_kstat_taskq);
-        kmem_free(ks->iitl_kstat_info->ks_data, sizeof (stmf_kstat_itl_info_t));
-        kstat_delete(ks->iitl_kstat_info);
-        kmem_free(ks->iitl_kstat_strbuf, ks->iitl_kstat_strbuflen);
-}
-
 void
 stmf_release_itl_handle(stmf_lu_t *lu, stmf_itl_data_t *itl)
 {
         stmf_itl_data_t **itlpp;
         stmf_i_lu_t *ilu;

@@ -4058,13 +3737,10 @@
                         return (STMF_NOT_FOUND);
         } else {
                 iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
         }
 
-        /*
-         * Acquire stmf_lock for stmf_itl_kstat_lookup.
-         */
         mutex_enter(&stmf_state.stmf_lock);
         rw_enter(iss->iss_lockp, RW_WRITER);
         n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
         lun_map_ent = (stmf_lun_map_ent_t *)
             stmf_get_ent_from_map(iss->iss_sm, n);

@@ -4090,17 +3766,10 @@
         itl->itl_session = iss;
         itl->itl_counter = 1;
         itl->itl_lun = n;
         itl->itl_handle = itl_handle;
 
-        if (stmf_setup_itl_kstats(itl) != STMF_SUCCESS) {
-                kmem_free(itl, sizeof (*itl));
-                rw_exit(iss->iss_lockp);
-                mutex_exit(&stmf_state.stmf_lock);
-                return (STMF_ALLOC_FAILURE);
-        }
-
         mutex_enter(&ilu->ilu_task_lock);
         itl->itl_next = ilu->ilu_itl_list;
         ilu->ilu_itl_list = itl;
         mutex_exit(&ilu->ilu_task_lock);
         lun_map_ent->ent_itl_datap = itl;

@@ -4126,14 +3795,10 @@
         ASSERT(itl->itl_counter);
 
         if (atomic_add_32_nv(&itl->itl_counter, -1))
                 return;
 
-        drv_usecwait(10);
-        if (itl->itl_counter)
-                return;
-
         stmf_release_itl_handle(lu, itl);
 }
 
 stmf_status_t
 stmf_deregister_all_lu_itl_handles(stmf_lu_t *lu)

@@ -4200,70 +3865,10 @@
 
         return (STMF_SUCCESS);
 }
 
 stmf_status_t
-stmf_deregister_itl_handle(stmf_lu_t *lu, uint8_t *lun,
-    stmf_scsi_session_t *ss, uint64_t session_id, void *itl_handle)
-{
-        stmf_i_scsi_session_t *iss;
-        stmf_itl_data_t *itl;
-        stmf_lun_map_ent_t *ent;
-        stmf_lun_map_t *lm;
-        int i;
-        uint16_t n;
-
-        if (ss == NULL) {
-                if (session_id == STMF_SESSION_ID_NONE)
-                        return (STMF_INVALID_ARG);
-                iss = stmf_session_id_to_issptr(session_id, 1);
-                if (iss == NULL)
-                        return (STMF_NOT_FOUND);
-        } else {
-                iss = (stmf_i_scsi_session_t *)ss->ss_stmf_private;
-                rw_enter(iss->iss_lockp, RW_WRITER);
-        }
-        lm = iss->iss_sm;
-        if (lm == NULL) {
-                rw_exit(iss->iss_lockp);
-                return (STMF_NOT_FOUND);
-        }
-
-        if (lun) {
-                n = ((uint16_t)lun[1] | (((uint16_t)(lun[0] & 0x3F)) << 8));
-                ent = (stmf_lun_map_ent_t *)
-                    stmf_get_ent_from_map(iss->iss_sm, n);
-        } else {
-                if (itl_handle == NULL) {
-                        rw_exit(iss->iss_lockp);
-                        return (STMF_INVALID_ARG);
-                }
-                ent = NULL;
-                for (i = 0; i < lm->lm_nentries; i++) {
-                        if (lm->lm_plus[i] == NULL)
-                                continue;
-                        ent = (stmf_lun_map_ent_t *)lm->lm_plus[i];
-                        if (ent->ent_itl_datap &&
-                            (ent->ent_itl_datap->itl_handle == itl_handle)) {
-                                break;
-                        }
-                }
-        }
-        if ((ent == NULL) || (ent->ent_lu != lu) ||
-            (ent->ent_itl_datap == NULL)) {
-                rw_exit(iss->iss_lockp);
-                return (STMF_NOT_FOUND);
-        }
-        itl = ent->ent_itl_datap;
-        ent->ent_itl_datap = NULL;
-        rw_exit(iss->iss_lockp);
-        stmf_do_itl_dereg(lu, itl, STMF_ITL_REASON_DEREG_REQUEST);
-
-        return (STMF_SUCCESS);
-}
-
-stmf_status_t
 stmf_get_itl_handle(stmf_lu_t *lu, uint8_t *lun, stmf_scsi_session_t *ss,
     uint64_t session_id, void **itl_handle_retp)
 {
         stmf_i_scsi_session_t *iss;
         stmf_lun_map_ent_t *ent;

@@ -4445,10 +4050,12 @@
         ilu = lu->lu_stmf_private;
         if (ilu->ilu_flags & ILU_RESET_ACTIVE) {
                 rw_exit(iss->iss_lockp);
                 return (NULL);
         }
+        ASSERT(lu == dlun0 || (ilu->ilu_state != STMF_STATE_OFFLINING &&
+            ilu->ilu_state != STMF_STATE_OFFLINE));
         do {
                 if (ilu->ilu_free_tasks == NULL) {
                         new_task = 1;
                         break;
                 }

@@ -4573,10 +4180,12 @@
         itask->itask_proxy_msg_id = 0;
         mutex_enter(&ilu->ilu_task_lock);
         itask->itask_lu_free_next = ilu->ilu_free_tasks;
         ilu->ilu_free_tasks = itask;
         ilu->ilu_ntasks_free++;
+        if (ilu->ilu_ntasks == ilu->ilu_ntasks_free)
+                cv_signal(&ilu->ilu_offline_pending_cv);
         mutex_exit(&ilu->ilu_task_lock);
         atomic_add_32(itask->itask_ilu_task_cntr, -1);
 }
 
 void

@@ -6089,20 +5698,21 @@
         struct timeval32 timestamp32;
         uint32_t *t = (uint32_t *)&timestamp32;
         struct ether_addr mac;
         uint8_t *e = (uint8_t *)&mac;
         int hid = (int)host_id;
+        uint16_t gen_number;
 
         if (company_id == COMPANY_ID_NONE)
                 company_id = COMPANY_ID_SUN;
 
         if (lu_id->ident_length != 0x10)
                 return (STMF_INVALID_ARG);
 
         p = (uint8_t *)lu_id;
 
-        atomic_add_16(&stmf_lu_id_gen_number, 1);
+        gen_number = atomic_add_16_nv(&stmf_lu_id_gen_number, 1);
 
         p[0] = 0xf1; p[1] = 3; p[2] = 0; p[3] = 0x10;
         p[4] = ((company_id >> 20) & 0xf) | 0x60;
         p[5] = (company_id >> 12) & 0xff;
         p[6] = (company_id >> 4) & 0xff;

@@ -6119,12 +5729,12 @@
         }
         bcopy(e, p+8, 6);
         uniqtime32(&timestamp32);
         *t = BE_32(*t);
         bcopy(t, p+14, 4);
-        p[18] = (stmf_lu_id_gen_number >> 8) & 0xff;
-        p[19] = stmf_lu_id_gen_number & 0xff;
+        p[18] = (gen_number >> 8) & 0xff;
+        p[19] = gen_number & 0xff;
 
         return (STMF_SUCCESS);
 }
 
 /*

@@ -7542,15 +7152,16 @@
         stmf_i_lu_t     *ilu;
 
         if (itl == NULL || task->task_lu == dlun0)
                 return;
         ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-        mutex_enter(ilu->ilu_kstat_io->ks_lock);
         itask->itask_start_timestamp = gethrtime();
-        kstat_waitq_enter(KSTAT_IO_PTR(itl->itl_kstat_taskq));
+        if (ilu->ilu_kstat_io != NULL) {
+                mutex_enter(ilu->ilu_kstat_io->ks_lock);
         stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_enter);
         mutex_exit(ilu->ilu_kstat_io->ks_lock);
+        }
 
         stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_enter);
 }
 
 void

@@ -7561,125 +7172,48 @@
         stmf_i_lu_t     *ilu;
 
         if (itl == NULL || task->task_lu == dlun0)
                 return;
         ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
+        if (ilu->ilu_kstat_io != NULL) {
         mutex_enter(ilu->ilu_kstat_io->ks_lock);
-        kstat_waitq_to_runq(KSTAT_IO_PTR(itl->itl_kstat_taskq));
         stmf_update_kstat_lu_q(itask->itask_task, kstat_waitq_to_runq);
         mutex_exit(ilu->ilu_kstat_io->ks_lock);
+        }
 
         stmf_update_kstat_lport_q(itask->itask_task, kstat_waitq_to_runq);
 }
 
 void
 stmf_itl_task_done(stmf_i_scsi_task_t *itask)
 {
         stmf_itl_data_t         *itl = itask->itask_itl_datap;
         scsi_task_t             *task = itask->itask_task;
-        kstat_io_t              *kip;
-        hrtime_t                elapsed_time;
-        stmf_kstat_itl_info_t   *itli;
         stmf_i_lu_t     *ilu;
 
+        itask->itask_done_timestamp = gethrtime();
+
         if (itl == NULL || task->task_lu == dlun0)
                 return;
         ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
 
+        if (ilu->ilu_kstat_io == NULL)
+                return;
+
         mutex_enter(ilu->ilu_kstat_io->ks_lock);
-        itli = (stmf_kstat_itl_info_t *)KSTAT_NAMED_PTR(itl->itl_kstat_info);
-        kip = KSTAT_IO_PTR(itl->itl_kstat_taskq);
 
-        itli->i_task_waitq_elapsed.value.ui64 += itask->itask_waitq_time;
-
-        itask->itask_done_timestamp = gethrtime();
-        elapsed_time =
-            itask->itask_done_timestamp - itask->itask_start_timestamp;
-
-        if (task->task_flags & TF_READ_DATA) {
-                kip->reads++;
-                kip->nread += itask->itask_read_xfer;
-                itli->i_task_read_elapsed.value.ui64 += elapsed_time;
-                itli->i_lu_read_elapsed.value.ui64 +=
-                    itask->itask_lu_read_time;
-                itli->i_lport_read_elapsed.value.ui64 +=
-                    itask->itask_lport_read_time;
-        }
-
-        if (task->task_flags & TF_WRITE_DATA) {
-                kip->writes++;
-                kip->nwritten += itask->itask_write_xfer;
-                itli->i_task_write_elapsed.value.ui64 += elapsed_time;
-                itli->i_lu_write_elapsed.value.ui64 +=
-                    itask->itask_lu_write_time;
-                itli->i_lport_write_elapsed.value.ui64 +=
-                    itask->itask_lport_write_time;
-        }
-
         if (itask->itask_flags & ITASK_KSTAT_IN_RUNQ) {
-                kstat_runq_exit(kip);
                 stmf_update_kstat_lu_q(task, kstat_runq_exit);
                 mutex_exit(ilu->ilu_kstat_io->ks_lock);
                 stmf_update_kstat_lport_q(task, kstat_runq_exit);
         } else {
-                kstat_waitq_exit(kip);
                 stmf_update_kstat_lu_q(task, kstat_waitq_exit);
                 mutex_exit(ilu->ilu_kstat_io->ks_lock);
                 stmf_update_kstat_lport_q(task, kstat_waitq_exit);
         }
 }
 
-void
-stmf_lu_xfer_start(scsi_task_t *task)
-{
-        stmf_i_scsi_task_t *itask = task->task_stmf_private;
-        stmf_itl_data_t *itl = itask->itask_itl_datap;
-        stmf_i_lu_t     *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-        kstat_io_t              *kip;
-
-        if (itl == NULL || task->task_lu == dlun0)
-                return;
-
-        kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
-        mutex_enter(ilu->ilu_kstat_io->ks_lock);
-        kstat_runq_enter(kip);
-        mutex_exit(ilu->ilu_kstat_io->ks_lock);
-}
-
-void
-stmf_lu_xfer_done(scsi_task_t *task, boolean_t read, uint64_t xfer_bytes,
-    hrtime_t elapsed_time)
-{
-        stmf_i_scsi_task_t      *itask = task->task_stmf_private;
-        stmf_itl_data_t         *itl = itask->itask_itl_datap;
-        stmf_i_lu_t     *ilu = (stmf_i_lu_t *)task->task_lu->lu_stmf_private;
-        kstat_io_t              *kip;
-
-        if (itl == NULL || task->task_lu == dlun0)
-                return;
-
-        if (read) {
-                atomic_add_64((uint64_t *)&itask->itask_lu_read_time,
-                    elapsed_time);
-        } else {
-                atomic_add_64((uint64_t *)&itask->itask_lu_write_time,
-                    elapsed_time);
-        }
-
-        kip = KSTAT_IO_PTR(itl->itl_kstat_lu_xfer);
-        mutex_enter(ilu->ilu_kstat_io->ks_lock);
-        kstat_runq_exit(kip);
-        if (read) {
-                kip->reads++;
-                kip->nread += xfer_bytes;
-        } else {
-                kip->writes++;
-                kip->nwritten += xfer_bytes;
-        }
-        mutex_exit(ilu->ilu_kstat_io->ks_lock);
-}
-
 static void
 stmf_lport_xfer_start(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
 {
         stmf_itl_data_t         *itl = itask->itask_itl_datap;
 

@@ -7694,21 +7228,16 @@
 
 static void
 stmf_lport_xfer_done(stmf_i_scsi_task_t *itask, stmf_data_buf_t *dbuf)
 {
         stmf_itl_data_t         *itl = itask->itask_itl_datap;
-        scsi_task_t             *task;
-        stmf_i_local_port_t     *ilp;
-        kstat_io_t              *kip;
         hrtime_t                elapsed_time;
         uint64_t                xfer_size;
 
         if (itl == NULL)
                 return;
 
-        task = (scsi_task_t *)itask->itask_task;
-        ilp = (stmf_i_local_port_t *)task->task_lport->lport_stmf_private;
         xfer_size = (dbuf->db_xfer_status == STMF_SUCCESS) ?
             dbuf->db_data_size : 0;
 
         elapsed_time = gethrtime() - dbuf->db_xfer_start_timestamp;
         if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {

@@ -7724,21 +7253,10 @@
         }
 
         DTRACE_PROBE3(scsi__xfer__end, scsi_task_t *, itask->itask_task,
             stmf_data_buf_t *, dbuf, hrtime_t, elapsed_time);
 
-        kip = KSTAT_IO_PTR(itl->itl_kstat_lport_xfer);
-        mutex_enter(ilp->ilport_kstat_io->ks_lock);
-        if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
-                kip->reads++;
-                kip->nread += xfer_size;
-        } else {
-                kip->writes++;
-                kip->nwritten += xfer_size;
-        }
-        mutex_exit(ilp->ilport_kstat_io->ks_lock);
-
         dbuf->db_xfer_start_timestamp = 0;
 }
 
 void
 stmf_svc_init()

@@ -7836,19 +7354,19 @@
                         mutex_exit(&stmf_state.stmf_lock);
                         stmf_task_lu_killall((stmf_lu_t *)req->svc_obj, NULL,
                             STMF_ABORTED);
                         lu = (stmf_lu_t *)req->svc_obj;
                         ilu = (stmf_i_lu_t *)lu->lu_stmf_private;
-                        if (ilu->ilu_ntasks != ilu->ilu_ntasks_free)
-                                break;
+                        stmf_wait_ilu_tasks_finish(ilu);
                         lu->lu_ctl(lu, req->svc_cmd, &req->svc_info);
                         break;
                 default:
                         cmn_err(CE_PANIC, "stmf_svc: unknown cmd %d",
                             req->svc_cmd);
                 }
 
+                kmem_free(req, req->svc_req_alloc_size);
                 mutex_enter(&stmf_state.stmf_lock);
         }
 
         stmf_state.stmf_svc_flags &= ~(STMF_SVC_STARTED | STMF_SVC_ACTIVE);
         mutex_exit(&stmf_state.stmf_lock);

@@ -7989,10 +7507,44 @@
         (void) cv_reltimedwait(&stmf_state.stmf_cv,
             &stmf_state.stmf_lock, td, TR_CLOCK_TICK);
         stmf_state.stmf_svc_flags |= STMF_SVC_ACTIVE;
 }
 
+/*
+ * Waits for ongoing I/O tasks to finish on an LU in preparation for
+ * the LU's offlining. The LU should already be in an Offlining state
+ * (otherwise I/O to the LU might never end). There is an additional
+ * enforcement of this via a deadman timer check.
+ */
+static void
+stmf_wait_ilu_tasks_finish(stmf_i_lu_t *ilu)
+{
+        clock_t start, now, deadline;
+
+        start = now = ddi_get_lbolt();
+        deadline = start + drv_usectohz(stmf_io_deadman * 1000000llu);
+        mutex_enter(&ilu->ilu_task_lock);
+        while (ilu->ilu_ntasks != ilu->ilu_ntasks_free) {
+                (void) cv_timedwait(&ilu->ilu_offline_pending_cv,
+                    &ilu->ilu_task_lock, deadline);
+                now = ddi_get_lbolt();
+                if (now > deadline) {
+                        if (stmf_io_deadman_enabled) {
+                                cmn_err(CE_PANIC, "stmf_svc: I/O deadman hit "
+                                    "on STMF_CMD_LU_OFFLINE after %d seconds",
+                                    stmf_io_deadman);
+                        } else {
+                                /* keep on spinning */
+                                deadline = now + drv_usectohz(stmf_io_deadman *
+                                    1000000llu);
+                        }
+                }
+        }
+        mutex_exit(&ilu->ilu_task_lock);
+        DTRACE_PROBE1(deadman__timeout__wait, clock_t, now - start);
+}
+
 void
 stmf_svc_queue(int cmd, void *obj, stmf_state_change_info_t *info)
 {
         stmf_svc_req_t *req;
         int s;