Merge git://www.linux-watchdog.org/linux-watchdog
[pandora-kernel.git] / drivers / scsi / qla4xxx / ql4_os.c
index 0bcb6fd..30f31b1 100644 (file)
@@ -78,8 +78,8 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
                                  enum iscsi_param param, char *buf);
 static int qla4xxx_host_get_param(struct Scsi_Host *shost,
                                  enum iscsi_host_param param, char *buf);
-static int qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data,
-                                  int count);
+static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data,
+                                  uint32_t len);
 static int qla4xxx_get_iface_param(struct iscsi_iface *iface,
                                   enum iscsi_param_type param_type,
                                   int param, char *buf);
@@ -203,6 +203,8 @@ static mode_t ql4_attr_is_visible(int param_type, int param)
                }
        case ISCSI_PARAM:
                switch (param) {
+               case ISCSI_PARAM_PERSISTENT_ADDRESS:
+               case ISCSI_PARAM_PERSISTENT_PORT:
                case ISCSI_PARAM_CONN_ADDRESS:
                case ISCSI_PARAM_CONN_PORT:
                case ISCSI_PARAM_TARGET_NAME:
@@ -718,7 +720,7 @@ static void qla4xxx_set_ipv6(struct scsi_qla_host *ha,
                        qla4xxx_destroy_ipv6_iface(ha);
                }
                break;
-       case ISCSI_NET_PARAM_VLAN_ID:
+       case ISCSI_NET_PARAM_VLAN_TAG:
                if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag))
                        break;
                init_fw_cb->ipv6_vlan_tag =
@@ -790,7 +792,7 @@ static void qla4xxx_set_ipv4(struct scsi_qla_host *ha,
                        qla4xxx_destroy_ipv4_iface(ha);
                }
                break;
-       case ISCSI_NET_PARAM_VLAN_ID:
+       case ISCSI_NET_PARAM_VLAN_TAG:
                if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag))
                        break;
                init_fw_cb->ipv4_vlan_tag =
@@ -842,7 +844,7 @@ qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb)
 }
 
 static int
-qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count)
+qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len)
 {
        struct scsi_qla_host *ha = to_qla_host(shost);
        int rval = 0;
@@ -851,8 +853,8 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count)
        dma_addr_t init_fw_cb_dma;
        uint32_t mbox_cmd[MBOX_REG_COUNT];
        uint32_t mbox_sts[MBOX_REG_COUNT];
-       uint32_t total_param_count;
-       uint32_t length;
+       uint32_t rem = len;
+       struct nlattr *attr;
 
        init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
                                        sizeof(struct addr_ctrl_blk),
@@ -873,11 +875,8 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count)
                goto exit_init_fw_cb;
        }
 
-       total_param_count = count;
-       iface_param = (struct iscsi_iface_param_info *)data;
-
-       for ( ; total_param_count != 0; total_param_count--) {
-               length = iface_param->len;
+       nla_for_each_attr(attr, data, len, rem) {
+               iface_param = nla_data(attr);
 
                if (iface_param->param_type != ISCSI_NET_PARAM)
                        continue;
@@ -914,10 +913,6 @@ qla4xxx_iface_set_param(struct Scsi_Host *shost, char *data, int count)
                        ql4_printk(KERN_ERR, ha, "Invalid iface type\n");
                        break;
                }
-
-               iface_param = (struct iscsi_iface_param_info *)
-                                               ((uint8_t *)iface_param +
-                           sizeof(struct iscsi_iface_param_info) + length);
        }
 
        init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A);
@@ -1004,6 +999,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep,
        qla_ep = ep->dd_data;
        dst_addr = (struct sockaddr *)&qla_ep->dst_addr;
        ha = to_qla_host(qla_ep->host);
+
 get_ddb_index:
        ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES);
 
@@ -1063,6 +1059,8 @@ static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess)
        ddb_entry = sess->dd_data;
        ha = ddb_entry->ha;
 
+       qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
        qla4xxx_free_ddb(ha, ddb_entry);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -1139,8 +1137,12 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
                */
                if (mbx_sts)
                        if (ddb_entry->fw_ddb_device_state ==
-                                                       DDB_DS_SESSION_ACTIVE)
+                                               DDB_DS_SESSION_ACTIVE) {
+                               iscsi_conn_start(ddb_entry->conn);
+                               iscsi_conn_login_event(ddb_entry->conn,
+                                               ISCSI_CONN_STATE_LOGGED_IN);
                                goto exit_set_param;
+                       }
 
                ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n",
                           __func__, ddb_entry->fw_ddb_index);
@@ -1155,10 +1157,13 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn)
                goto exit_conn_start;
        }
 
-       ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
+       if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE)
+               ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS;
+
+       DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__,
+                     ddb_entry->fw_ddb_device_state));
 
 exit_set_param:
-       iscsi_conn_start(cls_conn);
        ret = 0;
 
 exit_conn_start:
@@ -1183,14 +1188,6 @@ static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn)
        options = LOGOUT_OPTION_CLOSE_SESSION;
        if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR)
                ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__);
-       else
-               qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index);
-
-       /*
-        * Clear the DDB bit so that next login can use the bit
-        * if FW is not clearing the DDB entry then set DDB will fail anyways
-        */
-       clear_bit(ddb_entry->fw_ddb_index, ha->ddb_idx_map);
 }
 
 static void qla4xxx_task_work(struct work_struct *wdata)
@@ -1270,7 +1267,7 @@ static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
        DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n",
                      __func__, task->conn->max_recv_dlength, hdr_len));
 
-       task_data->resp_len = task->conn->max_recv_dlength;
+       task_data->resp_len = task->conn->max_recv_dlength + hdr_len;
        task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev,
                                                    task_data->resp_len,
                                                    &task_data->resp_dma,
@@ -1278,8 +1275,9 @@ static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
        if (!task_data->resp_buffer)
                goto exit_alloc_pdu;
 
+       task_data->req_len = task->data_count + hdr_len;
        task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev,
-                                                  task->data_count + hdr_len,
+                                                  task_data->req_len,
                                                   &task_data->req_dma,
                                                   GFP_ATOMIC);
        if (!task_data->req_buffer)
@@ -1297,7 +1295,7 @@ exit_alloc_pdu:
                                  task_data->resp_buffer, task_data->resp_dma);
 
        if (task_data->req_buffer)
-               dma_free_coherent(&ha->pdev->dev, task->data_count + hdr_len,
+               dma_free_coherent(&ha->pdev->dev, task_data->req_len,
                                  task_data->req_buffer, task_data->req_dma);
        return -ENOMEM;
 }
@@ -1326,7 +1324,7 @@ static void qla4xxx_task_cleanup(struct iscsi_task *task)
 
        dma_free_coherent(&ha->pdev->dev, task_data->resp_len,
                          task_data->resp_buffer, task_data->resp_dma);
-       dma_free_coherent(&ha->pdev->dev, task->data_count + hdr_len,
+       dma_free_coherent(&ha->pdev->dev, task_data->req_len,
                          task_data->req_buffer, task_data->req_dma);
        return;
 }
@@ -2779,12 +2777,10 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[])
 
        func_num = PCI_FUNC(ha->pdev->devfn);
 
-       DEBUG2(ql4_printk(KERN_INFO, ha,
-                         "%s: Get FW  boot info for 0x%x func %d\n", __func__,
-                         (is_qla4032(ha) ? PCI_DEVICE_ID_QLOGIC_ISP4032 :
-                          PCI_DEVICE_ID_QLOGIC_ISP8022), func_num));
+       ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n",
+                  __func__, ha->pdev->device, func_num);
 
-       if (is_qla4032(ha)) {
+       if (is_qla40XX(ha)) {
                if (func_num == 1) {
                        addr = NVRAM_PORT0_BOOT_MODE;
                        pri_addr = NVRAM_PORT0_BOOT_PRI_TGT;
@@ -2877,6 +2873,60 @@ exit_boot_info:
        return ret;
 }
 
+/**
+ * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password
+ * @ha: pointer to adapter structure
+ * @username: CHAP username to be returned
+ * @password: CHAP password to be returned
+ *
+ * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP
+ * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/.
+ * So from the CHAP cache find the first BIDI CHAP entry and set it
+ * to the boot record in sysfs.
+ **/
+static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username,
+                           char *password)
+{
+       int i, ret = -EINVAL;
+       int max_chap_entries = 0;
+       struct ql4_chap_table *chap_table;
+
+       if (is_qla8022(ha))
+               max_chap_entries = (ha->hw.flt_chap_size / 2) /
+                                               sizeof(struct ql4_chap_table);
+       else
+               max_chap_entries = MAX_CHAP_ENTRIES_40XX;
+
+       if (!ha->chap_list) {
+               ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
+               return ret;
+       }
+
+       mutex_lock(&ha->chap_sem);
+       for (i = 0; i < max_chap_entries; i++) {
+               chap_table = (struct ql4_chap_table *)ha->chap_list + i;
+               if (chap_table->cookie !=
+                   __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
+                       continue;
+               }
+
+               if (chap_table->flags & BIT_7) /* local */
+                       continue;
+
+               if (!(chap_table->flags & BIT_6)) /* Not BIDI */
+                       continue;
+
+               strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
+               strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&ha->chap_sem);
+
+       return ret;
+}
+
+
 static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
                                   struct ql4_boot_session_info *boot_sess,
                                   uint16_t ddb_index)
@@ -2948,10 +2998,10 @@ static int qla4xxx_get_boot_target(struct scsi_qla_host *ha,
 
                DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n"));
 
-               ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap.
-                                      intr_chap_name,
-                                      (char *)&boot_conn->chap.intr_secret,
-                                      (idx + 1));
+               ret = qla4xxx_get_bidi_chap(ha,
+                                   (char *)&boot_conn->chap.intr_chap_name,
+                                   (char *)&boot_conn->chap.intr_secret);
+
                if (ret) {
                        ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n");
                        ret = QLA_ERROR;