]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/scsi/qla2xxx/qla_attr.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-2.6
[linux-2.6-omap-h63xx.git] / drivers / scsi / qla2xxx / qla_attr.c
index 659a5d63467dc335a570f62e20f4d874bbbabe23..2efca52dff50c45629b82c6a9d3c3a2ea137d497 100644 (file)
@@ -1,20 +1,8 @@
 /*
- *                  QLOGIC LINUX SOFTWARE
- *
- * QLogic ISP2x00 device driver for Linux 2.6.x
- * Copyright (C) 2003-2005 QLogic Corporation
- * (www.qlogic.com)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
+ * QLogic Fibre Channel HBA Driver
+ * Copyright (c)  2003-2005 QLogic Corporation
  *
+ * See LICENSE.qla2xxx for copyright and licensing details.
  */
 #include "qla_def.h"
 
@@ -211,6 +199,221 @@ 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, "ISP%04X\n", ha->pdev->device);
+}
+
+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 ssize_t
+qla2x00_zio_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       int len = 0;
+
+       switch (ha->zio_mode) {
+       case QLA_ZIO_MODE_5:
+               len += snprintf(buf + len, PAGE_SIZE-len, "Mode 5\n");
+               break;
+       case QLA_ZIO_MODE_6:
+               len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
+               break;
+       case QLA_ZIO_DISABLED:
+               len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
+               break;
+       }
+       return len;
+}
+
+static ssize_t
+qla2x00_zio_store(struct class_device *cdev, const char *buf, size_t count)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       int val = 0;
+       uint16_t zio_mode;
+
+       if (sscanf(buf, "%d", &val) != 1)
+               return -EINVAL;
+
+       switch (val) {
+       case 1:
+               zio_mode = QLA_ZIO_MODE_5;
+               break;
+       case 2:
+               zio_mode = QLA_ZIO_MODE_6;
+               break;
+       default:
+               zio_mode = QLA_ZIO_DISABLED;
+               break;
+       }
+
+       /* Update per-hba values and queue a reset. */
+       if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) {
+               ha->zio_mode = zio_mode;
+               set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+       }
+       return strlen(buf);
+}
+
+static ssize_t
+qla2x00_zio_timer_show(struct class_device *cdev, char *buf)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+
+       return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
+}
+
+static ssize_t
+qla2x00_zio_timer_store(struct class_device *cdev, const char *buf,
+    size_t count)
+{
+       scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
+       int val = 0;
+       uint16_t zio_timer;
+
+       if (sscanf(buf, "%d", &val) != 1)
+               return -EINVAL;
+       if (val > 25500 || val < 100)
+               return -ERANGE;
+
+       zio_timer = (uint16_t)(val / 100);
+       ha->zio_timer = zio_timer;
+
+       return strlen(buf);
+}
+
+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);
+static CLASS_DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show,
+    qla2x00_zio_store);
+static CLASS_DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
+    qla2x00_zio_timer_store);
+
+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,
+       &class_device_attr_zio,
+       &class_device_attr_zio_timer,
+       NULL,
+};
+
 /* Host attributes. */
 
 static void
@@ -228,16 +431,16 @@ qla2x00_get_starget_node_name(struct scsi_target *starget)
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
        scsi_qla_host_t *ha = to_qla_host(host);
        fc_port_t *fcport;
-       uint64_t node_name = 0;
+       u64 node_name = 0;
 
        list_for_each_entry(fcport, &ha->fcports, list) {
                if (starget->id == fcport->os_target_id) {
-                       node_name = *(uint64_t *)fcport->node_name;
+                       node_name = wwn_to_u64(fcport->node_name);
                        break;
                }
        }
 
-       fc_starget_node_name(starget) = be64_to_cpu(node_name);
+       fc_starget_node_name(starget) = node_name;
 }
 
 static void
@@ -246,16 +449,16 @@ qla2x00_get_starget_port_name(struct scsi_target *starget)
        struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
        scsi_qla_host_t *ha = to_qla_host(host);
        fc_port_t *fcport;
-       uint64_t port_name = 0;
+       u64 port_name = 0;
 
        list_for_each_entry(fcport, &ha->fcports, list) {
                if (starget->id == fcport->os_target_id) {
-                       port_name = *(uint64_t *)fcport->port_name;
+                       port_name = wwn_to_u64(fcport->port_name);
                        break;
                }
        }
 
-       fc_starget_port_name(starget) = be64_to_cpu(port_name);
+       fc_starget_port_name(starget) = port_name;
 }
 
 static void
@@ -300,14 +503,26 @@ qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
        rport->dev_loss_tmo = ha->port_down_retry_count + 5;
 }
 
+static int
+qla2x00_issue_lip(struct Scsi_Host *shost)
+{
+       scsi_qla_host_t *ha = to_qla_host(shost);
+
+       set_bit(LOOP_RESET_NEEDED, &ha->dpc_flags);
+       return 0;
+}
+
 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,
@@ -320,13 +535,13 @@ struct fc_function_template qla2xxx_transport_functions = {
        .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
        .show_rport_dev_loss_tmo = 1,
 
+       .issue_fc_host_lip = qla2x00_issue_lip,
 };
 
 void
 qla2x00_init_host_attr(scsi_qla_host_t *ha)
 {
-       fc_host_node_name(ha->host) =
-           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_node_name(ha->host) = wwn_to_u64(ha->init_cb->node_name);
+       fc_host_port_name(ha->host) = wwn_to_u64(ha->init_cb->port_name);
+       fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
 }