@@ -351,6 +351,27 @@ struct fc_internal {
#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t)
+#define FC_LW_HOST_NUM_ATTRS 2
+struct fc_lw_internal {
+ struct scsi_transport_template t;
+ struct fc_function_template *f;
+
+ /*
+ * For attributes : each object has :
+ * An array of the actual attributes structures
+ * An array of null-terminated pointers to the attribute
+ * structures - used for mid-layer interaction.
+ *
+ * The attribute containers for the starget and host are are
+ * part of the midlayer. As the remote port is specific to the
+ * fc transport, we must provide the attribute container.
+ */
+ struct device_attribute private_host_attrs[FC_LW_HOST_NUM_ATTRS];
+ struct device_attribute *host_attrs[FC_LW_HOST_NUM_ATTRS + 1];
+};
+
+#define to_fc_lw_internal(tmpl) container_of(tmpl, struct fc_lw_internal, t)
+
static int fc_target_setup(struct transport_container *tc, struct device *dev,
struct device *cdev)
{
@@ -472,6 +493,12 @@ static int fc_host_remove(struct transport_container *tc, struct device *dev,
return 0;
}
+static DECLARE_TRANSPORT_CLASS(fc_lw_host_class,
+ "fc_host",
+ NULL,
+ NULL,
+ NULL);
+
static DECLARE_TRANSPORT_CLASS(fc_host_class,
"fc_host",
fc_host_setup,
@@ -654,11 +681,20 @@ send_vendor_fail:
EXPORT_SYMBOL(fc_host_post_vendor_event);
+static bool transport_inited;
+static bool lw_transport_inited;
-static __init int fc_transport_init(void)
+static int fc_transport_init(bool lw_transport)
{
int error;
+ bool inited = cmpxchg(&transport_inited, transport_inited, true);
+ /*
+ * If transport has already been inited, just return.
+ */
+ if (inited)
+ return 0;
+
atomic_set(&fc_event_seq, 0);
error = transport_class_register(&fc_host_class);
@@ -670,9 +706,15 @@ static __init int fc_transport_init(void)
error = transport_class_register(&fc_rport_class);
if (error)
goto unreg_vport_class;
- error = transport_class_register(&fc_transport_class);
+ if (lw_transport)
+ error = transport_class_register(&fc_lw_host_class);
+ else
+ error = transport_class_register(&fc_transport_class);
if (error)
goto unreg_rport_class;
+
+ if (lw_transport)
+ lw_transport_inited = true;
return 0;
unreg_rport_class:
@@ -686,8 +728,12 @@ unreg_host_class:
static void __exit fc_transport_exit(void)
{
- transport_class_unregister(&fc_transport_class);
+ if (lw_transport_inited)
+ transport_class_unregister(&fc_lw_host_class);
+ else
+ transport_class_unregister(&fc_transport_class);
transport_class_unregister(&fc_rport_class);
+ if (lw_transport_inited)
transport_class_unregister(&fc_host_class);
transport_class_unregister(&fc_vport_class);
}
@@ -1968,6 +2014,25 @@ static int fc_host_match(struct attribute_container *cont,
return &i->t.host_attrs.ac == cont;
}
+static int fc_lw_host_match(struct attribute_container *cont,
+ struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct fc_lw_internal *i;
+
+ if (!scsi_is_host_device(dev))
+ return 0;
+
+ shost = dev_to_shost(dev);
+ if (!shost->transportt || shost->transportt->host_attrs.ac.class
+ != &fc_lw_host_class.class)
+ return 0;
+
+ i = to_fc_lw_internal(shost->transportt);
+
+ return &i->t.host_attrs.ac == cont;
+}
+
static int fc_target_match(struct attribute_container *cont,
struct device *dev)
{
@@ -2171,13 +2236,70 @@ static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result)
return i->f->it_nexus_response(shost, nexus, result);
}
+/**
+ * fc_attach_lw_transport - light weight attach function
+ * @ft: function template for optional attributes
+ *
+ * This attach function is to be used only for virtual FC emulators
+ * which do not have a physical fabric underneath them and thus only
+ * need a few attributes and no helper functions
+ */
+struct scsi_transport_template *
+fc_lw_attach_transport(struct fc_function_template *ft)
+{
+ int count;
+ struct fc_lw_internal *i;
+
+ if (fc_transport_init(true))
+ return NULL;
+
+ i = kzalloc(sizeof(struct fc_lw_internal),
+ GFP_KERNEL);
+
+ if (unlikely(!i))
+ return NULL;
+
+ i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+ i->t.host_attrs.ac.class = &fc_lw_host_class.class;
+ i->t.host_attrs.ac.match = fc_lw_host_match;
+ i->t.host_size = sizeof(struct fc_host_attrs);
+ transport_container_register(&i->t.host_attrs);
+
+ i->f = ft;
+
+ count = 0;
+ SETUP_HOST_ATTRIBUTE_RD(node_name);
+ SETUP_HOST_ATTRIBUTE_RD(port_name);
+
+ BUG_ON(count > FC_HOST_NUM_ATTRS);
+
+ i->host_attrs[count] = NULL;
+
+ return &i->t;
+}
+EXPORT_SYMBOL(fc_lw_attach_transport);
+
+void fc_lw_release_transport(struct scsi_transport_template *t)
+{
+ struct fc_lw_internal *i = to_fc_lw_internal(t);
+
+ transport_container_unregister(&i->t.host_attrs);
+
+ kfree(i);
+}
+EXPORT_SYMBOL(fc_lw_release_transport);
+
struct scsi_transport_template *
fc_attach_transport(struct fc_function_template *ft)
{
int count;
- struct fc_internal *i = kzalloc(sizeof(struct fc_internal),
- GFP_KERNEL);
+ struct fc_internal *i;
+
+ if (fc_transport_init(false))
+ return NULL;
+ i = kzalloc(sizeof(struct fc_internal),
+ GFP_KERNEL);
if (unlikely(!i))
return NULL;
@@ -4148,5 +4270,4 @@ MODULE_AUTHOR("James Smart");
MODULE_DESCRIPTION("FC Transport Attributes");
MODULE_LICENSE("GPL");
-module_init(fc_transport_init);
module_exit(fc_transport_exit);
@@ -835,6 +835,9 @@ fc_vport_set_state(struct fc_vport *vport, enum fc_vport_state new_state)
vport->vport_state = new_state;
}
+struct scsi_transport_template *fc_lw_attach_transport(
+ struct fc_function_template *);
+void fc_lw_release_transport(struct scsi_transport_template *);
struct scsi_transport_template *fc_attach_transport(
struct fc_function_template *);
void fc_release_transport(struct scsi_transport_template *);