ibmvscsis target sysfs configuration interfaces
Signed-off-by: Dave Boutcher <[email protected]>
Signed-off-by: Santiago Leon <[email protected]>
Signed-off-by: Linda Xie <[email protected]>
--- linux-2.6.14-rc4-ibmvscsis-test/drivers/scsi/ibmvscsi/ibmvscsis.c 2005-10-16 20:31:10.000000000 -0500
+++ linux-2.6.14-rc4-ibmvscsis/drivers/scsi/ibmvscsi/ibmvscsis.c 2005-10-16 20:37:18.000000000 -0500
@@ -3125,6 +3125,455 @@
}
/* ==============================================================
+ * SYSFS Routines
+ * ==============================================================
+ */
+static struct class_interface vscsis_interface = {
+ .add = add_scsi_device,
+ .remove = rem_scsi_device,
+};
+
+static struct kobj_type ktype_vscsi_target;
+static struct kobj_type ktype_vscsi_bus;
+static struct kobj_type ktype_vscsi_stats;
+
+static void vscsi_target_release(struct kobject *kobj) {
+ struct vdev *tmpdev =
+ container_of(kobj,struct vdev,kobj);
+ kfree(tmpdev);
+}
+
+static void vscsi_bus_release(struct kobject *kobj) {
+ struct vbus *tmpbus =
+ container_of(kobj,struct vbus,kobj);
+ kfree(tmpbus);
+}
+
+static void set_num_targets(struct vbus* vbus, long value)
+{
+ struct device *dev =
+ container_of(vbus->kobj.parent, struct device , kobj);
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+ int cur_num_targets = atomic_read(&vbus->num_targets);
+ unsigned long flags;
+ struct vdev *tmpdev;
+
+ /* Growing */
+ if (cur_num_targets < value) {
+ int i;
+ for (i = cur_num_targets; i < value; i++) {
+ tmpdev = (struct vdev *)kmalloc(sizeof(struct vdev),
+ GFP_KERNEL);
+ if (!tmpdev) {
+ err("Couldn't allocate target memory %d\n", i);
+ return;
+ }
+ memset(tmpdev, 0, sizeof(struct vdev));
+
+ tmpdev->lun = make_lun(vbus->bus_num, i, 0);
+ tmpdev->b.blocksize = PAGE_CACHE_SIZE;
+ tmpdev->b.sectsize = 512;
+ tmpdev->disabled = 1;
+
+ tmpdev->kobj.parent = &vbus->kobj;
+ sprintf(tmpdev->kobj.name, "target%d", i);
+ tmpdev->kobj.ktype = &ktype_vscsi_target;
+ kobject_register(&tmpdev->kobj);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ if (vbus->vdev[i]) {
+ /* Race!!! */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ kobject_unregister(&tmpdev->kobj);
+ continue;
+ }
+
+ adapter->nvdevs++;
+ atomic_inc(&vbus->num_targets);
+ vbus->vdev[i] = tmpdev;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ }
+ } else { /* shrinking */
+ int i;
+ for (i = cur_num_targets - 1; i >= value; i--)
+ {
+ if (!vbus->vdev[i]->disabled) {
+ err("Can't remove active target %d\n", i);
+ return;
+ }
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ tmpdev = vbus->vdev[i];
+ vbus->vdev[i] = NULL;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ if (tmpdev)
+ kobject_unregister(&tmpdev->kobj);
+
+ adapter->nvdevs--;
+ atomic_dec(&vbus->num_targets);
+ }
+ }
+}
+
+static void set_num_buses(struct device *dev, long value)
+{
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+ int cur_num_buses = atomic_read(&adapter->num_buses);
+ unsigned long flags;
+ struct vbus *tmpbus;
+
+ if (cur_num_buses < value) { /* growing */
+ int i;
+ for (i = cur_num_buses; i < value; i++) {
+ tmpbus = (struct vbus *) kmalloc(sizeof(struct vbus),
+ GFP_KERNEL);
+ if (!tmpbus) {
+ err("Couldn't allocate bus %d memory\n", i);
+ return;
+ }
+
+ memset(tmpbus, 0, sizeof(struct vbus));
+ tmpbus->bus_num = i;
+ tmpbus->kobj.parent = &dev->kobj;
+ sprintf(tmpbus->kobj.name, "bus%d", i);
+ tmpbus->kobj.ktype = &ktype_vscsi_bus;
+ kobject_register(&tmpbus->kobj);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+
+ if (adapter->vbus[i] != NULL) {
+ /* Race condition! */
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ kobject_unregister(&tmpbus->kobj);
+ continue;
+ }
+
+ adapter->vbus[i] = tmpbus;
+
+ atomic_inc(&adapter->num_buses);
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ set_num_targets(adapter->vbus[i], 1);
+ }
+
+ } else if (cur_num_buses > value) { /* shrinking */
+ int i, j, active_target;
+ for (i = cur_num_buses - 1; i >= value; i--) {
+ active_target = -1;
+ for (j = 0; j < TARGETS_PER_BUS; j++) {
+ if (adapter->vbus[i]->vdev[j] &&
+ !adapter->vbus[i]->vdev[j]->disabled) {
+ active_target = j;
+ break;
+ }
+ }
+ if (active_target != -1) {
+ err("Can't remove bus%d, target%d active\n",
+ i, active_target);
+ return ;
+ }
+
+ set_num_targets(adapter->vbus[i], 0);
+
+ spin_lock_irqsave(&adapter->lock, flags);
+ atomic_dec(&adapter->num_buses);
+ tmpbus = adapter->vbus[i];
+ adapter->vbus[i] = NULL;
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ /* If we race this could already be NULL */
+ if (tmpbus)
+ kobject_unregister(&tmpbus->kobj);
+ }
+ }
+}
+
+/* Target sysfs stuff */
+static ATTR(target, device, 0644);
+static ATTR(target, active, 0644);
+static ATTR(target, ro, 0644);
+
+static ssize_t vscsi_target_show(struct kobject * kobj,
+ struct attribute * attr, char * buf)
+{
+ struct vdev *vdev = container_of(kobj, struct vdev, kobj);
+ struct device *dev = container_of(kobj->parent->parent,
+ struct device, kobj);
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+ unsigned long flags;
+ ssize_t returned;
+
+ spin_lock_irqsave(&adapter->lock, flags);
+
+ if (attr == &vscsi_target_device_attr)
+ returned = sprintf(buf, "%s\n", vdev->device_name);
+ else if (attr == &vscsi_target_active_attr)
+ returned = sprintf(buf, "%d\n", !vdev->disabled);
+ else if (attr == &vscsi_target_ro_attr)
+ returned = sprintf(buf, "%d\n", vdev->b.ro);
+ else {
+ returned = -EFAULT;
+ BUG();
+ }
+
+ spin_unlock_irqrestore(&adapter->lock, flags);
+
+ return returned;
+}
+
+static ssize_t vscsi_target_store(struct kobject * kobj,
+ struct attribute * attr,
+ const char * buf, size_t count)
+{
+ struct vdev *vdev = container_of(kobj, struct vdev, kobj);
+ struct device *dev = container_of(kobj->parent->parent,
+ struct device, kobj);
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+ long flags;
+ long value = simple_strtol(buf, NULL, 10);
+
+ if (attr != &vscsi_target_active_attr && !vdev->disabled) {
+ err("Error: Can't modify properties while target is active.\n");
+ return -EPERM;
+ }
+
+ if (attr == &vscsi_target_device_attr) {
+ int i;
+ spin_lock_irqsave(&adapter->lock, flags);
+ i = strlcpy(vdev->device_name, buf, TARGET_MAX_NAME_LEN);
+ for (; i >= 0; i--)
+ if (vdev->device_name[i] == '\n')
+ vdev->device_name[i] = '\0';
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ } else if (attr == &vscsi_target_active_attr) {
+ if (value) {
+ int rc;
+ if (!vdev->disabled) {
+ warn("Warning: Target was already active\n");
+ return -EINVAL;
+ }
+ rc = activate_device(vdev);
+ if (rc) {
+ err("Error opening device=%d\n", rc);
+ return rc;
+ }
+ } else {
+ if (!vdev->disabled)
+ deactivate_device(vdev);
+ }
+ } else if (attr == &vscsi_target_ro_attr)
+ vdev->b.ro = value > 0 ? 1 : 0;
+ else
+ BUG();
+
+ return count;
+}
+
+static struct attribute * vscsi_target_attrs[] = {
+ &vscsi_target_device_attr,
+ &vscsi_target_active_attr,
+ &vscsi_target_ro_attr,
+ NULL,
+};
+
+static struct sysfs_ops vscsi_target_ops = {
+ .show = vscsi_target_show,
+ .store = vscsi_target_store,
+};
+
+static struct kobj_type ktype_vscsi_target = {
+ .release = vscsi_target_release,
+ .sysfs_ops = &vscsi_target_ops,
+ .default_attrs = vscsi_target_attrs,
+};
+
+/* Bus sysfs stuff */
+static ssize_t vscsi_bus_show(struct kobject * kobj,
+ struct attribute * attr, char * buf)
+{
+ struct vbus *vbus = container_of(kobj, struct vbus, kobj);
+ return sprintf(buf, "%d\n", atomic_read(&vbus->num_targets));
+}
+
+static ssize_t vscsi_bus_store(struct kobject * kobj, struct attribute * attr,
+const char * buf, size_t count)
+{
+ struct vbus *vbus = container_of(kobj, struct vbus, kobj);
+ long value = simple_strtol(buf, NULL, 10);
+
+ if (value < 0 || value > TARGETS_PER_BUS)
+ return -EINVAL;
+
+ set_num_targets(vbus, value);
+
+ return count;
+}
+
+static ATTR(bus, num_targets, 0644);
+
+static struct attribute * vscsi_bus_attrs[] = {
+ &vscsi_bus_num_targets_attr,
+ NULL,
+};
+
+static struct sysfs_ops vscsi_bus_ops = {
+ .show = vscsi_bus_show,
+ .store = vscsi_bus_store,
+};
+
+static struct kobj_type ktype_vscsi_bus = {
+ .release = vscsi_bus_release,
+ .sysfs_ops = &vscsi_bus_ops,
+ .default_attrs = vscsi_bus_attrs,
+};
+
+/* Device attributes */
+static ssize_t vscsi_dev_bus_show(struct device * dev,
+ struct device_attribute *attr,
+ char * buf)
+{
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+
+ return sprintf(buf, "%d\n", atomic_read(&adapter->num_buses));
+}
+
+static ssize_t vscsi_dev_sector_show(struct device * dev,
+ struct device_attribute *attr,
+ char * buf)
+{
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+
+ return sprintf(buf, "%d\n", adapter->max_sectors);
+}
+
+static ssize_t vscsi_dev_bus_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ long value = simple_strtol(buf, NULL, 10);
+
+ if (value < 0 || value > BUS_PER_ADAPTER)
+ return -EINVAL;
+
+ set_num_buses(dev, value);
+ return count;
+}
+
+static ssize_t vscsi_dev_sector_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ long value = simple_strtol(buf, NULL, 10);
+ struct server_adapter *adapter =
+ (struct server_adapter *)dev->driver_data;
+
+ if (value <= 8 || value > SCSI_DEFAULT_MAX_SECTORS)
+ return -EINVAL;
+
+ adapter->max_sectors = value;
+
+ return count;
+}
+
+static ssize_t vscsi_dev_debug_store(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ long value = simple_strtol(buf, NULL, 10);
+
+ ibmvscsis_debug = value;
+ return count;
+}
+
+static ssize_t vscsi_dev_debug_show(struct device * dev,
+ struct device_attribute *attr,
+ char * buf)
+{
+ return sprintf(buf, "%d\n", ibmvscsis_debug);
+}
+
+static DEVICE_ATTR(debug, 0644, vscsi_dev_debug_show, vscsi_dev_debug_store);
+static DEVICE_ATTR(num_buses, 0644, vscsi_dev_bus_show, vscsi_dev_bus_store);
+static DEVICE_ATTR(max_sectors, 0644, vscsi_dev_sector_show,
+ vscsi_dev_sector_store);
+
+/* Stats kobj stuff */
+
+static ATTR(stats, interrupts, 0444);
+static ATTR(stats, read_ops, 0444);
+static ATTR(stats, write_ops, 0444);
+static ATTR(stats, crq_msgs, 0444);
+static ATTR(stats, iu_allocs, 0444);
+static ATTR(stats, bio_allocs, 0444);
+static ATTR(stats, buf_allocs, 0444);
+static ATTR(stats, errors, 0444);
+
+static struct attribute * vscsi_stats_attrs[] = {
+ &vscsi_stats_interrupts_attr,
+ &vscsi_stats_read_ops_attr,
+ &vscsi_stats_write_ops_attr,
+ &vscsi_stats_crq_msgs_attr,
+ &vscsi_stats_iu_allocs_attr,
+ &vscsi_stats_bio_allocs_attr,
+ &vscsi_stats_buf_allocs_attr,
+ &vscsi_stats_errors_attr,
+ NULL,
+};
+
+static ssize_t vscsi_stats_show(struct kobject * kobj,
+ struct attribute * attr, char * buf)
+{
+ struct server_adapter *adapter= container_of(kobj,
+ struct server_adapter,
+ stats_kobj);
+ if (attr == &vscsi_stats_interrupts_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->interrupts));
+ if (attr == &vscsi_stats_read_ops_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->read_processed));
+ if (attr == &vscsi_stats_write_ops_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->write_processed));
+ if (attr == &vscsi_stats_crq_msgs_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->crq_processed));
+ if (attr == &vscsi_stats_iu_allocs_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->iu_count));
+ if (attr == &vscsi_stats_bio_allocs_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->bio_count));
+ if (attr == &vscsi_stats_buf_allocs_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->buffers_allocated));
+ if (attr == &vscsi_stats_errors_attr)
+ return sprintf(buf, "%d\n",
+ atomic_read(&adapter->errors));
+
+ BUG();
+ return 0;
+}
+
+static struct sysfs_ops vscsi_stats_ops = {
+ .show = vscsi_stats_show,
+ .store = NULL,
+};
+
+static struct kobj_type ktype_vscsi_stats = {
+ .release = NULL,
+ .sysfs_ops = &vscsi_stats_ops,
+ .default_attrs = vscsi_stats_attrs,
+};
+
+/* ==============================================================
* Module load and unload
* ==============================================================
*/
@@ -3181,6 +3630,17 @@
return rc;
}
+ set_num_buses(&dev->dev, 1);
+ adapter->max_sectors = DEFAULT_MAX_SECTORS;
+ device_create_file(&dev->dev, &dev_attr_debug);
+ device_create_file(&dev->dev, &dev_attr_num_buses);
+ device_create_file(&dev->dev, &dev_attr_max_sectors);
+
+ adapter->stats_kobj.parent = &dev->dev.kobj;
+ strcpy(adapter->stats_kobj.name, "stats");
+ adapter->stats_kobj.ktype = & ktype_vscsi_stats;
+ kobject_register(&adapter->stats_kobj);
+
return 0;
}
@@ -3208,26 +3668,30 @@
if (vdev && !vdev ->disabled)
deactivate_device(vdev);
}
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ set_num_targets(adapter->vbus[bus], 0);
+ spin_lock_irqsave(&adapter->lock, flags);
}
}
spin_unlock_irqrestore(&adapter->lock, flags);
+ set_num_buses(adapter->dev, 0);
release_crq_queue(&adapter->queue, adapter);
release_iu_pool(adapter);
release_data_buffer(adapter);
+ kobject_unregister(&adapter->stats_kobj);
+ device_remove_file(&dev->dev, &dev_attr_debug);
+ device_remove_file(&dev->dev, &dev_attr_num_buses);
+ device_remove_file(&dev->dev, &dev_attr_max_sectors);
+
kfree(adapter);
return 0;
}
-static struct class_interface vscsis_interface = {
- .add = add_scsi_device,
- .remove = rem_scsi_device,
-};
-
static struct vio_device_id ibmvscsis_device_table[] __devinitdata = {
{"v-scsi-host", "IBM,v-scsi-host"},
{"",""}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]