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 #include -#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