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