* [PATCH] add block/unblock to iscsi class
@ 2005-02-23 8:19 Mike Christie
2005-02-23 18:17 ` SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class) Andrew Vasquez
0 siblings, 1 reply; 7+ messages in thread
From: Mike Christie @ 2005-02-23 8:19 UTC (permalink / raw)
To: linux-iscsi-devel, linux-scsi
[-- Attachment #1: Type: text/plain, Size: 607 bytes --]
The attached patch copies the code from the fc transport
class which allows a LLD to block and unblock a device.
The block/unblock code is used by the iscsi-sfnet
driver in replacement of a internal timer doing the
same thing.
I understand that the target code is under construction
and our group as well as the HW iSCSI guys are trying to move
to something closer to the fc's rport model, so I was not
sure if it is better to wait or get this basic functionality in
first so we (and other SW and HW iSCSI drivers) can kill some
of our duplicated code sooner and then incrementally update
the class.
Mike
[-- Attachment #2: add-iscsi-block.patch --]
[-- Type: text/x-patch, Size: 16269 bytes --]
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_transport_iscsi.c scsi-rc-fixes-2.6.work2/drivers/scsi/scsi_transport_iscsi.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_transport_iscsi.c 2005-02-14 16:59:53.000000000 -0800
+++ scsi-rc-fixes-2.6.work2/drivers/scsi/scsi_transport_iscsi.c 2005-02-22 23:44:26.000000000 -0800
@@ -25,8 +25,10 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
-#define ISCSI_SESSION_ATTRS 20
-#define ISCSI_HOST_ATTRS 2
+#include "scsi_priv.h"
+
+#define ISCSI_SESSION_ATTRS 21
+#define ISCSI_HOST_ATTRS 3
struct iscsi_internal {
struct scsi_transport_template t;
@@ -40,17 +42,6 @@ struct iscsi_internal {
#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
-static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
- "iscsi_transport",
- NULL,
- NULL,
- NULL);
-
-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
- "iscsi_host",
- NULL,
- NULL,
- NULL);
/*
* iSCSI target and session attrs
*/
@@ -68,10 +59,31 @@ show_session_##field(struct class_device
return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
}
+#define iscsi_session_store_fn(field, format_string) \
+static ssize_t \
+store_session_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ int val; \
+ struct scsi_target *starget = transport_class_to_starget(cdev); \
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+ \
+ val = simple_strtoul(buf, NULL, 0); \
+ i->fnt->set_##field(starget, val); \
+ return count; \
+}
+
#define iscsi_session_rd_attr(field, format) \
iscsi_session_show_fn(field, format) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
+#define iscsi_session_rw_attr(field, format) \
+ iscsi_session_show_fn(field, format) \
+ iscsi_session_store_fn(field, format) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
+ show_session_##field, store_session_##field)
+
iscsi_session_rd_attr(tpgt, "%hu");
iscsi_session_rd_attr(tsih, "%2x");
iscsi_session_rd_attr(max_recv_data_segment_len, "%u");
@@ -81,7 +93,7 @@ iscsi_session_rd_attr(def_time2wait, "%h
iscsi_session_rd_attr(def_time2retain, "%hu");
iscsi_session_rd_attr(max_outstanding_r2t, "%hu");
iscsi_session_rd_attr(erl, "%d");
-
+iscsi_session_rw_attr(session_recovery_tmo, "%d");
#define iscsi_session_show_bool_fn(field) \
\
@@ -242,18 +254,314 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO,
iscsi_host_rd_str_attr(initiator_name);
iscsi_host_rd_str_attr(initiator_alias);
+#define iscsi_host_show_fn(field, format) \
+ \
+static ssize_t \
+show_host_##field(struct class_device *cdev, char *buf) \
+{ \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+ \
+ if (i->fnt->get_host_##field) \
+ i->fnt->get_host_##field(shost); \
+ return snprintf(buf, 20, format"\n", iscsi_host_##field(shost)); \
+}
+
+#define iscsi_host_store_fn(field, format_string) \
+static ssize_t \
+store_host_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ int val; \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+ \
+ val = simple_strtoul(buf, NULL, 0); \
+ i->fnt->set_host_##field(shost, val); \
+ return count; \
+}
+
+#define iscsi_host_rw_attr(field, format) \
+ iscsi_host_show_fn(field, format) \
+ iscsi_host_store_fn(field, format) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
+ show_host_##field, store_host_##field)
+
+iscsi_host_rw_attr(recovery_tmo, "%d");
+
+/**
+ * iscsi_device_block - called by target functions to block a scsi device
+ * @dev: scsi device
+ * @data: unused
+ **/
+static void iscsi_device_block(struct scsi_device *sdev, void *data)
+{
+ scsi_internal_device_block(sdev);
+}
+
+/**
+ * iscsi_device_unblock - called by target functions to unblock a scsi device
+ * @dev: scsi device
+ * @data: unused
+ **/
+static void iscsi_device_unblock(struct scsi_device *sdev, void *data)
+{
+ scsi_internal_device_unblock(sdev);
+}
+
+/**
+ * iscsi_target_block - block a target by temporarily putting all its scsi devices
+ * into the SDEV_BLOCK state.
+ * @starget: scsi target managed by this iscsi scsi lldd.
+ *
+ * scsi lldd's with a iSCSI transport call this routine to temporarily stop all
+ * scsi commands to all devices managed by this scsi target. Called
+ * from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ * The timeout and timer types are extracted from the iscsi transport
+ * attributes from the caller's target pointer. This routine assumes no
+ * locks are held on entry.
+ **/
+int iscsi_target_block(struct scsi_target *starget)
+{
+ int timeout = iscsi_session_recovery_tmo(starget);
+ struct work_struct *work = &iscsi_session_recovery_work(starget);
+
+ if (timeout < 0 || (timeout * HZ) > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+ return -EINVAL;
+
+ starget_for_each_device(starget, NULL, iscsi_device_block);
+
+ /* The scsi lld blocks this target for the timeout period only. */
+ schedule_delayed_work(work, timeout);
+ return 0;
+}
+EXPORT_SYMBOL(iscsi_target_block);
+
+/**
+ * iscsi_target_unblock - unblock a target following a iscsi_target_block request.
+ * @starget: scsi target managed by this iscsi scsi lldd.
+ *
+ * scsi lld's with a iSCSI transport call this routine to restart IO to all
+ * devices associated with the caller's scsi target following a
+ * iscsi_target_block request. Called from interrupt or normal process
+ * context.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void iscsi_target_unblock(struct scsi_target *starget)
+{
+ /*
+ * Stop the target timer first. Take no action on the del_timer
+ * failure as the state machine state change will validate the
+ * transaction.
+ */
+ cancel_delayed_work(&iscsi_session_recovery_work(starget));
+ flush_scheduled_work();
+
+ starget_for_each_device(starget, NULL, iscsi_device_unblock);
+}
+EXPORT_SYMBOL(iscsi_target_unblock);
+
+/**
+ * iscsi_host_block - block all scsi devices managed by the calling host temporarily
+ * by putting each device in the SDEV_BLOCK state.
+ * @shost: scsi host pointer that contains all scsi device siblings.
+ *
+ * scsi lld's with a iSCSI transport call this routine to temporarily stop all
+ * scsi commands to all devices managed by this host. Called
+ * from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ * The timeout and timer types are extracted from the iscsi transport
+ * attributes from the caller's host pointer. This routine assumes no
+ * locks are held on entry.
+ **/
+int iscsi_host_block(struct Scsi_Host *shost)
+{
+ struct scsi_device *sdev;
+ int timeout = iscsi_host_recovery_tmo(shost);
+ struct work_struct *work = &iscsi_host_recovery_work(shost);
+
+ if (timeout < 0 || (timeout * HZ) > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+ return -EINVAL;
+
+ shost_for_each_device(sdev, shost)
+ scsi_internal_device_block(sdev);
+ schedule_delayed_work(work, timeout * HZ);
+
+ return 0;
+}
+EXPORT_SYMBOL(iscsi_host_block);
+
+/**
+ * iscsi_host_unblock - unblock all devices managed by this host following a
+ * iscsi_host_block request.
+ * @shost: scsi host containing all scsi device siblings to unblock.
+ *
+ * scsi lld's with a iSCSI transport call this routine to restart IO to all scsi
+ * devices managed by the specified scsi host following an iscsi_host_block
+ * request. Called from interrupt or normal process context.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void iscsi_host_unblock(struct Scsi_Host *shost)
+{
+ struct scsi_device *sdev;
+
+ /*
+ * Stop the host timer first. Take no action on the del_timer
+ * failure as the state machine state change will validate the
+ * transaction.
+ */
+ cancel_delayed_work(&iscsi_host_recovery_work(shost));
+ flush_scheduled_work();
+
+ shost_for_each_device(sdev, shost)
+ scsi_internal_device_unblock(sdev);
+}
+EXPORT_SYMBOL(iscsi_host_unblock);
+
+/**
+ * iscsi_target_block_timedout - Timeout handler for blocked scsi targets
+ * that fail to recover in the alloted time.
+ * @data: scsi target that failed to reappear in the alloted time.
+ **/
+static void iscsi_target_block_timedout(void *data)
+{
+ struct scsi_target *starget = (struct scsi_target *)data;
+ struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+
+ dev_printk(KERN_ERR, &starget->dev,
+ "blocked target time out: target resuming\n");
+
+ if (i->fnt->target_block_timedout)
+ i->fnt->target_block_timedout(starget);
+ /*
+ * set the device going again ... if the scsi lld didn't
+ * unblock this device, then IO errors will probably
+ * result if the host still isn't ready.
+ */
+ starget_for_each_device(starget, NULL, iscsi_device_unblock);
+}
+
+static int iscsi_add_target(struct device *dev)
+{
+ struct scsi_target *starget = to_scsi_target(dev);
+
+ iscsi_session_recovery_tmo(starget) = 30;
+ INIT_WORK(&iscsi_session_recovery_work(starget),
+ iscsi_target_block_timedout, starget);
+ return 0;
+}
+
+static int iscsi_remove_target(struct device *dev)
+{
+ struct scsi_target *starget = to_scsi_target(dev);
+ /* Stop the target timer */
+ cancel_delayed_work(&iscsi_session_recovery_work(starget));
+ flush_scheduled_work();
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
+ "iscsi_transport",
+ iscsi_add_target,
+ iscsi_remove_target,
+ NULL);
+
+/**
+ * iscsi_host_block_timedout - Timeout handler for blocked scsi hosts
+ * that fail to recover in the alloted time.
+ * @data: scsi host that failed to recover its devices in the alloted
+ * time.
+ **/
+static void iscsi_host_block_timedout(void *data)
+{
+ struct Scsi_Host *shost = (struct Scsi_Host *)data;
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+ struct scsi_device *sdev;
+
+ dev_printk(KERN_ERR, &shost->shost_gendev,
+ "blocked host time out: host resuming\n");
+
+ if (i->fnt->host_block_timedout)
+ i->fnt->host_block_timedout(shost);
+
+ shost_for_each_device(sdev, shost)
+ /*
+ * set the device going again ... if the scsi lld didn't
+ * unblock this device, then IO errors will probably
+ * result if the host still isn't ready.
+ */
+ scsi_internal_device_unblock(sdev);
+}
+
+static int iscsi_add_host(struct device *dev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+
+ iscsi_host_recovery_tmo(shost) = 30;
+ INIT_WORK(&iscsi_host_recovery_work(shost),
+ iscsi_host_block_timedout, shost);
+ return 0;
+}
+
+static int iscsi_remove_host(struct device *dev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ /* Stop the host timer */
+ cancel_delayed_work(&iscsi_host_recovery_work(shost));
+ flush_scheduled_work();
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+ "iscsi_host",
+ iscsi_add_host,
+ iscsi_remove_host,
+ NULL);
+
#define SETUP_SESSION_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->session_attrs[count] = &class_device_attr_##field; \
count++; \
}
+#define SETUP_SESSION_RW_ATTR(field) \
+ if (i->fnt->show_##field) { \
+ i->session_attrs[count] = &class_device_attr_##field; \
+ if (!i->fnt->set_##field) { \
+ i->session_attrs[count]->attr.mode = S_IRUGO; \
+ i->session_attrs[count]->store = NULL; \
+ } \
+ count++; \
+ }
+
#define SETUP_HOST_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->host_attrs[count] = &class_device_attr_##field; \
count++; \
}
+#define SETUP_HOST_RW_ATTR(field) \
+ if (i->fnt->show_host_##field) { \
+ i->host_attrs[count] = &class_device_attr_##field; \
+ if (!i->fnt->set_host_##field) { \
+ i->session_attrs[count]->attr.mode = S_IRUGO; \
+ i->session_attrs[count]->store = NULL; \
+ } \
+ count++; \
+ }
+
static int iscsi_host_match(struct attribute_container *cont,
struct device *dev)
{
@@ -331,6 +639,7 @@ iscsi_attach_transport(struct iscsi_func
SETUP_SESSION_RD_ATTR(data_pdu_in_order);
SETUP_SESSION_RD_ATTR(data_sequence_in_order);
SETUP_SESSION_RD_ATTR(erl);
+ SETUP_SESSION_RW_ATTR(session_recovery_tmo);
BUG_ON(count > ISCSI_SESSION_ATTRS);
i->session_attrs[count] = NULL;
@@ -339,11 +648,12 @@ iscsi_attach_transport(struct iscsi_func
i->t.host_attrs.class = &iscsi_host_class.class;
i->t.host_attrs.match = iscsi_host_match;
attribute_container_register(&i->t.host_attrs);
- i->t.host_size = 0;
+ i->t.host_size = sizeof(struct iscsi_host);
count = 0;
SETUP_HOST_RD_ATTR(initiator_name);
SETUP_HOST_RD_ATTR(initiator_alias);
+ SETUP_HOST_RW_ATTR(recovery_tmo);
BUG_ON(count > ISCSI_HOST_ATTRS);
i->host_attrs[count] = NULL;
diff -aurp scsi-rc-fixes-2.6.orig/include/scsi/scsi_transport_iscsi.h scsi-rc-fixes-2.6.work2/include/scsi/scsi_transport_iscsi.h
--- scsi-rc-fixes-2.6.orig/include/scsi/scsi_transport_iscsi.h 2005-02-14 16:59:06.000000000 -0800
+++ scsi-rc-fixes-2.6.work2/include/scsi/scsi_transport_iscsi.h 2005-02-22 23:44:14.000000000 -0800
@@ -50,6 +50,9 @@ struct iscsi_class_session {
int data_pdu_in_order; /* 1 Yes, 0 No */
int data_sequence_in_order; /* 1 Yes, 0 No */
int erl;
+
+ int session_recovery_tmo; /* recovery timeout in seconds */
+ struct work_struct session_recovery_work;
};
/*
@@ -95,6 +98,20 @@ struct iscsi_class_session {
(((struct iscsi_class_session *)&(x)->starget_data)->data_sequence_in_order)
#define iscsi_erl(x) \
(((struct iscsi_class_session *)&(x)->starget_data)->erl)
+#define iscsi_session_recovery_tmo(x) \
+ (((struct iscsi_class_session *)&(x)->starget_data)->session_recovery_tmo)
+#define iscsi_session_recovery_work(x) \
+ (((struct iscsi_class_session *)&(x)->starget_data)->session_recovery_work)
+
+struct iscsi_host {
+ int recovery_tmo; /* recovery timeout in seconds */
+ struct work_struct recovery_work;
+};
+
+#define iscsi_host_recovery_tmo(x) \
+ (((struct iscsi_host *)(x)->shost_data)->recovery_tmo)
+#define iscsi_host_recovery_work(x) \
+ (((struct iscsi_host *)(x)->shost_data)->recovery_work)
/*
* The functions by which the transport class and the driver communicate
@@ -130,6 +147,9 @@ struct iscsi_function_template {
void (*get_data_pdu_in_order)(struct scsi_target *);
void (*get_data_sequence_in_order)(struct scsi_target *);
void (*get_erl)(struct scsi_target *);
+ void (*get_session_recovery_tmo)(struct scsi_target *);
+ void (*set_session_recovery_tmo)(struct scsi_target *, int);
+ void (*target_block_timedout)(struct scsi_target *);
/*
* host atts
@@ -140,6 +160,9 @@ struct iscsi_function_template {
*/
ssize_t (*get_initiator_alias)(struct Scsi_Host *, char *, ssize_t);
ssize_t (*get_initiator_name)(struct Scsi_Host *, char *, ssize_t);
+ void (*get_host_recovery_tmo)(struct Scsi_Host *);
+ void (*set_host_recovery_tmo)(struct Scsi_Host *, int);
+ void (*host_block_timedout)(struct Scsi_Host *);
/*
* The driver sets these to tell the transport class it
* wants the attributes displayed in sysfs. If the show_ flag
@@ -170,9 +193,15 @@ struct iscsi_function_template {
unsigned long show_erl:1;
unsigned long show_initiator_name:1;
unsigned long show_initiator_alias:1;
+ unsigned long show_session_recovery_tmo:1;
+ unsigned long show_host_recovery_tmo:1;
};
struct scsi_transport_template *iscsi_attach_transport(struct iscsi_function_template *);
void iscsi_release_transport(struct scsi_transport_template *);
+int iscsi_target_block(struct scsi_target *starget);
+void iscsi_target_unblock(struct scsi_target *starget);
+int iscsi_host_block(struct Scsi_Host *shost);
+void iscsi_host_unblock(struct Scsi_Host *shost);
#endif
^ permalink raw reply [flat|nested] 7+ messages in thread
* SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class)
2005-02-23 8:19 [PATCH] add block/unblock to iscsi class Mike Christie
@ 2005-02-23 18:17 ` Andrew Vasquez
2005-02-23 19:55 ` Mike Christie
0 siblings, 1 reply; 7+ messages in thread
From: Andrew Vasquez @ 2005-02-23 18:17 UTC (permalink / raw)
To: Linux-SCSI Mailing List
On Wed, 23 Feb 2005, Mike Christie wrote:
> The attached patch copies the code from the fc transport
> class which allows a LLD to block and unblock a device.
> The block/unblock code is used by the iscsi-sfnet
> driver in replacement of a internal timer doing the
> same thing.
>
> I understand that the target code is under construction
> and our group as well as the HW iSCSI guys are trying to move
> to something closer to the fc's rport model, so I was not
> sure if it is better to wait or get this basic functionality in
> first so we (and other SW and HW iSCSI drivers) can kill some
> of our duplicated code sooner and then incrementally update
> the class.
>
Speaking of which, are there any major objections to the patches
proposed here:
Add scsi_target_[un]block() and scsi_target_remove() generics
http://marc.theaimsgroup.com/?l=linux-scsi&m=110867050306738&w=2
[RFC] adding per scsi-host workqueues for defered processing
http://marc.theaimsgroup.com/?l=linux-scsi&m=110903148407438&w=2
which add some infrastructure changes for the transport classes.
--
AV
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class)
2005-02-23 18:17 ` SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class) Andrew Vasquez
@ 2005-02-23 19:55 ` Mike Christie
2005-02-23 22:06 ` Andrew Vasquez
0 siblings, 1 reply; 7+ messages in thread
From: Mike Christie @ 2005-02-23 19:55 UTC (permalink / raw)
To: Andrew Vasquez; +Cc: Linux-SCSI Mailing List
Andrew Vasquez wrote:
> On Wed, 23 Feb 2005, Mike Christie wrote:
>
>
>>The attached patch copies the code from the fc transport
>>class which allows a LLD to block and unblock a device.
>>The block/unblock code is used by the iscsi-sfnet
>>driver in replacement of a internal timer doing the
>>same thing.
>>
>>I understand that the target code is under construction
>>and our group as well as the HW iSCSI guys are trying to move
>>to something closer to the fc's rport model, so I was not
>>sure if it is better to wait or get this basic functionality in
>>first so we (and other SW and HW iSCSI drivers) can kill some
>>of our duplicated code sooner and then incrementally update
>>the class.
>>
>
>
> Speaking of which, are there any major objections to the patches
> proposed here:
>
> Add scsi_target_[un]block() and scsi_target_remove() generics
> http://marc.theaimsgroup.com/?l=linux-scsi&m=110867050306738&w=2
>
> [RFC] adding per scsi-host workqueues for defered processing
> http://marc.theaimsgroup.com/?l=linux-scsi&m=110903148407438&w=2
>
When using single_threaded_workqueues do all single threaded ones
in the system use the same cpu_workqueue_struct? Will this be
a potential bottleneck if we end up using the workqueue for more
operations in the future?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class)
2005-02-23 19:55 ` Mike Christie
@ 2005-02-23 22:06 ` Andrew Vasquez
2005-02-24 0:00 ` Mike Christie
0 siblings, 1 reply; 7+ messages in thread
From: Andrew Vasquez @ 2005-02-23 22:06 UTC (permalink / raw)
To: Mike Christie; +Cc: Linux-SCSI Mailing List
On Wed, 23 Feb 2005, Mike Christie wrote:
> Andrew Vasquez wrote:
> >
> >Speaking of which, are there any major objections to the patches
> >proposed here:
> >
> >Add scsi_target_[un]block() and scsi_target_remove() generics
> >http://marc.theaimsgroup.com/?l=linux-scsi&m=110867050306738&w=2
> >
> >[RFC] adding per scsi-host workqueues for defered processing
> >http://marc.theaimsgroup.com/?l=linux-scsi&m=110903148407438&w=2
> >
>
> When using single_threaded_workqueues do all single threaded ones
> in the system use the same cpu_workqueue_struct? Will this be
> a potential bottleneck if we end up using the workqueue for more
> operations in the future?
The kernel-thread that is created for a single-threaded workqueue is
not bound to any particular CPU:
kthread.c:kthread()
...
/* By default we can run anywhere, unlike keventd. */
set_cpus_allowed(current, CPU_MASK_ALL);
--
Andrew Vasquez
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class)
2005-02-23 22:06 ` Andrew Vasquez
@ 2005-02-24 0:00 ` Mike Christie
2005-02-24 0:03 ` Mike Christie
0 siblings, 1 reply; 7+ messages in thread
From: Mike Christie @ 2005-02-24 0:00 UTC (permalink / raw)
To: Andrew Vasquez; +Cc: Linux-SCSI Mailing List
Andrew Vasquez wrote:
> On Wed, 23 Feb 2005, Mike Christie wrote:
>
>
>>Andrew Vasquez wrote:
>>
>>>Speaking of which, are there any major objections to the patches
>>>proposed here:
>>>
>>>Add scsi_target_[un]block() and scsi_target_remove() generics
>>>http://marc.theaimsgroup.com/?l=linux-scsi&m=110867050306738&w=2
>>>
>>>[RFC] adding per scsi-host workqueues for defered processing
>>>http://marc.theaimsgroup.com/?l=linux-scsi&m=110903148407438&w=2
>>>
>>
>>When using single_threaded_workqueues do all single threaded ones
>>in the system use the same cpu_workqueue_struct? Will this be
>>a potential bottleneck if we end up using the workqueue for more
>>operations in the future?
>
>
> The kernel-thread that is created for a single-threaded workqueue is
> not bound to any particular CPU:
>
> kthread.c:kthread()
>
> ...
> /* By default we can run anywhere, unlike keventd. */
> set_cpus_allowed(current, CPU_MASK_ALL);
>
My question is not about which cpu it is run on.
I am asking about the cpu_workqueue_struct. In
create_workqueue_thread cpu always equals zero so
later when it is run it can be on any cpu but every
single threaded workqueue will access the same
cpu_workqueue_struct.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class)
2005-02-24 0:00 ` Mike Christie
@ 2005-02-24 0:03 ` Mike Christie
0 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2005-02-24 0:03 UTC (permalink / raw)
To: Mike Christie; +Cc: Andrew Vasquez, Linux-SCSI Mailing List
Mike Christie wrote:
> Andrew Vasquez wrote:
>
>> On Wed, 23 Feb 2005, Mike Christie wrote:
>>
>>
>>> Andrew Vasquez wrote:
>>>
>>>> Speaking of which, are there any major objections to the patches
>>>> proposed here:
>>>>
>>>> Add scsi_target_[un]block() and scsi_target_remove() generics
>>>> http://marc.theaimsgroup.com/?l=linux-scsi&m=110867050306738&w=2
>>>>
>>>> [RFC] adding per scsi-host workqueues for defered processing
>>>> http://marc.theaimsgroup.com/?l=linux-scsi&m=110903148407438&w=2
>>>>
>>>
>>> When using single_threaded_workqueues do all single threaded ones
>>> in the system use the same cpu_workqueue_struct? Will this be
>>> a potential bottleneck if we end up using the workqueue for more
>>> operations in the future?
>>
>>
>>
>> The kernel-thread that is created for a single-threaded workqueue is
>> not bound to any particular CPU:
>>
>> kthread.c:kthread()
>>
>> ...
>> /* By default we can run anywhere, unlike keventd. */
>> set_cpus_allowed(current, CPU_MASK_ALL);
>>
>
> My question is not about which cpu it is run on.
> I am asking about the cpu_workqueue_struct. In
> create_workqueue_thread cpu always equals zero so
> later when it is run it can be on any cpu but every
> single threaded workqueue will access the same
> cpu_workqueue_struct.
>
Oh wait nevermind that too. I should read the code more
closely next time.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] add block/unblock to iscsi class
@ 2005-03-28 13:48 Mike Christie
0 siblings, 0 replies; 7+ messages in thread
From: Mike Christie @ 2005-03-28 13:48 UTC (permalink / raw)
To: linux-scsi
[-- Attachment #1: Type: text/plain, Size: 357 bytes --]
The attached patch adds session block and unblock functions
similar to the rport block and unblock code.
The patch was built against scsi misc (but also pathces
against scsi rc fixes) and this patch
http://marc.theaimsgroup.com/?l=linux-scsi&m=111181778109783&w=2
which adds a scsi_flush_work function.
Signed-off-by: Mike Chrisite <michaelc@cs.wisc.edu>
[-- Attachment #2: add-iscsi-block.patch --]
[-- Type: text/x-patch, Size: 25995 bytes --]
diff -aurp scsi-misc-2.6.orig/drivers/scsi/scsi_transport_iscsi.c scsi-misc-2.6.test/drivers/scsi/scsi_transport_iscsi.c
--- scsi-misc-2.6.orig/drivers/scsi/scsi_transport_iscsi.c 2005-03-25 21:34:54.000000000 -0800
+++ scsi-misc-2.6.test/drivers/scsi/scsi_transport_iscsi.c 2005-03-27 03:03:04.000000000 -0800
@@ -25,7 +25,9 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
-#define ISCSI_SESSION_ATTRS 20
+#include "scsi_priv.h"
+
+#define ISCSI_SESSION_ATTRS 21
#define ISCSI_HOST_ATTRS 2
struct iscsi_internal {
@@ -34,23 +36,13 @@ struct iscsi_internal {
/*
* We do not have any private or other attrs.
*/
+ struct transport_container session_cont;
struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
};
#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
-static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
- "iscsi_transport",
- NULL,
- NULL,
- NULL);
-
-static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
- "iscsi_host",
- NULL,
- NULL,
- NULL);
/*
* iSCSI target and session attrs
*/
@@ -59,19 +51,40 @@ static DECLARE_TRANSPORT_CLASS(iscsi_hos
static ssize_t \
show_session_##field(struct class_device *cdev, char *buf) \
{ \
- struct scsi_target *starget = transport_class_to_starget(cdev); \
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev); \
+ struct Scsi_Host *shost = iscsi_session_to_shost(session); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
- i->fnt->get_##field(starget); \
- return snprintf(buf, 20, format"\n", iscsi_##field(starget)); \
+ i->fnt->get_##field(session); \
+ return snprintf(buf, 20, format"\n", session->field); \
+}
+
+#define iscsi_session_store_fn(field, format_string) \
+static ssize_t \
+store_session_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev); \
+ struct Scsi_Host *shost = iscsi_session_to_shost(session); \
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+ int val; \
+ \
+ val = simple_strtoul(buf, NULL, 0); \
+ i->fnt->set_##field(session, val); \
+ return count; \
}
#define iscsi_session_rd_attr(field, format) \
iscsi_session_show_fn(field, format) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
+#define iscsi_session_rw_attr(field, format) \
+ iscsi_session_show_fn(field, format) \
+ iscsi_session_store_fn(field, format) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \
+ show_session_##field, store_session_##field)
+
iscsi_session_rd_attr(tpgt, "%hu");
iscsi_session_rd_attr(tsih, "%2x");
iscsi_session_rd_attr(max_recv_data_segment_len, "%u");
@@ -81,21 +94,21 @@ iscsi_session_rd_attr(def_time2wait, "%h
iscsi_session_rd_attr(def_time2retain, "%hu");
iscsi_session_rd_attr(max_outstanding_r2t, "%hu");
iscsi_session_rd_attr(erl, "%d");
-
+iscsi_session_rw_attr(session_recovery_tmo, "%d");
#define iscsi_session_show_bool_fn(field) \
\
static ssize_t \
show_session_bool_##field(struct class_device *cdev, char *buf) \
{ \
- struct scsi_target *starget = transport_class_to_starget(cdev); \
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev); \
+ struct Scsi_Host *shost = iscsi_session_to_shost(session); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
- i->fnt->get_##field(starget); \
+ i->fnt->get_##field(session); \
\
- if (iscsi_##field(starget)) \
+ if (session->field) \
return sprintf(buf, "Yes\n"); \
return sprintf(buf, "No\n"); \
}
@@ -114,14 +127,14 @@ iscsi_session_rd_bool_attr(data_sequence
static ssize_t \
show_##field(struct class_device *cdev, char *buf) \
{ \
- struct scsi_target *starget = transport_class_to_starget(cdev); \
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev); \
+ struct Scsi_Host *shost = iscsi_session_to_shost(session); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
- i->fnt->get_##field(starget); \
+ i->fnt->get_##field(session); \
\
- if (iscsi_##field(starget)) \
+ if (session->field) \
return sprintf(buf, "CRC32C\n"); \
return sprintf(buf, "None\n"); \
}
@@ -136,33 +149,33 @@ iscsi_session_rd_digest_attr(data_digest
static ssize_t
show_port(struct class_device *cdev, char *buf)
{
- struct scsi_target *starget = transport_class_to_starget(cdev);
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev);
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
if (i->fnt->get_port)
- i->fnt->get_port(starget);
+ i->fnt->get_port(session);
- return snprintf(buf, 20, "%hu\n", ntohs(iscsi_port(starget)));
+ return snprintf(buf, 20, "%hu\n", ntohs(session->port));
}
static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
static ssize_t
show_ip_address(struct class_device *cdev, char *buf)
{
- struct scsi_target *starget = transport_class_to_starget(cdev);
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev);
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
if (i->fnt->get_ip_address)
- i->fnt->get_ip_address(starget);
+ i->fnt->get_ip_address(session);
- if (iscsi_addr_type(starget) == AF_INET)
+ if (session->addr_type == AF_INET)
return sprintf(buf, "%u.%u.%u.%u\n",
- NIPQUAD(iscsi_sin_addr(starget)));
- else if(iscsi_addr_type(starget) == AF_INET6)
+ NIPQUAD(session->u.sin_addr));
+ else if(session->addr_type == AF_INET6)
return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
- NIP6(iscsi_sin6_addr(starget)));
+ NIP6(session->u.sin6_addr));
return -EINVAL;
}
static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL);
@@ -170,17 +183,17 @@ static CLASS_DEVICE_ATTR(ip_address, S_I
static ssize_t
show_isid(struct class_device *cdev, char *buf)
{
- struct scsi_target *starget = transport_class_to_starget(cdev);
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev);
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
if (i->fnt->get_isid)
- i->fnt->get_isid(starget);
+ i->fnt->get_isid(session);
return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
- iscsi_isid(starget)[0], iscsi_isid(starget)[1],
- iscsi_isid(starget)[2], iscsi_isid(starget)[3],
- iscsi_isid(starget)[4], iscsi_isid(starget)[5]);
+ session->isid[0], session->isid[1],
+ session->isid[2], session->isid[3],
+ session->isid[4], session->isid[5]);
}
static CLASS_DEVICE_ATTR(isid, S_IRUGO, show_isid, NULL);
@@ -196,12 +209,12 @@ static ssize_t \
show_session_str_##field(struct class_device *cdev, char *buf) \
{ \
ssize_t ret = 0; \
- struct scsi_target *starget = transport_class_to_starget(cdev); \
- struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \
+ struct iscsi_class_session *session = iscsi_cdev_to_session(cdev); \
+ struct Scsi_Host *shost = iscsi_session_to_shost(session); \
struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
\
if (i->fnt->get_##field) \
- ret = i->fnt->get_##field(starget, buf, PAGE_SIZE); \
+ ret = i->fnt->get_##field(session, buf, PAGE_SIZE); \
return ret; \
}
@@ -242,12 +255,227 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO,
iscsi_host_rd_str_attr(initiator_name);
iscsi_host_rd_str_attr(initiator_alias);
+/**
+ * iscsi_block_session - block IO to session.
+ * @session: iscsi_session
+ *
+ * scsi lldd's with a iSCSI transport call this routine to temporarily stop all
+ * scsi commands to all devices managed by this scsi target. Called
+ * from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+int iscsi_block_session(struct iscsi_class_session *session)
+{
+ struct work_struct *work = &session->session_recovery_work;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+ int timeout;
+
+ i->fnt->get_session_recovery_tmo(session);
+ timeout = session->session_recovery_tmo;
+ if (timeout < 0)
+ return -EINVAL;
+
+ scsi_target_block(&session->dev);
+
+ /* The scsi lld blocks this target for the timeout period only. */
+ schedule_delayed_work(work, timeout);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_block_session);
+
+/**
+ * iscsi_unblocksession - unblock IO to a session.
+ * @session: scsi target managed by this iscsi scsi lldd.
+ *
+ * scsi lld's with a iSCSI transport call this routine to restart IO to all
+ * devices associated with the caller's scsi target following a
+ * iscsi_target_block request. Called from normal process context.
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void iscsi_unblock_session(struct iscsi_class_session *session)
+{
+ /*
+ * Stop the target timer first. Take no action on the del_timer
+ * failure as the state machine state change will validate the
+ * transaction.
+ */
+ if (!cancel_delayed_work(&session->session_recovery_work))
+ flush_scheduled_work();
+
+ scsi_target_unblock(&session->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_unblock_session);
+
+/**
+ * iscsi_session_block_timedout - Timeout handler for blocked scsi targets
+ * that fail to recover in the alloted time.
+ * @data: iscsi session that failed to reappear in the alloted time.
+ **/
+static void iscsi_session_block_timedout(void *data)
+{
+ struct iscsi_class_session *session = data;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+
+ dev_printk(KERN_ERR, &session->dev,
+ "blocked session time out: target resuming\n");
+
+ if (i->fnt->session_recovery_timedout)
+ i->fnt->session_recovery_timedout(session);
+ /*
+ * set the device going again ... if the scsi lld didn't
+ * unblock this device, then IO errors will probably
+ * result if the host still isn't ready.
+ */
+ scsi_target_unblock(&session->dev);
+}
+
+/**
+ * iscsi_scan_session - called to perform a scsi scan on a session's target.
+ * @data: session to be scanned.
+ **/
+static void
+iscsi_scan_session(void *data)
+{
+ struct iscsi_class_session *session = data;
+
+ scsi_scan_target(&session->dev, session->channel, session->target_id,
+ SCAN_WILD_CARD, 1);
+}
+
+static void iscsi_session_dev_release(struct device *dev)
+{
+ struct iscsi_class_session *session = iscsi_dev_to_session(dev);
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+
+ kfree(session);
+ scsi_host_put(shost);
+}
+
+/**
+ * iscsi_add_session - add a session
+ * @shost: scsi host session is attached to
+ * @channel: channel on host session is attached to
+ *
+ * Allocate and add a iscsi session. After this call it will be accessable
+ * through sysfs. The LLD must set the create_workqueue bit in it's
+ * transport so iscsi_add_session can scan the sessions's target from
+ * the workqueue.
+ **/
+struct iscsi_class_session *
+iscsi_add_session(struct Scsi_Host *shost, unsigned int channel)
+{
+ struct iscsi_class_session *session;
+ struct iscsi_host *iscsi_host;
+ struct device *dev;
+
+ /*
+ * get a handle for the session since it references the
+ * template's internal data (this is released in the class's
+ * release function)
+ */
+ shost = scsi_host_get(shost);
+ if (!shost) {
+ printk(KERN_ERR "iSCSI: could not get reference to shost\n");
+ return NULL;
+ }
+ iscsi_host = shost->shost_data;
+
+ session = kmalloc(sizeof(*session), GFP_KERNEL);
+ if (!session) {
+ printk(KERN_ERR "iSCSI: could not allocate session\n");
+ goto put_host;
+ }
+
+ memset(session, 0, sizeof(*session));
+ INIT_WORK(&session->session_recovery_work,
+ iscsi_session_block_timedout, session);
+ INIT_WORK(&session->scan_work, iscsi_scan_session, session);
+ session->session_recovery_tmo = 15;
+ session->channel = channel;
+ session->target_id = iscsi_host->next_target_id++;
+
+ dev = &session->dev;
+ snprintf(dev->bus_id, BUS_ID_SIZE, "session%u:%u:%u", shost->host_no,
+ session->channel, session->target_id);
+ dev->parent = &shost->shost_gendev;
+ dev->release = iscsi_session_dev_release;
+ if (device_register(dev)) {
+ printk(KERN_ERR "iSCSI: could not register session dev\n");
+ goto free_session;
+ }
+
+ transport_register_device(dev);
+ scsi_queue_work(shost, &session->scan_work);
+
+ return session;
+
+ free_session:
+ kfree(session);
+ put_host:
+ scsi_host_put(shost);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(iscsi_add_session);
+
+void
+iscsi_remove_session(struct iscsi_class_session *session)
+{
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+
+ if (!cancel_delayed_work(&session->session_recovery_work))
+ flush_scheduled_work();
+ scsi_flush_work(shost);
+
+ transport_unregister_device(&session->dev);
+ device_unregister(&session->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_remove_session);
+
+static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
+ "iscsi_session",
+ NULL,
+ NULL,
+ NULL);
+
+static int iscsi_setup_host(struct device *dev)
+{
+ struct Scsi_Host *shost = dev_to_shost(dev);
+ struct iscsi_host *ihost = shost->shost_data;
+
+ ihost->next_target_id = 0;
+ return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+ "iscsi_host",
+ iscsi_setup_host,
+ NULL,
+ NULL);
+
#define SETUP_SESSION_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->session_attrs[count] = &class_device_attr_##field; \
count++; \
}
+#define SETUP_SESSION_RW_ATTR(field) \
+ if (i->fnt->show_##field) { \
+ i->session_attrs[count] = &class_device_attr_##field; \
+ if (!i->fnt->set_##field) { \
+ i->session_attrs[count]->attr.mode = S_IRUGO; \
+ i->session_attrs[count]->store = NULL; \
+ } \
+ count++; \
+ }
+
#define SETUP_HOST_RD_ATTR(field) \
if (i->fnt->show_##field) { \
i->host_attrs[count] = &class_device_attr_##field; \
@@ -273,13 +501,18 @@ static int iscsi_host_match(struct attri
return &i->t.host_attrs.ac == cont;
}
-static int iscsi_target_match(struct attribute_container *cont,
- struct device *dev)
+static int iscsi_dev_is_session(const struct device *dev)
+{
+ return dev->release == iscsi_session_dev_release;
+}
+
+static int iscsi_session_match(struct attribute_container *cont,
+ struct device *dev)
{
struct Scsi_Host *shost;
struct iscsi_internal *i;
- if (!scsi_is_target_device(dev))
+ if (!iscsi_dev_is_session(dev))
return 0;
shost = dev_to_shost(dev->parent);
@@ -288,8 +521,8 @@ static int iscsi_target_match(struct att
return 0;
i = to_iscsi_internal(shost->transportt);
-
- return &i->t.target_attrs.ac == cont;
+
+ return &i->session_cont.ac == cont;
}
struct scsi_transport_template *
@@ -304,12 +537,12 @@ iscsi_attach_transport(struct iscsi_func
memset(i, 0, sizeof(struct iscsi_internal));
i->fnt = fnt;
+ i->t.create_work_queue = 1;
- i->t.target_attrs.ac.attrs = &i->session_attrs[0];
- i->t.target_attrs.ac.class = &iscsi_transport_class.class;
- i->t.target_attrs.ac.match = iscsi_target_match;
- transport_container_register(&i->t.target_attrs);
- i->t.target_size = sizeof(struct iscsi_class_session);
+ i->session_cont.ac.attrs = &i->session_attrs[0];
+ i->session_cont.ac.class = &iscsi_session_class.class;
+ i->session_cont.ac.match = iscsi_session_match;
+ transport_container_register(&i->session_cont);
SETUP_SESSION_RD_ATTR(tsih);
SETUP_SESSION_RD_ATTR(isid);
@@ -331,6 +564,7 @@ iscsi_attach_transport(struct iscsi_func
SETUP_SESSION_RD_ATTR(data_pdu_in_order);
SETUP_SESSION_RD_ATTR(data_sequence_in_order);
SETUP_SESSION_RD_ATTR(erl);
+ SETUP_SESSION_RW_ATTR(session_recovery_tmo);
BUG_ON(count > ISCSI_SESSION_ATTRS);
i->session_attrs[count] = NULL;
@@ -339,7 +573,7 @@ iscsi_attach_transport(struct iscsi_func
i->t.host_attrs.ac.class = &iscsi_host_class.class;
i->t.host_attrs.ac.match = iscsi_host_match;
transport_container_register(&i->t.host_attrs);
- i->t.host_size = 0;
+ i->t.host_size = sizeof(struct iscsi_host);
count = 0;
SETUP_HOST_RD_ATTR(initiator_name);
@@ -357,7 +591,7 @@ void iscsi_release_transport(struct scsi
{
struct iscsi_internal *i = to_iscsi_internal(t);
- transport_container_unregister(&i->t.target_attrs);
+ transport_container_unregister(&i->session_cont);
transport_container_unregister(&i->t.host_attrs);
kfree(i);
@@ -367,17 +601,18 @@ EXPORT_SYMBOL(iscsi_release_transport);
static __init int iscsi_transport_init(void)
{
- int err = transport_class_register(&iscsi_transport_class);
+ int err = transport_class_register(&iscsi_session_class);
if (err)
return err;
+
return transport_class_register(&iscsi_host_class);
}
static void __exit iscsi_transport_exit(void)
{
transport_class_unregister(&iscsi_host_class);
- transport_class_unregister(&iscsi_transport_class);
+ transport_class_unregister(&iscsi_session_class);
}
module_init(iscsi_transport_init);
diff -aurp scsi-misc-2.6.orig/include/scsi/scsi_transport_iscsi.h scsi-misc-2.6.test/include/scsi/scsi_transport_iscsi.h
--- scsi-misc-2.6.orig/include/scsi/scsi_transport_iscsi.h 2005-03-25 21:34:28.000000000 -0800
+++ scsi-misc-2.6.test/include/scsi/scsi_transport_iscsi.h 2005-03-27 03:01:30.000000000 -0800
@@ -28,108 +28,91 @@
struct scsi_transport_template;
struct iscsi_class_session {
- uint8_t isid[6];
- uint16_t tsih;
- int header_digest; /* 1 CRC32, 0 None */
- int data_digest; /* 1 CRC32, 0 None */
- uint16_t tpgt;
+ uint8_t isid[6];
+ uint16_t tsih;
+ int header_digest; /* 1 CRC32, 0 None */
+ int data_digest; /* 1 CRC32, 0 None */
+ uint16_t tpgt;
union {
- struct in6_addr sin6_addr;
- struct in_addr sin_addr;
+ struct in6_addr sin6_addr;
+ struct in_addr sin_addr;
} u;
- sa_family_t addr_type; /* must be AF_INET or AF_INET6 */
- uint16_t port; /* must be in network byte order */
- int initial_r2t; /* 1 Yes, 0 No */
- int immediate_data; /* 1 Yes, 0 No */
- uint32_t max_recv_data_segment_len;
- uint32_t max_burst_len;
- uint32_t first_burst_len;
- uint16_t def_time2wait;
- uint16_t def_time2retain;
- uint16_t max_outstanding_r2t;
- int data_pdu_in_order; /* 1 Yes, 0 No */
- int data_sequence_in_order; /* 1 Yes, 0 No */
- int erl;
+ sa_family_t addr_type; /* must be AF_INET or AF_INET6 */
+ uint16_t port; /* must be in network byte order */
+ int initial_r2t; /* 1 Yes, 0 No */
+ int immediate_data; /* 1 Yes, 0 No */
+ uint32_t max_recv_data_segment_len;
+ uint32_t max_burst_len;
+ uint32_t first_burst_len;
+ uint16_t def_time2wait;
+ uint16_t def_time2retain;
+ uint16_t max_outstanding_r2t;
+ int data_pdu_in_order; /* 1 Yes, 0 No */
+ int data_sequence_in_order; /* 1 Yes, 0 No */
+ int erl;
+
+ int session_recovery_tmo; /* recovery timeout in secs */
+ struct work_struct session_recovery_work;
+ struct work_struct scan_work;
+ struct device dev;
+ unsigned channel;
+ unsigned target_id;
+
+ void *session_data; /* LLD storage */
};
-/*
- * accessor macros
- */
-#define iscsi_isid(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->isid)
-#define iscsi_tsih(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->tsih)
-#define iscsi_header_digest(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->header_digest)
-#define iscsi_data_digest(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->data_digest)
-#define iscsi_port(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->port)
-#define iscsi_addr_type(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->addr_type)
-#define iscsi_sin_addr(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->u.sin_addr)
-#define iscsi_sin6_addr(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->u.sin6_addr)
-#define iscsi_tpgt(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->tpgt)
-#define iscsi_initial_r2t(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->initial_r2t)
-#define iscsi_immediate_data(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->immediate_data)
-#define iscsi_max_recv_data_segment_len(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->max_recv_data_segment_len)
-#define iscsi_max_burst_len(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->max_burst_len)
-#define iscsi_first_burst_len(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->first_burst_len)
-#define iscsi_def_time2wait(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->def_time2wait)
-#define iscsi_def_time2retain(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->def_time2retain)
-#define iscsi_max_outstanding_r2t(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->max_outstanding_r2t)
-#define iscsi_data_pdu_in_order(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->data_pdu_in_order)
-#define iscsi_data_sequence_in_order(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->data_sequence_in_order)
-#define iscsi_erl(x) \
- (((struct iscsi_class_session *)&(x)->starget_data)->erl)
+#define iscsi_dev_to_session(_dev) \
+ container_of(_dev, struct iscsi_class_session, dev)
+
+#define iscsi_cdev_to_session(_cdev) \
+ iscsi_dev_to_session(_cdev->dev)
+
+#define iscsi_session_to_shost(_sess) \
+ dev_to_shost(_sess->dev.parent)
+
+struct iscsi_host {
+ unsigned next_target_id;
+};
/*
* The functions by which the transport class and the driver communicate
*/
struct iscsi_function_template {
/*
- * target attrs
+ * session attrs
*/
- void (*get_isid)(struct scsi_target *);
- void (*get_tsih)(struct scsi_target *);
- void (*get_header_digest)(struct scsi_target *);
- void (*get_data_digest)(struct scsi_target *);
- void (*get_port)(struct scsi_target *);
- void (*get_tpgt)(struct scsi_target *);
+ void (*get_isid)(struct iscsi_class_session *);
+ void (*get_tsih)(struct iscsi_class_session *);
+ void (*get_header_digest)(struct iscsi_class_session *);
+ void (*get_data_digest)(struct iscsi_class_session *);
+ void (*get_port)(struct iscsi_class_session *);
+ void (*get_tpgt)(struct iscsi_class_session *);
/*
* In get_ip_address the lld must set the address and
* the address type
*/
- void (*get_ip_address)(struct scsi_target *);
+ void (*get_ip_address)(struct iscsi_class_session *);
/*
* The lld should snprintf the name or alias to the buffer
*/
- ssize_t (*get_target_name)(struct scsi_target *, char *, ssize_t);
- ssize_t (*get_target_alias)(struct scsi_target *, char *, ssize_t);
- void (*get_initial_r2t)(struct scsi_target *);
- void (*get_immediate_data)(struct scsi_target *);
- void (*get_max_recv_data_segment_len)(struct scsi_target *);
- void (*get_max_burst_len)(struct scsi_target *);
- void (*get_first_burst_len)(struct scsi_target *);
- void (*get_def_time2wait)(struct scsi_target *);
- void (*get_def_time2retain)(struct scsi_target *);
- void (*get_max_outstanding_r2t)(struct scsi_target *);
- void (*get_data_pdu_in_order)(struct scsi_target *);
- void (*get_data_sequence_in_order)(struct scsi_target *);
- void (*get_erl)(struct scsi_target *);
+ ssize_t (*get_target_name)(struct iscsi_class_session *, char *,
+ ssize_t);
+ ssize_t (*get_target_alias)(struct iscsi_class_session *, char *,
+ ssize_t);
+ void (*get_initial_r2t)(struct iscsi_class_session *);
+ void (*get_immediate_data)(struct iscsi_class_session *);
+ void (*get_max_recv_data_segment_len)(struct iscsi_class_session *);
+ void (*get_max_burst_len)(struct iscsi_class_session *);
+ void (*get_first_burst_len)(struct iscsi_class_session *);
+ void (*get_def_time2wait)(struct iscsi_class_session *);
+ void (*get_def_time2retain)(struct iscsi_class_session *);
+ void (*get_max_outstanding_r2t)(struct iscsi_class_session *);
+ void (*get_data_pdu_in_order)(struct iscsi_class_session *);
+ void (*get_data_sequence_in_order)(struct iscsi_class_session *);
+ void (*get_erl)(struct iscsi_class_session *);
+ void (*get_session_recovery_tmo)(struct iscsi_class_session *);
+ void (*set_session_recovery_tmo)(struct iscsi_class_session *, int);
+ void (*session_recovery_timedout)(struct iscsi_class_session *);
/*
* host atts
@@ -170,9 +153,15 @@ struct iscsi_function_template {
unsigned long show_erl:1;
unsigned long show_initiator_name:1;
unsigned long show_initiator_alias:1;
+ unsigned long show_session_recovery_tmo:1;
};
struct scsi_transport_template *iscsi_attach_transport(struct iscsi_function_template *);
void iscsi_release_transport(struct scsi_transport_template *);
+int iscsi_block_session(struct iscsi_class_session *session);
+void iscsi_unblock_session(struct iscsi_class_session *session);
+struct iscsi_class_session *iscsi_add_session(struct Scsi_Host *shost,
+ unsigned int channel);
+void iscsi_remove_session(struct iscsi_class_session *session);
#endif
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2005-03-28 13:48 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-23 8:19 [PATCH] add block/unblock to iscsi class Mike Christie
2005-02-23 18:17 ` SCSI API generics (was Re: [PATCH] add block/unblock to iscsi class) Andrew Vasquez
2005-02-23 19:55 ` Mike Christie
2005-02-23 22:06 ` Andrew Vasquez
2005-02-24 0:00 ` Mike Christie
2005-02-24 0:03 ` Mike Christie
-- strict thread matches above, loose matches on Subject: below --
2005-03-28 13:48 [PATCH] add block/unblock to iscsi class Mike Christie
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox