145039663SJohn Forte /* 245039663SJohn Forte * CDDL HEADER START 345039663SJohn Forte * 445039663SJohn Forte * The contents of this file are subject to the terms of the 545039663SJohn Forte * Common Development and Distribution License (the "License"). 645039663SJohn Forte * You may not use this file except in compliance with the License. 745039663SJohn Forte * 845039663SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 945039663SJohn Forte * or http://www.opensolaris.org/os/licensing. 1045039663SJohn Forte * See the License for the specific language governing permissions 1145039663SJohn Forte * and limitations under the License. 1245039663SJohn Forte * 1345039663SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 1445039663SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1545039663SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 1645039663SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 1745039663SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 1845039663SJohn Forte * 1945039663SJohn Forte * CDDL HEADER END 2045039663SJohn Forte */ 2145039663SJohn Forte /* 2291159e90SJohn Forte * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23*ef3b9e2fSDan McDonald * Copyright 2013, Nexenta Systems, Inc. All rights reserved. 2445039663SJohn Forte */ 2545039663SJohn Forte 2645039663SJohn Forte #include <sys/cpuvar.h> 2745039663SJohn Forte #include <sys/types.h> 2845039663SJohn Forte #include <sys/conf.h> 2945039663SJohn Forte #include <sys/file.h> 3045039663SJohn Forte #include <sys/ddi.h> 3145039663SJohn Forte #include <sys/sunddi.h> 3245039663SJohn Forte #include <sys/modctl.h> 3345039663SJohn Forte #include <sys/sysmacros.h> 3445039663SJohn Forte 3545039663SJohn Forte #include <sys/socket.h> 3645039663SJohn Forte #include <sys/strsubr.h> 3745039663SJohn Forte #include <sys/door.h> 3845039663SJohn Forte 3945039663SJohn Forte #include <sys/stmf.h> 4045039663SJohn Forte #include <sys/stmf_ioctl.h> 4145039663SJohn Forte #include <sys/portif.h> 424558d122SViswanathan Kannappan 434558d122SViswanathan Kannappan #include "pppt.h" 4445039663SJohn Forte 4545039663SJohn Forte static void pppt_msg_tgt_register(stmf_ic_msg_t *reg_port); 4645039663SJohn Forte 4745039663SJohn Forte static void pppt_msg_tgt_deregister(stmf_ic_msg_t *msg); 4845039663SJohn Forte 4945039663SJohn Forte static void pppt_msg_session_destroy(stmf_ic_msg_t *msg); 5045039663SJohn Forte 5145039663SJohn Forte static void pppt_msg_scsi_cmd(stmf_ic_msg_t *msg); 5245039663SJohn Forte 5345039663SJohn Forte static void pppt_msg_data_xfer_done(stmf_ic_msg_t *msg); 5445039663SJohn Forte 5545039663SJohn Forte static void pppt_msg_handle_status(stmf_ic_msg_t *msg); 5645039663SJohn Forte 5745039663SJohn Forte void 5845039663SJohn Forte pppt_msg_rx(stmf_ic_msg_t *msg) 5945039663SJohn Forte { 6045039663SJohn Forte switch (msg->icm_msg_type) { 6145039663SJohn Forte case STMF_ICM_REGISTER_PROXY_PORT: 6245039663SJohn Forte pppt_msg_tgt_register(msg); 6345039663SJohn Forte break; 6445039663SJohn Forte case STMF_ICM_DEREGISTER_PROXY_PORT: 6545039663SJohn Forte pppt_msg_tgt_deregister(msg); 6645039663SJohn Forte break; 6745039663SJohn Forte case STMF_ICM_SESSION_CREATE: 6845039663SJohn Forte pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED); 6945039663SJohn Forte stmf_ic_msg_free(msg); 7045039663SJohn Forte break; 7145039663SJohn Forte case STMF_ICM_SESSION_DESTROY: 7245039663SJohn Forte pppt_msg_session_destroy(msg); 7345039663SJohn Forte break; 7445039663SJohn Forte case STMF_ICM_SCSI_CMD: 7545039663SJohn Forte pppt_msg_scsi_cmd(msg); 7645039663SJohn Forte break; 7745039663SJohn Forte case STMF_ICM_SCSI_DATA_XFER_DONE: 7845039663SJohn Forte pppt_msg_data_xfer_done(msg); 7945039663SJohn Forte break; 8045039663SJohn Forte case STMF_ICM_SCSI_DATA: 8145039663SJohn Forte /* Ignore, all proxy data will be immediate for now */ 8245039663SJohn Forte pppt_msg_tx_status(msg, STMF_NOT_SUPPORTED); 8345039663SJohn Forte stmf_ic_msg_free(msg); 8445039663SJohn Forte break; 8545039663SJohn Forte case STMF_ICM_STATUS: 8645039663SJohn Forte pppt_msg_handle_status(msg); 8745039663SJohn Forte break; 8845039663SJohn Forte default: 8945039663SJohn Forte /* Other message types are not allowed */ 9045039663SJohn Forte ASSERT(0); 9145039663SJohn Forte break; 9245039663SJohn Forte } 9345039663SJohn Forte } 9445039663SJohn Forte 9545039663SJohn Forte void 9645039663SJohn Forte pppt_msg_tx_status(stmf_ic_msg_t *orig_msg, stmf_status_t status) 9745039663SJohn Forte { 9845039663SJohn Forte stmf_ic_msg_t *msg; 9945039663SJohn Forte 10045039663SJohn Forte /* 10145039663SJohn Forte * If TX of status fails it should be treated the same as a loss of 10245039663SJohn Forte * connection. We expect the remote node to handle it. 10345039663SJohn Forte */ 10445039663SJohn Forte msg = stmf_ic_status_msg_alloc(status, orig_msg->icm_msg_type, 10545039663SJohn Forte orig_msg->icm_msgid); 10645039663SJohn Forte 10745039663SJohn Forte if (msg != NULL) { 10845039663SJohn Forte (void) stmf_ic_tx_msg(msg); 10945039663SJohn Forte } 11045039663SJohn Forte } 11145039663SJohn Forte 11245039663SJohn Forte static void 11345039663SJohn Forte pppt_msg_tgt_register(stmf_ic_msg_t *msg) 11445039663SJohn Forte { 11545039663SJohn Forte stmf_ic_reg_port_msg_t *reg_port; 11645039663SJohn Forte pppt_tgt_t *result; 11745039663SJohn Forte stmf_status_t stmf_status; 11845039663SJohn Forte 11945039663SJohn Forte reg_port = msg->icm_msg; 12045039663SJohn Forte 12145039663SJohn Forte PPPT_GLOBAL_LOCK(); 12245039663SJohn Forte if (pppt_global.global_svc_state != PSS_ENABLED) { 12345039663SJohn Forte stmf_status = STMF_FAILURE; 12445039663SJohn Forte PPPT_INC_STAT(es_tgt_reg_svc_disabled); 12545039663SJohn Forte goto pppt_register_tgt_done; 12645039663SJohn Forte } 12745039663SJohn Forte 12845039663SJohn Forte /* 12945039663SJohn Forte * For now we assume that the marshall/unmarshall code is responsible 13045039663SJohn Forte * for validating the message length and ensuring the resulting 13145039663SJohn Forte * request structure is self consistent. Make sure this 13245039663SJohn Forte * target doesn't already exist. 13345039663SJohn Forte */ 13445039663SJohn Forte if ((result = pppt_tgt_lookup_locked(reg_port->icrp_port_id)) != NULL) { 13545039663SJohn Forte stmf_status = STMF_ALREADY; 13645039663SJohn Forte PPPT_INC_STAT(es_tgt_reg_duplicate); 13745039663SJohn Forte goto pppt_register_tgt_done; 13845039663SJohn Forte } 13945039663SJohn Forte 14045039663SJohn Forte result = pppt_tgt_create(reg_port, &stmf_status); 14145039663SJohn Forte 14245039663SJohn Forte if (result == NULL) { 14345039663SJohn Forte stmf_status = STMF_TARGET_FAILURE; 14445039663SJohn Forte PPPT_INC_STAT(es_tgt_reg_create_fail); 14545039663SJohn Forte goto pppt_register_tgt_done; 14645039663SJohn Forte } 14745039663SJohn Forte 14845039663SJohn Forte avl_add(&pppt_global.global_target_list, result); 14945039663SJohn Forte 15045039663SJohn Forte stmf_status = STMF_SUCCESS; 15145039663SJohn Forte 15245039663SJohn Forte pppt_register_tgt_done: 15345039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 15445039663SJohn Forte pppt_msg_tx_status(msg, stmf_status); 15545039663SJohn Forte stmf_ic_msg_free(msg); 15645039663SJohn Forte } 15745039663SJohn Forte 15845039663SJohn Forte static void 15945039663SJohn Forte pppt_msg_tgt_deregister(stmf_ic_msg_t *msg) 16045039663SJohn Forte { 16145039663SJohn Forte stmf_ic_dereg_port_msg_t *dereg_port; 16245039663SJohn Forte stmf_status_t stmf_status; 16345039663SJohn Forte pppt_tgt_t *tgt; 16445039663SJohn Forte 16545039663SJohn Forte PPPT_GLOBAL_LOCK(); 16645039663SJohn Forte if (pppt_global.global_svc_state != PSS_ENABLED) { 16745039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 16845039663SJohn Forte stmf_status = STMF_FAILURE; 16945039663SJohn Forte PPPT_INC_STAT(es_tgt_dereg_svc_disabled); 17045039663SJohn Forte goto pppt_deregister_tgt_done; 17145039663SJohn Forte } 17245039663SJohn Forte 17345039663SJohn Forte dereg_port = msg->icm_msg; 17445039663SJohn Forte 17545039663SJohn Forte /* Lookup target */ 17645039663SJohn Forte if ((tgt = pppt_tgt_lookup_locked(dereg_port->icdp_port_id)) == NULL) { 17745039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 17845039663SJohn Forte stmf_status = STMF_NOT_FOUND; 17945039663SJohn Forte PPPT_INC_STAT(es_tgt_dereg_not_found); 18045039663SJohn Forte goto pppt_deregister_tgt_done; 18145039663SJohn Forte } 18245039663SJohn Forte avl_remove(&pppt_global.global_target_list, tgt); 18345039663SJohn Forte pppt_tgt_async_delete(tgt); 18445039663SJohn Forte 18545039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 18645039663SJohn Forte 18745039663SJohn Forte /* Wait for delete to complete */ 18845039663SJohn Forte mutex_enter(&tgt->target_mutex); 18945039663SJohn Forte while ((tgt->target_refcount > 0) || 19045039663SJohn Forte (tgt->target_state != TS_DELETING)) { 19145039663SJohn Forte cv_wait(&tgt->target_cv, &tgt->target_mutex); 19245039663SJohn Forte } 19345039663SJohn Forte mutex_exit(&tgt->target_mutex); 19445039663SJohn Forte 19545039663SJohn Forte pppt_tgt_destroy(tgt); 19645039663SJohn Forte stmf_status = STMF_SUCCESS; 19745039663SJohn Forte 19845039663SJohn Forte pppt_deregister_tgt_done: 19945039663SJohn Forte pppt_msg_tx_status(msg, stmf_status); 20045039663SJohn Forte stmf_ic_msg_free(msg); 20145039663SJohn Forte } 20245039663SJohn Forte 20345039663SJohn Forte static void 20445039663SJohn Forte pppt_msg_session_destroy(stmf_ic_msg_t *msg) 20545039663SJohn Forte { 20645039663SJohn Forte stmf_ic_session_create_destroy_msg_t *sess_destroy; 20745039663SJohn Forte pppt_tgt_t *tgt; 20845039663SJohn Forte pppt_sess_t *ps; 20945039663SJohn Forte 21045039663SJohn Forte sess_destroy = msg->icm_msg; 21145039663SJohn Forte 21245039663SJohn Forte PPPT_GLOBAL_LOCK(); 21345039663SJohn Forte 21445039663SJohn Forte /* 21545039663SJohn Forte * Look for existing session for this ID 21645039663SJohn Forte */ 21745039663SJohn Forte ps = pppt_sess_lookup_locked(sess_destroy->icscd_session_id, 218716c1805SNattuvetty Bhavyan sess_destroy->icscd_tgt_devid, sess_destroy->icscd_rport); 21945039663SJohn Forte 22045039663SJohn Forte if (ps == NULL) { 22145039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 22245039663SJohn Forte stmf_ic_msg_free(msg); 22345039663SJohn Forte PPPT_INC_STAT(es_sess_destroy_no_session); 22445039663SJohn Forte return; 22545039663SJohn Forte } 22645039663SJohn Forte 22745039663SJohn Forte tgt = ps->ps_target; 22845039663SJohn Forte 22945039663SJohn Forte mutex_enter(&tgt->target_mutex); 23045039663SJohn Forte mutex_enter(&ps->ps_mutex); 23145039663SJohn Forte 23245039663SJohn Forte /* Release the reference from the lookup */ 23345039663SJohn Forte pppt_sess_rele_locked(ps); 23445039663SJohn Forte 23545039663SJohn Forte /* Make sure another thread is not already closing the session */ 23645039663SJohn Forte if (!ps->ps_closed) { 23745039663SJohn Forte /* Found matching open session, quiesce... */ 23845039663SJohn Forte pppt_sess_close_locked(ps); 23945039663SJohn Forte } 24045039663SJohn Forte mutex_exit(&ps->ps_mutex); 24145039663SJohn Forte mutex_exit(&tgt->target_mutex); 24245039663SJohn Forte PPPT_GLOBAL_UNLOCK(); 24345039663SJohn Forte 24445039663SJohn Forte stmf_ic_msg_free(msg); 24545039663SJohn Forte } 24645039663SJohn Forte 24745039663SJohn Forte static void 24845039663SJohn Forte pppt_msg_scsi_cmd(stmf_ic_msg_t *msg) 24945039663SJohn Forte { 25045039663SJohn Forte pppt_sess_t *pppt_sess; 25145039663SJohn Forte pppt_buf_t *pbuf; 25245039663SJohn Forte stmf_ic_scsi_cmd_msg_t *scmd; 25345039663SJohn Forte pppt_task_t *ptask; 25445039663SJohn Forte scsi_task_t *task; 25545039663SJohn Forte pppt_status_t pppt_status; 25645039663SJohn Forte stmf_local_port_t *lport; 25745039663SJohn Forte stmf_scsi_session_t *stmf_sess; 25845039663SJohn Forte stmf_status_t stmf_status; 25945039663SJohn Forte 26045039663SJohn Forte /* 26145039663SJohn Forte * Get a task context 26245039663SJohn Forte */ 26345039663SJohn Forte ptask = pppt_task_alloc(); 26445039663SJohn Forte if (ptask == NULL) { 26545039663SJohn Forte /* 26645039663SJohn Forte * We must be very low on memory. Just free the message 26745039663SJohn Forte * and let the command timeout. 26845039663SJohn Forte */ 26945039663SJohn Forte stmf_ic_msg_free(msg); 27045039663SJohn Forte PPPT_INC_STAT(es_scmd_ptask_alloc_fail); 27145039663SJohn Forte return; 27245039663SJohn Forte } 27345039663SJohn Forte 27445039663SJohn Forte scmd = msg->icm_msg; 27545039663SJohn Forte 27645039663SJohn Forte /* 27745039663SJohn Forte * Session are created implicitly on the first use of an 27845039663SJohn Forte * IT nexus 27945039663SJohn Forte */ 28045039663SJohn Forte pppt_sess = pppt_sess_lookup_create(scmd->icsc_tgt_devid, 281716c1805SNattuvetty Bhavyan scmd->icsc_ini_devid, scmd->icsc_rport, 282716c1805SNattuvetty Bhavyan scmd->icsc_session_id, &stmf_status); 28345039663SJohn Forte if (pppt_sess == NULL) { 28445039663SJohn Forte pppt_task_free(ptask); 28545039663SJohn Forte pppt_msg_tx_status(msg, stmf_status); 28645039663SJohn Forte stmf_ic_msg_free(msg); 28745039663SJohn Forte PPPT_INC_STAT(es_scmd_sess_create_fail); 28845039663SJohn Forte return; 28945039663SJohn Forte } 29045039663SJohn Forte 29145039663SJohn Forte ptask->pt_sess = pppt_sess; 29245039663SJohn Forte ptask->pt_task_id = scmd->icsc_task_msgid; 29345039663SJohn Forte stmf_sess = pppt_sess->ps_stmf_sess; 29445039663SJohn Forte lport = stmf_sess->ss_lport; 29545039663SJohn Forte 29645039663SJohn Forte /* 29745039663SJohn Forte * Add task to our internal task set. 29845039663SJohn Forte */ 29945039663SJohn Forte pppt_status = pppt_task_start(ptask); 30045039663SJohn Forte 30145039663SJohn Forte if (pppt_status != 0) { 30245039663SJohn Forte /* Release hold from pppt_sess_lookup_create() */ 30345039663SJohn Forte PPPT_LOG(CE_WARN, "Duplicate taskid from remote node 0x%llx", 30445039663SJohn Forte (longlong_t)scmd->icsc_task_msgid); 30545039663SJohn Forte pppt_task_free(ptask); 30645039663SJohn Forte pppt_sess_rele(pppt_sess); 30745039663SJohn Forte pppt_msg_tx_status(msg, STMF_ALREADY); 30845039663SJohn Forte stmf_ic_msg_free(msg); 30945039663SJohn Forte PPPT_INC_STAT(es_scmd_dup_task_count); 31045039663SJohn Forte return; 31145039663SJohn Forte } 31245039663SJohn Forte 31345039663SJohn Forte /* 31445039663SJohn Forte * Allocate STMF task context 31545039663SJohn Forte */ 31645039663SJohn Forte ptask->pt_stmf_task = stmf_task_alloc(lport, stmf_sess, 31745039663SJohn Forte scmd->icsc_task_lun_no, 31845039663SJohn Forte scmd->icsc_task_cdb_length, 0); 31945039663SJohn Forte if (ptask->pt_stmf_task == NULL) { 320*ef3b9e2fSDan McDonald /* NOTE: pppt_task_done() will free ptask. */ 32145039663SJohn Forte (void) pppt_task_done(ptask); 32245039663SJohn Forte pppt_sess_rele(pppt_sess); 32345039663SJohn Forte pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE); 32445039663SJohn Forte stmf_ic_msg_free(msg); 32545039663SJohn Forte PPPT_INC_STAT(es_scmd_stask_alloc_fail); 32645039663SJohn Forte return; 32745039663SJohn Forte } 32845039663SJohn Forte 32945039663SJohn Forte task = ptask->pt_stmf_task; 330*ef3b9e2fSDan McDonald /* task_port_private reference is a real reference. */ 331*ef3b9e2fSDan McDonald (void) pppt_task_hold(ptask); 33245039663SJohn Forte task->task_port_private = ptask; 33345039663SJohn Forte task->task_flags = scmd->icsc_task_flags; 33445039663SJohn Forte task->task_additional_flags = 0; 33545039663SJohn Forte task->task_priority = 0; 33645039663SJohn Forte 33745039663SJohn Forte /* 33845039663SJohn Forte * Set task->task_mgmt_function to TM_NONE for a normal SCSI task 33945039663SJohn Forte * or one of these values for a task management command: 34045039663SJohn Forte * 34145039663SJohn Forte * TM_ABORT_TASK *** 34245039663SJohn Forte * TM_ABORT_TASK_SET 34345039663SJohn Forte * TM_CLEAR_ACA 34445039663SJohn Forte * TM_CLEAR_TASK_SET 34545039663SJohn Forte * TM_LUN_RESET 34645039663SJohn Forte * TM_TARGET_WARM_RESET 34745039663SJohn Forte * TM_TARGET_COLD_RESET 34845039663SJohn Forte * 34945039663SJohn Forte * *** Note that STMF does not currently support TM_ABORT_TASK so 35045039663SJohn Forte * port providers must implement this command on their own 35145039663SJohn Forte * (e.g. lookup the desired task and call stmf_abort). 35245039663SJohn Forte */ 35345039663SJohn Forte task->task_mgmt_function = scmd->icsc_task_mgmt_function; 35445039663SJohn Forte 35591159e90SJohn Forte task->task_max_nbufs = 1; /* Don't allow parallel xfers */ 35645039663SJohn Forte task->task_cmd_seq_no = msg->icm_msgid; 35745039663SJohn Forte task->task_expected_xfer_length = 35845039663SJohn Forte scmd->icsc_task_expected_xfer_length; 35945039663SJohn Forte 3608f641fa7SSue Gleeson if (scmd->icsc_task_cdb_length) { 3618f641fa7SSue Gleeson bcopy(scmd->icsc_task_cdb, task->task_cdb, 3628f641fa7SSue Gleeson scmd->icsc_task_cdb_length); 3638f641fa7SSue Gleeson } 36445039663SJohn Forte bcopy(scmd->icsc_lun_id, ptask->pt_lun_id, 16); 36545039663SJohn Forte 36645039663SJohn Forte if (scmd->icsc_immed_data_len) { 36745039663SJohn Forte pbuf = ptask->pt_immed_data; 36845039663SJohn Forte pbuf->pbuf_immed_msg = msg; 36945039663SJohn Forte pbuf->pbuf_stmf_buf->db_data_size = scmd->icsc_immed_data_len; 37045039663SJohn Forte pbuf->pbuf_stmf_buf->db_buf_size = scmd->icsc_immed_data_len; 37145039663SJohn Forte pbuf->pbuf_stmf_buf->db_relative_offset = 0; 37245039663SJohn Forte pbuf->pbuf_stmf_buf->db_sglist[0].seg_length = 37345039663SJohn Forte scmd->icsc_immed_data_len; 37445039663SJohn Forte pbuf->pbuf_stmf_buf->db_sglist[0].seg_addr = 37545039663SJohn Forte scmd->icsc_immed_data; 37645039663SJohn Forte 37745039663SJohn Forte stmf_post_task(task, pbuf->pbuf_stmf_buf); 37845039663SJohn Forte } else { 37945039663SJohn Forte stmf_post_task(task, NULL); 38045039663SJohn Forte stmf_ic_msg_free(msg); 38145039663SJohn Forte } 38245039663SJohn Forte } 38345039663SJohn Forte 38445039663SJohn Forte static void 38545039663SJohn Forte pppt_msg_data_xfer_done(stmf_ic_msg_t *msg) 38645039663SJohn Forte { 38745039663SJohn Forte pppt_task_t *pppt_task; 38845039663SJohn Forte stmf_ic_scsi_data_xfer_done_msg_t *data_xfer_done; 38945039663SJohn Forte 39045039663SJohn Forte data_xfer_done = msg->icm_msg; 39145039663SJohn Forte 39245039663SJohn Forte /* 39345039663SJohn Forte * Find task 39445039663SJohn Forte */ 39545039663SJohn Forte pppt_task = pppt_task_lookup(data_xfer_done->icsx_task_msgid); 39645039663SJohn Forte 39745039663SJohn Forte /* If we found one, complete the transfer */ 39845039663SJohn Forte if (pppt_task != NULL) { 39945039663SJohn Forte pppt_xfer_read_complete(pppt_task, data_xfer_done->icsx_status); 40045039663SJohn Forte } 40145039663SJohn Forte 40245039663SJohn Forte stmf_ic_msg_free(msg); 40345039663SJohn Forte } 40445039663SJohn Forte 40545039663SJohn Forte static void 40645039663SJohn Forte pppt_msg_handle_status(stmf_ic_msg_t *msg) 40745039663SJohn Forte { 40845039663SJohn Forte /* Don't care for now */ 40945039663SJohn Forte stmf_ic_msg_free(msg); 41045039663SJohn Forte } 411