17996a778SMike Christie /* 27996a778SMike Christie * iSCSI lib functions 37996a778SMike Christie * 47996a778SMike Christie * Copyright (C) 2006 Red Hat, Inc. All rights reserved. 57996a778SMike Christie * Copyright (C) 2004 - 2006 Mike Christie 67996a778SMike Christie * Copyright (C) 2004 - 2005 Dmitry Yusupov 77996a778SMike Christie * Copyright (C) 2004 - 2005 Alex Aizman 87996a778SMike Christie * maintained by open-iscsi@googlegroups.com 97996a778SMike Christie * 107996a778SMike Christie * This program is free software; you can redistribute it and/or modify 117996a778SMike Christie * it under the terms of the GNU General Public License as published by 127996a778SMike Christie * the Free Software Foundation; either version 2 of the License, or 137996a778SMike Christie * (at your option) any later version. 147996a778SMike Christie * 157996a778SMike Christie * This program is distributed in the hope that it will be useful, 167996a778SMike Christie * but WITHOUT ANY WARRANTY; without even the implied warranty of 177996a778SMike Christie * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 187996a778SMike Christie * GNU General Public License for more details. 197996a778SMike Christie * 207996a778SMike Christie * You should have received a copy of the GNU General Public License 217996a778SMike Christie * along with this program; if not, write to the Free Software 227996a778SMike Christie * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 237996a778SMike Christie */ 247996a778SMike Christie #include <linux/types.h> 257996a778SMike Christie #include <linux/kfifo.h> 267996a778SMike Christie #include <linux/delay.h> 278eb00539SMike Christie #include <asm/unaligned.h> 287996a778SMike Christie #include <net/tcp.h> 297996a778SMike Christie #include <scsi/scsi_cmnd.h> 307996a778SMike Christie #include <scsi/scsi_device.h> 317996a778SMike Christie #include <scsi/scsi_eh.h> 327996a778SMike Christie #include <scsi/scsi_tcq.h> 337996a778SMike Christie #include <scsi/scsi_host.h> 347996a778SMike Christie #include <scsi/scsi.h> 357996a778SMike Christie #include <scsi/iscsi_proto.h> 367996a778SMike Christie #include <scsi/scsi_transport.h> 377996a778SMike Christie #include <scsi/scsi_transport_iscsi.h> 387996a778SMike Christie #include <scsi/libiscsi.h> 397996a778SMike Christie 407996a778SMike Christie struct iscsi_session * 417996a778SMike Christie class_to_transport_session(struct iscsi_cls_session *cls_session) 427996a778SMike Christie { 437996a778SMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 447996a778SMike Christie return iscsi_hostdata(shost->hostdata); 457996a778SMike Christie } 467996a778SMike Christie EXPORT_SYMBOL_GPL(class_to_transport_session); 477996a778SMike Christie 4877a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ 4977a23c21SMike Christie #define SNA32_CHECK 2147483648UL 507996a778SMike Christie 5177a23c21SMike Christie static int iscsi_sna_lt(u32 n1, u32 n2) 5277a23c21SMike Christie { 5377a23c21SMike Christie return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || 5477a23c21SMike Christie (n1 > n2 && (n2 - n1 < SNA32_CHECK))); 5577a23c21SMike Christie } 5677a23c21SMike Christie 5777a23c21SMike Christie /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ 5877a23c21SMike Christie static int iscsi_sna_lte(u32 n1, u32 n2) 5977a23c21SMike Christie { 6077a23c21SMike Christie return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || 6177a23c21SMike Christie (n1 > n2 && (n2 - n1 < SNA32_CHECK))); 6277a23c21SMike Christie } 6377a23c21SMike Christie 6477a23c21SMike Christie void 6577a23c21SMike Christie iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) 667996a778SMike Christie { 677996a778SMike Christie uint32_t max_cmdsn = be32_to_cpu(hdr->max_cmdsn); 687996a778SMike Christie uint32_t exp_cmdsn = be32_to_cpu(hdr->exp_cmdsn); 697996a778SMike Christie 7077a23c21SMike Christie /* 7177a23c21SMike Christie * standard specifies this check for when to update expected and 7277a23c21SMike Christie * max sequence numbers 7377a23c21SMike Christie */ 7477a23c21SMike Christie if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1)) 7577a23c21SMike Christie return; 7677a23c21SMike Christie 7777a23c21SMike Christie if (exp_cmdsn != session->exp_cmdsn && 7877a23c21SMike Christie !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) 797996a778SMike Christie session->exp_cmdsn = exp_cmdsn; 807996a778SMike Christie 8177a23c21SMike Christie if (max_cmdsn != session->max_cmdsn && 8277a23c21SMike Christie !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { 8377a23c21SMike Christie session->max_cmdsn = max_cmdsn; 8477a23c21SMike Christie /* 8577a23c21SMike Christie * if the window closed with IO queued, then kick the 8677a23c21SMike Christie * xmit thread 8777a23c21SMike Christie */ 8877a23c21SMike Christie if (!list_empty(&session->leadconn->xmitqueue) || 89843c0a8aSMike Christie !list_empty(&session->leadconn->mgmtqueue)) 9077a23c21SMike Christie scsi_queue_work(session->host, 9177a23c21SMike Christie &session->leadconn->xmitwork); 927996a778SMike Christie } 9377a23c21SMike Christie } 9477a23c21SMike Christie EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); 957996a778SMike Christie 967996a778SMike Christie void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, 97ffd0436eSMike Christie struct iscsi_data *hdr) 987996a778SMike Christie { 997996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 1007996a778SMike Christie 1017996a778SMike Christie memset(hdr, 0, sizeof(struct iscsi_data)); 1027996a778SMike Christie hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); 1037996a778SMike Christie hdr->datasn = cpu_to_be32(ctask->unsol_datasn); 1047996a778SMike Christie ctask->unsol_datasn++; 1057996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; 1067996a778SMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 1077996a778SMike Christie 1087996a778SMike Christie hdr->itt = ctask->hdr->itt; 1097996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 110ffd0436eSMike Christie hdr->offset = cpu_to_be32(ctask->unsol_offset); 1117996a778SMike Christie 1127996a778SMike Christie if (ctask->unsol_count > conn->max_xmit_dlength) { 1137996a778SMike Christie hton24(hdr->dlength, conn->max_xmit_dlength); 1147996a778SMike Christie ctask->data_count = conn->max_xmit_dlength; 115ffd0436eSMike Christie ctask->unsol_offset += ctask->data_count; 1167996a778SMike Christie hdr->flags = 0; 1177996a778SMike Christie } else { 1187996a778SMike Christie hton24(hdr->dlength, ctask->unsol_count); 1197996a778SMike Christie ctask->data_count = ctask->unsol_count; 1207996a778SMike Christie hdr->flags = ISCSI_FLAG_CMD_FINAL; 1217996a778SMike Christie } 1227996a778SMike Christie } 1237996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); 1247996a778SMike Christie 1257996a778SMike Christie /** 1267996a778SMike Christie * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu 1277996a778SMike Christie * @ctask: iscsi cmd task 1287996a778SMike Christie * 1297996a778SMike Christie * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set 1307996a778SMike Christie * fields like dlength or final based on how much data it sends 1317996a778SMike Christie */ 1327996a778SMike Christie static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) 1337996a778SMike Christie { 1347996a778SMike Christie struct iscsi_conn *conn = ctask->conn; 1357996a778SMike Christie struct iscsi_session *session = conn->session; 1367996a778SMike Christie struct iscsi_cmd *hdr = ctask->hdr; 1377996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 1387996a778SMike Christie 1397996a778SMike Christie hdr->opcode = ISCSI_OP_SCSI_CMD; 1407996a778SMike Christie hdr->flags = ISCSI_ATTR_SIMPLE; 1417996a778SMike Christie int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 142b4377356SAl Viro hdr->itt = build_itt(ctask->itt, conn->id, session->age); 1431c138991SFUJITA Tomonori hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); 1447996a778SMike Christie hdr->cmdsn = cpu_to_be32(session->cmdsn); 1457996a778SMike Christie session->cmdsn++; 1467996a778SMike Christie hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); 1477996a778SMike Christie memcpy(hdr->cdb, sc->cmnd, sc->cmd_len); 148d473cc7fSMike Christie if (sc->cmd_len < MAX_COMMAND_SIZE) 149d473cc7fSMike Christie memset(&hdr->cdb[sc->cmd_len], 0, 150d473cc7fSMike Christie MAX_COMMAND_SIZE - sc->cmd_len); 1517996a778SMike Christie 152ffd0436eSMike Christie ctask->data_count = 0; 153218432c6SMike Christie ctask->imm_count = 0; 1547996a778SMike Christie if (sc->sc_data_direction == DMA_TO_DEVICE) { 1557996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_WRITE; 1567996a778SMike Christie /* 1577996a778SMike Christie * Write counters: 1587996a778SMike Christie * 1597996a778SMike Christie * imm_count bytes to be sent right after 1607996a778SMike Christie * SCSI PDU Header 1617996a778SMike Christie * 1627996a778SMike Christie * unsol_count bytes(as Data-Out) to be sent 1637996a778SMike Christie * without R2T ack right after 1647996a778SMike Christie * immediate data 1657996a778SMike Christie * 1667996a778SMike Christie * r2t_data_count bytes to be sent via R2T ack's 1677996a778SMike Christie * 1687996a778SMike Christie * pad_count bytes to be sent as zero-padding 1697996a778SMike Christie */ 1707996a778SMike Christie ctask->unsol_count = 0; 171ffd0436eSMike Christie ctask->unsol_offset = 0; 1727996a778SMike Christie ctask->unsol_datasn = 0; 1737996a778SMike Christie 1747996a778SMike Christie if (session->imm_data_en) { 1751c138991SFUJITA Tomonori if (scsi_bufflen(sc) >= session->first_burst) 1767996a778SMike Christie ctask->imm_count = min(session->first_burst, 1777996a778SMike Christie conn->max_xmit_dlength); 1787996a778SMike Christie else 1791c138991SFUJITA Tomonori ctask->imm_count = min(scsi_bufflen(sc), 1807996a778SMike Christie conn->max_xmit_dlength); 1817996a778SMike Christie hton24(ctask->hdr->dlength, ctask->imm_count); 1827996a778SMike Christie } else 1837996a778SMike Christie zero_data(ctask->hdr->dlength); 1847996a778SMike Christie 185ffd0436eSMike Christie if (!session->initial_r2t_en) { 186857ae0bdSMike Christie ctask->unsol_count = min((session->first_burst), 1871c138991SFUJITA Tomonori (scsi_bufflen(sc))) - ctask->imm_count; 188ffd0436eSMike Christie ctask->unsol_offset = ctask->imm_count; 189ffd0436eSMike Christie } 190ffd0436eSMike Christie 1917996a778SMike Christie if (!ctask->unsol_count) 1927996a778SMike Christie /* No unsolicit Data-Out's */ 1937996a778SMike Christie ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1947996a778SMike Christie } else { 1957996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1967996a778SMike Christie zero_data(hdr->dlength); 1977996a778SMike Christie 1987996a778SMike Christie if (sc->sc_data_direction == DMA_FROM_DEVICE) 1997996a778SMike Christie hdr->flags |= ISCSI_FLAG_CMD_READ; 2007996a778SMike Christie } 2017996a778SMike Christie 2027996a778SMike Christie conn->scsicmd_pdus_cnt++; 20377a23c21SMike Christie 20477a23c21SMike Christie debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " 20577a23c21SMike Christie "cmdsn %d win %d]\n", 20677a23c21SMike Christie sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", 2071c138991SFUJITA Tomonori conn->id, sc, sc->cmnd[0], ctask->itt, scsi_bufflen(sc), 20877a23c21SMike Christie session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); 2097996a778SMike Christie } 2107996a778SMike Christie 2117996a778SMike Christie /** 2127996a778SMike Christie * iscsi_complete_command - return command back to scsi-ml 2137996a778SMike Christie * @ctask: iscsi cmd task 2147996a778SMike Christie * 2157996a778SMike Christie * Must be called with session lock. 2167996a778SMike Christie * This function returns the scsi command to scsi-ml and returns 2177996a778SMike Christie * the cmd task to the pool of available cmd tasks. 2187996a778SMike Christie */ 21960ecebf5SMike Christie static void iscsi_complete_command(struct iscsi_cmd_task *ctask) 2207996a778SMike Christie { 22160ecebf5SMike Christie struct iscsi_session *session = ctask->conn->session; 2227996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 2237996a778SMike Christie 224b6c395edSMike Christie ctask->state = ISCSI_TASK_COMPLETED; 2257996a778SMike Christie ctask->sc = NULL; 226f47f2cf5SMike Christie /* SCSI eh reuses commands to verify us */ 227f47f2cf5SMike Christie sc->SCp.ptr = NULL; 2287996a778SMike Christie list_del_init(&ctask->running); 2297996a778SMike Christie __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); 2307996a778SMike Christie sc->scsi_done(sc); 2317996a778SMike Christie } 2327996a778SMike Christie 23360ecebf5SMike Christie static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) 23460ecebf5SMike Christie { 23560ecebf5SMike Christie atomic_inc(&ctask->refcount); 23660ecebf5SMike Christie } 23760ecebf5SMike Christie 23860ecebf5SMike Christie static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) 23960ecebf5SMike Christie { 240e648f63cSMike Christie if (atomic_dec_and_test(&ctask->refcount)) 24160ecebf5SMike Christie iscsi_complete_command(ctask); 24260ecebf5SMike Christie } 24360ecebf5SMike Christie 2447996a778SMike Christie /** 2457996a778SMike Christie * iscsi_cmd_rsp - SCSI Command Response processing 2467996a778SMike Christie * @conn: iscsi connection 2477996a778SMike Christie * @hdr: iscsi header 2487996a778SMike Christie * @ctask: scsi command task 2497996a778SMike Christie * @data: cmd data buffer 2507996a778SMike Christie * @datalen: len of buffer 2517996a778SMike Christie * 2527996a778SMike Christie * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and 2537996a778SMike Christie * then completes the command and task. 2547996a778SMike Christie **/ 25577a23c21SMike Christie static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 2567996a778SMike Christie struct iscsi_cmd_task *ctask, char *data, 2577996a778SMike Christie int datalen) 2587996a778SMike Christie { 2597996a778SMike Christie struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; 2607996a778SMike Christie struct iscsi_session *session = conn->session; 2617996a778SMike Christie struct scsi_cmnd *sc = ctask->sc; 2627996a778SMike Christie 26377a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); 2647996a778SMike Christie conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; 2657996a778SMike Christie 2667996a778SMike Christie sc->result = (DID_OK << 16) | rhdr->cmd_status; 2677996a778SMike Christie 2687996a778SMike Christie if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { 2697996a778SMike Christie sc->result = DID_ERROR << 16; 2707996a778SMike Christie goto out; 2717996a778SMike Christie } 2727996a778SMike Christie 2737996a778SMike Christie if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { 2749b80cb4bSMike Christie uint16_t senselen; 2757996a778SMike Christie 2767996a778SMike Christie if (datalen < 2) { 2777996a778SMike Christie invalid_datalen: 278be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " 279be2df72eSOr Gerlitz "invalid data buffer size of %d\n", datalen); 2807996a778SMike Christie sc->result = DID_BAD_TARGET << 16; 2817996a778SMike Christie goto out; 2827996a778SMike Christie } 2837996a778SMike Christie 2848eb00539SMike Christie senselen = be16_to_cpu(get_unaligned((__be16 *) data)); 2857996a778SMike Christie if (datalen < senselen) 2867996a778SMike Christie goto invalid_datalen; 2877996a778SMike Christie 2887996a778SMike Christie memcpy(sc->sense_buffer, data + 2, 2899b80cb4bSMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 2907996a778SMike Christie debug_scsi("copied %d bytes of sense\n", 2918eb00539SMike Christie min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); 2927996a778SMike Christie } 2937996a778SMike Christie 2947207fea4SBoaz Harrosh if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | 2957207fea4SBoaz Harrosh ISCSI_FLAG_CMD_OVERFLOW)) { 2967996a778SMike Christie int res_count = be32_to_cpu(rhdr->residual_count); 2977996a778SMike Christie 2987207fea4SBoaz Harrosh if (res_count > 0 && 2997207fea4SBoaz Harrosh (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || 3007207fea4SBoaz Harrosh res_count <= scsi_bufflen(sc))) 3011c138991SFUJITA Tomonori scsi_set_resid(sc, res_count); 3027996a778SMike Christie else 3037996a778SMike Christie sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 3047207fea4SBoaz Harrosh } else if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | 3057207fea4SBoaz Harrosh ISCSI_FLAG_CMD_BIDI_OVERFLOW)) 3067996a778SMike Christie sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; 3077996a778SMike Christie 3087996a778SMike Christie out: 3097996a778SMike Christie debug_scsi("done [sc %lx res %d itt 0x%x]\n", 3107996a778SMike Christie (long)sc, sc->result, ctask->itt); 3117996a778SMike Christie conn->scsirsp_pdus_cnt++; 3127996a778SMike Christie 31360ecebf5SMike Christie __iscsi_put_ctask(ctask); 3147996a778SMike Christie } 3157996a778SMike Christie 3167ea8b828SMike Christie static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) 3177ea8b828SMike Christie { 3187ea8b828SMike Christie struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; 3197ea8b828SMike Christie 3207ea8b828SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 3217ea8b828SMike Christie conn->tmfrsp_pdus_cnt++; 3227ea8b828SMike Christie 323843c0a8aSMike Christie if (conn->tmf_state != TMF_QUEUED) 3247ea8b828SMike Christie return; 3257ea8b828SMike Christie 3267ea8b828SMike Christie if (tmf->response == ISCSI_TMF_RSP_COMPLETE) 327843c0a8aSMike Christie conn->tmf_state = TMF_SUCCESS; 3287ea8b828SMike Christie else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) 329843c0a8aSMike Christie conn->tmf_state = TMF_NOT_FOUND; 3307ea8b828SMike Christie else 331843c0a8aSMike Christie conn->tmf_state = TMF_FAILED; 3327ea8b828SMike Christie wake_up(&conn->ehwait); 3337ea8b828SMike Christie } 3347ea8b828SMike Christie 33562f38300SMike Christie static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 33662f38300SMike Christie char *data, int datalen) 33762f38300SMike Christie { 33862f38300SMike Christie struct iscsi_reject *reject = (struct iscsi_reject *)hdr; 33962f38300SMike Christie struct iscsi_hdr rejected_pdu; 34062f38300SMike Christie uint32_t itt; 34162f38300SMike Christie 34262f38300SMike Christie conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; 34362f38300SMike Christie 34462f38300SMike Christie if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) { 34562f38300SMike Christie if (ntoh24(reject->dlength) > datalen) 34662f38300SMike Christie return ISCSI_ERR_PROTO; 34762f38300SMike Christie 34862f38300SMike Christie if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { 34962f38300SMike Christie memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); 350b4377356SAl Viro itt = get_itt(rejected_pdu.itt); 35162f38300SMike Christie printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " 35262f38300SMike Christie "due to DataDigest error.\n", itt, 35362f38300SMike Christie rejected_pdu.opcode); 35462f38300SMike Christie } 35562f38300SMike Christie } 35662f38300SMike Christie return 0; 35762f38300SMike Christie } 35862f38300SMike Christie 3597996a778SMike Christie /** 3607996a778SMike Christie * __iscsi_complete_pdu - complete pdu 3617996a778SMike Christie * @conn: iscsi conn 3627996a778SMike Christie * @hdr: iscsi header 3637996a778SMike Christie * @data: data buffer 3647996a778SMike Christie * @datalen: len of data buffer 3657996a778SMike Christie * 3667996a778SMike Christie * Completes pdu processing by freeing any resources allocated at 3677996a778SMike Christie * queuecommand or send generic. session lock must be held and verify 3687996a778SMike Christie * itt must have been called. 3697996a778SMike Christie */ 3707996a778SMike Christie int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 3717996a778SMike Christie char *data, int datalen) 3727996a778SMike Christie { 3737996a778SMike Christie struct iscsi_session *session = conn->session; 3747996a778SMike Christie int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; 3757996a778SMike Christie struct iscsi_cmd_task *ctask; 3767996a778SMike Christie struct iscsi_mgmt_task *mtask; 3777996a778SMike Christie uint32_t itt; 3787996a778SMike Christie 379b4377356SAl Viro if (hdr->itt != RESERVED_ITT) 380b4377356SAl Viro itt = get_itt(hdr->itt); 3817996a778SMike Christie else 382b4377356SAl Viro itt = ~0U; 3837996a778SMike Christie 3847996a778SMike Christie if (itt < session->cmds_max) { 3857996a778SMike Christie ctask = session->cmds[itt]; 3867996a778SMike Christie 3877996a778SMike Christie debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", 3887996a778SMike Christie opcode, conn->id, ctask->itt, datalen); 3897996a778SMike Christie 3907996a778SMike Christie switch(opcode) { 3917996a778SMike Christie case ISCSI_OP_SCSI_CMD_RSP: 3927996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 39377a23c21SMike Christie iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, 3947996a778SMike Christie datalen); 3957996a778SMike Christie break; 3967996a778SMike Christie case ISCSI_OP_SCSI_DATA_IN: 3977996a778SMike Christie BUG_ON((void*)ctask != ctask->sc->SCp.ptr); 3987996a778SMike Christie if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { 3997996a778SMike Christie conn->scsirsp_pdus_cnt++; 40060ecebf5SMike Christie __iscsi_put_ctask(ctask); 4017996a778SMike Christie } 4027996a778SMike Christie break; 4037996a778SMike Christie case ISCSI_OP_R2T: 4047996a778SMike Christie /* LLD handles this for now */ 4057996a778SMike Christie break; 4067996a778SMike Christie default: 4077996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 4087996a778SMike Christie break; 4097996a778SMike Christie } 4107996a778SMike Christie } else if (itt >= ISCSI_MGMT_ITT_OFFSET && 4117996a778SMike Christie itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { 4127996a778SMike Christie mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; 4137996a778SMike Christie 4147996a778SMike Christie debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", 4157996a778SMike Christie opcode, conn->id, mtask->itt, datalen); 4167996a778SMike Christie 41777a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 4188d2860b3SMike Christie switch(opcode) { 4198d2860b3SMike Christie case ISCSI_OP_LOGOUT_RSP: 420c8dc1e52SMike Christie if (datalen) { 421c8dc1e52SMike Christie rc = ISCSI_ERR_PROTO; 422c8dc1e52SMike Christie break; 423c8dc1e52SMike Christie } 4248d2860b3SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 4258d2860b3SMike Christie /* fall through */ 4268d2860b3SMike Christie case ISCSI_OP_LOGIN_RSP: 4278d2860b3SMike Christie case ISCSI_OP_TEXT_RSP: 4288d2860b3SMike Christie /* 4298d2860b3SMike Christie * login related PDU's exp_statsn is handled in 4308d2860b3SMike Christie * userspace 4318d2860b3SMike Christie */ 43240527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 43340527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 434843c0a8aSMike Christie list_del_init(&mtask->running); 4357996a778SMike Christie if (conn->login_mtask != mtask) 4367996a778SMike Christie __kfifo_put(session->mgmtpool.queue, 4377996a778SMike Christie (void*)&mtask, sizeof(void*)); 4387996a778SMike Christie break; 4397996a778SMike Christie case ISCSI_OP_SCSI_TMFUNC_RSP: 4407996a778SMike Christie if (datalen) { 4417996a778SMike Christie rc = ISCSI_ERR_PROTO; 4427996a778SMike Christie break; 4437996a778SMike Christie } 4448d2860b3SMike Christie 4457ea8b828SMike Christie iscsi_tmf_rsp(conn, hdr); 4467996a778SMike Christie break; 4477996a778SMike Christie case ISCSI_OP_NOOP_IN: 448b4377356SAl Viro if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { 4497996a778SMike Christie rc = ISCSI_ERR_PROTO; 4507996a778SMike Christie break; 4517996a778SMike Christie } 4527996a778SMike Christie conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; 4537996a778SMike Christie 45440527afeSMike Christie if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) 45540527afeSMike Christie rc = ISCSI_ERR_CONN_FAILED; 456843c0a8aSMike Christie list_del_init(&mtask->running); 4577996a778SMike Christie __kfifo_put(session->mgmtpool.queue, 4587996a778SMike Christie (void*)&mtask, sizeof(void*)); 4597996a778SMike Christie break; 4607996a778SMike Christie default: 4617996a778SMike Christie rc = ISCSI_ERR_BAD_OPCODE; 4627996a778SMike Christie break; 4637996a778SMike Christie } 464b4377356SAl Viro } else if (itt == ~0U) { 46577a23c21SMike Christie iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); 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 4957996a778SMike Christie return rc; 4967996a778SMike Christie } 4977996a778SMike Christie EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); 4987996a778SMike Christie 4997996a778SMike Christie int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 5007996a778SMike Christie char *data, int datalen) 5017996a778SMike Christie { 5027996a778SMike Christie int rc; 5037996a778SMike Christie 5047996a778SMike Christie spin_lock(&conn->session->lock); 5057996a778SMike Christie rc = __iscsi_complete_pdu(conn, hdr, data, datalen); 5067996a778SMike Christie spin_unlock(&conn->session->lock); 5077996a778SMike Christie return rc; 5087996a778SMike Christie } 5097996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_complete_pdu); 5107996a778SMike Christie 5117996a778SMike Christie /* verify itt (itt encoding: age+cid+itt) */ 5127996a778SMike Christie int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 5137996a778SMike Christie uint32_t *ret_itt) 5147996a778SMike Christie { 5157996a778SMike Christie struct iscsi_session *session = conn->session; 5167996a778SMike Christie struct iscsi_cmd_task *ctask; 5177996a778SMike Christie uint32_t itt; 5187996a778SMike Christie 519b4377356SAl Viro if (hdr->itt != RESERVED_ITT) { 520b4377356SAl Viro if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != 5217996a778SMike Christie (session->age << ISCSI_AGE_SHIFT)) { 522be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: received itt %x expected " 523b4377356SAl Viro "session age (%x)\n", (__force u32)hdr->itt, 5247996a778SMike Christie session->age & ISCSI_AGE_MASK); 5257996a778SMike Christie return ISCSI_ERR_BAD_ITT; 5267996a778SMike Christie } 5277996a778SMike Christie 528b4377356SAl Viro if (((__force u32)hdr->itt & ISCSI_CID_MASK) != 5297996a778SMike Christie (conn->id << ISCSI_CID_SHIFT)) { 530be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: received itt %x, expected " 531b4377356SAl Viro "CID (%x)\n", (__force u32)hdr->itt, conn->id); 5327996a778SMike Christie return ISCSI_ERR_BAD_ITT; 5337996a778SMike Christie } 534b4377356SAl Viro itt = get_itt(hdr->itt); 5357996a778SMike Christie } else 536b4377356SAl Viro itt = ~0U; 5377996a778SMike Christie 5387996a778SMike Christie if (itt < session->cmds_max) { 5397996a778SMike Christie ctask = session->cmds[itt]; 5407996a778SMike Christie 5417996a778SMike Christie if (!ctask->sc) { 542be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: dropping ctask with " 5437996a778SMike Christie "itt 0x%x\n", ctask->itt); 5447996a778SMike Christie /* force drop */ 5457996a778SMike Christie return ISCSI_ERR_NO_SCSI_CMD; 5467996a778SMike Christie } 5477996a778SMike Christie 5487996a778SMike Christie if (ctask->sc->SCp.phase != session->age) { 549be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: ctask's session age %d, " 5507996a778SMike Christie "expected %d\n", ctask->sc->SCp.phase, 5517996a778SMike Christie session->age); 5527996a778SMike Christie return ISCSI_ERR_SESSION_FAILED; 5537996a778SMike Christie } 5547996a778SMike Christie } 5557996a778SMike Christie 5567996a778SMike Christie *ret_itt = itt; 5577996a778SMike Christie return 0; 5587996a778SMike Christie } 5597996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_verify_itt); 5607996a778SMike Christie 5617996a778SMike Christie void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) 5627996a778SMike Christie { 5637996a778SMike Christie struct iscsi_session *session = conn->session; 5647996a778SMike Christie unsigned long flags; 5657996a778SMike Christie 5667996a778SMike Christie spin_lock_irqsave(&session->lock, flags); 567656cffc9SMike Christie if (session->state == ISCSI_STATE_FAILED) { 568656cffc9SMike Christie spin_unlock_irqrestore(&session->lock, flags); 569656cffc9SMike Christie return; 570656cffc9SMike Christie } 571656cffc9SMike Christie 57267a61114SMike Christie if (conn->stop_stage == 0) 5737996a778SMike Christie session->state = ISCSI_STATE_FAILED; 5747996a778SMike Christie spin_unlock_irqrestore(&session->lock, flags); 5757996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 5767996a778SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 5777996a778SMike Christie iscsi_conn_error(conn->cls_conn, err); 5787996a778SMike Christie } 5797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_failure); 5807996a778SMike Christie 58177a23c21SMike Christie static void iscsi_prep_mtask(struct iscsi_conn *conn, 58277a23c21SMike Christie struct iscsi_mgmt_task *mtask) 58377a23c21SMike Christie { 58477a23c21SMike Christie struct iscsi_session *session = conn->session; 58577a23c21SMike Christie struct iscsi_hdr *hdr = mtask->hdr; 58677a23c21SMike Christie struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; 58777a23c21SMike Christie 58877a23c21SMike Christie if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && 58977a23c21SMike Christie hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) 59077a23c21SMike Christie nop->exp_statsn = cpu_to_be32(conn->exp_statsn); 59177a23c21SMike Christie /* 59277a23c21SMike Christie * pre-format CmdSN for outgoing PDU. 59377a23c21SMike Christie */ 59477a23c21SMike Christie nop->cmdsn = cpu_to_be32(session->cmdsn); 59577a23c21SMike Christie if (hdr->itt != RESERVED_ITT) { 59677a23c21SMike Christie hdr->itt = build_itt(mtask->itt, conn->id, session->age); 597e0726407SMike Christie /* 598e0726407SMike Christie * TODO: We always use immediate, so we never hit this. 599e0726407SMike Christie * If we start to send tmfs or nops as non-immediate then 600e0726407SMike Christie * we should start checking the cmdsn numbers for mgmt tasks. 601e0726407SMike Christie */ 60277a23c21SMike Christie if (conn->c_stage == ISCSI_CONN_STARTED && 603e0726407SMike Christie !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { 604e0726407SMike Christie session->queued_cmdsn++; 60577a23c21SMike Christie session->cmdsn++; 60677a23c21SMike Christie } 607e0726407SMike Christie } 60877a23c21SMike Christie 60977a23c21SMike Christie if (session->tt->init_mgmt_task) 61077a23c21SMike Christie session->tt->init_mgmt_task(conn, mtask); 61177a23c21SMike Christie 61277a23c21SMike Christie debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", 613843c0a8aSMike Christie hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, 614843c0a8aSMike Christie mtask->data_count); 61577a23c21SMike Christie } 61677a23c21SMike Christie 61705db888aSMike Christie static int iscsi_xmit_mtask(struct iscsi_conn *conn) 618b5072ea0SMike Christie { 619b5072ea0SMike Christie struct iscsi_hdr *hdr = conn->mtask->hdr; 620b5072ea0SMike Christie int rc, was_logout = 0; 621b5072ea0SMike Christie 62277a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 623b5072ea0SMike Christie if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) { 624b5072ea0SMike Christie conn->session->state = ISCSI_STATE_IN_RECOVERY; 625b5072ea0SMike Christie iscsi_block_session(session_to_cls(conn->session)); 626b5072ea0SMike Christie was_logout = 1; 627b5072ea0SMike Christie } 628b5072ea0SMike Christie rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); 62977a23c21SMike Christie spin_lock_bh(&conn->session->lock); 630b5072ea0SMike Christie if (rc) 631b5072ea0SMike Christie return rc; 632b5072ea0SMike Christie 63305db888aSMike Christie /* done with this in-progress mtask */ 63405db888aSMike Christie conn->mtask = NULL; 63505db888aSMike Christie 636b5072ea0SMike Christie if (was_logout) { 637b5072ea0SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 638b5072ea0SMike Christie return -ENODATA; 639b5072ea0SMike Christie } 640b5072ea0SMike Christie return 0; 641b5072ea0SMike Christie } 642b5072ea0SMike Christie 64377a23c21SMike Christie static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) 64477a23c21SMike Christie { 64577a23c21SMike Christie struct iscsi_session *session = conn->session; 64677a23c21SMike Christie 64777a23c21SMike Christie /* 64877a23c21SMike Christie * Check for iSCSI window and take care of CmdSN wrap-around 64977a23c21SMike Christie */ 650e0726407SMike Christie if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) { 651e0726407SMike Christie debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u " 652e0726407SMike Christie "CmdSN %u/%u\n", session->exp_cmdsn, 653e0726407SMike Christie session->max_cmdsn, session->cmdsn, 654e0726407SMike Christie session->queued_cmdsn); 65577a23c21SMike Christie return -ENOSPC; 65677a23c21SMike Christie } 65777a23c21SMike Christie return 0; 65877a23c21SMike Christie } 65977a23c21SMike Christie 66077a23c21SMike Christie static int iscsi_xmit_ctask(struct iscsi_conn *conn) 66177a23c21SMike Christie { 66277a23c21SMike Christie struct iscsi_cmd_task *ctask = conn->ctask; 663843c0a8aSMike Christie int rc; 66477a23c21SMike Christie 66577a23c21SMike Christie __iscsi_get_ctask(ctask); 66677a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 66777a23c21SMike Christie rc = conn->session->tt->xmit_cmd_task(conn, ctask); 66877a23c21SMike Christie spin_lock_bh(&conn->session->lock); 66977a23c21SMike Christie __iscsi_put_ctask(ctask); 67077a23c21SMike Christie if (!rc) 67177a23c21SMike Christie /* done with this ctask */ 67277a23c21SMike Christie conn->ctask = NULL; 67377a23c21SMike Christie return rc; 67477a23c21SMike Christie } 67577a23c21SMike Christie 6767996a778SMike Christie /** 677843c0a8aSMike Christie * iscsi_requeue_ctask - requeue ctask to run from session workqueue 678843c0a8aSMike Christie * @ctask: ctask to requeue 679843c0a8aSMike Christie * 680843c0a8aSMike Christie * LLDs that need to run a ctask from the session workqueue should call 681843c0a8aSMike Christie * this. The session lock must be held. 682843c0a8aSMike Christie */ 683843c0a8aSMike Christie void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) 684843c0a8aSMike Christie { 685843c0a8aSMike Christie struct iscsi_conn *conn = ctask->conn; 686843c0a8aSMike Christie 687843c0a8aSMike Christie list_move_tail(&ctask->running, &conn->requeue); 688843c0a8aSMike Christie scsi_queue_work(conn->session->host, &conn->xmitwork); 689843c0a8aSMike Christie } 690843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); 691843c0a8aSMike Christie 692843c0a8aSMike Christie /** 6937996a778SMike Christie * iscsi_data_xmit - xmit any command into the scheduled connection 6947996a778SMike Christie * @conn: iscsi connection 6957996a778SMike Christie * 6967996a778SMike Christie * Notes: 6977996a778SMike Christie * The function can return -EAGAIN in which case the caller must 6987996a778SMike Christie * re-schedule it again later or recover. '0' return code means 6997996a778SMike Christie * successful xmit. 7007996a778SMike Christie **/ 7017996a778SMike Christie static int iscsi_data_xmit(struct iscsi_conn *conn) 7027996a778SMike Christie { 7033219e529SMike Christie int rc = 0; 7047996a778SMike Christie 70577a23c21SMike Christie spin_lock_bh(&conn->session->lock); 7067996a778SMike Christie if (unlikely(conn->suspend_tx)) { 7077996a778SMike Christie debug_scsi("conn %d Tx suspended!\n", conn->id); 70877a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 7093219e529SMike Christie return -ENODATA; 7107996a778SMike Christie } 7117996a778SMike Christie 7127996a778SMike Christie if (conn->ctask) { 71377a23c21SMike Christie rc = iscsi_xmit_ctask(conn); 7143219e529SMike Christie if (rc) 7157996a778SMike Christie goto again; 7167996a778SMike Christie } 71777a23c21SMike Christie 7187996a778SMike Christie if (conn->mtask) { 71905db888aSMike Christie rc = iscsi_xmit_mtask(conn); 7203219e529SMike Christie if (rc) 7217996a778SMike Christie goto again; 7227996a778SMike Christie } 7237996a778SMike Christie 72477a23c21SMike Christie /* 72577a23c21SMike Christie * process mgmt pdus like nops before commands since we should 72677a23c21SMike Christie * only have one nop-out as a ping from us and targets should not 72777a23c21SMike Christie * overflow us with nop-ins 72877a23c21SMike Christie */ 72977a23c21SMike Christie check_mgmt: 730843c0a8aSMike Christie while (!list_empty(&conn->mgmtqueue)) { 731843c0a8aSMike Christie conn->mtask = list_entry(conn->mgmtqueue.next, 732843c0a8aSMike Christie struct iscsi_mgmt_task, running); 73377a23c21SMike Christie iscsi_prep_mtask(conn, conn->mtask); 734843c0a8aSMike Christie list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); 73505db888aSMike Christie rc = iscsi_xmit_mtask(conn); 7363219e529SMike Christie if (rc) 7377996a778SMike Christie goto again; 7387996a778SMike Christie } 7397996a778SMike Christie 740843c0a8aSMike Christie /* process pending command queue */ 741b6c395edSMike Christie while (!list_empty(&conn->xmitqueue)) { 742843c0a8aSMike Christie if (conn->tmf_state == TMF_QUEUED) 743843c0a8aSMike Christie break; 744843c0a8aSMike Christie 745b6c395edSMike Christie conn->ctask = list_entry(conn->xmitqueue.next, 746b6c395edSMike Christie struct iscsi_cmd_task, running); 74777a23c21SMike Christie iscsi_prep_scsi_cmd_pdu(conn->ctask); 74877a23c21SMike Christie conn->session->tt->init_cmd_task(conn->ctask); 749b6c395edSMike Christie conn->ctask->state = ISCSI_TASK_RUNNING; 750b6c395edSMike Christie list_move_tail(conn->xmitqueue.next, &conn->run_list); 75177a23c21SMike Christie rc = iscsi_xmit_ctask(conn); 7523219e529SMike Christie if (rc) 7537996a778SMike Christie goto again; 75477a23c21SMike Christie /* 75577a23c21SMike Christie * we could continuously get new ctask requests so 75677a23c21SMike Christie * we need to check the mgmt queue for nops that need to 75777a23c21SMike Christie * be sent to aviod starvation 75877a23c21SMike Christie */ 759843c0a8aSMike Christie if (!list_empty(&conn->mgmtqueue)) 760843c0a8aSMike Christie goto check_mgmt; 761843c0a8aSMike Christie } 762843c0a8aSMike Christie 763843c0a8aSMike Christie while (!list_empty(&conn->requeue)) { 764843c0a8aSMike Christie if (conn->session->fast_abort && conn->tmf_state != TMF_INITIAL) 765843c0a8aSMike Christie break; 766843c0a8aSMike Christie 767843c0a8aSMike Christie conn->ctask = list_entry(conn->requeue.next, 768843c0a8aSMike Christie struct iscsi_cmd_task, running); 769843c0a8aSMike Christie conn->ctask->state = ISCSI_TASK_RUNNING; 770843c0a8aSMike Christie list_move_tail(conn->requeue.next, &conn->run_list); 771843c0a8aSMike Christie rc = iscsi_xmit_ctask(conn); 772843c0a8aSMike Christie if (rc) 773843c0a8aSMike Christie goto again; 774843c0a8aSMike Christie if (!list_empty(&conn->mgmtqueue)) 77577a23c21SMike Christie goto check_mgmt; 7767996a778SMike Christie } 77777a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 7783219e529SMike Christie return -ENODATA; 7797996a778SMike Christie 7807996a778SMike Christie again: 7817996a778SMike Christie if (unlikely(conn->suspend_tx)) 78277a23c21SMike Christie rc = -ENODATA; 78377a23c21SMike Christie spin_unlock_bh(&conn->session->lock); 7843219e529SMike Christie return rc; 7857996a778SMike Christie } 7867996a778SMike Christie 787c4028958SDavid Howells static void iscsi_xmitworker(struct work_struct *work) 7887996a778SMike Christie { 789c4028958SDavid Howells struct iscsi_conn *conn = 790c4028958SDavid Howells container_of(work, struct iscsi_conn, xmitwork); 7913219e529SMike Christie int rc; 7927996a778SMike Christie /* 7937996a778SMike Christie * serialize Xmit worker on a per-connection basis. 7947996a778SMike Christie */ 7953219e529SMike Christie do { 7963219e529SMike Christie rc = iscsi_data_xmit(conn); 7973219e529SMike Christie } while (rc >= 0 || rc == -EAGAIN); 7987996a778SMike Christie } 7997996a778SMike Christie 8007996a778SMike Christie enum { 8017996a778SMike Christie FAILURE_BAD_HOST = 1, 8027996a778SMike Christie FAILURE_SESSION_FAILED, 8037996a778SMike Christie FAILURE_SESSION_FREED, 8047996a778SMike Christie FAILURE_WINDOW_CLOSED, 80560ecebf5SMike Christie FAILURE_OOM, 8067996a778SMike Christie FAILURE_SESSION_TERMINATE, 807656cffc9SMike Christie FAILURE_SESSION_IN_RECOVERY, 8087996a778SMike Christie FAILURE_SESSION_RECOVERY_TIMEOUT, 8097996a778SMike Christie }; 8107996a778SMike Christie 8117996a778SMike Christie int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) 8127996a778SMike Christie { 8137996a778SMike Christie struct Scsi_Host *host; 8147996a778SMike Christie int reason = 0; 8157996a778SMike Christie struct iscsi_session *session; 8167996a778SMike Christie struct iscsi_conn *conn; 8177996a778SMike Christie struct iscsi_cmd_task *ctask = NULL; 8187996a778SMike Christie 8197996a778SMike Christie sc->scsi_done = done; 8207996a778SMike Christie sc->result = 0; 821f47f2cf5SMike Christie sc->SCp.ptr = NULL; 8227996a778SMike Christie 8237996a778SMike Christie host = sc->device->host; 8247996a778SMike Christie session = iscsi_hostdata(host->hostdata); 8257996a778SMike Christie 8267996a778SMike Christie spin_lock(&session->lock); 8277996a778SMike Christie 828656cffc9SMike Christie /* 829656cffc9SMike Christie * ISCSI_STATE_FAILED is a temp. state. The recovery 830656cffc9SMike Christie * code will decide what is best to do with command queued 831656cffc9SMike Christie * during this time 832656cffc9SMike Christie */ 833656cffc9SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN && 834656cffc9SMike Christie session->state != ISCSI_STATE_FAILED) { 835656cffc9SMike Christie /* 836656cffc9SMike Christie * to handle the race between when we set the recovery state 837656cffc9SMike Christie * and block the session we requeue here (commands could 838656cffc9SMike Christie * be entering our queuecommand while a block is starting 839656cffc9SMike Christie * up because the block code is not locked) 840656cffc9SMike Christie */ 841656cffc9SMike Christie if (session->state == ISCSI_STATE_IN_RECOVERY) { 842656cffc9SMike Christie reason = FAILURE_SESSION_IN_RECOVERY; 84367a61114SMike Christie goto reject; 8447996a778SMike Christie } 845656cffc9SMike Christie 846656cffc9SMike Christie if (session->state == ISCSI_STATE_RECOVERY_FAILED) 847656cffc9SMike Christie reason = FAILURE_SESSION_RECOVERY_TIMEOUT; 848656cffc9SMike Christie else if (session->state == ISCSI_STATE_TERMINATE) 849656cffc9SMike Christie reason = FAILURE_SESSION_TERMINATE; 850656cffc9SMike Christie else 8517996a778SMike Christie reason = FAILURE_SESSION_FREED; 8527996a778SMike Christie goto fault; 8537996a778SMike Christie } 8547996a778SMike Christie 8557996a778SMike Christie conn = session->leadconn; 85698644047SMike Christie if (!conn) { 85798644047SMike Christie reason = FAILURE_SESSION_FREED; 85898644047SMike Christie goto fault; 85998644047SMike Christie } 8607996a778SMike Christie 86177a23c21SMike Christie if (iscsi_check_cmdsn_window_closed(conn)) { 86277a23c21SMike Christie reason = FAILURE_WINDOW_CLOSED; 86377a23c21SMike Christie goto reject; 86477a23c21SMike Christie } 86577a23c21SMike Christie 86660ecebf5SMike Christie if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, 86760ecebf5SMike Christie sizeof(void*))) { 86860ecebf5SMike Christie reason = FAILURE_OOM; 86960ecebf5SMike Christie goto reject; 87060ecebf5SMike Christie } 871e0726407SMike Christie session->queued_cmdsn++; 872e0726407SMike Christie 8737996a778SMike Christie sc->SCp.phase = session->age; 8747996a778SMike Christie sc->SCp.ptr = (char *)ctask; 8757996a778SMike Christie 87660ecebf5SMike Christie atomic_set(&ctask->refcount, 1); 877b6c395edSMike Christie ctask->state = ISCSI_TASK_PENDING; 8787996a778SMike Christie ctask->conn = conn; 8797996a778SMike Christie ctask->sc = sc; 8807996a778SMike Christie INIT_LIST_HEAD(&ctask->running); 8817996a778SMike Christie 882b6c395edSMike Christie list_add_tail(&ctask->running, &conn->xmitqueue); 8837996a778SMike Christie spin_unlock(&session->lock); 8847996a778SMike Christie 8857996a778SMike Christie scsi_queue_work(host, &conn->xmitwork); 8867996a778SMike Christie return 0; 8877996a778SMike Christie 8887996a778SMike Christie reject: 8897996a778SMike Christie spin_unlock(&session->lock); 8907996a778SMike Christie debug_scsi("cmd 0x%x rejected (%d)\n", sc->cmnd[0], reason); 8917996a778SMike Christie return SCSI_MLQUEUE_HOST_BUSY; 8927996a778SMike Christie 8937996a778SMike Christie fault: 8947996a778SMike Christie spin_unlock(&session->lock); 895be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", 8967996a778SMike Christie sc->cmnd[0], reason); 8977996a778SMike Christie sc->result = (DID_NO_CONNECT << 16); 8981c138991SFUJITA Tomonori scsi_set_resid(sc, scsi_bufflen(sc)); 8997996a778SMike Christie sc->scsi_done(sc); 9007996a778SMike Christie return 0; 9017996a778SMike Christie } 9027996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_queuecommand); 9037996a778SMike Christie 9047996a778SMike Christie int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) 9057996a778SMike Christie { 9067996a778SMike Christie if (depth > ISCSI_MAX_CMD_PER_LUN) 9077996a778SMike Christie depth = ISCSI_MAX_CMD_PER_LUN; 9087996a778SMike Christie scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); 9097996a778SMike Christie return sdev->queue_depth; 9107996a778SMike Christie } 9117996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); 9127996a778SMike Christie 91377a23c21SMike Christie static struct iscsi_mgmt_task * 91477a23c21SMike Christie __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, 9157996a778SMike Christie char *data, uint32_t data_size) 9167996a778SMike Christie { 9177996a778SMike Christie struct iscsi_session *session = conn->session; 9187996a778SMike Christie struct iscsi_mgmt_task *mtask; 9197996a778SMike Christie 92077a23c21SMike Christie if (session->state == ISCSI_STATE_TERMINATE) 92177a23c21SMike Christie return NULL; 92277a23c21SMike Christie 9237996a778SMike Christie if (hdr->opcode == (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) || 9247996a778SMike Christie hdr->opcode == (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) 9257996a778SMike Christie /* 9267996a778SMike Christie * Login and Text are sent serially, in 9277996a778SMike Christie * request-followed-by-response sequence. 9287996a778SMike Christie * Same mtask can be used. Same ITT must be used. 9297996a778SMike Christie * Note that login_mtask is preallocated at conn_create(). 9307996a778SMike Christie */ 9317996a778SMike Christie mtask = conn->login_mtask; 9327996a778SMike Christie else { 9337996a778SMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); 9347996a778SMike Christie BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); 9357996a778SMike Christie 9367996a778SMike Christie if (!__kfifo_get(session->mgmtpool.queue, 93777a23c21SMike Christie (void*)&mtask, sizeof(void*))) 93877a23c21SMike Christie return NULL; 9397996a778SMike Christie } 9407996a778SMike Christie 9417996a778SMike Christie if (data_size) { 9427996a778SMike Christie memcpy(mtask->data, data, data_size); 9437996a778SMike Christie mtask->data_count = data_size; 9447996a778SMike Christie } else 9457996a778SMike Christie mtask->data_count = 0; 9467996a778SMike Christie 9477996a778SMike Christie memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); 948843c0a8aSMike Christie INIT_LIST_HEAD(&mtask->running); 949843c0a8aSMike Christie list_add_tail(&mtask->running, &conn->mgmtqueue); 95077a23c21SMike Christie return mtask; 9517996a778SMike Christie } 9527996a778SMike Christie 9537996a778SMike Christie int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, 9547996a778SMike Christie char *data, uint32_t data_size) 9557996a778SMike Christie { 9567996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 95777a23c21SMike Christie struct iscsi_session *session = conn->session; 95877a23c21SMike Christie int err = 0; 9597996a778SMike Christie 96077a23c21SMike Christie spin_lock_bh(&session->lock); 96177a23c21SMike Christie if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) 96277a23c21SMike Christie err = -EPERM; 96377a23c21SMike Christie spin_unlock_bh(&session->lock); 96477a23c21SMike Christie scsi_queue_work(session->host, &conn->xmitwork); 96577a23c21SMike Christie return err; 9667996a778SMike Christie } 9677996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); 9687996a778SMike Christie 9697996a778SMike Christie void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) 9707996a778SMike Christie { 9717996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 9727996a778SMike Christie 9737996a778SMike Christie spin_lock_bh(&session->lock); 9747996a778SMike Christie if (session->state != ISCSI_STATE_LOGGED_IN) { 975656cffc9SMike Christie session->state = ISCSI_STATE_RECOVERY_FAILED; 976843c0a8aSMike Christie if (session->leadconn) 977843c0a8aSMike Christie wake_up(&session->leadconn->ehwait); 9787996a778SMike Christie } 9797996a778SMike Christie spin_unlock_bh(&session->lock); 9807996a778SMike Christie } 9817996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); 9827996a778SMike Christie 9837996a778SMike Christie int iscsi_eh_host_reset(struct scsi_cmnd *sc) 9847996a778SMike Christie { 9857996a778SMike Christie struct Scsi_Host *host = sc->device->host; 9867996a778SMike Christie struct iscsi_session *session = iscsi_hostdata(host->hostdata); 9877996a778SMike Christie struct iscsi_conn *conn = session->leadconn; 9887996a778SMike Christie 9897996a778SMike Christie spin_lock_bh(&session->lock); 9907996a778SMike Christie if (session->state == ISCSI_STATE_TERMINATE) { 9917996a778SMike Christie failed: 9927996a778SMike Christie debug_scsi("failing host reset: session terminated " 993d6e24d1cSPete Wyckoff "[CID %d age %d]\n", conn->id, session->age); 9947996a778SMike Christie spin_unlock_bh(&session->lock); 9957996a778SMike Christie return FAILED; 9967996a778SMike Christie } 9977996a778SMike Christie 9987996a778SMike Christie spin_unlock_bh(&session->lock); 9997996a778SMike Christie 10007996a778SMike Christie /* 10017996a778SMike Christie * we drop the lock here but the leadconn cannot be destoyed while 10027996a778SMike Christie * we are in the scsi eh 10037996a778SMike Christie */ 10047996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 10057996a778SMike Christie 10067996a778SMike Christie debug_scsi("iscsi_eh_host_reset wait for relogin\n"); 10077996a778SMike Christie wait_event_interruptible(conn->ehwait, 10087996a778SMike Christie session->state == ISCSI_STATE_TERMINATE || 10097996a778SMike Christie session->state == ISCSI_STATE_LOGGED_IN || 1010656cffc9SMike Christie session->state == ISCSI_STATE_RECOVERY_FAILED); 10117996a778SMike Christie if (signal_pending(current)) 10127996a778SMike Christie flush_signals(current); 10137996a778SMike Christie 10147996a778SMike Christie spin_lock_bh(&session->lock); 10157996a778SMike Christie if (session->state == ISCSI_STATE_LOGGED_IN) 1016be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: host reset succeeded\n"); 10177996a778SMike Christie else 10187996a778SMike Christie goto failed; 10197996a778SMike Christie spin_unlock_bh(&session->lock); 10207996a778SMike Christie 10217996a778SMike Christie return SUCCESS; 10227996a778SMike Christie } 10237996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_host_reset); 10247996a778SMike Christie 1025843c0a8aSMike Christie static void iscsi_tmf_timedout(unsigned long data) 10267996a778SMike Christie { 1027843c0a8aSMike Christie struct iscsi_conn *conn = (struct iscsi_conn *)data; 10287996a778SMike Christie struct iscsi_session *session = conn->session; 10297996a778SMike Christie 10307996a778SMike Christie spin_lock(&session->lock); 1031843c0a8aSMike Christie if (conn->tmf_state == TMF_QUEUED) { 1032843c0a8aSMike Christie conn->tmf_state = TMF_TIMEDOUT; 1033843c0a8aSMike Christie debug_scsi("tmf timedout\n"); 10347996a778SMike Christie /* unblock eh_abort() */ 10357996a778SMike Christie wake_up(&conn->ehwait); 10367996a778SMike Christie } 10377996a778SMike Christie spin_unlock(&session->lock); 10387996a778SMike Christie } 10397996a778SMike Christie 1040843c0a8aSMike Christie static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, 1041843c0a8aSMike Christie struct iscsi_tm *hdr, int age) 10427996a778SMike Christie { 10437996a778SMike Christie struct iscsi_session *session = conn->session; 1044843c0a8aSMike Christie struct iscsi_mgmt_task *mtask; 10457996a778SMike Christie 1046843c0a8aSMike Christie mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, 10477996a778SMike Christie NULL, 0); 1048843c0a8aSMike Christie if (!mtask) { 10496724add1SMike Christie spin_unlock_bh(&session->lock); 10507996a778SMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1051843c0a8aSMike Christie spin_lock_bh(&session->lock); 1052843c0a8aSMike Christie debug_scsi("tmf exec failure\n"); 105377a23c21SMike Christie return -EPERM; 10547996a778SMike Christie } 10557996a778SMike Christie conn->tmfcmd_pdus_cnt++; 1056843c0a8aSMike Christie conn->tmf_timer.expires = 30 * HZ + jiffies; 1057843c0a8aSMike Christie conn->tmf_timer.function = iscsi_tmf_timedout; 1058843c0a8aSMike Christie conn->tmf_timer.data = (unsigned long)conn; 1059843c0a8aSMike Christie add_timer(&conn->tmf_timer); 1060843c0a8aSMike Christie debug_scsi("tmf set timeout\n"); 1061843c0a8aSMike Christie 10627996a778SMike Christie spin_unlock_bh(&session->lock); 10636724add1SMike Christie mutex_unlock(&session->eh_mutex); 106477a23c21SMike Christie scsi_queue_work(session->host, &conn->xmitwork); 10657996a778SMike Christie 10667996a778SMike Christie /* 10677996a778SMike Christie * block eh thread until: 10687996a778SMike Christie * 1069843c0a8aSMike Christie * 1) tmf response 1070843c0a8aSMike Christie * 2) tmf timeout 10717996a778SMike Christie * 3) session is terminated or restarted or userspace has 10727996a778SMike Christie * given up on recovery 10737996a778SMike Christie */ 1074843c0a8aSMike Christie wait_event_interruptible(conn->ehwait, age != session->age || 10757996a778SMike Christie session->state != ISCSI_STATE_LOGGED_IN || 1076843c0a8aSMike Christie conn->tmf_state != TMF_QUEUED); 10777996a778SMike Christie if (signal_pending(current)) 10787996a778SMike Christie flush_signals(current); 1079843c0a8aSMike Christie del_timer_sync(&conn->tmf_timer); 1080843c0a8aSMike Christie 10816724add1SMike Christie mutex_lock(&session->eh_mutex); 108277a23c21SMike Christie spin_lock_bh(&session->lock); 1083843c0a8aSMike Christie /* if the session drops it will clean up the mtask */ 1084843c0a8aSMike Christie if (age != session->age || 1085843c0a8aSMike Christie session->state != ISCSI_STATE_LOGGED_IN) 1086843c0a8aSMike Christie return -ENOTCONN; 10877996a778SMike Christie 1088843c0a8aSMike Christie if (!list_empty(&mtask->running)) { 1089843c0a8aSMike Christie list_del_init(&mtask->running); 1090843c0a8aSMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&mtask, 10917996a778SMike Christie sizeof(void*)); 1092843c0a8aSMike Christie } 10937996a778SMike Christie return 0; 10947996a778SMike Christie } 10957996a778SMike Christie 10967996a778SMike Christie /* 109777a23c21SMike Christie * session lock must be held 10987996a778SMike Christie */ 10997996a778SMike Christie static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, 11007996a778SMike Christie int err) 11017996a778SMike Christie { 11027996a778SMike Christie struct scsi_cmnd *sc; 11037996a778SMike Christie 11047996a778SMike Christie sc = ctask->sc; 11057996a778SMike Christie if (!sc) 11067996a778SMike Christie return; 1107e648f63cSMike Christie 1108e0726407SMike Christie if (ctask->state == ISCSI_TASK_PENDING) 1109e0726407SMike Christie /* 1110e0726407SMike Christie * cmd never made it to the xmit thread, so we should not count 1111e0726407SMike Christie * the cmd in the sequencing 1112e0726407SMike Christie */ 1113e0726407SMike Christie conn->session->queued_cmdsn--; 1114e0726407SMike Christie else 1115e648f63cSMike Christie conn->session->tt->cleanup_cmd_task(conn, ctask); 11167ea8b828SMike Christie 11177996a778SMike Christie sc->result = err; 11181c138991SFUJITA Tomonori scsi_set_resid(sc, scsi_bufflen(sc)); 111977a23c21SMike Christie if (conn->ctask == ctask) 112077a23c21SMike Christie conn->ctask = NULL; 1121e648f63cSMike Christie /* release ref from queuecommand */ 112260ecebf5SMike Christie __iscsi_put_ctask(ctask); 11237996a778SMike Christie } 11247996a778SMike Christie 1125843c0a8aSMike Christie /* 1126843c0a8aSMike Christie * Fail commands. session lock held and recv side suspended and xmit 1127843c0a8aSMike Christie * thread flushed 1128843c0a8aSMike Christie */ 1129843c0a8aSMike Christie static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) 1130843c0a8aSMike Christie { 1131843c0a8aSMike Christie struct iscsi_cmd_task *ctask, *tmp; 1132843c0a8aSMike Christie 1133843c0a8aSMike Christie if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) 1134843c0a8aSMike Christie conn->ctask = NULL; 1135843c0a8aSMike Christie 1136843c0a8aSMike Christie /* flush pending */ 1137843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { 1138843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1139843c0a8aSMike Christie debug_scsi("failing pending sc %p itt 0x%x\n", 1140843c0a8aSMike Christie ctask->sc, ctask->itt); 1141843c0a8aSMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 1142843c0a8aSMike Christie } 1143843c0a8aSMike Christie } 1144843c0a8aSMike Christie 1145843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { 1146843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1147843c0a8aSMike Christie debug_scsi("failing requeued sc %p itt 0x%x\n", 1148843c0a8aSMike Christie ctask->sc, ctask->itt); 1149843c0a8aSMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 1150843c0a8aSMike Christie } 1151843c0a8aSMike Christie } 1152843c0a8aSMike Christie 1153843c0a8aSMike Christie /* fail all other running */ 1154843c0a8aSMike Christie list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { 1155843c0a8aSMike Christie if (lun == ctask->sc->device->lun || lun == -1) { 1156843c0a8aSMike Christie debug_scsi("failing in progress sc %p itt 0x%x\n", 1157843c0a8aSMike Christie ctask->sc, ctask->itt); 1158843c0a8aSMike Christie fail_command(conn, ctask, DID_BUS_BUSY << 16); 1159843c0a8aSMike Christie } 1160843c0a8aSMike Christie } 1161843c0a8aSMike Christie } 1162843c0a8aSMike Christie 11636724add1SMike Christie static void iscsi_suspend_tx(struct iscsi_conn *conn) 11646724add1SMike Christie { 11656724add1SMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 11666724add1SMike Christie scsi_flush_work(conn->session->host); 11676724add1SMike Christie } 11686724add1SMike Christie 11696724add1SMike Christie static void iscsi_start_tx(struct iscsi_conn *conn) 11706724add1SMike Christie { 11716724add1SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 11726724add1SMike Christie scsi_queue_work(conn->session->host, &conn->xmitwork); 11736724add1SMike Christie } 11746724add1SMike Christie 1175843c0a8aSMike Christie static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, 1176843c0a8aSMike Christie struct iscsi_tm *hdr) 1177843c0a8aSMike Christie { 1178843c0a8aSMike Christie memset(hdr, 0, sizeof(*hdr)); 1179843c0a8aSMike Christie hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 1180843c0a8aSMike Christie hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; 1181843c0a8aSMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1182843c0a8aSMike Christie memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); 1183843c0a8aSMike Christie hdr->rtt = ctask->hdr->itt; 1184843c0a8aSMike Christie hdr->refcmdsn = ctask->hdr->cmdsn; 1185843c0a8aSMike Christie } 1186843c0a8aSMike Christie 11877996a778SMike Christie int iscsi_eh_abort(struct scsi_cmnd *sc) 11887996a778SMike Christie { 11896724add1SMike Christie struct Scsi_Host *host = sc->device->host; 11906724add1SMike Christie struct iscsi_session *session = iscsi_hostdata(host->hostdata); 1191f47f2cf5SMike Christie struct iscsi_conn *conn; 1192843c0a8aSMike Christie struct iscsi_cmd_task *ctask; 1193843c0a8aSMike Christie struct iscsi_tm *hdr; 1194843c0a8aSMike Christie int rc, age; 11957996a778SMike Christie 11966724add1SMike Christie mutex_lock(&session->eh_mutex); 11976724add1SMike Christie spin_lock_bh(&session->lock); 1198f47f2cf5SMike Christie /* 1199f47f2cf5SMike Christie * if session was ISCSI_STATE_IN_RECOVERY then we may not have 1200f47f2cf5SMike Christie * got the command. 1201f47f2cf5SMike Christie */ 1202f47f2cf5SMike Christie if (!sc->SCp.ptr) { 1203f47f2cf5SMike Christie debug_scsi("sc never reached iscsi layer or it completed.\n"); 12046724add1SMike Christie spin_unlock_bh(&session->lock); 12056724add1SMike Christie mutex_unlock(&session->eh_mutex); 1206f47f2cf5SMike Christie return SUCCESS; 1207f47f2cf5SMike Christie } 1208f47f2cf5SMike Christie 12097996a778SMike Christie /* 12107996a778SMike Christie * If we are not logged in or we have started a new session 12117996a778SMike Christie * then let the host reset code handle this 12127996a778SMike Christie */ 1213843c0a8aSMike Christie if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN || 1214843c0a8aSMike Christie sc->SCp.phase != session->age) { 1215843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1216843c0a8aSMike Christie mutex_unlock(&session->eh_mutex); 1217843c0a8aSMike Christie return FAILED; 1218843c0a8aSMike Christie } 1219843c0a8aSMike Christie 1220843c0a8aSMike Christie conn = session->leadconn; 1221843c0a8aSMike Christie conn->eh_abort_cnt++; 1222843c0a8aSMike Christie age = session->age; 1223843c0a8aSMike Christie 1224843c0a8aSMike Christie ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; 1225843c0a8aSMike Christie debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); 12267996a778SMike Christie 12277996a778SMike Christie /* ctask completed before time out */ 12287ea8b828SMike Christie if (!ctask->sc) { 12297ea8b828SMike Christie debug_scsi("sc completed while abort in progress\n"); 123077a23c21SMike Christie goto success; 12317ea8b828SMike Christie } 12327996a778SMike Christie 123377a23c21SMike Christie if (ctask->state == ISCSI_TASK_PENDING) { 123477a23c21SMike Christie fail_command(conn, ctask, DID_ABORT << 16); 123577a23c21SMike Christie goto success; 123677a23c21SMike Christie } 12377996a778SMike Christie 1238843c0a8aSMike Christie /* only have one tmf outstanding at a time */ 1239843c0a8aSMike Christie if (conn->tmf_state != TMF_INITIAL) 12407996a778SMike Christie goto failed; 1241843c0a8aSMike Christie conn->tmf_state = TMF_QUEUED; 12427996a778SMike Christie 1243843c0a8aSMike Christie hdr = &conn->tmhdr; 1244843c0a8aSMike Christie iscsi_prep_abort_task_pdu(ctask, hdr); 1245843c0a8aSMike Christie 1246843c0a8aSMike Christie if (iscsi_exec_task_mgmt_fn(conn, hdr, age)) { 1247843c0a8aSMike Christie rc = FAILED; 1248843c0a8aSMike Christie goto failed; 1249843c0a8aSMike Christie } 1250843c0a8aSMike Christie 1251843c0a8aSMike Christie switch (conn->tmf_state) { 1252843c0a8aSMike Christie case TMF_SUCCESS: 12537ea8b828SMike Christie spin_unlock_bh(&session->lock); 12546724add1SMike Christie iscsi_suspend_tx(conn); 12557996a778SMike Christie /* 125677a23c21SMike Christie * clean up task if aborted. grab the recv lock as a writer 12577996a778SMike Christie */ 12587996a778SMike Christie write_lock_bh(conn->recv_lock); 12597996a778SMike Christie spin_lock(&session->lock); 12607996a778SMike Christie fail_command(conn, ctask, DID_ABORT << 16); 1261843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 12627996a778SMike Christie spin_unlock(&session->lock); 12637996a778SMike Christie write_unlock_bh(conn->recv_lock); 12646724add1SMike Christie iscsi_start_tx(conn); 126577a23c21SMike Christie goto success_unlocked; 1266843c0a8aSMike Christie case TMF_TIMEDOUT: 1267843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1268843c0a8aSMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1269843c0a8aSMike Christie goto failed_unlocked; 1270843c0a8aSMike Christie case TMF_NOT_FOUND: 1271843c0a8aSMike Christie if (!sc->SCp.ptr) { 1272843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 127377a23c21SMike Christie /* ctask completed before tmf abort response */ 127477a23c21SMike Christie debug_scsi("sc completed while abort in progress\n"); 127577a23c21SMike Christie goto success; 127677a23c21SMike Christie } 127777a23c21SMike Christie /* fall through */ 127877a23c21SMike Christie default: 1279843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1280843c0a8aSMike Christie goto failed; 128177a23c21SMike Christie } 12827996a778SMike Christie 128377a23c21SMike Christie success: 128477a23c21SMike Christie spin_unlock_bh(&session->lock); 128577a23c21SMike Christie success_unlocked: 128677a23c21SMike Christie debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); 12876724add1SMike Christie mutex_unlock(&session->eh_mutex); 12887996a778SMike Christie return SUCCESS; 12897996a778SMike Christie 12907996a778SMike Christie failed: 12917996a778SMike Christie spin_unlock_bh(&session->lock); 129277a23c21SMike Christie failed_unlocked: 1293843c0a8aSMike Christie debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, 1294843c0a8aSMike Christie ctask ? ctask->itt : 0); 12956724add1SMike Christie mutex_unlock(&session->eh_mutex); 12967996a778SMike Christie return FAILED; 12977996a778SMike Christie } 12987996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_abort); 12997996a778SMike Christie 1300843c0a8aSMike Christie static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) 1301843c0a8aSMike Christie { 1302843c0a8aSMike Christie memset(hdr, 0, sizeof(*hdr)); 1303843c0a8aSMike Christie hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; 1304843c0a8aSMike Christie hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; 1305843c0a8aSMike Christie hdr->flags |= ISCSI_FLAG_CMD_FINAL; 1306843c0a8aSMike Christie int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); 1307843c0a8aSMike Christie hdr->rtt = ISCSI_RESERVED_TAG; 1308843c0a8aSMike Christie } 1309843c0a8aSMike Christie 1310843c0a8aSMike Christie int iscsi_eh_device_reset(struct scsi_cmnd *sc) 1311843c0a8aSMike Christie { 1312843c0a8aSMike Christie struct Scsi_Host *host = sc->device->host; 1313843c0a8aSMike Christie struct iscsi_session *session = iscsi_hostdata(host->hostdata); 1314843c0a8aSMike Christie struct iscsi_conn *conn; 1315843c0a8aSMike Christie struct iscsi_tm *hdr; 1316843c0a8aSMike Christie int rc = FAILED; 1317843c0a8aSMike Christie 1318843c0a8aSMike Christie debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); 1319843c0a8aSMike Christie 1320843c0a8aSMike Christie mutex_lock(&session->eh_mutex); 1321843c0a8aSMike Christie spin_lock_bh(&session->lock); 1322843c0a8aSMike Christie /* 1323843c0a8aSMike Christie * Just check if we are not logged in. We cannot check for 1324843c0a8aSMike Christie * the phase because the reset could come from a ioctl. 1325843c0a8aSMike Christie */ 1326843c0a8aSMike Christie if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) 1327843c0a8aSMike Christie goto unlock; 1328843c0a8aSMike Christie conn = session->leadconn; 1329843c0a8aSMike Christie 1330843c0a8aSMike Christie /* only have one tmf outstanding at a time */ 1331843c0a8aSMike Christie if (conn->tmf_state != TMF_INITIAL) 1332843c0a8aSMike Christie goto unlock; 1333843c0a8aSMike Christie conn->tmf_state = TMF_QUEUED; 1334843c0a8aSMike Christie 1335843c0a8aSMike Christie hdr = &conn->tmhdr; 1336843c0a8aSMike Christie iscsi_prep_lun_reset_pdu(sc, hdr); 1337843c0a8aSMike Christie 1338843c0a8aSMike Christie if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age)) { 1339843c0a8aSMike Christie rc = FAILED; 1340843c0a8aSMike Christie goto unlock; 1341843c0a8aSMike Christie } 1342843c0a8aSMike Christie 1343843c0a8aSMike Christie switch (conn->tmf_state) { 1344843c0a8aSMike Christie case TMF_SUCCESS: 1345843c0a8aSMike Christie break; 1346843c0a8aSMike Christie case TMF_TIMEDOUT: 1347843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1348843c0a8aSMike Christie iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); 1349843c0a8aSMike Christie goto done; 1350843c0a8aSMike Christie default: 1351843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1352843c0a8aSMike Christie goto unlock; 1353843c0a8aSMike Christie } 1354843c0a8aSMike Christie 1355843c0a8aSMike Christie rc = SUCCESS; 1356843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1357843c0a8aSMike Christie 1358843c0a8aSMike Christie iscsi_suspend_tx(conn); 1359843c0a8aSMike Christie /* need to grab the recv lock then session lock */ 1360843c0a8aSMike Christie write_lock_bh(conn->recv_lock); 1361843c0a8aSMike Christie spin_lock(&session->lock); 1362843c0a8aSMike Christie fail_all_commands(conn, sc->device->lun); 1363843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 1364843c0a8aSMike Christie spin_unlock(&session->lock); 1365843c0a8aSMike Christie write_unlock_bh(conn->recv_lock); 1366843c0a8aSMike Christie 1367843c0a8aSMike Christie iscsi_start_tx(conn); 1368843c0a8aSMike Christie goto done; 1369843c0a8aSMike Christie 1370843c0a8aSMike Christie unlock: 1371843c0a8aSMike Christie spin_unlock_bh(&session->lock); 1372843c0a8aSMike Christie done: 1373843c0a8aSMike Christie debug_scsi("iscsi_eh_device_reset %s\n", 1374843c0a8aSMike Christie rc == SUCCESS ? "SUCCESS" : "FAILED"); 1375843c0a8aSMike Christie mutex_unlock(&session->eh_mutex); 1376843c0a8aSMike Christie return rc; 1377843c0a8aSMike Christie } 1378843c0a8aSMike Christie EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); 1379843c0a8aSMike Christie 13807996a778SMike Christie int 13817996a778SMike Christie iscsi_pool_init(struct iscsi_queue *q, int max, void ***items, int item_size) 13827996a778SMike Christie { 13837996a778SMike Christie int i; 13847996a778SMike Christie 13857996a778SMike Christie *items = kmalloc(max * sizeof(void*), GFP_KERNEL); 13867996a778SMike Christie if (*items == NULL) 13877996a778SMike Christie return -ENOMEM; 13887996a778SMike Christie 13897996a778SMike Christie q->max = max; 13907996a778SMike Christie q->pool = kmalloc(max * sizeof(void*), GFP_KERNEL); 13917996a778SMike Christie if (q->pool == NULL) { 13927996a778SMike Christie kfree(*items); 13937996a778SMike Christie return -ENOMEM; 13947996a778SMike Christie } 13957996a778SMike Christie 13967996a778SMike Christie q->queue = kfifo_init((void*)q->pool, max * sizeof(void*), 13977996a778SMike Christie GFP_KERNEL, NULL); 13987996a778SMike Christie if (q->queue == ERR_PTR(-ENOMEM)) { 13997996a778SMike Christie kfree(q->pool); 14007996a778SMike Christie kfree(*items); 14017996a778SMike Christie return -ENOMEM; 14027996a778SMike Christie } 14037996a778SMike Christie 14047996a778SMike Christie for (i = 0; i < max; i++) { 14057996a778SMike Christie q->pool[i] = kmalloc(item_size, GFP_KERNEL); 14067996a778SMike Christie if (q->pool[i] == NULL) { 14077996a778SMike Christie int j; 14087996a778SMike Christie 14097996a778SMike Christie for (j = 0; j < i; j++) 14107996a778SMike Christie kfree(q->pool[j]); 14117996a778SMike Christie 14127996a778SMike Christie kfifo_free(q->queue); 14137996a778SMike Christie kfree(q->pool); 14147996a778SMike Christie kfree(*items); 14157996a778SMike Christie return -ENOMEM; 14167996a778SMike Christie } 14177996a778SMike Christie memset(q->pool[i], 0, item_size); 14187996a778SMike Christie (*items)[i] = q->pool[i]; 14197996a778SMike Christie __kfifo_put(q->queue, (void*)&q->pool[i], sizeof(void*)); 14207996a778SMike Christie } 14217996a778SMike Christie return 0; 14227996a778SMike Christie } 14237996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_init); 14247996a778SMike Christie 14257996a778SMike Christie void iscsi_pool_free(struct iscsi_queue *q, void **items) 14267996a778SMike Christie { 14277996a778SMike Christie int i; 14287996a778SMike Christie 14297996a778SMike Christie for (i = 0; i < q->max; i++) 14307996a778SMike Christie kfree(items[i]); 14317996a778SMike Christie kfree(q->pool); 14327996a778SMike Christie kfree(items); 14337996a778SMike Christie } 14347996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_pool_free); 14357996a778SMike Christie 14367996a778SMike Christie /* 14377996a778SMike Christie * iSCSI Session's hostdata organization: 14387996a778SMike Christie * 14397996a778SMike Christie * *------------------* <== hostdata_session(host->hostdata) 14407996a778SMike Christie * | ptr to class sess| 14417996a778SMike Christie * |------------------| <== iscsi_hostdata(host->hostdata) 14427996a778SMike Christie * | iscsi_session | 14437996a778SMike Christie * *------------------* 14447996a778SMike Christie */ 14457996a778SMike Christie 14467996a778SMike Christie #define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \ 14477996a778SMike Christie _sz % sizeof(unsigned long)) 14487996a778SMike Christie 14497996a778SMike Christie #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) 14507996a778SMike Christie 14517996a778SMike Christie /** 14527996a778SMike Christie * iscsi_session_setup - create iscsi cls session and host and session 14537996a778SMike Christie * @scsit: scsi transport template 14547996a778SMike Christie * @iscsit: iscsi transport template 14551548271eSMike Christie * @cmds_max: scsi host can queue 14561548271eSMike Christie * @qdepth: scsi host cmds per lun 14571548271eSMike Christie * @cmd_task_size: LLD ctask private data size 14581548271eSMike Christie * @mgmt_task_size: LLD mtask private data size 14597996a778SMike Christie * @initial_cmdsn: initial CmdSN 14607996a778SMike Christie * @hostno: host no allocated 14617996a778SMike Christie * 14627996a778SMike Christie * This can be used by software iscsi_transports that allocate 14637996a778SMike Christie * a session per scsi host. 14647996a778SMike Christie **/ 14657996a778SMike Christie struct iscsi_cls_session * 14667996a778SMike Christie iscsi_session_setup(struct iscsi_transport *iscsit, 14677996a778SMike Christie struct scsi_transport_template *scsit, 14681548271eSMike Christie uint16_t cmds_max, uint16_t qdepth, 14697996a778SMike Christie int cmd_task_size, int mgmt_task_size, 14707996a778SMike Christie uint32_t initial_cmdsn, uint32_t *hostno) 14717996a778SMike Christie { 14727996a778SMike Christie struct Scsi_Host *shost; 14737996a778SMike Christie struct iscsi_session *session; 14747996a778SMike Christie struct iscsi_cls_session *cls_session; 14757996a778SMike Christie int cmd_i; 14767996a778SMike Christie 14771548271eSMike Christie if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { 14781548271eSMike Christie if (qdepth != 0) 14791548271eSMike Christie printk(KERN_ERR "iscsi: invalid queue depth of %d. " 14801548271eSMike Christie "Queue depth must be between 1 and %d.\n", 14811548271eSMike Christie qdepth, ISCSI_MAX_CMD_PER_LUN); 14821548271eSMike Christie qdepth = ISCSI_DEF_CMD_PER_LUN; 14831548271eSMike Christie } 14841548271eSMike Christie 14851548271eSMike Christie if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || 14861548271eSMike Christie cmds_max >= ISCSI_MGMT_ITT_OFFSET) { 14871548271eSMike Christie if (cmds_max != 0) 14881548271eSMike Christie printk(KERN_ERR "iscsi: invalid can_queue of %d. " 14891548271eSMike Christie "can_queue must be a power of 2 and between " 14901548271eSMike Christie "2 and %d - setting to %d.\n", cmds_max, 14911548271eSMike Christie ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX); 14921548271eSMike Christie cmds_max = ISCSI_DEF_XMIT_CMDS_MAX; 14931548271eSMike Christie } 14941548271eSMike Christie 14957996a778SMike Christie shost = scsi_host_alloc(iscsit->host_template, 14967996a778SMike Christie hostdata_privsize(sizeof(*session))); 14977996a778SMike Christie if (!shost) 14987996a778SMike Christie return NULL; 14997996a778SMike Christie 15001548271eSMike Christie /* the iscsi layer takes one task for reserve */ 15011548271eSMike Christie shost->can_queue = cmds_max - 1; 15021548271eSMike Christie shost->cmd_per_lun = qdepth; 15037996a778SMike Christie shost->max_id = 1; 15047996a778SMike Christie shost->max_channel = 0; 15057996a778SMike Christie shost->max_lun = iscsit->max_lun; 15067996a778SMike Christie shost->max_cmd_len = iscsit->max_cmd_len; 15077996a778SMike Christie shost->transportt = scsit; 15087996a778SMike Christie shost->transportt->create_work_queue = 1; 15097996a778SMike Christie *hostno = shost->host_no; 15107996a778SMike Christie 15117996a778SMike Christie session = iscsi_hostdata(shost->hostdata); 15127996a778SMike Christie memset(session, 0, sizeof(struct iscsi_session)); 15137996a778SMike Christie session->host = shost; 15147996a778SMike Christie session->state = ISCSI_STATE_FREE; 15157996a778SMike Christie session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; 15161548271eSMike Christie session->cmds_max = cmds_max; 1517e0726407SMike Christie session->queued_cmdsn = session->cmdsn = initial_cmdsn; 15187996a778SMike Christie session->exp_cmdsn = initial_cmdsn + 1; 15197996a778SMike Christie session->max_cmdsn = initial_cmdsn + 1; 15207996a778SMike Christie session->max_r2t = 1; 15217996a778SMike Christie session->tt = iscsit; 15226724add1SMike Christie mutex_init(&session->eh_mutex); 15237996a778SMike Christie 15247996a778SMike Christie /* initialize SCSI PDU commands pool */ 15257996a778SMike Christie if (iscsi_pool_init(&session->cmdpool, session->cmds_max, 15267996a778SMike Christie (void***)&session->cmds, 15277996a778SMike Christie cmd_task_size + sizeof(struct iscsi_cmd_task))) 15287996a778SMike Christie goto cmdpool_alloc_fail; 15297996a778SMike Christie 15307996a778SMike Christie /* pre-format cmds pool with ITT */ 15317996a778SMike Christie for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { 15327996a778SMike Christie struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; 15337996a778SMike Christie 15347996a778SMike Christie if (cmd_task_size) 15357996a778SMike Christie ctask->dd_data = &ctask[1]; 15367996a778SMike Christie ctask->itt = cmd_i; 1537b6c395edSMike Christie INIT_LIST_HEAD(&ctask->running); 15387996a778SMike Christie } 15397996a778SMike Christie 15407996a778SMike Christie spin_lock_init(&session->lock); 15417996a778SMike Christie 15427996a778SMike Christie /* initialize immediate command pool */ 15437996a778SMike Christie if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, 15447996a778SMike Christie (void***)&session->mgmt_cmds, 15457996a778SMike Christie mgmt_task_size + sizeof(struct iscsi_mgmt_task))) 15467996a778SMike Christie goto mgmtpool_alloc_fail; 15477996a778SMike Christie 15487996a778SMike Christie 15497996a778SMike Christie /* pre-format immediate cmds pool with ITT */ 15507996a778SMike Christie for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { 15517996a778SMike Christie struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; 15527996a778SMike Christie 15537996a778SMike Christie if (mgmt_task_size) 15547996a778SMike Christie mtask->dd_data = &mtask[1]; 15557996a778SMike Christie mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; 1556b6c395edSMike Christie INIT_LIST_HEAD(&mtask->running); 15577996a778SMike Christie } 15587996a778SMike Christie 15597996a778SMike Christie if (scsi_add_host(shost, NULL)) 15607996a778SMike Christie goto add_host_fail; 15617996a778SMike Christie 1562f53a88daSMike Christie if (!try_module_get(iscsit->owner)) 1563f53a88daSMike Christie goto cls_session_fail; 1564f53a88daSMike Christie 15656a8a0d36SMike Christie cls_session = iscsi_create_session(shost, iscsit, 0); 15667996a778SMike Christie if (!cls_session) 1567f53a88daSMike Christie goto module_put; 15687996a778SMike Christie *(unsigned long*)shost->hostdata = (unsigned long)cls_session; 15697996a778SMike Christie 15707996a778SMike Christie return cls_session; 15717996a778SMike Christie 1572f53a88daSMike Christie module_put: 1573f53a88daSMike Christie module_put(iscsit->owner); 15747996a778SMike Christie cls_session_fail: 15757996a778SMike Christie scsi_remove_host(shost); 15767996a778SMike Christie add_host_fail: 15777996a778SMike Christie iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); 15787996a778SMike Christie mgmtpool_alloc_fail: 15797996a778SMike Christie iscsi_pool_free(&session->cmdpool, (void**)session->cmds); 15807996a778SMike Christie cmdpool_alloc_fail: 15817996a778SMike Christie scsi_host_put(shost); 15827996a778SMike Christie return NULL; 15837996a778SMike Christie } 15847996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_setup); 15857996a778SMike Christie 15867996a778SMike Christie /** 15877996a778SMike Christie * iscsi_session_teardown - destroy session, host, and cls_session 15887996a778SMike Christie * shost: scsi host 15897996a778SMike Christie * 15907996a778SMike Christie * This can be used by software iscsi_transports that allocate 15917996a778SMike Christie * a session per scsi host. 15927996a778SMike Christie **/ 15937996a778SMike Christie void iscsi_session_teardown(struct iscsi_cls_session *cls_session) 15947996a778SMike Christie { 15957996a778SMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 15967996a778SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 159763f75cc8SMike Christie struct module *owner = cls_session->transport->owner; 15987996a778SMike Christie 1599464bb99eSMike Christie iscsi_unblock_session(cls_session); 16007996a778SMike Christie scsi_remove_host(shost); 16017996a778SMike Christie 16027996a778SMike Christie iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds); 16037996a778SMike Christie iscsi_pool_free(&session->cmdpool, (void**)session->cmds); 16047996a778SMike Christie 1605b2c64167SMike Christie kfree(session->password); 1606b2c64167SMike Christie kfree(session->password_in); 1607b2c64167SMike Christie kfree(session->username); 1608b2c64167SMike Christie kfree(session->username_in); 1609f3ff0c36SMike Christie kfree(session->targetname); 1610d8196ed2SMike Christie kfree(session->netdev); 16110801c242SMike Christie kfree(session->hwaddress); 16128ad5781aSMike Christie kfree(session->initiatorname); 1613f3ff0c36SMike Christie 16147996a778SMike Christie iscsi_destroy_session(cls_session); 16157996a778SMike Christie scsi_host_put(shost); 161663f75cc8SMike Christie module_put(owner); 16177996a778SMike Christie } 16187996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_session_teardown); 16197996a778SMike Christie 16207996a778SMike Christie /** 16217996a778SMike Christie * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn 16227996a778SMike Christie * @cls_session: iscsi_cls_session 16237996a778SMike Christie * @conn_idx: cid 16247996a778SMike Christie **/ 16257996a778SMike Christie struct iscsi_cls_conn * 16267996a778SMike Christie iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) 16277996a778SMike Christie { 16287996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 16297996a778SMike Christie struct iscsi_conn *conn; 16307996a778SMike Christie struct iscsi_cls_conn *cls_conn; 1631d36ab6f3SMike Christie char *data; 16327996a778SMike Christie 16337996a778SMike Christie cls_conn = iscsi_create_conn(cls_session, conn_idx); 16347996a778SMike Christie if (!cls_conn) 16357996a778SMike Christie return NULL; 16367996a778SMike Christie conn = cls_conn->dd_data; 16377996a778SMike Christie memset(conn, 0, sizeof(*conn)); 16387996a778SMike Christie 16397996a778SMike Christie conn->session = session; 16407996a778SMike Christie conn->cls_conn = cls_conn; 16417996a778SMike Christie conn->c_stage = ISCSI_CONN_INITIAL_STAGE; 16427996a778SMike Christie conn->id = conn_idx; 16437996a778SMike Christie conn->exp_statsn = 0; 1644843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 16457996a778SMike Christie INIT_LIST_HEAD(&conn->run_list); 16467996a778SMike Christie INIT_LIST_HEAD(&conn->mgmt_run_list); 1647843c0a8aSMike Christie INIT_LIST_HEAD(&conn->mgmtqueue); 1648b6c395edSMike Christie INIT_LIST_HEAD(&conn->xmitqueue); 1649843c0a8aSMike Christie INIT_LIST_HEAD(&conn->requeue); 1650c4028958SDavid Howells INIT_WORK(&conn->xmitwork, iscsi_xmitworker); 16517996a778SMike Christie 16527996a778SMike Christie /* allocate login_mtask used for the login/text sequences */ 16537996a778SMike Christie spin_lock_bh(&session->lock); 16547996a778SMike Christie if (!__kfifo_get(session->mgmtpool.queue, 16557996a778SMike Christie (void*)&conn->login_mtask, 16567996a778SMike Christie sizeof(void*))) { 16577996a778SMike Christie spin_unlock_bh(&session->lock); 16587996a778SMike Christie goto login_mtask_alloc_fail; 16597996a778SMike Christie } 16607996a778SMike Christie spin_unlock_bh(&session->lock); 16617996a778SMike Christie 1662bf32ed33SMike Christie data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); 1663d36ab6f3SMike Christie if (!data) 1664d36ab6f3SMike Christie goto login_mtask_data_alloc_fail; 1665c8dc1e52SMike Christie conn->login_mtask->data = conn->data = data; 1666d36ab6f3SMike Christie 1667843c0a8aSMike Christie init_timer(&conn->tmf_timer); 16687996a778SMike Christie init_waitqueue_head(&conn->ehwait); 16697996a778SMike Christie 16707996a778SMike Christie return cls_conn; 16717996a778SMike Christie 1672d36ab6f3SMike Christie login_mtask_data_alloc_fail: 1673d36ab6f3SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 1674d36ab6f3SMike Christie sizeof(void*)); 16757996a778SMike Christie login_mtask_alloc_fail: 16767996a778SMike Christie iscsi_destroy_conn(cls_conn); 16777996a778SMike Christie return NULL; 16787996a778SMike Christie } 16797996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_setup); 16807996a778SMike Christie 16817996a778SMike Christie /** 16827996a778SMike Christie * iscsi_conn_teardown - teardown iscsi connection 16837996a778SMike Christie * cls_conn: iscsi class connection 16847996a778SMike Christie * 16857996a778SMike Christie * TODO: we may need to make this into a two step process 16867996a778SMike Christie * like scsi-mls remove + put host 16877996a778SMike Christie */ 16887996a778SMike Christie void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) 16897996a778SMike Christie { 16907996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 16917996a778SMike Christie struct iscsi_session *session = conn->session; 16927996a778SMike Christie unsigned long flags; 16937996a778SMike Christie 16947996a778SMike Christie spin_lock_bh(&session->lock); 16957996a778SMike Christie conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; 16967996a778SMike Christie if (session->leadconn == conn) { 16977996a778SMike Christie /* 16987996a778SMike Christie * leading connection? then give up on recovery. 16997996a778SMike Christie */ 17007996a778SMike Christie session->state = ISCSI_STATE_TERMINATE; 17017996a778SMike Christie wake_up(&conn->ehwait); 17027996a778SMike Christie } 17037996a778SMike Christie spin_unlock_bh(&session->lock); 17047996a778SMike Christie 17057996a778SMike Christie /* 17067996a778SMike Christie * Block until all in-progress commands for this connection 17077996a778SMike Christie * time out or fail. 17087996a778SMike Christie */ 17097996a778SMike Christie for (;;) { 17107996a778SMike Christie spin_lock_irqsave(session->host->host_lock, flags); 17117996a778SMike Christie if (!session->host->host_busy) { /* OK for ERL == 0 */ 17127996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 17137996a778SMike Christie break; 17147996a778SMike Christie } 17157996a778SMike Christie spin_unlock_irqrestore(session->host->host_lock, flags); 17167996a778SMike Christie msleep_interruptible(500); 1717be2df72eSOr Gerlitz printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " 1718be2df72eSOr Gerlitz "host_failed %d\n", session->host->host_busy, 1719be2df72eSOr Gerlitz session->host->host_failed); 17207996a778SMike Christie /* 17217996a778SMike Christie * force eh_abort() to unblock 17227996a778SMike Christie */ 17237996a778SMike Christie wake_up(&conn->ehwait); 17247996a778SMike Christie } 17257996a778SMike Christie 1726779ea120SMike Christie /* flush queued up work because we free the connection below */ 1727843c0a8aSMike Christie iscsi_suspend_tx(conn); 1728779ea120SMike Christie 17297996a778SMike Christie spin_lock_bh(&session->lock); 1730c8dc1e52SMike Christie kfree(conn->data); 1731f3ff0c36SMike Christie kfree(conn->persistent_address); 17327996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, 17337996a778SMike Christie sizeof(void*)); 1734e0726407SMike Christie if (session->leadconn == conn) 17357996a778SMike Christie session->leadconn = NULL; 17367996a778SMike Christie spin_unlock_bh(&session->lock); 17377996a778SMike Christie 17387996a778SMike Christie iscsi_destroy_conn(cls_conn); 17397996a778SMike Christie } 17407996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_teardown); 17417996a778SMike Christie 17427996a778SMike Christie int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) 17437996a778SMike Christie { 17447996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 17457996a778SMike Christie struct iscsi_session *session = conn->session; 17467996a778SMike Christie 1747ffd0436eSMike Christie if (!session) { 17487996a778SMike Christie printk(KERN_ERR "iscsi: can't start unbound connection\n"); 17497996a778SMike Christie return -EPERM; 17507996a778SMike Christie } 17517996a778SMike Christie 1752db98ccdeSMike Christie if ((session->imm_data_en || !session->initial_r2t_en) && 1753db98ccdeSMike Christie session->first_burst > session->max_burst) { 1754ffd0436eSMike Christie printk("iscsi: invalid burst lengths: " 1755ffd0436eSMike Christie "first_burst %d max_burst %d\n", 1756ffd0436eSMike Christie session->first_burst, session->max_burst); 1757ffd0436eSMike Christie return -EINVAL; 1758ffd0436eSMike Christie } 1759ffd0436eSMike Christie 17607996a778SMike Christie spin_lock_bh(&session->lock); 17617996a778SMike Christie conn->c_stage = ISCSI_CONN_STARTED; 17627996a778SMike Christie session->state = ISCSI_STATE_LOGGED_IN; 1763e0726407SMike Christie session->queued_cmdsn = session->cmdsn; 17647996a778SMike Christie 17657996a778SMike Christie switch(conn->stop_stage) { 17667996a778SMike Christie case STOP_CONN_RECOVER: 17677996a778SMike Christie /* 17687996a778SMike Christie * unblock eh_abort() if it is blocked. re-try all 17697996a778SMike Christie * commands after successful recovery 17707996a778SMike Christie */ 17717996a778SMike Christie conn->stop_stage = 0; 1772843c0a8aSMike Christie conn->tmf_state = TMF_INITIAL; 17737996a778SMike Christie session->age++; 17747996a778SMike Christie spin_unlock_bh(&session->lock); 17757996a778SMike Christie 17767996a778SMike Christie iscsi_unblock_session(session_to_cls(session)); 17777996a778SMike Christie wake_up(&conn->ehwait); 17787996a778SMike Christie return 0; 17797996a778SMike Christie case STOP_CONN_TERM: 17807996a778SMike Christie conn->stop_stage = 0; 17817996a778SMike Christie break; 17827996a778SMike Christie default: 17837996a778SMike Christie break; 17847996a778SMike Christie } 17857996a778SMike Christie spin_unlock_bh(&session->lock); 17867996a778SMike Christie 17877996a778SMike Christie return 0; 17887996a778SMike Christie } 17897996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_start); 17907996a778SMike Christie 17917996a778SMike Christie static void 17927996a778SMike Christie flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) 17937996a778SMike Christie { 17947996a778SMike Christie struct iscsi_mgmt_task *mtask, *tmp; 17957996a778SMike Christie 17967996a778SMike Christie /* handle pending */ 1797843c0a8aSMike Christie list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { 1798843c0a8aSMike Christie debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); 1799843c0a8aSMike Christie list_del_init(&mtask->running); 18007996a778SMike Christie if (mtask == conn->login_mtask) 18017996a778SMike Christie continue; 18027996a778SMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&mtask, 18037996a778SMike Christie sizeof(void*)); 18047996a778SMike Christie } 18057996a778SMike Christie 18067996a778SMike Christie /* handle running */ 18077996a778SMike Christie list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { 18087996a778SMike Christie debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); 1809843c0a8aSMike Christie list_del_init(&mtask->running); 1810ed2abc7fSMike Christie 18117996a778SMike Christie if (mtask == conn->login_mtask) 18127996a778SMike Christie continue; 1813ed2abc7fSMike Christie __kfifo_put(session->mgmtpool.queue, (void*)&mtask, 18147996a778SMike Christie sizeof(void*)); 18157996a778SMike Christie } 18167996a778SMike Christie 18177996a778SMike Christie conn->mtask = NULL; 18187996a778SMike Christie } 18197996a778SMike Christie 1820656cffc9SMike Christie static void iscsi_start_session_recovery(struct iscsi_session *session, 18217996a778SMike Christie struct iscsi_conn *conn, int flag) 18227996a778SMike Christie { 1823ed2abc7fSMike Christie int old_stop_stage; 1824ed2abc7fSMike Christie 18256724add1SMike Christie mutex_lock(&session->eh_mutex); 18267996a778SMike Christie spin_lock_bh(&session->lock); 1827ed2abc7fSMike Christie if (conn->stop_stage == STOP_CONN_TERM) { 18287996a778SMike Christie spin_unlock_bh(&session->lock); 18296724add1SMike Christie mutex_unlock(&session->eh_mutex); 18306724add1SMike Christie return; 18316724add1SMike Christie } 18326724add1SMike Christie 18336724add1SMike Christie /* 18346724add1SMike Christie * The LLD either freed/unset the lock on us, or userspace called 18356724add1SMike Christie * stop but did not create a proper connection (connection was never 18366724add1SMike Christie * bound or it was unbound then stop was called). 18376724add1SMike Christie */ 18386724add1SMike Christie if (!conn->recv_lock) { 18396724add1SMike Christie spin_unlock_bh(&session->lock); 18406724add1SMike Christie mutex_unlock(&session->eh_mutex); 18417996a778SMike Christie return; 18427996a778SMike Christie } 1843ed2abc7fSMike Christie 1844ed2abc7fSMike Christie /* 1845ed2abc7fSMike Christie * When this is called for the in_login state, we only want to clean 184667a61114SMike Christie * up the login task and connection. We do not need to block and set 184767a61114SMike Christie * the recovery state again 1848ed2abc7fSMike Christie */ 184967a61114SMike Christie if (flag == STOP_CONN_TERM) 185067a61114SMike Christie session->state = ISCSI_STATE_TERMINATE; 185167a61114SMike Christie else if (conn->stop_stage != STOP_CONN_RECOVER) 185267a61114SMike Christie session->state = ISCSI_STATE_IN_RECOVERY; 1853ed2abc7fSMike Christie 1854ed2abc7fSMike Christie old_stop_stage = conn->stop_stage; 18557996a778SMike Christie conn->stop_stage = flag; 185667a61114SMike Christie conn->c_stage = ISCSI_CONN_STOPPED; 18577996a778SMike Christie spin_unlock_bh(&session->lock); 18586724add1SMike Christie 18596724add1SMike Christie iscsi_suspend_tx(conn); 18607996a778SMike Christie 18611c83469dSMike Christie write_lock_bh(conn->recv_lock); 18621c83469dSMike Christie set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 18631c83469dSMike Christie write_unlock_bh(conn->recv_lock); 18647996a778SMike Christie 18657996a778SMike Christie /* 18667996a778SMike Christie * for connection level recovery we should not calculate 18677996a778SMike Christie * header digest. conn->hdr_size used for optimization 18687996a778SMike Christie * in hdr_extract() and will be re-negotiated at 18697996a778SMike Christie * set_param() time. 18707996a778SMike Christie */ 18717996a778SMike Christie if (flag == STOP_CONN_RECOVER) { 18727996a778SMike Christie conn->hdrdgst_en = 0; 18737996a778SMike Christie conn->datadgst_en = 0; 1874656cffc9SMike Christie if (session->state == ISCSI_STATE_IN_RECOVERY && 187567a61114SMike Christie old_stop_stage != STOP_CONN_RECOVER) { 187667a61114SMike Christie debug_scsi("blocking session\n"); 18777996a778SMike Christie iscsi_block_session(session_to_cls(session)); 18787996a778SMike Christie } 187967a61114SMike Christie } 1880656cffc9SMike Christie 1881656cffc9SMike Christie /* 1882656cffc9SMike Christie * flush queues. 1883656cffc9SMike Christie */ 1884656cffc9SMike Christie spin_lock_bh(&session->lock); 1885843c0a8aSMike Christie fail_all_commands(conn, -1); 1886656cffc9SMike Christie flush_control_queues(session, conn); 1887656cffc9SMike Christie spin_unlock_bh(&session->lock); 18886724add1SMike Christie mutex_unlock(&session->eh_mutex); 18897996a778SMike Christie } 18907996a778SMike Christie 18917996a778SMike Christie void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) 18927996a778SMike Christie { 18937996a778SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 18947996a778SMike Christie struct iscsi_session *session = conn->session; 18957996a778SMike Christie 18967996a778SMike Christie switch (flag) { 18977996a778SMike Christie case STOP_CONN_RECOVER: 18987996a778SMike Christie case STOP_CONN_TERM: 18997996a778SMike Christie iscsi_start_session_recovery(session, conn, flag); 19008d2860b3SMike Christie break; 19017996a778SMike Christie default: 1902be2df72eSOr Gerlitz printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); 19037996a778SMike Christie } 19047996a778SMike Christie } 19057996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_stop); 19067996a778SMike Christie 19077996a778SMike Christie int iscsi_conn_bind(struct iscsi_cls_session *cls_session, 19087996a778SMike Christie struct iscsi_cls_conn *cls_conn, int is_leading) 19097996a778SMike Christie { 19107996a778SMike Christie struct iscsi_session *session = class_to_transport_session(cls_session); 191198644047SMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 19127996a778SMike Christie 19137996a778SMike Christie spin_lock_bh(&session->lock); 19147996a778SMike Christie if (is_leading) 19157996a778SMike Christie session->leadconn = conn; 191698644047SMike Christie spin_unlock_bh(&session->lock); 19177996a778SMike Christie 19187996a778SMike Christie /* 19197996a778SMike Christie * Unblock xmitworker(), Login Phase will pass through. 19207996a778SMike Christie */ 19217996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); 19227996a778SMike Christie clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); 19237996a778SMike Christie return 0; 19247996a778SMike Christie } 19257996a778SMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_bind); 19267996a778SMike Christie 1927a54a52caSMike Christie 1928a54a52caSMike Christie int iscsi_set_param(struct iscsi_cls_conn *cls_conn, 1929a54a52caSMike Christie enum iscsi_param param, char *buf, int buflen) 1930a54a52caSMike Christie { 1931a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 1932a54a52caSMike Christie struct iscsi_session *session = conn->session; 1933a54a52caSMike Christie uint32_t value; 1934a54a52caSMike Christie 1935a54a52caSMike Christie switch(param) { 1936843c0a8aSMike Christie case ISCSI_PARAM_FAST_ABORT: 1937843c0a8aSMike Christie sscanf(buf, "%d", &session->fast_abort); 1938843c0a8aSMike Christie break; 1939a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 1940a54a52caSMike Christie sscanf(buf, "%d", &conn->max_recv_dlength); 1941a54a52caSMike Christie break; 1942a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 1943a54a52caSMike Christie sscanf(buf, "%d", &conn->max_xmit_dlength); 1944a54a52caSMike Christie break; 1945a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 1946a54a52caSMike Christie sscanf(buf, "%d", &conn->hdrdgst_en); 1947a54a52caSMike Christie break; 1948a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 1949a54a52caSMike Christie sscanf(buf, "%d", &conn->datadgst_en); 1950a54a52caSMike Christie break; 1951a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 1952a54a52caSMike Christie sscanf(buf, "%d", &session->initial_r2t_en); 1953a54a52caSMike Christie break; 1954a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 1955a54a52caSMike Christie sscanf(buf, "%d", &session->max_r2t); 1956a54a52caSMike Christie break; 1957a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 1958a54a52caSMike Christie sscanf(buf, "%d", &session->imm_data_en); 1959a54a52caSMike Christie break; 1960a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 1961a54a52caSMike Christie sscanf(buf, "%d", &session->first_burst); 1962a54a52caSMike Christie break; 1963a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 1964a54a52caSMike Christie sscanf(buf, "%d", &session->max_burst); 1965a54a52caSMike Christie break; 1966a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 1967a54a52caSMike Christie sscanf(buf, "%d", &session->pdu_inorder_en); 1968a54a52caSMike Christie break; 1969a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 1970a54a52caSMike Christie sscanf(buf, "%d", &session->dataseq_inorder_en); 1971a54a52caSMike Christie break; 1972a54a52caSMike Christie case ISCSI_PARAM_ERL: 1973a54a52caSMike Christie sscanf(buf, "%d", &session->erl); 1974a54a52caSMike Christie break; 1975a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 1976a54a52caSMike Christie sscanf(buf, "%d", &value); 1977a54a52caSMike Christie BUG_ON(value); 1978a54a52caSMike Christie break; 1979a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 1980a54a52caSMike Christie sscanf(buf, "%d", &value); 1981a54a52caSMike Christie BUG_ON(value); 1982a54a52caSMike Christie break; 1983a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 1984a54a52caSMike Christie sscanf(buf, "%u", &conn->exp_statsn); 1985a54a52caSMike Christie break; 1986b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 1987b2c64167SMike Christie kfree(session->username); 1988b2c64167SMike Christie session->username = kstrdup(buf, GFP_KERNEL); 1989b2c64167SMike Christie if (!session->username) 1990b2c64167SMike Christie return -ENOMEM; 1991b2c64167SMike Christie break; 1992b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 1993b2c64167SMike Christie kfree(session->username_in); 1994b2c64167SMike Christie session->username_in = kstrdup(buf, GFP_KERNEL); 1995b2c64167SMike Christie if (!session->username_in) 1996b2c64167SMike Christie return -ENOMEM; 1997b2c64167SMike Christie break; 1998b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 1999b2c64167SMike Christie kfree(session->password); 2000b2c64167SMike Christie session->password = kstrdup(buf, GFP_KERNEL); 2001b2c64167SMike Christie if (!session->password) 2002b2c64167SMike Christie return -ENOMEM; 2003b2c64167SMike Christie break; 2004b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 2005b2c64167SMike Christie kfree(session->password_in); 2006b2c64167SMike Christie session->password_in = kstrdup(buf, GFP_KERNEL); 2007b2c64167SMike Christie if (!session->password_in) 2008b2c64167SMike Christie return -ENOMEM; 2009b2c64167SMike Christie break; 2010a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 2011a54a52caSMike Christie /* this should not change between logins */ 2012a54a52caSMike Christie if (session->targetname) 2013a54a52caSMike Christie break; 2014a54a52caSMike Christie 2015a54a52caSMike Christie session->targetname = kstrdup(buf, GFP_KERNEL); 2016a54a52caSMike Christie if (!session->targetname) 2017a54a52caSMike Christie return -ENOMEM; 2018a54a52caSMike Christie break; 2019a54a52caSMike Christie case ISCSI_PARAM_TPGT: 2020a54a52caSMike Christie sscanf(buf, "%d", &session->tpgt); 2021a54a52caSMike Christie break; 2022a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2023a54a52caSMike Christie sscanf(buf, "%d", &conn->persistent_port); 2024a54a52caSMike Christie break; 2025a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 2026a54a52caSMike Christie /* 2027a54a52caSMike Christie * this is the address returned in discovery so it should 2028a54a52caSMike Christie * not change between logins. 2029a54a52caSMike Christie */ 2030a54a52caSMike Christie if (conn->persistent_address) 2031a54a52caSMike Christie break; 2032a54a52caSMike Christie 2033a54a52caSMike Christie conn->persistent_address = kstrdup(buf, GFP_KERNEL); 2034a54a52caSMike Christie if (!conn->persistent_address) 2035a54a52caSMike Christie return -ENOMEM; 2036a54a52caSMike Christie break; 2037a54a52caSMike Christie default: 2038a54a52caSMike Christie return -ENOSYS; 2039a54a52caSMike Christie } 2040a54a52caSMike Christie 2041a54a52caSMike Christie return 0; 2042a54a52caSMike Christie } 2043a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_set_param); 2044a54a52caSMike Christie 2045a54a52caSMike Christie int iscsi_session_get_param(struct iscsi_cls_session *cls_session, 2046a54a52caSMike Christie enum iscsi_param param, char *buf) 2047a54a52caSMike Christie { 2048a54a52caSMike Christie struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); 2049a54a52caSMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 2050a54a52caSMike Christie int len; 2051a54a52caSMike Christie 2052a54a52caSMike Christie switch(param) { 2053843c0a8aSMike Christie case ISCSI_PARAM_FAST_ABORT: 2054843c0a8aSMike Christie len = sprintf(buf, "%d\n", session->fast_abort); 2055843c0a8aSMike Christie break; 2056a54a52caSMike Christie case ISCSI_PARAM_INITIAL_R2T_EN: 2057a54a52caSMike Christie len = sprintf(buf, "%d\n", session->initial_r2t_en); 2058a54a52caSMike Christie break; 2059a54a52caSMike Christie case ISCSI_PARAM_MAX_R2T: 2060a54a52caSMike Christie len = sprintf(buf, "%hu\n", session->max_r2t); 2061a54a52caSMike Christie break; 2062a54a52caSMike Christie case ISCSI_PARAM_IMM_DATA_EN: 2063a54a52caSMike Christie len = sprintf(buf, "%d\n", session->imm_data_en); 2064a54a52caSMike Christie break; 2065a54a52caSMike Christie case ISCSI_PARAM_FIRST_BURST: 2066a54a52caSMike Christie len = sprintf(buf, "%u\n", session->first_burst); 2067a54a52caSMike Christie break; 2068a54a52caSMike Christie case ISCSI_PARAM_MAX_BURST: 2069a54a52caSMike Christie len = sprintf(buf, "%u\n", session->max_burst); 2070a54a52caSMike Christie break; 2071a54a52caSMike Christie case ISCSI_PARAM_PDU_INORDER_EN: 2072a54a52caSMike Christie len = sprintf(buf, "%d\n", session->pdu_inorder_en); 2073a54a52caSMike Christie break; 2074a54a52caSMike Christie case ISCSI_PARAM_DATASEQ_INORDER_EN: 2075a54a52caSMike Christie len = sprintf(buf, "%d\n", session->dataseq_inorder_en); 2076a54a52caSMike Christie break; 2077a54a52caSMike Christie case ISCSI_PARAM_ERL: 2078a54a52caSMike Christie len = sprintf(buf, "%d\n", session->erl); 2079a54a52caSMike Christie break; 2080a54a52caSMike Christie case ISCSI_PARAM_TARGET_NAME: 2081a54a52caSMike Christie len = sprintf(buf, "%s\n", session->targetname); 2082a54a52caSMike Christie break; 2083a54a52caSMike Christie case ISCSI_PARAM_TPGT: 2084a54a52caSMike Christie len = sprintf(buf, "%d\n", session->tpgt); 2085a54a52caSMike Christie break; 2086b2c64167SMike Christie case ISCSI_PARAM_USERNAME: 2087b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username); 2088b2c64167SMike Christie break; 2089b2c64167SMike Christie case ISCSI_PARAM_USERNAME_IN: 2090b2c64167SMike Christie len = sprintf(buf, "%s\n", session->username_in); 2091b2c64167SMike Christie break; 2092b2c64167SMike Christie case ISCSI_PARAM_PASSWORD: 2093b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password); 2094b2c64167SMike Christie break; 2095b2c64167SMike Christie case ISCSI_PARAM_PASSWORD_IN: 2096b2c64167SMike Christie len = sprintf(buf, "%s\n", session->password_in); 2097b2c64167SMike Christie break; 2098a54a52caSMike Christie default: 2099a54a52caSMike Christie return -ENOSYS; 2100a54a52caSMike Christie } 2101a54a52caSMike Christie 2102a54a52caSMike Christie return len; 2103a54a52caSMike Christie } 2104a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_session_get_param); 2105a54a52caSMike Christie 2106a54a52caSMike Christie int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, 2107a54a52caSMike Christie enum iscsi_param param, char *buf) 2108a54a52caSMike Christie { 2109a54a52caSMike Christie struct iscsi_conn *conn = cls_conn->dd_data; 2110a54a52caSMike Christie int len; 2111a54a52caSMike Christie 2112a54a52caSMike Christie switch(param) { 2113a54a52caSMike Christie case ISCSI_PARAM_MAX_RECV_DLENGTH: 2114a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_recv_dlength); 2115a54a52caSMike Christie break; 2116a54a52caSMike Christie case ISCSI_PARAM_MAX_XMIT_DLENGTH: 2117a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->max_xmit_dlength); 2118a54a52caSMike Christie break; 2119a54a52caSMike Christie case ISCSI_PARAM_HDRDGST_EN: 2120a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->hdrdgst_en); 2121a54a52caSMike Christie break; 2122a54a52caSMike Christie case ISCSI_PARAM_DATADGST_EN: 2123a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->datadgst_en); 2124a54a52caSMike Christie break; 2125a54a52caSMike Christie case ISCSI_PARAM_IFMARKER_EN: 2126a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ifmarker_en); 2127a54a52caSMike Christie break; 2128a54a52caSMike Christie case ISCSI_PARAM_OFMARKER_EN: 2129a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->ofmarker_en); 2130a54a52caSMike Christie break; 2131a54a52caSMike Christie case ISCSI_PARAM_EXP_STATSN: 2132a54a52caSMike Christie len = sprintf(buf, "%u\n", conn->exp_statsn); 2133a54a52caSMike Christie break; 2134a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_PORT: 2135a54a52caSMike Christie len = sprintf(buf, "%d\n", conn->persistent_port); 2136a54a52caSMike Christie break; 2137a54a52caSMike Christie case ISCSI_PARAM_PERSISTENT_ADDRESS: 2138a54a52caSMike Christie len = sprintf(buf, "%s\n", conn->persistent_address); 2139a54a52caSMike Christie break; 2140a54a52caSMike Christie default: 2141a54a52caSMike Christie return -ENOSYS; 2142a54a52caSMike Christie } 2143a54a52caSMike Christie 2144a54a52caSMike Christie return len; 2145a54a52caSMike Christie } 2146a54a52caSMike Christie EXPORT_SYMBOL_GPL(iscsi_conn_get_param); 2147a54a52caSMike Christie 21480801c242SMike Christie int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, 21490801c242SMike Christie char *buf) 21500801c242SMike Christie { 21510801c242SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 21520801c242SMike Christie int len; 21530801c242SMike Christie 21540801c242SMike Christie switch (param) { 2155d8196ed2SMike Christie case ISCSI_HOST_PARAM_NETDEV_NAME: 2156d8196ed2SMike Christie if (!session->netdev) 2157d8196ed2SMike Christie len = sprintf(buf, "%s\n", "default"); 2158d8196ed2SMike Christie else 2159d8196ed2SMike Christie len = sprintf(buf, "%s\n", session->netdev); 2160d8196ed2SMike Christie break; 21610801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 21620801c242SMike Christie if (!session->hwaddress) 21630801c242SMike Christie len = sprintf(buf, "%s\n", "default"); 21640801c242SMike Christie else 21650801c242SMike Christie len = sprintf(buf, "%s\n", session->hwaddress); 21660801c242SMike Christie break; 21678ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 21688ad5781aSMike Christie if (!session->initiatorname) 21698ad5781aSMike Christie len = sprintf(buf, "%s\n", "unknown"); 21708ad5781aSMike Christie else 21718ad5781aSMike Christie len = sprintf(buf, "%s\n", session->initiatorname); 21728ad5781aSMike Christie break; 21738ad5781aSMike Christie 21740801c242SMike Christie default: 21750801c242SMike Christie return -ENOSYS; 21760801c242SMike Christie } 21770801c242SMike Christie 21780801c242SMike Christie return len; 21790801c242SMike Christie } 21800801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_get_param); 21810801c242SMike Christie 21820801c242SMike Christie int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, 21830801c242SMike Christie char *buf, int buflen) 21840801c242SMike Christie { 21850801c242SMike Christie struct iscsi_session *session = iscsi_hostdata(shost->hostdata); 21860801c242SMike Christie 21870801c242SMike Christie switch (param) { 2188d8196ed2SMike Christie case ISCSI_HOST_PARAM_NETDEV_NAME: 2189d8196ed2SMike Christie if (!session->netdev) 2190d8196ed2SMike Christie session->netdev = kstrdup(buf, GFP_KERNEL); 2191d8196ed2SMike Christie break; 21920801c242SMike Christie case ISCSI_HOST_PARAM_HWADDRESS: 21930801c242SMike Christie if (!session->hwaddress) 21940801c242SMike Christie session->hwaddress = kstrdup(buf, GFP_KERNEL); 21950801c242SMike Christie break; 21968ad5781aSMike Christie case ISCSI_HOST_PARAM_INITIATOR_NAME: 21978ad5781aSMike Christie if (!session->initiatorname) 21988ad5781aSMike Christie session->initiatorname = kstrdup(buf, GFP_KERNEL); 21998ad5781aSMike Christie break; 22000801c242SMike Christie default: 22010801c242SMike Christie return -ENOSYS; 22020801c242SMike Christie } 22030801c242SMike Christie 22040801c242SMike Christie return 0; 22050801c242SMike Christie } 22060801c242SMike Christie EXPORT_SYMBOL_GPL(iscsi_host_set_param); 22070801c242SMike Christie 22087996a778SMike Christie MODULE_AUTHOR("Mike Christie"); 22097996a778SMike Christie MODULE_DESCRIPTION("iSCSI library functions"); 22107996a778SMike Christie MODULE_LICENSE("GPL"); 2211