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/mutex.h> 267996a778SMike Christie #include <linux/kfifo.h> 277996a778SMike Christie #include <linux/delay.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 417996a778SMike Christie struct iscsi_session * 427996a778SMike Christie class_to_transport_session(struct iscsi_cls_session *cls_session) 437996a778SMike Christie { 447996a778SMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 457996a778SMike Christie return iscsi_hostdata(shost->hostdata); 467996a778SMike Christie } 477996a778SMike Christie EXPORT_SYMBOL_GPL(class_to_transport_session); 487996a778SMike Christie 497996a778SMike Christie #define INVALID_SN_DELTA 0xffff 507996a778SMike Christie 517996a778SMike Christie int 527996a778SMike Christie iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) 537996a778SMike Christie { 547996a778SMike Christie uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); 557996a778SMike Christie uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); 567996a778SMike Christie 577996a778SMike Christie if (max_cmdsn < exp_cmdsn -1 && 587996a778SMike Christie max_cmdsn > exp_cmdsn - INVALID_SN_DELTA) 597996a778SMike Christie return ISCSI_ERR_MAX_CMDSN; 607996a778SMike Christie if (max_cmdsn > session->max_cmdsn || 617996a778SMike Christie max_cmdsn < session->max_cmdsn - INVALID_SN_DELTA) 627996a778SMike Christie session->max_cmdsn = max_cmdsn; 637996a778SMike Christie if (exp_cmdsn > session->exp_cmdsn || 647996a778SMike Christie exp_cmdsn < session->exp_cmdsn - INVALID_SN_DELTA) 657996a778SMike Christie session->exp_cmdsn = exp_cmdsn; 667996a778SMike Christie 677996a778SMike Christie return 0; 687996a778SMike Christie } 697996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn); 707996a778SMike Christie 717996a778SMike Christie void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, 72ffd0436eSMike Christie struct iscsi_data *hdr) 737996a778SMike Christie { 747996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 757996a778SMike Christie 767996a778SMike Christie memset(hdr, 0, sizeof(struct iscsi_data)); 777996a778SMike Christie hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); 787996a778SMike Christie hdr->datasn = cpu_to_be32(ctask->unsol_datasn); 797996a778SMike Christie ctask->unsol_datasn++; 807996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; 817996a778SMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 827996a778SMike Christie 837996a778SMike Christie hdr->itt = ctask->hdr->itt; 847996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 85ffd0436eSMike Christie hdr->offset = cpu_to_be32(ctask->unsol_offset); 867996a778SMike Christie 877996a778SMike Christie if (ctask->unsol_count > conn->max_xmit_dlength) { 887996a778SMike Christie hton24(hdr->dlength, conn->max_xmit_dlength); 897996a778SMike Christie ctask->data_count = conn->max_xmit_dlength; 90ffd0436eSMike Christie ctask->unsol_offset += ctask->data_count; 917996a778SMike Christie hdr->flags = 0; 927996a778SMike Christie } else { 937996a778SMike Christie hton24(hdr->dlength, ctask->unsol_count); 947996a778SMike Christie ctask->data_count = ctask->unsol_count; 957996a778SMike Christie hdr->flags = ISCSI_FLAG_CMD_FINAL; 967996a778SMike Christie } 977996a778SMike Christie } 987996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); 997996a778SMike Christie 1007996a778SMike Christie /** 1017996a778SMike Christie * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu 1027996a778SMike Christie * @ctask: iscsi cmd task 1037996a778SMike Christie * 1047996a778SMike Christie * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set 1057996a778SMike Christie * fields like dlength or final based on how much data it sends 1067996a778SMike Christie */ 1077996a778SMike Christie static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) 1087996a778SMike Christie { 1097996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 1107996a778SMike Christie struct iscsi_session *session = conn->session; 1117996a778SMike Christie struct iscsi_cmd *hdr = ctask->hdr; 1127996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 1137996a778SMike Christie 1147996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_CMD; 1157996a778SMike Christie hdr->flags = ISCSI_ATTR_SIMPLE; 1167996a778SMike Christie int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 117b4377356SAl Viro hdr->itt = build_itt(ctask->itt, conn->id, session->age); 1187996a778SMike Christie hdr->data_length = cpu_to_be32(sc->request_bufflen); 1197996a778SMike Christie hdr->cmdsn = cpu_to_be32(session->cmdsn); 1207996a778SMike Christie session->cmdsn++; 1217996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 1227996a778SMike Christie memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); 123d473cc7fSMike Christie if (sc->cmd_len < MAX_COMMAND_SIZE) 124d473cc7fSMike Christie memset(&hdr->cdb[sc->cmd_len], 0, 125d473cc7fSMike Christie MAX_COMMAND_SIZE - sc->cmd_len); 1267996a778SMike Christie 127ffd0436eSMike Christie ctask->data_count = 0; 128*218432c6SMike Christie ctask->imm_count = 0; 1297996a778SMike Christie if (sc->sc_data_direction == DMA_TO_DEVICE) { 1307996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_WRITE; 1317996a778SMike Christie /* 1327996a778SMike Christie * Write counters: 1337996a778SMike Christie * 1347996a778SMike Christie * imm_count bytes to be sent right after 1357996a778SMike Christie * SCSI PDU Header 1367996a778SMike Christie * 1377996a778SMike Christie * unsol_count bytes(as Data-Out) to be sent 1387996a778SMike Christie * without R2T ack right after 1397996a778SMike Christie * immediate data 1407996a778SMike Christie * 1417996a778SMike Christie * r2t_data_count bytes to be sent via R2T ack's 1427996a778SMike Christie * 1437996a778SMike Christie * pad_count bytes to be sent as zero-padding 1447996a778SMike Christie */ 1457996a778SMike Christie ctask->unsol_count = 0; 146ffd0436eSMike Christie ctask->unsol_offset = 0; 1477996a778SMike Christie ctask->unsol_datasn = 0; 1487996a778SMike Christie 1497996a778SMike Christie if (session->imm_data_en) { 150857ae0bdSMike Christie if (sc->request_bufflen >= session->first_burst) 1517996a778SMike Christie ctask->imm_count = min(session->first_burst, 1527996a778SMike Christie conn->max_xmit_dlength); 1537996a778SMike Christie else 154857ae0bdSMike Christie ctask->imm_count = min(sc->request_bufflen, 1557996a778SMike Christie conn->max_xmit_dlength); 1567996a778SMike Christie hton24(ctask->hdr->dlength, ctask->imm_count); 1577996a778SMike Christie } else 1587996a778SMike Christie zero_data(ctask->hdr->dlength); 1597996a778SMike Christie 160ffd0436eSMike Christie if (!session->initial_r2t_en) { 161857ae0bdSMike Christie ctask->unsol_count = min((session->first_burst), 162857ae0bdSMike Christie (sc->request_bufflen)) - ctask->imm_count; 163ffd0436eSMike Christie ctask->unsol_offset = ctask->imm_count; 164ffd0436eSMike Christie } 165ffd0436eSMike Christie 1667996a778SMike Christie if (!ctask->unsol_count) 1677996a778SMike Christie /* No unsolicit Data-Out's */ 1687996a778SMike Christie ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1697996a778SMike Christie } else { 1707996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1717996a778SMike Christie zero_data(hdr->dlength); 1727996a778SMike Christie 1737996a778SMike Christie if (sc->sc_data_direction == DMA_FROM_DEVICE) 1747996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_READ; 1757996a778SMike Christie } 1767996a778SMike Christie 1777996a778SMike Christie conn->scsicmd_pdus_cnt++; 1787996a778SMike Christie } 1797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu); 1807996a778SMike Christie 1817996a778SMike Christie /** 1827996a778SMike Christie * iscsi_complete_command - return command back to scsi-ml 1837996a778SMike Christie * @ctask: iscsi cmd task 1847996a778SMike Christie * 1857996a778SMike Christie * Must be called with session lock. 1867996a778SMike Christie * This function returns the scsi command to scsi-ml and returns 1877996a778SMike Christie * the cmd task to the pool of available cmd tasks. 1887996a778SMike Christie */ 18960ecebf5SMike Christie static void iscsi_complete_command(struct iscsi_cmd_task *ctask) 1907996a778SMike Christie { 19160ecebf5SMike Christie struct iscsi_session *session = ctask->conn->session; 1927996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 1937996a778SMike Christie 194b6c395edSMike Christie ctask->state = ISCSI_TASK_COMPLETED; 1957996a778SMike Christie ctask->sc = NULL; 196f47f2cf5SMike Christie /* SCSI eh reuses commands to verify us */ 197f47f2cf5SMike Christie sc->SCp.ptr = NULL; 1987996a778SMike Christie list_del_init(&ctask->running); 1997996a778SMike Christie __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); 2007996a778SMike Christie sc->scsi_done(sc); 2017996a778SMike Christie } 2027996a778SMike Christie 20360ecebf5SMike Christie static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) 20460ecebf5SMike Christie { 20560ecebf5SMike Christie atomic_inc(&ctask->refcount); 20660ecebf5SMike Christie } 20760ecebf5SMike Christie 20860ecebf5SMike Christie static void iscsi_get_ctask(struct iscsi_cmd_task *ctask) 20960ecebf5SMike Christie { 21060ecebf5SMike Christie spin_lock_bh(&ctask->conn->session->lock); 21160ecebf5SMike Christie __iscsi_get_ctask(ctask); 21260ecebf5SMike Christie spin_unlock_bh(&ctask->conn->session->lock); 21360ecebf5SMike Christie } 21460ecebf5SMike Christie 21560ecebf5SMike Christie static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) 21660ecebf5SMike Christie { 217e648f63cSMike Christie if (atomic_dec_and_test(&ctask->refcount)) 21860ecebf5SMike Christie iscsi_complete_command(ctask); 21960ecebf5SMike Christie } 22060ecebf5SMike Christie 22160ecebf5SMike Christie static void iscsi_put_ctask(struct iscsi_cmd_task *ctask) 22260ecebf5SMike Christie { 22360ecebf5SMike Christie spin_lock_bh(&ctask->conn->session->lock); 22460ecebf5SMike Christie __iscsi_put_ctask(ctask); 22560ecebf5SMike Christie spin_unlock_bh(&ctask->conn->session->lock); 22660ecebf5SMike Christie } 22760ecebf5SMike Christie 2287996a778SMike Christie /** 2297996a778SMike Christie * iscsi_cmd_rsp - SCSI Command Response processing 2307996a778SMike Christie * @conn: iscsi connection 2317996a778SMike Christie * @hdr: iscsi header 2327996a778SMike Christie * @ctask: scsi command task 2337996a778SMike Christie * @data: cmd data buffer 2347996a778SMike Christie * @datalen: len of buffer 2357996a778SMike Christie * 2367996a778SMike Christie * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and 2377996a778SMike Christie * then completes the command and task. 2387996a778SMike Christie **/ 2397996a778SMike Christie static int iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 2407996a778SMike Christie struct iscsi_cmd_task *ctask, char *data, 2417996a778SMike Christie int datalen) 2427996a778SMike Christie { 2437996a778SMike Christie int rc; 2447996a778SMike Christie struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; 2457996a778SMike Christie struct iscsi_session *session = conn->session; 2467996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 2477996a778SMike Christie 2487996a778SMike Christie rc = iscsi_check_assign_cmdsn(session, (struct iscsi_nopin*)rhdr); 2497996a778SMike Christie if (rc) { 2507996a778SMike Christie sc->result = DID_ERROR << 16; 2517996a778SMike Christie goto out; 2527996a778SMike Christie } 2537996a778SMike Christie 2547996a778SMike Christie conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; 2557996a778SMike Christie 2567996a778SMike Christie sc->result = (DID_OK << 16) | rhdr->cmd_status; 2577996a778SMike Christie 2587996a778SMike Christie if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { 2597996a778SMike Christie sc->result = DID_ERROR << 16; 2607996a778SMike Christie goto out; 2617996a778SMike Christie } 2627996a778SMike Christie 2637996a778SMike Christie if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { 2649b80cb4bSMike Christie uint16_t senselen; 2657996a778SMike Christie 2667996a778SMike Christie if (datalen < 2) { 2677996a778SMike Christie invalid_datalen: 268be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " 269be2df72eSOr Gerlitz "invalid data buffer size of %d\n", datalen); 2707996a778SMike Christie sc->result = DID_BAD_TARGET << 16; 2717996a778SMike Christie goto out; 2727996a778SMike Christie } 2737996a778SMike Christie 2748eb00539SMike Christie senselen = be16_to_cpu(get_unaligned((__be16 *) data)); 2757996a778SMike Christie if (datalen < senselen) 2767996a778SMike Christie goto invalid_datalen; 2777996a778SMike Christie 2787996a778SMike Christie memcpy(sc->sense_buffer, data + 2, 2799b80cb4bSMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 2807996a778SMike Christie debug_scsi("copied %d bytes of sense\n", 2818eb00539SMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 2827996a778SMike Christie } 2837996a778SMike Christie 2847996a778SMike Christie if (sc->sc_data_direction == DMA_TO_DEVICE) 2857996a778SMike Christie goto out; 2867996a778SMike Christie 2877996a778SMike Christie if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { 2887996a778SMike Christie int res_count = be32_to_cpu(rhdr->residual_count); 2897996a778SMike Christie 2907996a778SMike Christie if (res_count > 0 && res_count <= sc->request_bufflen) 2917996a778SMike Christie sc->resid = res_count; 2927996a778SMike Christie else 2937996a778SMike Christie sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 2947996a778SMike Christie } else if (rhdr->flags & ISCSI_FLAG_CMD_BIDI_UNDERFLOW) 2957996a778SMike Christie sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 2967996a778SMike Christie else if (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW) 2977996a778SMike Christie sc->resid = be32_to_cpu(rhdr->residual_count); 2987996a778SMike Christie 2997996a778SMike Christie out: 3007996a778SMike Christie debug_scsi("done [sc %lx res %d itt 0x%x]\n", 3017996a778SMike Christie (long)sc, sc->result, ctask->itt); 3027996a778SMike Christie conn->scsirsp_pdus_cnt++; 3037996a778SMike Christie 30460ecebf5SMike Christie __iscsi_put_ctask(ctask); 3057996a778SMike Christie return rc; 3067996a778SMike Christie } 3077996a778SMike Christie 3087ea8b828SMike Christie static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) 3097ea8b828SMike Christie { 3107ea8b828SMike Christie struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; 3117ea8b828SMike Christie 3127ea8b828SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 3137ea8b828SMike Christie conn->tmfrsp_pdus_cnt++; 3147ea8b828SMike Christie 3157ea8b828SMike Christie if (conn->tmabort_state != TMABORT_INITIAL) 3167ea8b828SMike Christie return; 3177ea8b828SMike Christie 3187ea8b828SMike Christie if (tmf->response == ISCSI_TMF_RSP_COMPLETE) 3197ea8b828SMike Christie conn->tmabort_state = TMABORT_SUCCESS; 3207ea8b828SMike Christie else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) 3217ea8b828SMike Christie conn->tmabort_state = TMABORT_NOT_FOUND; 3227ea8b828SMike Christie else 3237ea8b828SMike Christie conn->tmabort_state = TMABORT_FAILED; 3247ea8b828SMike Christie wake_up(&conn->ehwait); 3257ea8b828SMike Christie } 3267ea8b828SMike Christie 32762f38300SMike Christie static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 32862f38300SMike Christie char *data, int datalen) 32962f38300SMike Christie { 33062f38300SMike Christie struct iscsi_reject *reject = (struct iscsi_reject *)hdr; 33162f38300SMike Christie struct iscsi_hdr rejected_pdu; 33262f38300SMike Christie uint32_t itt; 33362f38300SMike Christie 33462f38300SMike Christie conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; 33562f38300SMike Christie 33662f38300SMike Christie if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { 33762f38300SMike Christie if (ntoh24(reject->dlength) > datalen) 33862f38300SMike Christie return ISCSI_ERR_PROTO; 33962f38300SMike Christie 34062f38300SMike Christie if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { 34162f38300SMike Christie memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); 342b4377356SAl Viro itt = get_itt(rejected_pdu.itt); 34362f38300SMike Christie printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " 34462f38300SMike Christie "due to DataDigest error.\n", itt, 34562f38300SMike Christie rejected_pdu.opcode); 34662f38300SMike Christie } 34762f38300SMike Christie } 34862f38300SMike Christie return 0; 34962f38300SMike Christie } 35062f38300SMike Christie 3517996a778SMike Christie /** 3527996a778SMike Christie * __iscsi_complete_pdu - complete pdu 3537996a778SMike Christie * @conn: iscsi conn 3547996a778SMike Christie * @hdr: iscsi header 3557996a778SMike Christie * @data: data buffer 3567996a778SMike Christie * @datalen: len of data buffer 3577996a778SMike Christie * 3587996a778SMike Christie * Completes pdu processing by freeing any resources allocated at 3597996a778SMike Christie * queuecommand or send generic. session lock must be held and verify 3607996a778SMike Christie * itt must have been called. 3617996a778SMike Christie */ 3627996a778SMike Christie int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 3637996a778SMike Christie char *data, int datalen) 3647996a778SMike Christie { 3657996a778SMike Christie struct iscsi_session *session = conn->session; 3667996a778SMike Christie int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; 3677996a778SMike Christie struct iscsi_cmd_task *ctask; 3687996a778SMike Christie struct iscsi_mgmt_task *mtask; 3697996a778SMike Christie uint32_t itt; 3707996a778SMike Christie 371b4377356SAl Viro if (hdr->itt != RESERVED_ITT) 372b4377356SAl Viro itt = get_itt(hdr->itt); 3737996a778SMike Christie else 374b4377356SAl Viro itt = ~0U; 3757996a778SMike Christie 3767996a778SMike Christie if (itt < session->cmds_max) { 3777996a778SMike Christie ctask = session->cmds[itt]; 3787996a778SMike Christie 3797996a778SMike Christie debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", 3807996a778SMike Christie opcode, conn->id, ctask->itt, datalen); 3817996a778SMike Christie 3827996a778SMike Christie switch(opcode) { 3837996a778SMike Christie case ISCSI_OP_SCSI_CMD_RSP: 3847996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 3857996a778SMike Christie rc = iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, 3867996a778SMike Christie datalen); 3877996a778SMike Christie break; 3887996a778SMike Christie case ISCSI_OP_SCSI_DATA_IN: 3897996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 3907996a778SMike Christie if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 3917996a778SMike Christie conn->scsirsp_pdus_cnt++; 39260ecebf5SMike Christie __iscsi_put_ctask(ctask); 3937996a778SMike Christie } 3947996a778SMike Christie break; 3957996a778SMike Christie case ISCSI_OP_R2T: 3967996a778SMike Christie /* LLD handles this for now */ 3977996a778SMike Christie break; 3987996a778SMike Christie default: 3997996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 4007996a778SMike Christie break; 4017996a778SMike Christie } 4027996a778SMike Christie } else if (itt >= ISCSI_MGMT_ITT_OFFSET && 4037996a778SMike Christie itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { 4047996a778SMike Christie mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; 4057996a778SMike Christie 4067996a778SMike Christie debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", 4077996a778SMike Christie opcode, conn->id, mtask->itt, datalen); 4087996a778SMike Christie 4097996a778SMike Christie rc = iscsi_check_assign_cmdsn(session, 4107996a778SMike Christie (struct iscsi_nopin*)hdr); 4117996a778SMike Christie if (rc) 4128d2860b3SMike Christie goto done; 4137996a778SMike Christie 4148d2860b3SMike Christie switch(opcode) { 4158d2860b3SMike Christie case ISCSI_OP_LOGOUT_RSP: 416c8dc1e52SMike Christie if (datalen) { 417c8dc1e52SMike Christie rc = ISCSI_ERR_PROTO; 418c8dc1e52SMike Christie break; 419c8dc1e52SMike Christie } 4208d2860b3SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 4218d2860b3SMike Christie /* fall through */ 4228d2860b3SMike Christie case ISCSI_OP_LOGIN_RSP: 4238d2860b3SMike Christie case ISCSI_OP_TEXT_RSP: 4248d2860b3SMike Christie /* 4258d2860b3SMike Christie * login related PDU's exp_statsn is handled in 4268d2860b3SMike Christie * userspace 4278d2860b3SMike Christie */ 42840527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 42940527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 4307996a778SMike Christie list_del(&mtask->running); 4317996a778SMike Christie if (conn->login_mtask != mtask) 4327996a778SMike Christie __kfifo_put(session->mgmtpool.queue, 4337996a778SMike Christie (void*)&mtask, sizeof(void*)); 4347996a778SMike Christie break; 4357996a778SMike Christie case ISCSI_OP_SCSI_TMFUNC_RSP: 4367996a778SMike Christie if (datalen) { 4377996a778SMike Christie rc = ISCSI_ERR_PROTO; 4387996a778SMike Christie break; 4397996a778SMike Christie } 4408d2860b3SMike Christie 4417ea8b828SMike Christie iscsi_tmf_rsp(conn, hdr); 4427996a778SMike Christie break; 4437996a778SMike Christie case ISCSI_OP_NOOP_IN: 444b4377356SAl Viro if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { 4457996a778SMike Christie rc = ISCSI_ERR_PROTO; 4467996a778SMike Christie break; 4477996a778SMike Christie } 4487996a778SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 4497996a778SMike Christie 45040527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 45140527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 4527996a778SMike Christie list_del(&mtask->running); 4537996a778SMike Christie if (conn->login_mtask != mtask) 4547996a778SMike Christie __kfifo_put(session->mgmtpool.queue, 4557996a778SMike Christie (void*)&mtask, sizeof(void*)); 4567996a778SMike Christie break; 4577996a778SMike Christie default: 4587996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 4597996a778SMike Christie break; 4607996a778SMike Christie } 461b4377356SAl Viro } else if (itt == ~0U) { 46262f38300SMike Christie rc = iscsi_check_assign_cmdsn(session, 46362f38300SMike Christie (struct iscsi_nopin*)hdr); 46462f38300SMike Christie if (rc) 46562f38300SMike Christie goto done; 46662f38300SMike Christie 4677996a778SMike Christie switch(opcode) { 4687996a778SMike Christie case ISCSI_OP_NOOP_IN: 46940527afeSMike Christie if (datalen) { 47040527afeSMike Christie rc = ISCSI_ERR_PROTO; 47140527afeSMike Christie break; 47240527afeSMike Christie } 47340527afeSMike Christie 474b4377356SAl Viro if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) 47540527afeSMike Christie break; 47640527afeSMike Christie 47740527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0)) 47840527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 4797996a778SMike Christie break; 4807996a778SMike Christie case ISCSI_OP_REJECT: 48162f38300SMike Christie rc = iscsi_handle_reject(conn, hdr, data, datalen); 48262f38300SMike Christie break; 4837996a778SMike Christie case ISCSI_OP_ASYNC_EVENT: 4848d2860b3SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 4855831c737SMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 4865831c737SMike Christie rc = ISCSI_ERR_CONN_FAILED; 4877996a778SMike Christie break; 4887996a778SMike Christie default: 4897996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 4907996a778SMike Christie break; 4917996a778SMike Christie } 4927996a778SMike Christie } else 4937996a778SMike Christie rc = ISCSI_ERR_BAD_ITT; 4947996a778SMike Christie 4958d2860b3SMike Christie done: 4967996a778SMike Christie return rc; 4977996a778SMike Christie } 4987996a778SMike Christie EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); 4997996a778SMike Christie 5007996a778SMike Christie int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 5017996a778SMike Christie char *data, int datalen) 5027996a778SMike Christie { 5037996a778SMike Christie int rc; 5047996a778SMike Christie 5057996a778SMike Christie spin_lock(&conn->session->lock); 5067996a778SMike Christie rc = __iscsi_complete_pdu(conn, hdr, data, datalen); 5077996a778SMike Christie spin_unlock(&conn->session->lock); 5087996a778SMike Christie return rc; 5097996a778SMike Christie } 5107996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_complete_pdu); 5117996a778SMike Christie 5127996a778SMike Christie /* verify itt (itt encoding: age+cid+itt) */ 5137996a778SMike Christie int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 5147996a778SMike Christie uint32_t *ret_itt) 5157996a778SMike Christie { 5167996a778SMike Christie struct iscsi_session *session = conn->session; 5177996a778SMike Christie struct iscsi_cmd_task *ctask; 5187996a778SMike Christie uint32_t itt; 5197996a778SMike Christie 520b4377356SAl Viro if (hdr->itt != RESERVED_ITT) { 521b4377356SAl Viro if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != 5227996a778SMike Christie (session->age << ISCSI_AGE_SHIFT)) { 523be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: received itt %x expected " 524b4377356SAl Viro "session age (%x)\n", (__force u32)hdr->itt, 5257996a778SMike Christie session->age & ISCSI_AGE_MASK); 5267996a778SMike Christie return ISCSI_ERR_BAD_ITT; 5277996a778SMike Christie } 5287996a778SMike Christie 529b4377356SAl Viro if (((__force u32)hdr->itt & ISCSI_CID_MASK) != 5307996a778SMike Christie (conn->id << ISCSI_CID_SHIFT)) { 531be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: received itt %x, expected " 532b4377356SAl Viro "CID (%x)\n", (__force u32)hdr->itt, conn->id); 5337996a778SMike Christie return ISCSI_ERR_BAD_ITT; 5347996a778SMike Christie } 535b4377356SAl Viro itt = get_itt(hdr->itt); 5367996a778SMike Christie } else 537b4377356SAl Viro itt = ~0U; 5387996a778SMike Christie 5397996a778SMike Christie if (itt < session->cmds_max) { 5407996a778SMike Christie ctask = session->cmds[itt]; 5417996a778SMike Christie 5427996a778SMike Christie if (!ctask->sc) { 543be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: dropping ctask with " 5447996a778SMike Christie "itt 0x%x\n", ctask->itt); 5457996a778SMike Christie /* force drop */ 5467996a778SMike Christie return ISCSI_ERR_NO_SCSI_CMD; 5477996a778SMike Christie } 5487996a778SMike Christie 5497996a778SMike Christie if (ctask->sc->SCp.phase != session->age) { 550be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: ctask's session age %d, " 5517996a778SMike Christie "expected %d\n", ctask->sc->SCp.phase, 5527996a778SMike Christie session->age); 5537996a778SMike Christie return ISCSI_ERR_SESSION_FAILED; 5547996a778SMike Christie } 5557996a778SMike Christie } 5567996a778SMike Christie 5577996a778SMike Christie *ret_itt = itt; 5587996a778SMike Christie return 0; 5597996a778SMike Christie } 5607996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_verify_itt); 5617996a778SMike Christie 5627996a778SMike Christie void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) 5637996a778SMike Christie { 5647996a778SMike Christie struct iscsi_session *session = conn->session; 5657996a778SMike Christie unsigned long flags; 5667996a778SMike Christie 5677996a778SMike Christie spin_lock_irqsave(&session->lock, flags); 568656cffc9SMike Christie if (session->state == ISCSI_STATE_FAILED) { 569656cffc9SMike Christie spin_unlock_irqrestore(&session->lock, flags); 570656cffc9SMike Christie return; 571656cffc9SMike Christie } 572656cffc9SMike Christie 57367a61114SMike Christie if (conn->stop_stage == 0) 5747996a778SMike Christie session->state = ISCSI_STATE_FAILED; 5757996a778SMike Christie spin_unlock_irqrestore(&session->lock, flags); 5767996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 5777996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 5787996a778SMike Christie iscsi_conn_error(conn->cls_conn, err); 5797996a778SMike Christie } 5807996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_failure); 5817996a778SMike Christie 58205db888aSMike Christie static int iscsi_xmit_mtask(struct iscsi_conn *conn) 583b5072ea0SMike Christie { 584b5072ea0SMike Christie struct iscsi_hdr *hdr = conn->mtask->hdr; 585b5072ea0SMike Christie int rc, was_logout = 0; 586b5072ea0SMike Christie 587b5072ea0SMike Christie if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { 588b5072ea0SMike Christie conn->session->state = ISCSI_STATE_IN_RECOVERY; 589b5072ea0SMike Christie iscsi_block_session(session_to_cls(conn->session)); 590b5072ea0SMike Christie was_logout = 1; 591b5072ea0SMike Christie } 592b5072ea0SMike Christie rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); 593b5072ea0SMike Christie if (rc) 594b5072ea0SMike Christie return rc; 595b5072ea0SMike Christie 59605db888aSMike Christie /* done with this in-progress mtask */ 59705db888aSMike Christie conn->mtask = NULL; 59805db888aSMike Christie 599b5072ea0SMike Christie if (was_logout) { 600b5072ea0SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 601b5072ea0SMike Christie return -ENODATA; 602b5072ea0SMike Christie } 603b5072ea0SMike Christie return 0; 604b5072ea0SMike Christie } 605b5072ea0SMike Christie 6067996a778SMike Christie /** 6077996a778SMike Christie * iscsi_data_xmit - xmit any command into the scheduled connection 6087996a778SMike Christie * @conn: iscsi connection 6097996a778SMike Christie * 6107996a778SMike Christie * Notes: 6117996a778SMike Christie * The function can return -EAGAIN in which case the caller must 6127996a778SMike Christie * re-schedule it again later or recover. '0' return code means 6137996a778SMike Christie * successful xmit. 6147996a778SMike Christie **/ 6157996a778SMike Christie static int iscsi_data_xmit(struct iscsi_conn *conn) 6167996a778SMike Christie { 6177996a778SMike Christie struct iscsi_transport *tt; 6183219e529SMike Christie int rc = 0; 6197996a778SMike Christie 6207996a778SMike Christie if (unlikely(conn->suspend_tx)) { 6217996a778SMike Christie debug_scsi("conn %d Tx suspended!\n", conn->id); 6223219e529SMike Christie return -ENODATA; 6237996a778SMike Christie } 6247996a778SMike Christie tt = conn->session->tt; 6257996a778SMike Christie 6267996a778SMike Christie /* 6277996a778SMike Christie * Transmit in the following order: 6287996a778SMike Christie * 6297996a778SMike Christie * 1) un-finished xmit (ctask or mtask) 6307996a778SMike Christie * 2) immediate control PDUs 6317996a778SMike Christie * 3) write data 6327996a778SMike Christie * 4) SCSI commands 6337996a778SMike Christie * 5) non-immediate control PDUs 6347996a778SMike Christie * 6357996a778SMike Christie * No need to lock around __kfifo_get as long as 6367996a778SMike Christie * there's one producer and one consumer. 6377996a778SMike Christie */ 6387996a778SMike Christie 6397996a778SMike Christie BUG_ON(conn->ctask && conn->mtask); 6407996a778SMike Christie 6417996a778SMike Christie if (conn->ctask) { 64260ecebf5SMike Christie iscsi_get_ctask(conn->ctask); 6433219e529SMike Christie rc = tt->xmit_cmd_task(conn, conn->ctask); 64460ecebf5SMike Christie iscsi_put_ctask(conn->ctask); 6453219e529SMike Christie if (rc) 6467996a778SMike Christie goto again; 6477996a778SMike Christie /* done with this in-progress ctask */ 6487996a778SMike Christie conn->ctask = NULL; 6497996a778SMike Christie } 6507996a778SMike Christie if (conn->mtask) { 65105db888aSMike Christie rc = iscsi_xmit_mtask(conn); 6523219e529SMike Christie if (rc) 6537996a778SMike Christie goto again; 6547996a778SMike Christie } 6557996a778SMike Christie 6567996a778SMike Christie /* process immediate first */ 6577996a778SMike Christie if (unlikely(__kfifo_len(conn->immqueue))) { 6587996a778SMike Christie while (__kfifo_get(conn->immqueue, (void*)&conn->mtask, 6597996a778SMike Christie sizeof(void*))) { 660994442e8SMike Christie spin_lock_bh(&conn->session->lock); 6617996a778SMike Christie list_add_tail(&conn->mtask->running, 6627996a778SMike Christie &conn->mgmt_run_list); 663994442e8SMike Christie spin_unlock_bh(&conn->session->lock); 66405db888aSMike Christie rc = iscsi_xmit_mtask(conn); 6653219e529SMike Christie if (rc) 6667996a778SMike Christie goto again; 6677996a778SMike Christie } 6687996a778SMike Christie } 6697996a778SMike Christie 6707996a778SMike Christie /* process command queue */ 671b6c395edSMike Christie spin_lock_bh(&conn->session->lock); 672b6c395edSMike Christie while (!list_empty(&conn->xmitqueue)) { 6737996a778SMike Christie /* 6747996a778SMike Christie * iscsi tcp may readd the task to the xmitqueue to send 6757996a778SMike Christie * write data 6767996a778SMike Christie */ 677b6c395edSMike Christie conn->ctask = list_entry(conn->xmitqueue.next, 678b6c395edSMike Christie struct iscsi_cmd_task, running); 679b6c395edSMike Christie conn->ctask->state = ISCSI_TASK_RUNNING; 680b6c395edSMike Christie list_move_tail(conn->xmitqueue.next, &conn->run_list); 68160ecebf5SMike Christie __iscsi_get_ctask(conn->ctask); 682994442e8SMike Christie spin_unlock_bh(&conn->session->lock); 683b6c395edSMike Christie 6843219e529SMike Christie rc = tt->xmit_cmd_task(conn, conn->ctask); 68560ecebf5SMike Christie 686b6c395edSMike Christie spin_lock_bh(&conn->session->lock); 68760ecebf5SMike Christie __iscsi_put_ctask(conn->ctask); 68860ecebf5SMike Christie if (rc) { 68960ecebf5SMike Christie spin_unlock_bh(&conn->session->lock); 69060ecebf5SMike Christie goto again; 69160ecebf5SMike Christie } 6927996a778SMike Christie } 693b6c395edSMike Christie spin_unlock_bh(&conn->session->lock); 6947996a778SMike Christie /* done with this ctask */ 6957996a778SMike Christie conn->ctask = NULL; 6967996a778SMike Christie 6977996a778SMike Christie /* process the rest control plane PDUs, if any */ 6987996a778SMike Christie if (unlikely(__kfifo_len(conn->mgmtqueue))) { 6997996a778SMike Christie while (__kfifo_get(conn->mgmtqueue, (void*)&conn->mtask, 7007996a778SMike Christie sizeof(void*))) { 701994442e8SMike Christie spin_lock_bh(&conn->session->lock); 7027996a778SMike Christie list_add_tail(&conn->mtask->running, 7037996a778SMike Christie &conn->mgmt_run_list); 704994442e8SMike Christie spin_unlock_bh(&conn->session->lock); 70505db888aSMike Christie rc = iscsi_xmit_mtask(conn); 7063219e529SMike Christie if (rc) 7077996a778SMike Christie goto again; 7087996a778SMike Christie } 7097996a778SMike Christie } 7107996a778SMike Christie 7113219e529SMike Christie return -ENODATA; 7127996a778SMike Christie 7137996a778SMike Christie again: 7147996a778SMike Christie if (unlikely(conn->suspend_tx)) 7153219e529SMike Christie return -ENODATA; 7167996a778SMike Christie 7173219e529SMike Christie return rc; 7187996a778SMike Christie } 7197996a778SMike Christie 720c4028958SDavid Howells static void iscsi_xmitworker(struct work_struct *work) 7217996a778SMike Christie { 722c4028958SDavid Howells struct iscsi_conn *conn = 723c4028958SDavid Howells container_of(work, struct iscsi_conn, xmitwork); 7243219e529SMike Christie int rc; 7257996a778SMike Christie /* 7267996a778SMike Christie * serialize Xmit worker on a per-connection basis. 7277996a778SMike Christie */ 7287996a778SMike Christie mutex_lock(&conn->xmitmutex); 7293219e529SMike Christie do { 7303219e529SMike Christie rc = iscsi_data_xmit(conn); 7313219e529SMike Christie } while (rc >= 0 || rc == -EAGAIN); 7327996a778SMike Christie mutex_unlock(&conn->xmitmutex); 7337996a778SMike Christie } 7347996a778SMike Christie 7357996a778SMike Christie enum { 7367996a778SMike Christie FAILURE_BAD_HOST = 1, 7377996a778SMike Christie FAILURE_SESSION_FAILED, 7387996a778SMike Christie FAILURE_SESSION_FREED, 7397996a778SMike Christie FAILURE_WINDOW_CLOSED, 74060ecebf5SMike Christie FAILURE_OOM, 7417996a778SMike Christie FAILURE_SESSION_TERMINATE, 742656cffc9SMike Christie FAILURE_SESSION_IN_RECOVERY, 7437996a778SMike Christie FAILURE_SESSION_RECOVERY_TIMEOUT, 7447996a778SMike Christie }; 7457996a778SMike Christie 7467996a778SMike Christie int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 7477996a778SMike Christie { 7487996a778SMike Christie struct Scsi_Host *host; 7497996a778SMike Christie int reason = 0; 7507996a778SMike Christie struct iscsi_session *session; 7517996a778SMike Christie struct iscsi_conn *conn; 7527996a778SMike Christie struct iscsi_cmd_task *ctask = NULL; 7537996a778SMike Christie 7547996a778SMike Christie sc->scsi_done = done; 7557996a778SMike Christie sc->result = 0; 756f47f2cf5SMike Christie sc->SCp.ptr = NULL; 7577996a778SMike Christie 7587996a778SMike Christie host = sc->device->host; 7597996a778SMike Christie session = iscsi_hostdata(host->hostdata); 7607996a778SMike Christie 7617996a778SMike Christie spin_lock(&session->lock); 7627996a778SMike Christie 763656cffc9SMike Christie /* 764656cffc9SMike Christie * ISCSI_STATE_FAILED is a temp. state. The recovery 765656cffc9SMike Christie * code will decide what is best to do with command queued 766656cffc9SMike Christie * during this time 767656cffc9SMike Christie */ 768656cffc9SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN && 769656cffc9SMike Christie session->state != ISCSI_STATE_FAILED) { 770656cffc9SMike Christie /* 771656cffc9SMike Christie * to handle the race between when we set the recovery state 772656cffc9SMike Christie * and block the session we requeue here (commands could 773656cffc9SMike Christie * be entering our queuecommand while a block is starting 774656cffc9SMike Christie * up because the block code is not locked) 775656cffc9SMike Christie */ 776656cffc9SMike Christie if (session->state == ISCSI_STATE_IN_RECOVERY) { 777656cffc9SMike Christie reason = FAILURE_SESSION_IN_RECOVERY; 77867a61114SMike Christie goto reject; 7797996a778SMike Christie } 780656cffc9SMike Christie 781656cffc9SMike Christie if (session->state == ISCSI_STATE_RECOVERY_FAILED) 782656cffc9SMike Christie reason = FAILURE_SESSION_RECOVERY_TIMEOUT; 783656cffc9SMike Christie else if (session->state == ISCSI_STATE_TERMINATE) 784656cffc9SMike Christie reason = FAILURE_SESSION_TERMINATE; 785656cffc9SMike Christie else 7867996a778SMike Christie reason = FAILURE_SESSION_FREED; 7877996a778SMike Christie goto fault; 7887996a778SMike Christie } 7897996a778SMike Christie 7907996a778SMike Christie /* 7917996a778SMike Christie * Check for iSCSI window and take care of CmdSN wrap-around 7927996a778SMike Christie */ 7937996a778SMike Christie if ((int)(session->max_cmdsn - session->cmdsn) < 0) { 7947996a778SMike Christie reason = FAILURE_WINDOW_CLOSED; 7957996a778SMike Christie goto reject; 7967996a778SMike Christie } 7977996a778SMike Christie 7987996a778SMike Christie conn = session->leadconn; 79998644047SMike Christie if (!conn) { 80098644047SMike Christie reason = FAILURE_SESSION_FREED; 80198644047SMike Christie goto fault; 80298644047SMike Christie } 8037996a778SMike Christie 80460ecebf5SMike Christie if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, 80560ecebf5SMike Christie sizeof(void*))) { 80660ecebf5SMike Christie reason = FAILURE_OOM; 80760ecebf5SMike Christie goto reject; 80860ecebf5SMike Christie } 8097996a778SMike Christie sc->SCp.phase = session->age; 8107996a778SMike Christie sc->SCp.ptr = (char *)ctask; 8117996a778SMike Christie 81260ecebf5SMike Christie atomic_set(&ctask->refcount, 1); 813b6c395edSMike Christie ctask->state = ISCSI_TASK_PENDING; 8147996a778SMike Christie ctask->mtask = NULL; 8157996a778SMike Christie ctask->conn = conn; 8167996a778SMike Christie ctask->sc = sc; 8177996a778SMike Christie INIT_LIST_HEAD(&ctask->running); 8187996a778SMike Christie iscsi_prep_scsi_cmd_pdu(ctask); 8197996a778SMike Christie 8207996a778SMike Christie session->tt->init_cmd_task(ctask); 8217996a778SMike Christie 822b6c395edSMike Christie list_add_tail(&ctask->running, &conn->xmitqueue); 8237996a778SMike Christie debug_scsi( 824f47f2cf5SMike Christie "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d " 825f47f2cf5SMike Christie "win %d]\n", 8267996a778SMike Christie sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", 827f47f2cf5SMike Christie conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen, 8287996a778SMike Christie session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); 8297996a778SMike Christie spin_unlock(&session->lock); 8307996a778SMike Christie 8317996a778SMike Christie scsi_queue_work(host, &conn->xmitwork); 8327996a778SMike Christie return 0; 8337996a778SMike Christie 8347996a778SMike Christie reject: 8357996a778SMike Christie spin_unlock(&session->lock); 8367996a778SMike Christie debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); 8377996a778SMike Christie return SCSI_MLQUEUE_HOST_BUSY; 8387996a778SMike Christie 8397996a778SMike Christie fault: 8407996a778SMike Christie spin_unlock(&session->lock); 841be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", 8427996a778SMike Christie sc->cmnd[0], reason); 8437996a778SMike Christie sc->result = (DID_NO_CONNECT << 16); 8447996a778SMike Christie sc->resid = sc->request_bufflen; 8457996a778SMike Christie sc->scsi_done(sc); 8467996a778SMike Christie return 0; 8477996a778SMike Christie } 8487996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_queuecommand); 8497996a778SMike Christie 8507996a778SMike Christie int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) 8517996a778SMike Christie { 8527996a778SMike Christie if (depth > ISCSI_MAX_CMD_PER_LUN) 8537996a778SMike Christie depth = ISCSI_MAX_CMD_PER_LUN; 8547996a778SMike Christie scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); 8557996a778SMike Christie return sdev->queue_depth; 8567996a778SMike Christie } 8577996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); 8587996a778SMike Christie 8597996a778SMike Christie static int 8607996a778SMike Christie iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 8617996a778SMike Christie char *data, uint32_t data_size) 8627996a778SMike Christie { 8637996a778SMike Christie struct iscsi_session *session = conn->session; 8647996a778SMike Christie struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; 8657996a778SMike Christie struct iscsi_mgmt_task *mtask; 8667996a778SMike Christie 8677996a778SMike Christie spin_lock_bh(&session->lock); 8687996a778SMike Christie if (session->state == ISCSI_STATE_TERMINATE) { 8697996a778SMike Christie spin_unlock_bh(&session->lock); 8707996a778SMike Christie return -EPERM; 8717996a778SMike Christie } 8727996a778SMike Christie if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || 8737996a778SMike Christie hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) 8747996a778SMike Christie /* 8757996a778SMike Christie * Login and Text are sent serially, in 8767996a778SMike Christie * request-followed-by-response sequence. 8777996a778SMike Christie * Same mtask can be used. Same ITT must be used. 8787996a778SMike Christie * Note that login_mtask is preallocated at conn_create(). 8797996a778SMike Christie */ 8807996a778SMike Christie mtask = conn->login_mtask; 8817996a778SMike Christie else { 8827996a778SMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); 8837996a778SMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); 8847996a778SMike Christie 8858d2860b3SMike Christie nop->exp_statsn = cpu_to_be32(conn->exp_statsn); 8867996a778SMike Christie if (!__kfifo_get(session->mgmtpool.queue, 8877996a778SMike Christie (void*)&mtask, sizeof(void*))) { 8887996a778SMike Christie spin_unlock_bh(&session->lock); 8897996a778SMike Christie return -ENOSPC; 8907996a778SMike Christie } 8917996a778SMike Christie } 8927996a778SMike Christie 8937996a778SMike Christie /* 8948d2860b3SMike Christie * pre-format CmdSN for outgoing PDU. 8957996a778SMike Christie */ 896b4377356SAl Viro if (hdr->itt != RESERVED_ITT) { 897b4377356SAl Viro hdr->itt = build_itt(mtask->itt, conn->id, session->age); 8987996a778SMike Christie nop->cmdsn = cpu_to_be32(session->cmdsn); 8997996a778SMike Christie if (conn->c_stage == ISCSI_CONN_STARTED && 9007996a778SMike Christie !(hdr->opcode & ISCSI_OP_IMMEDIATE)) 9017996a778SMike Christie session->cmdsn++; 9027996a778SMike Christie } else 9037996a778SMike Christie /* do not advance CmdSN */ 9047996a778SMike Christie nop->cmdsn = cpu_to_be32(session->cmdsn); 9057996a778SMike Christie 9067996a778SMike Christie if (data_size) { 9077996a778SMike Christie memcpy(mtask->data, data, data_size); 9087996a778SMike Christie mtask->data_count = data_size; 9097996a778SMike Christie } else 9107996a778SMike Christie mtask->data_count = 0; 9117996a778SMike Christie 9127996a778SMike Christie INIT_LIST_HEAD(&mtask->running); 9137996a778SMike Christie memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); 9147996a778SMike Christie if (session->tt->init_mgmt_task) 9157996a778SMike Christie session->tt->init_mgmt_task(conn, mtask, data, data_size); 9167996a778SMike Christie spin_unlock_bh(&session->lock); 9177996a778SMike Christie 9187996a778SMike Christie debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", 9197996a778SMike Christie hdr->opcode, hdr->itt, data_size); 9207996a778SMike Christie 9217996a778SMike Christie /* 9227996a778SMike Christie * since send_pdu() could be called at least from two contexts, 9237996a778SMike Christie * we need to serialize __kfifo_put, so we don't have to take 9247996a778SMike Christie * additional lock on fast data-path 9257996a778SMike Christie */ 9267996a778SMike Christie if (hdr->opcode & ISCSI_OP_IMMEDIATE) 9277996a778SMike Christie __kfifo_put(conn->immqueue, (void*)&mtask, sizeof(void*)); 9287996a778SMike Christie else 9297996a778SMike Christie __kfifo_put(conn->mgmtqueue, (void*)&mtask, sizeof(void*)); 9307996a778SMike Christie 9317996a778SMike Christie scsi_queue_work(session->host, &conn->xmitwork); 9327996a778SMike Christie return 0; 9337996a778SMike Christie } 9347996a778SMike Christie 9357996a778SMike Christie int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, 9367996a778SMike Christie char *data, uint32_t data_size) 9377996a778SMike Christie { 9387996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 9397996a778SMike Christie int rc; 9407996a778SMike Christie 9417996a778SMike Christie mutex_lock(&conn->xmitmutex); 9427996a778SMike Christie rc = iscsi_conn_send_generic(conn, hdr, data, data_size); 9437996a778SMike Christie mutex_unlock(&conn->xmitmutex); 9447996a778SMike Christie 9457996a778SMike Christie return rc; 9467996a778SMike Christie } 9477996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); 9487996a778SMike Christie 9497996a778SMike Christie void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) 9507996a778SMike Christie { 9517996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 9527996a778SMike Christie struct iscsi_conn *conn = session->leadconn; 9537996a778SMike Christie 9547996a778SMike Christie spin_lock_bh(&session->lock); 9557996a778SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN) { 956656cffc9SMike Christie session->state = ISCSI_STATE_RECOVERY_FAILED; 9577996a778SMike Christie if (conn) 9587996a778SMike Christie wake_up(&conn->ehwait); 9597996a778SMike Christie } 9607996a778SMike Christie spin_unlock_bh(&session->lock); 9617996a778SMike Christie } 9627996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); 9637996a778SMike Christie 9647996a778SMike Christie int iscsi_eh_host_reset(struct scsi_cmnd *sc) 9657996a778SMike Christie { 9667996a778SMike Christie struct Scsi_Host *host = sc->device->host; 9677996a778SMike Christie struct iscsi_session *session = iscsi_hostdata(host->hostdata); 9687996a778SMike Christie struct iscsi_conn *conn = session->leadconn; 9697996a778SMike Christie int fail_session = 0; 9707996a778SMike Christie 9717996a778SMike Christie spin_lock_bh(&session->lock); 9727996a778SMike Christie if (session->state == ISCSI_STATE_TERMINATE) { 9737996a778SMike Christie failed: 9747996a778SMike Christie debug_scsi("failing host reset: session terminated " 975d6e24d1cSPete Wyckoff "[CID %d age %d]\n", conn->id, session->age); 9767996a778SMike Christie spin_unlock_bh(&session->lock); 9777996a778SMike Christie return FAILED; 9787996a778SMike Christie } 9797996a778SMike Christie 9807996a778SMike Christie if (sc->SCp.phase == session->age) { 981d6e24d1cSPete Wyckoff debug_scsi("failing connection CID %d due to SCSI host reset\n", 9827996a778SMike Christie conn->id); 9837996a778SMike Christie fail_session = 1; 9847996a778SMike Christie } 9857996a778SMike Christie spin_unlock_bh(&session->lock); 9867996a778SMike Christie 9877996a778SMike Christie /* 9887996a778SMike Christie * we drop the lock here but the leadconn cannot be destoyed while 9897996a778SMike Christie * we are in the scsi eh 9907996a778SMike Christie */ 991656cffc9SMike Christie if (fail_session) 9927996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 9937996a778SMike Christie 9947996a778SMike Christie debug_scsi("iscsi_eh_host_reset wait for relogin\n"); 9957996a778SMike Christie wait_event_interruptible(conn->ehwait, 9967996a778SMike Christie session->state == ISCSI_STATE_TERMINATE || 9977996a778SMike Christie session->state == ISCSI_STATE_LOGGED_IN || 998656cffc9SMike Christie session->state == ISCSI_STATE_RECOVERY_FAILED); 9997996a778SMike Christie if (signal_pending(current)) 10007996a778SMike Christie flush_signals(current); 10017996a778SMike Christie 10027996a778SMike Christie spin_lock_bh(&session->lock); 10037996a778SMike Christie if (session->state == ISCSI_STATE_LOGGED_IN) 1004be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: host reset succeeded\n"); 10057996a778SMike Christie else 10067996a778SMike Christie goto failed; 10077996a778SMike Christie spin_unlock_bh(&session->lock); 10087996a778SMike Christie 10097996a778SMike Christie return SUCCESS; 10107996a778SMike Christie } 10117996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); 10127996a778SMike Christie 10137996a778SMike Christie static void iscsi_tmabort_timedout(unsigned long data) 10147996a778SMike Christie { 10157996a778SMike Christie struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)data; 10167996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 10177996a778SMike Christie struct iscsi_session *session = conn->session; 10187996a778SMike Christie 10197996a778SMike Christie spin_lock(&session->lock); 10207996a778SMike Christie if (conn->tmabort_state == TMABORT_INITIAL) { 10217996a778SMike Christie conn->tmabort_state = TMABORT_TIMEDOUT; 10227996a778SMike Christie debug_scsi("tmabort timedout [sc %p itt 0x%x]\n", 10237996a778SMike Christie ctask->sc, ctask->itt); 10247996a778SMike Christie /* unblock eh_abort() */ 10257996a778SMike Christie wake_up(&conn->ehwait); 10267996a778SMike Christie } 10277996a778SMike Christie spin_unlock(&session->lock); 10287996a778SMike Christie } 10297996a778SMike Christie 10307996a778SMike Christie /* must be called with the mutex lock */ 10317996a778SMike Christie static int iscsi_exec_abort_task(struct scsi_cmnd *sc, 10327996a778SMike Christie struct iscsi_cmd_task *ctask) 10337996a778SMike Christie { 10347996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 10357996a778SMike Christie struct iscsi_session *session = conn->session; 10367996a778SMike Christie struct iscsi_tm *hdr = &conn->tmhdr; 10377996a778SMike Christie int rc; 10387996a778SMike Christie 10397996a778SMike Christie /* 10407996a778SMike Christie * ctask timed out but session is OK requests must be serialized. 10417996a778SMike Christie */ 10427996a778SMike Christie memset(hdr, 0, sizeof(struct iscsi_tm)); 10437996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 10447996a778SMike Christie hdr->flags = ISCSI_TM_FUNC_ABORT_TASK; 10457996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 10467996a778SMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 10477996a778SMike Christie hdr->rtt = ctask->hdr->itt; 10487996a778SMike Christie hdr->refcmdsn = ctask->hdr->cmdsn; 10497996a778SMike Christie 10507996a778SMike Christie rc = iscsi_conn_send_generic(conn, (struct iscsi_hdr *)hdr, 10517996a778SMike Christie NULL, 0); 10527996a778SMike Christie if (rc) { 10537996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1054d6e24d1cSPete Wyckoff debug_scsi("abort sent failure [itt 0x%x] %d\n", ctask->itt, 1055d6e24d1cSPete Wyckoff rc); 10567996a778SMike Christie return rc; 10577996a778SMike Christie } 10587996a778SMike Christie 10597996a778SMike Christie debug_scsi("abort sent [itt 0x%x]\n", ctask->itt); 10607996a778SMike Christie 10617996a778SMike Christie spin_lock_bh(&session->lock); 10627996a778SMike Christie ctask->mtask = (struct iscsi_mgmt_task *) 1063b4377356SAl Viro session->mgmt_cmds[get_itt(hdr->itt) - 10647996a778SMike Christie ISCSI_MGMT_ITT_OFFSET]; 10657996a778SMike Christie 10667996a778SMike Christie if (conn->tmabort_state == TMABORT_INITIAL) { 10677996a778SMike Christie conn->tmfcmd_pdus_cnt++; 10687996a778SMike Christie conn->tmabort_timer.expires = 10*HZ + jiffies; 10697996a778SMike Christie conn->tmabort_timer.function = iscsi_tmabort_timedout; 10707996a778SMike Christie conn->tmabort_timer.data = (unsigned long)ctask; 10717996a778SMike Christie add_timer(&conn->tmabort_timer); 1072d6e24d1cSPete Wyckoff debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt); 10737996a778SMike Christie } 10747996a778SMike Christie spin_unlock_bh(&session->lock); 10757996a778SMike Christie mutex_unlock(&conn->xmitmutex); 10767996a778SMike Christie 10777996a778SMike Christie /* 10787996a778SMike Christie * block eh thread until: 10797996a778SMike Christie * 10807996a778SMike Christie * 1) abort response 10817996a778SMike Christie * 2) abort timeout 10827996a778SMike Christie * 3) session is terminated or restarted or userspace has 10837996a778SMike Christie * given up on recovery 10847996a778SMike Christie */ 10857996a778SMike Christie wait_event_interruptible(conn->ehwait, 10867996a778SMike Christie sc->SCp.phase != session->age || 10877996a778SMike Christie session->state != ISCSI_STATE_LOGGED_IN || 1088656cffc9SMike Christie conn->tmabort_state != TMABORT_INITIAL); 10897996a778SMike Christie if (signal_pending(current)) 10907996a778SMike Christie flush_signals(current); 10917996a778SMike Christie del_timer_sync(&conn->tmabort_timer); 10927996a778SMike Christie 10937996a778SMike Christie mutex_lock(&conn->xmitmutex); 10947996a778SMike Christie return 0; 10957996a778SMike Christie } 10967996a778SMike Christie 10977996a778SMike Christie /* 10987996a778SMike Christie * xmit mutex and session lock must be held 10997996a778SMike Christie */ 1100b6c395edSMike Christie static struct iscsi_mgmt_task * 1101b6c395edSMike Christie iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) 1102b6c395edSMike Christie { 1103b6c395edSMike Christie int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); 1104b6c395edSMike Christie struct iscsi_mgmt_task *task; 1105b6c395edSMike Christie 1106b6c395edSMike Christie debug_scsi("searching %d tasks\n", nr_tasks); 1107b6c395edSMike Christie 1108b6c395edSMike Christie for (i = 0; i < nr_tasks; i++) { 1109b6c395edSMike Christie __kfifo_get(fifo, (void*)&task, sizeof(void*)); 1110b6c395edSMike Christie debug_scsi("check task %u\n", task->itt); 1111b6c395edSMike Christie 1112b6c395edSMike Christie if (task->itt == itt) { 1113b6c395edSMike Christie debug_scsi("matched task\n"); 1114b6c395edSMike Christie return task; 11157996a778SMike Christie } 11167996a778SMike Christie 1117b6c395edSMike Christie __kfifo_put(fifo, (void*)&task, sizeof(void*)); 1118b6c395edSMike Christie } 1119b6c395edSMike Christie return NULL; 1120b6c395edSMike Christie } 11217996a778SMike Christie 11227996a778SMike Christie static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask) 11237996a778SMike Christie { 11247996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 11257996a778SMike Christie struct iscsi_session *session = conn->session; 11267996a778SMike Christie 11277996a778SMike Christie if (!ctask->mtask) 11287996a778SMike Christie return -EINVAL; 11297996a778SMike Christie 11307996a778SMike Christie if (!iscsi_remove_mgmt_task(conn->immqueue, ctask->mtask->itt)) 11317996a778SMike Christie list_del(&ctask->mtask->running); 11327996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&ctask->mtask, 11337996a778SMike Christie sizeof(void*)); 11347996a778SMike Christie ctask->mtask = NULL; 11357996a778SMike Christie return 0; 11367996a778SMike Christie } 11377996a778SMike Christie 11387996a778SMike Christie /* 11397996a778SMike Christie * session lock and xmitmutex must be held 11407996a778SMike Christie */ 11417996a778SMike Christie static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, 11427996a778SMike Christie int err) 11437996a778SMike Christie { 11447996a778SMike Christie struct scsi_cmnd *sc; 11457996a778SMike Christie 11467996a778SMike Christie sc = ctask->sc; 11477996a778SMike Christie if (!sc) 11487996a778SMike Christie return; 1149e648f63cSMike Christie 1150e648f63cSMike Christie conn->session->tt->cleanup_cmd_task(conn, ctask); 11517ea8b828SMike Christie iscsi_ctask_mtask_cleanup(ctask); 11527ea8b828SMike Christie 11537996a778SMike Christie sc->result = err; 11547996a778SMike Christie sc->resid = sc->request_bufflen; 1155e648f63cSMike Christie /* release ref from queuecommand */ 115660ecebf5SMike Christie __iscsi_put_ctask(ctask); 11577996a778SMike Christie } 11587996a778SMike Christie 11597996a778SMike Christie int iscsi_eh_abort(struct scsi_cmnd *sc) 11607996a778SMike Christie { 1161f47f2cf5SMike Christie struct iscsi_cmd_task *ctask; 1162f47f2cf5SMike Christie struct iscsi_conn *conn; 1163f47f2cf5SMike Christie struct iscsi_session *session; 11647996a778SMike Christie int rc; 11657996a778SMike Christie 1166f47f2cf5SMike Christie /* 1167f47f2cf5SMike Christie * if session was ISCSI_STATE_IN_RECOVERY then we may not have 1168f47f2cf5SMike Christie * got the command. 1169f47f2cf5SMike Christie */ 1170f47f2cf5SMike Christie if (!sc->SCp.ptr) { 1171f47f2cf5SMike Christie debug_scsi("sc never reached iscsi layer or it completed.\n"); 1172f47f2cf5SMike Christie return SUCCESS; 1173f47f2cf5SMike Christie } 1174f47f2cf5SMike Christie 1175f47f2cf5SMike Christie ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; 1176f47f2cf5SMike Christie conn = ctask->conn; 1177f47f2cf5SMike Christie session = conn->session; 1178f47f2cf5SMike Christie 11797996a778SMike Christie conn->eh_abort_cnt++; 11807996a778SMike Christie debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); 11817996a778SMike Christie 11827996a778SMike Christie mutex_lock(&conn->xmitmutex); 11837996a778SMike Christie spin_lock_bh(&session->lock); 11847996a778SMike Christie 11857996a778SMike Christie /* 11867996a778SMike Christie * If we are not logged in or we have started a new session 11877996a778SMike Christie * then let the host reset code handle this 11887996a778SMike Christie */ 11897996a778SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN || 11907996a778SMike Christie sc->SCp.phase != session->age) 11917996a778SMike Christie goto failed; 11927996a778SMike Christie 11937996a778SMike Christie /* ctask completed before time out */ 11947ea8b828SMike Christie if (!ctask->sc) { 11957ea8b828SMike Christie spin_unlock_bh(&session->lock); 11967ea8b828SMike Christie debug_scsi("sc completed while abort in progress\n"); 11977ea8b828SMike Christie goto success_rel_mutex; 11987ea8b828SMike Christie } 11997996a778SMike Christie 12007996a778SMike Christie /* what should we do here ? */ 12017996a778SMike Christie if (conn->ctask == ctask) { 1202be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: sc %p itt 0x%x partially sent. " 1203be2df72eSOr Gerlitz "Failing abort\n", sc, ctask->itt); 12047996a778SMike Christie goto failed; 12057996a778SMike Christie } 12067996a778SMike Christie 1207b6c395edSMike Christie if (ctask->state == ISCSI_TASK_PENDING) 12087ea8b828SMike Christie goto success_cleanup; 12097996a778SMike Christie 12107996a778SMike Christie conn->tmabort_state = TMABORT_INITIAL; 12117996a778SMike Christie 12127996a778SMike Christie spin_unlock_bh(&session->lock); 12137996a778SMike Christie rc = iscsi_exec_abort_task(sc, ctask); 12147996a778SMike Christie spin_lock_bh(&session->lock); 12157996a778SMike Christie 12167996a778SMike Christie if (rc || sc->SCp.phase != session->age || 12177996a778SMike Christie session->state != ISCSI_STATE_LOGGED_IN) 12187996a778SMike Christie goto failed; 12197ea8b828SMike Christie iscsi_ctask_mtask_cleanup(ctask); 12207996a778SMike Christie 12217ea8b828SMike Christie switch (conn->tmabort_state) { 12227ea8b828SMike Christie case TMABORT_SUCCESS: 12237ea8b828SMike Christie goto success_cleanup; 12247ea8b828SMike Christie case TMABORT_NOT_FOUND: 12257996a778SMike Christie if (!ctask->sc) { 12267ea8b828SMike Christie /* ctask completed before tmf abort response */ 12277ea8b828SMike Christie spin_unlock_bh(&session->lock); 12287996a778SMike Christie debug_scsi("sc completed while abort in progress\n"); 12297ea8b828SMike Christie goto success_rel_mutex; 12307996a778SMike Christie } 12317ea8b828SMike Christie /* fall through */ 12327ea8b828SMike Christie default: 12337ea8b828SMike Christie /* timedout or failed */ 12347996a778SMike Christie spin_unlock_bh(&session->lock); 12357996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 12367996a778SMike Christie spin_lock_bh(&session->lock); 12377996a778SMike Christie goto failed; 12387996a778SMike Christie } 12397996a778SMike Christie 12407ea8b828SMike Christie success_cleanup: 12417996a778SMike Christie debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 12427996a778SMike Christie spin_unlock_bh(&session->lock); 12437996a778SMike Christie 12447996a778SMike Christie /* 12457996a778SMike Christie * clean up task if aborted. we have the xmitmutex so grab 12467996a778SMike Christie * the recv lock as a writer 12477996a778SMike Christie */ 12487996a778SMike Christie write_lock_bh(conn->recv_lock); 12497996a778SMike Christie spin_lock(&session->lock); 12507996a778SMike Christie fail_command(conn, ctask, DID_ABORT << 16); 12517996a778SMike Christie spin_unlock(&session->lock); 12527996a778SMike Christie write_unlock_bh(conn->recv_lock); 12537996a778SMike Christie 12547ea8b828SMike Christie success_rel_mutex: 12557996a778SMike Christie mutex_unlock(&conn->xmitmutex); 12567996a778SMike Christie return SUCCESS; 12577996a778SMike Christie 12587996a778SMike Christie failed: 12597996a778SMike Christie spin_unlock_bh(&session->lock); 12607996a778SMike Christie mutex_unlock(&conn->xmitmutex); 12617996a778SMike Christie 12627996a778SMike Christie debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 12637996a778SMike Christie return FAILED; 12647996a778SMike Christie } 12657996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_abort); 12667996a778SMike Christie 12677996a778SMike Christie int 12687996a778SMike Christie iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) 12697996a778SMike Christie { 12707996a778SMike Christie int i; 12717996a778SMike Christie 12727996a778SMike Christie *items = kmalloc(max * sizeof(void*), GFP_KERNEL); 12737996a778SMike Christie if (*items == NULL) 12747996a778SMike Christie return -ENOMEM; 12757996a778SMike Christie 12767996a778SMike Christie q->max = max; 12777996a778SMike Christie q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); 12787996a778SMike Christie if (q->pool == NULL) { 12797996a778SMike Christie kfree(*items); 12807996a778SMike Christie return -ENOMEM; 12817996a778SMike Christie } 12827996a778SMike Christie 12837996a778SMike Christie q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), 12847996a778SMike Christie GFP_KERNEL, NULL); 12857996a778SMike Christie if (q->queue == ERR_PTR(-ENOMEM)) { 12867996a778SMike Christie kfree(q->pool); 12877996a778SMike Christie kfree(*items); 12887996a778SMike Christie return -ENOMEM; 12897996a778SMike Christie } 12907996a778SMike Christie 12917996a778SMike Christie for (i = 0; i < max; i++) { 12927996a778SMike Christie q->pool[i] = kmalloc(item_size, GFP_KERNEL); 12937996a778SMike Christie if (q->pool[i] == NULL) { 12947996a778SMike Christie int j; 12957996a778SMike Christie 12967996a778SMike Christie for (j = 0; j < i; j++) 12977996a778SMike Christie kfree(q->pool[j]); 12987996a778SMike Christie 12997996a778SMike Christie kfifo_free(q->queue); 13007996a778SMike Christie kfree(q->pool); 13017996a778SMike Christie kfree(*items); 13027996a778SMike Christie return -ENOMEM; 13037996a778SMike Christie } 13047996a778SMike Christie memset(q->pool[i], 0, item_size); 13057996a778SMike Christie (*items)[i] = q->pool[i]; 13067996a778SMike Christie __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*)); 13077996a778SMike Christie } 13087996a778SMike Christie return 0; 13097996a778SMike Christie } 13107996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_init); 13117996a778SMike Christie 13127996a778SMike Christie void iscsi_pool_free(struct iscsi_queue *q, void **items) 13137996a778SMike Christie { 13147996a778SMike Christie int i; 13157996a778SMike Christie 13167996a778SMike Christie for (i = 0; i < q->max; i++) 13177996a778SMike Christie kfree(items[i]); 13187996a778SMike Christie kfree(q->pool); 13197996a778SMike Christie kfree(items); 13207996a778SMike Christie } 13217996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_free); 13227996a778SMike Christie 13237996a778SMike Christie /* 13247996a778SMike Christie * iSCSI Session's hostdata organization: 13257996a778SMike Christie * 13267996a778SMike Christie * *------------------* <== hostdata_session(host->hostdata) 13277996a778SMike Christie * | ptr to class sess| 13287996a778SMike Christie * |------------------| <== iscsi_hostdata(host->hostdata) 13297996a778SMike Christie * | iscsi_session | 13307996a778SMike Christie * *------------------* 13317996a778SMike Christie */ 13327996a778SMike Christie 13337996a778SMike Christie #define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \ 13347996a778SMike Christie _sz % sizeof(unsigned long)) 13357996a778SMike Christie 13367996a778SMike Christie #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) 13377996a778SMike Christie 13387996a778SMike Christie /** 13397996a778SMike Christie * iscsi_session_setup - create iscsi cls session and host and session 13407996a778SMike Christie * @scsit: scsi transport template 13417996a778SMike Christie * @iscsit: iscsi transport template 13427996a778SMike Christie * @initial_cmdsn: initial CmdSN 13437996a778SMike Christie * @hostno: host no allocated 13447996a778SMike Christie * 13457996a778SMike Christie * This can be used by software iscsi_transports that allocate 13467996a778SMike Christie * a session per scsi host. 13477996a778SMike Christie **/ 13487996a778SMike Christie struct iscsi_cls_session * 13497996a778SMike Christie iscsi_session_setup(struct iscsi_transport *iscsit, 13507996a778SMike Christie struct scsi_transport_template *scsit, 13517996a778SMike Christie int cmd_task_size, int mgmt_task_size, 13527996a778SMike Christie uint32_t initial_cmdsn, uint32_t *hostno) 13537996a778SMike Christie { 13547996a778SMike Christie struct Scsi_Host *shost; 13557996a778SMike Christie struct iscsi_session *session; 13567996a778SMike Christie struct iscsi_cls_session *cls_session; 13577996a778SMike Christie int cmd_i; 13587996a778SMike Christie 13597996a778SMike Christie shost = scsi_host_alloc(iscsit->host_template, 13607996a778SMike Christie hostdata_privsize(sizeof(*session))); 13617996a778SMike Christie if (!shost) 13627996a778SMike Christie return NULL; 13637996a778SMike Christie 13647996a778SMike Christie shost->max_id = 1; 13657996a778SMike Christie shost->max_channel = 0; 13667996a778SMike Christie shost->max_lun = iscsit->max_lun; 13677996a778SMike Christie shost->max_cmd_len = iscsit->max_cmd_len; 13687996a778SMike Christie shost->transportt = scsit; 13697996a778SMike Christie shost->transportt->create_work_queue = 1; 13707996a778SMike Christie *hostno = shost->host_no; 13717996a778SMike Christie 13727996a778SMike Christie session = iscsi_hostdata(shost->hostdata); 13737996a778SMike Christie memset(session, 0, sizeof(struct iscsi_session)); 13747996a778SMike Christie session->host = shost; 13757996a778SMike Christie session->state = ISCSI_STATE_FREE; 13767996a778SMike Christie session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; 13777996a778SMike Christie session->cmds_max = ISCSI_XMIT_CMDS_MAX; 13787996a778SMike Christie session->cmdsn = initial_cmdsn; 13797996a778SMike Christie session->exp_cmdsn = initial_cmdsn + 1; 13807996a778SMike Christie session->max_cmdsn = initial_cmdsn + 1; 13817996a778SMike Christie session->max_r2t = 1; 13827996a778SMike Christie session->tt = iscsit; 13837996a778SMike Christie 13847996a778SMike Christie /* initialize SCSI PDU commands pool */ 13857996a778SMike Christie if (iscsi_pool_init(&session->cmdpool, session->cmds_max, 13867996a778SMike Christie (void***)&session->cmds, 13877996a778SMike Christie cmd_task_size + sizeof(struct iscsi_cmd_task))) 13887996a778SMike Christie goto cmdpool_alloc_fail; 13897996a778SMike Christie 13907996a778SMike Christie /* pre-format cmds pool with ITT */ 13917996a778SMike Christie for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { 13927996a778SMike Christie struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; 13937996a778SMike Christie 13947996a778SMike Christie if (cmd_task_size) 13957996a778SMike Christie ctask->dd_data = &ctask[1]; 13967996a778SMike Christie ctask->itt = cmd_i; 1397b6c395edSMike Christie INIT_LIST_HEAD(&ctask->running); 13987996a778SMike Christie } 13997996a778SMike Christie 14007996a778SMike Christie spin_lock_init(&session->lock); 14017996a778SMike Christie 14027996a778SMike Christie /* initialize immediate command pool */ 14037996a778SMike Christie if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, 14047996a778SMike Christie (void***)&session->mgmt_cmds, 14057996a778SMike Christie mgmt_task_size + sizeof(struct iscsi_mgmt_task))) 14067996a778SMike Christie goto mgmtpool_alloc_fail; 14077996a778SMike Christie 14087996a778SMike Christie 14097996a778SMike Christie /* pre-format immediate cmds pool with ITT */ 14107996a778SMike Christie for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { 14117996a778SMike Christie struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; 14127996a778SMike Christie 14137996a778SMike Christie if (mgmt_task_size) 14147996a778SMike Christie mtask->dd_data = &mtask[1]; 14157996a778SMike Christie mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; 1416b6c395edSMike Christie INIT_LIST_HEAD(&mtask->running); 14177996a778SMike Christie } 14187996a778SMike Christie 14197996a778SMike Christie if (scsi_add_host(shost, NULL)) 14207996a778SMike Christie goto add_host_fail; 14217996a778SMike Christie 1422f53a88daSMike Christie if (!try_module_get(iscsit->owner)) 1423f53a88daSMike Christie goto cls_session_fail; 1424f53a88daSMike Christie 14256a8a0d36SMike Christie cls_session = iscsi_create_session(shost, iscsit, 0); 14267996a778SMike Christie if (!cls_session) 1427f53a88daSMike Christie goto module_put; 14287996a778SMike Christie *(unsigned long*)shost->hostdata = (unsigned long)cls_session; 14297996a778SMike Christie 14307996a778SMike Christie return cls_session; 14317996a778SMike Christie 1432f53a88daSMike Christie module_put: 1433f53a88daSMike Christie module_put(iscsit->owner); 14347996a778SMike Christie cls_session_fail: 14357996a778SMike Christie scsi_remove_host(shost); 14367996a778SMike Christie add_host_fail: 14377996a778SMike Christie iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); 14387996a778SMike Christie mgmtpool_alloc_fail: 14397996a778SMike Christie iscsi_pool_free(&session->cmdpool, (void**)session->cmds); 14407996a778SMike Christie cmdpool_alloc_fail: 14417996a778SMike Christie scsi_host_put(shost); 14427996a778SMike Christie return NULL; 14437996a778SMike Christie } 14447996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_setup); 14457996a778SMike Christie 14467996a778SMike Christie /** 14477996a778SMike Christie * iscsi_session_teardown - destroy session, host, and cls_session 14487996a778SMike Christie * shost: scsi host 14497996a778SMike Christie * 14507996a778SMike Christie * This can be used by software iscsi_transports that allocate 14517996a778SMike Christie * a session per scsi host. 14527996a778SMike Christie **/ 14537996a778SMike Christie void iscsi_session_teardown(struct iscsi_cls_session *cls_session) 14547996a778SMike Christie { 14557996a778SMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 14567996a778SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 145763f75cc8SMike Christie struct module *owner = cls_session->transport->owner; 14587996a778SMike Christie 14597996a778SMike Christie scsi_remove_host(shost); 14607996a778SMike Christie 14617996a778SMike Christie iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); 14627996a778SMike Christie iscsi_pool_free(&session->cmdpool, (void**)session->cmds); 14637996a778SMike Christie 1464b2c64167SMike Christie kfree(session->password); 1465b2c64167SMike Christie kfree(session->password_in); 1466b2c64167SMike Christie kfree(session->username); 1467b2c64167SMike Christie kfree(session->username_in); 1468f3ff0c36SMike Christie kfree(session->targetname); 14690801c242SMike Christie kfree(session->hwaddress); 14708ad5781aSMike Christie kfree(session->initiatorname); 1471f3ff0c36SMike Christie 14727996a778SMike Christie iscsi_destroy_session(cls_session); 14737996a778SMike Christie scsi_host_put(shost); 147463f75cc8SMike Christie module_put(owner); 14757996a778SMike Christie } 14767996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_teardown); 14777996a778SMike Christie 14787996a778SMike Christie /** 14797996a778SMike Christie * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn 14807996a778SMike Christie * @cls_session: iscsi_cls_session 14817996a778SMike Christie * @conn_idx: cid 14827996a778SMike Christie **/ 14837996a778SMike Christie struct iscsi_cls_conn * 14847996a778SMike Christie iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) 14857996a778SMike Christie { 14867996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 14877996a778SMike Christie struct iscsi_conn *conn; 14887996a778SMike Christie struct iscsi_cls_conn *cls_conn; 1489d36ab6f3SMike Christie char *data; 14907996a778SMike Christie 14917996a778SMike Christie cls_conn = iscsi_create_conn(cls_session, conn_idx); 14927996a778SMike Christie if (!cls_conn) 14937996a778SMike Christie return NULL; 14947996a778SMike Christie conn = cls_conn->dd_data; 14957996a778SMike Christie memset(conn, 0, sizeof(*conn)); 14967996a778SMike Christie 14977996a778SMike Christie conn->session = session; 14987996a778SMike Christie conn->cls_conn = cls_conn; 14997996a778SMike Christie conn->c_stage = ISCSI_CONN_INITIAL_STAGE; 15007996a778SMike Christie conn->id = conn_idx; 15017996a778SMike Christie conn->exp_statsn = 0; 15027996a778SMike Christie conn->tmabort_state = TMABORT_INITIAL; 15037996a778SMike Christie INIT_LIST_HEAD(&conn->run_list); 15047996a778SMike Christie INIT_LIST_HEAD(&conn->mgmt_run_list); 1505b6c395edSMike Christie INIT_LIST_HEAD(&conn->xmitqueue); 15067996a778SMike Christie 15077996a778SMike Christie /* initialize general immediate & non-immediate PDU commands queue */ 15087996a778SMike Christie conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), 15097996a778SMike Christie GFP_KERNEL, NULL); 15107996a778SMike Christie if (conn->immqueue == ERR_PTR(-ENOMEM)) 15117996a778SMike Christie goto immqueue_alloc_fail; 15127996a778SMike Christie 15137996a778SMike Christie conn->mgmtqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*), 15147996a778SMike Christie GFP_KERNEL, NULL); 15157996a778SMike Christie if (conn->mgmtqueue == ERR_PTR(-ENOMEM)) 15167996a778SMike Christie goto mgmtqueue_alloc_fail; 15177996a778SMike Christie 1518c4028958SDavid Howells INIT_WORK(&conn->xmitwork, iscsi_xmitworker); 15197996a778SMike Christie 15207996a778SMike Christie /* allocate login_mtask used for the login/text sequences */ 15217996a778SMike Christie spin_lock_bh(&session->lock); 15227996a778SMike Christie if (!__kfifo_get(session->mgmtpool.queue, 15237996a778SMike Christie (void*)&conn->login_mtask, 15247996a778SMike Christie sizeof(void*))) { 15257996a778SMike Christie spin_unlock_bh(&session->lock); 15267996a778SMike Christie goto login_mtask_alloc_fail; 15277996a778SMike Christie } 15287996a778SMike Christie spin_unlock_bh(&session->lock); 15297996a778SMike Christie 1530bf32ed33SMike Christie data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); 1531d36ab6f3SMike Christie if (!data) 1532d36ab6f3SMike Christie goto login_mtask_data_alloc_fail; 1533c8dc1e52SMike Christie conn->login_mtask->data = conn->data = data; 1534d36ab6f3SMike Christie 15357996a778SMike Christie init_timer(&conn->tmabort_timer); 15367996a778SMike Christie mutex_init(&conn->xmitmutex); 15377996a778SMike Christie init_waitqueue_head(&conn->ehwait); 15387996a778SMike Christie 15397996a778SMike Christie return cls_conn; 15407996a778SMike Christie 1541d36ab6f3SMike Christie login_mtask_data_alloc_fail: 1542d36ab6f3SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 1543d36ab6f3SMike Christie sizeof(void*)); 15447996a778SMike Christie login_mtask_alloc_fail: 15457996a778SMike Christie kfifo_free(conn->mgmtqueue); 15467996a778SMike Christie mgmtqueue_alloc_fail: 15477996a778SMike Christie kfifo_free(conn->immqueue); 15487996a778SMike Christie immqueue_alloc_fail: 15497996a778SMike Christie iscsi_destroy_conn(cls_conn); 15507996a778SMike Christie return NULL; 15517996a778SMike Christie } 15527996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_setup); 15537996a778SMike Christie 15547996a778SMike Christie /** 15557996a778SMike Christie * iscsi_conn_teardown - teardown iscsi connection 15567996a778SMike Christie * cls_conn: iscsi class connection 15577996a778SMike Christie * 15587996a778SMike Christie * TODO: we may need to make this into a two step process 15597996a778SMike Christie * like scsi-mls remove + put host 15607996a778SMike Christie */ 15617996a778SMike Christie void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) 15627996a778SMike Christie { 15637996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 15647996a778SMike Christie struct iscsi_session *session = conn->session; 15657996a778SMike Christie unsigned long flags; 15667996a778SMike Christie 15677996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 156867a61114SMike Christie mutex_lock(&conn->xmitmutex); 15697996a778SMike Christie 15707996a778SMike Christie spin_lock_bh(&session->lock); 15717996a778SMike Christie conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; 15727996a778SMike Christie if (session->leadconn == conn) { 15737996a778SMike Christie /* 15747996a778SMike Christie * leading connection? then give up on recovery. 15757996a778SMike Christie */ 15767996a778SMike Christie session->state = ISCSI_STATE_TERMINATE; 15777996a778SMike Christie wake_up(&conn->ehwait); 15787996a778SMike Christie } 15797996a778SMike Christie spin_unlock_bh(&session->lock); 15807996a778SMike Christie 15817996a778SMike Christie mutex_unlock(&conn->xmitmutex); 15827996a778SMike Christie 15837996a778SMike Christie /* 15847996a778SMike Christie * Block until all in-progress commands for this connection 15857996a778SMike Christie * time out or fail. 15867996a778SMike Christie */ 15877996a778SMike Christie for (;;) { 15887996a778SMike Christie spin_lock_irqsave(session->host->host_lock, flags); 15897996a778SMike Christie if (!session->host->host_busy) { /* OK for ERL == 0 */ 15907996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 15917996a778SMike Christie break; 15927996a778SMike Christie } 15937996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 15947996a778SMike Christie msleep_interruptible(500); 1595be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " 1596be2df72eSOr Gerlitz "host_failed %d\n", session->host->host_busy, 1597be2df72eSOr Gerlitz session->host->host_failed); 15987996a778SMike Christie /* 15997996a778SMike Christie * force eh_abort() to unblock 16007996a778SMike Christie */ 16017996a778SMike Christie wake_up(&conn->ehwait); 16027996a778SMike Christie } 16037996a778SMike Christie 1604779ea120SMike Christie /* flush queued up work because we free the connection below */ 1605779ea120SMike Christie scsi_flush_work(session->host); 1606779ea120SMike Christie 16077996a778SMike Christie spin_lock_bh(&session->lock); 1608c8dc1e52SMike Christie kfree(conn->data); 1609f3ff0c36SMike Christie kfree(conn->persistent_address); 16107996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 16117996a778SMike Christie sizeof(void*)); 161298644047SMike Christie if (session->leadconn == conn) { 16137996a778SMike Christie session->leadconn = NULL; 16147996a778SMike Christie /* no connections exits.. reset sequencing */ 16157996a778SMike Christie session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1; 161698644047SMike Christie } 16177996a778SMike Christie spin_unlock_bh(&session->lock); 16187996a778SMike Christie 16197996a778SMike Christie kfifo_free(conn->immqueue); 16207996a778SMike Christie kfifo_free(conn->mgmtqueue); 16217996a778SMike Christie 16227996a778SMike Christie iscsi_destroy_conn(cls_conn); 16237996a778SMike Christie } 16247996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_teardown); 16257996a778SMike Christie 16267996a778SMike Christie int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) 16277996a778SMike Christie { 16287996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 16297996a778SMike Christie struct iscsi_session *session = conn->session; 16307996a778SMike Christie 1631ffd0436eSMike Christie if (!session) { 16327996a778SMike Christie printk(KERN_ERR "iscsi: can't start unbound connection\n"); 16337996a778SMike Christie return -EPERM; 16347996a778SMike Christie } 16357996a778SMike Christie 1636db98ccdeSMike Christie if ((session->imm_data_en || !session->initial_r2t_en) && 1637db98ccdeSMike Christie session->first_burst > session->max_burst) { 1638ffd0436eSMike Christie printk("iscsi: invalid burst lengths: " 1639ffd0436eSMike Christie "first_burst %d max_burst %d\n", 1640ffd0436eSMike Christie session->first_burst, session->max_burst); 1641ffd0436eSMike Christie return -EINVAL; 1642ffd0436eSMike Christie } 1643ffd0436eSMike Christie 16447996a778SMike Christie spin_lock_bh(&session->lock); 16457996a778SMike Christie conn->c_stage = ISCSI_CONN_STARTED; 16467996a778SMike Christie session->state = ISCSI_STATE_LOGGED_IN; 16477996a778SMike Christie 16487996a778SMike Christie switch(conn->stop_stage) { 16497996a778SMike Christie case STOP_CONN_RECOVER: 16507996a778SMike Christie /* 16517996a778SMike Christie * unblock eh_abort() if it is blocked. re-try all 16527996a778SMike Christie * commands after successful recovery 16537996a778SMike Christie */ 16547996a778SMike Christie conn->stop_stage = 0; 16557996a778SMike Christie conn->tmabort_state = TMABORT_INITIAL; 16567996a778SMike Christie session->age++; 16577996a778SMike Christie spin_unlock_bh(&session->lock); 16587996a778SMike Christie 16597996a778SMike Christie iscsi_unblock_session(session_to_cls(session)); 16607996a778SMike Christie wake_up(&conn->ehwait); 16617996a778SMike Christie return 0; 16627996a778SMike Christie case STOP_CONN_TERM: 16637996a778SMike Christie conn->stop_stage = 0; 16647996a778SMike Christie break; 16657996a778SMike Christie default: 16667996a778SMike Christie break; 16677996a778SMike Christie } 16687996a778SMike Christie spin_unlock_bh(&session->lock); 16697996a778SMike Christie 16707996a778SMike Christie return 0; 16717996a778SMike Christie } 16727996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_start); 16737996a778SMike Christie 16747996a778SMike Christie static void 16757996a778SMike Christie flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) 16767996a778SMike Christie { 16777996a778SMike Christie struct iscsi_mgmt_task *mtask, *tmp; 16787996a778SMike Christie 16797996a778SMike Christie /* handle pending */ 16807996a778SMike Christie while (__kfifo_get(conn->immqueue, (void*)&mtask, sizeof(void*)) || 16817996a778SMike Christie __kfifo_get(conn->mgmtqueue, (void*)&mtask, sizeof(void*))) { 16827996a778SMike Christie if (mtask == conn->login_mtask) 16837996a778SMike Christie continue; 16847996a778SMike Christie debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); 16857996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&mtask, 16867996a778SMike Christie sizeof(void*)); 16877996a778SMike Christie } 16887996a778SMike Christie 16897996a778SMike Christie /* handle running */ 16907996a778SMike Christie list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { 16917996a778SMike Christie debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); 1692ed2abc7fSMike Christie list_del(&mtask->running); 1693ed2abc7fSMike Christie 16947996a778SMike Christie if (mtask == conn->login_mtask) 16957996a778SMike Christie continue; 1696ed2abc7fSMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&mtask, 16977996a778SMike Christie sizeof(void*)); 16987996a778SMike Christie } 16997996a778SMike Christie 17007996a778SMike Christie conn->mtask = NULL; 17017996a778SMike Christie } 17027996a778SMike Christie 17037996a778SMike Christie /* Fail commands. Mutex and session lock held and recv side suspended */ 17047996a778SMike Christie static void fail_all_commands(struct iscsi_conn *conn) 17057996a778SMike Christie { 17067996a778SMike Christie struct iscsi_cmd_task *ctask, *tmp; 17077996a778SMike Christie 17087996a778SMike Christie /* flush pending */ 1709b6c395edSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { 17107996a778SMike Christie debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc, 17117996a778SMike Christie ctask->itt); 17127996a778SMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 17137996a778SMike Christie } 17147996a778SMike Christie 17157996a778SMike Christie /* fail all other running */ 17167996a778SMike Christie list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { 17177996a778SMike Christie debug_scsi("failing in progress sc %p itt 0x%x\n", 17187996a778SMike Christie ctask->sc, ctask->itt); 17197996a778SMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 17207996a778SMike Christie } 17217996a778SMike Christie 17227996a778SMike Christie conn->ctask = NULL; 17237996a778SMike Christie } 17247996a778SMike Christie 1725656cffc9SMike Christie static void iscsi_start_session_recovery(struct iscsi_session *session, 17267996a778SMike Christie struct iscsi_conn *conn, int flag) 17277996a778SMike Christie { 1728ed2abc7fSMike Christie int old_stop_stage; 1729ed2abc7fSMike Christie 17307996a778SMike Christie spin_lock_bh(&session->lock); 1731ed2abc7fSMike Christie if (conn->stop_stage == STOP_CONN_TERM) { 17327996a778SMike Christie spin_unlock_bh(&session->lock); 17337996a778SMike Christie return; 17347996a778SMike Christie } 1735ed2abc7fSMike Christie 1736ed2abc7fSMike Christie /* 1737ed2abc7fSMike Christie * When this is called for the in_login state, we only want to clean 173867a61114SMike Christie * up the login task and connection. We do not need to block and set 173967a61114SMike Christie * the recovery state again 1740ed2abc7fSMike Christie */ 174167a61114SMike Christie if (flag == STOP_CONN_TERM) 174267a61114SMike Christie session->state = ISCSI_STATE_TERMINATE; 174367a61114SMike Christie else if (conn->stop_stage != STOP_CONN_RECOVER) 174467a61114SMike Christie session->state = ISCSI_STATE_IN_RECOVERY; 1745ed2abc7fSMike Christie 1746ed2abc7fSMike Christie old_stop_stage = conn->stop_stage; 17477996a778SMike Christie conn->stop_stage = flag; 174867a61114SMike Christie conn->c_stage = ISCSI_CONN_STOPPED; 174967a61114SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 17507996a778SMike Christie spin_unlock_bh(&session->lock); 17517996a778SMike Christie 17521c83469dSMike Christie write_lock_bh(conn->recv_lock); 17531c83469dSMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 17541c83469dSMike Christie write_unlock_bh(conn->recv_lock); 17557996a778SMike Christie 17567996a778SMike Christie mutex_lock(&conn->xmitmutex); 17577996a778SMike Christie /* 17587996a778SMike Christie * for connection level recovery we should not calculate 17597996a778SMike Christie * header digest. conn->hdr_size used for optimization 17607996a778SMike Christie * in hdr_extract() and will be re-negotiated at 17617996a778SMike Christie * set_param() time. 17627996a778SMike Christie */ 17637996a778SMike Christie if (flag == STOP_CONN_RECOVER) { 17647996a778SMike Christie conn->hdrdgst_en = 0; 17657996a778SMike Christie conn->datadgst_en = 0; 1766656cffc9SMike Christie if (session->state == ISCSI_STATE_IN_RECOVERY && 176767a61114SMike Christie old_stop_stage != STOP_CONN_RECOVER) { 176867a61114SMike Christie debug_scsi("blocking session\n"); 17697996a778SMike Christie iscsi_block_session(session_to_cls(session)); 17707996a778SMike Christie } 177167a61114SMike Christie } 1772656cffc9SMike Christie 1773656cffc9SMike Christie /* 1774656cffc9SMike Christie * flush queues. 1775656cffc9SMike Christie */ 1776656cffc9SMike Christie spin_lock_bh(&session->lock); 1777656cffc9SMike Christie fail_all_commands(conn); 1778656cffc9SMike Christie flush_control_queues(session, conn); 1779656cffc9SMike Christie spin_unlock_bh(&session->lock); 1780656cffc9SMike Christie 17817996a778SMike Christie mutex_unlock(&conn->xmitmutex); 17827996a778SMike Christie } 17837996a778SMike Christie 17847996a778SMike Christie void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 17857996a778SMike Christie { 17867996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 17877996a778SMike Christie struct iscsi_session *session = conn->session; 17887996a778SMike Christie 17897996a778SMike Christie switch (flag) { 17907996a778SMike Christie case STOP_CONN_RECOVER: 17917996a778SMike Christie case STOP_CONN_TERM: 17927996a778SMike Christie iscsi_start_session_recovery(session, conn, flag); 17938d2860b3SMike Christie break; 17947996a778SMike Christie default: 1795be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); 17967996a778SMike Christie } 17977996a778SMike Christie } 17987996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_stop); 17997996a778SMike Christie 18007996a778SMike Christie int iscsi_conn_bind(struct iscsi_cls_session *cls_session, 18017996a778SMike Christie struct iscsi_cls_conn *cls_conn, int is_leading) 18027996a778SMike Christie { 18037996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 180498644047SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 18057996a778SMike Christie 18067996a778SMike Christie spin_lock_bh(&session->lock); 18077996a778SMike Christie if (is_leading) 18087996a778SMike Christie session->leadconn = conn; 180998644047SMike Christie spin_unlock_bh(&session->lock); 18107996a778SMike Christie 18117996a778SMike Christie /* 18127996a778SMike Christie * Unblock xmitworker(), Login Phase will pass through. 18137996a778SMike Christie */ 18147996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 18157996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 18167996a778SMike Christie return 0; 18177996a778SMike Christie } 18187996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_bind); 18197996a778SMike Christie 1820a54a52caSMike Christie 1821a54a52caSMike Christie int iscsi_set_param(struct iscsi_cls_conn *cls_conn, 1822a54a52caSMike Christie enum iscsi_param param, char *buf, int buflen) 1823a54a52caSMike Christie { 1824a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 1825a54a52caSMike Christie struct iscsi_session *session = conn->session; 1826a54a52caSMike Christie uint32_t value; 1827a54a52caSMike Christie 1828a54a52caSMike Christie switch(param) { 1829a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 1830a54a52caSMike Christie sscanf(buf, "%d", &conn->max_recv_dlength); 1831a54a52caSMike Christie break; 1832a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 1833a54a52caSMike Christie sscanf(buf, "%d", &conn->max_xmit_dlength); 1834a54a52caSMike Christie break; 1835a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 1836a54a52caSMike Christie sscanf(buf, "%d", &conn->hdrdgst_en); 1837a54a52caSMike Christie break; 1838a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 1839a54a52caSMike Christie sscanf(buf, "%d", &conn->datadgst_en); 1840a54a52caSMike Christie break; 1841a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 1842a54a52caSMike Christie sscanf(buf, "%d", &session->initial_r2t_en); 1843a54a52caSMike Christie break; 1844a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 1845a54a52caSMike Christie sscanf(buf, "%d", &session->max_r2t); 1846a54a52caSMike Christie break; 1847a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 1848a54a52caSMike Christie sscanf(buf, "%d", &session->imm_data_en); 1849a54a52caSMike Christie break; 1850a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 1851a54a52caSMike Christie sscanf(buf, "%d", &session->first_burst); 1852a54a52caSMike Christie break; 1853a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 1854a54a52caSMike Christie sscanf(buf, "%d", &session->max_burst); 1855a54a52caSMike Christie break; 1856a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 1857a54a52caSMike Christie sscanf(buf, "%d", &session->pdu_inorder_en); 1858a54a52caSMike Christie break; 1859a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 1860a54a52caSMike Christie sscanf(buf, "%d", &session->dataseq_inorder_en); 1861a54a52caSMike Christie break; 1862a54a52caSMike Christie case ISCSI_PARAM_ERL: 1863a54a52caSMike Christie sscanf(buf, "%d", &session->erl); 1864a54a52caSMike Christie break; 1865a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 1866a54a52caSMike Christie sscanf(buf, "%d", &value); 1867a54a52caSMike Christie BUG_ON(value); 1868a54a52caSMike Christie break; 1869a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 1870a54a52caSMike Christie sscanf(buf, "%d", &value); 1871a54a52caSMike Christie BUG_ON(value); 1872a54a52caSMike Christie break; 1873a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 1874a54a52caSMike Christie sscanf(buf, "%u", &conn->exp_statsn); 1875a54a52caSMike Christie break; 1876b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 1877b2c64167SMike Christie kfree(session->username); 1878b2c64167SMike Christie session->username = kstrdup(buf, GFP_KERNEL); 1879b2c64167SMike Christie if (!session->username) 1880b2c64167SMike Christie return -ENOMEM; 1881b2c64167SMike Christie break; 1882b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 1883b2c64167SMike Christie kfree(session->username_in); 1884b2c64167SMike Christie session->username_in = kstrdup(buf, GFP_KERNEL); 1885b2c64167SMike Christie if (!session->username_in) 1886b2c64167SMike Christie return -ENOMEM; 1887b2c64167SMike Christie break; 1888b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 1889b2c64167SMike Christie kfree(session->password); 1890b2c64167SMike Christie session->password = kstrdup(buf, GFP_KERNEL); 1891b2c64167SMike Christie if (!session->password) 1892b2c64167SMike Christie return -ENOMEM; 1893b2c64167SMike Christie break; 1894b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 1895b2c64167SMike Christie kfree(session->password_in); 1896b2c64167SMike Christie session->password_in = kstrdup(buf, GFP_KERNEL); 1897b2c64167SMike Christie if (!session->password_in) 1898b2c64167SMike Christie return -ENOMEM; 1899b2c64167SMike Christie break; 1900a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 1901a54a52caSMike Christie /* this should not change between logins */ 1902a54a52caSMike Christie if (session->targetname) 1903a54a52caSMike Christie break; 1904a54a52caSMike Christie 1905a54a52caSMike Christie session->targetname = kstrdup(buf, GFP_KERNEL); 1906a54a52caSMike Christie if (!session->targetname) 1907a54a52caSMike Christie return -ENOMEM; 1908a54a52caSMike Christie break; 1909a54a52caSMike Christie case ISCSI_PARAM_TPGT: 1910a54a52caSMike Christie sscanf(buf, "%d", &session->tpgt); 1911a54a52caSMike Christie break; 1912a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 1913a54a52caSMike Christie sscanf(buf, "%d", &conn->persistent_port); 1914a54a52caSMike Christie break; 1915a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 1916a54a52caSMike Christie /* 1917a54a52caSMike Christie * this is the address returned in discovery so it should 1918a54a52caSMike Christie * not change between logins. 1919a54a52caSMike Christie */ 1920a54a52caSMike Christie if (conn->persistent_address) 1921a54a52caSMike Christie break; 1922a54a52caSMike Christie 1923a54a52caSMike Christie conn->persistent_address = kstrdup(buf, GFP_KERNEL); 1924a54a52caSMike Christie if (!conn->persistent_address) 1925a54a52caSMike Christie return -ENOMEM; 1926a54a52caSMike Christie break; 1927a54a52caSMike Christie default: 1928a54a52caSMike Christie return -ENOSYS; 1929a54a52caSMike Christie } 1930a54a52caSMike Christie 1931a54a52caSMike Christie return 0; 1932a54a52caSMike Christie } 1933a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_set_param); 1934a54a52caSMike Christie 1935a54a52caSMike Christie int iscsi_session_get_param(struct iscsi_cls_session *cls_session, 1936a54a52caSMike Christie enum iscsi_param param, char *buf) 1937a54a52caSMike Christie { 1938a54a52caSMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 1939a54a52caSMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 1940a54a52caSMike Christie int len; 1941a54a52caSMike Christie 1942a54a52caSMike Christie switch(param) { 1943a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 1944a54a52caSMike Christie len = sprintf(buf, "%d\n", session->initial_r2t_en); 1945a54a52caSMike Christie break; 1946a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 1947a54a52caSMike Christie len = sprintf(buf, "%hu\n", session->max_r2t); 1948a54a52caSMike Christie break; 1949a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 1950a54a52caSMike Christie len = sprintf(buf, "%d\n", session->imm_data_en); 1951a54a52caSMike Christie break; 1952a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 1953a54a52caSMike Christie len = sprintf(buf, "%u\n", session->first_burst); 1954a54a52caSMike Christie break; 1955a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 1956a54a52caSMike Christie len = sprintf(buf, "%u\n", session->max_burst); 1957a54a52caSMike Christie break; 1958a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 1959a54a52caSMike Christie len = sprintf(buf, "%d\n", session->pdu_inorder_en); 1960a54a52caSMike Christie break; 1961a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 1962a54a52caSMike Christie len = sprintf(buf, "%d\n", session->dataseq_inorder_en); 1963a54a52caSMike Christie break; 1964a54a52caSMike Christie case ISCSI_PARAM_ERL: 1965a54a52caSMike Christie len = sprintf(buf, "%d\n", session->erl); 1966a54a52caSMike Christie break; 1967a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 1968a54a52caSMike Christie len = sprintf(buf, "%s\n", session->targetname); 1969a54a52caSMike Christie break; 1970a54a52caSMike Christie case ISCSI_PARAM_TPGT: 1971a54a52caSMike Christie len = sprintf(buf, "%d\n", session->tpgt); 1972a54a52caSMike Christie break; 1973b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 1974b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username); 1975b2c64167SMike Christie break; 1976b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 1977b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username_in); 1978b2c64167SMike Christie break; 1979b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 1980b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password); 1981b2c64167SMike Christie break; 1982b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 1983b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password_in); 1984b2c64167SMike Christie break; 1985a54a52caSMike Christie default: 1986a54a52caSMike Christie return -ENOSYS; 1987a54a52caSMike Christie } 1988a54a52caSMike Christie 1989a54a52caSMike Christie return len; 1990a54a52caSMike Christie } 1991a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_session_get_param); 1992a54a52caSMike Christie 1993a54a52caSMike Christie int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, 1994a54a52caSMike Christie enum iscsi_param param, char *buf) 1995a54a52caSMike Christie { 1996a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 1997a54a52caSMike Christie int len; 1998a54a52caSMike Christie 1999a54a52caSMike Christie switch(param) { 2000a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 2001a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_recv_dlength); 2002a54a52caSMike Christie break; 2003a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 2004a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_xmit_dlength); 2005a54a52caSMike Christie break; 2006a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 2007a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->hdrdgst_en); 2008a54a52caSMike Christie break; 2009a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 2010a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->datadgst_en); 2011a54a52caSMike Christie break; 2012a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 2013a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ifmarker_en); 2014a54a52caSMike Christie break; 2015a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 2016a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ofmarker_en); 2017a54a52caSMike Christie break; 2018a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 2019a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->exp_statsn); 2020a54a52caSMike Christie break; 2021a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2022a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->persistent_port); 2023a54a52caSMike Christie break; 2024a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 2025a54a52caSMike Christie len = sprintf(buf, "%s\n", conn->persistent_address); 2026a54a52caSMike Christie break; 2027a54a52caSMike Christie default: 2028a54a52caSMike Christie return -ENOSYS; 2029a54a52caSMike Christie } 2030a54a52caSMike Christie 2031a54a52caSMike Christie return len; 2032a54a52caSMike Christie } 2033a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_get_param); 2034a54a52caSMike Christie 20350801c242SMike Christie int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, 20360801c242SMike Christie char *buf) 20370801c242SMike Christie { 20380801c242SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 20390801c242SMike Christie int len; 20400801c242SMike Christie 20410801c242SMike Christie switch (param) { 20420801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 20430801c242SMike Christie if (!session->hwaddress) 20440801c242SMike Christie len = sprintf(buf, "%s\n", "default"); 20450801c242SMike Christie else 20460801c242SMike Christie len = sprintf(buf, "%s\n", session->hwaddress); 20470801c242SMike Christie break; 20488ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 20498ad5781aSMike Christie if (!session->initiatorname) 20508ad5781aSMike Christie len = sprintf(buf, "%s\n", "unknown"); 20518ad5781aSMike Christie else 20528ad5781aSMike Christie len = sprintf(buf, "%s\n", session->initiatorname); 20538ad5781aSMike Christie break; 20548ad5781aSMike Christie 20550801c242SMike Christie default: 20560801c242SMike Christie return -ENOSYS; 20570801c242SMike Christie } 20580801c242SMike Christie 20590801c242SMike Christie return len; 20600801c242SMike Christie } 20610801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_get_param); 20620801c242SMike Christie 20630801c242SMike Christie int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, 20640801c242SMike Christie char *buf, int buflen) 20650801c242SMike Christie { 20660801c242SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 20670801c242SMike Christie 20680801c242SMike Christie switch (param) { 20690801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 20700801c242SMike Christie if (!session->hwaddress) 20710801c242SMike Christie session->hwaddress = kstrdup(buf, GFP_KERNEL); 20720801c242SMike Christie break; 20738ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 20748ad5781aSMike Christie if (!session->initiatorname) 20758ad5781aSMike Christie session->initiatorname = kstrdup(buf, GFP_KERNEL); 20768ad5781aSMike Christie break; 20770801c242SMike Christie default: 20780801c242SMike Christie return -ENOSYS; 20790801c242SMike Christie } 20800801c242SMike Christie 20810801c242SMike Christie return 0; 20820801c242SMike Christie } 20830801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_set_param); 20840801c242SMike Christie 20857996a778SMike Christie MODULE_AUTHOR("Mike Christie"); 20867996a778SMike Christie MODULE_DESCRIPTION("iSCSI library functions"); 20877996a778SMike Christie MODULE_LICENSE("GPL"); 2088