Merge git://git.skbuff.net/gitroot/yoshfuji/linux-2.6-git-rfc3542
[sfrench/cifs-2.6.git] / drivers / scsi / qla2xxx / qla_attr.c
index 9bc1f153f7eaf833f0aa3d77082b3ac5fc9b5f37..fe0fce71adc70153d17abaa0851b15b3a102b862 100644 (file)
@@ -63,23 +63,29 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
                            ha->host_no);
 
                        vfree(ha->fw_dump_buffer);
-                       free_pages((unsigned long)ha->fw_dump,
-                           ha->fw_dump_order);
+                       if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha))
+                               free_pages((unsigned long)ha->fw_dump,
+                                   ha->fw_dump_order);
 
                        ha->fw_dump_reading = 0;
                        ha->fw_dump_buffer = NULL;
                        ha->fw_dump = NULL;
+                       ha->fw_dumped = 0;
                }
                break;
        case 1:
-               if (ha->fw_dump != NULL && !ha->fw_dump_reading) {
+               if ((ha->fw_dump || ha->fw_dumped) && !ha->fw_dump_reading) {
                        ha->fw_dump_reading = 1;
 
-                       dump_size = FW_DUMP_SIZE_1M;
-                       if (ha->fw_memory_size < 0x20000) 
-                               dump_size = FW_DUMP_SIZE_128K;
-                       else if (ha->fw_memory_size < 0x80000) 
-                               dump_size = FW_DUMP_SIZE_512K;
+                       if (IS_QLA24XX(ha) || IS_QLA25XX(ha))
+                               dump_size = FW_DUMP_SIZE_24XX;
+                       else {
+                               dump_size = FW_DUMP_SIZE_1M;
+                               if (ha->fw_memory_size < 0x20000)
+                                       dump_size = FW_DUMP_SIZE_128K;
+                               else if (ha->fw_memory_size < 0x80000)
+                                       dump_size = FW_DUMP_SIZE_512K;
+                       }
                        ha->fw_dump_buffer = (char *)vmalloc(dump_size);
                        if (ha->fw_dump_buffer == NULL) {
                                qla_printk(KERN_WARNING, ha,
@@ -93,10 +99,7 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
                            "Firmware dump ready for read on (%ld).\n",
                            ha->host_no);
                        memset(ha->fw_dump_buffer, 0, dump_size);
-                       if (IS_QLA2100(ha) || IS_QLA2200(ha))
-                               qla2100_ascii_fw_dump(ha);
-                       else
-                               qla2300_ascii_fw_dump(ha);
+                       ha->isp_ops.ascii_fw_dump(ha);
                        ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
                }
                break;
@@ -121,23 +124,15 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off,
 {
        struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
            struct device, kobj)));
-       uint16_t        *witer;
        unsigned long   flags;
-       uint16_t        cnt;
 
-       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
                return 0;
 
        /* Read NVRAM. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qla2x00_lock_nvram_access(ha);
-       witer = (uint16_t *)buf;
-       for (cnt = 0; cnt < count / 2; cnt++) {
-               *witer = cpu_to_le16(qla2x00_get_nvram_word(ha,
-                   cnt+ha->nvram_base));
-               witer++;
-       }
-       qla2x00_unlock_nvram_access(ha);
+       ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
+           ha->nvram_size);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        return (count);
@@ -149,34 +144,38 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off,
 {
        struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
            struct device, kobj)));
-       uint8_t         *iter;
-       uint16_t        *witer;
        unsigned long   flags;
        uint16_t        cnt;
-       uint8_t         chksum;
 
-       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
                return 0;
 
        /* Checksum NVRAM. */
-       iter = (uint8_t *)buf;
-       chksum = 0;
-       for (cnt = 0; cnt < count - 1; cnt++)
-               chksum += *iter++;
-       chksum = ~chksum + 1;
-       *iter = chksum;
+       if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) {
+               uint32_t *iter;
+               uint32_t chksum;
+
+               iter = (uint32_t *)buf;
+               chksum = 0;
+               for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
+                       chksum += le32_to_cpu(*iter++);
+               chksum = ~chksum + 1;
+               *iter = cpu_to_le32(chksum);
+       } else {
+               uint8_t *iter;
+               uint8_t chksum;
+
+               iter = (uint8_t *)buf;
+               chksum = 0;
+               for (cnt = 0; cnt < count - 1; cnt++)
+                       chksum += *iter++;
+               chksum = ~chksum + 1;
+               *iter = chksum;
+       }
 
        /* Write NVRAM. */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       qla2x00_lock_nvram_access(ha);
-       qla2x00_release_nvram_protection(ha);
-       witer = (uint16_t *)buf;
-       for (cnt = 0; cnt < count / 2; cnt++) {
-               qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,
-                   cpu_to_le16(*witer));
-               witer++;
-       }
-       qla2x00_unlock_nvram_access(ha);
+       ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        return (count);
@@ -188,7 +187,7 @@ static struct bin_attribute sysfs_nvram_attr = {
                .mode = S_IRUSR | S_IWUSR,
                .owner = THIS_MODULE,
        },
-       .size = sizeof(nvram_t),
+       .size = 0,
        .read = qla2x00_sysfs_read_nvram,
        .write = qla2x00_sysfs_write_nvram,
 };
@@ -199,6 +198,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
        struct Scsi_Host *host = ha->host;
 
        sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+       sysfs_nvram_attr.size = ha->nvram_size;
        sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
 }
 
@@ -211,6 +211,138 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
        sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
 }
 
+/* Scsi_Host attributes. */
+
+static ssize_t
+qla2x00_drvr_version_show(struct class_device *cdev, char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
+}
+
+static ssize_t
+qla2x00_fw_version_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       char fw_str[30];
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+           ha->isp_ops.fw_version_str(ha, fw_str));
+}
+
+static ssize_t
+qla2x00_serial_num_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       uint32_t sn;
+
+       sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
+       return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
+           sn % 100000);
+}
+
+static ssize_t
+qla2x00_isp_name_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name);
+}
+
+static ssize_t
+qla2x00_isp_id_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
+           ha->product_id[0], ha->product_id[1], ha->product_id[2],
+           ha->product_id[3]);
+}
+
+static ssize_t
+qla2x00_model_name_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
+}
+
+static ssize_t
+qla2x00_model_desc_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+           ha->model_desc ? ha->model_desc: "");
+}
+
+static ssize_t
+qla2x00_pci_info_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       char pci_info[30];
+
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+           ha->isp_ops.pci_info_str(ha, pci_info));
+}
+
+static ssize_t
+qla2x00_state_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       int len = 0;
+
+       if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+           atomic_read(&ha->loop_state) == LOOP_DEAD)
+               len = snprintf(buf, PAGE_SIZE, "Link Down\n");
+       else if (atomic_read(&ha->loop_state) != LOOP_READY ||
+           test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+           test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags))
+               len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
+       else {
+               len = snprintf(buf, PAGE_SIZE, "Link Up - ");
+
+               switch (ha->current_topology) {
+               case ISP_CFG_NL:
+                       len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+                       break;
+               case ISP_CFG_FL:
+                       len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
+                       break;
+               case ISP_CFG_N:
+                       len += snprintf(buf + len, PAGE_SIZE-len,
+                           "N_Port to N_Port\n");
+                       break;
+               case ISP_CFG_F:
+                       len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
+                       break;
+               default:
+                       len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
+                       break;
+               }
+       }
+       return len;
+}
+
+static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show,
+       NULL);
+static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
+static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
+static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
+static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
+static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
+static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
+static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
+static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL);
+
+struct class_device_attribute *qla2x00_host_attrs[] = {
+       &class_device_attr_driver_version,
+       &class_device_attr_fw_version,
+       &class_device_attr_serial_num,
+       &class_device_attr_isp_name,
+       &class_device_attr_isp_id,
+       &class_device_attr_model_name,
+       &class_device_attr_model_desc,
+       &class_device_attr_pci_info,
+       &class_device_attr_state,
+       NULL,
+};
+
 /* Host attributes. */
 
 static void
@@ -304,10 +436,13 @@ struct fc_function_template qla2xxx_transport_functions = {
 
        .show_host_node_name = 1,
        .show_host_port_name = 1,
+       .show_host_supported_classes = 1,
+
        .get_host_port_id = qla2x00_get_host_port_id,
        .show_host_port_id = 1,
 
        .dd_fcrport_size = sizeof(struct fc_port *),
+       .show_rport_supported_classes = 1,
 
        .get_starget_node_name = qla2x00_get_starget_node_name,
        .show_starget_node_name = 1,
@@ -329,4 +464,5 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha)
            be64_to_cpu(*(uint64_t *)ha->init_cb->node_name);
        fc_host_port_name(ha->host) =
            be64_to_cpu(*(uint64_t *)ha->init_cb->port_name);
+       fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
 }