]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/scsi/libiscsi.c
[SCSI] iscsi class, iscsi_tcp, ib_iser: add sysfs chap file
[mirror_ubuntu-bionic-kernel.git] / drivers / scsi / libiscsi.c
index d37048c96eab5163231f04917408a6c418c25b79..63981edf9ab92028a8928a13dd8e33f6b37e4d05 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mutex.h>
 #include <linux/kfifo.h>
 #include <linux/delay.h>
+#include <asm/unaligned.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -113,14 +114,15 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
         hdr->opcode = ISCSI_OP_SCSI_CMD;
         hdr->flags = ISCSI_ATTR_SIMPLE;
         int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun);
-        hdr->itt = ctask->itt | (conn->id << ISCSI_CID_SHIFT) |
-                         (session->age << ISCSI_AGE_SHIFT);
+        hdr->itt = build_itt(ctask->itt, conn->id, session->age);
         hdr->data_length = cpu_to_be32(sc->request_bufflen);
         hdr->cmdsn = cpu_to_be32(session->cmdsn);
         session->cmdsn++;
         hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
         memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
-        memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+       if (sc->cmd_len < MAX_COMMAND_SIZE)
+               memset(&hdr->cdb[sc->cmd_len], 0,
+                       MAX_COMMAND_SIZE - sc->cmd_len);
 
        ctask->data_count = 0;
        if (sc->sc_data_direction == DMA_TO_DEVICE) {
@@ -145,19 +147,19 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                ctask->unsol_datasn = 0;
 
                if (session->imm_data_en) {
-                       if (ctask->total_length >= session->first_burst)
+                       if (sc->request_bufflen >= session->first_burst)
                                ctask->imm_count = min(session->first_burst,
                                                        conn->max_xmit_dlength);
                        else
-                               ctask->imm_count = min(ctask->total_length,
+                               ctask->imm_count = min(sc->request_bufflen,
                                                        conn->max_xmit_dlength);
                        hton24(ctask->hdr->dlength, ctask->imm_count);
                } else
                        zero_data(ctask->hdr->dlength);
 
                if (!session->initial_r2t_en) {
-                       ctask->unsol_count = min(session->first_burst,
-                               ctask->total_length) - ctask->imm_count;
+                       ctask->unsol_count = min((session->first_burst),
+                               (sc->request_bufflen)) - ctask->imm_count;
                        ctask->unsol_offset = ctask->imm_count;
                }
 
@@ -165,7 +167,6 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
                        /* No unsolicit Data-Out's */
                        ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
        } else {
-               ctask->datasn = 0;
                hdr->flags |= ISCSI_FLAG_CMD_FINAL;
                zero_data(hdr->dlength);
 
@@ -270,14 +271,14 @@ invalid_datalen:
                        goto out;
                }
 
-               senselen = be16_to_cpu(*(uint16_t *)data);
+               senselen = be16_to_cpu(get_unaligned((__be16 *) data));
                if (datalen < senselen)
                        goto invalid_datalen;
 
                memcpy(sc->sense_buffer, data + 2,
                       min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
                debug_scsi("copied %d bytes of sense\n",
-                          min(senselen, SCSI_SENSE_BUFFERSIZE));
+                          min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE));
        }
 
        if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -338,7 +339,7 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
 
                if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
                        memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
-                       itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+                       itt = get_itt(rejected_pdu.itt);
                        printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
                                "due to DataDigest error.\n", itt,
                                rejected_pdu.opcode);
@@ -367,10 +368,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_mgmt_task *mtask;
        uint32_t itt;
 
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG))
-               itt = hdr->itt & ISCSI_ITT_MASK;
+       if (hdr->itt != RESERVED_ITT)
+               itt = get_itt(hdr->itt);
        else
-               itt = hdr->itt;
+               itt = ~0U;
 
        if (itt < session->cmds_max) {
                ctask = session->cmds[itt];
@@ -440,7 +441,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        iscsi_tmf_rsp(conn, hdr);
                        break;
                case ISCSI_OP_NOOP_IN:
-                       if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
+                       if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) {
                                rc = ISCSI_ERR_PROTO;
                                break;
                        }
@@ -457,7 +458,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                        rc = ISCSI_ERR_BAD_OPCODE;
                        break;
                }
-       } else if (itt == ISCSI_RESERVED_TAG) {
+       } else if (itt == ~0U) {
                rc = iscsi_check_assign_cmdsn(session,
                                             (struct iscsi_nopin*)hdr);
                if (rc)
@@ -470,7 +471,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
                                break;
                        }
 
-                       if (hdr->ttt == ISCSI_RESERVED_TAG)
+                       if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG))
                                break;
 
                        if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
@@ -516,24 +517,24 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        struct iscsi_cmd_task *ctask;
        uint32_t itt;
 
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-               if ((hdr->itt & ISCSI_AGE_MASK) !=
+       if (hdr->itt != RESERVED_ITT) {
+               if (((__force u32)hdr->itt & ISCSI_AGE_MASK) !=
                    (session->age << ISCSI_AGE_SHIFT)) {
                        printk(KERN_ERR "iscsi: received itt %x expected "
-                               "session age (%x)\n", hdr->itt,
+                               "session age (%x)\n", (__force u32)hdr->itt,
                                session->age & ISCSI_AGE_MASK);
                        return ISCSI_ERR_BAD_ITT;
                }
 
-               if ((hdr->itt & ISCSI_CID_MASK) !=
+               if (((__force u32)hdr->itt & ISCSI_CID_MASK) !=
                    (conn->id << ISCSI_CID_SHIFT)) {
                        printk(KERN_ERR "iscsi: received itt %x, expected "
-                               "CID (%x)\n", hdr->itt, conn->id);
+                               "CID (%x)\n", (__force u32)hdr->itt, conn->id);
                        return ISCSI_ERR_BAD_ITT;
                }
-               itt = hdr->itt & ISCSI_ITT_MASK;
+               itt = get_itt(hdr->itt);
        } else
-               itt = hdr->itt;
+               itt = ~0U;
 
        if (itt < session->cmds_max) {
                ctask = session->cmds[itt];
@@ -578,7 +579,7 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err)
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_failure);
 
-static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
+static int iscsi_xmit_mtask(struct iscsi_conn *conn)
 {
        struct iscsi_hdr *hdr = conn->mtask->hdr;
        int rc, was_logout = 0;
@@ -592,6 +593,9 @@ static int iscsi_xmit_imm_task(struct iscsi_conn *conn)
        if (rc)
                return rc;
 
+       /* done with this in-progress mtask */
+       conn->mtask = NULL;
+
        if (was_logout) {
                set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
                return -ENODATA;
@@ -644,11 +648,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                conn->ctask = NULL;
        }
        if (conn->mtask) {
-               rc = iscsi_xmit_imm_task(conn);
+               rc = iscsi_xmit_mtask(conn);
                if (rc)
                        goto again;
-               /* done with this in-progress mtask */
-               conn->mtask = NULL;
        }
 
        /* process immediate first */
@@ -659,12 +661,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                        list_add_tail(&conn->mtask->running,
                                      &conn->mgmt_run_list);
                        spin_unlock_bh(&conn->session->lock);
-                       rc = iscsi_xmit_imm_task(conn);
+                       rc = iscsi_xmit_mtask(conn);
                        if (rc)
                                goto again;
                }
-               /* done with this mtask */
-               conn->mtask = NULL;
        }
 
        /* process command queue */
@@ -702,12 +702,10 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
                        list_add_tail(&conn->mtask->running,
                                      &conn->mgmt_run_list);
                        spin_unlock_bh(&conn->session->lock);
-                       rc = tt->xmit_mgmt_task(conn, conn->mtask);
-                       if (rc)
+                       rc = iscsi_xmit_mtask(conn);
+                       if (rc)
                                goto again;
                }
-               /* done with this mtask */
-               conn->mtask = NULL;
        }
 
        return -ENODATA;
@@ -817,7 +815,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
        ctask->conn = conn;
        ctask->sc = sc;
        INIT_LIST_HEAD(&ctask->running);
-       ctask->total_length = sc->request_bufflen;
        iscsi_prep_scsi_cmd_pdu(ctask);
 
        session->tt->init_cmd_task(ctask);
@@ -896,9 +893,8 @@ iscsi_conn_send_generic(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
        /*
         * pre-format CmdSN for outgoing PDU.
         */
-       if (hdr->itt != cpu_to_be32(ISCSI_RESERVED_TAG)) {
-               hdr->itt = mtask->itt | (conn->id << ISCSI_CID_SHIFT) |
-                          (session->age << ISCSI_AGE_SHIFT);
+       if (hdr->itt != RESERVED_ITT) {
+               hdr->itt = build_itt(mtask->itt, conn->id, session->age);
                nop->cmdsn = cpu_to_be32(session->cmdsn);
                if (conn->c_stage == ISCSI_CONN_STARTED &&
                    !(hdr->opcode & ISCSI_OP_IMMEDIATE))
@@ -1064,7 +1060,7 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
 
        spin_lock_bh(&session->lock);
        ctask->mtask = (struct iscsi_mgmt_task *)
-                       session->mgmt_cmds[(hdr->itt & ISCSI_ITT_MASK) -
+                       session->mgmt_cmds[get_itt(hdr->itt) -
                                        ISCSI_MGMT_ITT_OFFSET];
 
        if (conn->tmabort_state == TMABORT_INITIAL) {
@@ -1465,7 +1461,13 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
        iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
        iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
 
+       kfree(session->password);
+       kfree(session->password_in);
+       kfree(session->username);
+       kfree(session->username_in);
        kfree(session->targetname);
+       kfree(session->hwaddress);
+       kfree(session->initiatorname);
 
        iscsi_destroy_session(cls_session);
        scsi_host_put(shost);
@@ -1525,7 +1527,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
        }
        spin_unlock_bh(&session->lock);
 
-       data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
+       data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL);
        if (!data)
                goto login_mtask_data_alloc_fail;
        conn->login_mtask->data = conn->data = data;
@@ -1599,6 +1601,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
                wake_up(&conn->ehwait);
        }
 
+       /* flush queued up work because we free the connection below */
+       scsi_flush_work(session->host);
+
        spin_lock_bh(&session->lock);
        kfree(conn->data);
        kfree(conn->persistent_address);
@@ -1868,6 +1873,30 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
        case ISCSI_PARAM_EXP_STATSN:
                sscanf(buf, "%u", &conn->exp_statsn);
                break;
+       case ISCSI_PARAM_USERNAME:
+               kfree(session->username);
+               session->username = kstrdup(buf, GFP_KERNEL);
+               if (!session->username)
+                       return -ENOMEM;
+               break;
+       case ISCSI_PARAM_USERNAME_IN:
+               kfree(session->username_in);
+               session->username_in = kstrdup(buf, GFP_KERNEL);
+               if (!session->username_in)
+                       return -ENOMEM;
+               break;
+       case ISCSI_PARAM_PASSWORD:
+               kfree(session->password);
+               session->password = kstrdup(buf, GFP_KERNEL);
+               if (!session->password)
+                       return -ENOMEM;
+               break;
+       case ISCSI_PARAM_PASSWORD_IN:
+               kfree(session->password_in);
+               session->password_in = kstrdup(buf, GFP_KERNEL);
+               if (!session->password_in)
+                       return -ENOMEM;
+               break;
        case ISCSI_PARAM_TARGET_NAME:
                /* this should not change between logins */
                if (session->targetname)
@@ -1941,6 +1970,18 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
        case ISCSI_PARAM_TPGT:
                len = sprintf(buf, "%d\n", session->tpgt);
                break;
+       case ISCSI_PARAM_USERNAME:
+               len = sprintf(buf, "%s\n", session->username);
+               break;
+       case ISCSI_PARAM_USERNAME_IN:
+               len = sprintf(buf, "%s\n", session->username_in);
+               break;
+       case ISCSI_PARAM_PASSWORD:
+               len = sprintf(buf, "%s\n", session->password);
+               break;
+       case ISCSI_PARAM_PASSWORD_IN:
+               len = sprintf(buf, "%s\n", session->password_in);
+               break;
        default:
                return -ENOSYS;
        }
@@ -1991,6 +2032,56 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
 }
 EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
 
+int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+                        char *buf)
+{
+       struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+       int len;
+
+       switch (param) {
+       case ISCSI_HOST_PARAM_HWADDRESS:
+               if (!session->hwaddress)
+                       len = sprintf(buf, "%s\n", "default");
+               else
+                       len = sprintf(buf, "%s\n", session->hwaddress);
+               break;
+       case ISCSI_HOST_PARAM_INITIATOR_NAME:
+               if (!session->initiatorname)
+                       len = sprintf(buf, "%s\n", "unknown");
+               else
+                       len = sprintf(buf, "%s\n", session->initiatorname);
+               break;
+
+       default:
+               return -ENOSYS;
+       }
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_get_param);
+
+int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param,
+                        char *buf, int buflen)
+{
+       struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+
+       switch (param) {
+       case ISCSI_HOST_PARAM_HWADDRESS:
+               if (!session->hwaddress)
+                       session->hwaddress = kstrdup(buf, GFP_KERNEL);
+               break;
+       case ISCSI_HOST_PARAM_INITIATOR_NAME:
+               if (!session->initiatorname)
+                       session->initiatorname = kstrdup(buf, GFP_KERNEL);
+               break;
+       default:
+               return -ENOSYS;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_host_set_param);
+
 MODULE_AUTHOR("Mike Christie");
 MODULE_DESCRIPTION("iSCSI library functions");
 MODULE_LICENSE("GPL");