17996a778SMike Christie /* 27996a778SMike Christie * iSCSI lib functions 37996a778SMike Christie * 47996a778SMike Christie * Copyright (C) 2006 Red Hat, Inc. All rights reserved. 57996a778SMike Christie * Copyright (C) 2004 - 2006 Mike Christie 67996a778SMike Christie * Copyright (C) 2004 - 2005 Dmitry Yusupov 77996a778SMike Christie * Copyright (C) 2004 - 2005 Alex Aizman 87996a778SMike Christie * maintained by open-iscsi@googlegroups.com 97996a778SMike Christie * 107996a778SMike Christie * This program is free software; you can redistribute it and/or modify 117996a778SMike Christie * it under the terms of the GNU General Public License as published by 127996a778SMike Christie * the Free Software Foundation; either version 2 of the License, or 137996a778SMike Christie * (at your option) any later version. 147996a778SMike Christie * 157996a778SMike Christie * This program is distributed in the hope that it will be useful, 167996a778SMike Christie * but WITHOUT ANY WARRANTY; without even the implied warranty of 177996a778SMike Christie * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 187996a778SMike Christie * GNU General Public License for more details. 197996a778SMike Christie * 207996a778SMike Christie * You should have received a copy of the GNU General Public License 217996a778SMike Christie * along with this program; if not, write to the Free Software 227996a778SMike Christie * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 237996a778SMike Christie */ 247996a778SMike Christie #include <linux/types.h> 257996a778SMike Christie #include <linux/kfifo.h> 267996a778SMike Christie #include <linux/delay.h> 2711836572Svignesh babu #include <linux/log2.h> 288eb00539SMike Christie #include <asm/unaligned.h> 297996a778SMike Christie #include <net/tcp.h> 307996a778SMike Christie #include <scsi/scsi_cmnd.h> 317996a778SMike Christie #include <scsi/scsi_device.h> 327996a778SMike Christie #include <scsi/scsi_eh.h> 337996a778SMike Christie #include <scsi/scsi_tcq.h> 347996a778SMike Christie #include <scsi/scsi_host.h> 357996a778SMike Christie #include <scsi/scsi.h> 367996a778SMike Christie #include <scsi/iscsi_proto.h> 377996a778SMike Christie #include <scsi/scsi_transport.h> 387996a778SMike Christie #include <scsi/scsi_transport_iscsi.h> 397996a778SMike Christie #include <scsi/libiscsi.h> 407996a778SMike Christie 4177a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ 4277a23c21SMike Christie #define SNA32_CHECK 2147483648UL 437996a778SMike Christie 4477a23c21SMike Christie static int iscsi_sna_lt(u32 n1, u32 n2) 4577a23c21SMike Christie { 4677a23c21SMike Christie return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || 4777a23c21SMike Christie (n1 > n2 && (n2 - n1 < SNA32_CHECK))); 4877a23c21SMike Christie } 4977a23c21SMike Christie 5077a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ 5177a23c21SMike Christie static int iscsi_sna_lte(u32 n1, u32 n2) 5277a23c21SMike Christie { 5377a23c21SMike Christie return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || 5477a23c21SMike Christie (n1 > n2 && (n2 - n1 < SNA32_CHECK))); 5577a23c21SMike Christie } 5677a23c21SMike Christie 5777a23c21SMike Christie void 5877a23c21SMike Christie iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) 597996a778SMike Christie { 607996a778SMike Christie uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); 617996a778SMike Christie uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); 627996a778SMike Christie 6377a23c21SMike Christie /* 6477a23c21SMike Christie * standard specifies this check for when to update expected and 6577a23c21SMike Christie * max sequence numbers 6677a23c21SMike Christie */ 6777a23c21SMike Christie if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1)) 6877a23c21SMike Christie return; 6977a23c21SMike Christie 7077a23c21SMike Christie if (exp_cmdsn != session->exp_cmdsn && 7177a23c21SMike Christie !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) 727996a778SMike Christie session->exp_cmdsn = exp_cmdsn; 737996a778SMike Christie 7477a23c21SMike Christie if (max_cmdsn != session->max_cmdsn && 7577a23c21SMike Christie !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { 7677a23c21SMike Christie session->max_cmdsn = max_cmdsn; 7777a23c21SMike Christie /* 7877a23c21SMike Christie * if the window closed with IO queued, then kick the 7977a23c21SMike Christie * xmit thread 8077a23c21SMike Christie */ 8177a23c21SMike Christie if (!list_empty(&session->leadconn->xmitqueue) || 82843c0a8aSMike Christie !list_empty(&session->leadconn->mgmtqueue)) 8377a23c21SMike Christie scsi_queue_work(session->host, 8477a23c21SMike Christie &session->leadconn->xmitwork); 857996a778SMike Christie } 8677a23c21SMike Christie } 8777a23c21SMike Christie EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); 887996a778SMike Christie 897996a778SMike Christie void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, 90ffd0436eSMike Christie struct iscsi_data *hdr) 917996a778SMike Christie { 927996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 937996a778SMike Christie 947996a778SMike Christie memset(hdr, 0, sizeof(struct iscsi_data)); 957996a778SMike Christie hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); 967996a778SMike Christie hdr->datasn = cpu_to_be32(ctask->unsol_datasn); 977996a778SMike Christie ctask->unsol_datasn++; 987996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; 997996a778SMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 1007996a778SMike Christie 1017996a778SMike Christie hdr->itt = ctask->hdr->itt; 1027996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 103ffd0436eSMike Christie hdr->offset = cpu_to_be32(ctask->unsol_offset); 1047996a778SMike Christie 1057996a778SMike Christie if (ctask->unsol_count > conn->max_xmit_dlength) { 1067996a778SMike Christie hton24(hdr->dlength, conn->max_xmit_dlength); 1077996a778SMike Christie ctask->data_count = conn->max_xmit_dlength; 108ffd0436eSMike Christie ctask->unsol_offset += ctask->data_count; 1097996a778SMike Christie hdr->flags = 0; 1107996a778SMike Christie } else { 1117996a778SMike Christie hton24(hdr->dlength, ctask->unsol_count); 1127996a778SMike Christie ctask->data_count = ctask->unsol_count; 1137996a778SMike Christie hdr->flags = ISCSI_FLAG_CMD_FINAL; 1147996a778SMike Christie } 1157996a778SMike Christie } 1167996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); 1177996a778SMike Christie 118004d6530SBoaz Harrosh static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) 119004d6530SBoaz Harrosh { 120004d6530SBoaz Harrosh unsigned exp_len = ctask->hdr_len + len; 121004d6530SBoaz Harrosh 122004d6530SBoaz Harrosh if (exp_len > ctask->hdr_max) { 123004d6530SBoaz Harrosh WARN_ON(1); 124004d6530SBoaz Harrosh return -EINVAL; 125004d6530SBoaz Harrosh } 126004d6530SBoaz Harrosh 127004d6530SBoaz Harrosh WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ 128004d6530SBoaz Harrosh ctask->hdr_len = exp_len; 129004d6530SBoaz Harrosh return 0; 130004d6530SBoaz Harrosh } 131004d6530SBoaz Harrosh 13238d1c069SBoaz Harrosh /* 13338d1c069SBoaz Harrosh * make an extended cdb AHS 13438d1c069SBoaz Harrosh */ 13538d1c069SBoaz Harrosh static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) 13638d1c069SBoaz Harrosh { 13738d1c069SBoaz Harrosh struct scsi_cmnd *cmd = ctask->sc; 13838d1c069SBoaz Harrosh unsigned rlen, pad_len; 13938d1c069SBoaz Harrosh unsigned short ahslength; 14038d1c069SBoaz Harrosh struct iscsi_ecdb_ahdr *ecdb_ahdr; 14138d1c069SBoaz Harrosh int rc; 14238d1c069SBoaz Harrosh 14338d1c069SBoaz Harrosh ecdb_ahdr = iscsi_next_hdr(ctask); 14438d1c069SBoaz Harrosh rlen = cmd->cmd_len - ISCSI_CDB_SIZE; 14538d1c069SBoaz Harrosh 14638d1c069SBoaz Harrosh BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); 14738d1c069SBoaz Harrosh ahslength = rlen + sizeof(ecdb_ahdr->reserved); 14838d1c069SBoaz Harrosh 14938d1c069SBoaz Harrosh pad_len = iscsi_padding(rlen); 15038d1c069SBoaz Harrosh 15138d1c069SBoaz Harrosh rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) + 15238d1c069SBoaz Harrosh sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); 15338d1c069SBoaz Harrosh if (rc) 15438d1c069SBoaz Harrosh return rc; 15538d1c069SBoaz Harrosh 15638d1c069SBoaz Harrosh if (pad_len) 15738d1c069SBoaz Harrosh memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len); 15838d1c069SBoaz Harrosh 15938d1c069SBoaz Harrosh ecdb_ahdr->ahslength = cpu_to_be16(ahslength); 16038d1c069SBoaz Harrosh ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB; 16138d1c069SBoaz Harrosh ecdb_ahdr->reserved = 0; 16238d1c069SBoaz Harrosh memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen); 16338d1c069SBoaz Harrosh 16438d1c069SBoaz Harrosh debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " 16538d1c069SBoaz Harrosh "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", 16638d1c069SBoaz Harrosh cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len); 16738d1c069SBoaz Harrosh 16838d1c069SBoaz Harrosh return 0; 16938d1c069SBoaz Harrosh } 17038d1c069SBoaz Harrosh 171c07d4444SBoaz Harrosh static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) 172c07d4444SBoaz Harrosh { 173c07d4444SBoaz Harrosh struct scsi_cmnd *sc = ctask->sc; 174c07d4444SBoaz Harrosh struct iscsi_rlength_ahdr *rlen_ahdr; 175c07d4444SBoaz Harrosh int rc; 176c07d4444SBoaz Harrosh 177c07d4444SBoaz Harrosh rlen_ahdr = iscsi_next_hdr(ctask); 178c07d4444SBoaz Harrosh rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); 179c07d4444SBoaz Harrosh if (rc) 180c07d4444SBoaz Harrosh return rc; 181c07d4444SBoaz Harrosh 182c07d4444SBoaz Harrosh rlen_ahdr->ahslength = 183c07d4444SBoaz Harrosh cpu_to_be16(sizeof(rlen_ahdr->read_length) + 184c07d4444SBoaz Harrosh sizeof(rlen_ahdr->reserved)); 185c07d4444SBoaz Harrosh rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; 186c07d4444SBoaz Harrosh rlen_ahdr->reserved = 0; 187c07d4444SBoaz Harrosh rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); 188c07d4444SBoaz Harrosh 189c07d4444SBoaz Harrosh debug_scsi("bidi-in rlen_ahdr->read_length(%d) " 190c07d4444SBoaz Harrosh "rlen_ahdr->ahslength(%d)\n", 191c07d4444SBoaz Harrosh be32_to_cpu(rlen_ahdr->read_length), 192c07d4444SBoaz Harrosh be16_to_cpu(rlen_ahdr->ahslength)); 193c07d4444SBoaz Harrosh return 0; 194c07d4444SBoaz Harrosh } 195c07d4444SBoaz Harrosh 1967996a778SMike Christie /** 1977996a778SMike Christie * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu 1987996a778SMike Christie * @ctask: iscsi cmd task 1997996a778SMike Christie * 2007996a778SMike Christie * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set 2017996a778SMike Christie * fields like dlength or final based on how much data it sends 2027996a778SMike Christie */ 203004d6530SBoaz Harrosh static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) 2047996a778SMike Christie { 2057996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 2067996a778SMike Christie struct iscsi_session *session = conn->session; 2077996a778SMike Christie struct iscsi_cmd *hdr = ctask->hdr; 2087996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 20938d1c069SBoaz Harrosh unsigned hdrlength, cmd_len; 210004d6530SBoaz Harrosh int rc; 2117996a778SMike Christie 212004d6530SBoaz Harrosh ctask->hdr_len = 0; 213004d6530SBoaz Harrosh rc = iscsi_add_hdr(ctask, sizeof(*hdr)); 214004d6530SBoaz Harrosh if (rc) 215004d6530SBoaz Harrosh return rc; 2167996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_CMD; 2177996a778SMike Christie hdr->flags = ISCSI_ATTR_SIMPLE; 2187996a778SMike Christie int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 2198b1d0343SMike Christie hdr->itt = build_itt(ctask->itt, session->age); 2207996a778SMike Christie hdr->cmdsn = cpu_to_be32(session->cmdsn); 2217996a778SMike Christie session->cmdsn++; 2227996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 22338d1c069SBoaz Harrosh cmd_len = sc->cmd_len; 22438d1c069SBoaz Harrosh if (cmd_len < ISCSI_CDB_SIZE) 22538d1c069SBoaz Harrosh memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); 22638d1c069SBoaz Harrosh else if (cmd_len > ISCSI_CDB_SIZE) { 22738d1c069SBoaz Harrosh rc = iscsi_prep_ecdb_ahs(ctask); 22838d1c069SBoaz Harrosh if (rc) 22938d1c069SBoaz Harrosh return rc; 23038d1c069SBoaz Harrosh cmd_len = ISCSI_CDB_SIZE; 23138d1c069SBoaz Harrosh } 23238d1c069SBoaz Harrosh memcpy(hdr->cdb, sc->cmnd, cmd_len); 2337996a778SMike Christie 234218432c6SMike Christie ctask->imm_count = 0; 235c07d4444SBoaz Harrosh if (scsi_bidi_cmnd(sc)) { 236c07d4444SBoaz Harrosh hdr->flags |= ISCSI_FLAG_CMD_READ; 237c07d4444SBoaz Harrosh rc = iscsi_prep_bidi_ahs(ctask); 238c07d4444SBoaz Harrosh if (rc) 239c07d4444SBoaz Harrosh return rc; 240c07d4444SBoaz Harrosh } 2417996a778SMike Christie if (sc->sc_data_direction == DMA_TO_DEVICE) { 242c07d4444SBoaz Harrosh unsigned out_len = scsi_out(sc)->length; 243c07d4444SBoaz Harrosh hdr->data_length = cpu_to_be32(out_len); 2447996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_WRITE; 2457996a778SMike Christie /* 2467996a778SMike Christie * Write counters: 2477996a778SMike Christie * 2487996a778SMike Christie * imm_count bytes to be sent right after 2497996a778SMike Christie * SCSI PDU Header 2507996a778SMike Christie * 2517996a778SMike Christie * unsol_count bytes(as Data-Out) to be sent 2527996a778SMike Christie * without R2T ack right after 2537996a778SMike Christie * immediate data 2547996a778SMike Christie * 2557996a778SMike Christie * r2t_data_count bytes to be sent via R2T ack's 2567996a778SMike Christie * 2577996a778SMike Christie * pad_count bytes to be sent as zero-padding 2587996a778SMike Christie */ 2597996a778SMike Christie ctask->unsol_count = 0; 260ffd0436eSMike Christie ctask->unsol_offset = 0; 2617996a778SMike Christie ctask->unsol_datasn = 0; 2627996a778SMike Christie 2637996a778SMike Christie if (session->imm_data_en) { 264c07d4444SBoaz Harrosh if (out_len >= session->first_burst) 2657996a778SMike Christie ctask->imm_count = min(session->first_burst, 2667996a778SMike Christie conn->max_xmit_dlength); 2677996a778SMike Christie else 268c07d4444SBoaz Harrosh ctask->imm_count = min(out_len, 2697996a778SMike Christie conn->max_xmit_dlength); 270a8ac6311SOlaf Kirch hton24(hdr->dlength, ctask->imm_count); 2717996a778SMike Christie } else 272a8ac6311SOlaf Kirch zero_data(hdr->dlength); 2737996a778SMike Christie 274ffd0436eSMike Christie if (!session->initial_r2t_en) { 275c07d4444SBoaz Harrosh ctask->unsol_count = min(session->first_burst, out_len) 276c07d4444SBoaz Harrosh - ctask->imm_count; 277ffd0436eSMike Christie ctask->unsol_offset = ctask->imm_count; 278ffd0436eSMike Christie } 279ffd0436eSMike Christie 2807996a778SMike Christie if (!ctask->unsol_count) 2817996a778SMike Christie /* No unsolicit Data-Out's */ 282a8ac6311SOlaf Kirch hdr->flags |= ISCSI_FLAG_CMD_FINAL; 2837996a778SMike Christie } else { 2847996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 2857996a778SMike Christie zero_data(hdr->dlength); 286c07d4444SBoaz Harrosh hdr->data_length = cpu_to_be32(scsi_in(sc)->length); 2877996a778SMike Christie 2887996a778SMike Christie if (sc->sc_data_direction == DMA_FROM_DEVICE) 2897996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_READ; 2907996a778SMike Christie } 2917996a778SMike Christie 292004d6530SBoaz Harrosh /* calculate size of additional header segments (AHSs) */ 293004d6530SBoaz Harrosh hdrlength = ctask->hdr_len - sizeof(*hdr); 294004d6530SBoaz Harrosh 295004d6530SBoaz Harrosh WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); 296004d6530SBoaz Harrosh hdrlength /= ISCSI_PAD_LEN; 297004d6530SBoaz Harrosh 298004d6530SBoaz Harrosh WARN_ON(hdrlength >= 256); 299004d6530SBoaz Harrosh hdr->hlength = hdrlength & 0xFF; 300004d6530SBoaz Harrosh 301a8ac6311SOlaf Kirch if (conn->session->tt->init_cmd_task(conn->ctask)) 302a8ac6311SOlaf Kirch return EIO; 30377a23c21SMike Christie 304a8ac6311SOlaf Kirch conn->scsicmd_pdus_cnt++; 305c07d4444SBoaz Harrosh debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " 306c07d4444SBoaz Harrosh "len %d bidi_len %d cmdsn %d win %d]\n", 307c07d4444SBoaz Harrosh scsi_bidi_cmnd(sc) ? "bidirectional" : 30877a23c21SMike Christie sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", 309c07d4444SBoaz Harrosh conn->id, sc, sc->cmnd[0], ctask->itt, 310c07d4444SBoaz Harrosh scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, 31177a23c21SMike Christie session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); 312004d6530SBoaz Harrosh return 0; 3137996a778SMike Christie } 3147996a778SMike Christie 3157996a778SMike Christie /** 3167996a778SMike Christie * iscsi_complete_command - return command back to scsi-ml 3177996a778SMike Christie * @ctask: iscsi cmd task 3187996a778SMike Christie * 3197996a778SMike Christie * Must be called with session lock. 3207996a778SMike Christie * This function returns the scsi command to scsi-ml and returns 3217996a778SMike Christie * the cmd task to the pool of available cmd tasks. 3227996a778SMike Christie */ 32360ecebf5SMike Christie static void iscsi_complete_command(struct iscsi_cmd_task *ctask) 3247996a778SMike Christie { 325c1635cb7SMike Christie struct iscsi_conn *conn = ctask->conn; 326c1635cb7SMike Christie struct iscsi_session *session = conn->session; 3277996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 3287996a778SMike Christie 329b6c395edSMike Christie ctask->state = ISCSI_TASK_COMPLETED; 3307996a778SMike Christie ctask->sc = NULL; 331f47f2cf5SMike Christie /* SCSI eh reuses commands to verify us */ 332f47f2cf5SMike Christie sc->SCp.ptr = NULL; 333c1635cb7SMike Christie if (conn->ctask == ctask) 334c1635cb7SMike Christie conn->ctask = NULL; 3357996a778SMike Christie list_del_init(&ctask->running); 3367996a778SMike Christie __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); 3377996a778SMike Christie sc->scsi_done(sc); 3387996a778SMike Christie } 3397996a778SMike Christie 34060ecebf5SMike Christie static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) 34160ecebf5SMike Christie { 34260ecebf5SMike Christie atomic_inc(&ctask->refcount); 34360ecebf5SMike Christie } 34460ecebf5SMike Christie 34560ecebf5SMike Christie static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) 34660ecebf5SMike Christie { 347e648f63cSMike Christie if (atomic_dec_and_test(&ctask->refcount)) 34860ecebf5SMike Christie iscsi_complete_command(ctask); 34960ecebf5SMike Christie } 35060ecebf5SMike Christie 351b3a7ea8dSMike Christie /* 352b3a7ea8dSMike Christie * session lock must be held 353b3a7ea8dSMike Christie */ 354b3a7ea8dSMike Christie static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, 355b3a7ea8dSMike Christie int err) 356b3a7ea8dSMike Christie { 357b3a7ea8dSMike Christie struct scsi_cmnd *sc; 358b3a7ea8dSMike Christie 359b3a7ea8dSMike Christie sc = ctask->sc; 360b3a7ea8dSMike Christie if (!sc) 361b3a7ea8dSMike Christie return; 362b3a7ea8dSMike Christie 363b3a7ea8dSMike Christie if (ctask->state == ISCSI_TASK_PENDING) 364b3a7ea8dSMike Christie /* 365b3a7ea8dSMike Christie * cmd never made it to the xmit thread, so we should not count 366b3a7ea8dSMike Christie * the cmd in the sequencing 367b3a7ea8dSMike Christie */ 368b3a7ea8dSMike Christie conn->session->queued_cmdsn--; 369b3a7ea8dSMike Christie else 370b3a7ea8dSMike Christie conn->session->tt->cleanup_cmd_task(conn, ctask); 371b3a7ea8dSMike Christie 372b3a7ea8dSMike Christie sc->result = err; 373c07d4444SBoaz Harrosh if (!scsi_bidi_cmnd(sc)) 374b3a7ea8dSMike Christie scsi_set_resid(sc, scsi_bufflen(sc)); 375c07d4444SBoaz Harrosh else { 376c07d4444SBoaz Harrosh scsi_out(sc)->resid = scsi_out(sc)->length; 377c07d4444SBoaz Harrosh scsi_in(sc)->resid = scsi_in(sc)->length; 378c07d4444SBoaz Harrosh } 379b3a7ea8dSMike Christie if (conn->ctask == ctask) 380b3a7ea8dSMike Christie conn->ctask = NULL; 381b3a7ea8dSMike Christie /* release ref from queuecommand */ 382b3a7ea8dSMike Christie __iscsi_put_ctask(ctask); 383b3a7ea8dSMike Christie } 384b3a7ea8dSMike Christie 385b3a7ea8dSMike Christie /** 386b3a7ea8dSMike Christie * iscsi_free_mgmt_task - return mgmt task back to pool 387b3a7ea8dSMike Christie * @conn: iscsi connection 388b3a7ea8dSMike Christie * @mtask: mtask 389b3a7ea8dSMike Christie * 390b3a7ea8dSMike Christie * Must be called with session lock. 391b3a7ea8dSMike Christie */ 392b3a7ea8dSMike Christie void iscsi_free_mgmt_task(struct iscsi_conn *conn, 393b3a7ea8dSMike Christie struct iscsi_mgmt_task *mtask) 394b3a7ea8dSMike Christie { 395b3a7ea8dSMike Christie list_del_init(&mtask->running); 396b3a7ea8dSMike Christie if (conn->login_mtask == mtask) 397b3a7ea8dSMike Christie return; 398f6d5180cSMike Christie 399f6d5180cSMike Christie if (conn->ping_mtask == mtask) 400f6d5180cSMike Christie conn->ping_mtask = NULL; 401b3a7ea8dSMike Christie __kfifo_put(conn->session->mgmtpool.queue, 402b3a7ea8dSMike Christie (void*)&mtask, sizeof(void*)); 403b3a7ea8dSMike Christie } 404b3a7ea8dSMike Christie EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); 405b3a7ea8dSMike Christie 406f6d5180cSMike Christie static struct iscsi_mgmt_task * 407f6d5180cSMike Christie __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 408f6d5180cSMike Christie char *data, uint32_t data_size) 409f6d5180cSMike Christie { 410f6d5180cSMike Christie struct iscsi_session *session = conn->session; 411f6d5180cSMike Christie struct iscsi_mgmt_task *mtask; 412f6d5180cSMike Christie 413f6d5180cSMike Christie if (session->state == ISCSI_STATE_TERMINATE) 414f6d5180cSMike Christie return NULL; 415f6d5180cSMike Christie 416f6d5180cSMike Christie if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || 417f6d5180cSMike Christie hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) 418f6d5180cSMike Christie /* 419f6d5180cSMike Christie * Login and Text are sent serially, in 420f6d5180cSMike Christie * request-followed-by-response sequence. 421f6d5180cSMike Christie * Same mtask can be used. Same ITT must be used. 422f6d5180cSMike Christie * Note that login_mtask is preallocated at conn_create(). 423f6d5180cSMike Christie */ 424f6d5180cSMike Christie mtask = conn->login_mtask; 425f6d5180cSMike Christie else { 426f6d5180cSMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); 427f6d5180cSMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); 428f6d5180cSMike Christie 429f6d5180cSMike Christie if (!__kfifo_get(session->mgmtpool.queue, 430f6d5180cSMike Christie (void*)&mtask, sizeof(void*))) 431f6d5180cSMike Christie return NULL; 432f6d5180cSMike Christie } 433f6d5180cSMike Christie 434f6d5180cSMike Christie if (data_size) { 435f6d5180cSMike Christie memcpy(mtask->data, data, data_size); 436f6d5180cSMike Christie mtask->data_count = data_size; 437f6d5180cSMike Christie } else 438f6d5180cSMike Christie mtask->data_count = 0; 439f6d5180cSMike Christie 440f6d5180cSMike Christie memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); 441f6d5180cSMike Christie INIT_LIST_HEAD(&mtask->running); 442f6d5180cSMike Christie list_add_tail(&mtask->running, &conn->mgmtqueue); 443f6d5180cSMike Christie return mtask; 444f6d5180cSMike Christie } 445f6d5180cSMike Christie 446f6d5180cSMike Christie int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, 447f6d5180cSMike Christie char *data, uint32_t data_size) 448f6d5180cSMike Christie { 449f6d5180cSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 450f6d5180cSMike Christie struct iscsi_session *session = conn->session; 451f6d5180cSMike Christie int err = 0; 452f6d5180cSMike Christie 453f6d5180cSMike Christie spin_lock_bh(&session->lock); 454f6d5180cSMike Christie if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) 455f6d5180cSMike Christie err = -EPERM; 456f6d5180cSMike Christie spin_unlock_bh(&session->lock); 457f6d5180cSMike Christie scsi_queue_work(session->host, &conn->xmitwork); 458f6d5180cSMike Christie return err; 459f6d5180cSMike Christie } 460f6d5180cSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); 461f6d5180cSMike Christie 4627996a778SMike Christie /** 4637996a778SMike Christie * iscsi_cmd_rsp - SCSI Command Response processing 4647996a778SMike Christie * @conn: iscsi connection 4657996a778SMike Christie * @hdr: iscsi header 4667996a778SMike Christie * @ctask: scsi command task 4677996a778SMike Christie * @data: cmd data buffer 4687996a778SMike Christie * @datalen: len of buffer 4697996a778SMike Christie * 4707996a778SMike Christie * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and 4717996a778SMike Christie * then completes the command and task. 4727996a778SMike Christie **/ 47377a23c21SMike Christie static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 4747996a778SMike Christie struct iscsi_cmd_task *ctask, char *data, 4757996a778SMike Christie int datalen) 4767996a778SMike Christie { 4777996a778SMike Christie struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; 4787996a778SMike Christie struct iscsi_session *session = conn->session; 4797996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 4807996a778SMike Christie 48177a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); 4827996a778SMike Christie conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; 4837996a778SMike Christie 4847996a778SMike Christie sc->result = (DID_OK << 16) | rhdr->cmd_status; 4857996a778SMike Christie 4867996a778SMike Christie if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { 4877996a778SMike Christie sc->result = DID_ERROR << 16; 4887996a778SMike Christie goto out; 4897996a778SMike Christie } 4907996a778SMike Christie 4917996a778SMike Christie if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { 4929b80cb4bSMike Christie uint16_t senselen; 4937996a778SMike Christie 4947996a778SMike Christie if (datalen < 2) { 4957996a778SMike Christie invalid_datalen: 496322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 497322d739dSMike Christie "Got CHECK_CONDITION but invalid data " 498322d739dSMike Christie "buffer size of %d\n", datalen); 4997996a778SMike Christie sc->result = DID_BAD_TARGET << 16; 5007996a778SMike Christie goto out; 5017996a778SMike Christie } 5027996a778SMike Christie 5038eb00539SMike Christie senselen = be16_to_cpu(get_unaligned((__be16 *) data)); 5047996a778SMike Christie if (datalen < senselen) 5057996a778SMike Christie goto invalid_datalen; 5067996a778SMike Christie 5077996a778SMike Christie memcpy(sc->sense_buffer, data + 2, 5089b80cb4bSMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 5097996a778SMike Christie debug_scsi("copied %d bytes of sense\n", 5108eb00539SMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 5117996a778SMike Christie } 5127996a778SMike Christie 513c07d4444SBoaz Harrosh if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | 514c07d4444SBoaz Harrosh ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { 515c07d4444SBoaz Harrosh int res_count = be32_to_cpu(rhdr->bi_residual_count); 516c07d4444SBoaz Harrosh 517c07d4444SBoaz Harrosh if (scsi_bidi_cmnd(sc) && res_count > 0 && 518c07d4444SBoaz Harrosh (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || 519c07d4444SBoaz Harrosh res_count <= scsi_in(sc)->length)) 520c07d4444SBoaz Harrosh scsi_in(sc)->resid = res_count; 521c07d4444SBoaz Harrosh else 522c07d4444SBoaz Harrosh sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 523c07d4444SBoaz Harrosh } 524c07d4444SBoaz Harrosh 5257207fea4SBoaz Harrosh if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | 5267207fea4SBoaz Harrosh ISCSI_FLAG_CMD_OVERFLOW)) { 5277996a778SMike Christie int res_count = be32_to_cpu(rhdr->residual_count); 5287996a778SMike Christie 5297207fea4SBoaz Harrosh if (res_count > 0 && 5307207fea4SBoaz Harrosh (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || 5317207fea4SBoaz Harrosh res_count <= scsi_bufflen(sc))) 532c07d4444SBoaz Harrosh /* write side for bidi or uni-io set_resid */ 5331c138991SFUJITA Tomonori scsi_set_resid(sc, res_count); 5347996a778SMike Christie else 5357996a778SMike Christie sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 536c07d4444SBoaz Harrosh } 5377996a778SMike Christie out: 5387996a778SMike Christie debug_scsi("done [sc %lx res %d itt 0x%x]\n", 5397996a778SMike Christie (long)sc, sc->result, ctask->itt); 5407996a778SMike Christie conn->scsirsp_pdus_cnt++; 5417996a778SMike Christie 54260ecebf5SMike Christie __iscsi_put_ctask(ctask); 5437996a778SMike Christie } 5447996a778SMike Christie 5457ea8b828SMike Christie static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) 5467ea8b828SMike Christie { 5477ea8b828SMike Christie struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; 5487ea8b828SMike Christie 5497ea8b828SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 5507ea8b828SMike Christie conn->tmfrsp_pdus_cnt++; 5517ea8b828SMike Christie 552843c0a8aSMike Christie if (conn->tmf_state != TMF_QUEUED) 5537ea8b828SMike Christie return; 5547ea8b828SMike Christie 5557ea8b828SMike Christie if (tmf->response == ISCSI_TMF_RSP_COMPLETE) 556843c0a8aSMike Christie conn->tmf_state = TMF_SUCCESS; 5577ea8b828SMike Christie else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) 558843c0a8aSMike Christie conn->tmf_state = TMF_NOT_FOUND; 5597ea8b828SMike Christie else 560843c0a8aSMike Christie conn->tmf_state = TMF_FAILED; 5617ea8b828SMike Christie wake_up(&conn->ehwait); 5627ea8b828SMike Christie } 5637ea8b828SMike Christie 564f6d5180cSMike Christie static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) 565f6d5180cSMike Christie { 566f6d5180cSMike Christie struct iscsi_nopout hdr; 567f6d5180cSMike Christie struct iscsi_mgmt_task *mtask; 568f6d5180cSMike Christie 569f6d5180cSMike Christie if (!rhdr && conn->ping_mtask) 570f6d5180cSMike Christie return; 571f6d5180cSMike Christie 572f6d5180cSMike Christie memset(&hdr, 0, sizeof(struct iscsi_nopout)); 573f6d5180cSMike Christie hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; 574f6d5180cSMike Christie hdr.flags = ISCSI_FLAG_CMD_FINAL; 575f6d5180cSMike Christie 576f6d5180cSMike Christie if (rhdr) { 577f6d5180cSMike Christie memcpy(hdr.lun, rhdr->lun, 8); 578f6d5180cSMike Christie hdr.ttt = rhdr->ttt; 579f6d5180cSMike Christie hdr.itt = RESERVED_ITT; 580f6d5180cSMike Christie } else 581f6d5180cSMike Christie hdr.ttt = RESERVED_ITT; 582f6d5180cSMike Christie 583f6d5180cSMike Christie mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); 584f6d5180cSMike Christie if (!mtask) { 585322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); 586f6d5180cSMike Christie return; 587f6d5180cSMike Christie } 588f6d5180cSMike Christie 589f6d5180cSMike Christie /* only track our nops */ 590f6d5180cSMike Christie if (!rhdr) { 591f6d5180cSMike Christie conn->ping_mtask = mtask; 592f6d5180cSMike Christie conn->last_ping = jiffies; 593f6d5180cSMike Christie } 594f6d5180cSMike Christie scsi_queue_work(conn->session->host, &conn->xmitwork); 595f6d5180cSMike Christie } 596f6d5180cSMike Christie 59762f38300SMike Christie static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 59862f38300SMike Christie char *data, int datalen) 59962f38300SMike Christie { 60062f38300SMike Christie struct iscsi_reject *reject = (struct iscsi_reject *)hdr; 60162f38300SMike Christie struct iscsi_hdr rejected_pdu; 60262f38300SMike Christie uint32_t itt; 60362f38300SMike Christie 60462f38300SMike Christie conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; 60562f38300SMike Christie 60662f38300SMike Christie if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { 60762f38300SMike Christie if (ntoh24(reject->dlength) > datalen) 60862f38300SMike Christie return ISCSI_ERR_PROTO; 60962f38300SMike Christie 61062f38300SMike Christie if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { 61162f38300SMike Christie memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); 612b4377356SAl Viro itt = get_itt(rejected_pdu.itt); 613322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 614322d739dSMike Christie "itt 0x%x had pdu (op 0x%x) rejected " 61562f38300SMike Christie "due to DataDigest error.\n", itt, 61662f38300SMike Christie rejected_pdu.opcode); 61762f38300SMike Christie } 61862f38300SMike Christie } 61962f38300SMike Christie return 0; 62062f38300SMike Christie } 62162f38300SMike Christie 6227996a778SMike Christie /** 6237996a778SMike Christie * __iscsi_complete_pdu - complete pdu 6247996a778SMike Christie * @conn: iscsi conn 6257996a778SMike Christie * @hdr: iscsi header 6267996a778SMike Christie * @data: data buffer 6277996a778SMike Christie * @datalen: len of data buffer 6287996a778SMike Christie * 6297996a778SMike Christie * Completes pdu processing by freeing any resources allocated at 6307996a778SMike Christie * queuecommand or send generic. session lock must be held and verify 6317996a778SMike Christie * itt must have been called. 6327996a778SMike Christie */ 633f8d9d654SAdrian Bunk static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 6347996a778SMike Christie char *data, int datalen) 6357996a778SMike Christie { 6367996a778SMike Christie struct iscsi_session *session = conn->session; 6377996a778SMike Christie int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; 6387996a778SMike Christie struct iscsi_cmd_task *ctask; 6397996a778SMike Christie struct iscsi_mgmt_task *mtask; 6407996a778SMike Christie uint32_t itt; 6417996a778SMike Christie 642f6d5180cSMike Christie conn->last_recv = jiffies; 643b4377356SAl Viro if (hdr->itt != RESERVED_ITT) 644b4377356SAl Viro itt = get_itt(hdr->itt); 6457996a778SMike Christie else 646b4377356SAl Viro itt = ~0U; 6477996a778SMike Christie 6487996a778SMike Christie if (itt < session->cmds_max) { 6497996a778SMike Christie ctask = session->cmds[itt]; 6507996a778SMike Christie 6517996a778SMike Christie debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", 6527996a778SMike Christie opcode, conn->id, ctask->itt, datalen); 6537996a778SMike Christie 6547996a778SMike Christie switch(opcode) { 6557996a778SMike Christie case ISCSI_OP_SCSI_CMD_RSP: 6567996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 65777a23c21SMike Christie iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, 6587996a778SMike Christie datalen); 6597996a778SMike Christie break; 6607996a778SMike Christie case ISCSI_OP_SCSI_DATA_IN: 6617996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 6627996a778SMike Christie if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 6637996a778SMike Christie conn->scsirsp_pdus_cnt++; 66460ecebf5SMike Christie __iscsi_put_ctask(ctask); 6657996a778SMike Christie } 6667996a778SMike Christie break; 6677996a778SMike Christie case ISCSI_OP_R2T: 6687996a778SMike Christie /* LLD handles this for now */ 6697996a778SMike Christie break; 6707996a778SMike Christie default: 6717996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 6727996a778SMike Christie break; 6737996a778SMike Christie } 6747996a778SMike Christie } else if (itt >= ISCSI_MGMT_ITT_OFFSET && 6757996a778SMike Christie itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { 6767996a778SMike Christie mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; 6777996a778SMike Christie 6787996a778SMike Christie debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", 6797996a778SMike Christie opcode, conn->id, mtask->itt, datalen); 6807996a778SMike Christie 68177a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 6828d2860b3SMike Christie switch(opcode) { 6838d2860b3SMike Christie case ISCSI_OP_LOGOUT_RSP: 684c8dc1e52SMike Christie if (datalen) { 685c8dc1e52SMike Christie rc = ISCSI_ERR_PROTO; 686c8dc1e52SMike Christie break; 687c8dc1e52SMike Christie } 6888d2860b3SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 6898d2860b3SMike Christie /* fall through */ 6908d2860b3SMike Christie case ISCSI_OP_LOGIN_RSP: 6918d2860b3SMike Christie case ISCSI_OP_TEXT_RSP: 6928d2860b3SMike Christie /* 6938d2860b3SMike Christie * login related PDU's exp_statsn is handled in 6948d2860b3SMike Christie * userspace 6958d2860b3SMike Christie */ 69640527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 69740527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 698b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, mtask); 6997996a778SMike Christie break; 7007996a778SMike Christie case ISCSI_OP_SCSI_TMFUNC_RSP: 7017996a778SMike Christie if (datalen) { 7027996a778SMike Christie rc = ISCSI_ERR_PROTO; 7037996a778SMike Christie break; 7047996a778SMike Christie } 7058d2860b3SMike Christie 7067ea8b828SMike Christie iscsi_tmf_rsp(conn, hdr); 707b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, mtask); 7087996a778SMike Christie break; 7097996a778SMike Christie case ISCSI_OP_NOOP_IN: 710f6d5180cSMike Christie if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || 711f6d5180cSMike Christie datalen) { 7127996a778SMike Christie rc = ISCSI_ERR_PROTO; 7137996a778SMike Christie break; 7147996a778SMike Christie } 7157996a778SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 7167996a778SMike Christie 717f6d5180cSMike Christie if (conn->ping_mtask != mtask) { 718f6d5180cSMike Christie /* 719f6d5180cSMike Christie * If this is not in response to one of our 720f6d5180cSMike Christie * nops then it must be from userspace. 721f6d5180cSMike Christie */ 722f6d5180cSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, 723f6d5180cSMike Christie datalen)) 72440527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 725c8611f97SMike Christie } else 726c8611f97SMike Christie mod_timer(&conn->transport_timer, 727c8611f97SMike Christie jiffies + conn->recv_timeout); 728b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, mtask); 7297996a778SMike Christie break; 7307996a778SMike Christie default: 7317996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 7327996a778SMike Christie break; 7337996a778SMike Christie } 734b4377356SAl Viro } else if (itt == ~0U) { 73577a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 73662f38300SMike Christie 7377996a778SMike Christie switch(opcode) { 7387996a778SMike Christie case ISCSI_OP_NOOP_IN: 73940527afeSMike Christie if (datalen) { 74040527afeSMike Christie rc = ISCSI_ERR_PROTO; 74140527afeSMike Christie break; 74240527afeSMike Christie } 74340527afeSMike Christie 744b4377356SAl Viro if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) 74540527afeSMike Christie break; 74640527afeSMike Christie 747f6d5180cSMike Christie iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr); 7487996a778SMike Christie break; 7497996a778SMike Christie case ISCSI_OP_REJECT: 75062f38300SMike Christie rc = iscsi_handle_reject(conn, hdr, data, datalen); 75162f38300SMike Christie break; 7527996a778SMike Christie case ISCSI_OP_ASYNC_EVENT: 7538d2860b3SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 7545831c737SMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 7555831c737SMike Christie rc = ISCSI_ERR_CONN_FAILED; 7567996a778SMike Christie break; 7577996a778SMike Christie default: 7587996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 7597996a778SMike Christie break; 7607996a778SMike Christie } 7617996a778SMike Christie } else 7627996a778SMike Christie rc = ISCSI_ERR_BAD_ITT; 7637996a778SMike Christie 7647996a778SMike Christie return rc; 7657996a778SMike Christie } 7667996a778SMike Christie 7677996a778SMike Christie int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 7687996a778SMike Christie char *data, int datalen) 7697996a778SMike Christie { 7707996a778SMike Christie int rc; 7717996a778SMike Christie 7727996a778SMike Christie spin_lock(&conn->session->lock); 7737996a778SMike Christie rc = __iscsi_complete_pdu(conn, hdr, data, datalen); 7747996a778SMike Christie spin_unlock(&conn->session->lock); 7757996a778SMike Christie return rc; 7767996a778SMike Christie } 7777996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_complete_pdu); 7787996a778SMike Christie 7797996a778SMike Christie /* verify itt (itt encoding: age+cid+itt) */ 7807996a778SMike Christie int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 7817996a778SMike Christie uint32_t *ret_itt) 7827996a778SMike Christie { 7837996a778SMike Christie struct iscsi_session *session = conn->session; 7847996a778SMike Christie struct iscsi_cmd_task *ctask; 7857996a778SMike Christie uint32_t itt; 7867996a778SMike Christie 787b4377356SAl Viro if (hdr->itt != RESERVED_ITT) { 788b4377356SAl Viro if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != 7897996a778SMike Christie (session->age << ISCSI_AGE_SHIFT)) { 790322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 791322d739dSMike Christie "received itt %x expected session " 792322d739dSMike Christie "age (%x)\n", (__force u32)hdr->itt, 7937996a778SMike Christie session->age & ISCSI_AGE_MASK); 7947996a778SMike Christie return ISCSI_ERR_BAD_ITT; 7957996a778SMike Christie } 7967996a778SMike Christie 797b4377356SAl Viro itt = get_itt(hdr->itt); 7987996a778SMike Christie } else 799b4377356SAl Viro itt = ~0U; 8007996a778SMike Christie 8017996a778SMike Christie if (itt < session->cmds_max) { 8027996a778SMike Christie ctask = session->cmds[itt]; 8037996a778SMike Christie 8047996a778SMike Christie if (!ctask->sc) { 805322d739dSMike Christie iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " 806322d739dSMike Christie "with itt 0x%x\n", ctask->itt); 8077996a778SMike Christie /* force drop */ 8087996a778SMike Christie return ISCSI_ERR_NO_SCSI_CMD; 8097996a778SMike Christie } 8107996a778SMike Christie 8117996a778SMike Christie if (ctask->sc->SCp.phase != session->age) { 812322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 813322d739dSMike Christie "iscsi: ctask's session age %d, " 8147996a778SMike Christie "expected %d\n", ctask->sc->SCp.phase, 8157996a778SMike Christie session->age); 8167996a778SMike Christie return ISCSI_ERR_SESSION_FAILED; 8177996a778SMike Christie } 8187996a778SMike Christie } 8197996a778SMike Christie 8207996a778SMike Christie *ret_itt = itt; 8217996a778SMike Christie return 0; 8227996a778SMike Christie } 8237996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_verify_itt); 8247996a778SMike Christie 8257996a778SMike Christie void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) 8267996a778SMike Christie { 8277996a778SMike Christie struct iscsi_session *session = conn->session; 8287996a778SMike Christie unsigned long flags; 8297996a778SMike Christie 8307996a778SMike Christie spin_lock_irqsave(&session->lock, flags); 831656cffc9SMike Christie if (session->state == ISCSI_STATE_FAILED) { 832656cffc9SMike Christie spin_unlock_irqrestore(&session->lock, flags); 833656cffc9SMike Christie return; 834656cffc9SMike Christie } 835656cffc9SMike Christie 83667a61114SMike Christie if (conn->stop_stage == 0) 8377996a778SMike Christie session->state = ISCSI_STATE_FAILED; 8387996a778SMike Christie spin_unlock_irqrestore(&session->lock, flags); 8397996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 8407996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 8417996a778SMike Christie iscsi_conn_error(conn->cls_conn, err); 8427996a778SMike Christie } 8437996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_failure); 8447996a778SMike Christie 84577a23c21SMike Christie static void iscsi_prep_mtask(struct iscsi_conn *conn, 84677a23c21SMike Christie struct iscsi_mgmt_task *mtask) 84777a23c21SMike Christie { 84877a23c21SMike Christie struct iscsi_session *session = conn->session; 84977a23c21SMike Christie struct iscsi_hdr *hdr = mtask->hdr; 85077a23c21SMike Christie struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; 85177a23c21SMike Christie 85277a23c21SMike Christie if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && 85377a23c21SMike Christie hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) 85477a23c21SMike Christie nop->exp_statsn = cpu_to_be32(conn->exp_statsn); 85577a23c21SMike Christie /* 85677a23c21SMike Christie * pre-format CmdSN for outgoing PDU. 85777a23c21SMike Christie */ 85877a23c21SMike Christie nop->cmdsn = cpu_to_be32(session->cmdsn); 85977a23c21SMike Christie if (hdr->itt != RESERVED_ITT) { 8608b1d0343SMike Christie hdr->itt = build_itt(mtask->itt, session->age); 861e0726407SMike Christie /* 862e0726407SMike Christie * TODO: We always use immediate, so we never hit this. 863e0726407SMike Christie * If we start to send tmfs or nops as non-immediate then 864e0726407SMike Christie * we should start checking the cmdsn numbers for mgmt tasks. 865e0726407SMike Christie */ 86677a23c21SMike Christie if (conn->c_stage == ISCSI_CONN_STARTED && 867e0726407SMike Christie !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { 868e0726407SMike Christie session->queued_cmdsn++; 86977a23c21SMike Christie session->cmdsn++; 87077a23c21SMike Christie } 871e0726407SMike Christie } 87277a23c21SMike Christie 87377a23c21SMike Christie if (session->tt->init_mgmt_task) 87477a23c21SMike Christie session->tt->init_mgmt_task(conn, mtask); 87577a23c21SMike Christie 87677a23c21SMike Christie debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", 877843c0a8aSMike Christie hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, 878843c0a8aSMike Christie mtask->data_count); 87977a23c21SMike Christie } 88077a23c21SMike Christie 88105db888aSMike Christie static int iscsi_xmit_mtask(struct iscsi_conn *conn) 882b5072ea0SMike Christie { 883b5072ea0SMike Christie struct iscsi_hdr *hdr = conn->mtask->hdr; 884b3a7ea8dSMike Christie int rc; 885b5072ea0SMike Christie 886b3a7ea8dSMike Christie if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) 887b3a7ea8dSMike Christie conn->session->state = ISCSI_STATE_LOGGING_OUT; 88877a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 889b3a7ea8dSMike Christie 890b5072ea0SMike Christie rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); 89177a23c21SMike Christie spin_lock_bh(&conn->session->lock); 892b5072ea0SMike Christie if (rc) 893b5072ea0SMike Christie return rc; 894b5072ea0SMike Christie 89505db888aSMike Christie /* done with this in-progress mtask */ 89605db888aSMike Christie conn->mtask = NULL; 897b5072ea0SMike Christie return 0; 898b5072ea0SMike Christie } 899b5072ea0SMike Christie 90077a23c21SMike Christie static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) 90177a23c21SMike Christie { 90277a23c21SMike Christie struct iscsi_session *session = conn->session; 90377a23c21SMike Christie 90477a23c21SMike Christie /* 90577a23c21SMike Christie * Check for iSCSI window and take care of CmdSN wrap-around 90677a23c21SMike Christie */ 907e0726407SMike Christie if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) { 908e0726407SMike Christie debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u " 909e0726407SMike Christie "CmdSN %u/%u\n", session->exp_cmdsn, 910e0726407SMike Christie session->max_cmdsn, session->cmdsn, 911e0726407SMike Christie session->queued_cmdsn); 91277a23c21SMike Christie return -ENOSPC; 91377a23c21SMike Christie } 91477a23c21SMike Christie return 0; 91577a23c21SMike Christie } 91677a23c21SMike Christie 91777a23c21SMike Christie static int iscsi_xmit_ctask(struct iscsi_conn *conn) 91877a23c21SMike Christie { 91977a23c21SMike Christie struct iscsi_cmd_task *ctask = conn->ctask; 920843c0a8aSMike Christie int rc; 92177a23c21SMike Christie 92277a23c21SMike Christie __iscsi_get_ctask(ctask); 92377a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 92477a23c21SMike Christie rc = conn->session->tt->xmit_cmd_task(conn, ctask); 92577a23c21SMike Christie spin_lock_bh(&conn->session->lock); 92677a23c21SMike Christie __iscsi_put_ctask(ctask); 92777a23c21SMike Christie if (!rc) 92877a23c21SMike Christie /* done with this ctask */ 92977a23c21SMike Christie conn->ctask = NULL; 93077a23c21SMike Christie return rc; 93177a23c21SMike Christie } 93277a23c21SMike Christie 9337996a778SMike Christie /** 934843c0a8aSMike Christie * iscsi_requeue_ctask - requeue ctask to run from session workqueue 935843c0a8aSMike Christie * @ctask: ctask to requeue 936843c0a8aSMike Christie * 937843c0a8aSMike Christie * LLDs that need to run a ctask from the session workqueue should call 938843c0a8aSMike Christie * this. The session lock must be held. 939843c0a8aSMike Christie */ 940843c0a8aSMike Christie void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) 941843c0a8aSMike Christie { 942843c0a8aSMike Christie struct iscsi_conn *conn = ctask->conn; 943843c0a8aSMike Christie 944843c0a8aSMike Christie list_move_tail(&ctask->running, &conn->requeue); 945843c0a8aSMike Christie scsi_queue_work(conn->session->host, &conn->xmitwork); 946843c0a8aSMike Christie } 947843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); 948843c0a8aSMike Christie 949843c0a8aSMike Christie /** 9507996a778SMike Christie * iscsi_data_xmit - xmit any command into the scheduled connection 9517996a778SMike Christie * @conn: iscsi connection 9527996a778SMike Christie * 9537996a778SMike Christie * Notes: 9547996a778SMike Christie * The function can return -EAGAIN in which case the caller must 9557996a778SMike Christie * re-schedule it again later or recover. '0' return code means 9567996a778SMike Christie * successful xmit. 9577996a778SMike Christie **/ 9587996a778SMike Christie static int iscsi_data_xmit(struct iscsi_conn *conn) 9597996a778SMike Christie { 9603219e529SMike Christie int rc = 0; 9617996a778SMike Christie 96277a23c21SMike Christie spin_lock_bh(&conn->session->lock); 9637996a778SMike Christie if (unlikely(conn->suspend_tx)) { 9647996a778SMike Christie debug_scsi("conn %d Tx suspended!\n", conn->id); 96577a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 9663219e529SMike Christie return -ENODATA; 9677996a778SMike Christie } 9687996a778SMike Christie 9697996a778SMike Christie if (conn->ctask) { 97077a23c21SMike Christie rc = iscsi_xmit_ctask(conn); 9713219e529SMike Christie if (rc) 9727996a778SMike Christie goto again; 9737996a778SMike Christie } 97477a23c21SMike Christie 9757996a778SMike Christie if (conn->mtask) { 97605db888aSMike Christie rc = iscsi_xmit_mtask(conn); 9773219e529SMike Christie if (rc) 9787996a778SMike Christie goto again; 9797996a778SMike Christie } 9807996a778SMike Christie 98177a23c21SMike Christie /* 98277a23c21SMike Christie * process mgmt pdus like nops before commands since we should 98377a23c21SMike Christie * only have one nop-out as a ping from us and targets should not 98477a23c21SMike Christie * overflow us with nop-ins 98577a23c21SMike Christie */ 98677a23c21SMike Christie check_mgmt: 987843c0a8aSMike Christie while (!list_empty(&conn->mgmtqueue)) { 988843c0a8aSMike Christie conn->mtask = list_entry(conn->mgmtqueue.next, 989843c0a8aSMike Christie struct iscsi_mgmt_task, running); 990b3a7ea8dSMike Christie if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { 991b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, conn->mtask); 992b3a7ea8dSMike Christie conn->mtask = NULL; 993b3a7ea8dSMike Christie continue; 994b3a7ea8dSMike Christie } 995b3a7ea8dSMike Christie 99677a23c21SMike Christie iscsi_prep_mtask(conn, conn->mtask); 997843c0a8aSMike Christie list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); 99805db888aSMike Christie rc = iscsi_xmit_mtask(conn); 9993219e529SMike Christie if (rc) 10007996a778SMike Christie goto again; 10017996a778SMike Christie } 10027996a778SMike Christie 1003843c0a8aSMike Christie /* process pending command queue */ 1004b6c395edSMike Christie while (!list_empty(&conn->xmitqueue)) { 1005843c0a8aSMike Christie if (conn->tmf_state == TMF_QUEUED) 1006843c0a8aSMike Christie break; 1007843c0a8aSMike Christie 1008b6c395edSMike Christie conn->ctask = list_entry(conn->xmitqueue.next, 1009b6c395edSMike Christie struct iscsi_cmd_task, running); 1010b3a7ea8dSMike Christie if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { 10119000bcd6SMike Christie fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); 1012b3a7ea8dSMike Christie continue; 1013b3a7ea8dSMike Christie } 1014004d6530SBoaz Harrosh if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { 1015004d6530SBoaz Harrosh fail_command(conn, conn->ctask, DID_ABORT << 16); 1016004d6530SBoaz Harrosh continue; 1017004d6530SBoaz Harrosh } 1018a8ac6311SOlaf Kirch 1019b6c395edSMike Christie conn->ctask->state = ISCSI_TASK_RUNNING; 1020b6c395edSMike Christie list_move_tail(conn->xmitqueue.next, &conn->run_list); 102177a23c21SMike Christie rc = iscsi_xmit_ctask(conn); 10223219e529SMike Christie if (rc) 10237996a778SMike Christie goto again; 102477a23c21SMike Christie /* 102577a23c21SMike Christie * we could continuously get new ctask requests so 102677a23c21SMike Christie * we need to check the mgmt queue for nops that need to 102777a23c21SMike Christie * be sent to aviod starvation 102877a23c21SMike Christie */ 1029843c0a8aSMike Christie if (!list_empty(&conn->mgmtqueue)) 1030843c0a8aSMike Christie goto check_mgmt; 1031843c0a8aSMike Christie } 1032843c0a8aSMike Christie 1033843c0a8aSMike Christie while (!list_empty(&conn->requeue)) { 1034843c0a8aSMike Christie if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) 1035843c0a8aSMike Christie break; 1036843c0a8aSMike Christie 1037b3a7ea8dSMike Christie /* 1038b3a7ea8dSMike Christie * we always do fastlogout - conn stop code will clean up. 1039b3a7ea8dSMike Christie */ 1040b3a7ea8dSMike Christie if (conn->session->state == ISCSI_STATE_LOGGING_OUT) 1041b3a7ea8dSMike Christie break; 1042b3a7ea8dSMike Christie 1043843c0a8aSMike Christie conn->ctask = list_entry(conn->requeue.next, 1044843c0a8aSMike Christie struct iscsi_cmd_task, running); 1045843c0a8aSMike Christie conn->ctask->state = ISCSI_TASK_RUNNING; 1046843c0a8aSMike Christie list_move_tail(conn->requeue.next, &conn->run_list); 1047843c0a8aSMike Christie rc = iscsi_xmit_ctask(conn); 1048843c0a8aSMike Christie if (rc) 1049843c0a8aSMike Christie goto again; 1050843c0a8aSMike Christie if (!list_empty(&conn->mgmtqueue)) 105177a23c21SMike Christie goto check_mgmt; 10527996a778SMike Christie } 105377a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 10543219e529SMike Christie return -ENODATA; 10557996a778SMike Christie 10567996a778SMike Christie again: 10577996a778SMike Christie if (unlikely(conn->suspend_tx)) 105877a23c21SMike Christie rc = -ENODATA; 105977a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 10603219e529SMike Christie return rc; 10617996a778SMike Christie } 10627996a778SMike Christie 1063c4028958SDavid Howells static void iscsi_xmitworker(struct work_struct *work) 10647996a778SMike Christie { 1065c4028958SDavid Howells struct iscsi_conn *conn = 1066c4028958SDavid Howells container_of(work, struct iscsi_conn, xmitwork); 10673219e529SMike Christie int rc; 10687996a778SMike Christie /* 10697996a778SMike Christie * serialize Xmit worker on a per-connection basis. 10707996a778SMike Christie */ 10713219e529SMike Christie do { 10723219e529SMike Christie rc = iscsi_data_xmit(conn); 10733219e529SMike Christie } while (rc >= 0 || rc == -EAGAIN); 10747996a778SMike Christie } 10757996a778SMike Christie 10767996a778SMike Christie enum { 10777996a778SMike Christie FAILURE_BAD_HOST = 1, 10787996a778SMike Christie FAILURE_SESSION_FAILED, 10797996a778SMike Christie FAILURE_SESSION_FREED, 10807996a778SMike Christie FAILURE_WINDOW_CLOSED, 108160ecebf5SMike Christie FAILURE_OOM, 10827996a778SMike Christie FAILURE_SESSION_TERMINATE, 1083656cffc9SMike Christie FAILURE_SESSION_IN_RECOVERY, 10847996a778SMike Christie FAILURE_SESSION_RECOVERY_TIMEOUT, 1085b3a7ea8dSMike Christie FAILURE_SESSION_LOGGING_OUT, 10866eabafbeSMike Christie FAILURE_SESSION_NOT_READY, 10877996a778SMike Christie }; 10887996a778SMike Christie 10897996a778SMike Christie int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 10907996a778SMike Christie { 109175613521SMike Christie struct iscsi_cls_session *cls_session; 10927996a778SMike Christie struct Scsi_Host *host; 10937996a778SMike Christie int reason = 0; 10947996a778SMike Christie struct iscsi_session *session; 10957996a778SMike Christie struct iscsi_conn *conn; 10967996a778SMike Christie struct iscsi_cmd_task *ctask = NULL; 10977996a778SMike Christie 10987996a778SMike Christie sc->scsi_done = done; 10997996a778SMike Christie sc->result = 0; 1100f47f2cf5SMike Christie sc->SCp.ptr = NULL; 11017996a778SMike Christie 11027996a778SMike Christie host = sc->device->host; 11031040c99dSMike Christie spin_unlock(host->host_lock); 11047996a778SMike Christie 110575613521SMike Christie cls_session = starget_to_session(scsi_target(sc->device)); 110675613521SMike Christie session = cls_session->dd_data; 11077996a778SMike Christie spin_lock(&session->lock); 11087996a778SMike Christie 110975613521SMike Christie reason = iscsi_session_chkready(cls_session); 11106eabafbeSMike Christie if (reason) { 11116eabafbeSMike Christie sc->result = reason; 11126eabafbeSMike Christie goto fault; 11136eabafbeSMike Christie } 11146eabafbeSMike Christie 1115656cffc9SMike Christie /* 1116656cffc9SMike Christie * ISCSI_STATE_FAILED is a temp. state. The recovery 1117656cffc9SMike Christie * code will decide what is best to do with command queued 1118656cffc9SMike Christie * during this time 1119656cffc9SMike Christie */ 1120656cffc9SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN && 1121656cffc9SMike Christie session->state != ISCSI_STATE_FAILED) { 1122656cffc9SMike Christie /* 1123656cffc9SMike Christie * to handle the race between when we set the recovery state 1124656cffc9SMike Christie * and block the session we requeue here (commands could 1125656cffc9SMike Christie * be entering our queuecommand while a block is starting 1126656cffc9SMike Christie * up because the block code is not locked) 1127656cffc9SMike Christie */ 11289000bcd6SMike Christie switch (session->state) { 11299000bcd6SMike Christie case ISCSI_STATE_IN_RECOVERY: 1130656cffc9SMike Christie reason = FAILURE_SESSION_IN_RECOVERY; 11316eabafbeSMike Christie sc->result = DID_IMM_RETRY << 16; 11326eabafbeSMike Christie break; 11339000bcd6SMike Christie case ISCSI_STATE_LOGGING_OUT: 11349000bcd6SMike Christie reason = FAILURE_SESSION_LOGGING_OUT; 11356eabafbeSMike Christie sc->result = DID_IMM_RETRY << 16; 11366eabafbeSMike Christie break; 1137b3a7ea8dSMike Christie case ISCSI_STATE_RECOVERY_FAILED: 1138656cffc9SMike Christie reason = FAILURE_SESSION_RECOVERY_TIMEOUT; 11396eabafbeSMike Christie sc->result = DID_NO_CONNECT << 16; 1140b3a7ea8dSMike Christie break; 1141b3a7ea8dSMike Christie case ISCSI_STATE_TERMINATE: 1142656cffc9SMike Christie reason = FAILURE_SESSION_TERMINATE; 11436eabafbeSMike Christie sc->result = DID_NO_CONNECT << 16; 1144b3a7ea8dSMike Christie break; 1145b3a7ea8dSMike Christie default: 11467996a778SMike Christie reason = FAILURE_SESSION_FREED; 11476eabafbeSMike Christie sc->result = DID_NO_CONNECT << 16; 1148b3a7ea8dSMike Christie } 11497996a778SMike Christie goto fault; 11507996a778SMike Christie } 11517996a778SMike Christie 11527996a778SMike Christie conn = session->leadconn; 115398644047SMike Christie if (!conn) { 115498644047SMike Christie reason = FAILURE_SESSION_FREED; 11556eabafbeSMike Christie sc->result = DID_NO_CONNECT << 16; 115698644047SMike Christie goto fault; 115798644047SMike Christie } 11587996a778SMike Christie 115977a23c21SMike Christie if (iscsi_check_cmdsn_window_closed(conn)) { 116077a23c21SMike Christie reason = FAILURE_WINDOW_CLOSED; 116177a23c21SMike Christie goto reject; 116277a23c21SMike Christie } 116377a23c21SMike Christie 116460ecebf5SMike Christie if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, 116560ecebf5SMike Christie sizeof(void*))) { 116660ecebf5SMike Christie reason = FAILURE_OOM; 116760ecebf5SMike Christie goto reject; 116860ecebf5SMike Christie } 1169e0726407SMike Christie session->queued_cmdsn++; 1170e0726407SMike Christie 11717996a778SMike Christie sc->SCp.phase = session->age; 11727996a778SMike Christie sc->SCp.ptr = (char *)ctask; 11737996a778SMike Christie 117460ecebf5SMike Christie atomic_set(&ctask->refcount, 1); 1175b6c395edSMike Christie ctask->state = ISCSI_TASK_PENDING; 11767996a778SMike Christie ctask->conn = conn; 11777996a778SMike Christie ctask->sc = sc; 11787996a778SMike Christie INIT_LIST_HEAD(&ctask->running); 11797996a778SMike Christie 1180b6c395edSMike Christie list_add_tail(&ctask->running, &conn->xmitqueue); 11817996a778SMike Christie spin_unlock(&session->lock); 11827996a778SMike Christie 11837996a778SMike Christie scsi_queue_work(host, &conn->xmitwork); 11841040c99dSMike Christie spin_lock(host->host_lock); 11857996a778SMike Christie return 0; 11867996a778SMike Christie 11877996a778SMike Christie reject: 11887996a778SMike Christie spin_unlock(&session->lock); 11897996a778SMike Christie debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); 11901040c99dSMike Christie spin_lock(host->host_lock); 11917996a778SMike Christie return SCSI_MLQUEUE_HOST_BUSY; 11927996a778SMike Christie 11937996a778SMike Christie fault: 11947996a778SMike Christie spin_unlock(&session->lock); 11956eabafbeSMike Christie debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); 1196c07d4444SBoaz Harrosh if (!scsi_bidi_cmnd(sc)) 11971c138991SFUJITA Tomonori scsi_set_resid(sc, scsi_bufflen(sc)); 1198c07d4444SBoaz Harrosh else { 1199c07d4444SBoaz Harrosh scsi_out(sc)->resid = scsi_out(sc)->length; 1200c07d4444SBoaz Harrosh scsi_in(sc)->resid = scsi_in(sc)->length; 1201c07d4444SBoaz Harrosh } 12027996a778SMike Christie sc->scsi_done(sc); 12031040c99dSMike Christie spin_lock(host->host_lock); 12047996a778SMike Christie return 0; 12057996a778SMike Christie } 12067996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_queuecommand); 12077996a778SMike Christie 12087996a778SMike Christie int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) 12097996a778SMike Christie { 12107996a778SMike Christie if (depth > ISCSI_MAX_CMD_PER_LUN) 12117996a778SMike Christie depth = ISCSI_MAX_CMD_PER_LUN; 12127996a778SMike Christie scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); 12137996a778SMike Christie return sdev->queue_depth; 12147996a778SMike Christie } 12157996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); 12167996a778SMike Christie 12177996a778SMike Christie void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) 12187996a778SMike Christie { 121975613521SMike Christie struct iscsi_session *session = cls_session->dd_data; 12207996a778SMike Christie 12217996a778SMike Christie spin_lock_bh(&session->lock); 12227996a778SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN) { 1223656cffc9SMike Christie session->state = ISCSI_STATE_RECOVERY_FAILED; 1224843c0a8aSMike Christie if (session->leadconn) 1225843c0a8aSMike Christie wake_up(&session->leadconn->ehwait); 12267996a778SMike Christie } 12277996a778SMike Christie spin_unlock_bh(&session->lock); 12287996a778SMike Christie } 12297996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); 12307996a778SMike Christie 12317996a778SMike Christie int iscsi_eh_host_reset(struct scsi_cmnd *sc) 12327996a778SMike Christie { 123375613521SMike Christie struct iscsi_cls_session *cls_session; 123475613521SMike Christie struct iscsi_session *session; 123575613521SMike Christie struct iscsi_conn *conn; 123675613521SMike Christie 123775613521SMike Christie cls_session = starget_to_session(scsi_target(sc->device)); 123875613521SMike Christie session = cls_session->dd_data; 123975613521SMike Christie conn = session->leadconn; 12407996a778SMike Christie 1241bc436b27SMike Christie mutex_lock(&session->eh_mutex); 12427996a778SMike Christie spin_lock_bh(&session->lock); 12437996a778SMike Christie if (session->state == ISCSI_STATE_TERMINATE) { 12447996a778SMike Christie failed: 12457996a778SMike Christie debug_scsi("failing host reset: session terminated " 1246d6e24d1cSPete Wyckoff "[CID %d age %d]\n", conn->id, session->age); 12477996a778SMike Christie spin_unlock_bh(&session->lock); 1248bc436b27SMike Christie mutex_unlock(&session->eh_mutex); 12497996a778SMike Christie return FAILED; 12507996a778SMike Christie } 12517996a778SMike Christie 12527996a778SMike Christie spin_unlock_bh(&session->lock); 1253bc436b27SMike Christie mutex_unlock(&session->eh_mutex); 12547996a778SMike Christie /* 12557996a778SMike Christie * we drop the lock here but the leadconn cannot be destoyed while 12567996a778SMike Christie * we are in the scsi eh 12577996a778SMike Christie */ 12587996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 12597996a778SMike Christie 12607996a778SMike Christie debug_scsi("iscsi_eh_host_reset wait for relogin\n"); 12617996a778SMike Christie wait_event_interruptible(conn->ehwait, 12627996a778SMike Christie session->state == ISCSI_STATE_TERMINATE || 12637996a778SMike Christie session->state == ISCSI_STATE_LOGGED_IN || 1264656cffc9SMike Christie session->state == ISCSI_STATE_RECOVERY_FAILED); 12657996a778SMike Christie if (signal_pending(current)) 12667996a778SMike Christie flush_signals(current); 12677996a778SMike Christie 1268bc436b27SMike Christie mutex_lock(&session->eh_mutex); 12697996a778SMike Christie spin_lock_bh(&session->lock); 12707996a778SMike Christie if (session->state == ISCSI_STATE_LOGGED_IN) 1271322d739dSMike Christie iscsi_session_printk(KERN_INFO, session, 1272322d739dSMike Christie "host reset succeeded\n"); 12737996a778SMike Christie else 12747996a778SMike Christie goto failed; 12757996a778SMike Christie spin_unlock_bh(&session->lock); 1276bc436b27SMike Christie mutex_unlock(&session->eh_mutex); 12777996a778SMike Christie return SUCCESS; 12787996a778SMike Christie } 12797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); 12807996a778SMike Christie 1281843c0a8aSMike Christie static void iscsi_tmf_timedout(unsigned long data) 12827996a778SMike Christie { 1283843c0a8aSMike Christie struct iscsi_conn *conn = (struct iscsi_conn *)data; 12847996a778SMike Christie struct iscsi_session *session = conn->session; 12857996a778SMike Christie 12867996a778SMike Christie spin_lock(&session->lock); 1287843c0a8aSMike Christie if (conn->tmf_state == TMF_QUEUED) { 1288843c0a8aSMike Christie conn->tmf_state = TMF_TIMEDOUT; 1289843c0a8aSMike Christie debug_scsi("tmf timedout\n"); 12907996a778SMike Christie /* unblock eh_abort() */ 12917996a778SMike Christie wake_up(&conn->ehwait); 12927996a778SMike Christie } 12937996a778SMike Christie spin_unlock(&session->lock); 12947996a778SMike Christie } 12957996a778SMike Christie 1296843c0a8aSMike Christie static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, 1297f6d5180cSMike Christie struct iscsi_tm *hdr, int age, 1298f6d5180cSMike Christie int timeout) 12997996a778SMike Christie { 13007996a778SMike Christie struct iscsi_session *session = conn->session; 1301843c0a8aSMike Christie struct iscsi_mgmt_task *mtask; 13027996a778SMike Christie 1303843c0a8aSMike Christie mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, 13047996a778SMike Christie NULL, 0); 1305843c0a8aSMike Christie if (!mtask) { 13066724add1SMike Christie spin_unlock_bh(&session->lock); 13077996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1308843c0a8aSMike Christie spin_lock_bh(&session->lock); 1309843c0a8aSMike Christie debug_scsi("tmf exec failure\n"); 131077a23c21SMike Christie return -EPERM; 13117996a778SMike Christie } 13127996a778SMike Christie conn->tmfcmd_pdus_cnt++; 1313f6d5180cSMike Christie conn->tmf_timer.expires = timeout * HZ + jiffies; 1314843c0a8aSMike Christie conn->tmf_timer.function = iscsi_tmf_timedout; 1315843c0a8aSMike Christie conn->tmf_timer.data = (unsigned long)conn; 1316843c0a8aSMike Christie add_timer(&conn->tmf_timer); 1317843c0a8aSMike Christie debug_scsi("tmf set timeout\n"); 1318843c0a8aSMike Christie 13197996a778SMike Christie spin_unlock_bh(&session->lock); 13206724add1SMike Christie mutex_unlock(&session->eh_mutex); 132177a23c21SMike Christie scsi_queue_work(session->host, &conn->xmitwork); 13227996a778SMike Christie 13237996a778SMike Christie /* 13247996a778SMike Christie * block eh thread until: 13257996a778SMike Christie * 1326843c0a8aSMike Christie * 1) tmf response 1327843c0a8aSMike Christie * 2) tmf timeout 13287996a778SMike Christie * 3) session is terminated or restarted or userspace has 13297996a778SMike Christie * given up on recovery 13307996a778SMike Christie */ 1331843c0a8aSMike Christie wait_event_interruptible(conn->ehwait, age != session->age || 13327996a778SMike Christie session->state != ISCSI_STATE_LOGGED_IN || 1333843c0a8aSMike Christie conn->tmf_state != TMF_QUEUED); 13347996a778SMike Christie if (signal_pending(current)) 13357996a778SMike Christie flush_signals(current); 1336843c0a8aSMike Christie del_timer_sync(&conn->tmf_timer); 1337843c0a8aSMike Christie 13386724add1SMike Christie mutex_lock(&session->eh_mutex); 133977a23c21SMike Christie spin_lock_bh(&session->lock); 1340843c0a8aSMike Christie /* if the session drops it will clean up the mtask */ 1341843c0a8aSMike Christie if (age != session->age || 1342843c0a8aSMike Christie session->state != ISCSI_STATE_LOGGED_IN) 1343843c0a8aSMike Christie return -ENOTCONN; 13447996a778SMike Christie return 0; 13457996a778SMike Christie } 13467996a778SMike Christie 13477996a778SMike Christie /* 1348843c0a8aSMike Christie * Fail commands. session lock held and recv side suspended and xmit 1349843c0a8aSMike Christie * thread flushed 1350843c0a8aSMike Christie */ 13516eabafbeSMike Christie static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, 13526eabafbeSMike Christie int error) 1353843c0a8aSMike Christie { 1354843c0a8aSMike Christie struct iscsi_cmd_task *ctask, *tmp; 1355843c0a8aSMike Christie 1356843c0a8aSMike Christie if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) 1357843c0a8aSMike Christie conn->ctask = NULL; 1358843c0a8aSMike Christie 1359843c0a8aSMike Christie /* flush pending */ 1360843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { 1361843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1362843c0a8aSMike Christie debug_scsi("failing pending sc %p itt 0x%x\n", 1363843c0a8aSMike Christie ctask->sc, ctask->itt); 13646eabafbeSMike Christie fail_command(conn, ctask, error << 16); 1365843c0a8aSMike Christie } 1366843c0a8aSMike Christie } 1367843c0a8aSMike Christie 1368843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { 1369843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1370843c0a8aSMike Christie debug_scsi("failing requeued sc %p itt 0x%x\n", 1371843c0a8aSMike Christie ctask->sc, ctask->itt); 13726eabafbeSMike Christie fail_command(conn, ctask, error << 16); 1373843c0a8aSMike Christie } 1374843c0a8aSMike Christie } 1375843c0a8aSMike Christie 1376843c0a8aSMike Christie /* fail all other running */ 1377843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { 1378843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1379843c0a8aSMike Christie debug_scsi("failing in progress sc %p itt 0x%x\n", 1380843c0a8aSMike Christie ctask->sc, ctask->itt); 1381843c0a8aSMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 1382843c0a8aSMike Christie } 1383843c0a8aSMike Christie } 1384843c0a8aSMike Christie } 1385843c0a8aSMike Christie 1386*b40977d9SMike Christie void iscsi_suspend_tx(struct iscsi_conn *conn) 13876724add1SMike Christie { 13886724add1SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 13896724add1SMike Christie scsi_flush_work(conn->session->host); 13906724add1SMike Christie } 1391*b40977d9SMike Christie EXPORT_SYMBOL_GPL(iscsi_suspend_tx); 13926724add1SMike Christie 13936724add1SMike Christie static void iscsi_start_tx(struct iscsi_conn *conn) 13946724add1SMike Christie { 13956724add1SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 13966724add1SMike Christie scsi_queue_work(conn->session->host, &conn->xmitwork); 13976724add1SMike Christie } 13986724add1SMike Christie 1399f6d5180cSMike Christie static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) 1400f6d5180cSMike Christie { 1401f6d5180cSMike Christie struct iscsi_cls_session *cls_session; 1402f6d5180cSMike Christie struct iscsi_session *session; 1403f6d5180cSMike Christie struct iscsi_conn *conn; 1404f6d5180cSMike Christie enum scsi_eh_timer_return rc = EH_NOT_HANDLED; 1405f6d5180cSMike Christie 1406f6d5180cSMike Christie cls_session = starget_to_session(scsi_target(scmd->device)); 140775613521SMike Christie session = cls_session->dd_data; 1408f6d5180cSMike Christie 1409f6d5180cSMike Christie debug_scsi("scsi cmd %p timedout\n", scmd); 1410f6d5180cSMike Christie 1411f6d5180cSMike Christie spin_lock(&session->lock); 1412f6d5180cSMike Christie if (session->state != ISCSI_STATE_LOGGED_IN) { 1413f6d5180cSMike Christie /* 1414f6d5180cSMike Christie * We are probably in the middle of iscsi recovery so let 1415f6d5180cSMike Christie * that complete and handle the error. 1416f6d5180cSMike Christie */ 1417f6d5180cSMike Christie rc = EH_RESET_TIMER; 1418f6d5180cSMike Christie goto done; 1419f6d5180cSMike Christie } 1420f6d5180cSMike Christie 1421f6d5180cSMike Christie conn = session->leadconn; 1422f6d5180cSMike Christie if (!conn) { 1423f6d5180cSMike Christie /* In the middle of shuting down */ 1424f6d5180cSMike Christie rc = EH_RESET_TIMER; 1425f6d5180cSMike Christie goto done; 1426f6d5180cSMike Christie } 1427f6d5180cSMike Christie 1428f6d5180cSMike Christie if (!conn->recv_timeout && !conn->ping_timeout) 1429f6d5180cSMike Christie goto done; 1430f6d5180cSMike Christie /* 1431f6d5180cSMike Christie * if the ping timedout then we are in the middle of cleaning up 1432f6d5180cSMike Christie * and can let the iscsi eh handle it 1433f6d5180cSMike Christie */ 1434f6d5180cSMike Christie if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + 1435f6d5180cSMike Christie (conn->ping_timeout * HZ), jiffies)) 1436f6d5180cSMike Christie rc = EH_RESET_TIMER; 1437f6d5180cSMike Christie /* 1438f6d5180cSMike Christie * if we are about to check the transport then give the command 1439f6d5180cSMike Christie * more time 1440f6d5180cSMike Christie */ 1441f6d5180cSMike Christie if (time_before_eq(conn->last_recv + (conn->recv_timeout * HZ), 1442f6d5180cSMike Christie jiffies)) 1443f6d5180cSMike Christie rc = EH_RESET_TIMER; 1444f6d5180cSMike Christie /* if in the middle of checking the transport then give us more time */ 1445f6d5180cSMike Christie if (conn->ping_mtask) 1446f6d5180cSMike Christie rc = EH_RESET_TIMER; 1447f6d5180cSMike Christie done: 1448f6d5180cSMike Christie spin_unlock(&session->lock); 1449f6d5180cSMike Christie debug_scsi("return %s\n", rc == EH_RESET_TIMER ? "timer reset" : "nh"); 1450f6d5180cSMike Christie return rc; 1451f6d5180cSMike Christie } 1452f6d5180cSMike Christie 1453f6d5180cSMike Christie static void iscsi_check_transport_timeouts(unsigned long data) 1454f6d5180cSMike Christie { 1455f6d5180cSMike Christie struct iscsi_conn *conn = (struct iscsi_conn *)data; 1456f6d5180cSMike Christie struct iscsi_session *session = conn->session; 14574cf10435SMike Christie unsigned long recv_timeout, next_timeout = 0, last_recv; 1458f6d5180cSMike Christie 1459f6d5180cSMike Christie spin_lock(&session->lock); 1460f6d5180cSMike Christie if (session->state != ISCSI_STATE_LOGGED_IN) 1461f6d5180cSMike Christie goto done; 1462f6d5180cSMike Christie 14634cf10435SMike Christie recv_timeout = conn->recv_timeout; 14644cf10435SMike Christie if (!recv_timeout) 1465f6d5180cSMike Christie goto done; 1466f6d5180cSMike Christie 14674cf10435SMike Christie recv_timeout *= HZ; 1468f6d5180cSMike Christie last_recv = conn->last_recv; 14694cf10435SMike Christie if (conn->ping_mtask && 14704cf10435SMike Christie time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), 1471f6d5180cSMike Christie jiffies)) { 1472322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " 1473322d739dSMike Christie "expired, last rx %lu, last ping %lu, " 1474322d739dSMike Christie "now %lu\n", conn->ping_timeout, last_recv, 1475f6d5180cSMike Christie conn->last_ping, jiffies); 1476f6d5180cSMike Christie spin_unlock(&session->lock); 1477f6d5180cSMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1478f6d5180cSMike Christie return; 1479f6d5180cSMike Christie } 1480f6d5180cSMike Christie 14814cf10435SMike Christie if (time_before_eq(last_recv + recv_timeout, jiffies)) { 1482f6d5180cSMike Christie /* send a ping to try to provoke some traffic */ 1483f6d5180cSMike Christie debug_scsi("Sending nopout as ping on conn %p\n", conn); 1484f6d5180cSMike Christie iscsi_send_nopout(conn, NULL); 14854cf10435SMike Christie next_timeout = conn->last_ping + (conn->ping_timeout * HZ); 1486ad294e9cSMike Christie } else 14874cf10435SMike Christie next_timeout = last_recv + recv_timeout; 1488f6d5180cSMike Christie 1489f6d5180cSMike Christie debug_scsi("Setting next tmo %lu\n", next_timeout); 1490f6d5180cSMike Christie mod_timer(&conn->transport_timer, next_timeout); 1491f6d5180cSMike Christie done: 1492f6d5180cSMike Christie spin_unlock(&session->lock); 1493f6d5180cSMike Christie } 1494f6d5180cSMike Christie 1495843c0a8aSMike Christie static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, 1496843c0a8aSMike Christie struct iscsi_tm *hdr) 1497843c0a8aSMike Christie { 1498843c0a8aSMike Christie memset(hdr, 0, sizeof(*hdr)); 1499843c0a8aSMike Christie hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 1500843c0a8aSMike Christie hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; 1501843c0a8aSMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1502843c0a8aSMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 1503843c0a8aSMike Christie hdr->rtt = ctask->hdr->itt; 1504843c0a8aSMike Christie hdr->refcmdsn = ctask->hdr->cmdsn; 1505843c0a8aSMike Christie } 1506843c0a8aSMike Christie 15077996a778SMike Christie int iscsi_eh_abort(struct scsi_cmnd *sc) 15087996a778SMike Christie { 150975613521SMike Christie struct iscsi_cls_session *cls_session; 151075613521SMike Christie struct iscsi_session *session; 1511f47f2cf5SMike Christie struct iscsi_conn *conn; 1512843c0a8aSMike Christie struct iscsi_cmd_task *ctask; 1513843c0a8aSMike Christie struct iscsi_tm *hdr; 1514843c0a8aSMike Christie int rc, age; 15157996a778SMike Christie 151675613521SMike Christie cls_session = starget_to_session(scsi_target(sc->device)); 151775613521SMike Christie session = cls_session->dd_data; 151875613521SMike Christie 15196724add1SMike Christie mutex_lock(&session->eh_mutex); 15206724add1SMike Christie spin_lock_bh(&session->lock); 1521f47f2cf5SMike Christie /* 1522f47f2cf5SMike Christie * if session was ISCSI_STATE_IN_RECOVERY then we may not have 1523f47f2cf5SMike Christie * got the command. 1524f47f2cf5SMike Christie */ 1525f47f2cf5SMike Christie if (!sc->SCp.ptr) { 1526f47f2cf5SMike Christie debug_scsi("sc never reached iscsi layer or it completed.\n"); 15276724add1SMike Christie spin_unlock_bh(&session->lock); 15286724add1SMike Christie mutex_unlock(&session->eh_mutex); 1529f47f2cf5SMike Christie return SUCCESS; 1530f47f2cf5SMike Christie } 1531f47f2cf5SMike Christie 15327996a778SMike Christie /* 15337996a778SMike Christie * If we are not logged in or we have started a new session 15347996a778SMike Christie * then let the host reset code handle this 15357996a778SMike Christie */ 1536843c0a8aSMike Christie if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN || 1537843c0a8aSMike Christie sc->SCp.phase != session->age) { 1538843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1539843c0a8aSMike Christie mutex_unlock(&session->eh_mutex); 1540843c0a8aSMike Christie return FAILED; 1541843c0a8aSMike Christie } 1542843c0a8aSMike Christie 1543843c0a8aSMike Christie conn = session->leadconn; 1544843c0a8aSMike Christie conn->eh_abort_cnt++; 1545843c0a8aSMike Christie age = session->age; 1546843c0a8aSMike Christie 1547843c0a8aSMike Christie ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; 1548843c0a8aSMike Christie debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); 15497996a778SMike Christie 15507996a778SMike Christie /* ctask completed before time out */ 15517ea8b828SMike Christie if (!ctask->sc) { 15527ea8b828SMike Christie debug_scsi("sc completed while abort in progress\n"); 155377a23c21SMike Christie goto success; 15547ea8b828SMike Christie } 15557996a778SMike Christie 155677a23c21SMike Christie if (ctask->state == ISCSI_TASK_PENDING) { 155777a23c21SMike Christie fail_command(conn, ctask, DID_ABORT << 16); 155877a23c21SMike Christie goto success; 155977a23c21SMike Christie } 15607996a778SMike Christie 1561843c0a8aSMike Christie /* only have one tmf outstanding at a time */ 1562843c0a8aSMike Christie if (conn->tmf_state != TMF_INITIAL) 15637996a778SMike Christie goto failed; 1564843c0a8aSMike Christie conn->tmf_state = TMF_QUEUED; 15657996a778SMike Christie 1566843c0a8aSMike Christie hdr = &conn->tmhdr; 1567843c0a8aSMike Christie iscsi_prep_abort_task_pdu(ctask, hdr); 1568843c0a8aSMike Christie 1569f6d5180cSMike Christie if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { 1570843c0a8aSMike Christie rc = FAILED; 1571843c0a8aSMike Christie goto failed; 1572843c0a8aSMike Christie } 1573843c0a8aSMike Christie 1574843c0a8aSMike Christie switch (conn->tmf_state) { 1575843c0a8aSMike Christie case TMF_SUCCESS: 15767ea8b828SMike Christie spin_unlock_bh(&session->lock); 15776724add1SMike Christie iscsi_suspend_tx(conn); 15787996a778SMike Christie /* 157977a23c21SMike Christie * clean up task if aborted. grab the recv lock as a writer 15807996a778SMike Christie */ 15817996a778SMike Christie write_lock_bh(conn->recv_lock); 15827996a778SMike Christie spin_lock(&session->lock); 15837996a778SMike Christie fail_command(conn, ctask, DID_ABORT << 16); 1584843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 15857996a778SMike Christie spin_unlock(&session->lock); 15867996a778SMike Christie write_unlock_bh(conn->recv_lock); 15876724add1SMike Christie iscsi_start_tx(conn); 158877a23c21SMike Christie goto success_unlocked; 1589843c0a8aSMike Christie case TMF_TIMEDOUT: 1590843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1591843c0a8aSMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1592843c0a8aSMike Christie goto failed_unlocked; 1593843c0a8aSMike Christie case TMF_NOT_FOUND: 1594843c0a8aSMike Christie if (!sc->SCp.ptr) { 1595843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 159677a23c21SMike Christie /* ctask completed before tmf abort response */ 159777a23c21SMike Christie debug_scsi("sc completed while abort in progress\n"); 159877a23c21SMike Christie goto success; 159977a23c21SMike Christie } 160077a23c21SMike Christie /* fall through */ 160177a23c21SMike Christie default: 1602843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1603843c0a8aSMike Christie goto failed; 160477a23c21SMike Christie } 16057996a778SMike Christie 160677a23c21SMike Christie success: 160777a23c21SMike Christie spin_unlock_bh(&session->lock); 160877a23c21SMike Christie success_unlocked: 160977a23c21SMike Christie debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 16106724add1SMike Christie mutex_unlock(&session->eh_mutex); 16117996a778SMike Christie return SUCCESS; 16127996a778SMike Christie 16137996a778SMike Christie failed: 16147996a778SMike Christie spin_unlock_bh(&session->lock); 161577a23c21SMike Christie failed_unlocked: 1616843c0a8aSMike Christie debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, 1617843c0a8aSMike Christie ctask ? ctask->itt : 0); 16186724add1SMike Christie mutex_unlock(&session->eh_mutex); 16197996a778SMike Christie return FAILED; 16207996a778SMike Christie } 16217996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_abort); 16227996a778SMike Christie 1623843c0a8aSMike Christie static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) 1624843c0a8aSMike Christie { 1625843c0a8aSMike Christie memset(hdr, 0, sizeof(*hdr)); 1626843c0a8aSMike Christie hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 1627843c0a8aSMike Christie hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; 1628843c0a8aSMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1629843c0a8aSMike Christie int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 1630f6d5180cSMike Christie hdr->rtt = RESERVED_ITT; 1631843c0a8aSMike Christie } 1632843c0a8aSMike Christie 1633843c0a8aSMike Christie int iscsi_eh_device_reset(struct scsi_cmnd *sc) 1634843c0a8aSMike Christie { 163575613521SMike Christie struct iscsi_cls_session *cls_session; 163675613521SMike Christie struct iscsi_session *session; 1637843c0a8aSMike Christie struct iscsi_conn *conn; 1638843c0a8aSMike Christie struct iscsi_tm *hdr; 1639843c0a8aSMike Christie int rc = FAILED; 1640843c0a8aSMike Christie 164175613521SMike Christie cls_session = starget_to_session(scsi_target(sc->device)); 164275613521SMike Christie session = cls_session->dd_data; 164375613521SMike Christie 1644843c0a8aSMike Christie debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); 1645843c0a8aSMike Christie 1646843c0a8aSMike Christie mutex_lock(&session->eh_mutex); 1647843c0a8aSMike Christie spin_lock_bh(&session->lock); 1648843c0a8aSMike Christie /* 1649843c0a8aSMike Christie * Just check if we are not logged in. We cannot check for 1650843c0a8aSMike Christie * the phase because the reset could come from a ioctl. 1651843c0a8aSMike Christie */ 1652843c0a8aSMike Christie if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) 1653843c0a8aSMike Christie goto unlock; 1654843c0a8aSMike Christie conn = session->leadconn; 1655843c0a8aSMike Christie 1656843c0a8aSMike Christie /* only have one tmf outstanding at a time */ 1657843c0a8aSMike Christie if (conn->tmf_state != TMF_INITIAL) 1658843c0a8aSMike Christie goto unlock; 1659843c0a8aSMike Christie conn->tmf_state = TMF_QUEUED; 1660843c0a8aSMike Christie 1661843c0a8aSMike Christie hdr = &conn->tmhdr; 1662843c0a8aSMike Christie iscsi_prep_lun_reset_pdu(sc, hdr); 1663843c0a8aSMike Christie 1664f6d5180cSMike Christie if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, 1665f6d5180cSMike Christie session->lu_reset_timeout)) { 1666843c0a8aSMike Christie rc = FAILED; 1667843c0a8aSMike Christie goto unlock; 1668843c0a8aSMike Christie } 1669843c0a8aSMike Christie 1670843c0a8aSMike Christie switch (conn->tmf_state) { 1671843c0a8aSMike Christie case TMF_SUCCESS: 1672843c0a8aSMike Christie break; 1673843c0a8aSMike Christie case TMF_TIMEDOUT: 1674843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1675843c0a8aSMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1676843c0a8aSMike Christie goto done; 1677843c0a8aSMike Christie default: 1678843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1679843c0a8aSMike Christie goto unlock; 1680843c0a8aSMike Christie } 1681843c0a8aSMike Christie 1682843c0a8aSMike Christie rc = SUCCESS; 1683843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1684843c0a8aSMike Christie 1685843c0a8aSMike Christie iscsi_suspend_tx(conn); 1686843c0a8aSMike Christie /* need to grab the recv lock then session lock */ 1687843c0a8aSMike Christie write_lock_bh(conn->recv_lock); 1688843c0a8aSMike Christie spin_lock(&session->lock); 16896eabafbeSMike Christie fail_all_commands(conn, sc->device->lun, DID_ERROR); 1690843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1691843c0a8aSMike Christie spin_unlock(&session->lock); 1692843c0a8aSMike Christie write_unlock_bh(conn->recv_lock); 1693843c0a8aSMike Christie 1694843c0a8aSMike Christie iscsi_start_tx(conn); 1695843c0a8aSMike Christie goto done; 1696843c0a8aSMike Christie 1697843c0a8aSMike Christie unlock: 1698843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1699843c0a8aSMike Christie done: 1700843c0a8aSMike Christie debug_scsi("iscsi_eh_device_reset %s\n", 1701843c0a8aSMike Christie rc == SUCCESS ? "SUCCESS" : "FAILED"); 1702843c0a8aSMike Christie mutex_unlock(&session->eh_mutex); 1703843c0a8aSMike Christie return rc; 1704843c0a8aSMike Christie } 1705843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); 1706843c0a8aSMike Christie 17076320377fSOlaf Kirch /* 17086320377fSOlaf Kirch * Pre-allocate a pool of @max items of @item_size. By default, the pool 17096320377fSOlaf Kirch * should be accessed via kfifo_{get,put} on q->queue. 17106320377fSOlaf Kirch * Optionally, the caller can obtain the array of object pointers 17116320377fSOlaf Kirch * by passing in a non-NULL @items pointer 17126320377fSOlaf Kirch */ 17137996a778SMike Christie int 17146320377fSOlaf Kirch iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) 17157996a778SMike Christie { 17166320377fSOlaf Kirch int i, num_arrays = 1; 17177996a778SMike Christie 17186320377fSOlaf Kirch memset(q, 0, sizeof(*q)); 17197996a778SMike Christie 17207996a778SMike Christie q->max = max; 17216320377fSOlaf Kirch 17226320377fSOlaf Kirch /* If the user passed an items pointer, he wants a copy of 17236320377fSOlaf Kirch * the array. */ 17246320377fSOlaf Kirch if (items) 17256320377fSOlaf Kirch num_arrays++; 17266320377fSOlaf Kirch q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL); 17276320377fSOlaf Kirch if (q->pool == NULL) 17286320377fSOlaf Kirch goto enomem; 17297996a778SMike Christie 17307996a778SMike Christie q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), 17317996a778SMike Christie GFP_KERNEL, NULL); 17326320377fSOlaf Kirch if (q->queue == ERR_PTR(-ENOMEM)) 17336320377fSOlaf Kirch goto enomem; 17347996a778SMike Christie 17357996a778SMike Christie for (i = 0; i < max; i++) { 17366320377fSOlaf Kirch q->pool[i] = kzalloc(item_size, GFP_KERNEL); 17377996a778SMike Christie if (q->pool[i] == NULL) { 17386320377fSOlaf Kirch q->max = i; 17396320377fSOlaf Kirch goto enomem; 17407996a778SMike Christie } 17417996a778SMike Christie __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*)); 17427996a778SMike Christie } 17436320377fSOlaf Kirch 17446320377fSOlaf Kirch if (items) { 17456320377fSOlaf Kirch *items = q->pool + max; 17466320377fSOlaf Kirch memcpy(*items, q->pool, max * sizeof(void *)); 17476320377fSOlaf Kirch } 17486320377fSOlaf Kirch 17497996a778SMike Christie return 0; 17506320377fSOlaf Kirch 17516320377fSOlaf Kirch enomem: 17526320377fSOlaf Kirch iscsi_pool_free(q); 17536320377fSOlaf Kirch return -ENOMEM; 17547996a778SMike Christie } 17557996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_init); 17567996a778SMike Christie 17576320377fSOlaf Kirch void iscsi_pool_free(struct iscsi_pool *q) 17587996a778SMike Christie { 17597996a778SMike Christie int i; 17607996a778SMike Christie 17617996a778SMike Christie for (i = 0; i < q->max; i++) 17626320377fSOlaf Kirch kfree(q->pool[i]); 17636320377fSOlaf Kirch if (q->pool) 17647996a778SMike Christie kfree(q->pool); 17657996a778SMike Christie } 17667996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_free); 17677996a778SMike Christie 1768a4804cd6SMike Christie /** 1769a4804cd6SMike Christie * iscsi_host_add - add host to system 1770a4804cd6SMike Christie * @shost: scsi host 1771a4804cd6SMike Christie * @pdev: parent device 1772a4804cd6SMike Christie * 1773a4804cd6SMike Christie * This should be called by partial offload and software iscsi drivers 1774a4804cd6SMike Christie * to add a host to the system. 1775a4804cd6SMike Christie */ 1776a4804cd6SMike Christie int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev) 17777996a778SMike Christie { 1778a4804cd6SMike Christie return scsi_add_host(shost, pdev); 1779a4804cd6SMike Christie } 1780a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_add); 1781a4804cd6SMike Christie 1782a4804cd6SMike Christie /** 1783a4804cd6SMike Christie * iscsi_host_alloc - allocate a host and driver data 1784a4804cd6SMike Christie * @sht: scsi host template 1785a4804cd6SMike Christie * @dd_data_size: driver host data size 1786a4804cd6SMike Christie * @qdepth: default device queue depth 1787a4804cd6SMike Christie * 1788a4804cd6SMike Christie * This should be called by partial offload and software iscsi drivers. 1789a4804cd6SMike Christie * To access the driver specific memory use the iscsi_host_priv() macro. 1790a4804cd6SMike Christie */ 1791a4804cd6SMike Christie struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, 1792a4804cd6SMike Christie int dd_data_size, uint16_t qdepth) 1793a4804cd6SMike Christie { 1794a4804cd6SMike Christie struct Scsi_Host *shost; 1795a4804cd6SMike Christie 1796a4804cd6SMike Christie shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); 1797a4804cd6SMike Christie if (!shost) 1798a4804cd6SMike Christie return NULL; 1799a4804cd6SMike Christie shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; 1800a4804cd6SMike Christie 18011548271eSMike Christie if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { 18021548271eSMike Christie if (qdepth != 0) 18031548271eSMike Christie printk(KERN_ERR "iscsi: invalid queue depth of %d. " 18041548271eSMike Christie "Queue depth must be between 1 and %d.\n", 18051548271eSMike Christie qdepth, ISCSI_MAX_CMD_PER_LUN); 18061548271eSMike Christie qdepth = ISCSI_DEF_CMD_PER_LUN; 18071548271eSMike Christie } 180875613521SMike Christie shost->cmd_per_lun = qdepth; 1809a4804cd6SMike Christie return shost; 181075613521SMike Christie } 1811a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_alloc); 181275613521SMike Christie 1813a4804cd6SMike Christie /** 1814a4804cd6SMike Christie * iscsi_host_remove - remove host and sessions 1815a4804cd6SMike Christie * @shost: scsi host 1816a4804cd6SMike Christie * 1817a4804cd6SMike Christie * This will also remove any sessions attached to the host, but if userspace 1818a4804cd6SMike Christie * is managing the session at the same time this will break. TODO: add 1819a4804cd6SMike Christie * refcounting to the netlink iscsi interface so a rmmod or host hot unplug 1820a4804cd6SMike Christie * does not remove the memory from under us. 1821a4804cd6SMike Christie */ 1822a4804cd6SMike Christie void iscsi_host_remove(struct Scsi_Host *shost) 1823a4804cd6SMike Christie { 1824a4804cd6SMike Christie iscsi_host_for_each_session(shost, iscsi_session_teardown); 1825a4804cd6SMike Christie scsi_remove_host(shost); 1826a4804cd6SMike Christie } 1827a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_remove); 1828a4804cd6SMike Christie 1829a4804cd6SMike Christie void iscsi_host_free(struct Scsi_Host *shost) 183075613521SMike Christie { 183175613521SMike Christie struct iscsi_host *ihost = shost_priv(shost); 183275613521SMike Christie 183375613521SMike Christie kfree(ihost->netdev); 183475613521SMike Christie kfree(ihost->hwaddress); 183575613521SMike Christie kfree(ihost->initiatorname); 1836a4804cd6SMike Christie scsi_host_put(shost); 183775613521SMike Christie } 1838a4804cd6SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_free); 183975613521SMike Christie 184075613521SMike Christie /** 184175613521SMike Christie * iscsi_session_setup - create iscsi cls session and host and session 184275613521SMike Christie * @iscsit: iscsi transport template 184375613521SMike Christie * @shost: scsi host 184475613521SMike Christie * @cmds_max: session can queue 184575613521SMike Christie * @cmd_task_size: LLD ctask private data size 184675613521SMike Christie * @mgmt_task_size: LLD mtask private data size 184775613521SMike Christie * @initial_cmdsn: initial CmdSN 184875613521SMike Christie * 184975613521SMike Christie * This can be used by software iscsi_transports that allocate 185075613521SMike Christie * a session per scsi host. 185175613521SMike Christie */ 185275613521SMike Christie struct iscsi_cls_session * 185375613521SMike Christie iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, 185475613521SMike Christie uint16_t cmds_max, int cmd_task_size, int mgmt_task_size, 185575613521SMike Christie uint32_t initial_cmdsn) 185675613521SMike Christie { 185775613521SMike Christie struct iscsi_session *session; 185875613521SMike Christie struct iscsi_cls_session *cls_session; 185975613521SMike Christie int cmd_i; 186075613521SMike Christie 186131ed0bf4SMike Christie if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || 186231ed0bf4SMike Christie cmds_max < 2) { 18631548271eSMike Christie if (cmds_max != 0) 18641548271eSMike Christie printk(KERN_ERR "iscsi: invalid can_queue of %d. " 18651548271eSMike Christie "can_queue must be a power of 2 and between " 18661548271eSMike Christie "2 and %d - setting to %d.\n", cmds_max, 18671548271eSMike Christie ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX); 18681548271eSMike Christie cmds_max = ISCSI_DEF_XMIT_CMDS_MAX; 18691548271eSMike Christie } 18701548271eSMike Christie 18715d91e209SMike Christie cls_session = iscsi_alloc_session(shost, iscsit, 18725d91e209SMike Christie sizeof(struct iscsi_session)); 187375613521SMike Christie if (!cls_session) 18747996a778SMike Christie return NULL; 187575613521SMike Christie session = cls_session->dd_data; 187675613521SMike Christie session->cls_session = cls_session; 18777996a778SMike Christie session->host = shost; 18787996a778SMike Christie session->state = ISCSI_STATE_FREE; 1879f6d5180cSMike Christie session->fast_abort = 1; 18804cd49ea1SMike Christie session->lu_reset_timeout = 15; 18814cd49ea1SMike Christie session->abort_timeout = 10; 18827996a778SMike Christie session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; 18831548271eSMike Christie session->cmds_max = cmds_max; 1884e0726407SMike Christie session->queued_cmdsn = session->cmdsn = initial_cmdsn; 18857996a778SMike Christie session->exp_cmdsn = initial_cmdsn + 1; 18867996a778SMike Christie session->max_cmdsn = initial_cmdsn + 1; 18877996a778SMike Christie session->max_r2t = 1; 18887996a778SMike Christie session->tt = iscsit; 18896724add1SMike Christie mutex_init(&session->eh_mutex); 189075613521SMike Christie spin_lock_init(&session->lock); 18917996a778SMike Christie 18927996a778SMike Christie /* initialize SCSI PDU commands pool */ 18937996a778SMike Christie if (iscsi_pool_init(&session->cmdpool, session->cmds_max, 18947996a778SMike Christie (void***)&session->cmds, 18957996a778SMike Christie cmd_task_size + sizeof(struct iscsi_cmd_task))) 18967996a778SMike Christie goto cmdpool_alloc_fail; 18977996a778SMike Christie 18987996a778SMike Christie /* pre-format cmds pool with ITT */ 18997996a778SMike Christie for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { 19007996a778SMike Christie struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; 19017996a778SMike Christie 19027996a778SMike Christie if (cmd_task_size) 19037996a778SMike Christie ctask->dd_data = &ctask[1]; 19047996a778SMike Christie ctask->itt = cmd_i; 1905b6c395edSMike Christie INIT_LIST_HEAD(&ctask->running); 19067996a778SMike Christie } 19077996a778SMike Christie 19087996a778SMike Christie /* initialize immediate command pool */ 19097996a778SMike Christie if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, 19107996a778SMike Christie (void***)&session->mgmt_cmds, 19117996a778SMike Christie mgmt_task_size + sizeof(struct iscsi_mgmt_task))) 19127996a778SMike Christie goto mgmtpool_alloc_fail; 19137996a778SMike Christie 19147996a778SMike Christie 19157996a778SMike Christie /* pre-format immediate cmds pool with ITT */ 19167996a778SMike Christie for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { 19177996a778SMike Christie struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; 19187996a778SMike Christie 19197996a778SMike Christie if (mgmt_task_size) 19207996a778SMike Christie mtask->dd_data = &mtask[1]; 19217996a778SMike Christie mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; 1922b6c395edSMike Christie INIT_LIST_HEAD(&mtask->running); 19237996a778SMike Christie } 19247996a778SMike Christie 1925f53a88daSMike Christie if (!try_module_get(iscsit->owner)) 192675613521SMike Christie goto module_get_fail; 192775613521SMike Christie 192875613521SMike Christie if (iscsi_add_session(cls_session, 0)) 1929f53a88daSMike Christie goto cls_session_fail; 19307996a778SMike Christie return cls_session; 19317996a778SMike Christie 19327996a778SMike Christie cls_session_fail: 193375613521SMike Christie module_put(iscsit->owner); 193475613521SMike Christie module_get_fail: 19356320377fSOlaf Kirch iscsi_pool_free(&session->mgmtpool); 19367996a778SMike Christie mgmtpool_alloc_fail: 19376320377fSOlaf Kirch iscsi_pool_free(&session->cmdpool); 19387996a778SMike Christie cmdpool_alloc_fail: 193975613521SMike Christie iscsi_free_session(cls_session); 19407996a778SMike Christie return NULL; 19417996a778SMike Christie } 19427996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_setup); 19437996a778SMike Christie 19447996a778SMike Christie /** 19457996a778SMike Christie * iscsi_session_teardown - destroy session, host, and cls_session 194675613521SMike Christie * @cls_session: iscsi session 19477996a778SMike Christie * 194875613521SMike Christie * The driver must have called iscsi_remove_session before 194975613521SMike Christie * calling this. 195075613521SMike Christie */ 19517996a778SMike Christie void iscsi_session_teardown(struct iscsi_cls_session *cls_session) 19527996a778SMike Christie { 195375613521SMike Christie struct iscsi_session *session = cls_session->dd_data; 195463f75cc8SMike Christie struct module *owner = cls_session->transport->owner; 19557996a778SMike Christie 19566320377fSOlaf Kirch iscsi_pool_free(&session->mgmtpool); 19576320377fSOlaf Kirch iscsi_pool_free(&session->cmdpool); 19587996a778SMike Christie 1959b2c64167SMike Christie kfree(session->password); 1960b2c64167SMike Christie kfree(session->password_in); 1961b2c64167SMike Christie kfree(session->username); 1962b2c64167SMike Christie kfree(session->username_in); 1963f3ff0c36SMike Christie kfree(session->targetname); 1964f3ff0c36SMike Christie 196575613521SMike Christie iscsi_destroy_session(cls_session); 196663f75cc8SMike Christie module_put(owner); 19677996a778SMike Christie } 19687996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_teardown); 19697996a778SMike Christie 19707996a778SMike Christie /** 19717996a778SMike Christie * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn 19727996a778SMike Christie * @cls_session: iscsi_cls_session 19735d91e209SMike Christie * @dd_size: private driver data size 19747996a778SMike Christie * @conn_idx: cid 19755d91e209SMike Christie */ 19767996a778SMike Christie struct iscsi_cls_conn * 19775d91e209SMike Christie iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, 19785d91e209SMike Christie uint32_t conn_idx) 19797996a778SMike Christie { 198075613521SMike Christie struct iscsi_session *session = cls_session->dd_data; 19817996a778SMike Christie struct iscsi_conn *conn; 19827996a778SMike Christie struct iscsi_cls_conn *cls_conn; 1983d36ab6f3SMike Christie char *data; 19847996a778SMike Christie 19855d91e209SMike Christie cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size, 19865d91e209SMike Christie conn_idx); 19877996a778SMike Christie if (!cls_conn) 19887996a778SMike Christie return NULL; 19897996a778SMike Christie conn = cls_conn->dd_data; 19905d91e209SMike Christie memset(conn, 0, sizeof(*conn) + dd_size); 19917996a778SMike Christie 19925d91e209SMike Christie conn->dd_data = cls_conn->dd_data + sizeof(*conn); 19937996a778SMike Christie conn->session = session; 19947996a778SMike Christie conn->cls_conn = cls_conn; 19957996a778SMike Christie conn->c_stage = ISCSI_CONN_INITIAL_STAGE; 19967996a778SMike Christie conn->id = conn_idx; 19977996a778SMike Christie conn->exp_statsn = 0; 1998843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1999f6d5180cSMike Christie 2000f6d5180cSMike Christie init_timer(&conn->transport_timer); 2001f6d5180cSMike Christie conn->transport_timer.data = (unsigned long)conn; 2002f6d5180cSMike Christie conn->transport_timer.function = iscsi_check_transport_timeouts; 2003f6d5180cSMike Christie 20047996a778SMike Christie INIT_LIST_HEAD(&conn->run_list); 20057996a778SMike Christie INIT_LIST_HEAD(&conn->mgmt_run_list); 2006843c0a8aSMike Christie INIT_LIST_HEAD(&conn->mgmtqueue); 2007b6c395edSMike Christie INIT_LIST_HEAD(&conn->xmitqueue); 2008843c0a8aSMike Christie INIT_LIST_HEAD(&conn->requeue); 2009c4028958SDavid Howells INIT_WORK(&conn->xmitwork, iscsi_xmitworker); 20107996a778SMike Christie 20117996a778SMike Christie /* allocate login_mtask used for the login/text sequences */ 20127996a778SMike Christie spin_lock_bh(&session->lock); 20137996a778SMike Christie if (!__kfifo_get(session->mgmtpool.queue, 20147996a778SMike Christie (void*)&conn->login_mtask, 20157996a778SMike Christie sizeof(void*))) { 20167996a778SMike Christie spin_unlock_bh(&session->lock); 20177996a778SMike Christie goto login_mtask_alloc_fail; 20187996a778SMike Christie } 20197996a778SMike Christie spin_unlock_bh(&session->lock); 20207996a778SMike Christie 2021bf32ed33SMike Christie data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); 2022d36ab6f3SMike Christie if (!data) 2023d36ab6f3SMike Christie goto login_mtask_data_alloc_fail; 2024c8dc1e52SMike Christie conn->login_mtask->data = conn->data = data; 2025d36ab6f3SMike Christie 2026843c0a8aSMike Christie init_timer(&conn->tmf_timer); 20277996a778SMike Christie init_waitqueue_head(&conn->ehwait); 20287996a778SMike Christie 20297996a778SMike Christie return cls_conn; 20307996a778SMike Christie 2031d36ab6f3SMike Christie login_mtask_data_alloc_fail: 2032d36ab6f3SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 2033d36ab6f3SMike Christie sizeof(void*)); 20347996a778SMike Christie login_mtask_alloc_fail: 20357996a778SMike Christie iscsi_destroy_conn(cls_conn); 20367996a778SMike Christie return NULL; 20377996a778SMike Christie } 20387996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_setup); 20397996a778SMike Christie 20407996a778SMike Christie /** 20417996a778SMike Christie * iscsi_conn_teardown - teardown iscsi connection 20427996a778SMike Christie * cls_conn: iscsi class connection 20437996a778SMike Christie * 20447996a778SMike Christie * TODO: we may need to make this into a two step process 20457996a778SMike Christie * like scsi-mls remove + put host 20467996a778SMike Christie */ 20477996a778SMike Christie void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) 20487996a778SMike Christie { 20497996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 20507996a778SMike Christie struct iscsi_session *session = conn->session; 20517996a778SMike Christie unsigned long flags; 20527996a778SMike Christie 2053f6d5180cSMike Christie del_timer_sync(&conn->transport_timer); 2054f6d5180cSMike Christie 20557996a778SMike Christie spin_lock_bh(&session->lock); 20567996a778SMike Christie conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; 20577996a778SMike Christie if (session->leadconn == conn) { 20587996a778SMike Christie /* 20597996a778SMike Christie * leading connection? then give up on recovery. 20607996a778SMike Christie */ 20617996a778SMike Christie session->state = ISCSI_STATE_TERMINATE; 20627996a778SMike Christie wake_up(&conn->ehwait); 20637996a778SMike Christie } 20647996a778SMike Christie spin_unlock_bh(&session->lock); 20657996a778SMike Christie 20667996a778SMike Christie /* 20677996a778SMike Christie * Block until all in-progress commands for this connection 20687996a778SMike Christie * time out or fail. 20697996a778SMike Christie */ 20707996a778SMike Christie for (;;) { 20717996a778SMike Christie spin_lock_irqsave(session->host->host_lock, flags); 20727996a778SMike Christie if (!session->host->host_busy) { /* OK for ERL == 0 */ 20737996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 20747996a778SMike Christie break; 20757996a778SMike Christie } 20767996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 20777996a778SMike Christie msleep_interruptible(500); 2078322d739dSMike Christie iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " 2079322d739dSMike Christie "host_busy %d host_failed %d\n", 2080322d739dSMike Christie session->host->host_busy, 2081be2df72eSOr Gerlitz session->host->host_failed); 20827996a778SMike Christie /* 20837996a778SMike Christie * force eh_abort() to unblock 20847996a778SMike Christie */ 20857996a778SMike Christie wake_up(&conn->ehwait); 20867996a778SMike Christie } 20877996a778SMike Christie 2088779ea120SMike Christie /* flush queued up work because we free the connection below */ 2089843c0a8aSMike Christie iscsi_suspend_tx(conn); 2090779ea120SMike Christie 20917996a778SMike Christie spin_lock_bh(&session->lock); 2092c8dc1e52SMike Christie kfree(conn->data); 2093f3ff0c36SMike Christie kfree(conn->persistent_address); 20947996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 20957996a778SMike Christie sizeof(void*)); 2096e0726407SMike Christie if (session->leadconn == conn) 20977996a778SMike Christie session->leadconn = NULL; 20987996a778SMike Christie spin_unlock_bh(&session->lock); 20997996a778SMike Christie 21007996a778SMike Christie iscsi_destroy_conn(cls_conn); 21017996a778SMike Christie } 21027996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_teardown); 21037996a778SMike Christie 21047996a778SMike Christie int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) 21057996a778SMike Christie { 21067996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 21077996a778SMike Christie struct iscsi_session *session = conn->session; 21087996a778SMike Christie 2109ffd0436eSMike Christie if (!session) { 2110322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 2111322d739dSMike Christie "can't start unbound connection\n"); 21127996a778SMike Christie return -EPERM; 21137996a778SMike Christie } 21147996a778SMike Christie 2115db98ccdeSMike Christie if ((session->imm_data_en || !session->initial_r2t_en) && 2116db98ccdeSMike Christie session->first_burst > session->max_burst) { 2117322d739dSMike Christie iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " 2118ffd0436eSMike Christie "first_burst %d max_burst %d\n", 2119ffd0436eSMike Christie session->first_burst, session->max_burst); 2120ffd0436eSMike Christie return -EINVAL; 2121ffd0436eSMike Christie } 2122ffd0436eSMike Christie 2123f6d5180cSMike Christie if (conn->ping_timeout && !conn->recv_timeout) { 2124322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " 2125322d739dSMike Christie "zero. Using 5 seconds\n."); 2126f6d5180cSMike Christie conn->recv_timeout = 5; 2127f6d5180cSMike Christie } 2128f6d5180cSMike Christie 2129f6d5180cSMike Christie if (conn->recv_timeout && !conn->ping_timeout) { 2130322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " 2131322d739dSMike Christie "zero. Using 5 seconds.\n"); 2132f6d5180cSMike Christie conn->ping_timeout = 5; 2133f6d5180cSMike Christie } 2134f6d5180cSMike Christie 21357996a778SMike Christie spin_lock_bh(&session->lock); 21367996a778SMike Christie conn->c_stage = ISCSI_CONN_STARTED; 21377996a778SMike Christie session->state = ISCSI_STATE_LOGGED_IN; 2138e0726407SMike Christie session->queued_cmdsn = session->cmdsn; 21397996a778SMike Christie 2140f6d5180cSMike Christie conn->last_recv = jiffies; 2141f6d5180cSMike Christie conn->last_ping = jiffies; 2142f6d5180cSMike Christie if (conn->recv_timeout && conn->ping_timeout) 2143f6d5180cSMike Christie mod_timer(&conn->transport_timer, 2144f6d5180cSMike Christie jiffies + (conn->recv_timeout * HZ)); 2145f6d5180cSMike Christie 21467996a778SMike Christie switch(conn->stop_stage) { 21477996a778SMike Christie case STOP_CONN_RECOVER: 21487996a778SMike Christie /* 21497996a778SMike Christie * unblock eh_abort() if it is blocked. re-try all 21507996a778SMike Christie * commands after successful recovery 21517996a778SMike Christie */ 21527996a778SMike Christie conn->stop_stage = 0; 2153843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 21547996a778SMike Christie session->age++; 21558b1d0343SMike Christie if (session->age == 16) 21568b1d0343SMike Christie session->age = 0; 21576eabafbeSMike Christie break; 21587996a778SMike Christie case STOP_CONN_TERM: 21597996a778SMike Christie conn->stop_stage = 0; 21607996a778SMike Christie break; 21617996a778SMike Christie default: 21627996a778SMike Christie break; 21637996a778SMike Christie } 21647996a778SMike Christie spin_unlock_bh(&session->lock); 21657996a778SMike Christie 216675613521SMike Christie iscsi_unblock_session(session->cls_session); 21676eabafbeSMike Christie wake_up(&conn->ehwait); 21687996a778SMike Christie return 0; 21697996a778SMike Christie } 21707996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_start); 21717996a778SMike Christie 21727996a778SMike Christie static void 21737996a778SMike Christie flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) 21747996a778SMike Christie { 21757996a778SMike Christie struct iscsi_mgmt_task *mtask, *tmp; 21767996a778SMike Christie 21777996a778SMike Christie /* handle pending */ 2178843c0a8aSMike Christie list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { 2179843c0a8aSMike Christie debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); 2180b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, mtask); 21817996a778SMike Christie } 21827996a778SMike Christie 21837996a778SMike Christie /* handle running */ 21847996a778SMike Christie list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { 21857996a778SMike Christie debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); 2186b3a7ea8dSMike Christie iscsi_free_mgmt_task(conn, mtask); 21877996a778SMike Christie } 21887996a778SMike Christie 21897996a778SMike Christie conn->mtask = NULL; 21907996a778SMike Christie } 21917996a778SMike Christie 2192656cffc9SMike Christie static void iscsi_start_session_recovery(struct iscsi_session *session, 21937996a778SMike Christie struct iscsi_conn *conn, int flag) 21947996a778SMike Christie { 2195ed2abc7fSMike Christie int old_stop_stage; 2196ed2abc7fSMike Christie 2197f6d5180cSMike Christie del_timer_sync(&conn->transport_timer); 2198f6d5180cSMike Christie 21996724add1SMike Christie mutex_lock(&session->eh_mutex); 22007996a778SMike Christie spin_lock_bh(&session->lock); 2201ed2abc7fSMike Christie if (conn->stop_stage == STOP_CONN_TERM) { 22027996a778SMike Christie spin_unlock_bh(&session->lock); 22036724add1SMike Christie mutex_unlock(&session->eh_mutex); 22046724add1SMike Christie return; 22056724add1SMike Christie } 22066724add1SMike Christie 22076724add1SMike Christie /* 22086724add1SMike Christie * The LLD either freed/unset the lock on us, or userspace called 22096724add1SMike Christie * stop but did not create a proper connection (connection was never 22106724add1SMike Christie * bound or it was unbound then stop was called). 22116724add1SMike Christie */ 22126724add1SMike Christie if (!conn->recv_lock) { 22136724add1SMike Christie spin_unlock_bh(&session->lock); 22146724add1SMike Christie mutex_unlock(&session->eh_mutex); 22157996a778SMike Christie return; 22167996a778SMike Christie } 2217ed2abc7fSMike Christie 2218ed2abc7fSMike Christie /* 2219ed2abc7fSMike Christie * When this is called for the in_login state, we only want to clean 222067a61114SMike Christie * up the login task and connection. We do not need to block and set 222167a61114SMike Christie * the recovery state again 2222ed2abc7fSMike Christie */ 222367a61114SMike Christie if (flag == STOP_CONN_TERM) 222467a61114SMike Christie session->state = ISCSI_STATE_TERMINATE; 222567a61114SMike Christie else if (conn->stop_stage != STOP_CONN_RECOVER) 222667a61114SMike Christie session->state = ISCSI_STATE_IN_RECOVERY; 2227ed2abc7fSMike Christie 2228ed2abc7fSMike Christie old_stop_stage = conn->stop_stage; 22297996a778SMike Christie conn->stop_stage = flag; 223067a61114SMike Christie conn->c_stage = ISCSI_CONN_STOPPED; 22317996a778SMike Christie spin_unlock_bh(&session->lock); 22326724add1SMike Christie 22336724add1SMike Christie iscsi_suspend_tx(conn); 22347996a778SMike Christie 22351c83469dSMike Christie write_lock_bh(conn->recv_lock); 22361c83469dSMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 22371c83469dSMike Christie write_unlock_bh(conn->recv_lock); 22387996a778SMike Christie 22397996a778SMike Christie /* 22407996a778SMike Christie * for connection level recovery we should not calculate 22417996a778SMike Christie * header digest. conn->hdr_size used for optimization 22427996a778SMike Christie * in hdr_extract() and will be re-negotiated at 22437996a778SMike Christie * set_param() time. 22447996a778SMike Christie */ 22457996a778SMike Christie if (flag == STOP_CONN_RECOVER) { 22467996a778SMike Christie conn->hdrdgst_en = 0; 22477996a778SMike Christie conn->datadgst_en = 0; 2248656cffc9SMike Christie if (session->state == ISCSI_STATE_IN_RECOVERY && 224967a61114SMike Christie old_stop_stage != STOP_CONN_RECOVER) { 225067a61114SMike Christie debug_scsi("blocking session\n"); 225175613521SMike Christie iscsi_block_session(session->cls_session); 22527996a778SMike Christie } 225367a61114SMike Christie } 2254656cffc9SMike Christie 2255656cffc9SMike Christie /* 2256656cffc9SMike Christie * flush queues. 2257656cffc9SMike Christie */ 2258656cffc9SMike Christie spin_lock_bh(&session->lock); 22596eabafbeSMike Christie fail_all_commands(conn, -1, 22606eabafbeSMike Christie STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); 2261656cffc9SMike Christie flush_control_queues(session, conn); 2262656cffc9SMike Christie spin_unlock_bh(&session->lock); 22636724add1SMike Christie mutex_unlock(&session->eh_mutex); 22647996a778SMike Christie } 22657996a778SMike Christie 22667996a778SMike Christie void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 22677996a778SMike Christie { 22687996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 22697996a778SMike Christie struct iscsi_session *session = conn->session; 22707996a778SMike Christie 22717996a778SMike Christie switch (flag) { 22727996a778SMike Christie case STOP_CONN_RECOVER: 22737996a778SMike Christie case STOP_CONN_TERM: 22747996a778SMike Christie iscsi_start_session_recovery(session, conn, flag); 22758d2860b3SMike Christie break; 22767996a778SMike Christie default: 2277322d739dSMike Christie iscsi_conn_printk(KERN_ERR, conn, 2278322d739dSMike Christie "invalid stop flag %d\n", flag); 22797996a778SMike Christie } 22807996a778SMike Christie } 22817996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_stop); 22827996a778SMike Christie 22837996a778SMike Christie int iscsi_conn_bind(struct iscsi_cls_session *cls_session, 22847996a778SMike Christie struct iscsi_cls_conn *cls_conn, int is_leading) 22857996a778SMike Christie { 228675613521SMike Christie struct iscsi_session *session = cls_session->dd_data; 228798644047SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 22887996a778SMike Christie 22897996a778SMike Christie spin_lock_bh(&session->lock); 22907996a778SMike Christie if (is_leading) 22917996a778SMike Christie session->leadconn = conn; 229298644047SMike Christie spin_unlock_bh(&session->lock); 22937996a778SMike Christie 22947996a778SMike Christie /* 22957996a778SMike Christie * Unblock xmitworker(), Login Phase will pass through. 22967996a778SMike Christie */ 22977996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 22987996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 22997996a778SMike Christie return 0; 23007996a778SMike Christie } 23017996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_bind); 23027996a778SMike Christie 2303a54a52caSMike Christie 2304a54a52caSMike Christie int iscsi_set_param(struct iscsi_cls_conn *cls_conn, 2305a54a52caSMike Christie enum iscsi_param param, char *buf, int buflen) 2306a54a52caSMike Christie { 2307a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 2308a54a52caSMike Christie struct iscsi_session *session = conn->session; 2309a54a52caSMike Christie uint32_t value; 2310a54a52caSMike Christie 2311a54a52caSMike Christie switch(param) { 2312843c0a8aSMike Christie case ISCSI_PARAM_FAST_ABORT: 2313843c0a8aSMike Christie sscanf(buf, "%d", &session->fast_abort); 2314843c0a8aSMike Christie break; 2315f6d5180cSMike Christie case ISCSI_PARAM_ABORT_TMO: 2316f6d5180cSMike Christie sscanf(buf, "%d", &session->abort_timeout); 2317f6d5180cSMike Christie break; 2318f6d5180cSMike Christie case ISCSI_PARAM_LU_RESET_TMO: 2319f6d5180cSMike Christie sscanf(buf, "%d", &session->lu_reset_timeout); 2320f6d5180cSMike Christie break; 2321f6d5180cSMike Christie case ISCSI_PARAM_PING_TMO: 2322f6d5180cSMike Christie sscanf(buf, "%d", &conn->ping_timeout); 2323f6d5180cSMike Christie break; 2324f6d5180cSMike Christie case ISCSI_PARAM_RECV_TMO: 2325f6d5180cSMike Christie sscanf(buf, "%d", &conn->recv_timeout); 2326f6d5180cSMike Christie break; 2327a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 2328a54a52caSMike Christie sscanf(buf, "%d", &conn->max_recv_dlength); 2329a54a52caSMike Christie break; 2330a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 2331a54a52caSMike Christie sscanf(buf, "%d", &conn->max_xmit_dlength); 2332a54a52caSMike Christie break; 2333a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 2334a54a52caSMike Christie sscanf(buf, "%d", &conn->hdrdgst_en); 2335a54a52caSMike Christie break; 2336a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 2337a54a52caSMike Christie sscanf(buf, "%d", &conn->datadgst_en); 2338a54a52caSMike Christie break; 2339a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 2340a54a52caSMike Christie sscanf(buf, "%d", &session->initial_r2t_en); 2341a54a52caSMike Christie break; 2342a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 2343a54a52caSMike Christie sscanf(buf, "%d", &session->max_r2t); 2344a54a52caSMike Christie break; 2345a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 2346a54a52caSMike Christie sscanf(buf, "%d", &session->imm_data_en); 2347a54a52caSMike Christie break; 2348a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 2349a54a52caSMike Christie sscanf(buf, "%d", &session->first_burst); 2350a54a52caSMike Christie break; 2351a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 2352a54a52caSMike Christie sscanf(buf, "%d", &session->max_burst); 2353a54a52caSMike Christie break; 2354a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 2355a54a52caSMike Christie sscanf(buf, "%d", &session->pdu_inorder_en); 2356a54a52caSMike Christie break; 2357a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 2358a54a52caSMike Christie sscanf(buf, "%d", &session->dataseq_inorder_en); 2359a54a52caSMike Christie break; 2360a54a52caSMike Christie case ISCSI_PARAM_ERL: 2361a54a52caSMike Christie sscanf(buf, "%d", &session->erl); 2362a54a52caSMike Christie break; 2363a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 2364a54a52caSMike Christie sscanf(buf, "%d", &value); 2365a54a52caSMike Christie BUG_ON(value); 2366a54a52caSMike Christie break; 2367a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 2368a54a52caSMike Christie sscanf(buf, "%d", &value); 2369a54a52caSMike Christie BUG_ON(value); 2370a54a52caSMike Christie break; 2371a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 2372a54a52caSMike Christie sscanf(buf, "%u", &conn->exp_statsn); 2373a54a52caSMike Christie break; 2374b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 2375b2c64167SMike Christie kfree(session->username); 2376b2c64167SMike Christie session->username = kstrdup(buf, GFP_KERNEL); 2377b2c64167SMike Christie if (!session->username) 2378b2c64167SMike Christie return -ENOMEM; 2379b2c64167SMike Christie break; 2380b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 2381b2c64167SMike Christie kfree(session->username_in); 2382b2c64167SMike Christie session->username_in = kstrdup(buf, GFP_KERNEL); 2383b2c64167SMike Christie if (!session->username_in) 2384b2c64167SMike Christie return -ENOMEM; 2385b2c64167SMike Christie break; 2386b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 2387b2c64167SMike Christie kfree(session->password); 2388b2c64167SMike Christie session->password = kstrdup(buf, GFP_KERNEL); 2389b2c64167SMike Christie if (!session->password) 2390b2c64167SMike Christie return -ENOMEM; 2391b2c64167SMike Christie break; 2392b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 2393b2c64167SMike Christie kfree(session->password_in); 2394b2c64167SMike Christie session->password_in = kstrdup(buf, GFP_KERNEL); 2395b2c64167SMike Christie if (!session->password_in) 2396b2c64167SMike Christie return -ENOMEM; 2397b2c64167SMike Christie break; 2398a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 2399a54a52caSMike Christie /* this should not change between logins */ 2400a54a52caSMike Christie if (session->targetname) 2401a54a52caSMike Christie break; 2402a54a52caSMike Christie 2403a54a52caSMike Christie session->targetname = kstrdup(buf, GFP_KERNEL); 2404a54a52caSMike Christie if (!session->targetname) 2405a54a52caSMike Christie return -ENOMEM; 2406a54a52caSMike Christie break; 2407a54a52caSMike Christie case ISCSI_PARAM_TPGT: 2408a54a52caSMike Christie sscanf(buf, "%d", &session->tpgt); 2409a54a52caSMike Christie break; 2410a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2411a54a52caSMike Christie sscanf(buf, "%d", &conn->persistent_port); 2412a54a52caSMike Christie break; 2413a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 2414a54a52caSMike Christie /* 2415a54a52caSMike Christie * this is the address returned in discovery so it should 2416a54a52caSMike Christie * not change between logins. 2417a54a52caSMike Christie */ 2418a54a52caSMike Christie if (conn->persistent_address) 2419a54a52caSMike Christie break; 2420a54a52caSMike Christie 2421a54a52caSMike Christie conn->persistent_address = kstrdup(buf, GFP_KERNEL); 2422a54a52caSMike Christie if (!conn->persistent_address) 2423a54a52caSMike Christie return -ENOMEM; 2424a54a52caSMike Christie break; 2425a54a52caSMike Christie default: 2426a54a52caSMike Christie return -ENOSYS; 2427a54a52caSMike Christie } 2428a54a52caSMike Christie 2429a54a52caSMike Christie return 0; 2430a54a52caSMike Christie } 2431a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_set_param); 2432a54a52caSMike Christie 2433a54a52caSMike Christie int iscsi_session_get_param(struct iscsi_cls_session *cls_session, 2434a54a52caSMike Christie enum iscsi_param param, char *buf) 2435a54a52caSMike Christie { 243675613521SMike Christie struct iscsi_session *session = cls_session->dd_data; 2437a54a52caSMike Christie int len; 2438a54a52caSMike Christie 2439a54a52caSMike Christie switch(param) { 2440843c0a8aSMike Christie case ISCSI_PARAM_FAST_ABORT: 2441843c0a8aSMike Christie len = sprintf(buf, "%d\n", session->fast_abort); 2442843c0a8aSMike Christie break; 2443f6d5180cSMike Christie case ISCSI_PARAM_ABORT_TMO: 2444f6d5180cSMike Christie len = sprintf(buf, "%d\n", session->abort_timeout); 2445f6d5180cSMike Christie break; 2446f6d5180cSMike Christie case ISCSI_PARAM_LU_RESET_TMO: 2447f6d5180cSMike Christie len = sprintf(buf, "%d\n", session->lu_reset_timeout); 2448f6d5180cSMike Christie break; 2449a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 2450a54a52caSMike Christie len = sprintf(buf, "%d\n", session->initial_r2t_en); 2451a54a52caSMike Christie break; 2452a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 2453a54a52caSMike Christie len = sprintf(buf, "%hu\n", session->max_r2t); 2454a54a52caSMike Christie break; 2455a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 2456a54a52caSMike Christie len = sprintf(buf, "%d\n", session->imm_data_en); 2457a54a52caSMike Christie break; 2458a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 2459a54a52caSMike Christie len = sprintf(buf, "%u\n", session->first_burst); 2460a54a52caSMike Christie break; 2461a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 2462a54a52caSMike Christie len = sprintf(buf, "%u\n", session->max_burst); 2463a54a52caSMike Christie break; 2464a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 2465a54a52caSMike Christie len = sprintf(buf, "%d\n", session->pdu_inorder_en); 2466a54a52caSMike Christie break; 2467a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 2468a54a52caSMike Christie len = sprintf(buf, "%d\n", session->dataseq_inorder_en); 2469a54a52caSMike Christie break; 2470a54a52caSMike Christie case ISCSI_PARAM_ERL: 2471a54a52caSMike Christie len = sprintf(buf, "%d\n", session->erl); 2472a54a52caSMike Christie break; 2473a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 2474a54a52caSMike Christie len = sprintf(buf, "%s\n", session->targetname); 2475a54a52caSMike Christie break; 2476a54a52caSMike Christie case ISCSI_PARAM_TPGT: 2477a54a52caSMike Christie len = sprintf(buf, "%d\n", session->tpgt); 2478a54a52caSMike Christie break; 2479b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 2480b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username); 2481b2c64167SMike Christie break; 2482b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 2483b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username_in); 2484b2c64167SMike Christie break; 2485b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 2486b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password); 2487b2c64167SMike Christie break; 2488b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 2489b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password_in); 2490b2c64167SMike Christie break; 2491a54a52caSMike Christie default: 2492a54a52caSMike Christie return -ENOSYS; 2493a54a52caSMike Christie } 2494a54a52caSMike Christie 2495a54a52caSMike Christie return len; 2496a54a52caSMike Christie } 2497a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_session_get_param); 2498a54a52caSMike Christie 2499a54a52caSMike Christie int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, 2500a54a52caSMike Christie enum iscsi_param param, char *buf) 2501a54a52caSMike Christie { 2502a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 2503a54a52caSMike Christie int len; 2504a54a52caSMike Christie 2505a54a52caSMike Christie switch(param) { 2506f6d5180cSMike Christie case ISCSI_PARAM_PING_TMO: 2507f6d5180cSMike Christie len = sprintf(buf, "%u\n", conn->ping_timeout); 2508f6d5180cSMike Christie break; 2509f6d5180cSMike Christie case ISCSI_PARAM_RECV_TMO: 2510f6d5180cSMike Christie len = sprintf(buf, "%u\n", conn->recv_timeout); 2511f6d5180cSMike Christie break; 2512a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 2513a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_recv_dlength); 2514a54a52caSMike Christie break; 2515a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 2516a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_xmit_dlength); 2517a54a52caSMike Christie break; 2518a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 2519a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->hdrdgst_en); 2520a54a52caSMike Christie break; 2521a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 2522a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->datadgst_en); 2523a54a52caSMike Christie break; 2524a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 2525a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ifmarker_en); 2526a54a52caSMike Christie break; 2527a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 2528a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ofmarker_en); 2529a54a52caSMike Christie break; 2530a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 2531a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->exp_statsn); 2532a54a52caSMike Christie break; 2533a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2534a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->persistent_port); 2535a54a52caSMike Christie break; 2536a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 2537a54a52caSMike Christie len = sprintf(buf, "%s\n", conn->persistent_address); 2538a54a52caSMike Christie break; 2539a54a52caSMike Christie default: 2540a54a52caSMike Christie return -ENOSYS; 2541a54a52caSMike Christie } 2542a54a52caSMike Christie 2543a54a52caSMike Christie return len; 2544a54a52caSMike Christie } 2545a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_get_param); 2546a54a52caSMike Christie 25470801c242SMike Christie int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, 25480801c242SMike Christie char *buf) 25490801c242SMike Christie { 255075613521SMike Christie struct iscsi_host *ihost = shost_priv(shost); 25510801c242SMike Christie int len; 25520801c242SMike Christie 25530801c242SMike Christie switch (param) { 2554d8196ed2SMike Christie case ISCSI_HOST_PARAM_NETDEV_NAME: 255575613521SMike Christie if (!ihost->netdev) 2556d8196ed2SMike Christie len = sprintf(buf, "%s\n", "default"); 2557d8196ed2SMike Christie else 255875613521SMike Christie len = sprintf(buf, "%s\n", ihost->netdev); 2559d8196ed2SMike Christie break; 25600801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 256175613521SMike Christie if (!ihost->hwaddress) 25620801c242SMike Christie len = sprintf(buf, "%s\n", "default"); 25630801c242SMike Christie else 256475613521SMike Christie len = sprintf(buf, "%s\n", ihost->hwaddress); 25650801c242SMike Christie break; 25668ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 256775613521SMike Christie if (!ihost->initiatorname) 25688ad5781aSMike Christie len = sprintf(buf, "%s\n", "unknown"); 25698ad5781aSMike Christie else 257075613521SMike Christie len = sprintf(buf, "%s\n", ihost->initiatorname); 25718ad5781aSMike Christie break; 257275613521SMike Christie case ISCSI_HOST_PARAM_IPADDRESS: 257375613521SMike Christie if (!strlen(ihost->local_address)) 257475613521SMike Christie len = sprintf(buf, "%s\n", "unknown"); 257575613521SMike Christie else 257675613521SMike Christie len = sprintf(buf, "%s\n", 257775613521SMike Christie ihost->local_address); 25780801c242SMike Christie default: 25790801c242SMike Christie return -ENOSYS; 25800801c242SMike Christie } 25810801c242SMike Christie 25820801c242SMike Christie return len; 25830801c242SMike Christie } 25840801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_get_param); 25850801c242SMike Christie 25860801c242SMike Christie int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, 25870801c242SMike Christie char *buf, int buflen) 25880801c242SMike Christie { 258975613521SMike Christie struct iscsi_host *ihost = shost_priv(shost); 25900801c242SMike Christie 25910801c242SMike Christie switch (param) { 2592d8196ed2SMike Christie case ISCSI_HOST_PARAM_NETDEV_NAME: 259375613521SMike Christie if (!ihost->netdev) 259475613521SMike Christie ihost->netdev = kstrdup(buf, GFP_KERNEL); 2595d8196ed2SMike Christie break; 25960801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 259775613521SMike Christie if (!ihost->hwaddress) 259875613521SMike Christie ihost->hwaddress = kstrdup(buf, GFP_KERNEL); 25990801c242SMike Christie break; 26008ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 260175613521SMike Christie if (!ihost->initiatorname) 260275613521SMike Christie ihost->initiatorname = kstrdup(buf, GFP_KERNEL); 26038ad5781aSMike Christie break; 26040801c242SMike Christie default: 26050801c242SMike Christie return -ENOSYS; 26060801c242SMike Christie } 26070801c242SMike Christie 26080801c242SMike Christie return 0; 26090801c242SMike Christie } 26100801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_set_param); 26110801c242SMike Christie 26127996a778SMike Christie MODULE_AUTHOR("Mike Christie"); 26137996a778SMike Christie MODULE_DESCRIPTION("iSCSI library functions"); 26147996a778SMike Christie MODULE_LICENSE("GPL"); 2615