diff --git a/open-iscsi-add-discovery-ops b/open-iscsi-add-discovery-ops deleted file mode 100644 index 6357ad2..0000000 --- a/open-iscsi-add-discovery-ops +++ /dev/null @@ -1,4684 +0,0 @@ -From: Mike Christie -Subject: Don't overwrite other nodes on discovery -References: 365259 - -The open-iscsi initiator will overwrite/delete old nodes whenever -we're doing a discovery. This is already fixes upstream, so we're -just pulling in the latest git fixes. - -This patch is based on git commit -6bd2e30b9a835cb54d4fd539c97f79efe9d70a7a - -Signed-off-by: Hannes Reinecke - -diff -pur open-iscsi-2.0-865/doc/iscsiadm.8 open-iscsi.git/doc/iscsiadm.8 ---- open-iscsi-2.0-865/doc/iscsiadm.8 2008-03-05 11:43:19.268973000 +0100 -+++ open-iscsi.git/doc/iscsiadm.8 2008-03-05 11:29:21.060588250 +0100 -@@ -12,7 +12,7 @@ iscsiadm \- open-iscsi administration ut - - \fBiscsiadm\fR -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ] - --\fBiscsiadm\fR -m fw -+\fBiscsiadm\fR -m fw [-l] - - \fBiscsiadm\fR -k priority - -@@ -90,7 +90,7 @@ This command and iscsid's SIGTERM handli - - .TP - \fB\-l\fR, \fB\-\-login\fR --For node mode, login to a specified record. For discovery mode, login to -+For node and fw mode, login to a specified record. For discovery mode, login to - all discovered targets. - .IP - This option is only valid for discovery and node modes. -@@ -125,16 +125,14 @@ operator. - Specifies a database operator \fIop\fR. \fIop\fR must be one of - \fInew\fR, \fIdelete\fR, \fIupdate\fR or \fIshow\fR. - .IP --This option is only valid for all modes, but delete should not be used on a running session. -+This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the -+record. - .IP --\fInew\fR is currently valid only for node, session and iface mode. It creates --a new database record for a given \fIportal\fR (IP address and port number). -+\fInew\fR creates a new database record for a given \fIportal\fR (IP address and port number). In discovery mode, iscsiadm will create new records for portals returned by the target. - .IP --\fIdelete\fR deletes a specified \fIrecid\fR. -+\fIdelete\fR deletes a specified \fIrecid\fR. In discovery node, iscsiadm will delete records for portals that are no longer returned. - .IP --\fIupdate\fR is currently valid only for node, session, and iface mode. --It updates a specified --\fIrecid\fR with \fIname\fR to the specified \fIvalue\fR. -+\fIupdate\fR will update the \fIrecid\fR with \fIname\fR to the specified \fIvalue\fR. In discovery node the \fIrecid\fR, \fIname\fR and \fIvalue\fR arguments are not needed. The update operation will operate on the portals returned by the target, and will update the record with info from the config file and command line. - .IP - \fIshow\fR is the default behaviour for node, discovery and iface mode. It is - also used when there are no commands passed into session mode and a running -diff -pur open-iscsi-2.0-865/etc/initd/initd.debian open-iscsi.git/etc/initd/initd.debian ---- open-iscsi-2.0-865/etc/initd/initd.debian 2007-06-13 17:56:49.000000000 +0200 -+++ open-iscsi.git/etc/initd/initd.debian 2008-02-06 08:24:28.884820000 +0100 -@@ -54,9 +54,16 @@ stop() { - log_daemon_msg "Stopping iSCSI initiator service" - start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON - rm -f $PIDFILE -+ status=0 - modprobe -r ib_iser 2>/dev/null -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi - modprobe -r iscsi_tcp 2>/dev/null -- log_end_msg 0 -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi -+ log_end_msg $status - } - - restart() { -diff -pur open-iscsi-2.0-865/etc/initd/initd.redhat open-iscsi.git/etc/initd/initd.redhat ---- open-iscsi-2.0-865/etc/initd/initd.redhat 2008-03-05 11:28:52.590809000 +0100 -+++ open-iscsi.git/etc/initd/initd.redhat 2008-02-06 08:24:28.908821500 +0100 -@@ -42,9 +42,20 @@ stop() - killproc iscsid - rm -f /var/run/iscsid.pid - [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/open-iscsi -+ status=0 - modprobe -r iscsi_tcp 2>/dev/null -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi - modprobe -r ib_iser 2>/dev/null -- success -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi -+ if [ "$status" -eq "0" ]; then -+ success -+ else -+ failure -+ fi - echo - - } -diff -pur open-iscsi-2.0-865/etc/initd/initd.suse open-iscsi.git/etc/initd/initd.suse ---- open-iscsi-2.0-865/etc/initd/initd.suse 2008-03-05 11:43:19.632995750 +0100 -+++ open-iscsi.git/etc/initd/initd.suse 2008-02-06 08:24:29.564862500 +0100 -@@ -5,7 +5,7 @@ - ### BEGIN INIT INFO - # Provides: iscsi - # Required-Start: $network --# Should-Start: -+# Should-Start: iscsitarget - # Required-Stop: - # Should-Stop: - # Default-Start: 3 5 -@@ -88,9 +88,16 @@ case "$1" in - echo -n "Stopping iSCSI initiator service: " - if [ "$RETVAL" == "0" ]; then - rm -f $PID_FILE -+ status=0 - modprobe -r iscsi_tcp -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi - modprobe -q -r ib_iser -- rc_failed 0 -+ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then -+ status=1 -+ fi -+ rc_failed $status - else - rc_failed 1 - fi -Only in open-iscsi.git/etc/initd: initd.suse~ -diff -pur open-iscsi-2.0-865/etc/iscsid.conf open-iscsi.git/etc/iscsid.conf ---- open-iscsi-2.0-865/etc/iscsid.conf 2008-03-05 11:28:52.622811000 +0100 -+++ open-iscsi.git/etc/iscsid.conf 2008-02-06 08:24:28.924822500 +0100 -@@ -126,7 +126,7 @@ node.session.initial_login_retry_max = 4 - node.session.cmds_max = 128 - - # To control the device's queue depth set node.session.queue_depth --# to a value between 1 and 128. The default is 128. -+# to a value between 1 and 128. The default is 32. - node.session.queue_depth = 32 - - #*************** -Only in open-iscsi.git: .git -diff -pur open-iscsi-2.0-865/include/iscsi_proto.h open-iscsi.git/include/iscsi_proto.h ---- open-iscsi-2.0-865/include/iscsi_proto.h 2008-03-05 11:28:52.742818500 +0100 -+++ open-iscsi.git/include/iscsi_proto.h 2008-03-05 11:29:21.096590500 +0100 -@@ -60,8 +60,8 @@ - /* initiator tags; opaque for target */ - typedef uint32_t __bitwise__ itt_t; - /* below makes sense only for initiator that created this tag */ --#define build_itt(itt, id, age) ((__force itt_t)\ -- ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) -+#define build_itt(itt, age) ((__force itt_t)\ -+ ((itt) | ((age) << ISCSI_AGE_SHIFT))) - #define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK) - #define RESERVED_ITT ((__force itt_t)0xffffffff) - -Only in open-iscsi.git: initd.patch -Only in open-iscsi.git: initd.patch~ -diff -pur open-iscsi-2.0-865/kernel/2.6.14-19_compat.patch open-iscsi.git/kernel/2.6.14-19_compat.patch ---- open-iscsi-2.0-865/kernel/2.6.14-19_compat.patch 2008-03-05 11:28:52.782821000 +0100 -+++ open-iscsi.git/kernel/2.6.14-19_compat.patch 2008-02-06 08:24:28.952824250 +0100 -@@ -1,9 +1,9 @@ - diff --git a/iscsi_compat.h b/iscsi_compat.h - new file mode 100644 --index 0000000..22e7c44 -+index 0000000..965157a - --- /dev/null - +++ b/iscsi_compat.h --@@ -0,0 +1,181 @@ -+@@ -0,0 +1,192 @@ - +#include - +#include - +#include -@@ -135,6 +135,14 @@ index 0000000..22e7c44 - + - +#endif - + -++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -++ -++static inline int is_power_of_2(unsigned long n) -++{ -++ return (n != 0 && ((n & (n - 1)) == 0)); -++} -++#endif -++ - +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) - +#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \ - + netlink_kernel_create(uint, groups, input, mod) -@@ -150,6 +158,9 @@ index 0000000..22e7c44 - + return sg + 1; - +} - + -++#define for_each_sg(sglist, sg, nr, __i) \ -++ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) -++ - +#define sg_page(_sg) _sg->page - + - +static inline void sg_set_page(struct scatterlist *sg, struct page *page, -@@ -186,7 +197,7 @@ index 0000000..22e7c44 - + - +#endif - diff --git a/iscsi_tcp.c b/iscsi_tcp.c --index cc075bc..af93a6c 100644 -+index 4472b23..46d3005 100644 - --- a/iscsi_tcp.c - +++ b/iscsi_tcp.c - @@ -43,6 +43,7 @@ -@@ -197,7 +208,7 @@ index cc075bc..af93a6c 100644 - - MODULE_AUTHOR("Dmitry Yusupov , " - "Alex Aizman "); --@@ -421,6 +422,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, -+@@ -422,6 +423,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, - - debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", - offset, size); -@@ -207,15 +218,15 @@ index cc075bc..af93a6c 100644 - + * or scsi-ml commands. - + */ - + if (!sg_count) { --+ iscsi_segment_init_linear(segment, (void *)sg + offset, -++ iscsi_segment_init_linear(segment, (void *)sg_list + offset, - + size, done, hash); - + return 0; - + } - + - __iscsi_segment_init(segment, size, done, hash); -- for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { -+ for_each_sg(sg_list, sg, sg_count, i) { - debug_scsi("sg %d, len %u offset %u\n", i, sg->length, --@@ -1934,7 +1946,9 @@ static struct scsi_host_template iscsi_sht = { -+@@ -1936,7 +1948,9 @@ static struct scsi_host_template iscsi_sht = { - .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_host_reset_handler = iscsi_eh_host_reset, - .use_clustering = DISABLE_CLUSTERING, -@@ -226,30 +237,33 @@ index cc075bc..af93a6c 100644 - .proc_name = "iscsi_tcp", - .this_id = -1, - diff --git a/iscsi_tcp.h b/iscsi_tcp.h --index 57c2317..783e448 100644 -+index 950d75f..662ddab 100644 - --- a/iscsi_tcp.h - +++ b/iscsi_tcp.h --@@ -27,6 +27,7 @@ -- #define ISCSI_SG_TABLESIZE SG_ALL -- #define ISCSI_TCP_MAX_CMD_LEN 16 -+@@ -24,6 +24,7 @@ -+ -+ #include "libiscsi.h" - - +#include "iscsi_compat.h" - struct crypto_hash; - struct socket; - struct iscsi_tcp_conn; - diff --git a/libiscsi.c b/libiscsi.c --index d175f14..da0dd4e 100644 -+index 20fa67e..2bc9bb2 100644 - --- a/libiscsi.c - +++ b/libiscsi.c --@@ -24,6 +24,7 @@ -+@@ -24,7 +24,10 @@ - #include - #include - #include - +#include -++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) -+ #include -++#endif - #include - #include - #include --@@ -976,10 +977,9 @@ again: -+@@ -980,10 +983,9 @@ again: - return rc; - } - -@@ -262,7 +276,7 @@ index d175f14..da0dd4e 100644 - int rc; - /* - * serialize Xmit worker on a per-connection basis. --@@ -1727,7 +1727,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit, -+@@ -1741,7 +1743,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit, - shost->max_cmd_len = iscsit->max_cmd_len; - shost->transportt = scsit; - shost->transportt->create_work_queue = 1; -@@ -272,7 +286,7 @@ index d175f14..da0dd4e 100644 - *hostno = shost->host_no; - - session = iscsi_hostdata(shost->hostdata); --@@ -1877,7 +1879,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) -+@@ -1891,7 +1895,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) - INIT_LIST_HEAD(&conn->mgmtqueue); - INIT_LIST_HEAD(&conn->xmitqueue); - INIT_LIST_HEAD(&conn->requeue); -@@ -282,7 +296,7 @@ index d175f14..da0dd4e 100644 - /* allocate login_mtask used for the login/text sequences */ - spin_lock_bh(&session->lock); - diff --git a/libiscsi.h b/libiscsi.h --index 8328bc7..028b5df 100644 -+index b7a9b08..134a05b 100644 - --- a/libiscsi.h - +++ b/libiscsi.h - @@ -24,12 +24,14 @@ -@@ -303,7 +317,7 @@ index 8328bc7..028b5df 100644 - struct scsi_device; - struct Scsi_Host; - diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c --index 7e5e168..65541bb 100644 -+index 22c947d..a5aa8a4 100644 - --- a/scsi_transport_iscsi.c - +++ b/scsi_transport_iscsi.c - @@ -21,7 +21,10 @@ -@@ -323,12 +337,25 @@ index 7e5e168..65541bb 100644 - #include "iscsi_if.h" - +#include "iscsi_compat.h" - -- #define ISCSI_SESSION_ATTRS 18 -- #define ISCSI_CONN_ATTRS 11 --@@ -254,11 +258,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, -+ #define ISCSI_SESSION_ATTRS 19 -+ #define ISCSI_CONN_ATTRS 13 -+@@ -322,10 +326,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, - return 0; - } - -+-static void iscsi_scan_session(struct work_struct *work) -++static void iscsi_scan_session(void *data) -+ { -+- struct iscsi_cls_session *session = -+- container_of(work, struct iscsi_cls_session, scan_work); -++ struct iscsi_cls_session *session = data; -+ struct Scsi_Host *shost = iscsi_session_to_shost(session); -+ struct iscsi_host *ihost = shost->shost_data; -+ unsigned long flags; -+@@ -343,11 +346,9 @@ done: -+ atomic_dec(&ihost->nr_scans); -+ } -+ - -static void session_recovery_timedout(struct work_struct *work) - +static void session_recovery_timedout(void *data) - { -@@ -336,10 +363,23 @@ index 7e5e168..65541bb 100644 - - container_of(work, struct iscsi_cls_session, - - recovery_work.work); - + struct iscsi_cls_session *session = data; -+ unsigned long flags; - -- dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " -- "out after %d secs\n", session->recovery_tmo); --@@ -285,11 +287,9 @@ void iscsi_block_session(struct iscsi_cls_session *session) -+ iscsi_cls_session_printk(KERN_INFO, session, -+@@ -396,10 +397,12 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) -+ * the async scanning code (drivers like iscsi_tcp do login and -+ * scanning from userspace). -+ */ -++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) -+ if (shost->hostt->scan_finished) { -+ if (queue_work(ihost->scan_workq, &session->scan_work)) -+ atomic_inc(&ihost->nr_scans); -+ } -++#endif -+ } -+ EXPORT_SYMBOL_GPL(iscsi_unblock_session); -+ -+@@ -417,11 +420,9 @@ void iscsi_block_session(struct iscsi_cls_session *session) - } - EXPORT_SYMBOL_GPL(iscsi_block_session); - -@@ -353,20 +393,31 @@ index 7e5e168..65541bb 100644 - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - --@@ -327,10 +327,10 @@ iscsi_alloc_session(struct Scsi_Host *shost, -- -+@@ -460,11 +461,11 @@ iscsi_alloc_session(struct Scsi_Host *shost, - session->transport = transport; - session->recovery_tmo = 120; -+ session->state = ISCSI_SESSION_FREE; - - INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); - + INIT_WORK(&session->recovery_work, session_recovery_timedout, session); - INIT_LIST_HEAD(&session->host_list); - INIT_LIST_HEAD(&session->sess_list); - - INIT_WORK(&session->unbind_work, __iscsi_unbind_session); -+- INIT_WORK(&session->scan_work, iscsi_scan_session); - + INIT_WORK(&session->unbind_work, __iscsi_unbind_session, session); -++ INIT_WORK(&session->scan_work, iscsi_scan_session, session); -+ spin_lock_init(&session->lock); - - /* this is released in the dev's release function */ -- scsi_host_get(shost); --@@ -1123,45 +1123,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -+@@ -582,7 +583,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) -+ session->state = ISCSI_SESSION_FREE; -+ spin_unlock_irqrestore(&session->lock, flags); -+ __iscsi_unblock_session(session); -+- __iscsi_unbind_session(&session->unbind_work); -++ __iscsi_unbind_session(session); -+ -+ /* flush running scans */ -+ flush_workqueue(ihost->scan_workq); -+@@ -1273,45 +1274,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) - * Malformed skbs with wrong lengths or invalid creds are not processed. - */ - static void -@@ -456,7 +507,7 @@ index 7e5e168..65541bb 100644 - } - mutex_unlock(&rx_queue_mutex); - } --@@ -1396,7 +1407,10 @@ iscsi_register_transport(struct iscsi_transport *tt) -+@@ -1555,7 +1567,10 @@ iscsi_register_transport(struct iscsi_transport *tt) - INIT_LIST_HEAD(&priv->list); - priv->daemon_pid = -1; - priv->iscsi_transport = tt; -@@ -468,7 +519,7 @@ index 7e5e168..65541bb 100644 - priv->cdev.class = &iscsi_transport_class; - snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); - diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h --index 6bda9b9..deaa582 100644 -+index 2a287c2..d2a0036 100644 - --- a/scsi_transport_iscsi.h - +++ b/scsi_transport_iscsi.h - @@ -25,8 +25,12 @@ -@@ -484,15 +535,15 @@ index 6bda9b9..deaa582 100644 - - struct scsi_transport_template; - struct iscsi_transport; --@@ -185,7 +189,7 @@ struct iscsi_cls_session { -+@@ -182,7 +186,7 @@ struct iscsi_cls_session { - - /* recovery fields */ - int recovery_tmo; - - struct delayed_work recovery_work; - + struct work_struct recovery_work; -- struct work_struct unbind_work; - - int target_id; -+ - -- - 1.5.1.2 - -diff -pur open-iscsi-2.0-865/kernel/2.6.20-21_compat.patch open-iscsi.git/kernel/2.6.20-21_compat.patch ---- open-iscsi-2.0-865/kernel/2.6.20-21_compat.patch 2008-03-05 11:28:52.834824250 +0100 -+++ open-iscsi.git/kernel/2.6.20-21_compat.patch 2008-02-06 08:24:28.976825750 +0100 -@@ -1,15 +1,24 @@ - diff --git a/iscsi_2.6.22_compat.h b/iscsi_2.6.22_compat.h - new file mode 100644 --index 0000000..f2693f1 -+index 0000000..2ba7deb - --- /dev/null - +++ b/iscsi_2.6.22_compat.h --@@ -0,0 +1,73 @@ -+@@ -0,0 +1,85 @@ - +#include - +#include - + - +#ifndef ISCSI_2622_COMPAT_H - +#define ISCSI_2622_COMPAT_H - + -++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20) -++ -++static inline __attribute__((const)) -++bool is_power_of_2(unsigned long n) -++{ -++ return (n != 0 && ((n & (n - 1)) == 0)); -++} -++#endif -++ - +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) - + - +#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \ -@@ -44,6 +53,9 @@ index 0000000..f2693f1 - + return sg + 1; - +} - + -++#define for_each_sg(sglist, sg, nr, __i) \ -++ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) -++ - +#define sg_page(_sg) _sg->page - + - +static inline void sg_set_page(struct scatterlist *sg, struct page *page, -@@ -78,10 +90,10 @@ index 0000000..f2693f1 - + - +#endif - diff --git a/iscsi_tcp.c b/iscsi_tcp.c --index cc075bc..156f87e 100644 -+index ce1fdf1..ad46009 100644 - --- a/iscsi_tcp.c - +++ b/iscsi_tcp.c --@@ -421,6 +421,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, -+@@ -422,6 +422,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, - - debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", - offset, size); -@@ -91,15 +103,15 @@ index cc075bc..156f87e 100644 - + * or scsi-ml commands. - + */ - + if (!sg_count) { --+ iscsi_segment_init_linear(segment, (void *)sg + offset, -++ iscsi_segment_init_linear(segment, (void *)sg_list + offset, - + size, done, hash); - + return 0; - + } - + - __iscsi_segment_init(segment, size, done, hash); -- for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { -+ for_each_sg(sg_list, sg, sg_count, i) { - debug_scsi("sg %d, len %u offset %u\n", i, sg->length, --@@ -1934,7 +1945,9 @@ static struct scsi_host_template iscsi_sht = { -+@@ -1933,7 +1944,9 @@ static struct scsi_host_template iscsi_sht = { - .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_host_reset_handler = iscsi_eh_host_reset, - .use_clustering = DISABLE_CLUSTERING, -@@ -110,19 +122,19 @@ index cc075bc..156f87e 100644 - .proc_name = "iscsi_tcp", - .this_id = -1, - diff --git a/iscsi_tcp.h b/iscsi_tcp.h --index 57c2317..0b706a3 100644 -+index 950d75f..a7bc56f 100644 - --- a/iscsi_tcp.h - +++ b/iscsi_tcp.h --@@ -27,6 +27,7 @@ -- #define ISCSI_SG_TABLESIZE SG_ALL -- #define ISCSI_TCP_MAX_CMD_LEN 16 -+@@ -24,6 +24,7 @@ -+ -+ #include "libiscsi.h" - - +#include "iscsi_2.6.22_compat.h" - struct crypto_hash; - struct socket; - struct iscsi_tcp_conn; - diff --git a/libiscsi.h b/libiscsi.h --index 8328bc7..fbe14c0 100644 -+index 72f6fc6..fb98306 100644 - --- a/libiscsi.h - +++ b/libiscsi.h - @@ -30,6 +30,8 @@ -@@ -135,7 +147,7 @@ index 8328bc7..fbe14c0 100644 - struct scsi_device; - struct Scsi_Host; - diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c --index 7e5e168..dbe94cc 100644 -+index 4686f3a..0cd18a0 100644 - --- a/scsi_transport_iscsi.c - +++ b/scsi_transport_iscsi.c - @@ -29,6 +29,7 @@ -@@ -144,9 +156,9 @@ index 7e5e168..dbe94cc 100644 - #include "iscsi_if.h" - +#include "iscsi_2.6.22_compat.h" - -- #define ISCSI_SESSION_ATTRS 18 -- #define ISCSI_CONN_ATTRS 11 --@@ -1119,49 +1120,61 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -+ #define ISCSI_SESSION_ATTRS 19 -+ #define ISCSI_CONN_ATTRS 13 -+@@ -1265,49 +1266,61 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) - } - - /* -Only in open-iscsi.git/kernel: iscsi_compat.h -diff -pur open-iscsi-2.0-865/kernel/iscsi_tcp.c open-iscsi.git/kernel/iscsi_tcp.c ---- open-iscsi-2.0-865/kernel/iscsi_tcp.c 2008-03-05 11:28:52.906828750 +0100 -+++ open-iscsi.git/kernel/iscsi_tcp.c 2008-02-06 08:24:29.000827250 +0100 -@@ -413,16 +413,17 @@ iscsi_segment_init_linear(struct iscsi_s - - static inline int - iscsi_segment_seek_sg(struct iscsi_segment *segment, -- struct scatterlist *sg, unsigned int sg_count, -+ struct scatterlist *sg_list, unsigned int sg_count, - unsigned int offset, size_t size, - iscsi_segment_done_fn_t *done, struct hash_desc *hash) - { -+ struct scatterlist *sg; - unsigned int i; - - debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", - offset, size); - __iscsi_segment_init(segment, size, done, hash); -- for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { -+ for_each_sg(sg_list, sg, sg_count, i) { - debug_scsi("sg %d, len %u offset %u\n", i, sg->length, - sg->offset); - if (offset < sg->length) { -@@ -628,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s - int rc; - - if (tcp_conn->in.datalen) { -- printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", -- tcp_conn->in.datalen); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "invalid R2t with datalen %d\n", -+ tcp_conn->in.datalen); - return ISCSI_ERR_DATALEN; - } - -@@ -640,13 +642,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s - } - - /* fill-in new R2T associated with the task */ -- spin_lock(&session->lock); - iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - - if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { -- printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " -- "recovery...\n", ctask->itt); -- spin_unlock(&session->lock); -+ iscsi_conn_printk(KERN_INFO, conn, -+ "dropping R2T itt %d in recovery.\n", -+ ctask->itt); - return 0; - } - -@@ -656,10 +657,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s - r2t->exp_statsn = rhdr->statsn; - r2t->data_length = be32_to_cpu(rhdr->data_length); - if (r2t->data_length == 0) { -- printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "invalid R2T with zero data len\n"); - __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); -- spin_unlock(&session->lock); - return ISCSI_ERR_DATALEN; - } - -@@ -670,12 +671,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s - - r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { -- printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " -- "offset %u and total length %d\n", r2t->data_length, -- r2t->data_offset, scsi_bufflen(ctask->sc)); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "invalid R2T with data len %u at offset %u " -+ "and total length %d\n", r2t->data_length, -+ r2t->data_offset, scsi_bufflen(ctask->sc)); - __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, - sizeof(void*)); -- spin_unlock(&session->lock); - return ISCSI_ERR_DATALEN; - } - -@@ -689,8 +690,6 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, s - conn->r2t_pdus_cnt++; - - iscsi_requeue_ctask(ctask); -- spin_unlock(&session->lock); -- - return 0; - } - -@@ -741,8 +740,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn - /* verify PDU length */ - tcp_conn->in.datalen = ntoh24(hdr->dlength); - if (tcp_conn->in.datalen > conn->max_recv_dlength) { -- printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", -- tcp_conn->in.datalen, conn->max_recv_dlength); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "iscsi_tcp: datalen %d > %d\n", -+ tcp_conn->in.datalen, conn->max_recv_dlength); - return ISCSI_ERR_DATALEN; - } - -@@ -763,7 +763,9 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn - switch(opcode) { - case ISCSI_OP_SCSI_DATA_IN: - ctask = session->cmds[itt]; -+ spin_lock(&conn->session->lock); - rc = iscsi_data_rsp(conn, ctask); -+ spin_unlock(&conn->session->lock); - if (rc) - return rc; - if (tcp_conn->in.datalen) { -@@ -805,9 +807,11 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn - ctask = session->cmds[itt]; - if (ahslen) - rc = ISCSI_ERR_AHSLEN; -- else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) -+ else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { -+ spin_lock(&session->lock); - rc = iscsi_r2t_rsp(conn, ctask); -- else -+ spin_unlock(&session->lock); -+ } else - rc = ISCSI_ERR_PROTO; - break; - case ISCSI_OP_LOGIN_RSP: -@@ -820,10 +824,12 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn - * For now we fail until we find a vendor that needs it - */ - if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { -- printk(KERN_ERR "iscsi_tcp: received buffer of len %u " -- "but conn buffer is only %u (opcode %0x)\n", -- tcp_conn->in.datalen, -- ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "iscsi_tcp: received buffer of " -+ "len %u but conn buffer is only %u " -+ "(opcode %0x)\n", -+ tcp_conn->in.datalen, -+ ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); - rc = ISCSI_ERR_PROTO; - break; - } -@@ -1497,30 +1503,25 @@ iscsi_tcp_conn_create(struct iscsi_cls_s - tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - tcp_conn->tx_hash.flags = 0; -- if (IS_ERR(tcp_conn->tx_hash.tfm)) { -- printk(KERN_ERR "Could not create connection due to crc32c " -- "loading error %ld. Make sure the crc32c module is " -- "built as a module or into the kernel\n", -- PTR_ERR(tcp_conn->tx_hash.tfm)); -+ if (IS_ERR(tcp_conn->tx_hash.tfm)) - goto free_tcp_conn; -- } - - tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - tcp_conn->rx_hash.flags = 0; -- if (IS_ERR(tcp_conn->rx_hash.tfm)) { -- printk(KERN_ERR "Could not create connection due to crc32c " -- "loading error %ld. Make sure the crc32c module is " -- "built as a module or into the kernel\n", -- PTR_ERR(tcp_conn->rx_hash.tfm)); -+ if (IS_ERR(tcp_conn->rx_hash.tfm)) - goto free_tx_tfm; -- } - - return cls_conn; - - free_tx_tfm: - crypto_free_hash(tcp_conn->tx_hash.tfm); - free_tcp_conn: -+ iscsi_conn_printk(KERN_ERR, conn, -+ "Could not create connection due to crc32c " -+ "loading error. Make sure the crc32c " -+ "module is built as a module or into the " -+ "kernel\n"); - kfree(tcp_conn); - tcp_conn_alloc_fail: - iscsi_conn_teardown(cls_conn); -@@ -1628,7 +1629,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_ses - /* lookup for existing socket */ - sock = sockfd_lookup((int)transport_eph, &err); - if (!sock) { -- printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "sockfd_lookup failed %d\n", err); - return -EEXIST; - } - /* -@@ -1775,12 +1777,12 @@ iscsi_conn_set_param(struct iscsi_cls_co - break; - case ISCSI_PARAM_MAX_R2T: - sscanf(buf, "%d", &value); -- if (session->max_r2t == roundup_pow_of_two(value)) -+ if (value <= 0 || !is_power_of_2(value)) -+ return -EINVAL; -+ if (session->max_r2t == value) - break; - iscsi_r2tpool_free(session); - iscsi_set_param(cls_conn, param, buf, buflen); -- if (session->max_r2t & (session->max_r2t - 1)) -- session->max_r2t = roundup_pow_of_two(session->max_r2t); - if (iscsi_r2tpool_alloc(session)) - return -ENOMEM; - break; -@@ -1927,7 +1929,7 @@ static struct scsi_host_template iscsi_s - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, -- .sg_tablesize = ISCSI_SG_TABLESIZE, -+ .sg_tablesize = 4096, - .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, - .eh_abort_handler = iscsi_eh_abort, -@@ -1974,7 +1976,7 @@ static struct iscsi_transport iscsi_tcp_ - .host_template = &iscsi_sht, - .conndata_size = sizeof(struct iscsi_conn), - .max_conn = 1, -- .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, -+ .max_cmd_len = 16, - /* session management */ - .create_session = iscsi_tcp_session_create, - .destroy_session = iscsi_tcp_session_destroy, -diff -pur open-iscsi-2.0-865/kernel/iscsi_tcp.h open-iscsi.git/kernel/iscsi_tcp.h ---- open-iscsi-2.0-865/kernel/iscsi_tcp.h 2008-03-05 11:28:52.942831000 +0100 -+++ open-iscsi.git/kernel/iscsi_tcp.h 2008-02-06 08:24:29.044830000 +0100 -@@ -24,9 +24,6 @@ - - #include "libiscsi.h" - --#define ISCSI_SG_TABLESIZE SG_ALL --#define ISCSI_TCP_MAX_CMD_LEN 16 -- - struct crypto_hash; - struct socket; - struct iscsi_tcp_conn; -diff -pur open-iscsi-2.0-865/kernel/libiscsi.c open-iscsi.git/kernel/libiscsi.c ---- open-iscsi-2.0-865/kernel/libiscsi.c 2008-03-05 11:28:52.986833750 +0100 -+++ open-iscsi.git/kernel/libiscsi.c 2008-03-05 11:29:21.132592750 +0100 -@@ -24,6 +24,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -159,7 +160,7 @@ static int iscsi_prep_scsi_cmd_pdu(struc - hdr->opcode = ISCSI_OP_SCSI_CMD; - hdr->flags = ISCSI_ATTR_SIMPLE; - int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); -- hdr->itt = build_itt(ctask->itt, conn->id, session->age); -+ hdr->itt = build_itt(ctask->itt, session->age); - hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); - hdr->cmdsn = cpu_to_be32(session->cmdsn); - session->cmdsn++; -@@ -415,8 +416,9 @@ static void iscsi_scsi_cmd_rsp(struct is - - if (datalen < 2) { - invalid_datalen: -- printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " -- "invalid data buffer size of %d\n", datalen); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "Got CHECK_CONDITION but invalid data " -+ "buffer size of %d\n", datalen); - sc->result = DID_BAD_TARGET << 16; - goto out; - } -@@ -431,9 +433,6 @@ invalid_datalen: - min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); - } - -- if (sc->sc_data_direction == DMA_TO_DEVICE) -- goto out; -- - if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | - ISCSI_FLAG_CMD_OVERFLOW)) { - int res_count = be32_to_cpu(rhdr->residual_count); -@@ -496,7 +495,7 @@ static void iscsi_send_nopout(struct isc - - mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); - if (!mtask) { -- printk(KERN_ERR "Could not send nopout\n"); -+ iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); - return; - } - -@@ -524,9 +523,10 @@ static int iscsi_handle_reject(struct is - if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { - memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - itt = get_itt(rejected_pdu.itt); -- printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " -- "due to DataDigest error.\n", itt, -- rejected_pdu.opcode); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "itt 0x%x had pdu (op 0x%x) rejected " -+ "due to DataDigest error.\n", itt, -+ rejected_pdu.opcode); - } - } - return 0; -@@ -699,18 +699,13 @@ int iscsi_verify_itt(struct iscsi_conn * - if (hdr->itt != RESERVED_ITT) { - if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != - (session->age << ISCSI_AGE_SHIFT)) { -- printk(KERN_ERR "iscsi: received itt %x expected " -- "session age (%x)\n", (__force u32)hdr->itt, -- session->age & ISCSI_AGE_MASK); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "received itt %x expected session " -+ "age (%x)\n", (__force u32)hdr->itt, -+ session->age & ISCSI_AGE_MASK); - return ISCSI_ERR_BAD_ITT; - } - -- if (((__force u32)hdr->itt & ISCSI_CID_MASK) != -- (conn->id << ISCSI_CID_SHIFT)) { -- printk(KERN_ERR "iscsi: received itt %x, expected " -- "CID (%x)\n", (__force u32)hdr->itt, conn->id); -- return ISCSI_ERR_BAD_ITT; -- } - itt = get_itt(hdr->itt); - } else - itt = ~0U; -@@ -719,16 +714,17 @@ int iscsi_verify_itt(struct iscsi_conn * - ctask = session->cmds[itt]; - - if (!ctask->sc) { -- printk(KERN_INFO "iscsi: dropping ctask with " -- "itt 0x%x\n", ctask->itt); -+ iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " -+ "with itt 0x%x\n", ctask->itt); - /* force drop */ - return ISCSI_ERR_NO_SCSI_CMD; - } - - if (ctask->sc->SCp.phase != session->age) { -- printk(KERN_ERR "iscsi: ctask's session age %d, " -- "expected %d\n", ctask->sc->SCp.phase, -- session->age); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "iscsi: ctask's session age %d, " -+ "expected %d\n", ctask->sc->SCp.phase, -+ session->age); - return ISCSI_ERR_SESSION_FAILED; - } - } -@@ -773,7 +769,7 @@ static void iscsi_prep_mtask(struct iscs - */ - nop->cmdsn = cpu_to_be32(session->cmdsn); - if (hdr->itt != RESERVED_ITT) { -- hdr->itt = build_itt(mtask->itt, conn->id, session->age); -+ hdr->itt = build_itt(mtask->itt, session->age); - /* - * TODO: We always use immediate, so we never hit this. - * If we start to send tmfs or nops as non-immediate then -@@ -999,6 +995,7 @@ enum { - FAILURE_SESSION_IN_RECOVERY, - FAILURE_SESSION_RECOVERY_TIMEOUT, - FAILURE_SESSION_LOGGING_OUT, -+ FAILURE_SESSION_NOT_READY, - }; - - int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) -@@ -1019,6 +1016,12 @@ int iscsi_queuecommand(struct scsi_cmnd - session = iscsi_hostdata(host->hostdata); - spin_lock(&session->lock); - -+ reason = iscsi_session_chkready(session_to_cls(session)); -+ if (reason) { -+ sc->result = reason; -+ goto fault; -+ } -+ - /* - * ISCSI_STATE_FAILED is a temp. state. The recovery - * code will decide what is best to do with command queued -@@ -1035,18 +1038,23 @@ int iscsi_queuecommand(struct scsi_cmnd - switch (session->state) { - case ISCSI_STATE_IN_RECOVERY: - reason = FAILURE_SESSION_IN_RECOVERY; -- goto reject; -+ sc->result = DID_IMM_RETRY << 16; -+ break; - case ISCSI_STATE_LOGGING_OUT: - reason = FAILURE_SESSION_LOGGING_OUT; -- goto reject; -+ sc->result = DID_IMM_RETRY << 16; -+ break; - case ISCSI_STATE_RECOVERY_FAILED: - reason = FAILURE_SESSION_RECOVERY_TIMEOUT; -+ sc->result = DID_NO_CONNECT << 16; - break; - case ISCSI_STATE_TERMINATE: - reason = FAILURE_SESSION_TERMINATE; -+ sc->result = DID_NO_CONNECT << 16; - break; - default: - reason = FAILURE_SESSION_FREED; -+ sc->result = DID_NO_CONNECT << 16; - } - goto fault; - } -@@ -1054,6 +1062,7 @@ int iscsi_queuecommand(struct scsi_cmnd - conn = session->leadconn; - if (!conn) { - reason = FAILURE_SESSION_FREED; -+ sc->result = DID_NO_CONNECT << 16; - goto fault; - } - -@@ -1093,9 +1102,7 @@ reject: - - fault: - spin_unlock(&session->lock); -- printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", -- sc->cmnd[0], reason); -- sc->result = (DID_NO_CONNECT << 16); -+ debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); - scsi_set_resid(sc, scsi_bufflen(sc)); - sc->scsi_done(sc); - spin_lock(host->host_lock); -@@ -1162,7 +1169,8 @@ failed: - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_LOGGED_IN) -- printk(KERN_INFO "iscsi: host reset succeeded\n"); -+ iscsi_session_printk(KERN_INFO, session, -+ "host reset succeeded\n"); - else - goto failed; - spin_unlock_bh(&session->lock); -@@ -1241,7 +1249,8 @@ static int iscsi_exec_task_mgmt_fn(struc - * Fail commands. session lock held and recv side suspended and xmit - * thread flushed - */ --static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) -+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, -+ int error) - { - struct iscsi_cmd_task *ctask, *tmp; - -@@ -1253,7 +1262,7 @@ static void fail_all_commands(struct isc - if (lun == ctask->sc->device->lun || lun == -1) { - debug_scsi("failing pending sc %p itt 0x%x\n", - ctask->sc, ctask->itt); -- fail_command(conn, ctask, DID_BUS_BUSY << 16); -+ fail_command(conn, ctask, error << 16); - } - } - -@@ -1261,7 +1270,7 @@ static void fail_all_commands(struct isc - if (lun == ctask->sc->device->lun || lun == -1) { - debug_scsi("failing requeued sc %p itt 0x%x\n", - ctask->sc, ctask->itt); -- fail_command(conn, ctask, DID_BUS_BUSY << 16); -+ fail_command(conn, ctask, error << 16); - } - } - -@@ -1359,10 +1368,10 @@ static void iscsi_check_transport_timeou - last_recv = conn->last_recv; - if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), - jiffies)) { -- printk(KERN_ERR "ping timeout of %d secs expired, " -- "last rx %lu, last ping %lu, now %lu\n", -- conn->ping_timeout, last_recv, -- conn->last_ping, jiffies); -+ iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " -+ "expired, last rx %lu, last ping %lu, " -+ "now %lu\n", conn->ping_timeout, last_recv, -+ conn->last_ping, jiffies); - spin_unlock(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return; -@@ -1375,14 +1384,11 @@ static void iscsi_check_transport_timeou - iscsi_send_nopout(conn, NULL); - } - next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); -- } else { -+ } else - next_timeout = last_recv + timeout; -- } - -- if (next_timeout) { -- debug_scsi("Setting next tmo %lu\n", next_timeout); -- mod_timer(&conn->transport_timer, next_timeout); -- } -+ debug_scsi("Setting next tmo %lu\n", next_timeout); -+ mod_timer(&conn->transport_timer, next_timeout); - done: - spin_unlock(&session->lock); - } -@@ -1575,7 +1581,7 @@ int iscsi_eh_device_reset(struct scsi_cm - /* need to grab the recv lock then session lock */ - write_lock_bh(conn->recv_lock); - spin_lock(&session->lock); -- fail_all_commands(conn, sc->device->lun); -+ fail_all_commands(conn, sc->device->lun, DID_ERROR); - conn->tmf_state = TMF_INITIAL; - spin_unlock(&session->lock); - write_unlock_bh(conn->recv_lock); -@@ -1703,7 +1709,7 @@ iscsi_session_setup(struct iscsi_transpo - qdepth = ISCSI_DEF_CMD_PER_LUN; - } - -- if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || -+ if (!is_power_of_2(cmds_max) || - cmds_max >= ISCSI_MGMT_ITT_OFFSET) { - if (cmds_max != 0) - printk(KERN_ERR "iscsi: invalid can_queue of %d. " -@@ -1946,9 +1952,10 @@ void iscsi_conn_teardown(struct iscsi_cl - } - spin_unlock_irqrestore(session->host->host_lock, flags); - msleep_interruptible(500); -- printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " -- "host_failed %d\n", session->host->host_busy, -- session->host->host_failed); -+ iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " -+ "host_busy %d host_failed %d\n", -+ session->host->host_busy, -+ session->host->host_failed); - /* - * force eh_abort() to unblock - */ -@@ -1977,27 +1984,28 @@ int iscsi_conn_start(struct iscsi_cls_co - struct iscsi_session *session = conn->session; - - if (!session) { -- printk(KERN_ERR "iscsi: can't start unbound connection\n"); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "can't start unbound connection\n"); - return -EPERM; - } - - if ((session->imm_data_en || !session->initial_r2t_en) && - session->first_burst > session->max_burst) { -- printk("iscsi: invalid burst lengths: " -- "first_burst %d max_burst %d\n", -- session->first_burst, session->max_burst); -+ iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " -+ "first_burst %d max_burst %d\n", -+ session->first_burst, session->max_burst); - return -EINVAL; - } - - if (conn->ping_timeout && !conn->recv_timeout) { -- printk(KERN_ERR "iscsi: invalid recv timeout of zero " -- "Using 5 seconds\n."); -+ iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " -+ "zero. Using 5 seconds\n."); - conn->recv_timeout = 5; - } - - if (conn->recv_timeout && !conn->ping_timeout) { -- printk(KERN_ERR "iscsi: invalid ping timeout of zero " -- "Using 5 seconds.\n"); -+ iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " -+ "zero. Using 5 seconds.\n"); - conn->ping_timeout = 5; - } - -@@ -2021,11 +2029,9 @@ int iscsi_conn_start(struct iscsi_cls_co - conn->stop_stage = 0; - conn->tmf_state = TMF_INITIAL; - session->age++; -- spin_unlock_bh(&session->lock); -- -- iscsi_unblock_session(session_to_cls(session)); -- wake_up(&conn->ehwait); -- return 0; -+ if (session->age == 16) -+ session->age = 0; -+ break; - case STOP_CONN_TERM: - conn->stop_stage = 0; - break; -@@ -2034,6 +2040,8 @@ int iscsi_conn_start(struct iscsi_cls_co - } - spin_unlock_bh(&session->lock); - -+ iscsi_unblock_session(session_to_cls(session)); -+ wake_up(&conn->ehwait); - return 0; - } - EXPORT_SYMBOL_GPL(iscsi_conn_start); -@@ -2125,7 +2133,8 @@ static void iscsi_start_session_recovery - * flush queues. - */ - spin_lock_bh(&session->lock); -- fail_all_commands(conn, -1); -+ fail_all_commands(conn, -1, -+ STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); - flush_control_queues(session, conn); - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); -@@ -2142,7 +2151,8 @@ void iscsi_conn_stop(struct iscsi_cls_co - iscsi_start_session_recovery(session, conn, flag); - break; - default: -- printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); -+ iscsi_conn_printk(KERN_ERR, conn, -+ "invalid stop flag %d\n", flag); - } - } - EXPORT_SYMBOL_GPL(iscsi_conn_stop); -Only in open-iscsi.git/kernel: libiscsi.c~ -diff -pur open-iscsi-2.0-865/kernel/libiscsi.h open-iscsi.git/kernel/libiscsi.h ---- open-iscsi-2.0-865/kernel/libiscsi.h 2008-03-05 11:28:53.310854000 +0100 -+++ open-iscsi.git/kernel/libiscsi.h 2008-03-05 11:29:21.160594500 +0100 -@@ -70,8 +70,6 @@ enum { - #define ISCSI_SUSPEND_BIT 1 - - #define ISCSI_ITT_MASK (0xfff) --#define ISCSI_CID_SHIFT 12 --#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT) - #define ISCSI_AGE_SHIFT 28 - #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) - -@@ -135,6 +133,14 @@ static inline void* iscsi_next_hdr(struc - return (void*)ctask->hdr + ctask->hdr_len; - } - -+/* Connection's states */ -+enum { -+ ISCSI_CONN_INITIAL_STAGE, -+ ISCSI_CONN_STARTED, -+ ISCSI_CONN_STOPPED, -+ ISCSI_CONN_CLEANUP_WAIT, -+}; -+ - struct iscsi_conn { - struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ - void *dd_data; /* iscsi_transport data */ -@@ -227,6 +233,17 @@ struct iscsi_pool { - int max; /* Max number of elements */ - }; - -+/* Session's states */ -+enum { -+ ISCSI_STATE_FREE = 1, -+ ISCSI_STATE_LOGGED_IN, -+ ISCSI_STATE_FAILED, -+ ISCSI_STATE_TERMINATE, -+ ISCSI_STATE_IN_RECOVERY, -+ ISCSI_STATE_RECOVERY_FAILED, -+ ISCSI_STATE_LOGGING_OUT, -+}; -+ - struct iscsi_session { - /* - * Syncs up the scsi eh thread with the iscsi eh thread when sending -@@ -325,6 +342,10 @@ extern int iscsi_session_get_param(struc - #define session_to_cls(_sess) \ - hostdata_session(_sess->host->hostdata) - -+#define iscsi_session_printk(prefix, _sess, fmt, a...) \ -+ iscsi_cls_session_printk(prefix, \ -+ (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) -+ - /* - * connection management - */ -@@ -339,6 +360,9 @@ extern void iscsi_conn_failure(struct is - extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf); - -+#define iscsi_conn_printk(prefix, _c, fmt, a...) \ -+ iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) -+ - /* - * pdu and task processing - */ -diff -pur open-iscsi-2.0-865/kernel/scsi_transport_iscsi.c open-iscsi.git/kernel/scsi_transport_iscsi.c ---- open-iscsi-2.0-865/kernel/scsi_transport_iscsi.c 2008-03-05 11:28:53.374858000 +0100 -+++ open-iscsi.git/kernel/scsi_transport_iscsi.c 2008-03-05 11:29:21.212597750 +0100 -@@ -30,10 +30,10 @@ - #include "scsi_transport_iscsi.h" - #include "iscsi_if.h" - --#define ISCSI_SESSION_ATTRS 18 --#define ISCSI_CONN_ATTRS 11 -+#define ISCSI_SESSION_ATTRS 19 -+#define ISCSI_CONN_ATTRS 13 - #define ISCSI_HOST_ATTRS 4 --#define ISCSI_TRANSPORT_VERSION "2.0-724" -+#define ISCSI_TRANSPORT_VERSION "2.0-868" - - struct iscsi_internal { - int daemon_pid; -@@ -127,12 +127,13 @@ static int iscsi_setup_host(struct trans - memset(ihost, 0, sizeof(*ihost)); - INIT_LIST_HEAD(&ihost->sessions); - mutex_init(&ihost->mutex); -+ atomic_set(&ihost->nr_scans, 0); - -- snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", -+ snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", - shost->host_no); -- ihost->unbind_workq = create_singlethread_workqueue( -- ihost->unbind_workq_name); -- if (!ihost->unbind_workq) -+ ihost->scan_workq = create_singlethread_workqueue( -+ ihost->scan_workq_name); -+ if (!ihost->scan_workq) - return -ENOMEM; - return 0; - } -@@ -143,7 +144,7 @@ static int iscsi_remove_host(struct tran - struct Scsi_Host *shost = dev_to_shost(dev); - struct iscsi_host *ihost = shost->shost_data; - -- destroy_workqueue(ihost->unbind_workq); -+ destroy_workqueue(ihost->scan_workq); - return 0; - } - -@@ -221,6 +222,54 @@ static struct iscsi_cls_conn *iscsi_conn - * The following functions can be used by LLDs that allocate - * their own scsi_hosts or by software iscsi LLDs - */ -+static struct { -+ int value; -+ char *name; -+} iscsi_session_state_names[] = { -+ { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, -+ { ISCSI_SESSION_FAILED, "FAILED" }, -+ { ISCSI_SESSION_FREE, "FREE" }, -+}; -+ -+const char *iscsi_session_state_name(int state) -+{ -+ int i; -+ char *name = NULL; -+ -+ for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { -+ if (iscsi_session_state_names[i].value == state) { -+ name = iscsi_session_state_names[i].name; -+ break; -+ } -+ } -+ return name; -+} -+ -+int iscsi_session_chkready(struct iscsi_cls_session *session) -+{ -+ unsigned long flags; -+ int err; -+ -+ spin_lock_irqsave(&session->lock, flags); -+ switch (session->state) { -+ case ISCSI_SESSION_LOGGED_IN: -+ err = 0; -+ break; -+ case ISCSI_SESSION_FAILED: -+ err = DID_IMM_RETRY << 16; -+ break; -+ case ISCSI_SESSION_FREE: -+ err = DID_NO_CONNECT << 16; -+ break; -+ default: -+ err = DID_NO_CONNECT << 16; -+ break; -+ } -+ spin_unlock_irqrestore(&session->lock, flags); -+ return err; -+} -+EXPORT_SYMBOL_GPL(iscsi_session_chkready); -+ - static void iscsi_session_release(struct device *dev) - { - struct iscsi_cls_session *session = iscsi_dev_to_session(dev); -@@ -236,6 +285,25 @@ static int iscsi_is_session_dev(const st - return dev->release == iscsi_session_release; - } - -+/** -+ * iscsi_scan_finished - helper to report when running scans are done -+ * @shost: scsi host -+ * @time: scan run time -+ * -+ * This function can be used by drives like qla4xxx to report to the scsi -+ * layer when the scans it kicked off at module load time are done. -+ */ -+int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) -+{ -+ struct iscsi_host *ihost = shost->shost_data; -+ /* -+ * qla4xxx will have kicked off some session unblocks before calling -+ * scsi_scan_host, so just wait for them to complete. -+ */ -+ return !atomic_read(&ihost->nr_scans); -+} -+EXPORT_SYMBOL_GPL(iscsi_scan_finished); -+ - static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, - uint id, uint lun) - { -@@ -254,14 +322,50 @@ static int iscsi_user_scan(struct Scsi_H - return 0; - } - -+static void iscsi_scan_session(struct work_struct *work) -+{ -+ struct iscsi_cls_session *session = -+ container_of(work, struct iscsi_cls_session, scan_work); -+ struct Scsi_Host *shost = iscsi_session_to_shost(session); -+ struct iscsi_host *ihost = shost->shost_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&session->lock, flags); -+ if (session->state != ISCSI_SESSION_LOGGED_IN) { -+ spin_unlock_irqrestore(&session->lock, flags); -+ goto done; -+ } -+ spin_unlock_irqrestore(&session->lock, flags); -+ -+ scsi_scan_target(&session->dev, 0, session->target_id, -+ SCAN_WILD_CARD, 1); -+done: -+ atomic_dec(&ihost->nr_scans); -+} -+ - static void session_recovery_timedout(struct work_struct *work) - { - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, - recovery_work.work); -+ unsigned long flags; - -- dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " -- "out after %d secs\n", session->recovery_tmo); -+ iscsi_cls_session_printk(KERN_INFO, session, -+ "session recovery timed out after %d secs\n", -+ session->recovery_tmo); -+ -+ spin_lock_irqsave(&session->lock, flags); -+ switch (session->state) { -+ case ISCSI_SESSION_FAILED: -+ session->state = ISCSI_SESSION_FREE; -+ break; -+ case ISCSI_SESSION_LOGGED_IN: -+ case ISCSI_SESSION_FREE: -+ /* we raced with the unblock's flush */ -+ spin_unlock_irqrestore(&session->lock, flags); -+ return; -+ } -+ spin_unlock_irqrestore(&session->lock, flags); - - if (session->transport->session_recovery_timedout) - session->transport->session_recovery_timedout(session); -@@ -269,16 +373,44 @@ static void session_recovery_timedout(st - scsi_target_unblock(&session->dev); - } - --void iscsi_unblock_session(struct iscsi_cls_session *session) -+void __iscsi_unblock_session(struct iscsi_cls_session *session) - { - if (!cancel_delayed_work(&session->recovery_work)) - flush_workqueue(iscsi_eh_timer_workq); - scsi_target_unblock(&session->dev); - } -+ -+void iscsi_unblock_session(struct iscsi_cls_session *session) -+{ -+ struct Scsi_Host *shost = iscsi_session_to_shost(session); -+ struct iscsi_host *ihost = shost->shost_data; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&session->lock, flags); -+ session->state = ISCSI_SESSION_LOGGED_IN; -+ spin_unlock_irqrestore(&session->lock, flags); -+ -+ __iscsi_unblock_session(session); -+ /* -+ * Only do kernel scanning if the driver is properly hooked into -+ * the async scanning code (drivers like iscsi_tcp do login and -+ * scanning from userspace). -+ */ -+ if (shost->hostt->scan_finished) { -+ if (queue_work(ihost->scan_workq, &session->scan_work)) -+ atomic_inc(&ihost->nr_scans); -+ } -+} - EXPORT_SYMBOL_GPL(iscsi_unblock_session); - - void iscsi_block_session(struct iscsi_cls_session *session) - { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&session->lock, flags); -+ session->state = ISCSI_SESSION_FAILED; -+ spin_unlock_irqrestore(&session->lock, flags); -+ - scsi_target_block(&session->dev); - queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, - session->recovery_tmo * HZ); -@@ -311,7 +443,7 @@ static int iscsi_unbind_session(struct i - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_host *ihost = shost->shost_data; - -- return queue_work(ihost->unbind_workq, &session->unbind_work); -+ return queue_work(ihost->scan_workq, &session->unbind_work); - } - - struct iscsi_cls_session * -@@ -327,10 +459,13 @@ iscsi_alloc_session(struct Scsi_Host *sh - - session->transport = transport; - session->recovery_tmo = 120; -+ session->state = ISCSI_SESSION_FREE; - INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); - INIT_LIST_HEAD(&session->host_list); - INIT_LIST_HEAD(&session->sess_list); - INIT_WORK(&session->unbind_work, __iscsi_unbind_session); -+ INIT_WORK(&session->scan_work, iscsi_scan_session); -+ spin_lock_init(&session->lock); - - /* this is released in the dev's release function */ - scsi_host_get(shost); -@@ -358,8 +493,8 @@ int iscsi_add_session(struct iscsi_cls_s - session->sid); - err = device_add(&session->dev); - if (err) { -- dev_printk(KERN_ERR, &session->dev, "iscsi: could not " -- "register session's dev\n"); -+ iscsi_cls_session_printk(KERN_ERR, session, -+ "could not register session's dev\n"); - goto release_host; - } - transport_register_device(&session->dev); -@@ -443,22 +578,28 @@ void iscsi_remove_session(struct iscsi_c - * If we are blocked let commands flow again. The lld or iscsi - * layer should set up the queuecommand to fail commands. - */ -- iscsi_unblock_session(session); -- iscsi_unbind_session(session); -+ spin_lock_irqsave(&session->lock, flags); -+ session->state = ISCSI_SESSION_FREE; -+ spin_unlock_irqrestore(&session->lock, flags); -+ __iscsi_unblock_session(session); -+ __iscsi_unbind_session(&session->unbind_work); -+ -+ /* flush running scans */ -+ flush_workqueue(ihost->scan_workq); - /* - * If the session dropped while removing devices then we need to make - * sure it is not blocked - */ - if (!cancel_delayed_work(&session->recovery_work)) - flush_workqueue(iscsi_eh_timer_workq); -- flush_workqueue(ihost->unbind_workq); - - /* hw iscsi may not have removed all connections from session */ - err = device_for_each_child(&session->dev, NULL, - iscsi_iter_destroy_conn_fn); - if (err) -- dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " -- "all connections for session. Error %d.\n", err); -+ iscsi_cls_session_printk(KERN_ERR, session, -+ "Could not delete all connections " -+ "for session. Error %d.\n", err); - - transport_unregister_device(&session->dev); - device_del(&session->dev); -@@ -530,8 +671,8 @@ iscsi_create_conn(struct iscsi_cls_sessi - conn->dev.release = iscsi_conn_release; - err = device_register(&conn->dev); - if (err) { -- dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " -- "connection's dev\n"); -+ iscsi_cls_session_printk(KERN_ERR, session, "could not " -+ "register connection's dev\n"); - goto release_parent_ref; - } - transport_register_device(&conn->dev); -@@ -638,8 +779,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); -- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " -- "control PDU: OOM\n"); -+ iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " -+ "control PDU: OOM\n"); - return -ENOMEM; - } - -@@ -660,20 +801,27 @@ EXPORT_SYMBOL_GPL(iscsi_recv_pdu); - - void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) - { -+ struct iscsi_cls_session *session = iscsi_conn_to_session(conn); - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - struct iscsi_internal *priv; - int len = NLMSG_SPACE(sizeof(*ev)); -+ unsigned long flags; - - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) - return; - -+ spin_lock_irqsave(&session->lock, flags); -+ if (session->state == ISCSI_SESSION_LOGGED_IN) -+ session->state = ISCSI_SESSION_FAILED; -+ spin_unlock_irqrestore(&session->lock, flags); -+ - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { -- dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " -- "conn error (%d)\n", error); -+ iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " -+ "conn error (%d)\n", error); - return; - } - -@@ -687,8 +835,8 @@ void iscsi_conn_error(struct iscsi_cls_c - - iscsi_broadcast_skb(skb, GFP_ATOMIC); - -- dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", -- error); -+ iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", -+ error); - } - EXPORT_SYMBOL_GPL(iscsi_conn_error); - -@@ -743,8 +891,8 @@ iscsi_if_get_stats(struct iscsi_transpor - - skbstat = alloc_skb(len, GFP_ATOMIC); - if (!skbstat) { -- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " -- "deliver stats: OOM\n"); -+ iscsi_cls_conn_printk(KERN_ERR, conn, "can not " -+ "deliver stats: OOM\n"); - return -ENOMEM; - } - -@@ -800,8 +948,9 @@ int iscsi_session_event(struct iscsi_cls - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) { -- dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " -- "of session event %u\n", event); -+ iscsi_cls_session_printk(KERN_ERR, session, -+ "Cannot notify userspace of session " -+ "event %u\n", event); - return -ENOMEM; - } - -@@ -824,8 +973,8 @@ int iscsi_session_event(struct iscsi_cls - ev->r.unbind_session.sid = session->sid; - break; - default: -- dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", -- event); -+ iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " -+ "%u.\n", event); - kfree_skb(skb); - return -EINVAL; - } -@@ -836,8 +985,10 @@ int iscsi_session_event(struct iscsi_cls - */ - rc = iscsi_broadcast_skb(skb, GFP_KERNEL); - if (rc < 0) -- dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " -- "of session event %u. Check iscsi daemon\n", event); -+ iscsi_cls_session_printk(KERN_ERR, session, -+ "Cannot notify userspace of session " -+ "event %u. Check iscsi daemon\n", -+ event); - return rc; - } - EXPORT_SYMBOL_GPL(iscsi_session_event); -@@ -870,16 +1021,15 @@ iscsi_if_create_conn(struct iscsi_transp - - session = iscsi_session_lookup(ev->u.c_conn.sid); - if (!session) { -- printk(KERN_ERR "iscsi: invalid session %d\n", -+ printk(KERN_ERR "iscsi: invalid session %d.\n", - ev->u.c_conn.sid); - return -EINVAL; - } - - conn = transport->create_conn(session, ev->u.c_conn.cid); - if (!conn) { -- printk(KERN_ERR "iscsi: couldn't create a new " -- "connection for session %d\n", -- session->sid); -+ iscsi_cls_session_printk(KERN_ERR, session, -+ "couldn't create a new connection."); - return -ENOMEM; - } - -@@ -1245,6 +1395,15 @@ iscsi_session_attr(fast_abort, ISCSI_PAR - iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); - iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); - -+static ssize_t -+show_priv_session_state(struct class_device *cdev, char *buf) -+{ -+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); -+ return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); -+} -+static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, -+ NULL); -+ - #define iscsi_priv_session_attr_show(field, format) \ - static ssize_t \ - show_priv_session_##field(struct class_device *cdev, char *buf) \ -@@ -1471,6 +1630,7 @@ iscsi_register_transport(struct iscsi_tr - SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); - SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); - SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); -+ SETUP_PRIV_SESSION_RD_ATTR(state); - - BUG_ON(count > ISCSI_SESSION_ATTRS); - priv->session_attrs[count] = NULL; -diff -pur open-iscsi-2.0-865/kernel/scsi_transport_iscsi.h open-iscsi.git/kernel/scsi_transport_iscsi.h ---- open-iscsi-2.0-865/kernel/scsi_transport_iscsi.h 2008-03-05 11:28:53.654875500 +0100 -+++ open-iscsi.git/kernel/scsi_transport_iscsi.h 2008-02-06 08:24:29.168837750 +0100 -@@ -149,13 +149,6 @@ extern void iscsi_conn_error(struct iscs - extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size); - -- --/* Connection's states */ --#define ISCSI_CONN_INITIAL_STAGE 0 --#define ISCSI_CONN_STARTED 1 --#define ISCSI_CONN_STOPPED 2 --#define ISCSI_CONN_CLEANUP_WAIT 3 -- - struct iscsi_cls_conn { - struct list_head conn_list; /* item in connlist */ - void *dd_data; /* LLD private data */ -@@ -169,27 +162,31 @@ struct iscsi_cls_conn { - #define iscsi_dev_to_conn(_dev) \ - container_of(_dev, struct iscsi_cls_conn, dev) - --/* Session's states */ --#define ISCSI_STATE_FREE 1 --#define ISCSI_STATE_LOGGED_IN 2 --#define ISCSI_STATE_FAILED 3 --#define ISCSI_STATE_TERMINATE 4 --#define ISCSI_STATE_IN_RECOVERY 5 --#define ISCSI_STATE_RECOVERY_FAILED 6 --#define ISCSI_STATE_LOGGING_OUT 7 -+#define iscsi_conn_to_session(_conn) \ -+ iscsi_dev_to_session(_conn->dev.parent) -+ -+/* iscsi class session state */ -+enum { -+ ISCSI_SESSION_LOGGED_IN, -+ ISCSI_SESSION_FAILED, -+ ISCSI_SESSION_FREE, -+}; - - struct iscsi_cls_session { - struct list_head sess_list; /* item in session_list */ - struct list_head host_list; - struct iscsi_transport *transport; -+ spinlock_t lock; -+ struct work_struct scan_work; -+ struct work_struct unbind_work; - - /* recovery fields */ - int recovery_tmo; - struct delayed_work recovery_work; -- struct work_struct unbind_work; - - int target_id; - -+ int state; - int sid; /* session id */ - void *dd_data; /* LLD private data */ - struct device dev; /* sysfs transport/container device */ -@@ -206,14 +203,22 @@ struct iscsi_cls_session { - - struct iscsi_host { - struct list_head sessions; -+ atomic_t nr_scans; - struct mutex mutex; -- struct workqueue_struct *unbind_workq; -- char unbind_workq_name[KOBJ_NAME_LEN]; -+ struct workqueue_struct *scan_workq; -+ char scan_workq_name[KOBJ_NAME_LEN]; - }; - - /* - * session and connection functions that can be used by HW iSCSI LLDs - */ -+#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \ -+ dev_printk(prefix, &(_cls_session)->dev, fmt, ##a) -+ -+#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \ -+ dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a) -+ -+extern int iscsi_session_chkready(struct iscsi_cls_session *session); - extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, - struct iscsi_transport *transport); - extern int iscsi_add_session(struct iscsi_cls_session *session, -@@ -231,6 +236,6 @@ extern struct iscsi_cls_conn *iscsi_crea - extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); - extern void iscsi_unblock_session(struct iscsi_cls_session *session); - extern void iscsi_block_session(struct iscsi_cls_session *session); -- -+extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); - - #endif -diff -pur open-iscsi-2.0-865/Makefile open-iscsi.git/Makefile ---- open-iscsi-2.0-865/Makefile 2008-03-05 11:28:52.450800250 +0100 -+++ open-iscsi.git/Makefile 2008-02-06 08:24:28.816815750 +0100 -@@ -95,8 +95,10 @@ install_iface: $(IFACEFILES) - $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces - - install_etc: $(ETCFILES) -- $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi -- $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi -+ if [ ! -f /etc/iscsi/iscsid.conf ]; then \ -+ $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \ -+ $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \ -+ fi - - install_doc: $(MANPAGES) - $(INSTALL) -d $(DESTDIR)$(mandir)/man8 -Only in open-iscsi.git: Makefile~ -Only in open-iscsi.git: open-iscsi-adjust-can_queue -Only in open-iscsi.git: open-iscsi-dont-overwrite-nodes-on-discovery -Only in open-iscsi.git: open-iscsi-fwparam_ppc -Only in open-iscsi.git: open-iscsi-fwparam-scan-in-blocks -Only in open-iscsi.git: open-iscsi-git-update -Only in open-iscsi.git: open-iscsi-suse-init-fixes -Only in open-iscsi-2.0-865: patches -Only in open-iscsi-2.0-865: .pc -diff -pur open-iscsi-2.0-865/README open-iscsi.git/README ---- open-iscsi-2.0-865/README 2008-03-05 11:43:19.248971750 +0100 -+++ open-iscsi.git/README 2008-03-05 11:29:21.020585750 +0100 -@@ -4,7 +4,7 @@ - - ================================================================= - -- Jan 26, 2007 -+ Feb 21, 2008 - - Contents - ======== -@@ -174,10 +174,36 @@ Usage: iscsiadm [OPTION] - - -m, --mode specify operational mode op = - -m discovery --type=[type] --interface=iscsi_ifacename \ -- --portal=[ip:port] --login --print=[N] -+ --portal=[ip:port] --login --print=[N] \ -+ --op=[op]=[NEW | UPDATE | DELETE] - perform [type] discovery for target portal with - ip-address [ip] and port [port]. - -+ By default this command will remove records -+ for portals no longer returned. And, if a portal is -+ returned by the target, then the discovery command -+ will create a new record or modify an existing one -+ with values from iscsi.conf and the command line. -+ -+ [op] can be passed in multiple times to this -+ command, and it will alter the DB manipulation. -+ -+ If [op] is passed in and the value is -+ "new", iscsiadm will add records for portals that do -+ not yet have records in the db. -+ -+ If [op] is passed in and the value is -+ "update", iscsiadm will update records using info -+ from iscsi.conf and the command line for portals -+ that are returned during discovery and have -+ a record in the db. -+ -+ if [op] is passed in and the value is "delete", -+ iscsiadm will delete records for portals that -+ were not returned during discovery. -+ -+ See the example section for more info. -+ - See below for how to setup iscsi ifaces for - software iscsi or override the system defaults. - -@@ -220,7 +246,10 @@ Usage: iscsiadm [OPTION] - op could be one of: - [new], [delete], [update] or [show]. In case of - [update], you have to provide [name] and [value] -- you wish to update -+ you wish to update. -+ [delete] - Note that if a session is using the -+ node record, the session will be logged out then -+ the record will be deleted. - - Print level can be 0 to 1. - -@@ -346,7 +375,7 @@ with the name "iface0" this command will - (This will set the hwaddress.) - # iscsiadm -m iface -I iface0 --op=update -n iface.hwaddress -v 00:0F:1F:92:6B:BF - --If you had sessions logged in iscsiadm will not update, delete or overwrite -+If you had sessions logged in iscsiadm will not update, overwrite - a iface. You must log out first. If you have a iface bound to a node/portal - but you have not logged in then, iscsiadm will update the config and - all existing bindings. -@@ -406,7 +435,49 @@ iscsiadm -m node -p ip:port -I iface0 -- - discovery will be setup so that they can logged in through - those interfaces. - -- - SendTargets iSCSI Discovery with a specific interface. If you -+ - SendTargets iSCSI Discovery updating existing records: -+ -+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ -+ -o update -+ -+ If there a record for targetX and portalY exists in the DB, and -+ is returned during discovery, it will be updated with the info -+ from the iscsi.conf. No new portals will be added and stale -+ portals will not be removed. -+ -+ - SendTargets iSCSI Discovery deleting existing records: -+ -+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ -+ -o delete -+ -+ If there a record for targetX and portalY exists in the DB, but -+ is not returned during discovery it will be removed from the DB. -+ No new portals will be added and existing portal records will not -+ be changed. -+ -+ Note: If a session is logged into portal we are going to delete -+ a record for, it will be logged out then the record will be -+ deleted. -+ -+ - SendTargets iSCSI Discovery adding new records: -+ -+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ -+ -o new -+ -+ If there targetX and portalY is returned during discovery and does -+ not have a record, it will be added. Existing records are not -+ modified. -+ -+ - SendTargets iSCSI Discovery using multiple ops: -+ -+ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ -+ -o new -o delete -+ -+ This command will add new portals and delete records for portals -+ no longer returned. It will not change the record information for -+ existing portals. -+ -+ - SendTargets iSCSI Discovery with a specific interface. If you - wish to only use a subset of the interfaces in /etc/iscsi/ifaces - then you can pass them in during discovery: - -@@ -866,6 +937,25 @@ Host Number: X State: Recovery - When the SCSI EH is running, commands will not be failed until - node.session.timeo.replacement_timeout seconds. - -+To modify the the timer that starts the SCSI EH, you can either write -+directly to the devices's sysfs file: -+ -+echo X > /sys/block/sdX/device/timeout -+ -+where X is in seconds or on most distros you can modify the udev rule. -+ -+To modify the udev rule open /etc/udev/rules.d/50-udev.rules, and find the -+following lines: -+ -+ACTION=="add", SUBSYSTEM=="scsi" , SYSFS{type}=="0|7|14", \ -+ RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'" -+ -+And change the echo 60 part of the line to the value that you want. -+ -+The default timeout for normal File System commands is 30 seconds when udev -+is not being used. If udev is used the default is the above value which -+is normally 60 seconds. -+ - - 8.1.2.2 Pending Commands and replacement_timeout - ------------------------------------------------ -@@ -889,13 +979,13 @@ dm-multipath. - --------------------------------------- - - The default value for replacement_timeout is 120 seconds, but because --multipath's queue if no path setting can prevent IO errors from being propogated --to the application, replacement_timeout can be set to a shorter value like --15 to 30 seconds. By setting it lower pending IO is quickly sent to a new path --and executed while the iSCSI layer attempts to re-establishment the session. --If all paths end up being failed, then the multipath and device mapper layer --will internally queue IO based on the multipath.conf settings, instead of the --iSCSI layer. -+multipath's queue_if_no_path and no_path_retyr setting can prevent IO errors -+from being propogated to the application, replacement_timeout can be set to a -+shorter value like 5 to 15 seconds. By setting it lower pending IO is quickly -+sent to a new path and executed while the iSCSI layer attempts -+re-establishment of the session. If all paths end up being failed, then the -+multipath and device mapper layer will internally queue IO based on the -+multipath.conf settings, instead of the iSCSI layer. - - - 8.2 iSCSI settings for iSCSI root -Only in open-iscsi-2.0-865: series -Only in open-iscsi.git: tmp -Only in open-iscsi.git: tmp~ -Only in open-iscsi.git/usr: actor.o -Only in open-iscsi.git/usr: auth.o -diff -pur open-iscsi-2.0-865/usr/discovery.c open-iscsi.git/usr/discovery.c ---- open-iscsi-2.0-865/usr/discovery.c 2008-03-05 11:43:19.280973750 +0100 -+++ open-iscsi.git/usr/discovery.c 2008-03-05 11:29:21.256600500 +0100 -@@ -183,12 +183,13 @@ iterate_targets(iscsi_session_t *session - return 1; - } - --static int add_portal(idbm_t *db, discovery_rec_t *drec, -- struct list_head *ifaces, node_rec_t *rec, -- char *address, char *port, char *tag) -+static int add_portal(idbm_t *db, struct list_head *rec_list, -+ discovery_rec_t *drec, char *targetname, char *address, -+ char *port, char *tag) - { - struct sockaddr_storage ss; - char host[NI_MAXHOST]; -+ struct node_rec *rec; - - /* resolve the address, in case it was a DNS name */ - if (resolve_address(address, port, &ss)) { -@@ -200,6 +201,16 @@ static int add_portal(idbm_t *db, discov - getnameinfo((struct sockaddr *) &ss, sizeof(ss), - host, sizeof(host), NULL, 0, NI_NUMERICHOST); - -+ rec = calloc(1, sizeof(*rec)); -+ if (!rec) -+ return 0; -+ -+ idbm_node_setup_from_conf(db, rec); -+ rec->disc_type = drec->type; -+ rec->disc_port = drec->port; -+ strcpy(rec->disc_address, drec->address); -+ -+ strncpy(rec->name, targetname, TARGET_NAME_MAXLEN); - if (tag && *tag) - rec->tpgt = atoi(tag); - else -@@ -210,21 +221,18 @@ static int add_portal(idbm_t *db, discov - rec->conn[0].port = ISCSI_LISTEN_PORT; - strncpy(rec->conn[0].address, address, NI_MAXHOST); - -- if (idbm_add_nodes(db, rec, drec, ifaces)) -- log_error("Could not add record for %s %s,%d,%d\n", -- rec->name, address, rec->conn[0].port, rec->tpgt); -+ list_add_tail(&rec->list, rec_list); - return 1; - } - - static int - add_target_record(idbm_t *db, char *name, char *end, -- discovery_rec_t *drec, struct list_head *ifaces, -+ discovery_rec_t *drec, struct list_head *rec_list, - char *default_port) - { - char *text = NULL; - char *nul = name; - size_t length; -- node_rec_t rec; - - /* address = IPv4 - * address = [IPv6] -@@ -251,10 +259,6 @@ add_target_record(idbm_t *db, char *name - log_error("TargetName %s too long, ignoring", name); - return 0; - } -- -- idbm_node_setup_from_conf(db, &rec); -- strncpy(rec.name, name, TARGET_NAME_MAXLEN); -- - text = name + length; - - /* skip NULs after the name */ -@@ -267,7 +271,7 @@ add_target_record(idbm_t *db, char *name - log_error("no default address known for target %s", - name); - return 0; -- } else if (!add_portal(db, drec, ifaces, &rec, drec->address, -+ } else if (!add_portal(db, rec_list, drec, name, drec->address, - default_port, NULL)) { - log_error("failed to add default portal, ignoring " - "target %s", name); -@@ -305,7 +309,7 @@ add_target_record(idbm_t *db, char *name - *temp = '\0'; - } - -- if (!add_portal(db, drec, ifaces, &rec, address, port, -+ if (!add_portal(db, rec_list, drec, name, address, port, - tag)) { - log_error("failed to add default portal, " - "ignoring target %s", name); -@@ -323,7 +327,7 @@ add_target_record(idbm_t *db, char *name - static int - process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets, - int final, discovery_rec_t *drec, -- struct list_head *ifaces, -+ struct list_head *rec_list, - char *default_port) - { - char *start = buffer_data(sendtargets); -@@ -375,7 +379,7 @@ process_sendtargets_response(idbm_t *db, - * "TargetName=" prefix. - */ - if (!add_target_record(db, record + 11, text, -- drec, ifaces, -+ drec, rec_list, - default_port)) { - log_error( - "failed to add target record"); -@@ -404,7 +408,7 @@ process_sendtargets_response(idbm_t *db, - "line %s", - record, record); - if (add_target_record (db, record + 11, text, -- drec, ifaces, default_port)) { -+ drec, rec_list, default_port)) { - num_targets++; - record = NULL; - truncate_buffer(sendtargets, 0); -@@ -684,7 +688,7 @@ setup_authentication(iscsi_session_t *se - static int - process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, - discovery_rec_t *drec, -- struct list_head *ifaces, -+ struct list_head *rec_list, - iscsi_session_t *session, - struct string_buffer *sendtargets, - char *default_port, -@@ -721,22 +725,12 @@ process_recvd_pdu(idbm_t *db, struct isc - memcpy(buffer_data(sendtargets) + curr_data_length, - data, dlength); - -- /* -- * we got a response so clear out the current -- * db values -- * -- * TODO: should we make whether rm the current -- * values configurable (maybe a --clear option) -- */ -- if (!*valid_text) -- idbm_new_discovery(db, drec); - *valid_text = 1; -- - /* process as much as we can right now */ - process_sendtargets_response(db, sendtargets, - final, - drec, -- ifaces, -+ rec_list, - default_port); - - if (final) { -@@ -828,7 +822,7 @@ done: - } - - int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, -- struct list_head *ifaces) -+ struct list_head *rec_list) - { - iscsi_session_t *session; - struct pollfd pfd; -@@ -981,7 +975,6 @@ redirect_reconnect: - break; - - case LOGIN_IO_ERROR: -- case LOGIN_WRONG_PORTAL_GROUP: - case LOGIN_REDIRECTION_FAILED: - /* try again */ - log_warning("retrying discovery login to %s", host); -@@ -1126,7 +1119,7 @@ repoll: - /* - * process iSCSI PDU received - */ -- rc = process_recvd_pdu(db, pdu, drec, ifaces, -+ rc = process_recvd_pdu(db, pdu, drec, rec_list, - session, &sendtargets, - default_port, - &active, &valid_text, data); -Only in open-iscsi.git/usr: discovery.c.orig -Only in open-iscsi.git/usr: discovery.c.rej -Only in open-iscsi.git/usr: discovery.o -diff -pur open-iscsi-2.0-865/usr/idbm.c open-iscsi.git/usr/idbm.c ---- open-iscsi-2.0-865/usr/idbm.c 2008-03-05 11:43:19.296974750 +0100 -+++ open-iscsi.git/usr/idbm.c 2008-03-05 11:29:21.300603250 +0100 -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -40,7 +41,7 @@ - #define IDBM_SHOW 1 /* Show parameter when print. */ - #define IDBM_MASKED 2 /* Show "stars" instead of real value when print */ - --#define __recinfo_str(_key, _info, _rec, _name, _show, _n) do { \ -+#define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \ - _info[_n].type = TYPE_STR; \ - strncpy(_info[_n].name, _key, NAME_MAXVAL); \ - if (strlen((char*)_rec->_name)) \ -@@ -49,20 +50,22 @@ - _info[_n].data = &_rec->_name; \ - _info[_n].data_len = sizeof(_rec->_name); \ - _info[_n].visible = _show; \ -+ _info[_n].can_modify = _mod; \ - _n++; \ - } while(0) - --#define __recinfo_int(_key, _info, _rec, _name, _show, _n) do { \ -+#define __recinfo_int(_key, _info, _rec, _name, _show, _n, _mod) do { \ - _info[_n].type = TYPE_INT; \ - strncpy(_info[_n].name, _key, NAME_MAXVAL); \ - snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \ - _info[_n].data = &_rec->_name; \ - _info[_n].data_len = sizeof(_rec->_name); \ - _info[_n].visible = _show; \ -+ _info[_n].can_modify = _mod; \ - _n++; \ - } while(0) - --#define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n) do { \ -+#define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \ - _info[_n].type = TYPE_INT_O; \ - strncpy(_info[_n].name, _key, NAME_MAXVAL); \ - if (_rec->_name == 0) strncpy(_info[_n].value, _op0, VALUE_MAXVAL); \ -@@ -73,38 +76,46 @@ - _info[_n].opts[0] = _op0; \ - _info[_n].opts[1] = _op1; \ - _info[_n].numopts = 2; \ -+ _info[_n].can_modify = _mod; \ - _n++; \ - } while(0) - --#define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n)do{ \ -- __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n); _n--; \ -- if (_rec->_name == 2) strncpy(_info[_n].value, _op2, VALUE_MAXVAL); \ -+#define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, \ -+ _mod) do { \ -+ __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod); \ -+ _n--; \ -+ if (_rec->_name == 2) strncpy(_info[_n].value, _op2, VALUE_MAXVAL);\ - _info[_n].opts[2] = _op2; \ - _info[_n].numopts = 3; \ - _n++; \ - } while(0) - --#define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n)do{\ -- __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n); _n--; \ -+#define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n, \ -+ _mod) do { \ -+ __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, _mod); \ -+ _n--; \ - if (_rec->_name == 3) strncpy(_info[_n].value, _op3, VALUE_MAXVAL); \ - _info[_n].opts[3] = _op3; \ - _info[_n].numopts = 4; \ - _n++; \ - } while(0) - --#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_op4,_n)do{\ -- __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n); _n--; \ -+#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ -+ _op4,_n, _mod) do { \ -+ __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ -+ _n,_mod); \ -+ _n--; \ - if (_rec->_name == 4) strncpy(_info[_n].value, _op4, VALUE_MAXVAL); \ - _info[_n].opts[4] = _op4; \ - _info[_n].numopts = 5; \ - _n++; \ - } while(0) - --#define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2,\ -- _op3,_op4,_op5,_n)\ --do{\ -- __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,\ -- _op4,_n); _n--; \ -+#define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2, \ -+ _op3,_op4,_op5,_n,_mod) do { \ -+ __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ -+ _op4,_n,_mod); \ -+ _n--; \ - if (_rec->_name == 5) strncpy(_info[_n].value, _op5, VALUE_MAXVAL); \ - _info[_n].opts[5] = _op5; \ - _info[_n].numopts = 6; \ -@@ -194,47 +205,47 @@ idbm_recinfo_discovery(discovery_rec_t * - int num = 0; - - __recinfo_int_o2("discovery.startup", ri, r, startup, IDBM_SHOW, -- "manual", "automatic", num); -+ "manual", "automatic", num, 1); - __recinfo_int_o6("discovery.type", ri, r, type, IDBM_SHOW, - "sendtargets", "offload_send_targets", "slp", "isns", -- "static", "fw", num); -+ "static", "fw", num, 0); - if (r->type == DISCOVERY_TYPE_SENDTARGETS) { - __recinfo_str("discovery.sendtargets.address", ri, r, -- address, IDBM_SHOW, num); -+ address, IDBM_SHOW, num, 0); - __recinfo_int("discovery.sendtargets.port", ri, r, -- port, IDBM_SHOW, num); -+ port, IDBM_SHOW, num, 0); - __recinfo_int_o2("discovery.sendtargets.auth.authmethod", ri, r, - u.sendtargets.auth.authmethod, -- IDBM_SHOW, "None", "CHAP", num); -+ IDBM_SHOW, "None", "CHAP", num, 1); - __recinfo_str("discovery.sendtargets.auth.username", ri, r, -- u.sendtargets.auth.username, IDBM_SHOW, num); -+ u.sendtargets.auth.username, IDBM_SHOW, num, 1); - __recinfo_str("discovery.sendtargets.auth.password", ri, r, -- u.sendtargets.auth.password, IDBM_MASKED, num); -+ u.sendtargets.auth.password, IDBM_MASKED, num, 1); - __recinfo_int("discovery.sendtargets.auth.password_length", - ri, r, u.sendtargets.auth.password_length, -- IDBM_HIDE, num); -+ IDBM_HIDE, num, 1); - __recinfo_str("discovery.sendtargets.auth.username_in", ri, r, -- u.sendtargets.auth.username_in, IDBM_SHOW, num); -+ u.sendtargets.auth.username_in, IDBM_SHOW, num, 1); - __recinfo_str("discovery.sendtargets.auth.password_in", ri, r, -- u.sendtargets.auth.password_in, IDBM_MASKED, num); -+ u.sendtargets.auth.password_in, IDBM_MASKED, num, 1); - __recinfo_int("discovery.sendtargets.auth.password_in_length", - ri, r, u.sendtargets.auth.password_in_length, -- IDBM_HIDE, num); -+ IDBM_HIDE, num, 1); - __recinfo_int("discovery.sendtargets.timeo.login_timeout",ri, r, - u.sendtargets.conn_timeo.login_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("discovery.sendtargets.reopen_max",ri, r, - u.sendtargets.reopen_max, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("discovery.sendtargets.timeo.auth_timeout", ri, r, - u.sendtargets.conn_timeo.auth_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("discovery.sendtargets.timeo.active_timeout",ri,r, - u.sendtargets.conn_timeo.active_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("discovery.sendtargets.iscsi.MaxRecvDataSegmentLength", - ri, r, u.sendtargets.iscsi.MaxRecvDataSegmentLength, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - } - } - -@@ -243,137 +254,151 @@ idbm_recinfo_node(node_rec_t *r, recinfo - { - int num = 0, i; - -- __recinfo_str("node.name", ri, r, name, IDBM_SHOW, num); -- __recinfo_int("node.tpgt", ri, r, tpgt, IDBM_SHOW, num); -+ __recinfo_str("node.name", ri, r, name, IDBM_SHOW, num, 0); -+ __recinfo_int("node.tpgt", ri, r, tpgt, IDBM_SHOW, num, 0); - __recinfo_int_o3("node.startup", ri, r, startup, -- IDBM_SHOW, "manual", "automatic", "onboot", num); -+ IDBM_SHOW, "manual", "automatic", "onboot", num, 1); -+ /* -+ * Note: because we do not add the iface.iscsi_ifacename to -+ * sysfs iscsiadm does some weird matching. We can change the iface -+ * values if a session is not running, but node record ifaces values -+ * have to be changed and so do the iface record ones. -+ * -+ * Users should nornmally not want to change the iface ones -+ * in the node record directly and instead do it through -+ * the iface mode which will do the right thing (althought that -+ * needs some locking). -+ */ - __recinfo_str("iface.hwaddress", ri, r, iface.hwaddress, IDBM_SHOW, -- num); -+ num, 1); - // __recinfo_str("iface.ipaddress", ri, r, iface.ipaddress, - // IDBM_SHOW, num); - __recinfo_str("iface.iscsi_ifacename", ri, r, iface.name, IDBM_SHOW, -- num); -+ num, 1); - __recinfo_str("iface.net_ifacename", ri, r, iface.netdev, IDBM_SHOW, -- num); -+ num, 1); - /* - * svn 780 compat: older versions used node.transport_name and - * rec->transport_name - */ - __recinfo_str("iface.transport_name", ri, r, iface.transport_name, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_str("node.discovery_address", ri, r, disc_address, IDBM_SHOW, -- num); -- __recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, num); -+ num, 0); -+ __recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, -+ num, 0); - __recinfo_int_o6("node.discovery_type", ri, r, disc_type, - IDBM_SHOW, "send_targets", "offload_send_targets", -- "slp", "isns", "static", "fw", num); -+ "slp", "isns", "static", "fw", num, 0); - __recinfo_int("node.session.initial_cmdsn", ri, r, -- session.initial_cmdsn, IDBM_SHOW, num); -+ session.initial_cmdsn, IDBM_SHOW, num, 1); - __recinfo_int("node.session.initial_login_retry_max", ri, r, -- session.initial_login_retry_max, IDBM_SHOW, num); -+ session.initial_login_retry_max, IDBM_SHOW, num, 1); - __recinfo_int("node.session.cmds_max", ri, r, -- session.cmds_max, IDBM_SHOW, num); -+ session.cmds_max, IDBM_SHOW, num, 1); - __recinfo_int("node.session.queue_depth", ri, r, -- session.queue_depth, IDBM_SHOW, num); -+ session.queue_depth, IDBM_SHOW, num, 1); - __recinfo_int_o2("node.session.auth.authmethod", ri, r, -- session.auth.authmethod, IDBM_SHOW, "None", "CHAP", num); -+ session.auth.authmethod, IDBM_SHOW, "None", "CHAP", num, 1); - __recinfo_str("node.session.auth.username", ri, r, -- session.auth.username, IDBM_SHOW, num); -+ session.auth.username, IDBM_SHOW, num, 1); - __recinfo_str("node.session.auth.password", ri, r, -- session.auth.password, IDBM_MASKED, num); -+ session.auth.password, IDBM_MASKED, num, 1); - __recinfo_int("node.session.auth.password_length", ri, r, -- session.auth.password_length, IDBM_HIDE, num); -+ session.auth.password_length, IDBM_HIDE, num, 1); - __recinfo_str("node.session.auth.username_in", ri, r, -- session.auth.username_in, IDBM_SHOW, num); -+ session.auth.username_in, IDBM_SHOW, num, 1); - __recinfo_str("node.session.auth.password_in", ri, r, -- session.auth.password_in, IDBM_MASKED, num); -+ session.auth.password_in, IDBM_MASKED, num, 1); - __recinfo_int("node.session.auth.password_in_length", ri, r, -- session.auth.password_in_length, IDBM_HIDE, num); -+ session.auth.password_in_length, IDBM_HIDE, num, 1); - __recinfo_int("node.session.timeo.replacement_timeout", ri, r, - session.timeo.replacement_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("node.session.err_timeo.abort_timeout", ri, r, - session.err_timeo.abort_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("node.session.err_timeo.lu_reset_timeout", ri, r, - session.err_timeo.lu_reset_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int("node.session.err_timeo.host_reset_timeout", ri, r, - session.err_timeo.host_reset_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - __recinfo_int_o2("node.session.iscsi.FastAbort", ri, r, -- session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes", num); -+ session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes", -+ num, 1); - __recinfo_int_o2("node.session.iscsi.InitialR2T", ri, r, - session.iscsi.InitialR2T, IDBM_SHOW, -- "No", "Yes", num); -+ "No", "Yes", num, 1); - __recinfo_int_o2("node.session.iscsi.ImmediateData", - ri, r, session.iscsi.ImmediateData, IDBM_SHOW, -- "No", "Yes", num); -+ "No", "Yes", num, 1); - __recinfo_int("node.session.iscsi.FirstBurstLength", ri, r, -- session.iscsi.FirstBurstLength, IDBM_SHOW, num); -+ session.iscsi.FirstBurstLength, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.MaxBurstLength", ri, r, -- session.iscsi.MaxBurstLength, IDBM_SHOW, num); -+ session.iscsi.MaxBurstLength, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.DefaultTime2Retain", ri, r, -- session.iscsi.DefaultTime2Retain, IDBM_SHOW, num); -+ session.iscsi.DefaultTime2Retain, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.DefaultTime2Wait", ri, r, -- session.iscsi.DefaultTime2Wait, IDBM_SHOW, num); -+ session.iscsi.DefaultTime2Wait, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.MaxConnections", ri, r, -- session.iscsi.MaxConnections, IDBM_SHOW, num); -+ session.iscsi.MaxConnections, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.MaxOutstandingR2T", ri, r, -- session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num); -+ session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1); - __recinfo_int("node.session.iscsi.ERL", ri, r, -- session.iscsi.ERL, IDBM_SHOW, num); -+ session.iscsi.ERL, IDBM_SHOW, num, 1); - - for (i = 0; i < ISCSI_CONN_MAX; i++) { - char key[NAME_MAXVAL]; - - sprintf(key, "node.conn[%d].address", i); -- __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num); -+ __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num, 0); - sprintf(key, "node.conn[%d].port", i); -- __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num); -+ __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num, 0); - sprintf(key, "node.conn[%d].startup", i); - __recinfo_int_o3(key, ri, r, conn[i].startup, IDBM_SHOW, -- "manual", "automatic", "onboot", num); -+ "manual", "automatic", "onboot", num, 1); - sprintf(key, "node.conn[%d].tcp.window_size", i); - __recinfo_int(key, ri, r, conn[i].tcp.window_size, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - sprintf(key, "node.conn[%d].tcp.type_of_service", i); - __recinfo_int(key, ri, r, conn[i].tcp.type_of_service, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - sprintf(key, "node.conn[%d].timeo.logout_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.logout_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - sprintf(key, "node.conn[%d].timeo.login_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.login_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - sprintf(key, "node.conn[%d].timeo.auth_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - - sprintf(key, "node.conn[%d].timeo.noop_out_interval", i); - __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - sprintf(key, "node.conn[%d].timeo.noop_out_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.noop_out_timeout, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - - sprintf(key, "node.conn[%d].iscsi.MaxRecvDataSegmentLength", i); - __recinfo_int(key, ri, r, -- conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW, num); -+ conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW, -+ num, 1); - sprintf(key, "node.conn[%d].iscsi.HeaderDigest", i); - __recinfo_int_o4(key, ri, r, conn[i].iscsi.HeaderDigest, - IDBM_SHOW, "None", "CRC32C", "CRC32C,None", -- "None,CRC32C", num); -+ "None,CRC32C", num, 1); - sprintf(key, "node.conn[%d].iscsi.DataDigest", i); - __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, - "None", "CRC32C", "CRC32C,None", -- "None,CRC32C", num); -+ "None,CRC32C", num, 1); - sprintf(key, "node.conn[%d].iscsi.IFMarker", i); - __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, -- "No", "Yes", num); -+ "No", "Yes", num, 1); - sprintf(key, "node.conn[%d].iscsi.OFMarker", i); - __recinfo_int_o2(key, ri, r, conn[i].iscsi.OFMarker, IDBM_SHOW, -- "No", "Yes", num); -+ "No", "Yes", num, 1); - } - } - -@@ -382,12 +407,12 @@ idbm_recinfo_iface(iface_rec_t *r, recin - { - int num = 0; - -- __recinfo_str("iface.iscsi_ifacename", ri, r, name, IDBM_SHOW, num); -- __recinfo_str("iface.net_ifacename", ri, r, netdev, IDBM_SHOW, num); --// __recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num); -- __recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num); -+ __recinfo_str("iface.iscsi_ifacename", ri, r, name, IDBM_SHOW, num, 0); -+ __recinfo_str("iface.net_ifacename", ri, r, netdev, IDBM_SHOW, num, 1); -+// __recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num, 1); -+ __recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num, 1); - __recinfo_str("iface.transport_name", ri, r, transport_name, -- IDBM_SHOW, num); -+ IDBM_SHOW, num, 1); - } - - static recinfo_t* -@@ -481,8 +506,8 @@ idbm_discovery_setup_defaults(discovery_ - } - - static int --idbm_node_update_param(recinfo_t *info, char *name, char *value, -- int line_number) -+idbm_rec_update_param(recinfo_t *info, char *name, char *value, -+ int line_number) - { - int i; - int passwd_done = 0; -@@ -551,6 +576,31 @@ updated: - return 0; - } - -+/* -+ * TODO: we can also check for valid values here. -+ */ -+static int idbm_verify_param(recinfo_t *info, char *name) -+{ -+ int i; -+ -+ for (i = 0; i < MAX_KEYS; i++) { -+ if (strcmp(name, info[i].name)) -+ continue; -+ -+ log_debug(7, "verify %s %d\n", name, info[i].can_modify); -+ if (info[i].can_modify) -+ return 0; -+ else { -+ log_error("Cannot modify %s. It is used to look up " -+ "the record and cannot be changed.", name); -+ return EINVAL; -+ } -+ } -+ -+ log_error("Cannot modify %s. Invalid param name.", name); -+ return EINVAL; -+} -+ - static void - idbm_recinfo_config(recinfo_t *info, FILE *f) - { -@@ -615,7 +665,7 @@ idbm_recinfo_config(recinfo_t *info, FIL - } - *(value+i) = 0; - -- (void)idbm_node_update_param(info, name, value, line_number); -+ (void)idbm_rec_update_param(info, name, value, line_number); - } while (line); - } - -@@ -710,6 +760,14 @@ int idbm_print_node_info(idbm_t *db, voi - return 0; - } - -+int idbm_print_iface_info(idbm_t *db, void *data, struct iface_rec *iface) -+{ -+ int show = *((int *)data); -+ -+ idbm_print(PRINT_TYPE_IFACE, iface, show, stdout); -+ return 0; -+} -+ - int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec) - { - if (strchr(rec->conn[0].address, '.')) -@@ -964,7 +1022,11 @@ int iface_conf_update(idbm_t *db, struct - return ENOMEM; - - idbm_recinfo_iface(iface, info); -- rc = idbm_node_update_param(info, param->name, param->value, 0); -+ rc = idbm_verify_param(info, param->name); -+ if (rc) -+ goto free_info; -+ -+ rc = idbm_rec_update_param(info, param->name, param->value, 0); - if (rc) { - rc = EIO; - goto free_info; -@@ -976,59 +1038,6 @@ free_info: - return rc; - } - --static void idbm_read_def_ifaces(struct list_head *ifaces) --{ -- DIR *iface_dirfd; -- struct dirent *iface_dent; -- struct iface_rec *iface; -- int err = 0; -- -- iface_dirfd = opendir(IFACE_CONFIG_DIR); -- if (!iface_dirfd) -- return; -- -- while ((iface_dent = readdir(iface_dirfd))) { -- if (!strcmp(iface_dent->d_name, ".") || -- !strcmp(iface_dent->d_name, "..")) -- continue; -- -- log_debug(5, "idbm_read_def_ifaces found %s", -- iface_dent->d_name); -- iface = iface_alloc(iface_dent->d_name, &err); -- if (!iface || err) { -- if (err == EINVAL) -- log_error("Invalid iface name %s. Must be " -- "from 1 to %d characters.", -- iface_dent->d_name, -- ISCSI_MAX_IFACE_LEN - 1); -- else -- log_error("Could not add iface %s.", -- iface_dent->d_name); -- free(iface); -- continue; -- } -- -- err = __iface_conf_read(iface); -- if (err) { -- log_error("Could not read def iface %s (err %d)", -- iface->name, err); -- free(iface); -- continue; -- } -- if (!iface_is_bound(iface)) { -- log_debug(5, "Default iface is not bound " -- "Iface settings " iface_fmt, -- iface_str(iface)); -- free(iface); -- continue; -- } -- -- log_debug(5, "idbm_read_def_ifaces added %s", iface->name); -- list_add_tail(&iface->list, ifaces); -- } -- closedir(iface_dirfd); --} -- - static int iface_get_next_id(void) - { - struct stat statb; -@@ -1304,6 +1313,27 @@ int iface_is_bound_by_ipaddr(struct ifac - */ - } - -+/** -+ * iface_print_node_tree - print out binding info -+ * @iface: iface to print out -+ * -+ * Currently this looks like the iface conf print, because we only -+ * have the binding info. When we store the iface specific node settings -+ * in the iface record then it will look different. -+ */ -+int iface_print_tree(void *data, struct iface_rec *iface) -+{ -+ printf("Name: %s\n", iface->name); -+ printf("\tTransport Name: %s\n", -+ strlen(iface->transport_name) ? iface->transport_name : -+ UNKNOWN_VALUE); -+ printf("\tHW Address: %s\n", -+ strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE); -+ printf("\tNetdev: %s\n", -+ strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE); -+ return 0; -+} -+ - int iface_print_flat(void *data, struct iface_rec *iface) - { - printf("%s %s,%s,%s\n", -@@ -1315,34 +1345,34 @@ int iface_print_flat(void *data, struct - return 0; - } - --static int iface_filter(const struct dirent *dir) --{ -- return strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."); --} -- - int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, iface_op_fn *fn) - { -- struct dirent **namelist; -+ DIR *iface_dirfd; -+ struct dirent *iface_dent; - struct iface_rec *iface; -- int err = 0, n, i; -+ int err = 0; - -- n = scandir(IFACE_CONFIG_DIR, &namelist, iface_filter, versionsort); -- if (n <= 0) -- return 0; -+ iface_dirfd = opendir(IFACE_CONFIG_DIR); -+ if (!iface_dirfd) -+ return errno; -+ -+ while ((iface_dent = readdir(iface_dirfd))) { -+ if (!strcmp(iface_dent->d_name, ".") || -+ !strcmp(iface_dent->d_name, "..")) -+ continue; - -- for (i = 0; i < n; i++) { - log_debug(5, "iface_for_each_iface found %s", -- namelist[i]->d_name); -- iface = iface_alloc(namelist[i]->d_name, &err); -+ iface_dent->d_name); -+ iface = iface_alloc(iface_dent->d_name, &err); - if (!iface || err) { - if (err == EINVAL) - log_error("Invalid iface name %s. Must be " - "from 1 to %d characters.", -- namelist[i]->d_name, -+ iface_dent->d_name, - ISCSI_MAX_IFACE_LEN - 1); - else - log_error("Could not add iface %s.", -- namelist[i]->d_name); -+ iface_dent->d_name); - free(iface); - continue; - } -@@ -1372,12 +1402,32 @@ int iface_for_each_iface(idbm_t *db, voi - (*nr_found)++; - } - -- for (i = 0; i < n; i++) -- free(namelist[i]); -- free(namelist); -+ closedir(iface_dirfd); - return err; - } - -+static int iface_link(void *data, struct iface_rec *iface) -+{ -+ struct list_head *ifaces = data; -+ struct iface_rec *iface_copy; -+ -+ iface_copy = calloc(1, sizeof(*iface_copy)); -+ if (!iface_copy) -+ return ENOMEM; -+ -+ memcpy(iface_copy, iface, sizeof(*iface_copy)); -+ INIT_LIST_HEAD(&iface_copy->list); -+ list_add_tail(&iface_copy->list, ifaces); -+ return 0; -+} -+ -+static void iface_link_ifaces(idbm_t *db, struct list_head *ifaces) -+{ -+ int nr_found = 0; -+ -+ iface_for_each_iface(db, ifaces, &nr_found, iface_link); -+} -+ - /* - * Backwards Compat: - * If the portal is a file then we are doing the old style default -@@ -1486,7 +1536,7 @@ static int print_discovered(idbm_t *db, - struct dirent **namelist; - node_rec_t *rec; - -- n = scandir(disc_path, &namelist, st_disc_filter, versionsort); -+ n = scandir(disc_path, &namelist, st_disc_filter, direntcmp); - if (n < 0) - return 0; - -@@ -2094,14 +2144,16 @@ free_portal: - return rc; - } - --static int --idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec) -+int -+idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec, int overwrite) - { - discovery_rec_t rec; - int rc; - - if (!idbm_discovery_read(db, &rec, newrec->address, - newrec->port)) { -+ if (!overwrite) -+ return 0; - log_debug(7, "overwriting existing record"); - } else - log_debug(7, "adding new DB record"); -@@ -2159,7 +2211,8 @@ static int setup_disc_to_node_link(char - return rc; - } - --int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec) -+int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, -+ int overwrite) - { - node_rec_t rec; - char *node_portal, *disc_portal; -@@ -2168,7 +2221,10 @@ int idbm_add_node(idbm_t *db, node_rec_t - if (!idbm_rec_read(db, &rec, newrec->name, newrec->tpgt, - newrec->conn[0].address, newrec->conn[0].port, - &newrec->iface)) { -- rc = idbm_delete_node(db, NULL, &rec); -+ if (!overwrite) -+ return 0; -+ -+ rc = idbm_delete_node(db, &rec); - if (rc) - return rc; - log_debug(7, "overwriting existing record"); -@@ -2221,8 +2277,26 @@ free_portal: - return rc; - } - --int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, -- struct list_head *ifaces) -+static int idbm_bind_iface_to_node(struct node_rec *new_rec, -+ struct iface_rec *iface, -+ struct list_head *bound_recs) -+{ -+ struct node_rec *clone_rec; -+ -+ clone_rec = calloc(1, sizeof(*clone_rec)); -+ if (!clone_rec) -+ return ENOMEM; -+ -+ memcpy(clone_rec, new_rec, sizeof(*clone_rec)); -+ INIT_LIST_HEAD(&clone_rec->list); -+ iface_copy(&clone_rec->iface, iface); -+ list_add_tail(&clone_rec->list, bound_recs); -+ return 0; -+} -+ -+int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec, -+ struct list_head *ifaces, -+ struct list_head *bound_recs) - { - struct iface_rec *iface, *tmp; - struct iscsi_transport *t; -@@ -2232,25 +2306,78 @@ int idbm_add_nodes(idbm_t *db, node_rec_ - struct list_head def_ifaces; - - INIT_LIST_HEAD(&def_ifaces); -- idbm_lock(db); -- idbm_read_def_ifaces(&def_ifaces); -- idbm_unlock(db); -+ iface_link_ifaces(db, &def_ifaces); - - list_for_each_entry_safe(iface, tmp, &def_ifaces, list) { - list_del(&iface->list); - t = get_transport_by_name(iface->transport_name); -- if (!t) { -+ if (!t || t->caps & CAP_FW_DB) { - free(iface); - continue; - } - -- if (t->caps & CAP_FW_DB) { -+ rc = idbm_bind_iface_to_node(new_rec, iface, -+ bound_recs); -+ free(iface); -+ if (rc) -+ return rc; -+ found = 1; -+ } -+ -+ /* create default iface with old/default behavior */ -+ if (!found) { -+ struct iface_rec def_iface; -+ -+ iface_init(&def_iface); -+ return idbm_bind_iface_to_node(new_rec, &def_iface, -+ bound_recs); -+ } -+ } else { -+ list_for_each_entry(iface, ifaces, list) { -+ if (strcmp(iface->name, DEFAULT_IFACENAME) && -+ !iface_is_bound(iface)) { -+ log_error("iface %s is not bound. Will not " -+ "bind node to it. Iface settings " -+ iface_fmt, iface->name, -+ iface_str(iface)); -+ continue; -+ } -+ -+ rc = idbm_bind_iface_to_node(new_rec, iface, -+ bound_recs); -+ if (rc) -+ return rc; -+ } -+ } -+ return 0; -+} -+ -+/* -+ * remove this when isns is converted -+ */ -+int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, -+ struct list_head *ifaces, int update) -+{ -+ struct iface_rec *iface, *tmp; -+ struct iscsi_transport *t; -+ int rc = 0, found = 0; -+ -+ if (!ifaces || list_empty(ifaces)) { -+ struct list_head def_ifaces; -+ -+ INIT_LIST_HEAD(&def_ifaces); -+ iface_link_ifaces(db, &def_ifaces); -+ -+ list_for_each_entry_safe(iface, tmp, &def_ifaces, list) { -+ list_del(&iface->list); -+ t = get_transport_by_name(iface->transport_name); -+ if (!t || t->caps & CAP_FW_DB) { - free(iface); - continue; - } - - iface_copy(&newrec->iface, iface); -- rc = idbm_add_node(db, newrec, drec); -+ rc = idbm_add_node(db, newrec, drec, update); - free(iface); - if (rc) - return rc; -@@ -2260,7 +2387,7 @@ int idbm_add_nodes(idbm_t *db, node_rec_ - /* create default iface with old/default behavior */ - if (!found) { - iface_init(&newrec->iface); -- return idbm_add_node(db, newrec, drec); -+ return idbm_add_node(db, newrec, drec, update); - } - } else { - list_for_each_entry(iface, ifaces, list) { -@@ -2274,7 +2401,7 @@ int idbm_add_nodes(idbm_t *db, node_rec_ - } - - iface_copy(&newrec->iface, iface); -- rc = idbm_add_node(db, newrec, drec); -+ rc = idbm_add_node(db, newrec, drec, update); - if (rc) - return rc; - } -@@ -2282,13 +2409,6 @@ int idbm_add_nodes(idbm_t *db, node_rec_ - return 0; - } - --void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec) --{ -- idbm_delete_discovery(db, drec); -- if (idbm_add_discovery(db, drec)) -- log_error("can not update discovery record."); --} -- - static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir) - { - char *target = NULL, *tpgt = NULL, *port = NULL; -@@ -2328,7 +2448,7 @@ static void idbm_rm_disc_node_links(idbm - strncpy(rec->conn[0].address, address, NI_MAXHOST); - strncpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN); - -- if (idbm_delete_node(db, NULL, rec)) -+ if (idbm_delete_node(db, rec)) - log_error("Could not delete node %s/%s/%s,%s/%s", - NODE_CONFIG_DIR, target, address, port, - iface_id); -@@ -2438,7 +2558,7 @@ done: - return rc; - } - --int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec) -+int idbm_delete_node(idbm_t *db, node_rec_t *rec) - { - struct stat statb; - char *portal; -@@ -2494,7 +2614,7 @@ rm_conf: - snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR, - rec->name, rec->conn[0].address, rec->conn[0].port, - rec->tpgt); -- n = scandir(portal, &namelist, st_disc_filter, versionsort); -+ n = scandir(portal, &namelist, st_disc_filter, direntcmp); - if (n < 0) - goto free_portal; - if (n == 0) -@@ -2532,8 +2652,7 @@ idbm_slp_defaults(idbm_t *db, struct isc - sizeof(struct iscsi_slp_config)); - } - --int --idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec) -+int idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec) - { - struct db_set_param *param = data; - recinfo_t *info; -@@ -2545,6 +2664,9 @@ idbm_node_set_param(idbm_t *db, void *da - - idbm_recinfo_node(rec, info); - -+ rc = idbm_verify_param(info, param->name); -+ if (rc) -+ goto free_info; - /* - * Another compat hack!!!!: in the future we will have a common - * way to define node wide vs iface wide values and it will -@@ -2553,23 +2675,20 @@ idbm_node_set_param(idbm_t *db, void *da - * we update it for them. - */ - if (!strcmp("node.transport_name", param->name)) -- rc = idbm_node_update_param(info, "iface.transport_name", -+ rc = idbm_rec_update_param(info, "iface.transport_name", - param->value, 0); - else -- rc = idbm_node_update_param(info, param->name, param->value, 0); -- if (rc) { -- free(info); -- return EIO; -- } -+ rc = idbm_rec_update_param(info, param->name, param->value, 0); -+ if (rc) -+ goto free_info; - - rc = idbm_rec_write(param->db, rec); -- if (rc) { -- free(info); -- return rc; -- } -+ if (rc) -+ goto free_info; - -+free_info: - free(info); -- return 0; -+ return rc; - } - - idbm_t* -Only in open-iscsi.git/usr: idbm.c~ -Only in open-iscsi.git/usr: idbm.c.orig -Only in open-iscsi.git/usr: idbm.c.rej -diff -pur open-iscsi-2.0-865/usr/idbm.h open-iscsi.git/usr/idbm.h ---- open-iscsi-2.0-865/usr/idbm.h 2008-03-05 11:43:19.308975500 +0100 -+++ open-iscsi.git/usr/idbm.h 2008-03-05 11:29:21.328605000 +0100 -@@ -50,6 +50,12 @@ typedef struct recinfo { - int visible; - char* opts[OPTS_MAXVAL]; - int numopts; -+ /* -+ * bool indicating if we can change it or not. -+ * TODO: make it a enum that can indicate wheter it also requires -+ * a relogin to pick up if a session is running. -+ */ -+ int can_modify; - } recinfo_t; - - typedef char *(idbm_get_config_file_fn)(void); -@@ -73,7 +79,7 @@ typedef struct idbm { - struct db_set_param { - char *name; - char *value; -- struct idbm *db; -+ struct idbm *db; - }; - - typedef int (idbm_iface_op_fn)(idbm_t *db, void *data, node_rec_t *rec); -@@ -100,6 +106,8 @@ extern idbm_t *idbm_init(idbm_get_config - - extern void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec); - extern void idbm_terminate(idbm_t *db); -+extern int idbm_print_iface_info(idbm_t *db, void *data, -+ struct iface_rec *iface); - extern int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec); - extern int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec); - extern int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec); -@@ -110,13 +118,18 @@ extern int idbm_print_discovered(idbm_t - int info_level); - extern int idbm_delete_discovery(idbm_t *db, discovery_rec_t *rec); - extern void idbm_node_setup_defaults(node_rec_t *rec); --extern int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec); --extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec); -- -+extern int idbm_delete_node(idbm_t *db, node_rec_t *rec); -+extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, -+ int overwrite); - struct list_head; -+extern int idbm_bind_ifaces_to_node(idbm_t *db, struct node_rec *new_rec, -+ struct list_head *ifaces, -+ struct list_head *bound_recs); - extern int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, -- discovery_rec_t *drec, struct list_head *ifaces); --extern void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec); -+ discovery_rec_t *drec, struct list_head *ifaces, -+ int overwrite); -+extern int idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec, -+ int overwrite); - extern void idbm_sendtargets_defaults(idbm_t *db, - struct iscsi_sendtargets_config *cfg); - extern void idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg); -@@ -143,6 +156,7 @@ typedef int (iface_op_fn)(void *data, st - extern int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, - iface_op_fn *fn); - extern int iface_print_flat(void *data, struct iface_rec *iface); -+extern int iface_print_tree(void *data, struct iface_rec *iface); - extern void iface_setup_host_bindings(idbm_t *db); - extern int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern, - struct iface_rec *out_rec); -Only in open-iscsi.git/usr: idbm.o -diff -pur open-iscsi-2.0-865/usr/initiator.c open-iscsi.git/usr/initiator.c ---- open-iscsi-2.0-865/usr/initiator.c 2008-03-05 11:28:54.082902250 +0100 -+++ open-iscsi.git/usr/initiator.c 2008-03-05 11:29:21.376608000 +0100 -@@ -149,7 +149,6 @@ __login_response_status(iscsi_conn_t *co - case LOGIN_REDIRECT: - return CONN_LOGIN_IMM_REDIRECT_RETRY; - case LOGIN_IO_ERROR: -- case LOGIN_WRONG_PORTAL_GROUP: - case LOGIN_REDIRECTION_FAILED: - return CONN_LOGIN_RETRY; - default: -@@ -365,6 +364,11 @@ iscsi_copy_operational_params(iscsi_conn - session->initial_r2t_en = rec->session.iscsi.InitialR2T; - session->imm_data_en = rec->session.iscsi.ImmediateData; - session->first_burst = __padding(rec->session.iscsi.FirstBurstLength); -+ /* -+ * some targets like netapp fail the login if sent bad first_burst -+ * and max_burst lens, even when immediate data=no and -+ * initial r2t = Yes, so we always check the user values. -+ */ - if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN || - session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) { - log_error("Invalid iscsi.FirstBurstLength of %u. Must be " -@@ -388,6 +392,14 @@ iscsi_copy_operational_params(iscsi_conn - session->max_burst = DEF_INI_MAX_BURST_LEN; - } - -+ if (session->first_burst > session->max_burst) { -+ log_error("Invalid iscsi.FirstBurstLength of %u. Must be " -+ "less than iscsi.MaxBurstLength. Setting to %u\n", -+ session->first_burst, session->max_burst); -+ rec->session.iscsi.FirstBurstLength = session->max_burst; -+ session->first_burst = session->max_burst; -+ } -+ - session->def_time2wait = rec->session.iscsi.DefaultTime2Wait; - session->def_time2retain = rec->session.iscsi.DefaultTime2Retain; - session->erl = rec->session.iscsi.ERL; -@@ -590,7 +602,10 @@ session_conn_shutdown(iscsi_conn_t *conn - { - iscsi_session_t *session = conn->session; - -- if (!conn->ksetup) -+ if (session->id == -1) -+ goto disconnect_conn; -+ -+ if (!sysfs_session_has_leadconn(session->id)) - goto disconnect_conn; - - if (conn->state == STATE_IN_LOGIN || -@@ -611,7 +626,6 @@ session_conn_shutdown(iscsi_conn_t *conn - log_error("can not safely destroy connection %d", conn->id); - return MGMT_IPC_ERR_INTERNAL; - } -- conn->ksetup = 0; - - disconnect_conn: - log_debug(2, "disconnect conn"); -@@ -1708,7 +1722,6 @@ static void session_conn_poll(void *data - err = MGMT_IPC_ERR_INTERNAL; - goto cleanup; - } -- conn->ksetup = 1; - log_debug(3, "created new iSCSI connection " - "%d:%d", session->id, conn->id); - } -diff -pur open-iscsi-2.0-865/usr/initiator.h open-iscsi.git/usr/initiator.h ---- open-iscsi-2.0-865/usr/initiator.h 2008-03-05 11:28:54.110904000 +0100 -+++ open-iscsi.git/usr/initiator.h 2008-03-05 11:29:21.404609750 +0100 -@@ -75,10 +75,9 @@ enum iscsi_login_status { - LOGIN_VERSION_MISMATCH = 3, - LOGIN_NEGOTIATION_FAILED = 4, - LOGIN_AUTHENTICATION_FAILED = 5, -- LOGIN_WRONG_PORTAL_GROUP = 6, -- LOGIN_REDIRECTION_FAILED = 7, -- LOGIN_INVALID_PDU = 8, -- LOGIN_REDIRECT = 9, -+ LOGIN_REDIRECTION_FAILED = 6, -+ LOGIN_INVALID_PDU = 7, -+ LOGIN_REDIRECT = 8, - }; - - typedef enum iscsi_event_e { -@@ -117,7 +116,6 @@ struct iscsi_conn_context; - /* daemon's connection structure */ - typedef struct iscsi_conn { - uint32_t id; -- int ksetup; - struct iscsi_session *session; - iscsi_login_context_t login_context; - struct iscsi_conn_context *recv_context; -Only in open-iscsi.git/usr: initiator.o -diff -pur open-iscsi-2.0-865/usr/io.c open-iscsi.git/usr/io.c ---- open-iscsi-2.0-865/usr/io.c 2008-03-05 11:28:54.138905750 +0100 -+++ open-iscsi.git/usr/io.c 2008-03-05 11:29:21.440612000 +0100 -@@ -24,7 +24,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -75,6 +74,8 @@ set_non_blocking(int fd) - - } - -+#if 0 -+/* not used by anyone */ - static int get_hwaddress_from_netdev(char *netdev, char *hwaddress) - { - struct ifaddrs *ifap, *ifa; -@@ -152,6 +153,7 @@ free_ifap: - freeifaddrs(ifap); - return found; - } -+#endif - - /* - * In this mode we do not support interfaces like a bond or alias because -@@ -159,15 +161,14 @@ free_ifap: - */ - static int get_netdev_from_hwaddress(char *hwaddress, char *netdev) - { -- struct ifaddrs *ifap, *ifa; -- struct sockaddr_in *s4; -- struct sockaddr_in6 *s6; -+ struct if_nameindex *ifni; - struct ifreq if_hwaddr; -- int found = 0, sockfd; -+ int found = 0, sockfd, i = 0; - unsigned char *hwaddr; -- char buf[INET6_ADDRSTRLEN], tmp_hwaddress[ISCSI_MAX_IFACE_LEN]; -+ char tmp_hwaddress[ISCSI_MAX_IFACE_LEN]; - -- if (getifaddrs(&ifap)) { -+ ifni = if_nameindex(); -+ if (ifni == NULL) { - log_error("Could not match hwaddress %s to netdev. " - "getifaddrs failed %d", hwaddress, errno); - return 0; -@@ -177,34 +178,13 @@ static int get_netdev_from_hwaddress(cha - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) { - log_error("Could not open socket for ioctl."); -- goto free_ifap; -+ goto free_ifni; - } - -- for (ifa = ifap; ifa; ifa = ifa->ifa_next) { -- if (!ifa->ifa_addr) -- continue; -- -- switch (ifa->ifa_addr->sa_family) { -- case AF_INET: -- s4 = (struct sockaddr_in *)(ifa->ifa_addr); -- if (!inet_ntop(ifa->ifa_addr->sa_family, -- (void *)&(s4->sin_addr), buf, -- INET_ADDRSTRLEN)) -- continue; -- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); -- break; -- case AF_INET6: -- s6 = (struct sockaddr_in6 *)(ifa->ifa_addr); -- if (!inet_ntop(ifa->ifa_addr->sa_family, -- (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN)) -- continue; -- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); -- break; -- default: -- continue; -- } -+ for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) { -+ struct if_nameindex *n = &ifni[i]; - -- strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ); -+ strncpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ); - if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) { - log_error("Could not match %s to netdevice.", - hwaddress); -@@ -224,17 +204,17 @@ static int get_netdev_from_hwaddress(cha - log_debug(4, "Found hardware address %s", tmp_hwaddress); - if (!strcasecmp(tmp_hwaddress, hwaddress)) { - log_debug(4, "Matches %s to %s", hwaddress, -- ifa->ifa_name); -+ n->if_name); - memset(netdev, 0, IFNAMSIZ); -- strncpy(netdev, ifa->ifa_name, IFNAMSIZ); -+ strncpy(netdev, n->if_name, IFNAMSIZ); - found = 1; - break; - } - } - - close(sockfd); --free_ifap: -- freeifaddrs(ifap); -+free_ifni: -+ if_freenameindex(ifni); - return found; - } - -Only in open-iscsi.git/usr: io.o -Only in open-iscsi.git/usr: iscsiadm -diff -pur open-iscsi-2.0-865/usr/iscsiadm.c open-iscsi.git/usr/iscsiadm.c ---- open-iscsi-2.0-865/usr/iscsiadm.c 2008-03-05 11:43:19.340977500 +0100 -+++ open-iscsi.git/usr/iscsiadm.c 2008-03-05 11:29:21.504616000 +0100 -@@ -55,10 +55,11 @@ enum iscsiadm_mode { - }; - - enum iscsiadm_op { -- OP_NEW, -- OP_DELETE, -- OP_UPDATE, -- OP_SHOW, -+ OP_NOOP = 0x0, -+ OP_NEW = 0x1, -+ OP_DELETE = 0x2, -+ OP_UPDATE = 0x4, -+ OP_SHOW = 0x8, - }; - - static struct option const long_options[] = -@@ -101,6 +102,7 @@ iscsiadm -m node [ -hV ] [ -d debug_leve - [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ - iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ - iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ -+iscsiadm -m fw [ -l ]\n\ - iscsiadm -k priority\n"); - } - exit(status == 0 ? 0 : -1); -@@ -120,7 +122,7 @@ str_to_op(char *str) - else if (!strcmp("show", str)) - op = OP_SHOW; - else -- op = -1; -+ op = OP_NOOP; - - return op; - } -@@ -197,21 +199,31 @@ static void kill_iscsid(int priority) - } - - /* -- * TODO: when we get more time we can make add what sessions -- * are connected to the host. For now you can see this in session -- * mode although with -P 3, althought it is not nicely structured -- * like how you would want -+ * TODO: we can display how the ifaces are related to node records. -+ * And we can add a scsi_host mode which would display how -+ * sessions are related to hosts -+ * (scsi_host and iscsi_sessions are the currently running instance of -+ * a iface or node record). - */ - static int print_ifaces(idbm_t *db, int info_level) - { - int err, num_found = 0; - -- if (info_level > 0) { -- log_error("Invalid info level %d. Try 0.", info_level); -+ switch (info_level) { -+ case 0: -+ case -1: -+ err = iface_for_each_iface(db, NULL, &num_found, -+ iface_print_flat); -+ break; -+ case 1: -+ err = iface_for_each_iface(db, NULL, &num_found, -+ iface_print_tree); -+ break; -+ default: -+ log_error("Invalid info level %d. Try 0 or 1.", info_level); - return EINVAL; - } - -- err = iface_for_each_iface(db, NULL, &num_found, iface_print_flat); - if (!num_found) { - log_error("No interfaces found."); - err = ENODEV; -@@ -356,11 +368,20 @@ for_each_session(struct node_rec *rec, s - return err; - } - -+struct session_link_info { -+ struct list_head *list; -+ struct session_info *match_info; -+}; -+ - static int link_sessions(void *data, struct session_info *info) - { -- struct list_head *list = data; -+ struct session_link_info *link_info = data; -+ struct list_head *list = link_info->list; - struct session_info *new, *curr, *match = NULL; - -+ if (link_info->match_info && link_info->match_info->sid != info->sid) -+ return 0; -+ - new = calloc(1, sizeof(*new)); - if (!new) - return ENOMEM; -@@ -461,14 +482,19 @@ __logout_portals(idbm_t *db, void *data, - struct session_info *)) - { - struct session_info *curr_info, *tmp; -+ struct session_link_info link_info; - struct list_head session_list, logout_list; - int ret = 0, err; - - INIT_LIST_HEAD(&session_list); - INIT_LIST_HEAD(&logout_list); -+ -+ memset(&link_info, 0, sizeof(link_info)); -+ link_info.list = &session_list; -+ link_info.match_info = NULL; - *nr_found = 0; - -- err = sysfs_for_each_session(&session_list, nr_found, -+ err = sysfs_for_each_session(&link_info, nr_found, - link_sessions); - if (err || !*nr_found) - return err; -@@ -877,8 +903,12 @@ static char *get_config_file(void) - - static int print_session_flat(void *data, struct session_info *info) - { -+ struct session_info *match_info = data; - struct iscsi_transport *t = get_transport_by_sid(info->sid); - -+ if (match_info && match_info->sid != info->sid) -+ return 0; -+ - if (strchr(info->persistent_address, '.')) - printf("%s: [%d] %s:%d,%d %s\n", - t ? t->name : UNKNOWN_VALUE, -@@ -896,7 +926,9 @@ static int print_iscsi_state(int sid) - { - iscsiadm_req_t req; - iscsiadm_rsp_t rsp; -+ int err; - char *state = NULL; -+ char state_buff[SCSI_MAX_STATE_VALUE]; - static char *conn_state[] = { - "FREE", - "TRANSPORT WAIT", -@@ -917,23 +949,24 @@ static int print_iscsi_state(int sid) - req.command = MGMT_IPC_SESSION_INFO; - req.u.session.sid = sid; - -- if (do_iscsid(&req, &rsp)) { -- printf("\t\tiSCSI Connection State: Unknown\n"); -- printf("\t\tInternal iscsid Session State: Unknown\n"); -- return ENODEV; -- } -- -+ err = do_iscsid(&req, &rsp); - /* - * for drivers like qla4xxx, iscsid does not display - * anything here since it does not know about it. - */ -- if (rsp.u.session_state.conn_state >= 0 && -+ if (!err && rsp.u.session_state.conn_state >= 0 && - rsp.u.session_state.conn_state <= STATE_CLEANUP_WAIT) - state = conn_state[rsp.u.session_state.conn_state]; - printf("\t\tiSCSI Connection State: %s\n", state ? state : "Unknown"); - state = NULL; - -- if (rsp.u.session_state.session_state >= 0 && -+ memset(state_buff, 0, SCSI_MAX_STATE_VALUE); -+ if (!get_session_state(state_buff, sid)) -+ printf("\t\tiSCSI Session State: %s\n", state_buff); -+ else -+ printf("\t\tiSCSI Session State: Unknown\n"); -+ -+ if (!err && rsp.u.session_state.session_state >= 0 && - rsp.u.session_state.session_state <= R_STAGE_SESSION_REDIRECT) - state = session_state[rsp.u.session_state.session_state]; - printf("\t\tInternal iscsid Session State: %s\n", -@@ -1096,37 +1129,8 @@ next: - } - } - --static int print_session(idbm_t *db, int info_level, struct session_info *info) --{ -- struct list_head list; -- int err; -- -- switch (info_level) { -- case 0: -- case -1: -- err = print_session_flat(NULL, info); -- break; -- case 1: -- case 2: -- case 3: -- INIT_LIST_HEAD(&list); -- -- err = link_sessions(&list, info); -- if (err) -- break; -- print_sessions_tree(db, &list, info_level); -- break; -- default: -- log_error("Invalid info level %d. Try 0 - 3.", info_level); -- return EINVAL; -- } -- -- if (err) -- log_error("Can not get session info (%d)", err); -- return 0; --} -- --static int print_sessions(idbm_t *db, int info_level) -+static int print_sessions(idbm_t *db, int info_level, -+ struct session_info *match_info) - { - struct list_head list; - int num_found = 0, err = 0; -@@ -1135,7 +1139,7 @@ static int print_sessions(idbm_t *db, in - switch (info_level) { - case 0: - case -1: -- err = sysfs_for_each_session(NULL, &num_found, -+ err = sysfs_for_each_session(match_info, &num_found, - print_session_flat); - break; - case 2: -@@ -1149,8 +1153,13 @@ static int print_sessions(idbm_t *db, in - /* fall through */ - case 1: - INIT_LIST_HEAD(&list); -+ struct session_link_info link_info; -+ -+ memset(&link_info, 0, sizeof(link_info)); -+ link_info.list = &list; -+ link_info.match_info = match_info; - -- err = sysfs_for_each_session(&list, &num_found, -+ err = sysfs_for_each_session(&link_info, &num_found, - link_sessions); - if (err || !num_found) - break; -@@ -1317,7 +1326,7 @@ static int add_static_rec(idbm_t *db, in - iface_copy(&rec->iface, iface); - } - -- rc = idbm_add_node(db, rec, drec); -+ rc = idbm_add_node(db, rec, drec, 1); - if (!rc) { - (*found)++; - printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n", -@@ -1427,35 +1436,201 @@ static int login_discovered_portal(void - return 0; - } - -+/* TODO merge with initiator.c implementation */ -+/* And add locking */ -+static int check_for_session_through_iface(struct node_rec *rec) -+{ -+ int nr_found = 0; -+ if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) -+ return 1; -+ return 0; -+} -+ -+static int delete_node(struct idbm *db, void *data, struct node_rec *rec) -+{ -+ if (check_for_session_through_iface(rec)) { -+ /* -+ * perf is not important in this path, so do not worry -+ * about doing a async logout -+ */ -+ log_warning("Found running session using record. Logging " -+ "out session [iface: %s, target: %s, " -+ "portal: %s,%d] before deleting record.", -+ rec->iface.name, rec->name, -+ rec->conn[0].address, rec->conn[0].port); -+ switch (iscsid_req(MGMT_IPC_SESSION_LOGOUT, rec)) { -+ case MGMT_IPC_ERR_NOT_FOUND: -+ case MGMT_IPC_OK: -+ break; -+ default: -+ log_error("Could not remove record, because there " -+ "is a session to the portal that cannot " -+ "stopped. Please log out session: " -+ "[iface: %s, target: %s, portal: %s,%d]" -+ "and then remove record.", -+ rec->iface.name, rec->name, -+ rec->conn[0].address, rec->conn[0].port); -+ return EINVAL; -+ } -+ } -+ return idbm_delete_node(db, rec); -+} -+ -+static int delete_stale_recs(struct idbm *db, void *data, struct node_rec *rec) -+{ -+ struct list_head *new_rec_list = data; -+ struct node_rec *new_rec; -+ -+ list_for_each_entry(new_rec, new_rec_list, list) { -+ /* -+ * We could also move this to idbm.c and instead of looping -+ * over every node just loop over disc to node links. -+ */ -+ if (rec->disc_type != new_rec->disc_type || -+ rec->disc_port != new_rec->disc_port || -+ strcmp(rec->disc_address, new_rec->disc_address)) -+ /* -+ * if we are not from the same discovery source -+ * ignore it -+ */ -+ return 0; -+ -+ /* -+ * we only care if the target endpoint matches, because -+ * it is gone and we want to logout all sessions with -+ * that endpoint, so we pass in null for the iface. -+ */ -+ if (__iscsi_match_session(rec, -+ new_rec->name, -+ new_rec->conn[0].address, -+ new_rec->conn[0].port, -+ &new_rec->iface)) -+ return 0; -+ } -+ /* if there is a error we can continue on */ -+ delete_node(db, NULL, rec); -+ return 0; -+} -+ -+static int -+update_discovery_recs(idbm_t *db, discovery_rec_t *drec, -+ struct list_head *new_rec_list, struct list_head *ifaces, -+ int info_level, int do_login, int op) -+{ -+ int rc, err, found = 0; -+ struct list_head bound_rec_list; -+ struct node_rec *new_rec, *tmp; -+ -+ INIT_LIST_HEAD(&bound_rec_list); -+ -+ /* bind ifaces to node recs so we know what we have */ -+ list_for_each_entry(new_rec, new_rec_list, list) { -+ rc = idbm_bind_ifaces_to_node(db, new_rec, ifaces, -+ &bound_rec_list); -+ if (rc) -+ goto free_bound_recs; -+ } -+ -+ -+ /* clean up node db */ -+ if (op & OP_DELETE) -+ idbm_for_each_rec(db, &found, &bound_rec_list, -+ delete_stale_recs); -+ -+ if (op & OP_NEW || op & OP_UPDATE) { -+ /* now add/update records */ -+ list_for_each_entry(new_rec, &bound_rec_list, list) { -+ int update = op & OP_UPDATE; -+ -+ if (update && -+ check_for_session_through_iface(new_rec)) { -+ log_warning("Could not update record for " -+ "[iface: %s, target: %s, portal: " -+ "%s,%d], because session is " -+ "logged in. Log out session " -+ "then retry operation, or run " -+ "discovery without the 'update' " -+ "option.", -+ new_rec->iface.name, new_rec->name, -+ new_rec->conn[0].address, -+ new_rec->conn[0].port); -+ continue; -+ } -+ -+ rc = idbm_add_node(db, new_rec, drec, update); -+ if (rc) -+ log_error("Could not add/update " -+ "[%s:" iface_fmt " %s,%d,%d %s]", -+ new_rec->iface.transport_name, -+ iface_str(&new_rec->iface), -+ new_rec->conn[0].address, -+ new_rec->conn[0].port, -+ new_rec->tpgt, new_rec->name); -+ } -+ } -+ -+ idbm_print_discovered(db, drec, info_level); -+ -+ if (!do_login) { -+ rc = 0; -+ goto free_bound_recs; -+ } -+ -+ err = __login_portals(drec, &found, &bound_rec_list, -+ login_discovered_portal); -+ if (err && !rc) -+ rc = err; -+ -+free_bound_recs: -+ list_for_each_entry_safe(new_rec, tmp, &bound_rec_list, list) { -+ list_del(&new_rec->list); -+ free(new_rec); -+ } -+ return rc; -+} -+ - static int - do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec, -- struct list_head *ifaces, int info_level, int do_login) -+ struct list_head *ifaces, int info_level, int do_login, -+ int op) - { -- int rc, err, nr_found = 0; -- struct list_head rec_list; -+ struct list_head new_rec_list; -+ struct node_rec *new_rec, *tmp; -+ int rc; -+ -+ INIT_LIST_HEAD(&new_rec_list); -+ /* -+ * compat: if the user did not pass any op then we do all -+ * ops for them -+ */ -+ if (!op) -+ op = OP_NEW | OP_DELETE | OP_UPDATE; - - drec->type = DISCOVERY_TYPE_SENDTARGETS; -- rc = discovery_sendtargets(db, drec, ifaces); -+ rc = discovery_sendtargets(db, drec, &new_rec_list); - if (rc) - return rc; - -- idbm_print_discovered(db, drec, info_level); -+ rc = idbm_add_discovery(db, drec, op & OP_UPDATE); -+ if (rc) { -+ log_error("Could not add new discovery record."); -+ goto free_new_recs; -+ } - -- if (!do_login) -- return 0; -+ rc = update_discovery_recs(db, drec, &new_rec_list, ifaces, -+ info_level, do_login, op); - -- INIT_LIST_HEAD(&rec_list); -- rc = idbm_for_each_rec(db, &nr_found, &rec_list, link_recs); -- err = __login_portals(drec, &nr_found, &rec_list, -- login_discovered_portal); -- if (err && !rc) -- rc = err; -+free_new_recs: -+ list_for_each_entry_safe(new_rec, tmp, &new_rec_list, list) { -+ list_del(&new_rec->list); -+ free(new_rec); -+ } - return rc; - } - - static int - do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, -- int info_level, int do_login) -+ int info_level, int do_login, int op) - { - struct iface_rec *tmp, *iface; - int rc, host_no; -@@ -1515,7 +1690,8 @@ do_sendtargets(idbm_t *db, discovery_rec - return ENODEV; - - sw_st: -- return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login); -+ return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login, -+ op); - } - - /* TODO: merge this with the idbm code */ -@@ -1534,53 +1710,6 @@ static void print_fw_nodes(struct node_r - } - } - --static int do_fw_discovery(idbm_t *db, discovery_rec_t *drec, int do_login, -- int info_level) --{ -- struct boot_context context; -- struct node_rec *rec; -- int ret; -- -- memset(&context, 0, sizeof(struct boot_context)); -- ret = fw_get_entry(&context, NULL); -- if (ret) { -- log_error("Could not read fw values."); -- return ret; -- } -- /* tpgt hard coded to 1 */ -- rec = create_node_record(db, context.targetname, 1, -- context.target_ipaddr, context.target_port, -- NULL, 1); -- if (!rec) { -- log_error("Could not setup rec for fw discovery login."); -- return ENOMEM; -- } -- -- /* todo - grab mac and set that here */ -- iface_init(&rec->iface); -- strncpy(rec->iface.iname, context.initiatorname, -- sizeof(context.initiatorname)); -- strncpy(rec->session.auth.username, context.chap_name, -- sizeof(context.chap_name)); -- strncpy((char *)rec->session.auth.password, context.chap_password, -- sizeof(context.chap_password)); -- strncpy(rec->session.auth.username_in, context.chap_name_in, -- sizeof(context.chap_name_in)); -- strncpy((char *)rec->session.auth.password_in, context.chap_password_in, -- sizeof(context.chap_password_in)); -- rec->session.auth.password_length = -- strlen((char *)context.chap_password); -- rec->session.auth.password_in_length = -- strlen((char *)context.chap_password_in); -- -- print_fw_nodes(rec, info_level); -- if (do_login) -- ret = login_portal(db, NULL, rec); -- free(rec); -- return ret; --} -- -- - static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec, - int info_level) - { -@@ -1627,16 +1756,7 @@ static void catch_sigint( int signo ) { - exit(1); - } - --/* TODO merge with initiator.c implementation */ --/* And add locking */ --static int check_for_session_through_iface(struct node_rec *rec) --{ -- int nr_found = 0; -- if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) -- return 1; -- return 0; --} -- -+/* TODO: merge iter helpers and clean them up, so we can use them here */ - static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, - struct iface_rec *iface, char *name, char *value) - { -@@ -1684,13 +1804,8 @@ new_fail: - } - - if (iface_is_bound(&rec->iface)) { -- if (check_for_session_through_iface(rec)) { -- rc = EBUSY; -- goto delete_fail; -- } -- -- /* delete node records using it first */ -- rc = __for_each_rec(db, 0, rec, NULL, idbm_delete_node); -+ /* logout and delete records using it first */ -+ rc = __for_each_rec(db, 0, rec, NULL, delete_node); - if (rc && rc != ENODEV) - goto delete_fail; - } -@@ -1775,10 +1890,19 @@ update_fail: - iface->name); - break; - default: -- if (op < 0 || op == OP_SHOW) -- rc = print_ifaces(db, info_level); -- else -- rc = EINVAL; -+ if (!iface) { -+ if (op == OP_NOOP || op == OP_SHOW) -+ rc = print_ifaces(db, info_level); -+ else -+ rc = EINVAL; -+ } else { -+ rc = iface_conf_read(db, iface); -+ if (!rc) -+ idbm_print_iface_info(db, &do_show, iface); -+ else -+ log_error("Could not read iface %s (%d).", -+ iface->name, rc); -+ } - } - - if (rec) -@@ -1824,14 +1948,14 @@ static int exec_node_op(idbm_t *db, int - goto out; - } - -- if ((do_login || do_logout) && op >= 0) { -+ if ((do_login || do_logout) && op > OP_NOOP) { - log_error("either operation or login/logout " - "at the time allowed!"); - rc = -1; - goto out; - } - -- if ((!do_login && !do_logout && op < 0) && -+ if ((!do_login && !do_logout && op == OP_NOOP) && - (!strlen(rec->name) && !strlen(rec->conn[0].address) && - !strlen(rec->iface.name))) { - rc = print_nodes(db, info_level, rec); -@@ -1850,7 +1974,7 @@ static int exec_node_op(idbm_t *db, int - goto out; - } - -- if (op < 0 || (!do_login && !do_logout && op == OP_SHOW)) { -+ if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) { - if (for_each_rec(db, rec, &do_show, idbm_print_node_info)) - rc = -1; - goto out; -@@ -1863,6 +1987,22 @@ static int exec_node_op(idbm_t *db, int - goto out; - } - -+ /* -+ * We do not export the iscsiadm iface.iscsi_ifacename -+ * in sysfs because it is iscsiadm specific abstraction. -+ * To work around this, we do some hacky matching by bind -+ * info. As a result we cannot change the iface binding -+ * values here and must do it in iface mode which will do -+ * the right thing. -+ */ -+ if (!strncmp(name, "iface.", 6) && -+ strcmp(name, "iface.transport_name")) { -+ log_error("Cannot modify %s. Use iface mode to update " -+ "this value.", name); -+ rc = -1; -+ goto out; -+ } -+ - set_param.db = db; - set_param.name = name; - set_param.value = value; -@@ -1871,7 +2011,7 @@ static int exec_node_op(idbm_t *db, int - rc = -1; - goto out; - } else if (op == OP_DELETE) { -- if (for_each_rec(db, rec, NULL, idbm_delete_node)) -+ if (for_each_rec(db, rec, NULL, delete_node)) - rc = -1; - goto out; - } else { -@@ -1883,10 +2023,46 @@ out: - return rc; - } - --static int exec_fw_op(void) -+static struct node_rec * -+fw_create_rec_by_entry(idbm_t *db, struct boot_context *context) -+{ -+ struct node_rec *rec; -+ -+ /* tpgt hard coded to 1 ??? */ -+ rec = create_node_record(db, context->targetname, 1, -+ context->target_ipaddr, context->target_port, -+ NULL, 1); -+ if (!rec) { -+ log_error("Could not setup rec for fw discovery login."); -+ return NULL; -+ } -+ -+ /* todo - grab mac and set that here */ -+ iface_init(&rec->iface); -+ strncpy(rec->iface.iname, context->initiatorname, -+ sizeof(context->initiatorname)); -+ strncpy(rec->session.auth.username, context->chap_name, -+ sizeof(context->chap_name)); -+ strncpy((char *)rec->session.auth.password, context->chap_password, -+ sizeof(context->chap_password)); -+ strncpy(rec->session.auth.username_in, context->chap_name_in, -+ sizeof(context->chap_name_in)); -+ strncpy((char *)rec->session.auth.password_in, -+ context->chap_password_in, -+ sizeof(context->chap_password_in)); -+ rec->session.auth.password_length = -+ strlen((char *)context->chap_password); -+ rec->session.auth.password_in_length = -+ strlen((char *)context->chap_password_in); -+ return rec; -+} -+ -+static int exec_fw_op(idbm_t *db, discovery_rec_t *drec, int do_login, -+ int info_level) - { - struct boot_context context; -- int ret; -+ struct node_rec *rec; -+ int ret = 0; - - memset(&context, 0, sizeof(struct boot_context)); - ret = fw_get_entry(&context, NULL); -@@ -1895,8 +2071,22 @@ static int exec_fw_op(void) - return ret; - } - -- fw_print_entry(&context); -- return 0; -+ rec = fw_create_rec_by_entry(db, &context); -+ if (!rec) -+ return ENODEV; -+ -+ /* if discovery, print nodes that were found. */ -+ if (drec) -+ print_fw_nodes(rec, info_level); -+ -+ if (do_login) -+ ret = login_portal(db, NULL, rec); -+ free(rec); -+ -+ /* print the fw node info if called in fw mode with no params */ -+ if (!do_login && !drec) -+ fw_print_entry(&context); -+ return ret; - } - - static int parse_sid(char *session) -@@ -1955,9 +2145,9 @@ main(int argc, char **argv) - char *ip = NULL, *name = NULL, *value = NULL; - char *targetname = NULL, *group_session_mgmt_mode = NULL; - int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0; -- int rc=0, sid=-1, op=-1, type=-1, do_logout=0, do_stats=0, do_show=0; -+ int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0; - int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0; -- int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1; -+ int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0; - idbm_t *db = NULL; - struct sigaction sa_old; - struct sigaction sa_new; -@@ -1999,8 +2189,8 @@ main(int argc, char **argv) - type = str_to_type(optarg); - break; - case 'o': -- op = str_to_op(optarg); -- if (op < 0) { -+ op |= str_to_op(optarg); -+ if (op == OP_NOOP) { - log_error("can not recognize operation: '%s'", - optarg); - return -1; -@@ -2098,14 +2288,14 @@ main(int argc, char **argv) - usage(0); - - if (mode == MODE_FW) { -- if ((rc = verify_mode_params(argc, argv, "m", 0))) { -+ if ((rc = verify_mode_params(argc, argv, "ml", 0))) { - log_error("fw mode: option '-%c' is not " - "allowed/supported", rc); - rc = -1; - goto out; - } - -- rc = exec_fw_op(); -+ rc = exec_fw_op(db, NULL, do_login, info_level); - goto out; - } - -@@ -2160,7 +2350,7 @@ main(int argc, char **argv) - drec.port = port; - - if (do_sendtargets(db, &drec, &ifaces, info_level, -- do_login)) { -+ do_login, op)) { - rc = -1; - goto out; - } -@@ -2178,7 +2368,7 @@ main(int argc, char **argv) - break; - case DISCOVERY_TYPE_FWBOOT: - drec.type = DISCOVERY_TYPE_FWBOOT; -- if (do_fw_discovery(db, &drec, do_login, info_level)) -+ if (exec_fw_op(db, &drec, do_login, info_level)) - rc = -1; - break; - default: -@@ -2192,7 +2382,8 @@ main(int argc, char **argv) - if (do_login && - drec.type == DISCOVERY_TYPE_SENDTARGETS) { - do_sendtargets(db, &drec, &ifaces, -- info_level, do_login); -+ info_level, do_login, -+ op); - } else if (do_login && - drec.type == DISCOVERY_TYPE_SLP) { - log_error("SLP discovery is not fully " -@@ -2205,7 +2396,7 @@ main(int argc, char **argv) - "implemented yet."); - rc = -1; - goto out; -- } else if (op < 0 || op == OP_SHOW) { -+ } else if (op == OP_NOOP || op == OP_SHOW) { - if (!idbm_print_discovery_info(db, - &drec, do_show)) { - log_error("no records found!"); -@@ -2223,7 +2414,7 @@ main(int argc, char **argv) - goto out; - } - -- } else if (op < 0 || op == OP_SHOW) { -+ } else if (op == OP_NOOP || op == OP_SHOW) { - if (!idbm_print_all_discovery(db, info_level)) - rc = -1; - goto out; -@@ -2315,9 +2506,9 @@ main(int argc, char **argv) - if (!t) - goto free_info; - -- if (!do_logout && !do_rescan && !do_stats && op < 0 && -- info_level > 0) { -- rc = print_session(db, info_level, info); -+ if (!do_logout && !do_rescan && !do_stats && -+ op == OP_NOOP && info_level > 0) { -+ rc = print_sessions(db, info_level, info); - if (rc) - rc = -1; - goto free_info; -@@ -2348,7 +2539,7 @@ free_info: - goto out; - } - -- rc = print_sessions(db, info_level); -+ rc = print_sessions(db, info_level, NULL); - } - break; - default: -Only in open-iscsi.git/usr: iscsiadm.c~ -diff -pur open-iscsi-2.0-865/usr/iscsiadm.h open-iscsi.git/usr/iscsiadm.h ---- open-iscsi-2.0-865/usr/iscsiadm.h 2008-03-05 11:43:19.352978250 +0100 -+++ open-iscsi.git/usr/iscsiadm.h 2008-03-05 11:29:21.536618000 +0100 -@@ -29,7 +29,7 @@ struct discovery_rec; - struct list_head; - - extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec, -- struct list_head *ifaces); -+ struct list_head *rec_list); - extern int discovery_offload_sendtargets(struct idbm *db, int host_no, - int do_login, discovery_rec_t *drec); - #endif /* ISCSIADM_H */ -Only in open-iscsi.git/usr: iscsiadm.o -Only in open-iscsi.git/usr: iscsid -diff -pur open-iscsi-2.0-865/usr/iscsid.c open-iscsi.git/usr/iscsid.c ---- open-iscsi-2.0-865/usr/iscsid.c 2008-03-05 11:28:54.310916500 +0100 -+++ open-iscsi.git/usr/iscsid.c 2008-02-06 08:24:29.404852500 +0100 -@@ -369,7 +369,10 @@ int main(int argc, char *argv[]) - log_pid = log_init(program_name, DEFAULT_AREA_SIZE); - if (log_pid < 0) - exit(1); -- check_class_version(); -+ if (check_class_version()) { -+ log_close(log_pid); -+ exit(1); -+ } - - umask(0177); - -@@ -379,11 +382,14 @@ int main(int argc, char *argv[]) - daemon_config.initiator_alias = NULL; - if (atexit(iscsid_exit)) { - log_error("failed to set exit function\n"); -+ log_close(log_pid); - exit(1); - } - -- if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) -+ if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) { -+ log_close(log_pid); - exit(-1); -+ } - - if (log_daemon) { - char buf[64]; -@@ -392,23 +398,28 @@ int main(int argc, char *argv[]) - fd = open(pid_file, O_WRONLY|O_CREAT, 0644); - if (fd < 0) { - log_error("Unable to create pid file"); -+ log_close(log_pid); - exit(1); - } - pid = fork(); - if (pid < 0) { - log_error("Starting daemon failed"); -+ log_close(log_pid); - exit(1); - } else if (pid) { - log_error("iSCSI daemon with pid=%d started!", pid); - exit(0); - } - -- if ((control_fd = ipc->ctldev_open()) < 0) -+ if ((control_fd = ipc->ctldev_open()) < 0) { -+ log_close(log_pid); - exit(-1); -+ } - - chdir("/"); - if (lockf(fd, F_TLOCK, 0) < 0) { - log_error("Unable to lock pid file"); -+ log_close(log_pid); - exit(1); - } - ftruncate(fd, 0); -@@ -417,8 +428,10 @@ int main(int argc, char *argv[]) - - daemon_init(); - } else { -- if ((control_fd = ipc->ctldev_open()) < 0) -+ if ((control_fd = ipc->ctldev_open()) < 0) { -+ log_close(log_pid); - exit(-1); -+ } - } - - if (uid && setuid(uid) < 0) -@@ -468,6 +481,7 @@ int main(int argc, char *argv[]) - /* we don't want our active sessions to be paged out... */ - if (mlockall(MCL_CURRENT | MCL_FUTURE)) { - log_error("failed to mlockall, exiting..."); -+ log_close(log_pid); - exit(1); - } - -Only in open-iscsi.git/usr: iscsid.o -diff -pur open-iscsi-2.0-865/usr/iscsi_settings.h open-iscsi.git/usr/iscsi_settings.h ---- open-iscsi-2.0-865/usr/iscsi_settings.h 2008-03-05 11:28:54.190909000 +0100 -+++ open-iscsi.git/usr/iscsi_settings.h 2008-02-06 08:24:29.228841500 +0100 -@@ -5,8 +5,8 @@ - /* timeouts in seconds */ - #define DEF_LOGIN_TIMEO 30 - #define DEF_LOGOUT_TIMEO 15 --#define DEF_NOOP_OUT_INTERVAL 10 --#define DEF_NOOP_OUT_TIMEO 15 -+#define DEF_NOOP_OUT_INTERVAL 5 -+#define DEF_NOOP_OUT_TIMEO 5 - #define DEF_REPLACEMENT_TIMEO 120 - - #define DEF_ABORT_TIMEO 15 -Only in open-iscsi.git/usr: iscsistart -diff -pur open-iscsi-2.0-865/usr/iscsistart.c open-iscsi.git/usr/iscsistart.c ---- open-iscsi-2.0-865/usr/iscsistart.c 2008-03-05 11:28:54.354919250 +0100 -+++ open-iscsi.git/usr/iscsistart.c 2008-02-06 08:24:29.420853500 +0100 -@@ -305,7 +305,9 @@ int main(int argc, char *argv[]) - log_daemon = 0; - log_init(program_name, DEFAULT_AREA_SIZE); - -- check_class_version(); -+ if (check_class_version()) -+ exit(1); -+ - if (check_params(initiatorname)) - exit(1); - -Only in open-iscsi.git/usr: iscsistart.o -diff -pur open-iscsi-2.0-865/usr/iscsi_sysfs.c open-iscsi.git/usr/iscsi_sysfs.c ---- open-iscsi-2.0-865/usr/iscsi_sysfs.c 2008-03-05 11:28:54.222911000 +0100 -+++ open-iscsi.git/usr/iscsi_sysfs.c 2008-03-05 11:29:21.464613500 +0100 -@@ -38,11 +38,41 @@ - - #define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST - -+/* -+ * TODO: make this into a real API and check inputs better and add doc. -+ * We should also use a common lib and search sysfs according to the sysfs -+ * doc in the kernel documetnation. -+ */ -+ - /* tmp buffer used by sysfs functions */ - static char sysfs_file[PATH_MAX]; - int num_transports = 0; - LIST_HEAD(transports); - -+/* mini implementation of versionsort for uclibc compatility */ -+int direntcmp(const void *d1, const void *d2) -+{ -+ const char *a = (*(const struct dirent **)d1)->d_name; -+ const char *b = (*(const struct dirent **)d2)->d_name; -+ while (*a && *b) { -+ int mask = (isdigit(*a) != 0) | ((isdigit(*b) != 0) << 1); -+ switch (mask) { -+ case 0: /* none are digit */ -+ if (*a == *b) -+ break; -+ return (*a - *b); -+ case 1: /* a is digit but not b */ -+ return -1; -+ case 2: /* b is digit but not a */ -+ return 1; -+ case 3: /* both ar digits */ -+ return atoi(a) - atoi(b); -+ } -+ a++; b++; -+ } -+ return *a - *b; -+} -+ - int read_sysfs_file(char *filename, void *value, char *format) - { - FILE *file; -@@ -91,7 +121,7 @@ static int read_transports(void) - log_debug(7, "in %s", __FUNCTION__); - - n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter, -- versionsort); -+ direntcmp); - if (n < 0) { - log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR); - return n; -@@ -373,7 +403,7 @@ int sysfs_for_each_host(void *data, int - return ENOMEM; - - n = scandir(ISCSI_HOST_DIR, &namelist, trans_filter, -- versionsort); -+ direntcmp); - if (n <= 0) - goto free_info; - -@@ -439,6 +469,24 @@ free_info: - return rc; - } - -+/** -+ * sysfs_session_has_leadconn - checks if session has lead conn in kernel -+ * @sid: session id -+ * -+ * return 1 if session has lead conn and 0 if not. -+ */ -+int sysfs_session_has_leadconn(uint32_t sid) -+{ -+ struct stat statb; -+ -+ memset(sysfs_file, 0, PATH_MAX); -+ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%u:0", sid); -+ if (!stat(sysfs_file, &statb)) -+ return 1; -+ else -+ return 0; -+} -+ - int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session) - { - int ret, pers_failed = 0; -@@ -598,7 +646,7 @@ int sysfs_for_each_session(void *data, i - - sprintf(sysfs_file, ISCSI_SESSION_DIR); - n = scandir(sysfs_file, &namelist, trans_filter, -- versionsort); -+ direntcmp); - if (n <= 0) - goto free_info; - -@@ -629,6 +677,13 @@ free_info: - return rc; - } - -+int get_session_state(char *state, int sid) -+{ -+ memset(sysfs_file, 0, PATH_MAX); -+ sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/state", sid); -+ return read_sysfs_file(sysfs_file, state, "%s\n"); -+} -+ - int get_host_state(char *state, int host_no) - { - memset(sysfs_file, 0, PATH_MAX); -@@ -798,7 +853,7 @@ int sysfs_for_each_device(int host_no, u - sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/device/target%d:0:%d", - sid, host_no, target); - n = scandir(sysfs_file, &namelist, trans_filter, -- versionsort); -+ direntcmp); - if (n <= 0) - return 0; - -@@ -917,7 +972,7 @@ int get_iscsi_kernel_version(char *buf) - return 0; - } - --void check_class_version(void) -+int check_class_version(void) - { - char version[20]; - int i; -@@ -943,12 +998,12 @@ void check_class_version(void) - if (!strncmp(version, ISCSI_VERSION_STR, i) || - /* support 2.6.18 */ - !strncmp(version, "1.1", 3)) -- return; -+ return 0; - - fail: - log_error( "Missing or Invalid version from %s. Make sure a up " - "to date scsi_transport_iscsi module is loaded and a up to" - "date version of iscsid is running. Exiting...", - ISCSI_VERSION_FILE); -- exit(1); -+ return -1; - } -diff -pur open-iscsi-2.0-865/usr/iscsi_sysfs.h open-iscsi.git/usr/iscsi_sysfs.h ---- open-iscsi-2.0-865/usr/iscsi_sysfs.h 2008-03-05 11:28:54.242912250 +0100 -+++ open-iscsi.git/usr/iscsi_sysfs.h 2008-03-05 11:29:21.484614750 +0100 -@@ -48,11 +48,13 @@ struct host_info { - int host_no; - }; - -+extern int direntcmp(const void *d1, const void *d2); - extern void free_transports(void); - extern int get_iscsi_kernel_version(char *buf); --extern void check_class_version(void); -+extern int check_class_version(void); - extern int get_sessioninfo_by_sysfs_id(struct session_info *info, - char *sys_session); -+extern int sysfs_session_has_leadconn(uint32_t sid); - - typedef int (sysfs_session_op_fn)(void *, struct session_info *); - typedef int (sysfs_host_op_fn)(void *, struct host_info *); -@@ -76,6 +78,7 @@ extern void get_negotiated_session_conf( - extern void get_negotiated_conn_conf(int sid, - struct iscsi_conn_operational_config *conf); - extern pid_t scan_host(int hostno, int async); -+extern int get_session_state(char *state, int sid); - extern int get_host_state(char *state, int host_no); - extern int get_device_state(char *state, int host_no, int target, int lun); - extern void set_device_online(int hostno, int target, int lun); -Only in open-iscsi.git/usr: iscsi_sysfs.o -diff -pur open-iscsi-2.0-865/usr/isns.c open-iscsi.git/usr/isns.c ---- open-iscsi-2.0-865/usr/isns.c 2008-03-05 11:43:19.384980250 +0100 -+++ open-iscsi.git/usr/isns.c 2008-03-05 11:29:21.556619250 +0100 -@@ -286,7 +286,10 @@ static void add_new_target_node(char *ta - char dst[INET6_ADDRSTRLEN]; - - memset(dst, 0, sizeof(dst)); -- if (!memcmp(ip, dst, 10) && ip[10] == 0xff && ip[11] == 0xff) -+ /* -+ * some servers are sending compat instead of mapped -+ */ -+ if (IN6_IS_ADDR_V4MAPPED(ip) || IN6_IS_ADDR_V4COMPAT(ip)) - inet_ntop(AF_INET, ip + 12, dst, sizeof(dst)); - else - inet_ntop(AF_INET6, ip, dst, sizeof(dst)); -@@ -309,7 +312,7 @@ static void add_new_target_node(char *ta - /* TODO?: shoudl we set the address and port of the server ? */ - memset(&drec, 0, sizeof(discovery_rec_t)); - drec.type = DISCOVERY_TYPE_ISNS; -- err = idbm_add_nodes(db, &rec, &drec, NULL); -+ err = idbm_add_nodes(db, &rec, &drec, NULL, 0); - if (err) - log_error("Could not add new target node:%s %s,%d", - targetname, dst, port); -diff -pur open-iscsi-2.0-865/usr/list.h open-iscsi.git/usr/list.h ---- open-iscsi-2.0-865/usr/list.h 2008-03-05 11:28:54.406922500 +0100 -+++ open-iscsi.git/usr/list.h 2008-03-05 11:29:21.572620250 +0100 -@@ -1,6 +1,7 @@ - #ifndef __LIST_H__ - #define __LIST_H__ - -+#include - /* taken from linux kernel */ - - #undef offsetof -diff -pur open-iscsi-2.0-865/usr/login.c open-iscsi.git/usr/login.c ---- open-iscsi-2.0-865/usr/login.c 2008-03-05 11:28:54.458925750 +0100 -+++ open-iscsi.git/usr/login.c 2008-03-05 11:29:21.616623000 +0100 -@@ -264,24 +264,20 @@ get_security_text_keys(iscsi_session_t * - &value, &value_end)) { - /* - * We should have already obtained this -- * via discovery. -- * We've already picked an isid, so the -- * most we can do is confirm we reached -- * the portal group we were expecting to -+ * via discovery, but the value could be stale. -+ * If the target was reconfigured it will send us -+ * the updated tpgt. - */ - tag = strtoul(value, NULL, 0); - if (session->portal_group_tag >= 0) { -- if (tag != session->portal_group_tag) { -- log_error("Portal group tag " -+ if (tag != session->portal_group_tag) -+ log_debug(2, "Portal group tag " - "mismatch, expected %u, " -- "received %u", -+ "received %u. Updating", - session->portal_group_tag, tag); -- return LOGIN_WRONG_PORTAL_GROUP; -- } -- } else -- /* we now know the tag */ -- session->portal_group_tag = tag; -- -+ } -+ /* we now know the tag */ -+ session->portal_group_tag = tag; - text = value_end; - } else { - /* -@@ -339,21 +335,22 @@ get_op_params_text_keys(iscsi_session_t - } - } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end, - &value, &value_end)) { -+ int tag = strtoul(value, NULL, 0); - /* -- * confirm we reached the portal group we were expecting to -+ * We should have already obtained this -+ * via discovery, but the value could be stale. -+ * If the target was reconfigured it will send us -+ * the updated tpgt. - */ -- int tag = strtoul(value, NULL, 0); - if (session->portal_group_tag >= 0) { -- if (tag != session->portal_group_tag) { -- log_error("Portal group tag mismatch, " -- "expected %u, received %u", -+ if (tag != session->portal_group_tag) -+ log_debug(2, "Portal group tag " -+ "mismatch, expected %u, " -+ "received %u. Updating", - session->portal_group_tag, tag); -- return LOGIN_WRONG_PORTAL_GROUP; -- } -- } else -- /* we now know the tag */ -- session->portal_group_tag = tag; -- -+ } -+ /* we now know the tag */ -+ session->portal_group_tag = tag; - text = value_end; - } else if (iscsi_find_key_value("InitialR2T", text, end, &value, - &value_end)) { -diff -pur open-iscsi-2.0-865/usr/mgmt_ipc.c open-iscsi.git/usr/mgmt_ipc.c ---- open-iscsi-2.0-865/usr/mgmt_ipc.c 2008-03-05 11:43:19.396981000 +0100 -+++ open-iscsi.git/usr/mgmt_ipc.c 2008-03-05 11:29:21.656625500 +0100 -@@ -139,7 +139,7 @@ mgmt_ipc_session_logout(queue_task_t *qt - iscsi_session_t *session; - - if (!(session = session_find_by_rec(rec))) { -- log_error("session [%s,%s,%d] not found!", rec->name, -+ log_debug(1, "session [%s,%s,%d] not found!", rec->name, - rec->conn[0].address, rec->conn[0].port); - return MGMT_IPC_ERR_NOT_FOUND; - } -@@ -172,7 +172,7 @@ mgmt_ipc_session_info(queue_task_t *qtas - struct ipc_msg_session_state *info; - - if (!(session = session_find_by_sid(sid))) { -- log_error("session with sid %d not found!", sid); -+ log_debug(1, "session with sid %d not found!", sid); - return MGMT_IPC_ERR_NOT_FOUND; - } - -diff -pur open-iscsi-2.0-865/usr/strings.c open-iscsi.git/usr/strings.c ---- open-iscsi-2.0-865/usr/strings.c 2008-03-05 11:28:54.670939000 +0100 -+++ open-iscsi.git/usr/strings.c 2008-02-06 08:24:29.436854500 +0100 -@@ -78,7 +78,7 @@ enlarge_data(struct string_buffer *s, in - - if (s) { - s->data_length += length; -- if (s->data_length >= s->allocated_length) { -+ if (s->data_length > s->allocated_length) { - log_debug(7, "enlarge buffer from %lu to %lu\n", - s->allocated_length, s->data_length); - new_buf = realloc(s->buffer, s->data_length); -@@ -91,8 +91,9 @@ enlarge_data(struct string_buffer *s, in - exit(1); - } - s->buffer = new_buf; -- memset(s->buffer + s->allocated_length, 0, length); -- s->allocated_length += length; -+ memset(s->buffer + s->allocated_length, 0, -+ s->data_length - s->allocated_length); -+ s->allocated_length = s->data_length; - } - } - } -diff -pur open-iscsi-2.0-865/usr/util.c open-iscsi.git/usr/util.c ---- open-iscsi-2.0-865/usr/util.c 2008-03-05 11:43:19.436983500 +0100 -+++ open-iscsi.git/usr/util.c 2008-03-05 11:29:21.692627750 +0100 -@@ -313,7 +313,7 @@ int __iscsi_match_session(node_rec_t *re - if (rec->conn[0].port != -1 && port != rec->conn[0].port) - return 0; - -- if (strlen(rec->iface.transport_name) && -+ if (iface && strlen(rec->iface.transport_name) && - strcmp(rec->iface.transport_name, iface->transport_name)) - return 0; - -diff -pur open-iscsi-2.0-865/usr/version.h open-iscsi.git/usr/version.h ---- open-iscsi-2.0-865/usr/version.h 2007-06-13 17:56:49.000000000 +0200 -+++ open-iscsi.git/usr/version.h 2008-03-05 11:29:21.720629500 +0100 -@@ -6,7 +6,7 @@ - * This may not be the same value as the kernel versions because - * some other maintainer could merge a patch without going through us - */ --#define ISCSI_VERSION_STR "2.0-865" -+#define ISCSI_VERSION_STR "2.0-868" - #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" - - #endif -diff -pur open-iscsi-2.0-865/utils/fwparam_ibft/fw_entry.c open-iscsi.git/utils/fwparam_ibft/fw_entry.c ---- open-iscsi-2.0-865/utils/fwparam_ibft/fw_entry.c 2008-03-05 11:28:54.870951500 +0100 -+++ open-iscsi.git/utils/fwparam_ibft/fw_entry.c 2008-02-06 08:24:29.472856750 +0100 -@@ -43,10 +43,7 @@ static void dump_mac(struct boot_context - if (!strlen(context->mac)) - return; - -- printf("iface.hwaddress = "); -- for (i = 0; i < 5; i++) -- printf("%02x:", context->mac[i]); -- printf("%02x\n", context->mac[i]); -+ printf("iface.hwaddress = %s\n", context->mac); - } - - static void dump_initiator(struct boot_context *context) -diff -pur open-iscsi-2.0-865/utils/iscsi_discovery open-iscsi.git/utils/iscsi_discovery ---- open-iscsi-2.0-865/utils/iscsi_discovery 2007-05-31 20:14:20.000000000 +0200 -+++ open-iscsi.git/utils/iscsi_discovery 2008-02-06 08:24:29.484857500 +0100 -@@ -63,6 +63,12 @@ parse_cmdline() - - discover() - { -+ # If open-iscsi is already logged in to the portal, exit -+ if [ $(iscsiadm -m session | grep -c ${ip}:${port}) -ne 0 ]; then -+ echo "Please logout from all targets on ${ip}:${port} before trying to run discovery on that portal" -+ exit 2 -+ fi -+ - connected=0 - discovered=0 - df=/tmp/discovered.$$ -@@ -80,7 +86,7 @@ discover() - echo "failed to discover targets at ${ip}" - exit 2 - else -- echo "discovered ${discovered} targets at ${ip}, connected to ${connected}" -+ echo "discovered ${discovered} targets at ${ip}" - fi - /bin/rm -f ${df} - } diff --git a/open-iscsi-add-suse-boot-script b/open-iscsi-add-suse-boot-script deleted file mode 100644 index 42c4877..0000000 --- a/open-iscsi-add-suse-boot-script +++ /dev/null @@ -1,112 +0,0 @@ -commit a9552e7d8651ecdaefc39ea7913ba2a382a025fe -Author: Hannes Reinecke -Date: Mon Mar 10 10:16:46 2008 +0100 - - Add SUSE boot script - - For root on iSCSI SUSE requires a separate boot script to start - up iscsid as soon as possible. - - Signed-off-by: Hannes Reinecke - -diff --git a/Makefile b/Makefile -index 046c0f9..8eb812c 100644 ---- a/Makefile -+++ b/Makefile -@@ -79,6 +79,8 @@ install_initd_suse: - $(INSTALL) -d $(DESTDIR)$(initddir) - $(INSTALL) -m 755 etc/initd/initd.suse \ - $(DESTDIR)$(initddir)/open-iscsi -+ $(INSTALL) -m 755 etc/initd/boot.suse \ -+ $(DESTDIR)$(initddir)/boot.open-iscsi - - install_initd_redhat: - $(INSTALL) -d $(DESTDIR)$(initddir) -diff --git a/etc/initd/boot.suse b/etc/initd/boot.suse -new file mode 100644 -index 0000000..df64e21 ---- /dev/null -+++ b/etc/initd/boot.suse -@@ -0,0 +1,82 @@ -+#!/bin/bash -+# -+# /etc/init.d/iscsi -+# -+### BEGIN INIT INFO -+# Provides: iscsiboot -+# Required-Start: boot.proc -+# Should-Start: -+# Required-Stop: -+# Should-Stop: -+# Default-Start: B -+# Default-Stop: -+# Short-Description: Starts the iSCSI initiator daemon -+# -+### END INIT INFO -+ -+ISCSIADM=/sbin/iscsiadm -+PID_FILE=/var/run/iscsi.pid -+CONFIG_FILE=/etc/iscsid.conf -+DAEMON=/sbin/iscsid -+ARGS="-c $CONFIG_FILE -p $PID_FILE" -+ -+# Source LSB init functions -+. /etc/rc.status -+ -+# -+# This service is run right after booting. So all activated targets -+# must be enabled during mkinitrd run and thus should not be removed -+# when the open-iscsi service is stopped. -+# -+iscsi_mark_root_nodes() -+{ -+ $ISCSIADM -m session 2> /dev/null | while read t num i target ; do -+ ip=${i%%:*} -+ STARTUP=`$ISCSIADM -m node -p $ip -T $target | grep "node.conn\[0\].startup" | cut -d' ' -f3` -+ if [ "$STARTUP" != "onboot" ] ; then -+ $ISCSIADM -m node -p $ip -T $target -o update -n node.conn[0].startup -v onboot -+ fi -+ done -+} -+ -+# Reset status of this service -+rc_reset -+ -+# We only need to start this for root on iSCSI -+if ! grep -q iscsi_tcp /proc/modules ; then -+ rc_failed 6 -+ rc_exit -+fi -+ -+case "$1" in -+ start) -+ [ ! -d /var/lib/open-iscsi ] && mkdir -p /var/lib/open-iscsi -+ echo -n "Starting iSCSI initiator for the root device: " -+ startproc $DAEMON $ARGS -+ rc_status -v -+ iscsi_mark_root_nodes -+ ;; -+ stop) -+ rc_failed 0 -+ ;; -+ status) -+ echo -n "Checking for iSCSI initiator service: " -+ if checkproc $DAEMON ; then -+ rc_status -v -+ else -+ rc_failed 3 -+ rc_status -v -+ fi -+ ;; -+ restart) -+ $0 stop -+ sleep 1 -+ $0 start -+ ;; -+ *) -+ echo "Usage: $0 {start|stop|status|restart}" -+ exit 1 -+ ;; -+esac -+rc_exit -+ diff --git a/open-iscsi-check-logmsg-length b/open-iscsi-check-logmsg-length deleted file mode 100644 index 369df65..0000000 --- a/open-iscsi-check-logmsg-length +++ /dev/null @@ -1,90 +0,0 @@ -commit fa1429ee35e2dc2ea4895ec38216482afc3d95b5 -Author: Hannes Reinecke -Date: Wed Apr 2 11:31:18 2008 +0200 - - log_syslog might crash upon failure - - log_dequeue returns 1 on two conditions; either the log queue is empty entirely - or this is the last message on the queue. When the first condition is true the - logger will crash as it tries to access an invalid message. - - Signed-off-by: Hannes Reinecke - -diff --git a/usr/iscsid.c b/usr/iscsid.c -index 2959821..2fbc387 100644 ---- a/usr/iscsid.c -+++ b/usr/iscsid.c -@@ -388,7 +388,7 @@ int main(int argc, char *argv[]) - - if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) { - log_close(log_pid); -- exit(-1); -+ exit(1); - } - - if (log_daemon) { -@@ -413,7 +413,7 @@ int main(int argc, char *argv[]) - - if ((control_fd = ipc->ctldev_open()) < 0) { - log_close(log_pid); -- exit(-1); -+ exit(1); - } - - chdir("/"); -@@ -430,7 +430,7 @@ int main(int argc, char *argv[]) - } else { - if ((control_fd = ipc->ctldev_open()) < 0) { - log_close(log_pid); -- exit(-1); -+ exit(1); - } - } - -diff --git a/usr/log.c b/usr/log.c -index 9b82c46..a738454 100644 ---- a/usr/log.c -+++ b/usr/log.c -@@ -196,7 +196,7 @@ int log_dequeue (void * buff) - int len; - - if (la->empty) -- return 1; -+ return 0; - - len = strlen((char *)&src->str) * sizeof(char) + - sizeof(struct logmsg) + 1; -@@ -215,7 +215,7 @@ int log_dequeue (void * buff) - - memset((void *)src, 0, len); - -- return la->empty; -+ return len; - } - - /* -@@ -314,19 +314,22 @@ static void __dump_char(int level, unsigned char *buf, int *cp, int ch) - - static void log_flush(void) - { -+ int msglen; -+ - while (!la->empty) { - la->ops[0].sem_op = -1; - if (semop(la->semid, la->ops, 1) < 0) { - syslog(LOG_ERR, "semop up failed %d", errno); - exit(1); - } -- log_dequeue(la->buff); -+ msglen = log_dequeue(la->buff); - la->ops[0].sem_op = 1; - if (semop(la->semid, la->ops, 1) < 0) { - syslog(LOG_ERR, "semop down failed"); - exit(1); - } -- log_syslog(la->buff); -+ if (msglen) -+ log_syslog(la->buff); - } - } - diff --git a/open-iscsi-cleanup-IPC b/open-iscsi-cleanup-IPC deleted file mode 100644 index 35b72d1..0000000 --- a/open-iscsi-cleanup-IPC +++ /dev/null @@ -1,151 +0,0 @@ -commit 824e3244cd75d33653eacde88acc8b456145543c -Author: Hannes Reinecke -Date: Fri Apr 4 13:14:14 2008 +0200 - - Cleanup IPC segments and identifiers - - Upon error we're not cleaning up IPC identifiers properly, - hence we're leaking IPC ids to the system. Not good. - And we're not invalidating the logarea itself, making the - daemon crash when started twice. - - Signed-off-by: Hannes Reinecke - -diff --git a/usr/log.c b/usr/log.c -index a738454..013caed 100644 ---- a/usr/log.c -+++ b/usr/log.c -@@ -37,6 +37,33 @@ int log_level = 0; - - static int log_stop_daemon = 0; - -+static void free_logarea (void) -+{ -+ int shmid; -+ -+ if (!la) -+ return; -+ -+ if (la->semid != -1) -+ semctl(la->semid, 0, IPC_RMID, la->semarg); -+ if (la->buff) { -+ shmdt(la->buff); -+ shmctl(la->shmid_buff, IPC_RMID, NULL); -+ la->buff = NULL; -+ la->shmid_buff = -1; -+ } -+ if (la->start) { -+ shmdt(la->start); -+ shmctl(la->shmid_msg, IPC_RMID, NULL); -+ la->start = NULL; -+ la->shmid_msg = -1; -+ } -+ shmid = la->shmid; -+ shmdt(la); -+ shmctl(shmid, IPC_RMID, NULL); -+ la = NULL; -+} -+ - static int logarea_init (int size) - { - int shmid; -@@ -48,21 +75,28 @@ static int logarea_init (int size) - return 1; - - la = shmat(shmid, NULL, 0); -- if (!la) -+ if (!la) { -+ shmctl(shmid, IPC_RMID, NULL); - return 1; -+ } -+ la->shmid = shmid; -+ la->start = NULL; -+ la->buff = NULL; -+ la->semid = -1; - - if (size < MAX_MSG_SIZE) - size = DEFAULT_AREA_SIZE; - - if ((shmid = shmget(IPC_PRIVATE, size, - 0644 | IPC_CREAT | IPC_EXCL)) == -1) { -- shmdt(la); -+ free_logarea(); - return 1; - } -+ la->shmid_msg = shmid; - -- la->start = shmat(shmid, NULL, 0); -+ la->start = shmat(la->shmid_msg, NULL, 0); - if (!la->start) { -- shmdt(la); -+ free_logarea(); - return 1; - } - memset(la->start, 0, size); -@@ -74,32 +108,27 @@ static int logarea_init (int size) - - if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg), - 0644 | IPC_CREAT | IPC_EXCL)) == -1) { -- shmdt(la->start); -- shmdt(la); -+ free_logarea(); - return 1; - } - la->buff = shmat(shmid, NULL, 0); - if (!la->buff) { -- shmdt(la->start); -- shmdt(la); -+ free_logarea(); - return 1; - } - - if ((la->semid = semget(SEMKEY, 1, 0600 | IPC_CREAT)) < 0) { -- shmdt(la->buff); -- shmdt(la->start); -- shmdt(la); -+ free_logarea(); - return 1; - } - - la->semarg.val=1; - if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) { -- shmdt(la->buff); -- shmdt(la->start); -- shmdt(la); -+ free_logarea(); - return 1; - } - -+ la->shmid_buff = shmid; - la->ops[0].sem_num = 0; - la->ops[0].sem_flg = 0; - -@@ -107,14 +136,6 @@ static int logarea_init (int size) - - } - --static void free_logarea (void) --{ -- shmdt(la->buff); -- shmdt(la->start); -- shmdt(la); -- semctl(la->semid, 0, IPC_RMID, la->semarg); --} -- - #if LOGDBG - static void dump_logarea (void) - { -diff --git a/usr/log.h b/usr/log.h -index 4816a1b..4d2a265 100644 ---- a/usr/log.h -+++ b/usr/log.h -@@ -51,6 +51,9 @@ struct logmsg { - }; - - struct logarea { -+ int shmid; -+ int shmid_msg; -+ int shmid_buff; - int empty; - void *head; - void *tail; diff --git a/open-iscsi-discover-all-targets b/open-iscsi-discover-all-targets deleted file mode 100644 index 45a3481..0000000 --- a/open-iscsi-discover-all-targets +++ /dev/null @@ -1,52 +0,0 @@ ---- open-iscsi-2.0-707/etc/initd/initd.suse 2007/11/15 13:42:43 1.37 -+++ open-iscsi-2.0-707/etc/initd/initd.suse 2007/11/30 08:10:00 -@@ -94,6 +94,38 @@ - done - } - -+iscsi_discover_all_targets() -+{ -+ # Strip off any existing ID information -+ RAW_NODE_LIST=`iscsiadm -m node | sed -nre 's/^(\[[0-9a-f]*\] )?(.*)$/\2/p'` -+ # Obtain IPv4 list -+ IPV4_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9]{1,3}(\.[0-9]{1,3}){3}):[^: ]* (.*)$/\1 \3/p'` -+ # Now obtain IPv6 list -+ IPV6_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9a-f]{1,4}(:[0-9a-f]{0,4}){6}:[0-9a-f]{1,4}):[^: ]* (.*)$/\1 \3/p'` -+ -+ DISC_TARGETS="" -+ while read NODE_ADDR NODE_NAME; do -+ [ -z "$NODE_ADDR" -a -z "$NODE_NAME" ] && continue -+ NODE_ATTRS=`iscsiadm -m node -p "$NODE_ADDR" -T "$NODE_NAME"` -+ NODE_STATUS=`echo "$NODE_ATTRS" | sed -nre 's/^.*node\.conn\[0\]\.startup = ([a-z]*).*$/\1/p'` -+ -+ if [ "$NODE_STATUS" == 'automatic' ]; then -+ DISC_TARGETS=`echo "$DISC_TARGETS" | sed -re '/'"$NODE_ADDR"'/!{s/(.*)/\1 '"$NODE_ADDR"'/}'` -+ fi -+ done < <(echo "$IPV4_NODE_LIST"; echo "$IPV6_NODE_LIST") -+ -+ for TARGET_ADDR in $DISC_TARGETS; do -+ echo -n "Attempting discovery on target at ${TARGET_ADDR}: " -+ iscsiadm -m discovery -t st -p "$TARGET_ADDR" > /dev/null 2>&1 -+ if [ "$?" -ne 0 ]; then -+ rc_failed 1 -+ rc_status -v -+ return 1 -+ fi -+ rc_status -v -+ done -+} -+ - case "$1" in - start) - [ ! -d /var/lib/iscsi ] && mkdir -p /var/lib/iscsi -@@ -108,6 +140,10 @@ - rc_status -v - fi - if [ "$RETVAL" == "0" ]; then -+ iscsi_discover_all_targets -+ RETVAL=$? -+ fi -+ if [ "$RETVAL" == "0" ]; then - iscsi_login_all_nodes - fi - ;; diff --git a/open-iscsi-dont-fail-init-script-on-stop b/open-iscsi-dont-fail-init-script-on-stop deleted file mode 100644 index 4ea9c86..0000000 --- a/open-iscsi-dont-fail-init-script-on-stop +++ /dev/null @@ -1,25 +0,0 @@ -commit f866141b55c21b4697f31309054fb4ecdcda19b6 -Author: Hannes Reinecke -Date: Mon Mar 17 15:21:21 2008 +0100 - - Don't fail SUSE init script when calling 'stop' twice - - When calling SUSE init script twice with 'stop' or once when - the daemon is not running, it will return failed. - - References: 369300 - Signed-off-by: Hannes Reinecke - -diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse -index a8b4a0c..d8b91cc 100644 ---- a/etc/initd/initd.suse -+++ b/etc/initd/initd.suse -@@ -176,7 +176,7 @@ case "$1" in - fi - rc_failed $status - else -- rc_failed 1 -+ rc_failed $RETVAL - fi - rc_status -v - ;; diff --git a/open-iscsi-fixup-debug-option b/open-iscsi-fixup-debug-option deleted file mode 100644 index d2cebca..0000000 --- a/open-iscsi-fixup-debug-option +++ /dev/null @@ -1,11 +0,0 @@ ---- open-iscsi-2.0-865/usr/iscsiadm.c 2007/12/13 07:37:12 1.5 -+++ open-iscsi-2.0-865/usr/iscsiadm.c 2007/12/13 07:30:41 -@@ -80,7 +80,7 @@ - {"logoutall", required_argument, NULL, 'U'}, - {"stats", no_argument, NULL, 's'}, - {"killiscsid", required_argument, NULL, 'k'}, -- {"debug", required_argument, NULL, 'g'}, -+ {"debug", required_argument, NULL, 'd'}, - {"show", no_argument, NULL, 'S'}, - {"version", no_argument, NULL, 'V'}, - {"help", no_argument, NULL, 'h'}, diff --git a/open-iscsi-fixup-init-script b/open-iscsi-fixup-init-script deleted file mode 100644 index d31795f..0000000 --- a/open-iscsi-fixup-init-script +++ /dev/null @@ -1,34 +0,0 @@ ---- open-iscsi-2.0-865/etc/initd/initd.suse 2007/12/06 07:55:12 1.9 -+++ open-iscsi-2.0-865/etc/initd/initd.suse 2007/12/06 10:38:32 -@@ -34,19 +34,26 @@ - iscsi_login_all_nodes() - { - echo -n "Setting up iSCSI targets: " -- $ISCSIADM -m node --loginall=automatic -+ $ISCSIADM -m node --loginall=automatic 2> /dev/null -+ if [ $? == 19 ] ; then -+ rc_failed 6 -+ fi - rc_status -v - } - - iscsi_logout_all_nodes() - { -+ echo -n "Closing all iSCSI connections: " - # Logout from all active sessions -- if $ISCSIADM -m node --logoutall=all ; then -- rc_status -v -- else -- RETVAL=$? -+ if ! $ISCSIADM -m node --logoutall=automatic 2> /dev/null; then -+ if [ $? == 19 ] ; then -+ RETVAL=6 -+ else -+ RETVAL=1 -+ fi - rc_failed $RETVAL - fi -+ rc_status -v - - # Not sure whether this is still needed - sleep 1 diff --git a/open-iscsi-git-update b/open-iscsi-git-update index caa0a22..8cdaba6 100644 --- a/open-iscsi-git-update +++ b/open-iscsi-git-update @@ -1,5 +1,5 @@ diff --git a/Makefile b/Makefile -index b2ba0c3..13062db 100644 +index b2ba0c3..e405c9c 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,7 @@ etcdir = /etc @@ -51,7 +51,29 @@ index b2ba0c3..13062db 100644 install_programs: $(PROGRAMS) $(INSTALL) -d $(DESTDIR)$(sbindir) $(INSTALL) -m 755 $^ $(DESTDIR)$(sbindir) -@@ -113,4 +114,9 @@ install_iname: +@@ -78,6 +79,8 @@ install_initd_suse: + $(INSTALL) -d $(DESTDIR)$(initddir) + $(INSTALL) -m 755 etc/initd/initd.suse \ + $(DESTDIR)$(initddir)/open-iscsi ++ $(INSTALL) -m 755 etc/initd/boot.suse \ ++ $(DESTDIR)$(initddir)/boot.open-iscsi + + install_initd_redhat: + $(INSTALL) -d $(DESTDIR)$(initddir) +@@ -94,8 +97,10 @@ install_iface: $(IFACEFILES) + $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi/ifaces + + install_etc: $(ETCFILES) +- $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi +- $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ++ if [ ! -f /etc/iscsi/iscsid.conf ]; then \ ++ $(INSTALL) -d $(DESTDIR)$(etcdir)/iscsi ; \ ++ $(INSTALL) -m 644 $^ $(DESTDIR)$(etcdir)/iscsi ; \ ++ fi + + install_doc: $(MANPAGES) + $(INSTALL) -d $(DESTDIR)$(mandir)/man8 +@@ -113,4 +118,9 @@ install_iname: echo "***************************************************" ; \ fi @@ -62,9 +84,18 @@ index b2ba0c3..13062db 100644 + # vim: ft=make tw=72 sw=4 ts=4: diff --git a/README b/README -index 59878ce..639524a 100644 +index 59878ce..21f961a 100644 --- a/README +++ b/README +@@ -4,7 +4,7 @@ + + ================================================================= + +- Jan 26, 2007 ++ Mar 14, 2008 + + Contents + ======== @@ -16,7 +16,8 @@ Contents - 5. Open-iSCSI Configuration Utility - 6. Configuration @@ -93,7 +124,102 @@ index 59878ce..639524a 100644 You need to enable "Cryptographic API" under "Cryptographic options" in the kernel config. And you must enable "CRC32c CRC algorithm" even if you do not use header or data digests. They are the kernel options, -@@ -322,7 +328,7 @@ TCP/IP. Then in /etc/iscsi/ifaces/iface0 you would enter: +@@ -95,16 +101,26 @@ To compile on SUSE Linux you'll have to use + + where is the kernel configuration to use (eg. 'smp'). + +-If you choose to install the Debian packages instead of building from source, +-please read the file /usr/share/doc/linux-iscsi/README.debian for information +-on how to build kernel modules against your specific kernel. +- + For Red Hat/Fedora and Debian distributions open-iscsi can be installed by + typing "make install". This will copy iscsid and iscsiadm to /usr/sbin, the + init script to /etc/init.d, and the kernel modules: iscsi_tcp.ko, libiscsi.ko + and scsi_transport_iscsi to /lib/modules/`uname -r`/kernel/drivers/scsi/ + overwriting existing iscsi modules. + ++For Debian, be sure to install the linux-headers package that ++corresponds to your kernel in order to compile the kernel modules ++('aptitude install linux-headers-`uname -r`'). You may also wish to ++run 'make -C kernel/ dpkg_divert' before installing kernel modules if ++you run a Debian-provided kernel. This will use dpkg-divert(8) to ++move the packaged kernel modules out of the way, and ensure that ++future kernel upgrades will not overwrite them. ++ ++Also, please be aware that the compatibility patches that enable these ++iscsi modules to run on kernels older than 2.6.25 will not update the ++ib_iser module; you may get warnings related to mismatched symbols on ++this driver, in which case you'll be unable to load ib_iser and ++open-iscsi simultaneously. ++ + 4. Open-iSCSI daemon + ==================== + +@@ -168,10 +184,36 @@ Usage: iscsiadm [OPTION] + + -m, --mode specify operational mode op = + -m discovery --type=[type] --interface=iscsi_ifacename \ +- --portal=[ip:port] --login --print=[N] ++ --portal=[ip:port] --login --print=[N] \ ++ --op=[op]=[NEW | UPDATE | DELETE] + perform [type] discovery for target portal with + ip-address [ip] and port [port]. + ++ By default this command will remove records ++ for portals no longer returned. And, if a portal is ++ returned by the target, then the discovery command ++ will create a new record or modify an existing one ++ with values from iscsi.conf and the command line. ++ ++ [op] can be passed in multiple times to this ++ command, and it will alter the DB manipulation. ++ ++ If [op] is passed in and the value is ++ "new", iscsiadm will add records for portals that do ++ not yet have records in the db. ++ ++ If [op] is passed in and the value is ++ "update", iscsiadm will update records using info ++ from iscsi.conf and the command line for portals ++ that are returned during discovery and have ++ a record in the db. ++ ++ if [op] is passed in and the value is "delete", ++ iscsiadm will delete records for portals that ++ were not returned during discovery. ++ ++ See the example section for more info. ++ + See below for how to setup iscsi ifaces for + software iscsi or override the system defaults. + +@@ -214,7 +256,10 @@ Usage: iscsiadm [OPTION] + op could be one of: + [new], [delete], [update] or [show]. In case of + [update], you have to provide [name] and [value] +- you wish to update ++ you wish to update. ++ [delete] - Note that if a session is using the ++ node record, the session will be logged out then ++ the record will be deleted. + + Print level can be 0 to 1. + +@@ -224,11 +269,11 @@ Usage: iscsiadm [OPTION] + Stats prints the iSCSI stats for the session. + -m node --logoutall=[all|manual|automatic] + Logout "all" the running sessions or just the ones +- with a node or conn startup value manual or automatic. ++ with a node startup value manual or automatic. + Nodes marked as ONBOOT are skipped. + -m node --loginall=[all|manual|automatic] + Login "all" the running sessions or just the ones +- with a node or conn startup value manual or automatic. ++ with a node startup value manual or automatic. + Nodes marked as ONBOOT are skipped. + -m session display all active sessions and connections + -m session --sid=[sid] [ --print=level | --rescan | --logout ] +@@ -322,7 +367,7 @@ TCP/IP. Then in /etc/iscsi/ifaces/iface0 you would enter: iface.transport_name = tcp iface.hwaddress = 00:0F:1F:92:6B:BF @@ -102,7 +228,67 @@ index 59878ce..639524a 100644 iface.transport_name = tcp iface.hwaddress = 00:C0:DD:08:63:E7 -@@ -439,12 +445,14 @@ iscsiadm -m node -p ip:port -I iface0 --op=delete +@@ -340,7 +385,7 @@ with the name "iface0" this command will overwrite it.) + (This will set the hwaddress.) + # iscsiadm -m iface -I iface0 --op=update -n iface.hwaddress -v 00:0F:1F:92:6B:BF + +-If you had sessions logged in iscsiadm will not update, delete or overwrite ++If you had sessions logged in iscsiadm will not update, overwrite + a iface. You must log out first. If you have a iface bound to a node/portal + but you have not logged in then, iscsiadm will update the config and + all existing bindings. +@@ -400,7 +445,49 @@ iscsiadm -m node -p ip:port -I iface0 --op=delete + discovery will be setup so that they can logged in through + those interfaces. + +- - SendTargets iSCSI Discovery with a specific interface. If you ++ - SendTargets iSCSI Discovery updating existing records: ++ ++ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ ++ -o update ++ ++ If there a record for targetX and portalY exists in the DB, and ++ is returned during discovery, it will be updated with the info ++ from the iscsi.conf. No new portals will be added and stale ++ portals will not be removed. ++ ++ - SendTargets iSCSI Discovery deleting existing records: ++ ++ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ ++ -o delete ++ ++ If there a record for targetX and portalY exists in the DB, but ++ is not returned during discovery it will be removed from the DB. ++ No new portals will be added and existing portal records will not ++ be changed. ++ ++ Note: If a session is logged into portal we are going to delete ++ a record for, it will be logged out then the record will be ++ deleted. ++ ++ - SendTargets iSCSI Discovery adding new records: ++ ++ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ ++ -o new ++ ++ If there targetX and portalY is returned during discovery and does ++ not have a record, it will be added. Existing records are not ++ modified. ++ ++ - SendTargets iSCSI Discovery using multiple ops: ++ ++ ./iscsiadm -m discovery -t sendtargets -p 192.168.1.1:3260 \ ++ -o new -o delete ++ ++ This command will add new portals and delete records for portals ++ no longer returned. It will not change the record information for ++ existing portals. ++ ++ - SendTargets iSCSI Discovery with a specific interface. If you + wish to only use a subset of the interfaces in /etc/iscsi/ifaces + then you can pass them in during discovery: + +@@ -439,12 +526,14 @@ iscsiadm -m node -p ip:port -I iface0 --op=delete To specify a IPv6 address the following can be used: @@ -119,7 +305,7 @@ index 59878ce..639524a 100644 - iSCSI Login to a specific portal through the NIC setup as iface0: -@@ -714,6 +722,9 @@ running: +@@ -714,6 +803,9 @@ running: iscsiadm -m discovery -t isns @@ -129,7 +315,28 @@ index 59878ce..639524a 100644 Both commands will print out the list of all discovered targets and their portals: -@@ -782,7 +793,130 @@ e.g /etc/init.d/open-iscsi restart. On your next startup the nodes will +@@ -763,16 +855,16 @@ Note: this may only work for distros with init scripts. + To automate login to a node, use the following with the record ID + (record ID is the targetname and portal) of the node discovered in the + discovery above: +- iscsiadm -m node -T targetname -p ip:port --op update -n node.conn[0].startup -v automatic ++ iscsiadm -m node -T targetname -p ip:port --op update -n node.startup -v automatic + + To set the automatic setting to all portals on a target through every + interface setup for each protal, the following can be run: +- iscsiadm -m node -T targetname --op update -n node.conn[0].startup -v automatic ++ iscsiadm -m node -T targetname --op update -n node.startup -v automatic + +-Or to set the "node.conn[0].statup" attribute to "startup" as default for ++Or to set the "node.startup" attribute to "startup" as default for + all sessions add the following to the /etc/iscsi/iscsid.conf: + +- node.conn[0].startup = automatic ++ node.startup = automatic + + Setting this in iscsid.conf, will not affect existing nodes. It will only + affect nodes that are discovered after setting the value. +@@ -782,7 +874,149 @@ e.g /etc/init.d/open-iscsi restart. On your next startup the nodes will be logged into autmotically. @@ -207,6 +414,25 @@ index 59878ce..639524a 100644 +When the SCSI EH is running, commands will not be failed until +node.session.timeo.replacement_timeout seconds. + ++To modify the the timer that starts the SCSI EH, you can either write ++directly to the devices's sysfs file: ++ ++echo X > /sys/block/sdX/device/timeout ++ ++where X is in seconds or on most distros you can modify the udev rule. ++ ++To modify the udev rule open /etc/udev/rules.d/50-udev.rules, and find the ++following lines: ++ ++ACTION=="add", SUBSYSTEM=="scsi" , SYSFS{type}=="0|7|14", \ ++ RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'" ++ ++And change the echo 60 part of the line to the value that you want. ++ ++The default timeout for normal File System commands is 30 seconds when udev ++is not being used. If udev is used the default is the above value which ++is normally 60 seconds. ++ + +8.1.2.2 Pending Commands and replacement_timeout +------------------------------------------------ @@ -230,13 +456,13 @@ index 59878ce..639524a 100644 +--------------------------------------- + +The default value for replacement_timeout is 120 seconds, but because -+multipath's queue if no path setting can prevent IO errors from being propogated -+to the application, replacement_timeout can be set to a shorter value like -+15 to 30 seconds. By setting it lower pending IO is quickly sent to a new path -+and executed while the iSCSI layer attempts to re-establishment the session. -+If all paths end up being failed, then the multipath and device mapper layer -+will internally queue IO based on the multipath.conf settings, instead of the -+iSCSI layer. ++multipath's queue_if_no_path and no_path_retyr setting can prevent IO errors ++from being propogated to the application, replacement_timeout can be set to a ++shorter value like 5 to 15 seconds. By setting it lower pending IO is quickly ++sent to a new path and executed while the iSCSI layer attempts ++re-establishment of the session. If all paths end up being failed, then the ++multipath and device mapper layer will internally queue IO based on the ++multipath.conf settings, instead of the iSCSI layer. + + +8.2 iSCSI settings for iSCSI root @@ -261,8 +487,72 @@ index 59878ce..639524a 100644 ==================== To get information about the running sessions: including the session and +diff --git a/doc/iscsi_discovery.8 b/doc/iscsi_discovery.8 +index e772130..c46223b 100644 +--- a/doc/iscsi_discovery.8 ++++ b/doc/iscsi_discovery.8 +@@ -8,32 +8,45 @@ + .SH NAME + iscsi_discovery \- discover iscsi devices + .SH SYNOPSIS +-.B iscsi_discovery [port] ++.B iscsi_discovery [-p ] [-d] [-t [-f]] [-m] [-l] + + .SH DESCRIPTION + Perform send-targets discovery to the specified IP. If a discovery record +-is generated, try to login to the portal using iSER and TCP transports. ++is generated, try to login to the portal using iSER and TCP transports ++(-t flag specifies the requested transport type, TCP is the default). + If login using a certain transport succeeds, mark the portal for automatic +-login, and disconnect. ++login (unless -m flag is used), and disconnect (unless -l flag is used). + + For iscsi discovery to work, open-iscsi services must be running. e.g. iscsid + should be up, and the iscsi modules loaded. This is best accomplished by the + init.d startup script. + + .\" .SH OPTIONS +-.\" .TP +-.\" .B \- +-.\" +-.\" .TP +-.\" .B \- +-.\" +-.\" .TP +-.\" .B +-.\" .SH "SEE ALSO" +-.\" ++.TP ++.BI [-p=]\fIport\-number\fP ++set the port number (defualt is 3260). ++.TP ++.BI [-d] ++print debugging information. ++.TP ++.BI [-t=]\fItransport\-type\fP ++set transport (default is tcp). ++.TP ++.BI [-f] ++force specific transport - ++disable the fallback to tcp (default is fallback enabled). ++force the transport specified by the argument of the -t flag. ++ ++.TP ++.BI [-m] ++manual startup - will set manual startup (default is automatic startup). ++.TP ++.BI [-l] ++login - login to the new discovered nodes (defualt is false). ++ + .SH AUTHOR + Written by Dan Bar Dov + .SH "REPORTING BUGS" +-Report bugs to . ++Report bugs to . + .SH COPYRIGHT + Copyright \(co Voltaire Ltd. 2006. diff --git a/doc/iscsiadm.8 b/doc/iscsiadm.8 -index c750b4d..710fd39 100644 +index c750b4d..11f49e2 100644 --- a/doc/iscsiadm.8 +++ b/doc/iscsiadm.8 @@ -2,15 +2,19 @@ @@ -283,7 +573,7 @@ index c750b4d..710fd39 100644 -\fBiscsiadm\fR -m iface [ -dhV ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ] +\fBiscsiadm\fR -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ] + -+\fBiscsiadm\fR -m fw ++\fBiscsiadm\fR -m fw [-l] + +\fBiscsiadm\fR -k priority @@ -300,7 +590,7 @@ index c750b4d..710fd39 100644 .TP \fB\-h\fR, \fB\-\-help\fR -@@ -75,6 +79,14 @@ In node mode, only a single interface is supported in each call to iscsiadm. +@@ -75,10 +79,18 @@ In node mode, only a single interface is supported in each call to iscsiadm. .IP This option is valid for discovery, node and iface mode. @@ -315,6 +605,11 @@ index c750b4d..710fd39 100644 .TP \fB\-l\fR, \fB\-\-login\fR +-For node mode, login to a specified record. For discovery mode, login to ++For node and fw mode, login to a specified record. For discovery mode, login to + all discovered targets. + .IP + This option is only valid for discovery and node modes. @@ -95,11 +107,12 @@ for session mode). .TP \fB\-m, \-\-mode \fIop\fR @@ -330,7 +625,29 @@ index c750b4d..710fd39 100644 .TP \fB\-n\fR, \fB\-\-name=\fIname\fR -@@ -181,8 +194,8 @@ This option is only valid for node and session mode. +@@ -112,16 +125,14 @@ operator. + Specifies a database operator \fIop\fR. \fIop\fR must be one of + \fInew\fR, \fIdelete\fR, \fIupdate\fR or \fIshow\fR. + .IP +-This option is only valid for all modes, but delete should not be used on a running session. ++This option is valid for all modes except fw. Delete should not be used on a running session. If it is iscsiadm will stop the session and then delete the ++record. + .IP +-\fInew\fR is currently valid only for node, session and iface mode. It creates +-a new database record for a given \fIportal\fR (IP address and port number). ++\fInew\fR creates a new database record for a given \fIportal\fR (IP address and port number). In discovery mode, iscsiadm will create new records for portals returned by the target. + .IP +-\fIdelete\fR deletes a specified \fIrecid\fR. ++\fIdelete\fR deletes a specified \fIrecid\fR. In discovery node, iscsiadm will delete records for portals that are no longer returned. + .IP +-\fIupdate\fR is currently valid only for node, session, and iface mode. +-It updates a specified +-\fIrecid\fR with \fIname\fR to the specified \fIvalue\fR. ++\fIupdate\fR will update the \fIrecid\fR with \fIname\fR to the specified \fIvalue\fR. In discovery node the \fIrecid\fR, \fIname\fR and \fIvalue\fR arguments are not needed. The update operation will operate on the portals returned by the target, and will update the record with info from the config file and command line. + .IP + \fIshow\fR is the default behaviour for node, discovery and iface mode. It is + also used when there are no commands passed into session mode and a running +@@ -181,8 +192,8 @@ This option is only valid for node and session mode. .TP \fB\-t\fR, \fB\-\-type=\fItype\fR \fItype\fR must be \fIsendtargets\fR (or abbreviated as \fIst\fR), @@ -341,7 +658,7 @@ index c750b4d..710fd39 100644 .IP This option is only valid for discovery mode. -@@ -238,6 +251,22 @@ and iscsiadm must be run in discovery mode with the "isns" discovery type. +@@ -238,6 +249,22 @@ and iscsiadm must be run in discovery mode with the "isns" discovery type. iSNS support in open-iscsi is experimental. The iscsid.conf settings, iscsiadm syntax and node DB layout may change. @@ -379,11 +696,172 @@ index e545f4f..1dfa1e5 100644 .TP .BI [-u|--uid=]\fIuid\fP run under user ID \fIuid\fR (default is the current user ID) +diff --git a/etc/iface.example b/etc/iface.example +index 5587a73..7684aea 100644 +--- a/etc/iface.example ++++ b/etc/iface.example +@@ -4,22 +4,41 @@ + # There must be a seperate iscsi interface config file for each NIC, network + # interface or port or iscsi HBA you want to bind sessions to. + # +-# For hardware/offload iscsi, this is created for you when you run iscsiadm. ++# For hardware iscsi, this is created for you when you run iscsiadm. + # For software iscsi, you must define these files yourself. + # + ++# REQUIRED: iface.transport_name ++# + # Set the iscsi transport/driver to use for the iface by setting + # iface.transport_name + # example: + # iface.transport_name = tcp + +-# This values is required and valid values for iface.transport_name are: ++# This value is required and valid values for iface.transport_name are: + # - tcp (Software iSCSI over TCP/IP) + # - iser (Software iSCSI over infinniband + # - qla4xxx (Qlogic QLA4XXX HBAs) +- +- +-# __One__ of the following values are required for the binding. ++# ++# ++#OPTIONAL: iface.initiatorname ++# To use a initiator name other than the one set in ++# /etc/iscsi/initiatorname.iscsi for normal sessions set the ++# iface.initiatorname. This is only used for normal sessions. ++# For discovery sessions the /etc/iscsi/initiatorname.iscsi value ++# is used. ++# ++# iface.initiatorname = iqn.2003-04.com.fedora:test ++# ++# ++# REQUIRED to be able to bind a session to a network device: ++# [iface.net_ifacename | iface.hwaddress] ++# ++# OPTIONAL if you are creating ifaces so you can create multiple sessions ++# using the default behavior where the network layer selects the device. ++# ++# __One__ of the following values are required for binding a session ++# to a specific nic/netdevice. + # + # To bind by network interface name (example: eth0, eth2:2, eth1.3) + # set iface.net_ifacename +diff --git a/etc/initd/boot.suse b/etc/initd/boot.suse +new file mode 100644 +index 0000000..df64e21 +--- /dev/null ++++ b/etc/initd/boot.suse +@@ -0,0 +1,82 @@ ++#!/bin/bash ++# ++# /etc/init.d/iscsi ++# ++### BEGIN INIT INFO ++# Provides: iscsiboot ++# Required-Start: boot.proc ++# Should-Start: ++# Required-Stop: ++# Should-Stop: ++# Default-Start: B ++# Default-Stop: ++# Short-Description: Starts the iSCSI initiator daemon ++# ++### END INIT INFO ++ ++ISCSIADM=/sbin/iscsiadm ++PID_FILE=/var/run/iscsi.pid ++CONFIG_FILE=/etc/iscsid.conf ++DAEMON=/sbin/iscsid ++ARGS="-c $CONFIG_FILE -p $PID_FILE" ++ ++# Source LSB init functions ++. /etc/rc.status ++ ++# ++# This service is run right after booting. So all activated targets ++# must be enabled during mkinitrd run and thus should not be removed ++# when the open-iscsi service is stopped. ++# ++iscsi_mark_root_nodes() ++{ ++ $ISCSIADM -m session 2> /dev/null | while read t num i target ; do ++ ip=${i%%:*} ++ STARTUP=`$ISCSIADM -m node -p $ip -T $target | grep "node.conn\[0\].startup" | cut -d' ' -f3` ++ if [ "$STARTUP" != "onboot" ] ; then ++ $ISCSIADM -m node -p $ip -T $target -o update -n node.conn[0].startup -v onboot ++ fi ++ done ++} ++ ++# Reset status of this service ++rc_reset ++ ++# We only need to start this for root on iSCSI ++if ! grep -q iscsi_tcp /proc/modules ; then ++ rc_failed 6 ++ rc_exit ++fi ++ ++case "$1" in ++ start) ++ [ ! -d /var/lib/open-iscsi ] && mkdir -p /var/lib/open-iscsi ++ echo -n "Starting iSCSI initiator for the root device: " ++ startproc $DAEMON $ARGS ++ rc_status -v ++ iscsi_mark_root_nodes ++ ;; ++ stop) ++ rc_failed 0 ++ ;; ++ status) ++ echo -n "Checking for iSCSI initiator service: " ++ if checkproc $DAEMON ; then ++ rc_status -v ++ else ++ rc_failed 3 ++ rc_status -v ++ fi ++ ;; ++ restart) ++ $0 stop ++ sleep 1 ++ $0 start ++ ;; ++ *) ++ echo "Usage: $0 {start|stop|status|restart}" ++ exit 1 ++ ;; ++esac ++rc_exit ++ +diff --git a/etc/initd/initd.debian b/etc/initd/initd.debian +index 9e9f134..c0dfd1e 100644 +--- a/etc/initd/initd.debian ++++ b/etc/initd/initd.debian +@@ -54,9 +54,16 @@ stop() { + log_daemon_msg "Stopping iSCSI initiator service" + start-stop-daemon --stop --quiet --pidfile $PIDFILE --exec $DAEMON + rm -f $PIDFILE ++ status=0 + modprobe -r ib_iser 2>/dev/null ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi + modprobe -r iscsi_tcp 2>/dev/null +- log_end_msg 0 ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi ++ log_end_msg $status + } + + restart() { diff --git a/etc/initd/initd.redhat b/etc/initd/initd.redhat -index c591534..7cf198e 100644 +index c591534..d68f135 100644 --- a/etc/initd/initd.redhat +++ b/etc/initd/initd.redhat -@@ -39,9 +39,8 @@ stop() +@@ -39,13 +39,23 @@ stop() echo -n $"Stopping iSCSI initiator service: " sync iscsiadm -m node --logoutall=all @@ -392,9 +870,25 @@ index c591534..7cf198e 100644 rm -f /var/run/iscsid.pid - #killproc iscsid [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/open-iscsi ++ status=0 modprobe -r iscsi_tcp 2>/dev/null ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi modprobe -r ib_iser 2>/dev/null -@@ -73,7 +72,7 @@ case "$1" in +- success ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi ++ if [ "$status" -eq "0" ]; then ++ success ++ else ++ failure ++ fi + echo + + } +@@ -73,7 +83,7 @@ case "$1" in RETVAL=$? ;; condrestart) @@ -403,8 +897,169 @@ index c591534..7cf198e 100644 ;; *) echo $"Usage: $0 {start|stop|restart|status|condrestart}" +diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse +index 163479e..d8b91cc 100644 +--- a/etc/initd/initd.suse ++++ b/etc/initd/initd.suse +@@ -5,7 +5,7 @@ + ### BEGIN INIT INFO + # Provides: iscsi + # Required-Start: $network +-# Should-Start: ++# Should-Start: iscsitarget + # Required-Stop: + # Should-Stop: + # Default-Start: 3 5 +@@ -29,25 +29,65 @@ rc_reset + iscsi_login_all_nodes() + { + echo -n "Setting up iSCSI targets: " +- $ISCSIADM -m node --loginall=automatic ++ $ISCSIADM -m node --loginall=automatic 2> /dev/null ++ if [ $? == 19 ] ; then ++ rc_failed 6 ++ fi + rc_status -v + } + + iscsi_logout_all_nodes() + { +- # Logout from all active sessions +- if $ISCSIADM -m node --logoutall=all ; then +- rc_status -v +- else +- RETVAL=$? ++ echo -n "Closing all iSCSI connections: " ++ # Logout from all sessions marked automatic ++ if ! $ISCSIADM -m node --logoutall=automatic 2> /dev/null; then ++ if [ $? == 19 ] ; then ++ RETVAL=6 ++ else ++ RETVAL=1 ++ fi + rc_failed $RETVAL + fi ++ rc_status -v + + # Not sure whether this is still needed + sleep 1 + return ${RETVAL:-0} + } + ++iscsi_umount_all_luns() ++{ ++ local d m dev p s ++ ++ cat /proc/mounts | sed -ne '/^\/dev\/.*/p' | while read d m t o x; do ++ if [ "$m" = "/" ] ; then ++ continue; ++ fi ++ if [ -L "$d" ] ; then ++ d=$(readlink -f $d) ++ fi ++ dev=${d##/dev} ++ ++ if [ "${dev##/sd}" = "$dev" ] ; then ++ continue; ++ fi ++ p="/sys/block${dev%%[0-9]*}" ++ ++ if [ ! -d ${p} ] && [ ! -d ${p}/device ] ; then ++ continue; ++ fi ++ ++ s=$(cd -P ${p}/device && echo $PWD) ++ ++ case "$s" in ++ */session[0-9]*/*) ++ # This is an iSCSI device ++ umount "$m" ++ ;; ++ esac ++ done ++} ++ + iscsi_list_all_nodes() + { + # Check for active sessions +@@ -61,6 +101,38 @@ iscsi_list_all_nodes() + done + } + ++iscsi_discover_all_targets() ++{ ++ # Strip off any existing ID information ++ RAW_NODE_LIST=`iscsiadm -m node | sed -nre 's/^(\[[0-9a-f]*\] )?(.*)$/\2/p'` ++ # Obtain IPv4 list ++ IPV4_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9]{1,3}(\.[0-9]{1,3}){3}):[^: ]* (.*)$/\1 \3/p'` ++ # Now obtain IPv6 list ++ IPV6_NODE_LIST=`echo "$RAW_NODE_LIST" | sed -nre 's/^([0-9a-f]{1,4}(:[0-9a-f]{0,4}){6}:[0-9a-f]{1,4}):[^: ]* (.*)$/\1 \3/p'` ++ ++ DISC_TARGETS="" ++ while read NODE_ADDR NODE_NAME; do ++ [ -z "$NODE_ADDR" -a -z "$NODE_NAME" ] && continue ++ NODE_ATTRS=`iscsiadm -m node -p "$NODE_ADDR" -T "$NODE_NAME"` ++ NODE_STATUS=`echo "$NODE_ATTRS" | sed -nre 's/^.*node\.conn\[0\]\.startup = ([a-z]*).*$/\1/p'` ++ ++ if [ "$NODE_STATUS" == 'automatic' ]; then ++ DISC_TARGETS=`echo "$DISC_TARGETS" | sed -re '/'"$NODE_ADDR"'/!{s/(.*)/\1 '"$NODE_ADDR"'/}'` ++ fi ++ done < <(echo "$IPV4_NODE_LIST"; echo "$IPV6_NODE_LIST") ++ ++ for TARGET_ADDR in $DISC_TARGETS; do ++ echo -n "Attempting discovery on target at ${TARGET_ADDR}: " ++ iscsiadm -m discovery -t st -p "$TARGET_ADDR" > /dev/null 2>&1 ++ if [ "$?" -ne 0 ]; then ++ rc_failed 1 ++ rc_status -v ++ return 1 ++ fi ++ rc_status -v ++ done ++} ++ + case "$1" in + start) + [ ! -d /var/lib/iscsi ] && mkdir -p /var/lib/iscsi +@@ -75,10 +147,15 @@ case "$1" in + rc_status -v + fi + if [ "$RETVAL" == "0" ]; then ++ iscsi_discover_all_targets ++ RETVAL=$? ++ fi ++ if [ "$RETVAL" == "0" ]; then + iscsi_login_all_nodes + fi + ;; + stop) ++ iscsi_umount_all_luns + if iscsi_logout_all_nodes ; then + killproc -KILL $DAEMON + RETVAL=$? +@@ -88,11 +165,18 @@ case "$1" in + echo -n "Stopping iSCSI initiator service: " + if [ "$RETVAL" == "0" ]; then + rm -f $PID_FILE ++ status=0 + modprobe -r iscsi_tcp ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi + modprobe -q -r ib_iser +- rc_failed 0 ++ if [ "$?" -ne "0" -a "$?" -ne "1" ]; then ++ status=1 ++ fi ++ rc_failed $status + else +- rc_failed 1 ++ rc_failed $RETVAL + fi + rc_status -v + ;; diff --git a/etc/iscsid.conf b/etc/iscsid.conf -index 94dd758..29a02c4 100644 +index 94dd758..f2691ee 100644 --- a/etc/iscsid.conf +++ b/etc/iscsid.conf @@ -65,7 +65,10 @@ node.startup = manual @@ -469,16 +1124,22 @@ index 94dd758..29a02c4 100644 +node.session.cmds_max = 128 + +# To control the device's queue depth set node.session.queue_depth -+# to a value between 1 and 128. The default is 128. ++# to a value between 1 and 128. The default is 32. +node.session.queue_depth = 32 + #*************** # iSCSI settings #*************** -@@ -188,3 +211,18 @@ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 - # The default is to never use DataDigests and to allow the target to control - # the setting of the HeaderDigest checking with the initiator requesting - # a preference of disabling the checking. +@@ -185,6 +208,21 @@ discovery.sendtargets.iscsi.MaxRecvDataSegmentLength = 32768 + #node.conn[0].iscsi.HeaderDigest = None + #node.conn[0].iscsi.DataDigest = None + # +-# The default is to never use DataDigests and to allow the target to control +-# the setting of the HeaderDigest checking with the initiator requesting +-# a preference of disabling the checking. ++# The default is to never use DataDigests or HeaderDigests. ++# ++ + +#************ +# Workarounds @@ -547,7 +1208,7 @@ index 0000000..47ac6ae + +#endif /* FWPARAM_CONTEXT_H_ */ diff --git a/include/iscsi_if.h b/include/iscsi_if.h -index 8458425..7ad582e 100644 +index 8458425..19df961 100644 --- a/include/iscsi_if.h +++ b/include/iscsi_if.h @@ -21,7 +21,7 @@ @@ -559,7 +1220,7 @@ index 8458425..7ad582e 100644 #define UEVENT_BASE 10 #define KEVENT_BASE 100 -@@ -49,12 +49,15 @@ enum iscsi_uevent_e { +@@ -49,12 +49,16 @@ enum iscsi_uevent_e { ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, ISCSI_UEVENT_SET_HOST_PARAM = UEVENT_BASE + 16, @@ -572,10 +1233,11 @@ index 8458425..7ad582e 100644 ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4, + ISCSI_KEVENT_UNBIND_SESSION = KEVENT_BASE + 5, + ISCSI_KEVENT_CREATE_SESSION = KEVENT_BASE + 6, ++ ISCSI_KEVENT_TRANS_ERROR = KEVENT_BASE + 7, }; enum iscsi_tgt_dscvr { -@@ -156,6 +159,10 @@ struct iscsi_uevent { +@@ -156,6 +160,10 @@ struct iscsi_uevent { uint32_t sid; uint32_t cid; } c_conn_ret; @@ -586,7 +1248,7 @@ index 8458425..7ad582e 100644 struct msg_recv_req { uint32_t sid; uint32_t cid; -@@ -236,6 +243,13 @@ enum iscsi_param { +@@ -236,36 +244,54 @@ enum iscsi_param { ISCSI_PARAM_PASSWORD, ISCSI_PARAM_PASSWORD_IN, @@ -597,23 +1259,92 @@ index 8458425..7ad582e 100644 + + ISCSI_PARAM_PING_TMO, + ISCSI_PARAM_RECV_TMO, ++ ++ ISCSI_PARAM_IFACE_NAME, ++ ISCSI_PARAM_ISID, /* must always be last */ ISCSI_PARAM_MAX, }; -@@ -266,6 +280,12 @@ enum iscsi_param { - #define ISCSI_USERNAME_IN (1 << ISCSI_PARAM_USERNAME_IN) - #define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) - #define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) -+#define ISCSI_FAST_ABORT (1 << ISCSI_PARAM_FAST_ABORT) -+#define ISCSI_ABORT_TMO (1 << ISCSI_PARAM_ABORT_TMO) -+#define ISCSI_LU_RESET_TMO (1 << ISCSI_PARAM_LU_RESET_TMO) -+#define ISCSI_HOST_RESET_TMO (1 << ISCSI_PARAM_HOST_RESET_TMO) -+#define ISCSI_PING_TMO (1 << ISCSI_PARAM_PING_TMO) -+#define ISCSI_RECV_TMO (1 << ISCSI_PARAM_RECV_TMO) + +-#define ISCSI_MAX_RECV_DLENGTH (1 << ISCSI_PARAM_MAX_RECV_DLENGTH) +-#define ISCSI_MAX_XMIT_DLENGTH (1 << ISCSI_PARAM_MAX_XMIT_DLENGTH) +-#define ISCSI_HDRDGST_EN (1 << ISCSI_PARAM_HDRDGST_EN) +-#define ISCSI_DATADGST_EN (1 << ISCSI_PARAM_DATADGST_EN) +-#define ISCSI_INITIAL_R2T_EN (1 << ISCSI_PARAM_INITIAL_R2T_EN) +-#define ISCSI_MAX_R2T (1 << ISCSI_PARAM_MAX_R2T) +-#define ISCSI_IMM_DATA_EN (1 << ISCSI_PARAM_IMM_DATA_EN) +-#define ISCSI_FIRST_BURST (1 << ISCSI_PARAM_FIRST_BURST) +-#define ISCSI_MAX_BURST (1 << ISCSI_PARAM_MAX_BURST) +-#define ISCSI_PDU_INORDER_EN (1 << ISCSI_PARAM_PDU_INORDER_EN) +-#define ISCSI_DATASEQ_INORDER_EN (1 << ISCSI_PARAM_DATASEQ_INORDER_EN) +-#define ISCSI_ERL (1 << ISCSI_PARAM_ERL) +-#define ISCSI_IFMARKER_EN (1 << ISCSI_PARAM_IFMARKER_EN) +-#define ISCSI_OFMARKER_EN (1 << ISCSI_PARAM_OFMARKER_EN) +-#define ISCSI_EXP_STATSN (1 << ISCSI_PARAM_EXP_STATSN) +-#define ISCSI_TARGET_NAME (1 << ISCSI_PARAM_TARGET_NAME) +-#define ISCSI_TPGT (1 << ISCSI_PARAM_TPGT) +-#define ISCSI_PERSISTENT_ADDRESS (1 << ISCSI_PARAM_PERSISTENT_ADDRESS) +-#define ISCSI_PERSISTENT_PORT (1 << ISCSI_PARAM_PERSISTENT_PORT) +-#define ISCSI_SESS_RECOVERY_TMO (1 << ISCSI_PARAM_SESS_RECOVERY_TMO) +-#define ISCSI_CONN_PORT (1 << ISCSI_PARAM_CONN_PORT) +-#define ISCSI_CONN_ADDRESS (1 << ISCSI_PARAM_CONN_ADDRESS) +-#define ISCSI_USERNAME (1 << ISCSI_PARAM_USERNAME) +-#define ISCSI_USERNAME_IN (1 << ISCSI_PARAM_USERNAME_IN) +-#define ISCSI_PASSWORD (1 << ISCSI_PARAM_PASSWORD) +-#define ISCSI_PASSWORD_IN (1 << ISCSI_PARAM_PASSWORD_IN) ++#define ISCSI_MAX_RECV_DLENGTH (1ULL << ISCSI_PARAM_MAX_RECV_DLENGTH) ++#define ISCSI_MAX_XMIT_DLENGTH (1ULL << ISCSI_PARAM_MAX_XMIT_DLENGTH) ++#define ISCSI_HDRDGST_EN (1ULL << ISCSI_PARAM_HDRDGST_EN) ++#define ISCSI_DATADGST_EN (1ULL << ISCSI_PARAM_DATADGST_EN) ++#define ISCSI_INITIAL_R2T_EN (1ULL << ISCSI_PARAM_INITIAL_R2T_EN) ++#define ISCSI_MAX_R2T (1ULL << ISCSI_PARAM_MAX_R2T) ++#define ISCSI_IMM_DATA_EN (1ULL << ISCSI_PARAM_IMM_DATA_EN) ++#define ISCSI_FIRST_BURST (1ULL << ISCSI_PARAM_FIRST_BURST) ++#define ISCSI_MAX_BURST (1ULL << ISCSI_PARAM_MAX_BURST) ++#define ISCSI_PDU_INORDER_EN (1ULL << ISCSI_PARAM_PDU_INORDER_EN) ++#define ISCSI_DATASEQ_INORDER_EN (1ULL << ISCSI_PARAM_DATASEQ_INORDER_EN) ++#define ISCSI_ERL (1ULL << ISCSI_PARAM_ERL) ++#define ISCSI_IFMARKER_EN (1ULL << ISCSI_PARAM_IFMARKER_EN) ++#define ISCSI_OFMARKER_EN (1ULL << ISCSI_PARAM_OFMARKER_EN) ++#define ISCSI_EXP_STATSN (1ULL << ISCSI_PARAM_EXP_STATSN) ++#define ISCSI_TARGET_NAME (1ULL << ISCSI_PARAM_TARGET_NAME) ++#define ISCSI_TPGT (1ULL << ISCSI_PARAM_TPGT) ++#define ISCSI_PERSISTENT_ADDRESS (1ULL << ISCSI_PARAM_PERSISTENT_ADDRESS) ++#define ISCSI_PERSISTENT_PORT (1ULL << ISCSI_PARAM_PERSISTENT_PORT) ++#define ISCSI_SESS_RECOVERY_TMO (1ULL << ISCSI_PARAM_SESS_RECOVERY_TMO) ++#define ISCSI_CONN_PORT (1ULL << ISCSI_PARAM_CONN_PORT) ++#define ISCSI_CONN_ADDRESS (1ULL << ISCSI_PARAM_CONN_ADDRESS) ++#define ISCSI_USERNAME (1ULL << ISCSI_PARAM_USERNAME) ++#define ISCSI_USERNAME_IN (1ULL << ISCSI_PARAM_USERNAME_IN) ++#define ISCSI_PASSWORD (1ULL << ISCSI_PARAM_PASSWORD) ++#define ISCSI_PASSWORD_IN (1ULL << ISCSI_PARAM_PASSWORD_IN) ++#define ISCSI_FAST_ABORT (1ULL << ISCSI_PARAM_FAST_ABORT) ++#define ISCSI_ABORT_TMO (1ULL << ISCSI_PARAM_ABORT_TMO) ++#define ISCSI_LU_RESET_TMO (1ULL << ISCSI_PARAM_LU_RESET_TMO) ++#define ISCSI_HOST_RESET_TMO (1ULL << ISCSI_PARAM_HOST_RESET_TMO) ++#define ISCSI_PING_TMO (1ULL << ISCSI_PARAM_PING_TMO) ++#define ISCSI_RECV_TMO (1ULL << ISCSI_PARAM_RECV_TMO) ++#define ISCSI_IFACE_NAME (1ULL << ISCSI_PARAM_IFACE_NAME) ++#define ISCSI_ISID (1ULL << ISCSI_PARAM_ISID) /* iSCSI HBA params */ enum iscsi_host_param { -@@ -311,6 +331,7 @@ enum iscsi_host_param { +@@ -276,10 +302,10 @@ enum iscsi_host_param { + ISCSI_HOST_PARAM_MAX, + }; + +-#define ISCSI_HOST_HWADDRESS (1 << ISCSI_HOST_PARAM_HWADDRESS) +-#define ISCSI_HOST_INITIATOR_NAME (1 << ISCSI_HOST_PARAM_INITIATOR_NAME) +-#define ISCSI_HOST_NETDEV_NAME (1 << ISCSI_HOST_PARAM_NETDEV_NAME) +-#define ISCSI_HOST_IPADDRESS (1 << ISCSI_HOST_PARAM_IPADDRESS) ++#define ISCSI_HOST_HWADDRESS (1ULL << ISCSI_HOST_PARAM_HWADDRESS) ++#define ISCSI_HOST_INITIATOR_NAME (1ULL << ISCSI_HOST_PARAM_INITIATOR_NAME) ++#define ISCSI_HOST_NETDEV_NAME (1ULL << ISCSI_HOST_PARAM_NETDEV_NAME) ++#define ISCSI_HOST_IPADDRESS (1ULL << ISCSI_HOST_PARAM_IPADDRESS) + + #define iscsi_ptr(_handle) ((void*)(unsigned long)_handle) + #define iscsi_handle(_ptr) ((uint64_t)(unsigned long)_ptr) +@@ -311,6 +337,7 @@ enum iscsi_host_param { * These flags describes reason of stop_conn() call */ #define STOP_CONN_TERM 0x1 @@ -622,7 +1353,7 @@ index 8458425..7ad582e 100644 #define ISCSI_STATS_CUSTOM_MAX 32 diff --git a/include/iscsi_proto.h b/include/iscsi_proto.h -index 059fd74..6256e37 100644 +index 059fd74..916c02c 100644 --- a/include/iscsi_proto.h +++ b/include/iscsi_proto.h @@ -21,13 +21,15 @@ @@ -642,6 +1373,17 @@ index 059fd74..6256e37 100644 /* * useful common(control and data pathes) macro +@@ -58,8 +60,8 @@ + /* initiator tags; opaque for target */ + typedef uint32_t __bitwise__ itt_t; + /* below makes sense only for initiator that created this tag */ +-#define build_itt(itt, id, age) ((__force itt_t)\ +- ((itt) | ((id) << ISCSI_CID_SHIFT) | ((age) << ISCSI_AGE_SHIFT))) ++#define build_itt(itt, age) ((__force itt_t)\ ++ ((itt) | ((age) << ISCSI_AGE_SHIFT))) + #define get_itt(itt) ((__force uint32_t)(itt_t)(itt) & ISCSI_ITT_MASK) + #define RESERVED_ITT ((__force itt_t)0xffffffff) + @@ -162,6 +164,14 @@ struct iscsi_rlength_ahdr { __be32 read_length; }; @@ -771,16 +1513,16 @@ index e319924..0000000 - #define ISCSI_CONN_ATTRS 6 diff --git a/kernel/2.6.14-19_compat.patch b/kernel/2.6.14-19_compat.patch new file mode 100644 -index 0000000..51991c1 +index 0000000..4d66655 --- /dev/null +++ b/kernel/2.6.14-19_compat.patch -@@ -0,0 +1,498 @@ +@@ -0,0 +1,589 @@ +diff --git a/iscsi_compat.h b/iscsi_compat.h +new file mode 100644 -+index 0000000..22e7c44 ++index 0000000..965157a +--- /dev/null ++++ b/iscsi_compat.h -+@@ -0,0 +1,181 @@ ++@@ -0,0 +1,192 @@ ++#include ++#include ++#include @@ -912,6 +1654,14 @@ index 0000000..51991c1 ++ ++#endif ++ +++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +++ +++static inline int is_power_of_2(unsigned long n) +++{ +++ return (n != 0 && ((n & (n - 1)) == 0)); +++} +++#endif +++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) ++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \ ++ netlink_kernel_create(uint, groups, input, mod) @@ -927,6 +1677,9 @@ index 0000000..51991c1 ++ return sg + 1; ++} ++ +++#define for_each_sg(sglist, sg, nr, __i) \ +++ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) +++ ++#define sg_page(_sg) _sg->page ++ ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, @@ -963,7 +1716,7 @@ index 0000000..51991c1 ++ ++#endif +diff --git a/iscsi_tcp.c b/iscsi_tcp.c -+index cc075bc..af93a6c 100644 ++index 0d21d87..16908b6 100644 +--- a/iscsi_tcp.c ++++ b/iscsi_tcp.c +@@ -43,6 +43,7 @@ @@ -974,7 +1727,7 @@ index 0000000..51991c1 + + MODULE_AUTHOR("Dmitry Yusupov , " + "Alex Aizman "); -+@@ -421,6 +422,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, ++@@ -422,6 +423,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, + + debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", + offset, size); @@ -984,49 +1737,42 @@ index 0000000..51991c1 ++ * or scsi-ml commands. ++ */ ++ if (!sg_count) { -++ iscsi_segment_init_linear(segment, (void *)sg + offset, +++ iscsi_segment_init_linear(segment, (void *)sg_list + offset, ++ size, done, hash); ++ return 0; ++ } ++ + __iscsi_segment_init(segment, size, done, hash); -+ for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { ++ for_each_sg(sg_list, sg, sg_count, i) { + debug_scsi("sg %d, len %u offset %u\n", i, sg->length, -+@@ -1934,7 +1946,9 @@ static struct scsi_host_template iscsi_sht = { -+ .eh_device_reset_handler= iscsi_eh_device_reset, -+ .eh_host_reset_handler = iscsi_eh_host_reset, -+ .use_clustering = DISABLE_CLUSTERING, -++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -+ .use_sg_chaining = ENABLE_SG_CHAINING, -++#endif -+ .slave_configure = iscsi_tcp_slave_configure, -+ .proc_name = "iscsi_tcp", -+ .this_id = -1, +diff --git a/iscsi_tcp.h b/iscsi_tcp.h -+index 57c2317..783e448 100644 ++index 950d75f..662ddab 100644 +--- a/iscsi_tcp.h ++++ b/iscsi_tcp.h -+@@ -27,6 +27,7 @@ -+ #define ISCSI_SG_TABLESIZE SG_ALL -+ #define ISCSI_TCP_MAX_CMD_LEN 16 ++@@ -24,6 +24,7 @@ ++ ++ #include "libiscsi.h" + ++#include "iscsi_compat.h" + struct crypto_hash; + struct socket; + struct iscsi_tcp_conn; +diff --git a/libiscsi.c b/libiscsi.c -+index d175f14..da0dd4e 100644 ++index 31b6477..e89b92a 100644 +--- a/libiscsi.c ++++ b/libiscsi.c -+@@ -24,6 +24,7 @@ ++@@ -24,7 +24,10 @@ + #include + #include + #include ++#include +++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) ++ #include +++#endif + #include + #include + #include -+@@ -976,10 +977,9 @@ again: ++@@ -971,10 +974,9 @@ again: + return rc; + } + @@ -1039,7 +1785,7 @@ index 0000000..51991c1 + int rc; + /* + * serialize Xmit worker on a per-connection basis. -+@@ -1727,7 +1727,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit, ++@@ -1732,7 +1734,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit, + shost->max_cmd_len = iscsit->max_cmd_len; + shost->transportt = scsit; + shost->transportt->create_work_queue = 1; @@ -1049,7 +1795,7 @@ index 0000000..51991c1 + *hostno = shost->host_no; + + session = iscsi_hostdata(shost->hostdata); -+@@ -1877,7 +1879,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) ++@@ -1882,7 +1886,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) + INIT_LIST_HEAD(&conn->mgmtqueue); + INIT_LIST_HEAD(&conn->xmitqueue); + INIT_LIST_HEAD(&conn->requeue); @@ -1059,7 +1805,7 @@ index 0000000..51991c1 + /* allocate login_mtask used for the login/text sequences */ + spin_lock_bh(&session->lock); +diff --git a/libiscsi.h b/libiscsi.h -+index 8328bc7..028b5df 100644 ++index 6f10518..61be101 100644 +--- a/libiscsi.h ++++ b/libiscsi.h +@@ -24,12 +24,14 @@ @@ -1080,7 +1826,7 @@ index 0000000..51991c1 + struct scsi_device; + struct Scsi_Host; +diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c -+index 7e5e168..65541bb 100644 ++index e8f8cf1..3c7878d 100644 +--- a/scsi_transport_iscsi.c ++++ b/scsi_transport_iscsi.c +@@ -21,7 +21,10 @@ @@ -1100,12 +1846,25 @@ index 0000000..51991c1 + #include "iscsi_if.h" ++#include "iscsi_compat.h" + -+ #define ISCSI_SESSION_ATTRS 18 -+ #define ISCSI_CONN_ATTRS 11 -+@@ -254,11 +258,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, ++ #define ISCSI_SESSION_ATTRS 19 ++ #define ISCSI_CONN_ATTRS 13 ++@@ -322,10 +326,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, + return 0; + } + ++-static void iscsi_scan_session(struct work_struct *work) +++static void iscsi_scan_session(void *data) ++ { ++- struct iscsi_cls_session *session = ++- container_of(work, struct iscsi_cls_session, scan_work); +++ struct iscsi_cls_session *session = data; ++ struct Scsi_Host *shost = iscsi_session_to_shost(session); ++ struct iscsi_host *ihost = shost->shost_data; ++ unsigned long flags; ++@@ -343,11 +346,9 @@ done: ++ atomic_dec(&ihost->nr_scans); ++ } ++ +-static void session_recovery_timedout(struct work_struct *work) ++static void session_recovery_timedout(void *data) + { @@ -1113,10 +1872,51 @@ index 0000000..51991c1 +- container_of(work, struct iscsi_cls_session, +- recovery_work.work); ++ struct iscsi_cls_session *session = data; ++ unsigned long flags; + -+ dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " -+ "out after %d secs\n", session->recovery_tmo); -+@@ -285,11 +287,9 @@ void iscsi_block_session(struct iscsi_cls_session *session) ++ iscsi_cls_session_printk(KERN_INFO, session, ++@@ -373,11 +374,9 @@ static void session_recovery_timedout(struct work_struct *work) ++ scsi_target_unblock(&session->dev); ++ } ++ ++-static void __iscsi_unblock_session(struct work_struct *work) +++static void __iscsi_unblock_session(void *data) ++ { ++- struct iscsi_cls_session *session = ++- container_of(work, struct iscsi_cls_session, ++- unblock_work); +++ struct iscsi_cls_session *session = data; ++ struct Scsi_Host *shost = iscsi_session_to_shost(session); ++ struct iscsi_host *ihost = shost->shost_data; ++ unsigned long flags; ++@@ -397,10 +396,12 @@ static void __iscsi_unblock_session(struct work_struct *work) ++ * the async scanning code (drivers like iscsi_tcp do login and ++ * scanning from userspace). ++ */ +++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) ++ if (shost->hostt->scan_finished) { ++ if (queue_work(ihost->scan_workq, &session->scan_work)) ++ atomic_inc(&ihost->nr_scans); ++ } +++#endif ++ } ++ ++ /** ++@@ -420,11 +421,9 @@ void iscsi_unblock_session(struct iscsi_cls_session *session) ++ } ++ EXPORT_SYMBOL_GPL(iscsi_unblock_session); ++ ++-static void __iscsi_block_session(struct work_struct *work) +++static void __iscsi_block_session(void *data) ++ { ++- struct iscsi_cls_session *session = ++- container_of(work, struct iscsi_cls_session, ++- block_work); +++ struct iscsi_cls_session *session = data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&session->lock, flags); ++@@ -441,11 +440,9 @@ void iscsi_block_session(struct iscsi_cls_session *session) + } + EXPORT_SYMBOL_GPL(iscsi_block_session); + @@ -1130,20 +1930,35 @@ index 0000000..51991c1 + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + -+@@ -327,10 +327,10 @@ iscsi_alloc_session(struct Scsi_Host *shost, -+ ++@@ -484,13 +481,13 @@ iscsi_alloc_session(struct Scsi_Host *shost, + session->transport = transport; + session->recovery_tmo = 120; ++ session->state = ISCSI_SESSION_FREE; +- INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); ++ INIT_WORK(&session->recovery_work, session_recovery_timedout, session); + INIT_LIST_HEAD(&session->host_list); + INIT_LIST_HEAD(&session->sess_list); ++- INIT_WORK(&session->unblock_work, __iscsi_unblock_session); ++- INIT_WORK(&session->block_work, __iscsi_block_session); +- INIT_WORK(&session->unbind_work, __iscsi_unbind_session); ++- INIT_WORK(&session->scan_work, iscsi_scan_session); +++ INIT_WORK(&session->unblock_work, __iscsi_unblock_session, session); +++ INIT_WORK(&session->block_work, __iscsi_block_session, session); ++ INIT_WORK(&session->unbind_work, __iscsi_unbind_session, session); +++ INIT_WORK(&session->scan_work, iscsi_scan_session, session); ++ spin_lock_init(&session->lock); + + /* this is released in the dev's release function */ -+ scsi_host_get(shost); -+@@ -1123,45 +1123,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ++@@ -619,7 +616,7 @@ void iscsi_remove_session(struct iscsi_cls_session *session) ++ scsi_target_unblock(&session->dev); ++ /* flush running scans then delete devices */ ++ flush_workqueue(ihost->scan_workq); ++- __iscsi_unbind_session(&session->unbind_work); +++ __iscsi_unbind_session(session); ++ ++ /* hw iscsi may not have removed all connections from session */ ++ err = device_for_each_child(&session->dev, NULL, ++@@ -1294,45 +1291,56 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + * Malformed skbs with wrong lengths or invalid creds are not processed. + */ + static void @@ -1233,7 +2048,7 @@ index 0000000..51991c1 + } + mutex_unlock(&rx_queue_mutex); + } -+@@ -1396,7 +1407,10 @@ iscsi_register_transport(struct iscsi_transport *tt) ++@@ -1576,7 +1584,10 @@ iscsi_register_transport(struct iscsi_transport *tt) + INIT_LIST_HEAD(&priv->list); + priv->daemon_pid = -1; + priv->iscsi_transport = tt; @@ -1244,8 +2059,26 @@ index 0000000..51991c1 + + priv->cdev.class = &iscsi_transport_class; + snprintf(priv->cdev.class_id, BUS_ID_SIZE, "%s", tt->name); ++@@ -1738,7 +1749,7 @@ static __init int iscsi_transport_init(void) ++ return 0; ++ ++ release_nls: ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ unregister_session_class: ++ transport_class_unregister(&iscsi_session_class); ++ unregister_conn_class: ++@@ -1753,7 +1764,7 @@ unregister_transport_class: ++ static void __exit iscsi_transport_exit(void) ++ { ++ destroy_workqueue(iscsi_eh_timer_workq); ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ transport_class_unregister(&iscsi_connection_class); ++ transport_class_unregister(&iscsi_session_class); ++ transport_class_unregister(&iscsi_host_class); +diff --git a/scsi_transport_iscsi.h b/scsi_transport_iscsi.h -+index 6bda9b9..deaa582 100644 ++index 3492abe..faa435c 100644 +--- a/scsi_transport_iscsi.h ++++ b/scsi_transport_iscsi.h +@@ -25,8 +25,12 @@ @@ -1261,17 +2094,17 @@ index 0000000..51991c1 + + struct scsi_transport_template; + struct iscsi_transport; -+@@ -185,7 +189,7 @@ struct iscsi_cls_session { ++@@ -184,7 +188,7 @@ struct iscsi_cls_session { + + /* recovery fields */ + int recovery_tmo; +- struct delayed_work recovery_work; ++ struct work_struct recovery_work; -+ struct work_struct unbind_work; + + int target_id; ++ +-- -+1.5.1.2 ++1.5.4.1 + diff --git a/kernel/2.6.14-and-2.6.15-compat.patch b/kernel/2.6.14-and-2.6.15-compat.patch deleted file mode 100644 @@ -1612,22 +2445,31 @@ index d743d08..0000000 - int target_id; diff --git a/kernel/2.6.20-21_compat.patch b/kernel/2.6.20-21_compat.patch new file mode 100644 -index 0000000..da20259 +index 0000000..9c3e3b3 --- /dev/null +++ b/kernel/2.6.20-21_compat.patch -@@ -0,0 +1,248 @@ +@@ -0,0 +1,278 @@ +diff --git a/iscsi_2.6.22_compat.h b/iscsi_2.6.22_compat.h +new file mode 100644 -+index 0000000..f2693f1 ++index 0000000..2ba7deb +--- /dev/null ++++ b/iscsi_2.6.22_compat.h -+@@ -0,0 +1,73 @@ ++@@ -0,0 +1,85 @@ ++#include ++#include ++ ++#ifndef ISCSI_2622_COMPAT_H ++#define ISCSI_2622_COMPAT_H ++ +++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20) +++ +++static inline __attribute__((const)) +++bool is_power_of_2(unsigned long n) +++{ +++ return (n != 0 && ((n & (n - 1)) == 0)); +++} +++#endif +++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21) ++ ++#define netlink_kernel_create(net, uint, groups, input, cb_mutex, mod) \ @@ -1662,6 +2504,9 @@ index 0000000..da20259 ++ return sg + 1; ++} ++ +++#define for_each_sg(sglist, sg, nr, __i) \ +++ for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) +++ ++#define sg_page(_sg) _sg->page ++ ++static inline void sg_set_page(struct scatterlist *sg, struct page *page, @@ -1696,10 +2541,10 @@ index 0000000..da20259 ++ ++#endif +diff --git a/iscsi_tcp.c b/iscsi_tcp.c -+index cc075bc..156f87e 100644 ++index 0d21d87..b24e533 100644 +--- a/iscsi_tcp.c ++++ b/iscsi_tcp.c -+@@ -421,6 +421,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, ++@@ -422,6 +422,17 @@ iscsi_segment_seek_sg(struct iscsi_segment *segment, + + debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", + offset, size); @@ -1709,38 +2554,38 @@ index 0000000..da20259 ++ * or scsi-ml commands. ++ */ ++ if (!sg_count) { -++ iscsi_segment_init_linear(segment, (void *)sg + offset, +++ iscsi_segment_init_linear(segment, (void *)sg_list + offset, ++ size, done, hash); ++ return 0; ++ } ++ + __iscsi_segment_init(segment, size, done, hash); -+ for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { ++ for_each_sg(sg_list, sg, sg_count, i) { + debug_scsi("sg %d, len %u offset %u\n", i, sg->length, -+@@ -1934,7 +1945,9 @@ static struct scsi_host_template iscsi_sht = { ++@@ -1936,6 +1947,9 @@ static struct scsi_host_template iscsi_sht = { + .eh_device_reset_handler= iscsi_eh_device_reset, + .eh_host_reset_handler = iscsi_eh_host_reset, + .use_clustering = DISABLE_CLUSTERING, -++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -+ .use_sg_chaining = ENABLE_SG_CHAINING, +++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24) +++ .use_sg_chaining = ENABLE_SG_CHAINING, ++#endif + .slave_configure = iscsi_tcp_slave_configure, + .proc_name = "iscsi_tcp", + .this_id = -1, +diff --git a/iscsi_tcp.h b/iscsi_tcp.h -+index 57c2317..0b706a3 100644 ++index 950d75f..a7bc56f 100644 +--- a/iscsi_tcp.h ++++ b/iscsi_tcp.h -+@@ -27,6 +27,7 @@ -+ #define ISCSI_SG_TABLESIZE SG_ALL -+ #define ISCSI_TCP_MAX_CMD_LEN 16 ++@@ -24,6 +24,7 @@ ++ ++ #include "libiscsi.h" + ++#include "iscsi_2.6.22_compat.h" + struct crypto_hash; + struct socket; + struct iscsi_tcp_conn; +diff --git a/libiscsi.h b/libiscsi.h -+index 8328bc7..fbe14c0 100644 ++index 6f10518..995852f 100644 +--- a/libiscsi.h ++++ b/libiscsi.h +@@ -30,6 +30,8 @@ @@ -1753,7 +2598,7 @@ index 0000000..da20259 + struct scsi_device; + struct Scsi_Host; +diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c -+index 7e5e168..dbe94cc 100644 ++index e8f8cf1..0ab82de 100644 +--- a/scsi_transport_iscsi.c ++++ b/scsi_transport_iscsi.c +@@ -29,6 +29,7 @@ @@ -1762,9 +2607,9 @@ index 0000000..da20259 + #include "iscsi_if.h" ++#include "iscsi_2.6.22_compat.h" + -+ #define ISCSI_SESSION_ATTRS 18 -+ #define ISCSI_CONN_ATTRS 11 -+@@ -1119,49 +1120,61 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) ++ #define ISCSI_SESSION_ATTRS 19 ++ #define ISCSI_CONN_ATTRS 13 ++@@ -1290,49 +1291,61 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) + } + + /* @@ -1861,14 +2706,82 @@ index 0000000..da20259 + } + mutex_unlock(&rx_queue_mutex); + } ++@@ -1738,7 +1751,7 @@ static __init int iscsi_transport_init(void) ++ return 0; ++ ++ release_nls: ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ unregister_session_class: ++ transport_class_unregister(&iscsi_session_class); ++ unregister_conn_class: ++@@ -1753,7 +1766,7 @@ unregister_transport_class: ++ static void __exit iscsi_transport_exit(void) ++ { ++ destroy_workqueue(iscsi_eh_timer_workq); ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ transport_class_unregister(&iscsi_connection_class); ++ transport_class_unregister(&iscsi_session_class); ++ transport_class_unregister(&iscsi_host_class); +-- -+1.5.1.2 ++1.5.4.1 + +diff --git a/kernel/2.6.24_compat.patch b/kernel/2.6.24_compat.patch +new file mode 100644 +index 0000000..4cbb173 +--- /dev/null ++++ b/kernel/2.6.24_compat.patch +@@ -0,0 +1,44 @@ ++diff --git a/iscsi_tcp.c b/iscsi_tcp.c ++index 0d21d87..ed5cdfa 100644 ++--- a/iscsi_tcp.c +++++ b/iscsi_tcp.c ++@@ -26,6 +26,7 @@ ++ * Zhenyu Wang ++ */ ++ +++#include ++ #include ++ #include ++ #include ++@@ -1936,6 +1937,9 @@ static struct scsi_host_template iscsi_sht = { ++ .eh_device_reset_handler= iscsi_eh_device_reset, ++ .eh_host_reset_handler = iscsi_eh_host_reset, ++ .use_clustering = DISABLE_CLUSTERING, +++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,24) +++ .use_sg_chaining = ENABLE_SG_CHAINING, +++#endif ++ .slave_configure = iscsi_tcp_slave_configure, ++ .proc_name = "iscsi_tcp", ++ .this_id = -1, ++diff --git a/scsi_transport_iscsi.c b/scsi_transport_iscsi.c ++index e8f8cf1..7c19201 100644 ++--- a/scsi_transport_iscsi.c +++++ b/scsi_transport_iscsi.c ++@@ -1738,7 +1738,7 @@ static __init int iscsi_transport_init(void) ++ return 0; ++ ++ release_nls: ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ unregister_session_class: ++ transport_class_unregister(&iscsi_session_class); ++ unregister_conn_class: ++@@ -1753,7 +1753,7 @@ unregister_transport_class: ++ static void __exit iscsi_transport_exit(void) ++ { ++ destroy_workqueue(iscsi_eh_timer_workq); ++- netlink_kernel_release(nls); +++ sock_release(nls->sk_socket); ++ transport_class_unregister(&iscsi_connection_class); ++ transport_class_unregister(&iscsi_session_class); ++ transport_class_unregister(&iscsi_host_class); diff --git a/kernel/Makefile b/kernel/Makefile -index 199241b..2ec194d 100644 +index 199241b..7281a60 100644 --- a/kernel/Makefile +++ b/kernel/Makefile -@@ -48,11 +48,9 @@ all: kernel_check +@@ -48,11 +48,10 @@ all: kernel_check # form. #some constants @@ -1879,11 +2792,12 @@ index 199241b..2ec194d 100644 -all_patches=13_patch 14to15_patch 16to18_patch 19_patch +14to19_patch=2.6.14-19_compat.patch +20to21_patch=2.6.20-21_compat.patch -+all_patches=14to21_patch 20to21_patch ++24_patch=2.6.24_compat.patch ++all_patches=14to21_patch 20to21_patch 24_patch cur_patched=cur_patched ## fun stuff for maintaining multiple versions -@@ -66,67 +64,52 @@ KSUBLEVEL = $(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | +@@ -66,67 +65,63 @@ KSUBLEVEL = $(shell cat $(KSRC)/Makefile | awk -F= '/^SUBLEVEL =/ {print $$2}' | KERNEL_TARGET=linux_2_6_$(KSUBLEVEL) kernel_check: $(KERNEL_TARGET) @@ -1916,7 +2830,9 @@ index 199241b..2ec194d 100644 -linux_2_6_21: $(unpatch_code) +linux_2_6_23: has_20to21_patch + -+linux_2_6_24: $(unpatch_code) ++linux_2_6_24: has_24_patch ++ ++linux_2_6_25: $(unpatch_code) do_unpatch_code: - echo "Un-patching source code for use with linux-2.6.20 and up ..." @@ -1929,51 +2845,65 @@ index 199241b..2ec194d 100644 # otherwise below compat_patch: target will not work -has_13_patch: $(13_patch) - echo "Patching source code for linux-2.6.13 ..." -- if [ -e $(cur_patched) ]; then \ -- make -C . clean; \ -- fi -- patch -p1 < $(13_patch) -- cp $(13_patch) $@ -- ln -s $@ $(cur_patched) -- --has_14to15_patch: $(14to15_patch) -- echo "Patching source code for linux-2.6.14-15 ..." -- if [ -e $(cur_patched) ]; then \ -- make -C . clean; \ -- fi -- patch -p1 < $(14to15_patch) -- cp $(14to15_patch) $@ -- ln -s $@ $(cur_patched) -- --has_16to18_patch: $(16to18_patch) -- echo "Patching source code for linux-2.6.16-18 ..." +has_14to19_patch: $(14to19_patch) + echo "Patching source code for linux-2.6.14-19 ..." if [ -e $(cur_patched) ]; then \ make -C . clean; \ fi -- patch -p1 < $(16to18_patch) -- cp $(16to18_patch) $@ +- patch -p1 < $(13_patch) +- cp $(13_patch) $@ + patch -p1 < $(14to19_patch) + cp $(14to19_patch) $@ ln -s $@ $(cur_patched) --has_19_patch: $(19_patch) -- echo "Patching source code for linux-2.6.19 ..." +-has_14to15_patch: $(14to15_patch) +- echo "Patching source code for linux-2.6.14-15 ..." +has_20to21_patch: $(20to21_patch) + echo "Patching source code for linux-2.6.20-21 ..." if [ -e $(cur_patched) ]; then \ make -C . clean; \ fi -- patch -p1 < $(19_patch) -- cp $(19_patch) $@ +- patch -p1 < $(14to15_patch) +- cp $(14to15_patch) $@ + patch -p1 < $(20to21_patch) + cp $(20to21_patch) $@ ln -s $@ $(cur_patched) +-has_16to18_patch: $(16to18_patch) +- echo "Patching source code for linux-2.6.16-18 ..." ++has_24_patch: $(24_patch) ++ echo "Patching source code for linux-2.6.24 ..." + if [ -e $(cur_patched) ]; then \ + make -C . clean; \ + fi +- patch -p1 < $(16to18_patch) +- cp $(16to18_patch) $@ +- ln -s $@ $(cur_patched) +- +-has_19_patch: $(19_patch) +- echo "Patching source code for linux-2.6.19 ..." +- if [ -e $(cur_patched) ]; then \ +- make -C . clean; \ +- fi +- patch -p1 < $(19_patch) +- cp $(19_patch) $@ ++ patch -p1 < $(24_patch) ++ cp $(24_patch) $@ + ln -s $@ $(cur_patched) + # ============ END code for kernel_check and source patching ================= +@@ -173,4 +168,9 @@ $(ko): all + install_kernel: $(ko) + $(KBUILD_BASE) modules_install INSTALL_MOD_DIR=$(INSTALL_MOD_DIR) INSTALL_MOD_PATH=$(INSTALL_MOD_PATH) + ++dpkg_divert: ++ for module in $(ko) ; do \ ++ dpkg-divert --rename /lib/modules/$(KERNELRELEASE)/$(INSTALL_MOD_DIR)/$$module ; \ ++ done ++ + # vim: ft=make tw=72 sw=4 ts=4: diff --git a/kernel/iscsi_tcp.c b/kernel/iscsi_tcp.c -index 7f7a919..cc075bc 100644 +index 7f7a919..daabd46 100644 --- a/kernel/iscsi_tcp.c +++ b/kernel/iscsi_tcp.c @@ -48,7 +48,7 @@ MODULE_AUTHOR("Dmitry Yusupov , " @@ -1985,7 +2915,7 @@ index 7f7a919..cc075bc 100644 #define DEBUG_ASSERT #ifdef DEBUG_TCP -@@ -67,118 +67,428 @@ MODULE_LICENSE("GPL"); +@@ -67,118 +67,429 @@ MODULE_LICENSE("GPL"); static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); @@ -2355,7 +3285,13 @@ index 7f7a919..cc075bc 100644 + sg_init_one(&sg, hdr, hdrlen); + crypto_hash_digest(hash, &sg, hdrlen, digest); +} -+ + +- tcp_conn->in.offset += copylen; +- tcp_conn->in.copy -= copylen; +- if (copylen < hdr_remains) { +- tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER; +- tcp_conn->in.hdr_offset += copylen; +- return -EAGAIN; +static inline int +iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, + struct iscsi_segment *segment) @@ -2398,25 +3334,20 @@ index 7f7a919..cc075bc 100644 + segment->data = data; + segment->size = size; +} - -- tcp_conn->in.offset += copylen; -- tcp_conn->in.copy -= copylen; -- if (copylen < hdr_remains) { -- tcp_conn->in_progress = IN_PROGRESS_HEADER_GATHER; -- tcp_conn->in.hdr_offset += copylen; -- return -EAGAIN; ++ +static inline int +iscsi_segment_seek_sg(struct iscsi_segment *segment, -+ struct scatterlist *sg, unsigned int sg_count, ++ struct scatterlist *sg_list, unsigned int sg_count, + unsigned int offset, size_t size, + iscsi_segment_done_fn_t *done, struct hash_desc *hash) +{ ++ struct scatterlist *sg; + unsigned int i; + + debug_scsi("iscsi_segment_seek_sg offset %u size %llu\n", + offset, size); + __iscsi_segment_init(segment, size, done, hash); -+ for (i = 0; i < sg_count; i++, sg = sg_next(sg)) { ++ for_each_sg(sg_list, sg, sg_count, i) { + debug_scsi("sg %d, len %u offset %u\n", i, sg->length, + sg->offset); + if (offset < sg->length) { @@ -2489,7 +3420,7 @@ index 7f7a919..cc075bc 100644 /* * must be called with session lock */ -@@ -187,7 +497,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +@@ -187,7 +498,6 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) { struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; struct iscsi_r2t_info *r2t; @@ -2497,7 +3428,7 @@ index 7f7a919..cc075bc 100644 /* flush ctask's r2t queues */ while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { -@@ -196,12 +505,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +@@ -196,12 +506,12 @@ iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); } @@ -2516,7 +3447,7 @@ index 7f7a919..cc075bc 100644 } /** -@@ -220,11 +529,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +@@ -220,11 +530,6 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) int datasn = be32_to_cpu(rhdr->datasn); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); @@ -2528,7 +3459,7 @@ index 7f7a919..cc075bc 100644 if (tcp_conn->in.datalen == 0) return 0; -@@ -237,30 +541,28 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +@@ -237,30 +542,28 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn++; tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); @@ -2569,7 +3500,7 @@ index 7f7a919..cc075bc 100644 } conn->datain_pdus_cnt++; -@@ -284,7 +586,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, +@@ -284,7 +587,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, struct iscsi_r2t_info *r2t) { struct iscsi_data *hdr; @@ -2577,7 +3508,7 @@ index 7f7a919..cc075bc 100644 hdr = &r2t->dtask.hdr; memset(hdr, 0, sizeof(struct iscsi_data)); -@@ -308,43 +609,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, +@@ -308,43 +610,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, conn->dataout_pdus_cnt++; r2t->sent = 0; @@ -2621,43 +3552,70 @@ index 7f7a919..cc075bc 100644 } /** -@@ -379,8 +643,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) - spin_lock(&session->lock); +@@ -364,8 +629,9 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) + int rc; + + if (tcp_conn->in.datalen) { +- printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n", +- tcp_conn->in.datalen); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "invalid R2t with datalen %d\n", ++ tcp_conn->in.datalen); + return ISCSI_ERR_DATALEN; + } + +@@ -376,14 +642,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) + } + + /* fill-in new R2T associated with the task */ +- spin_lock(&session->lock); iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - if (!ctask->sc || ctask->mtask || - session->state != ISCSI_STATE_LOGGED_IN) { +- printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " +- "recovery...\n", ctask->itt); +- spin_unlock(&session->lock); + if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { - printk(KERN_INFO "iscsi_tcp: dropping R2T itt %d in " - "recovery...\n", ctask->itt); - spin_unlock(&session->lock); -@@ -394,6 +657,8 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) ++ iscsi_conn_printk(KERN_INFO, conn, ++ "dropping R2T itt %d in recovery.\n", ++ ctask->itt); + return 0; + } + +@@ -393,8 +657,10 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) + r2t->exp_statsn = rhdr->statsn; r2t->data_length = be32_to_cpu(rhdr->data_length); if (r2t->data_length == 0) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); +- printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n"); +- spin_unlock(&session->lock); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "invalid R2T with zero data len\n"); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); - spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } -@@ -404,11 +669,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) + +@@ -404,11 +670,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) r2t->data_length, session->max_burst); r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > ctask->sc->request_bufflen) { - spin_unlock(&session->lock); -+ if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { - printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " - "offset %u and total length %d\n", r2t->data_length, +- printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at " +- "offset %u and total length %d\n", r2t->data_length, - r2t->data_offset, ctask->sc->request_bufflen); -+ r2t->data_offset, scsi_bufflen(ctask->sc)); ++ if (r2t->data_offset + r2t->data_length > scsi_bufflen(ctask->sc)) { ++ iscsi_conn_printk(KERN_ERR, conn, ++ "invalid R2T with data len %u at offset %u " ++ "and total length %d\n", r2t->data_length, ++ r2t->data_offset, scsi_bufflen(ctask->sc)); + __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, + sizeof(void*)); -+ spin_unlock(&session->lock); return ISCSI_ERR_DATALEN; } -@@ -419,26 +686,57 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) +@@ -419,106 +687,131 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) tcp_ctask->exp_datasn = r2tsn + 1; __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); @@ -2666,10 +3624,9 @@ index 7f7a919..cc075bc 100644 - - scsi_queue_work(session->host, &conn->xmitwork); conn->r2t_pdus_cnt++; -+ -+ iscsi_requeue_ctask(ctask); - spin_unlock(&session->lock); +- spin_unlock(&session->lock); ++ iscsi_requeue_ctask(ctask); return 0; } @@ -2724,8 +3681,12 @@ index 7f7a919..cc075bc 100644 /* verify PDU length */ tcp_conn->in.datalen = ntoh24(hdr->dlength); -@@ -447,77 +745,68 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) - tcp_conn->in.datalen, conn->max_recv_dlength); + if (tcp_conn->in.datalen > conn->max_recv_dlength) { +- printk(KERN_ERR "iscsi_tcp: datalen %d > %d\n", +- tcp_conn->in.datalen, conn->max_recv_dlength); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "iscsi_tcp: datalen %d > %d\n", ++ tcp_conn->in.datalen, conn->max_recv_dlength); return ISCSI_ERR_DATALEN; } - tcp_conn->data_copied = 0; @@ -2787,7 +3748,9 @@ index 7f7a919..cc075bc 100644 - tcp_conn->in.ctask = session->cmds[itt]; - rc = iscsi_data_rsp(conn, tcp_conn->in.ctask); + ctask = session->cmds[itt]; ++ spin_lock(&conn->session->lock); + rc = iscsi_data_rsp(conn, ctask); ++ spin_unlock(&conn->session->lock); if (rc) return rc; + if (tcp_conn->in.datalen) { @@ -2840,22 +3803,33 @@ index 7f7a919..cc075bc 100644 - else if (tcp_conn->in.ctask->sc->sc_data_direction == - DMA_TO_DEVICE) - rc = iscsi_r2t_rsp(conn, tcp_conn->in.ctask); -+ else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) +- else ++ else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { ++ spin_lock(&session->lock); + rc = iscsi_r2t_rsp(conn, ctask); - else ++ spin_unlock(&session->lock); ++ } else rc = ISCSI_ERR_PROTO; break; -@@ -530,8 +819,7 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) + case ISCSI_OP_LOGIN_RSP: +@@ -530,18 +823,24 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) * than 8K, but there are no targets that currently do this. * For now we fail until we find a vendor that needs it */ - if (ISCSI_DEF_MAX_RECV_SEG_LEN < - tcp_conn->in.datalen) { +- printk(KERN_ERR "iscsi_tcp: received buffer of len %u " +- "but conn buffer is only %u (opcode %0x)\n", +- tcp_conn->in.datalen, +- ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - printk(KERN_ERR "iscsi_tcp: received buffer of len %u " - "but conn buffer is only %u (opcode %0x)\n", - tcp_conn->in.datalen, -@@ -540,8 +828,13 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) ++ iscsi_conn_printk(KERN_ERR, conn, ++ "iscsi_tcp: received buffer of " ++ "len %u but conn buffer is only %u " ++ "(opcode %0x)\n", ++ tcp_conn->in.datalen, ++ ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); + rc = ISCSI_ERR_PROTO; break; } @@ -2871,7 +3845,7 @@ index 7f7a919..cc075bc 100644 /* fall through */ case ISCSI_OP_LOGOUT_RSP: case ISCSI_OP_NOOP_IN: -@@ -553,480 +846,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) +@@ -553,480 +852,161 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn) break; } @@ -3448,7 +4422,7 @@ index 7f7a919..cc075bc 100644 } static void -@@ -1106,121 +1080,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn) +@@ -1106,121 +1086,173 @@ iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn) } /** @@ -3629,9 +4603,7 @@ index 7f7a919..cc075bc 100644 + +static void +iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) - { -- crypto_hash_init(&tcp_conn->tx_hash); -- tcp_ctask->digest_count = 4; ++{ + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + + debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn, @@ -3670,7 +4642,9 @@ index 7f7a919..cc075bc 100644 +iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, + unsigned int count, unsigned int offset, + unsigned int len) -+{ + { +- crypto_hash_init(&tcp_conn->tx_hash); +- tcp_ctask->digest_count = 4; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct hash_desc *tx_hash = NULL; + unsigned int hdr_spec_len; @@ -3716,7 +4690,7 @@ index 7f7a919..cc075bc 100644 } /** -@@ -1236,13 +1262,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn, +@@ -1236,13 +1268,17 @@ iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn, * * Called under connection lock. **/ @@ -3738,7 +4712,7 @@ index 7f7a919..cc075bc 100644 hdr = &r2t->dtask.hdr; memset(hdr, 0, sizeof(struct iscsi_data)); -@@ -1263,50 +1293,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, +@@ -1263,50 +1299,46 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, r2t->data_count = left; hdr->flags = ISCSI_FLAG_CMD_FINAL; } @@ -3817,7 +4791,7 @@ index 7f7a919..cc075bc 100644 } /** -@@ -1318,493 +1344,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) +@@ -1318,493 +1350,130 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask) * The function can return -EAGAIN in which case caller must * call it again later, or recover. '0' return code means successful * xmit. @@ -4203,7 +5177,7 @@ index 7f7a919..cc075bc 100644 - } - return 0; -} -- + -static int iscsi_send_sol_pdu(struct iscsi_conn *conn, - struct iscsi_cmd_task *ctask) -{ @@ -4212,7 +5186,7 @@ index 7f7a919..cc075bc 100644 - struct iscsi_r2t_info *r2t; - struct iscsi_data_task *dtask; - int left, rc; - +- - if (tcp_ctask->xmstate & XMSTATE_SOL_HDR_INIT) { - if (!tcp_ctask->r2t) { - spin_lock_bh(&session->lock); @@ -4392,7 +5366,7 @@ index 7f7a919..cc075bc 100644 } static struct iscsi_cls_conn * -@@ -1830,9 +1493,6 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) +@@ -1830,37 +1499,29 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->dd_data = tcp_conn; tcp_conn->iscsi_conn = conn; @@ -4402,7 +5376,42 @@ index 7f7a919..cc075bc 100644 tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, CRYPTO_ALG_ASYNC); -@@ -1909,11 +1569,9 @@ static void + tcp_conn->tx_hash.flags = 0; +- if (IS_ERR(tcp_conn->tx_hash.tfm)) { +- printk(KERN_ERR "Could not create connection due to crc32c " +- "loading error %ld. Make sure the crc32c module is " +- "built as a module or into the kernel\n", +- PTR_ERR(tcp_conn->tx_hash.tfm)); ++ if (IS_ERR(tcp_conn->tx_hash.tfm)) + goto free_tcp_conn; +- } + + tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, + CRYPTO_ALG_ASYNC); + tcp_conn->rx_hash.flags = 0; +- if (IS_ERR(tcp_conn->rx_hash.tfm)) { +- printk(KERN_ERR "Could not create connection due to crc32c " +- "loading error %ld. Make sure the crc32c module is " +- "built as a module or into the kernel\n", +- PTR_ERR(tcp_conn->rx_hash.tfm)); ++ if (IS_ERR(tcp_conn->rx_hash.tfm)) + goto free_tx_tfm; +- } + + return cls_conn; + + free_tx_tfm: + crypto_free_hash(tcp_conn->tx_hash.tfm); + free_tcp_conn: ++ iscsi_conn_printk(KERN_ERR, conn, ++ "Could not create connection due to crc32c " ++ "loading error. Make sure the crc32c " ++ "module is built as a module or into the " ++ "kernel\n"); + kfree(tcp_conn); + tcp_conn_alloc_fail: + iscsi_conn_teardown(cls_conn); +@@ -1909,11 +1570,9 @@ static void iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) { struct iscsi_conn *conn = cls_conn->dd_data; @@ -4414,7 +5423,7 @@ index 7f7a919..cc075bc 100644 } static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, -@@ -1926,7 +1584,7 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, +@@ -1926,7 +1585,7 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, struct sockaddr_in *sin; int rc = 0, len; @@ -4423,7 +5432,17 @@ index 7f7a919..cc075bc 100644 if (!addr) return -ENOMEM; -@@ -2013,7 +1671,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, +@@ -1970,7 +1629,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, + /* lookup for existing socket */ + sock = sockfd_lookup((int)transport_eph, &err); + if (!sock) { +- printk(KERN_ERR "iscsi_tcp: sockfd_lookup failed %d\n", err); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "sockfd_lookup failed %d\n", err); + return -EEXIST; + } + /* +@@ -2013,7 +1673,7 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, /* * set receive state machine into initial state */ @@ -4432,7 +5451,7 @@ index 7f7a919..cc075bc 100644 return 0; free_socket: -@@ -2023,10 +1681,17 @@ free_socket: +@@ -2023,10 +1683,17 @@ free_socket: /* called with host lock */ static void @@ -4453,7 +5472,7 @@ index 7f7a919..cc075bc 100644 } static int -@@ -2049,8 +1714,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) +@@ -2049,8 +1716,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) */ /* R2T pool */ @@ -4463,7 +5482,7 @@ index 7f7a919..cc075bc 100644 sizeof(struct iscsi_r2t_info))) { goto r2t_alloc_fail; } -@@ -2059,8 +1723,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) +@@ -2059,8 +1725,7 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) tcp_ctask->r2tqueue = kfifo_alloc( session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { @@ -4473,7 +5492,7 @@ index 7f7a919..cc075bc 100644 goto r2t_alloc_fail; } } -@@ -2073,8 +1736,7 @@ r2t_alloc_fail: +@@ -2073,8 +1738,7 @@ r2t_alloc_fail: struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); @@ -4483,7 +5502,7 @@ index 7f7a919..cc075bc 100644 } return -ENOMEM; } -@@ -2089,8 +1751,7 @@ iscsi_r2tpool_free(struct iscsi_session *session) +@@ -2089,8 +1753,7 @@ iscsi_r2tpool_free(struct iscsi_session *session) struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; kfifo_free(tcp_ctask->r2tqueue); @@ -4493,7 +5512,7 @@ index 7f7a919..cc075bc 100644 } } -@@ -2106,9 +1767,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, +@@ -2106,9 +1769,6 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, switch(param) { case ISCSI_PARAM_HDRDGST_EN: iscsi_set_param(cls_conn, param, buf, buflen); @@ -4503,7 +5522,23 @@ index 7f7a919..cc075bc 100644 break; case ISCSI_PARAM_DATADGST_EN: iscsi_set_param(cls_conn, param, buf, buflen); -@@ -2229,14 +1887,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, +@@ -2117,12 +1777,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, + break; + case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &value); +- if (session->max_r2t == roundup_pow_of_two(value)) ++ if (value <= 0 || !is_power_of_2(value)) ++ return -EINVAL; ++ if (session->max_r2t == value) + break; + iscsi_r2tpool_free(session); + iscsi_set_param(cls_conn, param, buf, buflen); +- if (session->max_r2t & (session->max_r2t - 1)) +- session->max_r2t = roundup_pow_of_two(session->max_r2t); + if (iscsi_r2tpool_alloc(session)) + return -ENOMEM; + break; +@@ -2229,14 +1889,15 @@ iscsi_tcp_session_create(struct iscsi_transport *iscsit, struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; @@ -4521,7 +5556,7 @@ index 7f7a919..cc075bc 100644 } if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session))) -@@ -2257,11 +1916,13 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) +@@ -2257,19 +1918,22 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) static int iscsi_tcp_slave_configure(struct scsi_device *sdev) { @@ -4535,18 +5570,17 @@ index 7f7a919..cc075bc 100644 .name = "iSCSI Initiator over TCP/IP", .queuecommand = iscsi_queuecommand, .change_queue_depth = iscsi_change_queue_depth, -@@ -2270,8 +1931,10 @@ static struct scsi_host_template iscsi_sht = { + .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, +- .sg_tablesize = ISCSI_SG_TABLESIZE, ++ .sg_tablesize = 4096, .max_sectors = 0xFFFF, .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler= iscsi_eh_device_reset, .eh_host_reset_handler = iscsi_eh_host_reset, .use_clustering = DISABLE_CLUSTERING, -+ .use_sg_chaining = ENABLE_SG_CHAINING, .slave_configure = iscsi_tcp_slave_configure, - .proc_name = "iscsi_tcp", - .this_id = -1, -@@ -2301,7 +1964,10 @@ static struct iscsi_transport iscsi_tcp_transport = { +@@ -2301,14 +1965,18 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_PERSISTENT_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT | ISCSI_USERNAME | ISCSI_PASSWORD | @@ -4554,11 +5588,20 @@ index 7f7a919..cc075bc 100644 + ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | + ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | + ISCSI_LU_RESET_TMO | -+ ISCSI_PING_TMO | ISCSI_RECV_TMO, ++ ISCSI_PING_TMO | ISCSI_RECV_TMO | ++ ISCSI_IFACE_NAME, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME | ISCSI_HOST_NETDEV_NAME, -@@ -2327,8 +1993,8 @@ static struct iscsi_transport iscsi_tcp_transport = { + .host_template = &iscsi_sht, + .conndata_size = sizeof(struct iscsi_conn), + .max_conn = 1, +- .max_cmd_len = ISCSI_TCP_MAX_CMD_LEN, ++ .max_cmd_len = 16, + /* session management */ + .create_session = iscsi_tcp_session_create, + .destroy_session = iscsi_tcp_session_destroy, +@@ -2327,8 +1995,8 @@ static struct iscsi_transport iscsi_tcp_transport = { /* IO */ .send_pdu = iscsi_conn_send_pdu, .get_stats = iscsi_conn_get_stats, @@ -4570,10 +5613,10 @@ index 7f7a919..cc075bc 100644 .xmit_mgmt_task = iscsi_tcp_mtask_xmit, .cleanup_cmd_task = iscsi_tcp_cleanup_ctask, diff --git a/kernel/iscsi_tcp.h b/kernel/iscsi_tcp.h -index 4b86fe4..57c2317 100644 +index 4b86fe4..950d75f 100644 --- a/kernel/iscsi_tcp.h +++ b/kernel/iscsi_tcp.h -@@ -24,71 +24,64 @@ +@@ -24,71 +24,61 @@ #include "libiscsi.h" @@ -4602,9 +5645,9 @@ index 4b86fe4..57c2317 100644 -#define XMSTATE_SOL_HDR_INIT 0x2000 - -#define ISCSI_PAD_LEN 4 - #define ISCSI_SG_TABLESIZE SG_ALL - #define ISCSI_TCP_MAX_CMD_LEN 16 - +-#define ISCSI_SG_TABLESIZE SG_ALL +-#define ISCSI_TCP_MAX_CMD_LEN 16 +- struct crypto_hash; struct socket; +struct iscsi_tcp_conn; @@ -4681,7 +5724,7 @@ index 4b86fe4..57c2317 100644 /* old values for socket callbacks */ void (*old_data_ready)(struct sock *, int); -@@ -103,29 +96,19 @@ struct iscsi_tcp_conn { +@@ -103,29 +93,19 @@ struct iscsi_tcp_conn { uint32_t sendpage_failures_cnt; uint32_t discontiguous_hdr_cnt; @@ -4715,7 +5758,7 @@ index 4b86fe4..57c2317 100644 }; struct iscsi_r2t_info { -@@ -133,38 +116,26 @@ struct iscsi_r2t_info { +@@ -133,38 +113,26 @@ struct iscsi_r2t_info { __be32 exp_statsn; /* copied from R2T */ uint32_t data_length; /* copied from R2T */ uint32_t data_offset; /* copied from R2T */ @@ -4766,10 +5809,18 @@ index 4b86fe4..57c2317 100644 #endif /* ISCSI_H */ diff --git a/kernel/libiscsi.c b/kernel/libiscsi.c -index f2ef4c7..d175f14 100644 +index f2ef4c7..30ea61a 100644 --- a/kernel/libiscsi.c +++ b/kernel/libiscsi.c -@@ -86,7 +86,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -86,7 +87,7 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) * xmit thread */ if (!list_empty(&session->leadconn->xmitqueue) || @@ -4778,7 +5829,7 @@ index f2ef4c7..d175f14 100644 scsi_queue_work(session->host, &session->leadconn->xmitwork); } -@@ -122,6 +122,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, +@@ -122,6 +123,20 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, } EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); @@ -4799,7 +5850,7 @@ index f2ef4c7..d175f14 100644 /** * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu * @ctask: iscsi cmd task -@@ -129,27 +143,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); +@@ -129,27 +144,32 @@ EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set * fields like dlength or final based on how much data it sends */ @@ -4829,7 +5880,7 @@ index f2ef4c7..d175f14 100644 + hdr->opcode = ISCSI_OP_SCSI_CMD; + hdr->flags = ISCSI_ATTR_SIMPLE; + int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); -+ hdr->itt = build_itt(ctask->itt, conn->id, session->age); ++ hdr->itt = build_itt(ctask->itt, session->age); + hdr->data_length = cpu_to_be32(scsi_bufflen(sc)); + hdr->cmdsn = cpu_to_be32(session->cmdsn); + session->cmdsn++; @@ -4843,7 +5894,7 @@ index f2ef4c7..d175f14 100644 ctask->imm_count = 0; if (sc->sc_data_direction == DMA_TO_DEVICE) { hdr->flags |= ISCSI_FLAG_CMD_WRITE; -@@ -172,25 +191,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +@@ -172,25 +192,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) ctask->unsol_datasn = 0; if (session->imm_data_en) { @@ -4875,14 +5926,15 @@ index f2ef4c7..d175f14 100644 } else { hdr->flags |= ISCSI_FLAG_CMD_FINAL; zero_data(hdr->dlength); -@@ -199,13 +218,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +@@ -199,13 +219,25 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) hdr->flags |= ISCSI_FLAG_CMD_READ; } - conn->scsicmd_pdus_cnt++; + /* calculate size of additional header segments (AHSs) */ + hdrlength = ctask->hdr_len - sizeof(*hdr); -+ + +- debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " + WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); + hdrlength /= ISCSI_PAD_LEN; + @@ -4891,8 +5943,7 @@ index f2ef4c7..d175f14 100644 + + if (conn->session->tt->init_cmd_task(conn->ctask)) + return EIO; - -- debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " ++ + conn->scsicmd_pdus_cnt++; + debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " "cmdsn %d win %d]\n", @@ -4906,7 +5957,7 @@ index f2ef4c7..d175f14 100644 } /** -@@ -218,13 +249,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) +@@ -218,13 +250,16 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) */ static void iscsi_complete_command(struct iscsi_cmd_task *ctask) { @@ -4924,7 +5975,7 @@ index f2ef4c7..d175f14 100644 list_del_init(&ctask->running); __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); sc->scsi_done(sc); -@@ -241,6 +275,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) +@@ -241,6 +276,112 @@ static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) iscsi_complete_command(ctask); } @@ -5037,10 +6088,25 @@ index f2ef4c7..d175f14 100644 /** * iscsi_cmd_rsp - SCSI Command Response processing * @conn: iscsi connection -@@ -294,17 +434,19 @@ invalid_datalen: - if (sc->sc_data_direction == DMA_TO_DEVICE) - goto out; +@@ -275,8 +416,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + if (datalen < 2) { + invalid_datalen: +- printk(KERN_ERR "iscsi: Got CHECK_CONDITION but " +- "invalid data buffer size of %d\n", datalen); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "Got CHECK_CONDITION but invalid data " ++ "buffer size of %d\n", datalen); + sc->result = DID_BAD_TARGET << 16; + goto out; + } +@@ -291,20 +433,19 @@ invalid_datalen: + min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); + } + +- if (sc->sc_data_direction == DMA_TO_DEVICE) +- goto out; +- - if (rhdr->flags & ISCSI_FLAG_CMD_UNDERFLOW) { + if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | + ISCSI_FLAG_CMD_OVERFLOW)) { @@ -5063,7 +6129,7 @@ index f2ef4c7..d175f14 100644 out: debug_scsi("done [sc %lx res %d itt 0x%x]\n", -@@ -321,18 +463,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) +@@ -321,18 +462,51 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; conn->tmfrsp_pdus_cnt++; @@ -5104,7 +6170,7 @@ index f2ef4c7..d175f14 100644 + + mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); + if (!mtask) { -+ printk(KERN_ERR "Could not send nopout\n"); ++ iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); + return; + } + @@ -5119,6 +6185,31 @@ index f2ef4c7..d175f14 100644 static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *data, int datalen) { +@@ -349,9 +523,10 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) { + memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); + itt = get_itt(rejected_pdu.itt); +- printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected " +- "due to DataDigest error.\n", itt, +- rejected_pdu.opcode); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "itt 0x%x had pdu (op 0x%x) rejected " ++ "due to DataDigest error.\n", itt, ++ rejected_pdu.opcode); + } + } + return 0; +@@ -368,8 +543,8 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + * queuecommand or send generic. session lock must be held and verify + * itt must have been called. + */ +-int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, +- char *data, int datalen) ++static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, ++ char *data, int datalen) + { + struct iscsi_session *session = conn->session; + int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; @@ -377,6 +552,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_mgmt_task *mtask; uint32_t itt; @@ -5183,10 +6274,66 @@ index f2ef4c7..d175f14 100644 break; case ISCSI_OP_REJECT: rc = iscsi_handle_reject(conn, hdr, data, datalen); -@@ -596,29 +774,35 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, +@@ -496,7 +674,6 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + + return rc; + } +-EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); + + int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + char *data, int datalen) +@@ -521,18 +698,13 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + if (hdr->itt != RESERVED_ITT) { + if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != + (session->age << ISCSI_AGE_SHIFT)) { +- printk(KERN_ERR "iscsi: received itt %x expected " +- "session age (%x)\n", (__force u32)hdr->itt, +- session->age & ISCSI_AGE_MASK); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "received itt %x expected session " ++ "age (%x)\n", (__force u32)hdr->itt, ++ session->age & ISCSI_AGE_MASK); + return ISCSI_ERR_BAD_ITT; + } + +- if (((__force u32)hdr->itt & ISCSI_CID_MASK) != +- (conn->id << ISCSI_CID_SHIFT)) { +- printk(KERN_ERR "iscsi: received itt %x, expected " +- "CID (%x)\n", (__force u32)hdr->itt, conn->id); +- return ISCSI_ERR_BAD_ITT; +- } + itt = get_itt(hdr->itt); + } else + itt = ~0U; +@@ -541,16 +713,17 @@ int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, + ctask = session->cmds[itt]; + + if (!ctask->sc) { +- printk(KERN_INFO "iscsi: dropping ctask with " +- "itt 0x%x\n", ctask->itt); ++ iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " ++ "with itt 0x%x\n", ctask->itt); + /* force drop */ + return ISCSI_ERR_NO_SCSI_CMD; + } + + if (ctask->sc->SCp.phase != session->age) { +- printk(KERN_ERR "iscsi: ctask's session age %d, " +- "expected %d\n", ctask->sc->SCp.phase, +- session->age); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "iscsi: ctask's session age %d, " ++ "expected %d\n", ctask->sc->SCp.phase, ++ session->age); + return ISCSI_ERR_SESSION_FAILED; + } + } +@@ -595,30 +768,36 @@ static void iscsi_prep_mtask(struct iscsi_conn *conn, + */ nop->cmdsn = cpu_to_be32(session->cmdsn); if (hdr->itt != RESERVED_ITT) { - hdr->itt = build_itt(mtask->itt, conn->id, session->age); +- hdr->itt = build_itt(mtask->itt, conn->id, session->age); ++ hdr->itt = build_itt(mtask->itt, session->age); + /* + * TODO: We always use immediate, so we never hit this. + * If we start to send tmfs or nops as non-immediate then @@ -5227,7 +6374,7 @@ index f2ef4c7..d175f14 100644 rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); spin_lock_bh(&conn->session->lock); if (rc) -@@ -626,11 +810,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) +@@ -626,11 +805,6 @@ static int iscsi_xmit_mtask(struct iscsi_conn *conn) /* done with this in-progress mtask */ conn->mtask = NULL; @@ -5239,7 +6386,7 @@ index f2ef4c7..d175f14 100644 return 0; } -@@ -641,9 +820,11 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) +@@ -641,9 +815,11 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) /* * Check for iSCSI window and take care of CmdSN wrap-around */ @@ -5254,7 +6401,7 @@ index f2ef4c7..d175f14 100644 return -ENOSPC; } return 0; -@@ -652,21 +833,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) +@@ -652,21 +828,13 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) static int iscsi_xmit_ctask(struct iscsi_conn *conn) { struct iscsi_cmd_task *ctask = conn->ctask; @@ -5277,7 +6424,7 @@ index f2ef4c7..d175f14 100644 if (!rc) /* done with this ctask */ conn->ctask = NULL; -@@ -674,6 +847,22 @@ done: +@@ -674,6 +842,22 @@ done: } /** @@ -5300,7 +6447,7 @@ index f2ef4c7..d175f14 100644 * iscsi_data_xmit - xmit any command into the scheduled connection * @conn: iscsi connection * -@@ -711,32 +900,38 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) +@@ -711,32 +895,38 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) * overflow us with nop-ins */ check_mgmt: @@ -5346,16 +6493,16 @@ index f2ef4c7..d175f14 100644 + if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { + fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); + continue; -+ } + } + if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { + fail_command(conn, conn->ctask, DID_ABORT << 16); + continue; - } ++ } + conn->ctask->state = ISCSI_TASK_RUNNING; list_move_tail(conn->xmitqueue.next, &conn->run_list); rc = iscsi_xmit_ctask(conn); -@@ -747,7 +942,28 @@ check_mgmt: +@@ -747,7 +937,28 @@ check_mgmt: * we need to check the mgmt queue for nops that need to * be sent to aviod starvation */ @@ -5385,15 +6532,16 @@ index f2ef4c7..d175f14 100644 goto check_mgmt; } spin_unlock_bh(&conn->session->lock); -@@ -782,6 +998,7 @@ enum { +@@ -782,6 +993,8 @@ enum { FAILURE_SESSION_TERMINATE, FAILURE_SESSION_IN_RECOVERY, FAILURE_SESSION_RECOVERY_TIMEOUT, + FAILURE_SESSION_LOGGING_OUT, ++ FAILURE_SESSION_NOT_READY, }; int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) -@@ -797,8 +1014,9 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) +@@ -797,10 +1010,17 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) sc->SCp.ptr = NULL; host = sc->device->host; @@ -5403,8 +6551,16 @@ index f2ef4c7..d175f14 100644 + session = iscsi_hostdata(host->hostdata); spin_lock(&session->lock); ++ reason = iscsi_session_chkready(session_to_cls(session)); ++ if (reason) { ++ sc->result = reason; ++ goto fault; ++ } ++ /* -@@ -814,17 +1032,22 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) + * ISCSI_STATE_FAILED is a temp. state. The recovery + * code will decide what is best to do with command queued +@@ -814,32 +1034,37 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) * be entering our queuecommand while a block is starting * up because the block code is not locked) */ @@ -5412,28 +6568,37 @@ index f2ef4c7..d175f14 100644 + switch (session->state) { + case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; - goto reject; +- goto reject; - } - - if (session->state == ISCSI_STATE_RECOVERY_FAILED) ++ sc->result = DID_IMM_RETRY << 16; ++ break; + case ISCSI_STATE_LOGGING_OUT: + reason = FAILURE_SESSION_LOGGING_OUT; -+ goto reject; ++ sc->result = DID_IMM_RETRY << 16; ++ break; + case ISCSI_STATE_RECOVERY_FAILED: reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - else if (session->state == ISCSI_STATE_TERMINATE) ++ sc->result = DID_NO_CONNECT << 16; + break; + case ISCSI_STATE_TERMINATE: reason = FAILURE_SESSION_TERMINATE; - else ++ sc->result = DID_NO_CONNECT << 16; + break; + default: reason = FAILURE_SESSION_FREED; ++ sc->result = DID_NO_CONNECT << 16; + } goto fault; } -@@ -834,12 +1057,6 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) + conn = session->leadconn; + if (!conn) { + reason = FAILURE_SESSION_FREED; ++ sc->result = DID_NO_CONNECT << 16; goto fault; } @@ -5446,7 +6611,7 @@ index f2ef4c7..d175f14 100644 if (iscsi_check_cmdsn_window_closed(conn)) { reason = FAILURE_WINDOW_CLOSED; goto reject; -@@ -850,12 +1067,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) +@@ -850,12 +1075,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) reason = FAILURE_OOM; goto reject; } @@ -5461,7 +6626,7 @@ index f2ef4c7..d175f14 100644 ctask->conn = conn; ctask->sc = sc; INIT_LIST_HEAD(&ctask->running); -@@ -864,11 +1082,13 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) +@@ -864,20 +1090,21 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) spin_unlock(&session->lock); scsi_queue_work(host, &conn->xmitwork); @@ -5475,18 +6640,19 @@ index f2ef4c7..d175f14 100644 return SCSI_MLQUEUE_HOST_BUSY; fault: -@@ -876,8 +1096,9 @@ fault: - printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", - sc->cmnd[0], reason); - sc->result = (DID_NO_CONNECT << 16); + spin_unlock(&session->lock); +- printk(KERN_ERR "iscsi: cmd 0x%x is not queued (%d)\n", +- sc->cmnd[0], reason); +- sc->result = (DID_NO_CONNECT << 16); - sc->resid = sc->request_bufflen; ++ debug_scsi("iscsi: cmd 0x%x is not queued (%d)\n", sc->cmnd[0], reason); + scsi_set_resid(sc, scsi_bufflen(sc)); sc->scsi_done(sc); + spin_lock(host->host_lock); return 0; } EXPORT_SYMBOL_GPL(iscsi_queuecommand); -@@ -891,72 +1112,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) +@@ -891,72 +1118,15 @@ int iscsi_change_queue_depth(struct scsi_device *sdev, int depth) } EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); @@ -5561,7 +6727,7 @@ index f2ef4c7..d175f14 100644 } spin_unlock_bh(&session->lock); } -@@ -967,30 +1131,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) +@@ -967,30 +1137,25 @@ int iscsi_eh_host_reset(struct scsi_cmnd *sc) struct Scsi_Host *host = sc->device->host; struct iscsi_session *session = iscsi_hostdata(host->hostdata); struct iscsi_conn *conn = session->leadconn; @@ -5596,14 +6762,16 @@ index f2ef4c7..d175f14 100644 debug_scsi("iscsi_eh_host_reset wait for relogin\n"); wait_event_interruptible(conn->ehwait, -@@ -1000,190 +1159,285 @@ failed: +@@ -1000,190 +1165,284 @@ failed: if (signal_pending(current)) flush_signals(current); + mutex_lock(&session->eh_mutex); spin_lock_bh(&session->lock); if (session->state == ISCSI_STATE_LOGGED_IN) - printk(KERN_INFO "iscsi: host reset succeeded\n"); +- printk(KERN_INFO "iscsi: host reset succeeded\n"); ++ iscsi_session_printk(KERN_INFO, session, ++ "host reset succeeded\n"); else goto failed; spin_unlock_bh(&session->lock); @@ -5729,7 +6897,8 @@ index f2ef4c7..d175f14 100644 */ -static struct iscsi_mgmt_task * -iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt) -+static void fail_all_commands(struct iscsi_conn *conn, unsigned lun) ++static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, ++ int error) { - int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); - struct iscsi_mgmt_task *task; @@ -5747,7 +6916,7 @@ index f2ef4c7..d175f14 100644 + if (lun == ctask->sc->device->lun || lun == -1) { + debug_scsi("failing pending sc %p itt 0x%x\n", + ctask->sc, ctask->itt); -+ fail_command(conn, ctask, DID_BUS_BUSY << 16); ++ fail_command(conn, ctask, error << 16); + } + } @@ -5758,7 +6927,7 @@ index f2ef4c7..d175f14 100644 + if (lun == ctask->sc->device->lun || lun == -1) { + debug_scsi("failing requeued sc %p itt 0x%x\n", + ctask->sc, ctask->itt); -+ fail_command(conn, ctask, DID_BUS_BUSY << 16); ++ fail_command(conn, ctask, error << 16); } + } @@ -5877,10 +7046,10 @@ index f2ef4c7..d175f14 100644 + last_recv = conn->last_recv; + if (time_before_eq(last_recv + timeout + (conn->ping_timeout * HZ), + jiffies)) { -+ printk(KERN_ERR "ping timeout of %d secs expired, " -+ "last rx %lu, last ping %lu, now %lu\n", -+ conn->ping_timeout, last_recv, -+ conn->last_ping, jiffies); ++ iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " ++ "expired, last rx %lu, last ping %lu, " ++ "now %lu\n", conn->ping_timeout, last_recv, ++ conn->last_ping, jiffies); + spin_unlock(&session->lock); + iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); return; @@ -5896,9 +7065,8 @@ index f2ef4c7..d175f14 100644 + iscsi_send_nopout(conn, NULL); + } + next_timeout = last_recv + timeout + (conn->ping_timeout * HZ); -+ } else { ++ } else + next_timeout = last_recv + timeout; -+ } - sc->result = err; - sc->resid = sc->request_bufflen; @@ -5906,10 +7074,8 @@ index f2ef4c7..d175f14 100644 - conn->ctask = NULL; - /* release ref from queuecommand */ - __iscsi_put_ctask(ctask); -+ if (next_timeout) { -+ debug_scsi("Setting next tmo %lu\n", next_timeout); -+ mod_timer(&conn->transport_timer, next_timeout); -+ } ++ debug_scsi("Setting next tmo %lu\n", next_timeout); ++ mod_timer(&conn->transport_timer, next_timeout); +done: + spin_unlock(&session->lock); +} @@ -5983,7 +7149,7 @@ index f2ef4c7..d175f14 100644 /* ctask completed before time out */ if (!ctask->sc) { -@@ -1191,123 +1445,212 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) +@@ -1191,123 +1450,212 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) goto success; } @@ -6143,7 +7309,7 @@ index f2ef4c7..d175f14 100644 + /* need to grab the recv lock then session lock */ + write_lock_bh(conn->recv_lock); + spin_lock(&session->lock); -+ fail_all_commands(conn, sc->device->lun); ++ fail_all_commands(conn, sc->device->lun, DID_ERROR); + conn->tmf_state = TMF_INITIAL; + spin_unlock(&session->lock); + write_unlock_bh(conn->recv_lock); @@ -6253,7 +7419,7 @@ index f2ef4c7..d175f14 100644 } EXPORT_SYMBOL_GPL(iscsi_pool_free); -@@ -1357,7 +1700,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, +@@ -1357,11 +1705,11 @@ iscsi_session_setup(struct iscsi_transport *iscsit, printk(KERN_ERR "iscsi: invalid queue depth of %d. " "Queue depth must be between 1 and %d.\n", qdepth, ISCSI_MAX_CMD_PER_LUN); @@ -6261,8 +7427,14 @@ index f2ef4c7..d175f14 100644 + qdepth = ISCSI_DEF_CMD_PER_LUN; } - if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || -@@ -1384,19 +1727,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit, +- if (cmds_max < 2 || (cmds_max & (cmds_max - 1)) || +- cmds_max >= ISCSI_MGMT_ITT_OFFSET) { ++ if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || ++ cmds_max < 2) { + if (cmds_max != 0) + printk(KERN_ERR "iscsi: invalid can_queue of %d. " + "can_queue must be a power of 2 and between " +@@ -1384,19 +1732,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit, shost->max_cmd_len = iscsit->max_cmd_len; shost->transportt = scsit; shost->transportt->create_work_queue = 1; @@ -6288,7 +7460,7 @@ index f2ef4c7..d175f14 100644 /* initialize SCSI PDU commands pool */ if (iscsi_pool_init(&session->cmdpool, session->cmds_max, -@@ -1451,9 +1799,9 @@ module_put: +@@ -1451,9 +1804,9 @@ module_put: cls_session_fail: scsi_remove_host(shost); add_host_fail: @@ -6300,7 +7472,7 @@ index f2ef4c7..d175f14 100644 cmdpool_alloc_fail: scsi_host_put(shost); return NULL; -@@ -1473,10 +1821,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) +@@ -1473,10 +1826,11 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) struct iscsi_session *session = iscsi_hostdata(shost->hostdata); struct module *owner = cls_session->transport->owner; @@ -6314,16 +7486,18 @@ index f2ef4c7..d175f14 100644 kfree(session->password); kfree(session->password_in); -@@ -1487,7 +1836,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) +@@ -1486,8 +1840,9 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) + kfree(session->netdev); kfree(session->hwaddress); kfree(session->initiatorname); ++ kfree(session->ifacename); - iscsi_destroy_session(cls_session); + iscsi_free_session(cls_session); scsi_host_put(shost); module_put(owner); } -@@ -1517,17 +1866,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) +@@ -1517,17 +1872,17 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) conn->c_stage = ISCSI_CONN_INITIAL_STAGE; conn->id = conn_idx; conn->exp_statsn = 0; @@ -6349,7 +7523,7 @@ index f2ef4c7..d175f14 100644 INIT_WORK(&conn->xmitwork, iscsi_xmitworker); /* allocate login_mtask used for the login/text sequences */ -@@ -1545,7 +1894,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) +@@ -1545,7 +1900,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) goto login_mtask_data_alloc_fail; conn->login_mtask->data = conn->data = data; @@ -6358,7 +7532,7 @@ index f2ef4c7..d175f14 100644 init_waitqueue_head(&conn->ehwait); return cls_conn; -@@ -1554,8 +1903,6 @@ login_mtask_data_alloc_fail: +@@ -1554,8 +1909,6 @@ login_mtask_data_alloc_fail: __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, sizeof(void*)); login_mtask_alloc_fail: @@ -6367,7 +7541,7 @@ index f2ef4c7..d175f14 100644 iscsi_destroy_conn(cls_conn); return NULL; } -@@ -1574,8 +1921,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) +@@ -1574,8 +1927,9 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) struct iscsi_session *session = conn->session; unsigned long flags; @@ -6378,7 +7552,21 @@ index f2ef4c7..d175f14 100644 conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; if (session->leadconn == conn) { /* -@@ -1608,22 +1956,17 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) +@@ -1598,9 +1952,10 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) + } + spin_unlock_irqrestore(session->host->host_lock, flags); + msleep_interruptible(500); +- printk(KERN_INFO "iscsi: scsi conn_destroy(): host_busy %d " +- "host_failed %d\n", session->host->host_busy, +- session->host->host_failed); ++ iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " ++ "host_busy %d host_failed %d\n", ++ session->host->host_busy, ++ session->host->host_failed); + /* + * force eh_abort() to unblock + */ +@@ -1608,22 +1963,17 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) } /* flush queued up work because we free the connection below */ @@ -6403,19 +7591,36 @@ index f2ef4c7..d175f14 100644 iscsi_destroy_conn(cls_conn); } EXPORT_SYMBOL_GPL(iscsi_conn_teardown); -@@ -1646,9 +1989,28 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) +@@ -1634,21 +1984,41 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) + struct iscsi_session *session = conn->session; + + if (!session) { +- printk(KERN_ERR "iscsi: can't start unbound connection\n"); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "can't start unbound connection\n"); + return -EPERM; + } + + if ((session->imm_data_en || !session->initial_r2t_en) && + session->first_burst > session->max_burst) { +- printk("iscsi: invalid burst lengths: " +- "first_burst %d max_burst %d\n", +- session->first_burst, session->max_burst); ++ iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " ++ "first_burst %d max_burst %d\n", ++ session->first_burst, session->max_burst); return -EINVAL; } + if (conn->ping_timeout && !conn->recv_timeout) { -+ printk(KERN_ERR "iscsi: invalid recv timeout of zero " -+ "Using 5 seconds\n."); ++ iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " ++ "zero. Using 5 seconds\n."); + conn->recv_timeout = 5; + } + + if (conn->recv_timeout && !conn->ping_timeout) { -+ printk(KERN_ERR "iscsi: invalid ping timeout of zero " -+ "Using 5 seconds.\n"); ++ iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " ++ "zero. Using 5 seconds.\n"); + conn->ping_timeout = 5; + } + @@ -6432,16 +7637,34 @@ index f2ef4c7..d175f14 100644 switch(conn->stop_stage) { case STOP_CONN_RECOVER: -@@ -1657,7 +2019,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) +@@ -1657,13 +2027,11 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) * commands after successful recovery */ conn->stop_stage = 0; - conn->tmabort_state = TMABORT_INITIAL; + conn->tmf_state = TMF_INITIAL; session->age++; - spin_unlock_bh(&session->lock); +- spin_unlock_bh(&session->lock); +- +- iscsi_unblock_session(session_to_cls(session)); +- wake_up(&conn->ehwait); +- return 0; ++ if (session->age == 16) ++ session->age = 0; ++ break; + case STOP_CONN_TERM: + conn->stop_stage = 0; + break; +@@ -1672,6 +2040,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) + } + spin_unlock_bh(&session->lock); -@@ -1682,58 +2044,43 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) ++ iscsi_unblock_session(session_to_cls(session)); ++ wake_up(&conn->ehwait); + return 0; + } + EXPORT_SYMBOL_GPL(iscsi_conn_start); +@@ -1682,58 +2052,43 @@ flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) struct iscsi_mgmt_task *mtask, *tmp; /* handle pending */ @@ -6518,7 +7741,7 @@ index f2ef4c7..d175f14 100644 return; } -@@ -1750,9 +2097,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, +@@ -1750,9 +2105,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, old_stop_stage = conn->stop_stage; conn->stop_stage = flag; conn->c_stage = ISCSI_CONN_STOPPED; @@ -6530,19 +7753,30 @@ index f2ef4c7..d175f14 100644 write_lock_bh(conn->recv_lock); set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); -@@ -1778,9 +2125,10 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, +@@ -1778,9 +2133,11 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, * flush queues. */ spin_lock_bh(&session->lock); - fail_all_commands(conn); -+ fail_all_commands(conn, -1); ++ fail_all_commands(conn, -1, ++ STOP_CONN_RECOVER ? DID_BUS_BUSY : DID_ERROR); flush_control_queues(session, conn); spin_unlock_bh(&session->lock); + mutex_unlock(&session->eh_mutex); } void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) -@@ -1828,6 +2176,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, +@@ -1794,7 +2151,8 @@ void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) + iscsi_start_session_recovery(session, conn, flag); + break; + default: +- printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag); ++ iscsi_conn_printk(KERN_ERR, conn, ++ "invalid stop flag %d\n", flag); + } + } + EXPORT_SYMBOL_GPL(iscsi_conn_stop); +@@ -1828,6 +2186,21 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, uint32_t value; switch(param) { @@ -6564,7 +7798,18 @@ index f2ef4c7..d175f14 100644 case ISCSI_PARAM_MAX_RECV_DLENGTH: sscanf(buf, "%d", &conn->max_recv_dlength); break; -@@ -1942,6 +2305,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, +@@ -1926,6 +2299,10 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + if (!conn->persistent_address) + return -ENOMEM; + break; ++ case ISCSI_PARAM_IFACE_NAME: ++ if (!session->ifacename) ++ session->ifacename = kstrdup(buf, GFP_KERNEL); ++ break; + default: + return -ENOSYS; + } +@@ -1942,6 +2319,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, int len; switch(param) { @@ -6580,7 +7825,17 @@ index f2ef4c7..d175f14 100644 case ISCSI_PARAM_INITIAL_R2T_EN: len = sprintf(buf, "%d\n", session->initial_r2t_en); break; -@@ -1999,6 +2371,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, +@@ -1984,6 +2370,9 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + case ISCSI_PARAM_PASSWORD_IN: + len = sprintf(buf, "%s\n", session->password_in); + break; ++ case ISCSI_PARAM_IFACE_NAME: ++ len = sprintf(buf, "%s\n", session->ifacename); ++ break; + default: + return -ENOSYS; + } +@@ -1999,6 +2388,12 @@ int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, int len; switch(param) { @@ -6593,11 +7848,19 @@ index f2ef4c7..d175f14 100644 case ISCSI_PARAM_MAX_RECV_DLENGTH: len = sprintf(buf, "%u\n", conn->max_recv_dlength); break; +@@ -2059,7 +2454,6 @@ int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, + else + len = sprintf(buf, "%s\n", session->initiatorname); + break; +- + default: + return -ENOSYS; + } diff --git a/kernel/libiscsi.h b/kernel/libiscsi.h -index 3ee0f4f..8328bc7 100644 +index 3ee0f4f..a409e3a 100644 --- a/kernel/libiscsi.h +++ b/kernel/libiscsi.h -@@ -57,11 +57,14 @@ struct iscsi_nopin; +@@ -57,23 +57,31 @@ struct iscsi_nopin; #define ISCSI_MAX_CMD_PER_LUN 128 /* Task Mgmt states */ @@ -6617,7 +7880,12 @@ index 3ee0f4f..8328bc7 100644 /* Connection suspend "bit" */ #define ISCSI_SUSPEND_BIT 1 -@@ -74,6 +77,13 @@ struct iscsi_nopin; + + #define ISCSI_ITT_MASK (0xfff) +-#define ISCSI_CID_SHIFT 12 +-#define ISCSI_CID_MASK (0xffff << ISCSI_CID_SHIFT) + #define ISCSI_AGE_SHIFT 28 + #define ISCSI_AGE_MASK (0xf << ISCSI_AGE_SHIFT) #define ISCSI_ADDRESS_BUF_LEN 64 @@ -6631,7 +7899,7 @@ index 3ee0f4f..8328bc7 100644 struct iscsi_mgmt_task { /* * Becuae LLDs allocate their hdr differently, this is a pointer to -@@ -91,15 +101,17 @@ enum { +@@ -91,15 +99,17 @@ enum { ISCSI_TASK_COMPLETED, ISCSI_TASK_PENDING, ISCSI_TASK_RUNNING, @@ -6652,7 +7920,7 @@ index 3ee0f4f..8328bc7 100644 int itt; /* this ITT */ uint32_t unsol_datasn; -@@ -110,7 +122,6 @@ struct iscsi_cmd_task { +@@ -110,7 +120,6 @@ struct iscsi_cmd_task { unsigned data_count; /* remaining Data-Out */ struct scsi_cmnd *sc; /* associated SCSI cmd*/ struct iscsi_conn *conn; /* used connection */ @@ -6660,7 +7928,7 @@ index 3ee0f4f..8328bc7 100644 /* state set/tested under session->lock */ int state; -@@ -119,6 +130,11 @@ struct iscsi_cmd_task { +@@ -119,6 +128,19 @@ struct iscsi_cmd_task { void *dd_data; /* driver/transport data */ }; @@ -6668,11 +7936,19 @@ index 3ee0f4f..8328bc7 100644 +{ + return (void*)ctask->hdr + ctask->hdr_len; +} ++ ++/* Connection's states */ ++enum { ++ ISCSI_CONN_INITIAL_STAGE, ++ ISCSI_CONN_STARTED, ++ ISCSI_CONN_STOPPED, ++ ISCSI_CONN_CLEANUP_WAIT, ++}; + struct iscsi_conn { struct iscsi_cls_conn *cls_conn; /* ptr to class connection */ void *dd_data; /* iscsi_transport data */ -@@ -132,6 +148,12 @@ struct iscsi_conn { +@@ -132,6 +154,12 @@ struct iscsi_conn { * conn_stop() flag: stop to recover, stop to terminate */ int stop_stage; @@ -6685,7 +7961,7 @@ index 3ee0f4f..8328bc7 100644 /* iSCSI connection-wide sequencing */ uint32_t exp_statsn; -@@ -152,10 +174,11 @@ struct iscsi_conn { +@@ -152,10 +180,11 @@ struct iscsi_conn { struct iscsi_cmd_task *ctask; /* xmit ctask in progress */ /* xmit */ @@ -6698,7 +7974,7 @@ index 3ee0f4f..8328bc7 100644 struct work_struct xmitwork; /* per-conn. xmit workqueue */ unsigned long suspend_tx; /* suspend Tx */ unsigned long suspend_rx; /* suspend Rx */ -@@ -163,8 +186,8 @@ struct iscsi_conn { +@@ -163,8 +192,8 @@ struct iscsi_conn { /* abort */ wait_queue_head_t ehwait; /* used in eh_abort() */ struct iscsi_tm tmhdr; @@ -6709,7 +7985,7 @@ index 3ee0f4f..8328bc7 100644 /* negotiated params */ unsigned max_recv_dlength; /* initiator_max_recv_dsl*/ -@@ -198,19 +221,31 @@ struct iscsi_conn { +@@ -198,19 +227,42 @@ struct iscsi_conn { uint32_t eh_abort_cnt; }; @@ -6720,6 +7996,17 @@ index 3ee0f4f..8328bc7 100644 int max; /* Max number of elements */ }; ++/* Session's states */ ++enum { ++ ISCSI_STATE_FREE = 1, ++ ISCSI_STATE_LOGGED_IN, ++ ISCSI_STATE_FAILED, ++ ISCSI_STATE_TERMINATE, ++ ISCSI_STATE_IN_RECOVERY, ++ ISCSI_STATE_RECOVERY_FAILED, ++ ISCSI_STATE_LOGGING_OUT, ++}; ++ struct iscsi_session { + /* + * Syncs up the scsi eh thread with the iscsi eh thread when sending @@ -6742,7 +8029,7 @@ index 3ee0f4f..8328bc7 100644 int initial_r2t_en; unsigned max_r2t; int imm_data_en; -@@ -221,6 +256,7 @@ struct iscsi_session { +@@ -221,6 +273,7 @@ struct iscsi_session { int pdu_inorder_en; int dataseq_inorder_en; int erl; @@ -6750,7 +8037,15 @@ index 3ee0f4f..8328bc7 100644 int tpgt; char *username; char *username_in; -@@ -246,10 +282,10 @@ struct iscsi_session { +@@ -231,6 +284,7 @@ struct iscsi_session { + /* hw address or netdev iscsi connection is bound to */ + char *hwaddress; + char *netdev; ++ char *ifacename; + /* control data */ + struct iscsi_transport *tt; + struct Scsi_Host *host; +@@ -246,10 +300,10 @@ struct iscsi_session { int cmds_max; /* size of cmds array */ struct iscsi_cmd_task **cmds; /* Original Cmds arr */ @@ -6763,7 +8058,7 @@ index 3ee0f4f..8328bc7 100644 }; /* -@@ -258,6 +294,7 @@ struct iscsi_session { +@@ -258,6 +312,7 @@ struct iscsi_session { extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth); extern int iscsi_eh_abort(struct scsi_cmnd *sc); extern int iscsi_eh_host_reset(struct scsi_cmnd *sc); @@ -6771,8 +8066,33 @@ index 3ee0f4f..8328bc7 100644 extern int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)); -@@ -316,11 +353,32 @@ extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, - char *, int); +@@ -288,6 +343,10 @@ extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + #define session_to_cls(_sess) \ + hostdata_session(_sess->host->hostdata) + ++#define iscsi_session_printk(prefix, _sess, fmt, a...) \ ++ iscsi_cls_session_printk(prefix, \ ++ (struct iscsi_cls_session *)session_to_cls(_sess), fmt, ##a) ++ + /* + * connection management + */ +@@ -302,6 +361,9 @@ extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); + extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf); + ++#define iscsi_conn_printk(prefix, _c, fmt, a...) \ ++ iscsi_cls_conn_printk(prefix, _c->cls_conn, fmt, ##a) ++ + /* + * pdu and task processing + */ +@@ -312,15 +374,34 @@ extern int iscsi_conn_send_pdu(struct iscsi_cls_conn *, struct iscsi_hdr *, + char *, uint32_t); + extern int iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, + char *, int); +-extern int __iscsi_complete_pdu(struct iscsi_conn *, struct iscsi_hdr *, +- char *, int); extern int iscsi_verify_itt(struct iscsi_conn *, struct iscsi_hdr *, uint32_t *); +extern void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask); @@ -6807,7 +8127,7 @@ index 3ee0f4f..8328bc7 100644 #endif diff --git a/kernel/scsi_transport_iscsi.c b/kernel/scsi_transport_iscsi.c -index 29730a1..7e5e168 100644 +index 29730a1..98bb210 100644 --- a/kernel/scsi_transport_iscsi.c +++ b/kernel/scsi_transport_iscsi.c @@ -30,10 +30,10 @@ @@ -6815,11 +8135,12 @@ index 29730a1..7e5e168 100644 #include "iscsi_if.h" -#define ISCSI_SESSION_ATTRS 15 -+#define ISCSI_SESSION_ATTRS 18 - #define ISCSI_CONN_ATTRS 11 +-#define ISCSI_CONN_ATTRS 11 ++#define ISCSI_SESSION_ATTRS 20 ++#define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 -#define ISCSI_TRANSPORT_VERSION "2.0-865" -+#define ISCSI_TRANSPORT_VERSION "2.0-724" ++#define ISCSI_TRANSPORT_VERSION "2.0-869" struct iscsi_internal { int daemon_pid; @@ -6840,16 +8161,17 @@ index 29730a1..7e5e168 100644 static int iscsi_setup_host(struct transport_container *tc, struct device *dev, struct class_device *cdev) { -@@ -124,13 +127,30 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, +@@ -124,13 +127,31 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); INIT_LIST_HEAD(&ihost->sessions); mutex_init(&ihost->mutex); ++ atomic_set(&ihost->nr_scans, 0); + -+ snprintf(ihost->unbind_workq_name, KOBJ_NAME_LEN, "iscsi_unbind_%d", ++ snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", + shost->host_no); -+ ihost->unbind_workq = create_singlethread_workqueue( -+ ihost->unbind_workq_name); -+ if (!ihost->unbind_workq) ++ ihost->scan_workq = create_singlethread_workqueue( ++ ihost->scan_workq_name); ++ if (!ihost->scan_workq) + return -ENOMEM; + return 0; +} @@ -6860,7 +8182,7 @@ index 29730a1..7e5e168 100644 + struct Scsi_Host *shost = dev_to_shost(dev); + struct iscsi_host *ihost = shost->shost_data; + -+ destroy_workqueue(ihost->unbind_workq); ++ destroy_workqueue(ihost->scan_workq); return 0; } @@ -6872,23 +8194,215 @@ index 29730a1..7e5e168 100644 NULL); static DECLARE_TRANSPORT_CLASS(iscsi_session_class, -@@ -252,7 +272,7 @@ static void session_recovery_timedout(struct work_struct *work) - void iscsi_unblock_session(struct iscsi_cls_session *session) +@@ -201,6 +222,54 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) + * The following functions can be used by LLDs that allocate + * their own scsi_hosts or by software iscsi LLDs + */ ++static struct { ++ int value; ++ char *name; ++} iscsi_session_state_names[] = { ++ { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, ++ { ISCSI_SESSION_FAILED, "FAILED" }, ++ { ISCSI_SESSION_FREE, "FREE" }, ++}; ++ ++static const char *iscsi_session_state_name(int state) ++{ ++ int i; ++ char *name = NULL; ++ ++ for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { ++ if (iscsi_session_state_names[i].value == state) { ++ name = iscsi_session_state_names[i].name; ++ break; ++ } ++ } ++ return name; ++} ++ ++int iscsi_session_chkready(struct iscsi_cls_session *session) ++{ ++ unsigned long flags; ++ int err; ++ ++ spin_lock_irqsave(&session->lock, flags); ++ switch (session->state) { ++ case ISCSI_SESSION_LOGGED_IN: ++ err = 0; ++ break; ++ case ISCSI_SESSION_FAILED: ++ err = DID_IMM_RETRY << 16; ++ break; ++ case ISCSI_SESSION_FREE: ++ err = DID_NO_CONNECT << 16; ++ break; ++ default: ++ err = DID_NO_CONNECT << 16; ++ break; ++ } ++ spin_unlock_irqrestore(&session->lock, flags); ++ return err; ++} ++EXPORT_SYMBOL_GPL(iscsi_session_chkready); ++ + static void iscsi_session_release(struct device *dev) { - if (!cancel_delayed_work(&session->recovery_work)) -- flush_scheduled_work(); -+ flush_workqueue(iscsi_eh_timer_workq); + struct iscsi_cls_session *session = iscsi_dev_to_session(dev); +@@ -216,6 +285,25 @@ static int iscsi_is_session_dev(const struct device *dev) + return dev->release == iscsi_session_release; + } + ++/** ++ * iscsi_scan_finished - helper to report when running scans are done ++ * @shost: scsi host ++ * @time: scan run time ++ * ++ * This function can be used by drives like qla4xxx to report to the scsi ++ * layer when the scans it kicked off at module load time are done. ++ */ ++int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) ++{ ++ struct iscsi_host *ihost = shost->shost_data; ++ /* ++ * qla4xxx will have kicked off some session unblocks before calling ++ * scsi_scan_host, so just wait for them to complete. ++ */ ++ return !atomic_read(&ihost->nr_scans); ++} ++EXPORT_SYMBOL_GPL(iscsi_scan_finished); ++ + static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, + uint id, uint lun) + { +@@ -234,14 +322,50 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, + return 0; + } + ++static void iscsi_scan_session(struct work_struct *work) ++{ ++ struct iscsi_cls_session *session = ++ container_of(work, struct iscsi_cls_session, scan_work); ++ struct Scsi_Host *shost = iscsi_session_to_shost(session); ++ struct iscsi_host *ihost = shost->shost_data; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&session->lock, flags); ++ if (session->state != ISCSI_SESSION_LOGGED_IN) { ++ spin_unlock_irqrestore(&session->lock, flags); ++ goto done; ++ } ++ spin_unlock_irqrestore(&session->lock, flags); ++ ++ scsi_scan_target(&session->dev, 0, session->target_id, ++ SCAN_WILD_CARD, 1); ++done: ++ atomic_dec(&ihost->nr_scans); ++} ++ + static void session_recovery_timedout(struct work_struct *work) + { + struct iscsi_cls_session *session = + container_of(work, struct iscsi_cls_session, + recovery_work.work); ++ unsigned long flags; ++ ++ iscsi_cls_session_printk(KERN_INFO, session, ++ "session recovery timed out after %d secs\n", ++ session->recovery_tmo); + +- dev_printk(KERN_INFO, &session->dev, "iscsi: session recovery timed " +- "out after %d secs\n", session->recovery_tmo); ++ spin_lock_irqsave(&session->lock, flags); ++ switch (session->state) { ++ case ISCSI_SESSION_FAILED: ++ session->state = ISCSI_SESSION_FREE; ++ break; ++ case ISCSI_SESSION_LOGGED_IN: ++ case ISCSI_SESSION_FREE: ++ /* we raced with the unblock's flush */ ++ spin_unlock_irqrestore(&session->lock, flags); ++ return; ++ } ++ spin_unlock_irqrestore(&session->lock, flags); + + if (session->transport->session_recovery_timedout) + session->transport->session_recovery_timedout(session); +@@ -249,22 +373,103 @@ static void session_recovery_timedout(struct work_struct *work) scsi_target_unblock(&session->dev); } - EXPORT_SYMBOL_GPL(iscsi_unblock_session); -@@ -260,11 +280,40 @@ EXPORT_SYMBOL_GPL(iscsi_unblock_session); - void iscsi_block_session(struct iscsi_cls_session *session) + +-void iscsi_unblock_session(struct iscsi_cls_session *session) ++static void __iscsi_unblock_session(struct work_struct *work) { +- if (!cancel_delayed_work(&session->recovery_work)) +- flush_scheduled_work(); ++ struct iscsi_cls_session *session = ++ container_of(work, struct iscsi_cls_session, ++ unblock_work); ++ struct Scsi_Host *shost = iscsi_session_to_shost(session); ++ struct iscsi_host *ihost = shost->shost_data; ++ unsigned long flags; ++ ++ /* ++ * The recovery and unblock work get run from the same workqueue, ++ * so try to cancel it if it was going to run after this unblock. ++ */ ++ cancel_delayed_work(&session->recovery_work); ++ spin_lock_irqsave(&session->lock, flags); ++ session->state = ISCSI_SESSION_LOGGED_IN; ++ spin_unlock_irqrestore(&session->lock, flags); ++ /* start IO */ + scsi_target_unblock(&session->dev); ++ /* ++ * Only do kernel scanning if the driver is properly hooked into ++ * the async scanning code (drivers like iscsi_tcp do login and ++ * scanning from userspace). ++ */ ++ if (shost->hostt->scan_finished) { ++ if (queue_work(ihost->scan_workq, &session->scan_work)) ++ atomic_inc(&ihost->nr_scans); ++ } ++} ++ ++/** ++ * iscsi_unblock_session - set a session as logged in and start IO. ++ * @session: iscsi session ++ * ++ * Mark a session as ready to accept IO. ++ */ ++void iscsi_unblock_session(struct iscsi_cls_session *session) ++{ ++ queue_work(iscsi_eh_timer_workq, &session->unblock_work); ++ /* ++ * make sure all the events have completed before tell the driver ++ * it is safe ++ */ ++ flush_workqueue(iscsi_eh_timer_workq); + } + EXPORT_SYMBOL_GPL(iscsi_unblock_session); + +-void iscsi_block_session(struct iscsi_cls_session *session) ++static void __iscsi_block_session(struct work_struct *work) + { ++ struct iscsi_cls_session *session = ++ container_of(work, struct iscsi_cls_session, ++ block_work); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&session->lock, flags); ++ session->state = ISCSI_SESSION_FAILED; ++ spin_unlock_irqrestore(&session->lock, flags); scsi_target_block(&session->dev); - schedule_delayed_work(&session->recovery_work, - session->recovery_tmo * HZ); + queue_delayed_work(iscsi_eh_timer_workq, &session->recovery_work, + session->recovery_tmo * HZ); ++} ++ ++void iscsi_block_session(struct iscsi_cls_session *session) ++{ ++ queue_work(iscsi_eh_timer_workq, &session->block_work); } EXPORT_SYMBOL_GPL(iscsi_block_session); @@ -6918,21 +8432,29 @@ index 29730a1..7e5e168 100644 + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost = shost->shost_data; + -+ return queue_work(ihost->unbind_workq, &session->unbind_work); ++ return queue_work(ihost->scan_workq, &session->unbind_work); +} + struct iscsi_cls_session * iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport) -@@ -281,6 +330,7 @@ iscsi_alloc_session(struct Scsi_Host *shost, +@@ -278,9 +483,15 @@ iscsi_alloc_session(struct Scsi_Host *shost, + + session->transport = transport; + session->recovery_tmo = 120; ++ session->state = ISCSI_SESSION_FREE; INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); ++ INIT_WORK(&session->unblock_work, __iscsi_unblock_session); ++ INIT_WORK(&session->block_work, __iscsi_block_session); + INIT_WORK(&session->unbind_work, __iscsi_unbind_session); ++ INIT_WORK(&session->scan_work, iscsi_scan_session); ++ spin_lock_init(&session->lock); /* this is released in the dev's release function */ scsi_host_get(shost); -@@ -297,6 +347,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) +@@ -297,6 +508,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost; @@ -6940,7 +8462,15 @@ index 29730a1..7e5e168 100644 int err; ihost = shost->shost_data; -@@ -313,9 +364,15 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) +@@ -307,15 +519,21 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) + session->sid); + err = device_add(&session->dev); + if (err) { +- dev_printk(KERN_ERR, &session->dev, "iscsi: could not " +- "register session's dev\n"); ++ iscsi_cls_session_printk(KERN_ERR, session, ++ "could not register session's dev\n"); + goto release_host; } transport_register_device(&session->dev); @@ -6956,7 +8486,19 @@ index 29730a1..7e5e168 100644 return 0; release_host: -@@ -350,19 +407,58 @@ iscsi_create_session(struct Scsi_Host *shost, +@@ -328,9 +546,10 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); + * iscsi_create_session - create iscsi class session + * @shost: scsi host + * @transport: iscsi transport ++ * @target_id: which target + * + * This can be called from a LLD or iscsi_transport. +- **/ ++ */ + struct iscsi_cls_session * + iscsi_create_session(struct Scsi_Host *shost, + struct iscsi_transport *transport, +@@ -350,19 +569,65 @@ iscsi_create_session(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(iscsi_create_session); @@ -6987,41 +8529,47 @@ index 29730a1..7e5e168 100644 struct iscsi_host *ihost = shost->shost_data; + unsigned long flags; + int err; - -- if (!cancel_delayed_work(&session->recovery_work)) -- flush_scheduled_work(); ++ + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); -- mutex_lock(&ihost->mutex); -- list_del(&session->host_list); -- mutex_unlock(&ihost->mutex); ++ /* make sure there are no blocks/unblocks queued */ ++ flush_workqueue(iscsi_eh_timer_workq); ++ /* make sure the timedout callout is not running */ + if (!cancel_delayed_work(&session->recovery_work)) +- flush_scheduled_work(); ++ flush_workqueue(iscsi_eh_timer_workq); + /* + * If we are blocked let commands flow again. The lld or iscsi + * layer should set up the queuecommand to fail commands. ++ * We assume that LLD will not be calling block/unblock while ++ * removing the session. + */ -+ iscsi_unblock_session(session); -+ iscsi_unbind_session(session); -+ /* -+ * If the session dropped while removing devices then we need to make -+ * sure it is not blocked -+ */ -+ if (!cancel_delayed_work(&session->recovery_work)) -+ flush_workqueue(iscsi_eh_timer_workq); -+ flush_workqueue(ihost->unbind_workq); ++ spin_lock_irqsave(&session->lock, flags); ++ session->state = ISCSI_SESSION_FREE; ++ spin_unlock_irqrestore(&session->lock, flags); + +- mutex_lock(&ihost->mutex); +- list_del(&session->host_list); +- mutex_unlock(&ihost->mutex); ++ scsi_target_unblock(&session->dev); ++ /* flush running scans then delete devices */ ++ flush_workqueue(ihost->scan_workq); ++ __iscsi_unbind_session(&session->unbind_work); - scsi_remove_target(&session->dev); + /* hw iscsi may not have removed all connections from session */ + err = device_for_each_child(&session->dev, NULL, + iscsi_iter_destroy_conn_fn); + if (err) -+ dev_printk(KERN_ERR, &session->dev, "iscsi: Could not delete " -+ "all connections for session. Error %d.\n", err); ++ iscsi_cls_session_printk(KERN_ERR, session, ++ "Could not delete all connections " ++ "for session. Error %d.\n", err); transport_unregister_device(&session->dev); device_del(&session->dev); -@@ -371,9 +467,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session); +@@ -371,9 +636,9 @@ EXPORT_SYMBOL_GPL(iscsi_remove_session); void iscsi_free_session(struct iscsi_cls_session *session) { @@ -7032,7 +8580,16 @@ index 29730a1..7e5e168 100644 EXPORT_SYMBOL_GPL(iscsi_free_session); /** -@@ -391,20 +487,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) +@@ -382,7 +647,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session); + * + * Can be called by a LLD or iscsi_transport. There must not be + * any running connections. +- **/ ++ */ + int iscsi_destroy_session(struct iscsi_cls_session *session) + { + iscsi_remove_session(session); +@@ -391,20 +656,6 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_destroy_session); @@ -7053,7 +8610,14 @@ index 29730a1..7e5e168 100644 /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session -@@ -424,6 +506,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) +@@ -418,12 +669,13 @@ static int iscsi_is_conn_dev(const struct device *dev) + * for software iscsi we could be trying to preallocate a connection struct + * in which case there could be two connection structs and cid would be + * non-zero. +- **/ ++ */ + struct iscsi_cls_conn * + iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) { struct iscsi_transport *transport = session->transport; struct iscsi_cls_conn *conn; @@ -7061,7 +8625,14 @@ index 29730a1..7e5e168 100644 int err; conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); -@@ -452,6 +535,11 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) +@@ -447,11 +699,16 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) + conn->dev.release = iscsi_conn_release; + err = device_register(&conn->dev); + if (err) { +- dev_printk(KERN_ERR, &conn->dev, "iscsi: could not register " +- "connection's dev\n"); ++ iscsi_cls_session_printk(KERN_ERR, session, "could not " ++ "register connection's dev\n"); goto release_parent_ref; } transport_register_device(&conn->dev); @@ -7073,8 +8644,16 @@ index 29730a1..7e5e168 100644 return conn; release_parent_ref: -@@ -471,11 +559,17 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn); - **/ +@@ -465,17 +722,23 @@ EXPORT_SYMBOL_GPL(iscsi_create_conn); + + /** + * iscsi_destroy_conn - destroy iscsi class connection +- * @session: iscsi cls session ++ * @conn: iscsi cls session + * + * This can be called from a LLD or iscsi_transport. +- **/ ++ */ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) { + unsigned long flags; @@ -7092,7 +8671,51 @@ index 29730a1..7e5e168 100644 EXPORT_SYMBOL_GPL(iscsi_destroy_conn); /* -@@ -685,132 +779,74 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) +@@ -544,8 +807,8 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + iscsi_conn_error(conn, ISCSI_ERR_CONN_FAILED); +- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not deliver " +- "control PDU: OOM\n"); ++ iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " ++ "control PDU: OOM\n"); + return -ENOMEM; + } + +@@ -578,8 +841,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) + + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { +- dev_printk(KERN_ERR, &conn->dev, "iscsi: gracefully ignored " +- "conn error (%d)\n", error); ++ iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " ++ "conn error (%d)\n", error); + return; + } + +@@ -593,8 +856,8 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) + + iscsi_broadcast_skb(skb, GFP_ATOMIC); + +- dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", +- error); ++ iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", ++ error); + } + EXPORT_SYMBOL_GPL(iscsi_conn_error); + +@@ -649,8 +912,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) + + skbstat = alloc_skb(len, GFP_ATOMIC); + if (!skbstat) { +- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not " +- "deliver stats: OOM\n"); ++ iscsi_cls_conn_printk(KERN_ERR, conn, "can not " ++ "deliver stats: OOM\n"); + return -ENOMEM; + } + +@@ -685,132 +948,77 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) } /** @@ -7101,11 +8724,12 @@ index 29730a1..7e5e168 100644 - * - * This is called by HW iscsi LLDs to notify userpsace that its HW has - * removed a session. +- **/ +-int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) + * iscsi_session_event - send session destr. completion event + * @session: iscsi class session + * @event: type of event - **/ --int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) ++ */ +int iscsi_session_event(struct iscsi_cls_session *session, + enum iscsi_uevent_e event) { @@ -7130,8 +8754,9 @@ index 29730a1..7e5e168 100644 if (!skb) { - dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " - "session creation event\n"); -+ dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " -+ "of session event %u\n", event); ++ iscsi_cls_session_printk(KERN_ERR, session, ++ "Cannot notify userspace of session " ++ "event %u\n", event); return -ENOMEM; } @@ -7163,8 +8788,7 @@ index 29730a1..7e5e168 100644 - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done); -+ ev->transport_handle = iscsi_handle(session->transport); - +- -/** - * iscsi_if_create_session_done - send session creation completion event - * @conn: leading connection for session @@ -7182,7 +8806,8 @@ index 29730a1..7e5e168 100644 - struct nlmsghdr *nlh; - unsigned long flags; - int rc, len = NLMSG_SPACE(sizeof(*ev)); -- ++ ev->transport_handle = iscsi_handle(session->transport); + - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) + ev->type = event; @@ -7200,8 +8825,8 @@ index 29730a1..7e5e168 100644 + ev->r.unbind_session.sid = session->sid; + break; + default: -+ dev_printk(KERN_ERR, &session->dev, "Invalid event %u.\n", -+ event); ++ iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " ++ "%u.\n", event); + kfree_skb(skb); return -EINVAL; - @@ -7239,8 +8864,10 @@ index 29730a1..7e5e168 100644 - list_add(&conn->conn_list, &connlist); - conn->active = 1; - spin_unlock_irqrestore(&connlock, flags); -+ dev_printk(KERN_ERR, &session->dev, "Cannot notify userspace " -+ "of session event %u. Check iscsi daemon\n", event); ++ iscsi_cls_session_printk(KERN_ERR, session, ++ "Cannot notify userspace of session " ++ "event %u. Check iscsi daemon\n", ++ event); return rc; } -EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); @@ -7255,7 +8882,7 @@ index 29730a1..7e5e168 100644 uint32_t hostno; session = transport->create_session(transport, &priv->t, -@@ -821,10 +857,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) +@@ -821,10 +1029,6 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) if (!session) return -ENOMEM; @@ -7266,7 +8893,7 @@ index 29730a1..7e5e168 100644 ev->r.c_session_ret.host_no = hostno; ev->r.c_session_ret.sid = session->sid; return 0; -@@ -835,7 +867,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) +@@ -835,47 +1039,34 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) { struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; @@ -7274,7 +8901,21 @@ index 29730a1..7e5e168 100644 session = iscsi_session_lookup(ev->u.c_conn.sid); if (!session) { -@@ -854,28 +885,17 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) +- printk(KERN_ERR "iscsi: invalid session %d\n", ++ printk(KERN_ERR "iscsi: invalid session %d.\n", + ev->u.c_conn.sid); + return -EINVAL; + } + + conn = transport->create_conn(session, ev->u.c_conn.cid); + if (!conn) { +- printk(KERN_ERR "iscsi: couldn't create a new " +- "connection for session %d\n", +- session->sid); ++ iscsi_cls_session_printk(KERN_ERR, session, ++ "couldn't create a new connection."); + return -ENOMEM; + } ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; @@ -7303,7 +8944,7 @@ index 29730a1..7e5e168 100644 if (transport->destroy_conn) transport->destroy_conn(conn); -@@ -1002,7 +1022,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +@@ -1002,7 +1193,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct iscsi_internal *priv; struct iscsi_cls_session *session; struct iscsi_cls_conn *conn; @@ -7311,7 +8952,7 @@ index 29730a1..7e5e168 100644 priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) -@@ -1020,13 +1039,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +@@ -1020,13 +1210,16 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case ISCSI_UEVENT_DESTROY_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); @@ -7334,7 +8975,7 @@ index 29730a1..7e5e168 100644 err = -EINVAL; break; case ISCSI_UEVENT_CREATE_CONN: -@@ -1097,61 +1119,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +@@ -1097,61 +1290,49 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) } /* @@ -7431,7 +9072,7 @@ index 29730a1..7e5e168 100644 } mutex_unlock(&rx_queue_mutex); } -@@ -1191,6 +1201,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); +@@ -1191,6 +1372,8 @@ iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); @@ -7440,17 +9081,27 @@ index 29730a1..7e5e168 100644 #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) -@@ -1229,6 +1241,9 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); +@@ -1229,6 +1412,19 @@ iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1); iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1); iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); +iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); +iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); +iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); ++iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); ++ ++static ssize_t ++show_priv_session_state(struct class_device *cdev, char *buf) ++{ ++ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); ++ return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); ++} ++static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, ++ NULL); #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ -@@ -1425,6 +1440,8 @@ iscsi_register_transport(struct iscsi_transport *tt) +@@ -1425,6 +1621,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); @@ -7459,17 +9110,62 @@ index 29730a1..7e5e168 100644 BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; -@@ -1450,6 +1467,9 @@ iscsi_register_transport(struct iscsi_transport *tt) +@@ -1450,7 +1648,12 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN); SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD); SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN); + SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); + SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); + SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); ++ SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); ++ SETUP_PRIV_SESSION_RD_ATTR(state); BUG_ON(count > ISCSI_SESSION_ATTRS); -@@ -1523,15 +1543,21 @@ static __init int iscsi_transport_init(void) + priv->session_attrs[count] = NULL; +@@ -1470,6 +1673,32 @@ free_priv: + } + EXPORT_SYMBOL_GPL(iscsi_register_transport); + ++void iscsi_trans_error(struct iscsi_transport *tt) ++{ ++ struct nlmsghdr *nlh; ++ struct sk_buff *skb; ++ struct iscsi_uevent *ev; ++ int len = NLMSG_SPACE(sizeof(*ev)); ++ struct iscsi_internal *priv; ++ ++ priv = iscsi_if_transport_lookup(tt); ++ if (!priv) ++ return; ++ ++ skb = alloc_skb(len, GFP_KERNEL); ++ if (!skb) { ++ printk(KERN_ERR "iscsi: gracefully ignored transport error\n"); ++ return; ++ } ++ ++ nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); ++ ev = NLMSG_DATA(nlh); ++ ev->transport_handle = iscsi_handle(tt); ++ ev->type = ISCSI_KEVENT_TRANS_ERROR; ++ ++ iscsi_broadcast_skb(skb, GFP_KERNEL); ++} ++ + int iscsi_unregister_transport(struct iscsi_transport *tt) + { + struct iscsi_internal *priv; +@@ -1479,6 +1708,8 @@ int iscsi_unregister_transport(struct iscsi_transport *tt) + + mutex_lock(&rx_queue_mutex); + ++ iscsi_trans_error(tt); ++ + priv = iscsi_if_transport_lookup(tt); + BUG_ON (!priv); + +@@ -1523,15 +1754,21 @@ static __init int iscsi_transport_init(void) if (err) goto unregister_conn_class; @@ -7488,20 +9184,22 @@ index 29730a1..7e5e168 100644 return 0; +release_nls: -+ sock_release(nls->sk_socket); ++ netlink_kernel_release(nls); unregister_session_class: transport_class_unregister(&iscsi_session_class); unregister_conn_class: -@@ -1545,6 +1571,7 @@ unregister_transport_class: +@@ -1545,7 +1782,8 @@ unregister_transport_class: static void __exit iscsi_transport_exit(void) { +- sock_release(nls->sk_socket); + destroy_workqueue(iscsi_eh_timer_workq); - sock_release(nls->sk_socket); ++ netlink_kernel_release(nls); transport_class_unregister(&iscsi_connection_class); transport_class_unregister(&iscsi_session_class); + transport_class_unregister(&iscsi_host_class); diff --git a/kernel/scsi_transport_iscsi.h b/kernel/scsi_transport_iscsi.h -index 05e2554..6bda9b9 100644 +index 05e2554..3492abe 100644 --- a/kernel/scsi_transport_iscsi.h +++ b/kernel/scsi_transport_iscsi.h @@ -24,6 +24,8 @@ @@ -7522,32 +9220,82 @@ index 05e2554..6bda9b9 100644 void (*init_mgmt_task) (struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask); int (*xmit_cmd_task) (struct iscsi_conn *conn, -@@ -174,6 +176,7 @@ struct iscsi_cls_conn { - #define ISCSI_STATE_TERMINATE 4 - #define ISCSI_STATE_IN_RECOVERY 5 - #define ISCSI_STATE_RECOVERY_FAILED 6 -+#define ISCSI_STATE_LOGGING_OUT 7 +@@ -147,13 +149,6 @@ extern void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error); + extern int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, + char *data, uint32_t data_size); + +- +-/* Connection's states */ +-#define ISCSI_CONN_INITIAL_STAGE 0 +-#define ISCSI_CONN_STARTED 1 +-#define ISCSI_CONN_STOPPED 2 +-#define ISCSI_CONN_CLEANUP_WAIT 3 +- + struct iscsi_cls_conn { + struct list_head conn_list; /* item in connlist */ + void *dd_data; /* LLD private data */ +@@ -167,18 +162,25 @@ struct iscsi_cls_conn { + #define iscsi_dev_to_conn(_dev) \ + container_of(_dev, struct iscsi_cls_conn, dev) + +-/* Session's states */ +-#define ISCSI_STATE_FREE 1 +-#define ISCSI_STATE_LOGGED_IN 2 +-#define ISCSI_STATE_FAILED 3 +-#define ISCSI_STATE_TERMINATE 4 +-#define ISCSI_STATE_IN_RECOVERY 5 +-#define ISCSI_STATE_RECOVERY_FAILED 6 ++#define iscsi_conn_to_session(_conn) \ ++ iscsi_dev_to_session(_conn->dev.parent) ++ ++/* iscsi class session state */ ++enum { ++ ISCSI_SESSION_LOGGED_IN, ++ ISCSI_SESSION_FAILED, ++ ISCSI_SESSION_FREE, ++}; struct iscsi_cls_session { struct list_head sess_list; /* item in session_list */ -@@ -183,6 +186,7 @@ struct iscsi_cls_session { + struct list_head host_list; + struct iscsi_transport *transport; ++ spinlock_t lock; ++ struct work_struct block_work; ++ struct work_struct unblock_work; ++ struct work_struct scan_work; ++ struct work_struct unbind_work; + /* recovery fields */ int recovery_tmo; - struct delayed_work recovery_work; -+ struct work_struct unbind_work; +@@ -186,6 +188,7 @@ struct iscsi_cls_session { int target_id; -@@ -203,6 +207,8 @@ struct iscsi_cls_session { ++ int state; + int sid; /* session id */ + void *dd_data; /* LLD private data */ + struct device dev; /* sysfs transport/container device */ +@@ -202,18 +205,28 @@ struct iscsi_cls_session { + struct iscsi_host { struct list_head sessions; ++ atomic_t nr_scans; struct mutex mutex; -+ struct workqueue_struct *unbind_workq; -+ char unbind_workq_name[KOBJ_NAME_LEN]; ++ struct workqueue_struct *scan_workq; ++ char scan_workq_name[KOBJ_NAME_LEN]; }; /* -@@ -212,8 +218,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, + * session and connection functions that can be used by HW iSCSI LLDs + */ ++#define iscsi_cls_session_printk(prefix, _cls_session, fmt, a...) \ ++ dev_printk(prefix, &(_cls_session)->dev, fmt, ##a) ++ ++#define iscsi_cls_conn_printk(prefix, _cls_conn, fmt, a...) \ ++ dev_printk(prefix, &(_cls_conn)->dev, fmt, ##a) ++ ++extern int iscsi_session_chkready(struct iscsi_cls_session *session); + extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport); extern int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id); @@ -7558,11 +9306,78 @@ index 05e2554..6bda9b9 100644 extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *t, unsigned int target_id); +@@ -225,6 +238,6 @@ extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, + extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); + extern void iscsi_unblock_session(struct iscsi_cls_session *session); + extern void iscsi_block_session(struct iscsi_cls_session *session); +- ++extern int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time); + + #endif +diff --git a/test/regression.sh b/test/regression.sh +index 5b535f7..25d4a28 100755 +--- a/test/regression.sh ++++ b/test/regression.sh +@@ -133,7 +133,7 @@ function bonnie_run() { + + function fatal() { + echo "regression.sh: $1" +- echo "Usage: regression.sh [test#[:#]] [bsize]" ++ echo "Usage: regression.sh [-f | ] [test#[:#]] [bsize]" + exit 1 + } + +@@ -147,18 +147,19 @@ test ! -e ${datfile} && fatal "can not find regression.dat" + test ! -e ${disktest} && fatal "can not find disktest" + test ! -e ${iscsiadm} && fatal "can not find iscsiadm" + test ! -e ${bonnie} && fatal "can not find bonnie++" +-test x$1 = x && fatal "target name parameter error" +-test x$2 = x && fatal "ipnumber parameter error" +-test x$3 = x && fatal "SCSI device parameter error" + + if test x$1 = "x-f" -o x$1 = "x--format"; then +- mkfs_run +- exit +-fi ++ test x$2 = x && fatal "SCSI device parameter error" ++ device=$2 ++else ++ test x$1 = x && fatal "target name parameter error" ++ test x$2 = x && fatal "ipnumber parameter error" ++ test x$3 = x && fatal "SCSI device parameter error" + +-target="$1" +-ipnr="$2" +-device=$3 ++ target="$1" ++ ipnr="$2" ++ device=$3 ++fi + + device_dir="$(dirname ${device})" + device_partition='' +@@ -172,6 +173,11 @@ case "${device_dir}" in + /dev/iscsi/*) device_partition="${device}-part1" ;; + esac + ++if test x$1 = "x-f" -o x$1 = "x--format"; then ++ mkfs_run ++ exit ++fi ++ + if [ -z "${device_partition}" ]; then + echo 'Unable to find device name for first partition.' >&2 + exit 1 diff --git a/usr/Makefile b/usr/Makefile -index db33ed1..e77e7de 100644 +index db33ed1..b3e0e72 100644 --- a/usr/Makefile +++ b/usr/Makefile -@@ -38,19 +38,26 @@ ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iscsi_sysfs.o idb +@@ -34,23 +34,30 @@ CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -I../include -D$(OSNAME) $(IPC_CFLAGS) + PROGRAMS = iscsid iscsiadm iscsistart + + # sources shared between iscsid, iscsiadm and iscsistart +-ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iscsi_sysfs.o idbm.o ++ISCSI_LIB_SRCS = util.o io.o auth.o login.o log.o md5.o sha1.o iface.o idbm.o iscsi_sysfs.o # sources shared between iscsid and iscsiadm COMMON_SRCS = $(ISCSI_LIB_SRCS) # core initiator files @@ -7931,20 +9746,143 @@ index 493be42..e767d6d 100644 typedef struct node_rec { diff --git a/usr/discovery.c b/usr/discovery.c -index f1decef..985a60e 100644 +index f1decef..dab6249 100644 --- a/usr/discovery.c +++ b/usr/discovery.c -@@ -50,6 +50,9 @@ +@@ -50,7 +50,10 @@ static int rediscover = 0; +-int discovery_offload_sendtargets(idbm_t *db, int host_no, int do_login, +static char initiator_name[TARGET_NAME_MAXLEN]; +static char initiator_alias[TARGET_NAME_MAXLEN]; + - int discovery_offload_sendtargets(idbm_t *db, int host_no, int do_login, ++int discovery_offload_sendtargets(int host_no, int do_login, discovery_rec_t *drec) { -@@ -502,36 +505,38 @@ msecs_until(struct timeval *timer) + struct sockaddr_storage ss; +@@ -180,12 +183,12 @@ iterate_targets(iscsi_session_t *session, uint32_t ttt) + return 1; + } + +-static int add_portal(idbm_t *db, discovery_rec_t *drec, +- struct list_head *ifaces, node_rec_t *rec, +- char *address, char *port, char *tag) ++static int add_portal(struct list_head *rec_list, discovery_rec_t *drec, ++ char *targetname, char *address, char *port, char *tag) + { + struct sockaddr_storage ss; + char host[NI_MAXHOST]; ++ struct node_rec *rec; + + /* resolve the address, in case it was a DNS name */ + if (resolve_address(address, port, &ss)) { +@@ -197,6 +200,16 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec, + getnameinfo((struct sockaddr *) &ss, sizeof(ss), + host, sizeof(host), NULL, 0, NI_NUMERICHOST); + ++ rec = calloc(1, sizeof(*rec)); ++ if (!rec) ++ return 0; ++ ++ idbm_node_setup_from_conf(rec); ++ rec->disc_type = drec->type; ++ rec->disc_port = drec->port; ++ strcpy(rec->disc_address, drec->address); ++ ++ strncpy(rec->name, targetname, TARGET_NAME_MAXLEN); + if (tag && *tag) + rec->tpgt = atoi(tag); + else +@@ -207,21 +220,17 @@ static int add_portal(idbm_t *db, discovery_rec_t *drec, + rec->conn[0].port = ISCSI_LISTEN_PORT; + strncpy(rec->conn[0].address, address, NI_MAXHOST); + +- if (idbm_add_nodes(db, rec, drec, ifaces)) +- log_error("Could not add record for %s %s,%d,%d\n", +- rec->name, address, rec->conn[0].port, rec->tpgt); ++ list_add_tail(&rec->list, rec_list); + return 1; + } + + static int +-add_target_record(idbm_t *db, char *name, char *end, +- discovery_rec_t *drec, struct list_head *ifaces, +- char *default_port) ++add_target_record(char *name, char *end, discovery_rec_t *drec, ++ struct list_head *rec_list, char *default_port) + { + char *text = NULL; + char *nul = name; + size_t length; +- node_rec_t rec; + + /* address = IPv4 + * address = [IPv6] +@@ -248,10 +257,6 @@ add_target_record(idbm_t *db, char *name, char *end, + log_error("TargetName %s too long, ignoring", name); + return 0; + } +- +- idbm_node_setup_from_conf(db, &rec); +- strncpy(rec.name, name, TARGET_NAME_MAXLEN); +- + text = name + length; + + /* skip NULs after the name */ +@@ -264,7 +269,7 @@ add_target_record(idbm_t *db, char *name, char *end, + log_error("no default address known for target %s", + name); + return 0; +- } else if (!add_portal(db, drec, ifaces, &rec, drec->address, ++ } else if (!add_portal(rec_list, drec, name, drec->address, + default_port, NULL)) { + log_error("failed to add default portal, ignoring " + "target %s", name); +@@ -302,7 +307,7 @@ add_target_record(idbm_t *db, char *name, char *end, + *temp = '\0'; + } + +- if (!add_portal(db, drec, ifaces, &rec, address, port, ++ if (!add_portal(rec_list, drec, name, address, port, + tag)) { + log_error("failed to add default portal, " + "ignoring target %s", name); +@@ -318,9 +323,9 @@ add_target_record(idbm_t *db, char *name, char *end, + } + + static int +-process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets, ++process_sendtargets_response(struct string_buffer *sendtargets, + int final, discovery_rec_t *drec, +- struct list_head *ifaces, ++ struct list_head *rec_list, + char *default_port) + { + char *start = buffer_data(sendtargets); +@@ -371,8 +376,8 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets, + * the end of. don't bother passing the + * "TargetName=" prefix. + */ +- if (!add_target_record(db, record + 11, text, +- drec, ifaces, ++ if (!add_target_record(record + 11, text, ++ drec, rec_list, + default_port)) { + log_error( + "failed to add target record"); +@@ -400,8 +405,8 @@ process_sendtargets_response(idbm_t *db, struct string_buffer *sendtargets, + "processing final sendtargets record %p, " + "line %s", + record, record); +- if (add_target_record (db, record + 11, text, +- drec, ifaces, default_port)) { ++ if (add_target_record (record + 11, text, ++ drec, rec_list, default_port)) { + num_targets++; + record = NULL; + truncate_buffer(sendtargets, 0); +@@ -502,36 +507,38 @@ msecs_until(struct timeval *timer) return msecs; } @@ -8005,7 +9943,7 @@ index f1decef..985a60e 100644 } static iscsi_session_t * -@@ -548,7 +553,6 @@ init_new_session(struct iscsi_sendtargets_config *config) +@@ -548,7 +555,6 @@ init_new_session(struct iscsi_sendtargets_config *config) session->conn[0].login_timeout = config->conn_timeo.login_timeout; session->conn[0].auth_timeout = config->conn_timeo.auth_timeout; session->conn[0].active_timeout = config->conn_timeo.active_timeout; @@ -8013,7 +9951,7 @@ index f1decef..985a60e 100644 session->conn[0].hdrdgst_en = ISCSI_DIGEST_NONE; session->conn[0].datadgst_en = ISCSI_DIGEST_NONE; -@@ -577,6 +581,12 @@ init_new_session(struct iscsi_sendtargets_config *config) +@@ -577,6 +583,12 @@ init_new_session(struct iscsi_sendtargets_config *config) session->isid[5] = 0; /* initialize the session */ @@ -8026,7 +9964,17 @@ index f1decef..985a60e 100644 session->initiator_name = initiator_name; session->initiator_alias = initiator_alias; session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN; -@@ -680,7 +690,6 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, +@@ -672,15 +684,14 @@ setup_authentication(iscsi_session_t *session, + } + + static int +-process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, ++process_recvd_pdu(struct iscsi_hdr *pdu, + discovery_rec_t *drec, +- struct list_head *ifaces, ++ struct list_head *rec_list, + iscsi_session_t *session, + struct string_buffer *sendtargets, char *default_port, int *active, int *valid_text, @@ -8034,7 +9982,7 @@ index f1decef..985a60e 100644 char *data) { int rc=0; -@@ -693,6 +702,7 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, +@@ -693,6 +704,7 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, int final = (text_response->flags & ISCSI_FLAG_CMD_FINAL) || (text_response-> ttt == ISCSI_RESERVED_TAG); @@ -8042,7 +9990,7 @@ index f1decef..985a60e 100644 log_debug(4, "discovery session to %s:%d received text" " response, %d data bytes, ttt 0x%x, " -@@ -706,7 +716,10 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, +@@ -706,24 +718,17 @@ process_recvd_pdu(idbm_t *db, struct iscsi_hdr *pdu, /* mark how much more data in the sendtargets * buffer is now valid */ @@ -8052,9 +10000,38 @@ index f1decef..985a60e 100644 + memcpy(buffer_data(sendtargets) + curr_data_length, + data, dlength); - /* - * we got a response so clear out the current -@@ -822,14 +835,13 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, +- /* +- * we got a response so clear out the current +- * db values +- * +- * TODO: should we make whether rm the current +- * values configurable (maybe a --clear option) +- */ +- if (!*valid_text) +- idbm_new_discovery(db, drec); + *valid_text = 1; +- + /* process as much as we can right now */ +- process_sendtargets_response(db, sendtargets, ++ process_sendtargets_response(sendtargets, + final, + drec, +- ifaces, ++ rec_list, + default_port); + + if (final) { +@@ -814,22 +819,21 @@ done: + iscsi_io_disconnect(&session->conn[0]); + } + +-int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, +- struct list_head *ifaces) ++int discovery_sendtargets(discovery_rec_t *drec, ++ struct list_head *rec_list) + { + iscsi_session_t *session; + struct pollfd pfd; struct iscsi_hdr pdu_buffer; struct iscsi_hdr *pdu = &pdu_buffer; char *data = NULL; @@ -8071,7 +10048,7 @@ index f1decef..985a60e 100644 int login_delay = 0; struct sockaddr_storage ss; char host[NI_MAXHOST], serv[NI_MAXSERV], default_port[NI_MAXSERV]; -@@ -840,13 +852,13 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, +@@ -840,13 +844,13 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, drec->address, drec->port); memset(&pdu_buffer, 0, sizeof (pdu_buffer)); clear_timer(&connection_timer); @@ -8088,7 +10065,7 @@ index f1decef..985a60e 100644 return 1; } -@@ -856,13 +868,15 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, +@@ -856,13 +860,15 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, session->isid[1], session->isid[2], session->isid[3], session->isid[4], session->isid[5]); @@ -8108,7 +10085,7 @@ index f1decef..985a60e 100644 sprintf(default_port, "%d", drec->port); /* resolve the DiscoveryAddress to an IP address */ -@@ -872,11 +886,9 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, +@@ -872,11 +878,9 @@ int discovery_sendtargets(idbm_t *db, discovery_rec_t *drec, goto free_sendtargets; } @@ -8122,7 +10099,7 @@ index f1decef..985a60e 100644 /* setup authentication variables for the session*/ rc = setup_authentication(session, drec, config); -@@ -958,8 +970,9 @@ redirect_reconnect: +@@ -958,8 +962,9 @@ redirect_reconnect: status_class = 0; status_detail = 0; @@ -8134,7 +10111,15 @@ index f1decef..985a60e 100644 &status_class, &status_detail); switch (rc) { -@@ -1047,13 +1060,9 @@ redirect_reconnect: +@@ -968,7 +973,6 @@ redirect_reconnect: + break; + + case LOGIN_IO_ERROR: +- case LOGIN_WRONG_PORTAL_GROUP: + case LOGIN_REDIRECTION_FAILED: + /* try again */ + log_warning("retrying discovery login to %s", host); +@@ -1047,13 +1051,9 @@ redirect_reconnect: goto reconnect; } @@ -8148,7 +10133,7 @@ index f1decef..985a60e 100644 /* ask for targets */ if (!request_targets(session)) { goto reconnect; -@@ -1068,40 +1077,8 @@ redirect_reconnect: +@@ -1068,40 +1068,8 @@ redirect_reconnect: pfd.fd = session->conn[0].socket_fd; pfd.events = POLLIN | POLLPRI; @@ -8191,7 +10176,7 @@ index f1decef..985a60e 100644 /* block until we receive a PDU, a TCP FIN, a TCP RST, * or a timeout */ -@@ -1118,50 +1095,24 @@ redirect_reconnect: +@@ -1118,50 +1086,24 @@ redirect_reconnect: "discovery process to %s:%d returned from poll, rc %d", drec->address, drec->port, rc); @@ -8256,7 +10241,7 @@ index f1decef..985a60e 100644 log_debug(1, "discovery session to " "%s:%d failed to recv a PDU " "response, terminating", -@@ -1171,7 +1122,25 @@ redirect_reconnect: +@@ -1171,7 +1113,25 @@ redirect_reconnect: rc = 1; goto free_sendtargets; } @@ -8264,7 +10249,7 @@ index f1decef..985a60e 100644 + /* + * process iSCSI PDU received + */ -+ rc = process_recvd_pdu(db, pdu, drec, ifaces, ++ rc = process_recvd_pdu(pdu, drec, rec_list, + session, &sendtargets, + default_port, + &active, &valid_text, data); @@ -8282,7 +10267,7 @@ index f1decef..985a60e 100644 if (pfd.revents & POLLHUP) { log_warning("discovery session to %s:%d " "terminating after hangup", -@@ -1213,6 +1182,7 @@ redirect_reconnect: +@@ -1213,6 +1173,7 @@ redirect_reconnect: free_sendtargets: free_string_buffer(&sendtargets); @@ -8291,10 +10276,10 @@ index f1decef..985a60e 100644 free(session); return rc; diff --git a/usr/idbm.c b/usr/idbm.c -index dcdae56..bd46824 100644 +index dcdae56..389d904 100644 --- a/usr/idbm.c +++ b/usr/idbm.c -@@ -24,13 +24,10 @@ +@@ -24,13 +24,11 @@ #include #include #include @@ -8302,21 +10287,106 @@ index dcdae56..bd46824 100644 #include -#include #include ++#include #include #include -#include #include "idbm.h" #include "log.h" -@@ -103,10 +100,44 @@ +@@ -38,12 +36,15 @@ + #include "iscsi_settings.h" + #include "transport.h" + #include "iscsi_sysfs.h" ++#include "iface.h" + + #define IDBM_HIDE 0 /* Hide parameter when print. */ + #define IDBM_SHOW 1 /* Show parameter when print. */ + #define IDBM_MASKED 2 /* Show "stars" instead of real value when print */ + +-#define __recinfo_str(_key, _info, _rec, _name, _show, _n) do { \ ++static struct idbm *db; ++ ++#define __recinfo_str(_key, _info, _rec, _name, _show, _n, _mod) do { \ + _info[_n].type = TYPE_STR; \ + strncpy(_info[_n].name, _key, NAME_MAXVAL); \ + if (strlen((char*)_rec->_name)) \ +@@ -52,20 +53,22 @@ + _info[_n].data = &_rec->_name; \ + _info[_n].data_len = sizeof(_rec->_name); \ + _info[_n].visible = _show; \ ++ _info[_n].can_modify = _mod; \ _n++; \ } while(0) -+#define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2,\ -+ _op3,_op4,_op5,_n)\ -+do{\ -+ __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,\ -+ _op4,_n); _n--; \ +-#define __recinfo_int(_key, _info, _rec, _name, _show, _n) do { \ ++#define __recinfo_int(_key, _info, _rec, _name, _show, _n, _mod) do { \ + _info[_n].type = TYPE_INT; \ + strncpy(_info[_n].name, _key, NAME_MAXVAL); \ + snprintf(_info[_n].value, VALUE_MAXVAL, "%d", _rec->_name); \ + _info[_n].data = &_rec->_name; \ + _info[_n].data_len = sizeof(_rec->_name); \ + _info[_n].visible = _show; \ ++ _info[_n].can_modify = _mod; \ + _n++; \ + } while(0) + +-#define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n) do { \ ++#define __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod) do { \ + _info[_n].type = TYPE_INT_O; \ + strncpy(_info[_n].name, _key, NAME_MAXVAL); \ + if (_rec->_name == 0) strncpy(_info[_n].value, _op0, VALUE_MAXVAL); \ +@@ -76,37 +79,79 @@ + _info[_n].opts[0] = _op0; \ + _info[_n].opts[1] = _op1; \ + _info[_n].numopts = 2; \ ++ _info[_n].can_modify = _mod; \ + _n++; \ + } while(0) + +-#define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n)do{ \ +- __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n); _n--; \ +- if (_rec->_name == 2) strncpy(_info[_n].value, _op2, VALUE_MAXVAL); \ ++#define __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, \ ++ _mod) do { \ ++ __recinfo_int_o2(_key,_info,_rec,_name,_show,_op0,_op1,_n, _mod); \ ++ _n--; \ ++ if (_rec->_name == 2) strncpy(_info[_n].value, _op2, VALUE_MAXVAL);\ + _info[_n].opts[2] = _op2; \ + _info[_n].numopts = 3; \ + _n++; \ + } while(0) + +-#define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n)do{\ +- __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n); _n--; \ ++#define __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n, \ ++ _mod) do { \ ++ __recinfo_int_o3(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_n, _mod); \ ++ _n--; \ + if (_rec->_name == 3) strncpy(_info[_n].value, _op3, VALUE_MAXVAL); \ + _info[_n].opts[3] = _op3; \ + _info[_n].numopts = 4; \ + _n++; \ + } while(0) + +-#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_op4,_n)do{\ +- __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3,_n); _n--; \ ++#define __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ ++ _op4,_n, _mod) do { \ ++ __recinfo_int_o4(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ ++ _n,_mod); \ ++ _n--; \ + if (_rec->_name == 4) strncpy(_info[_n].value, _op4, VALUE_MAXVAL); \ + _info[_n].opts[4] = _op4; \ + _info[_n].numopts = 5; \ + _n++; \ + } while(0) + ++#define __recinfo_int_o6(_key,_info,_rec,_name,_show,_op0,_op1,_op2, \ ++ _op3,_op4,_op5,_n,_mod) do { \ ++ __recinfo_int_o5(_key,_info,_rec,_name,_show,_op0,_op1,_op2,_op3, \ ++ _op4,_n,_mod); \ ++ _n--; \ + if (_rec->_name == 5) strncpy(_info[_n].value, _op5, VALUE_MAXVAL); \ + _info[_n].opts[5] = _op5; \ + _info[_n].numopts = 6; \ @@ -8354,7 +10424,7 @@ index dcdae56..bd46824 100644 char *line, buffer[1024]; char *name = NULL; -@@ -119,30 +150,21 @@ static char *get_global_string_param(char *pathname, const char *key) +@@ -119,30 +164,21 @@ static char *get_global_string_param(char *pathname, const char *key) if ((f = fopen(pathname, "r"))) { while ((line = fgets(buffer, sizeof (buffer), f))) { @@ -8391,7 +10461,7 @@ index dcdae56..bd46824 100644 log_debug(5, "%s=%s", key, name); } else log_error("can't open %s configuration file %s", key, pathname); -@@ -152,7 +174,13 @@ static char *get_global_string_param(char *pathname, const char *key) +@@ -152,7 +188,13 @@ static char *get_global_string_param(char *pathname, const char *key) char *get_iscsi_initiatorname(char *pathname) { @@ -8406,21 +10476,60 @@ index dcdae56..bd46824 100644 } char *get_iscsi_initiatoralias(char *pathname) -@@ -167,9 +195,9 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) +@@ -166,50 +208,47 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) + int num = 0; __recinfo_int_o2("discovery.startup", ri, r, startup, IDBM_SHOW, - "manual", "automatic", num); +- "manual", "automatic", num); - __recinfo_int_o5("discovery.type", ri, r, type, IDBM_SHOW, ++ "manual", "automatic", num, 1); + __recinfo_int_o6("discovery.type", ri, r, type, IDBM_SHOW, "sendtargets", "offload_send_targets", "slp", "isns", - "static", num); -+ "static", "fw", num); ++ "static", "fw", num, 0); if (r->type == DISCOVERY_TYPE_SENDTARGETS) { __recinfo_str("discovery.sendtargets.address", ri, r, - address, IDBM_SHOW, num); -@@ -202,11 +230,8 @@ idbm_recinfo_discovery(discovery_rec_t *r, recinfo_t *ri) +- address, IDBM_SHOW, num); ++ address, IDBM_SHOW, num, 0); + __recinfo_int("discovery.sendtargets.port", ri, r, +- port, IDBM_SHOW, num); ++ port, IDBM_SHOW, num, 0); + __recinfo_int_o2("discovery.sendtargets.auth.authmethod", ri, r, + u.sendtargets.auth.authmethod, +- IDBM_SHOW, "None", "CHAP", num); ++ IDBM_SHOW, "None", "CHAP", num, 1); + __recinfo_str("discovery.sendtargets.auth.username", ri, r, +- u.sendtargets.auth.username, IDBM_SHOW, num); ++ u.sendtargets.auth.username, IDBM_SHOW, num, 1); + __recinfo_str("discovery.sendtargets.auth.password", ri, r, +- u.sendtargets.auth.password, IDBM_MASKED, num); ++ u.sendtargets.auth.password, IDBM_MASKED, num, 1); + __recinfo_int("discovery.sendtargets.auth.password_length", + ri, r, u.sendtargets.auth.password_length, +- IDBM_HIDE, num); ++ IDBM_HIDE, num, 1); + __recinfo_str("discovery.sendtargets.auth.username_in", ri, r, +- u.sendtargets.auth.username_in, IDBM_SHOW, num); ++ u.sendtargets.auth.username_in, IDBM_SHOW, num, 1); + __recinfo_str("discovery.sendtargets.auth.password_in", ri, r, +- u.sendtargets.auth.password_in, IDBM_MASKED, num); ++ u.sendtargets.auth.password_in, IDBM_MASKED, num, 1); + __recinfo_int("discovery.sendtargets.auth.password_in_length", + ri, r, u.sendtargets.auth.password_in_length, +- IDBM_HIDE, num); ++ IDBM_HIDE, num, 1); + __recinfo_int("discovery.sendtargets.timeo.login_timeout",ri, r, + u.sendtargets.conn_timeo.login_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + __recinfo_int("discovery.sendtargets.reopen_max",ri, r, + u.sendtargets.reopen_max, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + __recinfo_int("discovery.sendtargets.timeo.auth_timeout", ri, r, u.sendtargets.conn_timeo.auth_timeout, - IDBM_SHOW, num); +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); __recinfo_int("discovery.sendtargets.timeo.active_timeout",ri,r, - u.sendtargets.conn_timeo.active_timeout, - IDBM_SHOW, num); @@ -8428,43 +10537,182 @@ index dcdae56..bd46824 100644 - u.sendtargets.conn_timeo.idle_timeout, - IDBM_SHOW, num); + u.sendtargets.conn_timeo.active_timeout, -+ IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); __recinfo_int("discovery.sendtargets.iscsi.MaxRecvDataSegmentLength", ri, r, u.sendtargets.iscsi.MaxRecvDataSegmentLength, - IDBM_SHOW, num); -@@ -239,9 +264,9 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + } + } + +@@ -218,159 +257,170 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) + { + int num = 0, i; + +- __recinfo_str("node.name", ri, r, name, IDBM_SHOW, num); +- __recinfo_int("node.tpgt", ri, r, tpgt, IDBM_SHOW, num); ++ __recinfo_str("node.name", ri, r, name, IDBM_SHOW, num, 0); ++ __recinfo_int("node.tpgt", ri, r, tpgt, IDBM_SHOW, num, 0); + __recinfo_int_o3("node.startup", ri, r, startup, +- IDBM_SHOW, "manual", "automatic", "onboot", num); ++ IDBM_SHOW, "manual", "automatic", "onboot", num, 1); ++ /* ++ * Note: because we do not add the iface.iscsi_ifacename to ++ * sysfs iscsiadm does some weird matching. We can change the iface ++ * values if a session is not running, but node record ifaces values ++ * have to be changed and so do the iface record ones. ++ * ++ * Users should nornmally not want to change the iface ones ++ * in the node record directly and instead do it through ++ * the iface mode which will do the right thing (althought that ++ * needs some locking). ++ */ + __recinfo_str("iface.hwaddress", ri, r, iface.hwaddress, IDBM_SHOW, +- num); ++ num, 1); + // __recinfo_str("iface.ipaddress", ri, r, iface.ipaddress, + // IDBM_SHOW, num); + __recinfo_str("iface.iscsi_ifacename", ri, r, iface.name, IDBM_SHOW, +- num); ++ num, 1); + __recinfo_str("iface.net_ifacename", ri, r, iface.netdev, IDBM_SHOW, +- num); ++ num, 1); + /* + * svn 780 compat: older versions used node.transport_name and + * rec->transport_name + */ + __recinfo_str("iface.transport_name", ri, r, iface.transport_name, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); ++ __recinfo_str("iface.initiatorname", ri, r, iface.iname, ++ IDBM_SHOW, num, 1); __recinfo_str("node.discovery_address", ri, r, disc_address, IDBM_SHOW, - num); - __recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, num); +- num); +- __recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, num); - __recinfo_int_o5("node.discovery_type", ri, r, disc_type, ++ num, 0); ++ __recinfo_int("node.discovery_port", ri, r, disc_port, IDBM_SHOW, ++ num, 0); + __recinfo_int_o6("node.discovery_type", ri, r, disc_type, IDBM_SHOW, "send_targets", "offload_send_targets", - "slp", "isns", "static", num); -+ "slp", "isns", "static", "fw", num); ++ "slp", "isns", "static", "fw", num, 0); __recinfo_int("node.session.initial_cmdsn", ri, r, - session.initial_cmdsn, IDBM_SHOW, num); +- session.initial_cmdsn, IDBM_SHOW, num); ++ session.initial_cmdsn, IDBM_SHOW, num, 1); __recinfo_int("node.session.initial_login_retry_max", ri, r, -@@ -270,9 +295,14 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) +- session.initial_login_retry_max, IDBM_SHOW, num); ++ session.initial_login_retry_max, IDBM_SHOW, num, 1); + __recinfo_int("node.session.cmds_max", ri, r, +- session.cmds_max, IDBM_SHOW, num); ++ session.cmds_max, IDBM_SHOW, num, 1); + __recinfo_int("node.session.queue_depth", ri, r, +- session.queue_depth, IDBM_SHOW, num); ++ session.queue_depth, IDBM_SHOW, num, 1); + __recinfo_int_o2("node.session.auth.authmethod", ri, r, +- session.auth.authmethod, IDBM_SHOW, "None", "CHAP", num); ++ session.auth.authmethod, IDBM_SHOW, "None", "CHAP", num, 1); + __recinfo_str("node.session.auth.username", ri, r, +- session.auth.username, IDBM_SHOW, num); ++ session.auth.username, IDBM_SHOW, num, 1); + __recinfo_str("node.session.auth.password", ri, r, +- session.auth.password, IDBM_MASKED, num); ++ session.auth.password, IDBM_MASKED, num, 1); + __recinfo_int("node.session.auth.password_length", ri, r, +- session.auth.password_length, IDBM_HIDE, num); ++ session.auth.password_length, IDBM_HIDE, num, 1); + __recinfo_str("node.session.auth.username_in", ri, r, +- session.auth.username_in, IDBM_SHOW, num); ++ session.auth.username_in, IDBM_SHOW, num, 1); + __recinfo_str("node.session.auth.password_in", ri, r, +- session.auth.password_in, IDBM_MASKED, num); ++ session.auth.password_in, IDBM_MASKED, num, 1); + __recinfo_int("node.session.auth.password_in_length", ri, r, +- session.auth.password_in_length, IDBM_HIDE, num); ++ session.auth.password_in_length, IDBM_HIDE, num, 1); + __recinfo_int("node.session.timeo.replacement_timeout", ri, r, + session.timeo.replacement_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); __recinfo_int("node.session.err_timeo.abort_timeout", ri, r, session.err_timeo.abort_timeout, - IDBM_SHOW, num); +- IDBM_SHOW, num); - __recinfo_int("node.session.err_timeo.reset_timeout", ri, r, - session.err_timeo.reset_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + __recinfo_int("node.session.err_timeo.lu_reset_timeout", ri, r, + session.err_timeo.lu_reset_timeout, -+ IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + __recinfo_int("node.session.err_timeo.host_reset_timeout", ri, r, + session.err_timeo.host_reset_timeout, - IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + __recinfo_int_o2("node.session.iscsi.FastAbort", ri, r, -+ session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes", num); ++ session.iscsi.FastAbort, IDBM_SHOW, "No", "Yes", ++ num, 1); __recinfo_int_o2("node.session.iscsi.InitialR2T", ri, r, session.iscsi.InitialR2T, IDBM_SHOW, - "No", "Yes", num); -@@ -319,15 +349,6 @@ idbm_recinfo_node(node_rec_t *r, recinfo_t *ri) +- "No", "Yes", num); ++ "No", "Yes", num, 1); + __recinfo_int_o2("node.session.iscsi.ImmediateData", + ri, r, session.iscsi.ImmediateData, IDBM_SHOW, +- "No", "Yes", num); ++ "No", "Yes", num, 1); + __recinfo_int("node.session.iscsi.FirstBurstLength", ri, r, +- session.iscsi.FirstBurstLength, IDBM_SHOW, num); ++ session.iscsi.FirstBurstLength, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.MaxBurstLength", ri, r, +- session.iscsi.MaxBurstLength, IDBM_SHOW, num); ++ session.iscsi.MaxBurstLength, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.DefaultTime2Retain", ri, r, +- session.iscsi.DefaultTime2Retain, IDBM_SHOW, num); ++ session.iscsi.DefaultTime2Retain, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.DefaultTime2Wait", ri, r, +- session.iscsi.DefaultTime2Wait, IDBM_SHOW, num); ++ session.iscsi.DefaultTime2Wait, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.MaxConnections", ri, r, +- session.iscsi.MaxConnections, IDBM_SHOW, num); ++ session.iscsi.MaxConnections, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.MaxOutstandingR2T", ri, r, +- session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num); ++ session.iscsi.MaxOutstandingR2T, IDBM_SHOW, num, 1); + __recinfo_int("node.session.iscsi.ERL", ri, r, +- session.iscsi.ERL, IDBM_SHOW, num); ++ session.iscsi.ERL, IDBM_SHOW, num, 1); + + for (i = 0; i < ISCSI_CONN_MAX; i++) { + char key[NAME_MAXVAL]; + + sprintf(key, "node.conn[%d].address", i); +- __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num); ++ __recinfo_str(key, ri, r, conn[i].address, IDBM_SHOW, num, 0); + sprintf(key, "node.conn[%d].port", i); +- __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num); ++ __recinfo_int(key, ri, r, conn[i].port, IDBM_SHOW, num, 0); + sprintf(key, "node.conn[%d].startup", i); + __recinfo_int_o3(key, ri, r, conn[i].startup, IDBM_SHOW, +- "manual", "automatic", "onboot", num); ++ "manual", "automatic", "onboot", num, 1); + sprintf(key, "node.conn[%d].tcp.window_size", i); + __recinfo_int(key, ri, r, conn[i].tcp.window_size, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + sprintf(key, "node.conn[%d].tcp.type_of_service", i); + __recinfo_int(key, ri, r, conn[i].tcp.type_of_service, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + sprintf(key, "node.conn[%d].timeo.logout_timeout", i); + __recinfo_int(key, ri, r, conn[i].timeo.logout_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + sprintf(key, "node.conn[%d].timeo.login_timeout", i); + __recinfo_int(key, ri, r, conn[i].timeo.login_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); sprintf(key, "node.conn[%d].timeo.auth_timeout", i); __recinfo_int(key, ri, r, conn[i].timeo.auth_timeout, - IDBM_SHOW, num); +- IDBM_SHOW, num); - sprintf(key, "node.conn[%d].timeo.active_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.active_timeout, - IDBM_SHOW, num); @@ -8474,10 +10722,103 @@ index dcdae56..bd46824 100644 - sprintf(key, "node.conn[%d].timeo.ping_timeout", i); - __recinfo_int(key, ri, r, conn[i].timeo.ping_timeout, - IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); sprintf(key, "node.conn[%d].timeo.noop_out_interval", i); __recinfo_int(key, ri, r, conn[i].timeo.noop_out_interval, -@@ -444,7 +465,6 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type) +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + sprintf(key, "node.conn[%d].timeo.noop_out_timeout", i); + __recinfo_int(key, ri, r, conn[i].timeo.noop_out_timeout, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); + + sprintf(key, "node.conn[%d].iscsi.MaxRecvDataSegmentLength", i); + __recinfo_int(key, ri, r, +- conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW, num); ++ conn[i].iscsi.MaxRecvDataSegmentLength, IDBM_SHOW, ++ num, 1); + sprintf(key, "node.conn[%d].iscsi.HeaderDigest", i); + __recinfo_int_o4(key, ri, r, conn[i].iscsi.HeaderDigest, + IDBM_SHOW, "None", "CRC32C", "CRC32C,None", +- "None,CRC32C", num); ++ "None,CRC32C", num, 1); + sprintf(key, "node.conn[%d].iscsi.DataDigest", i); + __recinfo_int_o4(key, ri, r, conn[i].iscsi.DataDigest, IDBM_SHOW, + "None", "CRC32C", "CRC32C,None", +- "None,CRC32C", num); ++ "None,CRC32C", num, 1); + sprintf(key, "node.conn[%d].iscsi.IFMarker", i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.IFMarker, IDBM_SHOW, +- "No", "Yes", num); ++ "No", "Yes", num, 1); + sprintf(key, "node.conn[%d].iscsi.OFMarker", i); + __recinfo_int_o2(key, ri, r, conn[i].iscsi.OFMarker, IDBM_SHOW, +- "No", "Yes", num); ++ "No", "Yes", num, 1); + } + } + +-static void +-idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) ++void idbm_recinfo_iface(iface_rec_t *r, recinfo_t *ri) + { + int num = 0; + +- __recinfo_str("iface.iscsi_ifacename", ri, r, name, IDBM_SHOW, num); +- __recinfo_str("iface.net_ifacename", ri, r, netdev, IDBM_SHOW, num); +-// __recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num); +- __recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num); ++ __recinfo_str("iface.iscsi_ifacename", ri, r, name, IDBM_SHOW, num, 0); ++ __recinfo_str("iface.net_ifacename", ri, r, netdev, IDBM_SHOW, num, 1); ++// __recinfo_str("iface.ipaddress", ri, r, ipaddress, IDBM_SHOW, num, 1); ++ __recinfo_str("iface.hwaddress", ri, r, hwaddress, IDBM_SHOW, num, 1); + __recinfo_str("iface.transport_name", ri, r, transport_name, +- IDBM_SHOW, num); ++ IDBM_SHOW, num, 1); ++ __recinfo_str("iface.initiatorname", ri, r, iname, IDBM_SHOW, num, 1); + } + +-static recinfo_t* +-idbm_recinfo_alloc(int max_keys) ++recinfo_t *idbm_recinfo_alloc(int max_keys) + { + recinfo_t *info; + +@@ -381,14 +431,7 @@ idbm_recinfo_alloc(int max_keys) + return info; + } + +-enum { +- PRINT_TYPE_DISCOVERY, +- PRINT_TYPE_NODE, +- PRINT_TYPE_IFACE, +-}; +- +-static void +-idbm_print(int type, void *rec, int show, FILE *f) ++void idbm_print(int type, void *rec, int show, FILE *f) + { + int i; + recinfo_t *info; +@@ -398,13 +441,13 @@ idbm_print(int type, void *rec, int show, FILE *f) + return; + + switch (type) { +- case PRINT_TYPE_DISCOVERY: ++ case IDBM_PRINT_TYPE_DISCOVERY: + idbm_recinfo_discovery((discovery_rec_t*)rec, info); + break; +- case PRINT_TYPE_NODE: ++ case IDBM_PRINT_TYPE_NODE: + idbm_recinfo_node((node_rec_t*)rec, info); + break; +- case PRINT_TYPE_IFACE: ++ case IDBM_PRINT_TYPE_IFACE: + idbm_recinfo_iface((struct iface_rec *)rec, info); + break; + } +@@ -444,7 +487,6 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type) rec->u.sendtargets.conn_timeo.login_timeout=15; rec->u.sendtargets.conn_timeo.auth_timeout = 45; rec->u.sendtargets.conn_timeo.active_timeout=30; @@ -8485,7 +10826,52 @@ index dcdae56..bd46824 100644 rec->u.sendtargets.iscsi.MaxRecvDataSegmentLength = DEF_INI_DISC_MAX_RECV_SEG_LEN; } else if (type == DISCOVERY_TYPE_SLP) { -@@ -538,7 +558,7 @@ idbm_recinfo_config(recinfo_t *info, FILE *f) +@@ -460,9 +502,8 @@ idbm_discovery_setup_defaults(discovery_rec_t *rec, discovery_type_e type) + } + } + +-static int +-idbm_node_update_param(recinfo_t *info, char *name, char *value, +- int line_number) ++int idbm_rec_update_param(recinfo_t *info, char *name, char *value, ++ int line_number) + { + int i; + int passwd_done = 0; +@@ -531,14 +572,38 @@ updated: + return 0; + } + +-static void +-idbm_recinfo_config(recinfo_t *info, FILE *f) ++/* ++ * TODO: we can also check for valid values here. ++ */ ++int idbm_verify_param(recinfo_t *info, char *name) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_KEYS; i++) { ++ if (strcmp(name, info[i].name)) ++ continue; ++ ++ log_debug(7, "verify %s %d\n", name, info[i].can_modify); ++ if (info[i].can_modify) ++ return 0; ++ else { ++ log_error("Cannot modify %s. It is used to look up " ++ "the record and cannot be changed.", name); ++ return EINVAL; ++ } ++ } ++ ++ log_error("Cannot modify %s. Invalid param name.", name); ++ return EINVAL; ++} ++ ++void idbm_recinfo_config(recinfo_t *info, FILE *f) + { + char name[NAME_MAXVAL]; char value[VALUE_MAXVAL]; char *line, *nl, buffer[2048]; int line_number = 0; @@ -8494,7 +10880,7 @@ index dcdae56..bd46824 100644 fseek(f, 0, SEEK_SET); -@@ -549,27 +569,16 @@ idbm_recinfo_config(recinfo_t *info, FILE *f) +@@ -549,27 +614,16 @@ idbm_recinfo_config(recinfo_t *info, FILE *f) if (!line) continue; @@ -8526,15 +10912,27 @@ index dcdae56..bd46824 100644 continue; /* parse name */ -@@ -616,6 +625,7 @@ idbm_recinfo_config(recinfo_t *info, FILE *f) - static void - idbm_sync_config(idbm_t *db) +@@ -606,16 +660,16 @@ idbm_recinfo_config(recinfo_t *info, FILE *f) + } + *(value+i) = 0; + +- (void)idbm_node_update_param(info, name, value, line_number); ++ (void)idbm_rec_update_param(info, name, value, line_number); + } while (line); + } + + /* + * TODO: remove db's copy of nrec and infos + */ +-static void +-idbm_sync_config(idbm_t *db) ++static void idbm_sync_config(void) { + char *config_file; FILE *f; /* in case of no configuration file found we just -@@ -631,15 +641,25 @@ idbm_sync_config(idbm_t *db) +@@ -631,15 +685,25 @@ idbm_sync_config(idbm_t *db) idbm_recinfo_discovery(&db->drec_isns, db->dinfo_isns); idbm_recinfo_node(&db->nrec, db->ninfo); @@ -8564,7 +10962,57 @@ index dcdae56..bd46824 100644 idbm_recinfo_config(db->dinfo_st, f); idbm_recinfo_config(db->dinfo_slp, f); -@@ -705,13 +725,15 @@ int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec) +@@ -668,29 +732,37 @@ idbm_sync_config(idbm_t *db) + strlen((char*)db->nrec.session.auth.password_in); + } + +-void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec) ++void idbm_node_setup_from_conf(node_rec_t *rec) + { + memset(rec, 0, sizeof(*rec)); + idbm_node_setup_defaults(rec); +- idbm_sync_config(db); ++ idbm_sync_config(); + memcpy(rec, &db->nrec, sizeof(*rec)); + } + +-int idbm_print_discovery_info(idbm_t *db, discovery_rec_t *rec, int show) ++int idbm_print_discovery_info(discovery_rec_t *rec, int show) + { +- idbm_print(PRINT_TYPE_DISCOVERY, rec, show, stdout); ++ idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, show, stdout); + return 1; + } + +-int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec) ++int idbm_print_node_info(void *data, node_rec_t *rec) ++{ ++ int show = *((int *)data); ++ ++ idbm_print(IDBM_PRINT_TYPE_NODE, rec, show, stdout); ++ return 0; ++} ++ ++int idbm_print_iface_info(void *data, struct iface_rec *iface) + { + int show = *((int *)data); + +- idbm_print(PRINT_TYPE_NODE, rec, show, stdout); ++ idbm_print(IDBM_PRINT_TYPE_IFACE, iface, show, stdout); + return 0; + } + +-int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec) ++int idbm_print_node_flat(void *data, node_rec_t *rec) + { + if (strchr(rec->conn[0].address, '.')) + printf("%s:%d,%d %s\n", rec->conn[0].address, rec->conn[0].port, +@@ -701,17 +773,19 @@ int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec) + return 0; + } + +-int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec) ++int idbm_print_node_tree(void *data, node_rec_t *rec) { node_rec_t *last_rec = data; @@ -8584,7 +11032,7 @@ index dcdae56..bd46824 100644 if (strchr(rec->conn[0].address, '.')) printf("\tPortal: %s:%d,%d\n", rec->conn[0].address, rec->conn[0].port, rec->tpgt); -@@ -722,7 +744,8 @@ int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec) +@@ -722,7 +796,8 @@ int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec) printf("\t\tIface Name: %s\n", rec->iface.name); @@ -8594,109 +11042,904 @@ index dcdae56..bd46824 100644 return 0; } -@@ -827,7 +850,7 @@ struct iface_rec *iface_alloc(char *ifname, int *err) - return iface; +@@ -750,7 +825,7 @@ get_params_from_disc_link(char *link, char **target, char **tpgt, + return 0; } +-static int idbm_lock(idbm_t *db) ++int idbm_lock(void) + { + int fd, i, ret; + +@@ -782,7 +857,7 @@ static int idbm_lock(idbm_t *db) + return 0; + } + +-static void idbm_unlock(idbm_t *db) ++void idbm_unlock(void) + { + if (db->refs > 1) { + db->refs--; +@@ -794,551 +869,6 @@ static void idbm_unlock(idbm_t *db) + } + + /* +- * default is to use tcp through whatever the network layer +- * selects for us +- */ +-void iface_init(struct iface_rec *iface) +-{ +- sprintf(iface->netdev, DEFAULT_NETDEV); +-// sprintf(iface->ipaddress, DEFAULT_IPADDRESS); +- sprintf(iface->hwaddress, DEFAULT_HWADDRESS); +- sprintf(iface->transport_name, DEFAULT_TRANSPORT); +- if (!strlen(iface->name)) +- sprintf(iface->name, DEFAULT_IFACENAME); +-} +- +-struct iface_rec *iface_alloc(char *ifname, int *err) +-{ +- struct iface_rec *iface; +- +- if (!strlen(ifname) || strlen(ifname) + 1 > ISCSI_MAX_IFACE_LEN) { +- *err = EINVAL; +- return NULL; +- } +- +- iface = calloc(1, sizeof(*iface)); +- if (!iface) { +- *err = ENOMEM; +- return NULL; +- } +- +- strncpy(iface->name, ifname, ISCSI_MAX_IFACE_LEN); +- INIT_LIST_HEAD(&iface->list); +- return iface; +-} +- -int iface_conf_read(struct iface_rec *iface) -+static int __iface_conf_read(struct iface_rec *iface) - { - char *iface_conf; - recinfo_t *info; -@@ -874,7 +897,17 @@ free_conf: - return rc; +-{ +- char *iface_conf; +- recinfo_t *info; +- FILE *f; +- int rc = 0; +- +- iface_conf = calloc(1, PATH_MAX); +- if (!iface_conf) +- return ENOMEM; +- +- info = idbm_recinfo_alloc(MAX_KEYS); +- if (!info) { +- rc = ENOMEM; +- goto free_conf; +- } +- +- snprintf(iface_conf, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR, +- iface->name); +- +- log_debug(5, "looking for iface conf %s", iface_conf); +- f = fopen(iface_conf, "r"); +- if (!f) { +- /* +- * if someone passes in default but has not defined +- * a iface with default then we do it for them +- */ +- if (!strcmp(iface->name, DEFAULT_IFACENAME)) { +- iface_init(iface); +- rc = 0; +- } else +- rc = errno; +- goto free_info; +- } +- +- iface_init(iface); +- idbm_recinfo_iface(iface, info); +- idbm_recinfo_config(info, f); +- fclose(f); +- +-free_info: +- free(info); +-free_conf: +- free(iface_conf); +- return rc; +-} +- +-int iface_conf_delete(struct iface_rec *iface) +-{ +- char *iface_conf; +- int rc = 0; +- +- iface_conf = calloc(1, PATH_MAX); +- if (!iface_conf) +- return ENOMEM; +- +- sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name); +- if (unlink(iface_conf)) +- rc = errno; +- free(iface_conf); +- return rc; +-} +- +-int iface_conf_write(struct iface_rec *iface) +-{ +- char *iface_conf; +- FILE *f; +- int rc = 0; +- +- iface_conf = calloc(1, PATH_MAX); +- if (!iface_conf) +- return ENOMEM; +- +- sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name); +- f = fopen(iface_conf, "w"); +- if (!f) { +- rc = errno; +- goto free_conf; +- } +- +- idbm_print(PRINT_TYPE_IFACE, iface, 1, f); +- fclose(f); +-free_conf: +- free(iface_conf); +- return rc; +-} +- +-int iface_conf_update(struct db_set_param *param, struct iface_rec *iface) +-{ +- recinfo_t *info; +- int rc = 0; +- +- info = idbm_recinfo_alloc(MAX_KEYS); +- if (!info) +- return ENOMEM; +- +- idbm_recinfo_iface(iface, info); +- rc = idbm_node_update_param(info, param->name, param->value, 0); +- if (rc) { +- rc = EIO; +- goto free_info; +- } +- +- rc = iface_conf_write(iface); +-free_info: +- free(info); +- return rc; +-} +- +-static void idbm_read_def_ifaces(struct list_head *ifaces) +-{ +- DIR *iface_dirfd; +- struct dirent *iface_dent; +- struct iface_rec *iface; +- int err = 0; +- +- iface_dirfd = opendir(IFACE_CONFIG_DIR); +- if (!iface_dirfd) +- return; +- +- while ((iface_dent = readdir(iface_dirfd))) { +- if (!strcmp(iface_dent->d_name, ".") || +- !strcmp(iface_dent->d_name, "..")) +- continue; +- +- log_debug(5, "idbm_read_def_ifaces found %s", +- iface_dent->d_name); +- iface = iface_alloc(iface_dent->d_name, &err); +- if (!iface || err) { +- if (err == EINVAL) +- log_error("Invalid iface name %s. Must be " +- "from 1 to %d characters.", +- iface_dent->d_name, +- ISCSI_MAX_IFACE_LEN - 1); +- else +- log_error("Could not add iface %s.", +- iface_dent->d_name); +- free(iface); +- continue; +- } +- +- err = iface_conf_read(iface); +- if (err) { +- log_error("Could not read def iface %s (err %d)", +- iface->name, err); +- free(iface); +- continue; +- } +- if (!iface_is_bound(iface)) { +- log_debug(5, "Default iface is not bound " +- "Iface settings " iface_fmt, +- iface_str(iface)); +- free(iface); +- continue; +- } +- +- log_debug(5, "idbm_read_def_ifaces added %s", iface->name); +- list_add_tail(&iface->list, ifaces); +- } +- closedir(iface_dirfd); +-} +- +-static int iface_get_next_id(void) +-{ +- struct stat statb; +- char *iface_conf; +- int i, rc = ENOSPC; +- +- iface_conf = calloc(1, PATH_MAX); +- if (!iface_conf) +- return ENOMEM; +- +- for (i = 0; i < INT_MAX; i++) { +- memset(iface_conf, 0, PATH_MAX); +- /* check len */ +- snprintf(iface_conf, PATH_MAX, "iface%d", i); +- if (strlen(iface_conf) > ISCSI_MAX_IFACE_LEN - 1) { +- log_error("iface namespace is full. Remove unused " +- "iface definitions from %s or send mail " +- "to open-iscsi@googlegroups.com to report " +- "the problem", IFACE_CONFIG_DIR); +- rc = ENOSPC; +- break; +- } +- memset(iface_conf, 0, PATH_MAX); +- snprintf(iface_conf, PATH_MAX, "%s/iface%d", IFACE_CONFIG_DIR, +- i); +- +- if (!stat(iface_conf, &statb)) +- continue; +- if (errno == ENOENT) { +- rc = i; +- break; +- } +- } +- +- free(iface_conf); +- return rc; +-} +- +-struct iface_search { +- struct iface_rec *pattern; +- struct iface_rec *found; +-}; +- +-static int __iface_get_by_bind_info(void *data, struct iface_rec *iface) +-{ +- struct iface_search *search = data; +- +- if (!strcmp(search->pattern->name, iface->name)) { +- iface_copy(search->found, iface); +- return 1; +- } +- +- if (iface_is_bound_by_hwaddr(search->pattern)) { +- if (!strcmp(iface->hwaddress, search->pattern->hwaddress)) { +- iface_copy(search->found, iface); +- return 1; +- } else +- return 0; +- } +- +- if (iface_is_bound_by_netdev(search->pattern)) { +- if (!strcmp(iface->netdev, search->pattern->netdev)) { +- iface_copy(search->found, iface); +- return 1; +- } else +- return 0; +- } +- +-/* +- if (iface_is_bound_by_ipaddr(search->pattern)) { +- if (!strcmp(iface->ipaddress, search->pattern->ipaddress)) { +- iface_copy(search->found, iface); +- return 1; +- } else +- return 0; +- } +-*/ +- return 0; +-} +- +-int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern, +- struct iface_rec *out_rec) +-{ +- int num_found = 0, rc; +- struct iface_search search; +- +- search.pattern = pattern; +- search.found = out_rec; +- +- rc = iface_for_each_iface(db, &search, &num_found, +- __iface_get_by_bind_info); +- if (rc == 1) +- return 0; +- +- if (iface_is_bound(pattern)) +- return ENODEV; +- +- /* +- * compat for default behavior +- */ +- if (!strlen(pattern->name) || +- !strcmp(pattern->name, DEFAULT_IFACENAME)) { +- iface_init(out_rec); +- return 0; +- } +- +- return ENODEV; +-} +- +-static int __iface_setup_host_bindings(void *data, struct host_info *info) +-{ +- idbm_t *db = data; +- struct iface_rec iface; +- struct iscsi_transport *t; +- int id; +- +- if (!strlen(info->iface.hwaddress) || +- !strlen(info->iface.transport_name)) +- return 0; +- +- t = get_transport_by_hba(info->host_no); +- if (!t) +- return 0; +- /* +- * if software iscsi do not touch the bindngs. They do not +- * need it and may not support it +- */ +- if (!(t->caps & CAP_DATA_PATH_OFFLOAD)) +- return 0; +- +- if (iface_get_by_bind_info(db, &info->iface, &iface)) { +- /* Must be a new port */ +- id = iface_get_next_id(); +- if (id < 0) { +- log_error("Could not add iface for %s.", +- info->iface.hwaddress); +- return 0; +- } +- memset(&iface, 0, sizeof(struct iface_rec)); +- strcpy(iface.hwaddress, info->iface.hwaddress); +- strcpy(iface.transport_name, info->iface.transport_name); +- sprintf(iface.name, "iface%d", id); +- if (iface_conf_write(&iface)) +- log_error("Could not write iface conf for %s %s", +- iface.name, iface.hwaddress); +- /* fall through - will not be persistent */ +- } +- return 0; +-} +- +-/* +- * sync hw/offload iscsi scsi_hosts with iface values +- */ +-void iface_setup_host_bindings(idbm_t *db) +-{ +- int nr_found = 0; +- +- idbm_lock(db); +- if (access(IFACE_CONFIG_DIR, F_OK) != 0) { +- if (mkdir(IFACE_CONFIG_DIR, 0660) != 0) { +- log_error("Could not make %s. HW/OFFLOAD iscsi " +- "may not be supported", IFACE_CONFIG_DIR); +- idbm_unlock(db); +- return; +- } +- } +- idbm_unlock(db); +- +- if (sysfs_for_each_host(db, &nr_found, +- __iface_setup_host_bindings)) +- log_error("Could not scan scsi hosts. HW/OFFLOAD iscsi " +- "operations may not be supported."); +-} +- +-void iface_copy(struct iface_rec *dst, struct iface_rec *src) +-{ +- if (strlen(src->name)) +- strcpy(dst->name, src->name); +- if (strlen(src->netdev)) +- strcpy(dst->netdev, src->netdev); +-// if (strlen(src->ipaddress)) +-// strcpy(dst->ipaddress, src->ipaddress); +- if (strlen(src->hwaddress)) +- strcpy(dst->hwaddress, src->hwaddress); +- if (strlen(src->transport_name)) +- strcpy(dst->transport_name, src->transport_name); +-} +- +-int iface_is_bound(struct iface_rec *iface) +-{ +- if (!iface) +- return 0; +- +- if (iface_is_bound_by_hwaddr(iface)) +- return 1; +- +- if (iface_is_bound_by_netdev(iface)) +- return 1; +- +-// if (iface_is_bound_by_ipaddr(iface)) +-// return 1; +- +- return 0; +-} +- +-int iface_match_bind_info(struct iface_rec *pattern, struct iface_rec *iface) +-{ +- if (!pattern || !iface) +- return 1; +- +- /* if no values set then we have a match */ +- if (!strlen(pattern->hwaddress) && +-// !strlen(pattern->ipaddress) && +- !strlen(pattern->netdev) && +- !strlen(pattern->name)) +- return 1; +- +- /* +- * If both interfaces are not bound we return match. +- * This assumes we will not have two ifaces with different +- * names and no binding info. There should only be one +- * iface with no binding info for each transport and that +- * is the "default" which is used for backward compat from +- * when we did not have ifaces. +- */ +- if (!iface_is_bound(iface) && +- !iface_is_bound(pattern)) +- return 1; +- +- if (iface_is_bound_by_hwaddr(pattern) && +- !strcmp(pattern->hwaddress, iface->hwaddress)) +- return 1; +- +- if (iface_is_bound_by_netdev(iface) && +- !strcmp(pattern->netdev, iface->netdev)) +- return 1; +- +-// if (iface_is_bound_by_ipaddr(iface) && +-// !strcmp(pattern->ipaddress, iface->ipaddress)) +-// return 1; +- +- if (strlen(pattern->name)) { +- if (!strcmp(pattern->name, iface->name)) +- return 1; +- } +- +- return 0; +-} +- +-int iface_is_bound_by_hwaddr(struct iface_rec *iface) +-{ +- if (iface && strlen(iface->hwaddress) && +- strcmp(iface->hwaddress, DEFAULT_HWADDRESS)) +- return 1; +- return 0; +-} +- +-int iface_is_bound_by_netdev(struct iface_rec *iface) +-{ +- if (iface && strlen(iface->netdev) && +- strcmp(iface->netdev, DEFAULT_NETDEV)) +- return 1; +- return 0; +-} +- +-int iface_is_bound_by_ipaddr(struct iface_rec *iface) +-{ +- return 0; +-/* if (iface && strlen(iface->ipaddress) && +- strcmp(iface->ipaddress, DEFAULT_NETDEV)) +- return 1; +- return 0; +-*/ +-} +- +-int iface_print_flat(void *data, struct iface_rec *iface) +-{ +- printf("%s %s,%s,%s\n", +- strlen(iface->name) ? iface->name : UNKNOWN_VALUE, +- strlen(iface->transport_name) ? iface->transport_name : +- UNKNOWN_VALUE, +- strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE, +- strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE); +- return 0; +-} +- +-static int iface_filter(const struct dirent *dir) +-{ +- return strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."); +-} +- +-int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, iface_op_fn *fn) +-{ +- struct dirent **namelist; +- struct iface_rec *iface; +- int err = 0, n, i; +- +- n = scandir(IFACE_CONFIG_DIR, &namelist, iface_filter, versionsort); +- if (n <= 0) +- return 0; +- +- for (i = 0; i < n; i++) { +- log_debug(5, "iface_for_each_iface found %s", +- namelist[i]->d_name); +- iface = iface_alloc(namelist[i]->d_name, &err); +- if (!iface || err) { +- if (err == EINVAL) +- log_error("Invalid iface name %s. Must be " +- "from 1 to %d characters.", +- namelist[i]->d_name, +- ISCSI_MAX_IFACE_LEN - 1); +- else +- log_error("Could not add iface %s.", +- namelist[i]->d_name); +- free(iface); +- continue; +- } +- +- idbm_lock(db); +- err = iface_conf_read(iface); +- idbm_unlock(db); +- if (err) { +- log_error("Could not read def iface %s (err %d)", +- iface->name, err); +- free(iface); +- continue; +- } +- +- if (!iface_is_bound(iface)) { +- log_debug(5, "iface is not bound " +- "Iface settings " iface_fmt, +- iface_str(iface)); +- free(iface); +- continue; +- } +- +- err = fn(data, iface); +- free(iface); +- if (err) +- break; +- (*nr_found)++; +- } +- +- for (i = 0; i < n; i++) +- free(namelist[i]); +- free(namelist); +- return err; +-} +- +-/* + * Backwards Compat: + * If the portal is a file then we are doing the old style default + * session behavior (svn pre 780). +@@ -1361,7 +891,7 @@ static FILE *idbm_open_rec_r(char *portal, char *config) + return fopen(portal, "r"); } --int iface_conf_delete(struct iface_rec *iface) -+int iface_conf_read(idbm_t *db, struct iface_rec *iface) -+{ -+ int rc; -+ -+ idbm_lock(db); -+ rc = __iface_conf_read(iface); -+ idbm_unlock(db); -+ return rc; -+} -+ -+int iface_conf_delete(idbm_t *db, struct iface_rec *iface) +-static int __idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *conf) ++static int __idbm_rec_read(node_rec_t *out_rec, char *conf) { - char *iface_conf; - int rc = 0; -@@ -884,13 +917,16 @@ int iface_conf_delete(struct iface_rec *iface) + recinfo_t *info; + FILE *f; +@@ -1371,7 +901,7 @@ static int __idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *conf) + if (!info) return ENOMEM; - sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name); -+ idbm_lock(db); - if (unlink(iface_conf)) - rc = errno; -+ idbm_unlock(db); -+ - free(iface_conf); - return rc; - } - --int iface_conf_write(struct iface_rec *iface) -+int iface_conf_write(idbm_t *db, struct iface_rec *iface) - { - char *iface_conf; - FILE *f; -@@ -907,14 +943,18 @@ int iface_conf_write(struct iface_rec *iface) - goto free_conf; - } - -+ idbm_lock(db); - idbm_print(PRINT_TYPE_IFACE, iface, 1, f); -+ idbm_unlock(db); -+ +- idbm_lock(db); ++ idbm_lock(); + f = fopen(conf, "r"); + if (!f) { + log_debug(5, "Could not open %s err %d\n", conf, errno); +@@ -1386,13 +916,13 @@ static int __idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *conf) fclose(f); - free_conf: - free(iface_conf); - return rc; - } --int iface_conf_update(struct db_set_param *param, struct iface_rec *iface) -+int iface_conf_update(idbm_t *db, struct db_set_param *param, -+ struct iface_rec *iface) - { - recinfo_t *info; - int rc = 0; -@@ -930,7 +970,7 @@ int iface_conf_update(struct db_set_param *param, struct iface_rec *iface) - goto free_info; - } - -- rc = iface_conf_write(iface); -+ rc = iface_conf_write(db, iface); - free_info: + unlock: +- idbm_unlock(db); ++ idbm_unlock(); free(info); return rc; -@@ -968,7 +1008,7 @@ static void idbm_read_def_ifaces(struct list_head *ifaces) + } + + int +-idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *targetname, int tpgt, ++idbm_rec_read(node_rec_t *out_rec, char *targetname, int tpgt, + char *ip, int port, struct iface_rec *iface) + { + struct stat statb; +@@ -1425,7 +955,7 @@ idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *targetname, int tpgt, + } + + read: +- rc = __idbm_rec_read(db, out_rec, portal); ++ rc = __idbm_rec_read(out_rec, portal); + free_portal: + free(portal); + return rc; +@@ -1437,7 +967,7 @@ static int st_disc_filter(const struct dirent *dir) + strcmp(dir->d_name, ST_CONFIG_NAME); + } + +-static int print_discovered(idbm_t *db, char *disc_path, int info_level) ++static int print_discovered(char *disc_path, int info_level) + { + char *tmp_port = NULL, *last_address = NULL, *last_target = NULL; + char *target = NULL, *address = NULL, *ifaceid = NULL, *tpgt = NULL; +@@ -1446,7 +976,7 @@ static int print_discovered(idbm_t *db, char *disc_path, int info_level) + struct dirent **namelist; + node_rec_t *rec; + +- n = scandir(disc_path, &namelist, st_disc_filter, versionsort); ++ n = scandir(disc_path, &namelist, st_disc_filter, direntcmp); + if (n < 0) + return 0; + +@@ -1469,7 +999,7 @@ static int print_discovered(idbm_t *db, char *disc_path, int info_level) + memset(portal, 0, PATH_MAX); + snprintf(portal, PATH_MAX, "%s/%s/%s,%s,%s/%s", NODE_CONFIG_DIR, + target, address, tmp_port, tpgt, ifaceid); +- if (__idbm_rec_read(db, rec, portal)) { ++ if (__idbm_rec_read(rec, portal)) { + log_error("Could not read node record for %s " + "%s %d %s", target, address, atoi(tmp_port), + ifaceid); +@@ -1519,7 +1049,7 @@ free_namelist: + return n; + } + +-int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec, int info_level) ++int idbm_print_discovered(discovery_rec_t *drec, int info_level) + { + char *disc_path; + int rc; +@@ -1545,13 +1075,13 @@ int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec, int info_level) + goto done; + } + +- rc = print_discovered(db, disc_path, info_level); ++ rc = print_discovered(disc_path, info_level); + done: + free(disc_path); + return rc; + } + +-static int idbm_print_all_st(idbm_t *db, int info_level) ++static int idbm_print_all_st(int info_level) + { + DIR *entity_dirfd; + struct dirent *entity_dent; +@@ -1578,7 +1108,7 @@ static int idbm_print_all_st(idbm_t *db, int info_level) + entity_dent->d_name); + + printf("DiscoveryAddress: %s\n", entity_dent->d_name); +- found += print_discovered(db, disc_dir, info_level); ++ found += print_discovered(disc_dir, info_level); + } else { + char *tmp_port; + +@@ -1598,13 +1128,13 @@ free_disc: + return found; + } + +-int idbm_print_all_discovery(idbm_t *db, int info_level) ++int idbm_print_all_discovery(int info_level) + { + discovery_rec_t *drec; + int found = 0, tmp; + + if (info_level < 1) +- return idbm_print_all_st(db, info_level); ++ return idbm_print_all_st(info_level); + + drec = calloc(1, sizeof(*drec)); + if (!drec) +@@ -1612,7 +1142,7 @@ int idbm_print_all_discovery(idbm_t *db, int info_level) + + tmp = 0; + printf("SENDTARGETS:\n"); +- tmp = idbm_print_all_st(db, info_level); ++ tmp = idbm_print_all_st(info_level); + if (!tmp) + printf("No targets found.\n"); + found += tmp; +@@ -1620,7 +1150,7 @@ int idbm_print_all_discovery(idbm_t *db, int info_level) + + printf("iSNS:\n"); + drec->type = DISCOVERY_TYPE_ISNS; +- tmp = idbm_print_discovered(db, drec, info_level); ++ tmp = idbm_print_discovered(drec, info_level); + if (!tmp) + printf("No targets found.\n"); + found += tmp; +@@ -1628,7 +1158,7 @@ int idbm_print_all_discovery(idbm_t *db, int info_level) + + printf("STATIC:\n"); + drec->type = DISCOVERY_TYPE_STATIC; +- tmp = idbm_print_discovered(db, drec, info_level); ++ tmp = idbm_print_discovered(drec, info_level); + if (!tmp) + printf("No targets found.\n"); + found += tmp; +@@ -1641,7 +1171,7 @@ int idbm_print_all_discovery(idbm_t *db, int info_level) + * This iterates over the ifaces in use in the nodes dir. + * It does not iterate over the ifaces setup in /etc/iscsi/ifaces. + */ +-static int idbm_for_each_iface(idbm_t *db, int *found, void *data, ++static int idbm_for_each_iface(int *found, void *data, + idbm_iface_op_fn *fn, + char *targetname, int tpgt, char *ip, int port) + { +@@ -1668,11 +1198,11 @@ static int idbm_for_each_iface(idbm_t *db, int *found, void *data, + goto free_portal; + } + +- rc = __idbm_rec_read(db, &rec, portal); ++ rc = __idbm_rec_read(&rec, portal); + if (rc) + goto free_portal; + +- rc = fn(db, data, &rec); ++ rc = fn(data, &rec); + if (!rc) + (*found)++; + else if (rc == -1) +@@ -1698,11 +1228,11 @@ read_iface: + memset(portal, 0, PATH_MAX); + snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d/%s", NODE_CONFIG_DIR, + targetname, ip, port, tpgt, iface_dent->d_name); +- if (__idbm_rec_read(db, &rec, portal)) ++ if (__idbm_rec_read(&rec, portal)) continue; - } -- err = iface_conf_read(iface); -+ err = __iface_conf_read(iface); - if (err) { - log_error("Could not read def iface %s (err %d)", - iface->name, err); -@@ -1131,7 +1171,7 @@ static int __iface_setup_host_bindings(void *data, struct host_info *info) - strcpy(iface.hwaddress, info->iface.hwaddress); - strcpy(iface.transport_name, info->iface.transport_name); - sprintf(iface.name, "iface%d", id); -- if (iface_conf_write(&iface)) -+ if (iface_conf_write(db, &iface)) - log_error("Could not write iface conf for %s %s", - iface.name, iface.hwaddress); - /* fall through - will not be persistent */ -@@ -1308,7 +1348,7 @@ int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, iface_op_fn *fn) - } + /* less than zero means it was not a match */ +- rc = fn(db, data, &rec); ++ rc = fn(data, &rec); + if (rc > 0) + break; + else if (rc == 0) +@@ -1721,8 +1251,8 @@ free_portal: + * backwards compat + * The portal could be a file or dir with interfaces + */ +-int idbm_for_each_portal(idbm_t *db, int *found, void *data, +- idbm_portal_op_fn *fn, char *targetname) ++int idbm_for_each_portal(int *found, void *data, idbm_portal_op_fn *fn, ++ char *targetname) + { + DIR *portal_dirfd; + struct dirent *portal_dent; +@@ -1756,7 +1286,7 @@ int idbm_for_each_portal(idbm_t *db, int *found, void *data, + if (tmp_tpgt) + *tmp_tpgt++ = '\0'; - idbm_lock(db); -- err = iface_conf_read(iface); -+ err = __iface_conf_read(iface); - idbm_unlock(db); - if (err) { - log_error("Could not read def iface %s (err %d)", -@@ -2023,7 +2063,7 @@ idbm_discovery_write(idbm_t *db, discovery_rec_t *rec) +- rc = fn(db, found, data, targetname, ++ rc = fn(found, data, targetname, + tmp_tpgt ? atoi(tmp_tpgt) : -1, + portal_dent->d_name, atoi(tmp_port)); + if (rc) +@@ -1768,7 +1298,7 @@ done: + return rc; + } + +-int idbm_for_each_node(idbm_t *db, int *found, void *data, idbm_node_op_fn *fn) ++int idbm_for_each_node(int *found, void *data, idbm_node_op_fn *fn) + { + DIR *node_dirfd; + struct dirent *node_dent; +@@ -1787,7 +1317,7 @@ int idbm_for_each_node(idbm_t *db, int *found, void *data, idbm_node_op_fn *fn) + continue; + + log_debug(5, "searching %s\n", node_dent->d_name); +- rc = fn(db, found, data, node_dent->d_name); ++ rc = fn(found, data, node_dent->d_name); + if (rc) + break; + } +@@ -1796,26 +1326,26 @@ int idbm_for_each_node(idbm_t *db, int *found, void *data, idbm_node_op_fn *fn) + return rc; + } + +-static int iface_fn(idbm_t *db, void *data, node_rec_t *rec) ++static int iface_fn(void *data, node_rec_t *rec) + { + struct rec_op_data *op_data = data; + +- return op_data->fn(db, op_data->data, rec); ++ return op_data->fn(op_data->data, rec); + } + +-static int portal_fn(idbm_t *db, int *found, void *data, char *targetname, ++static int portal_fn(int *found, void *data, char *targetname, + int tpgt, char *ip, int port) + { +- return idbm_for_each_iface(db, found, data, iface_fn, targetname, ++ return idbm_for_each_iface(found, data, iface_fn, targetname, + tpgt, ip, port); + } + +-static int node_fn(idbm_t *db, int *found, void *data, char *targetname) ++static int node_fn(int *found, void *data, char *targetname) + { +- return idbm_for_each_portal(db, found, data, portal_fn, targetname); ++ return idbm_for_each_portal(found, data, portal_fn, targetname); + } + +-int idbm_for_each_rec(idbm_t *db, int *found, void *data, idbm_iface_op_fn *fn) ++int idbm_for_each_rec(int *found, void *data, idbm_iface_op_fn *fn) + { + struct rec_op_data op_data; + +@@ -1823,11 +1353,11 @@ int idbm_for_each_rec(idbm_t *db, int *found, void *data, idbm_iface_op_fn *fn) + op_data.data = data; + op_data.fn = fn; + +- return idbm_for_each_node(db, found, &op_data, node_fn); ++ return idbm_for_each_node(found, &op_data, node_fn); + } + + int +-idbm_discovery_read(idbm_t *db, discovery_rec_t *out_rec, char *addr, int port) ++idbm_discovery_read(discovery_rec_t *out_rec, char *addr, int port) + { + recinfo_t *info; + char *portal; +@@ -1848,7 +1378,7 @@ idbm_discovery_read(idbm_t *db, discovery_rec_t *out_rec, char *addr, int port) + addr, port); + log_debug(5, "Looking for config file %s\n", portal); + +- idbm_lock(db); ++ idbm_lock(); + + f = idbm_open_rec_r(portal, ST_CONFIG_NAME); + if (!f) { +@@ -1863,7 +1393,7 @@ idbm_discovery_read(idbm_t *db, discovery_rec_t *out_rec, char *addr, int port) + fclose(f); + + unlock: +- idbm_unlock(db); ++ idbm_unlock(); + free_info: + free(portal); + free(info); +@@ -1914,7 +1444,7 @@ mkdir_portal: + return f; + } + +-static int idbm_rec_write(idbm_t *db, node_rec_t *rec) ++static int idbm_rec_write(node_rec_t *rec) + { + struct stat statb; + FILE *f; +@@ -1949,7 +1479,7 @@ static int idbm_rec_write(idbm_t *db, node_rec_t *rec) + rec->name, rec->conn[0].address, rec->conn[0].port); + log_debug(5, "Looking for config file %s", portal); + +- idbm_lock(db); ++ idbm_lock(); + + rc = stat(portal, &statb); + if (rc) { +@@ -2004,17 +1534,17 @@ open_conf: + goto unlock; + } + +- idbm_print(PRINT_TYPE_NODE, rec, 1, f); ++ idbm_print(IDBM_PRINT_TYPE_NODE, rec, 1, f); + fclose(f); + unlock: +- idbm_unlock(db); ++ idbm_unlock(); + free_portal: + free(portal); + return rc; + } + + static int +-idbm_discovery_write(idbm_t *db, discovery_rec_t *rec) ++idbm_discovery_write(discovery_rec_t *rec) + { + FILE *f; + char *portal; +@@ -2023,10 +1553,10 @@ idbm_discovery_write(idbm_t *db, discovery_rec_t *rec) portal = malloc(PATH_MAX); if (!portal) { log_error("Could not alloc portal\n"); @@ -8704,8 +11947,48 @@ index dcdae56..bd46824 100644 + return ENOMEM; } - idbm_lock(db); -@@ -2106,8 +2146,8 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec) +- idbm_lock(db); ++ idbm_lock(); + snprintf(portal, PATH_MAX, "%s", ST_CONFIG_DIR); + if (access(portal, F_OK) != 0) { + if (mkdir(portal, 0660) != 0) { +@@ -2046,27 +1576,29 @@ idbm_discovery_write(idbm_t *db, discovery_rec_t *rec) + goto free_portal; + } + +- idbm_print(PRINT_TYPE_DISCOVERY, rec, 1, f); ++ idbm_print(IDBM_PRINT_TYPE_DISCOVERY, rec, 1, f); + fclose(f); + free_portal: +- idbm_unlock(db); ++ idbm_unlock(); + free(portal); + return rc; + } + +-static int +-idbm_add_discovery(idbm_t *db, discovery_rec_t *newrec) ++int ++idbm_add_discovery(discovery_rec_t *newrec, int overwrite) + { + discovery_rec_t rec; + int rc; + +- if (!idbm_discovery_read(db, &rec, newrec->address, ++ if (!idbm_discovery_read(&rec, newrec->address, + newrec->port)) { ++ if (!overwrite) ++ return 0; + log_debug(7, "overwriting existing record"); + } else + log_debug(7, "adding new DB record"); + +- rc = idbm_discovery_write(db, newrec); ++ rc = idbm_discovery_write(newrec); + return rc; + } + +@@ -2106,8 +1638,8 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec) } } @@ -8716,13 +11999,185 @@ index dcdae56..bd46824 100644 rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, rec->iface.name); break; -@@ -2224,6 +2264,15 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, +@@ -2119,16 +1651,19 @@ static int setup_disc_to_node_link(char *disc_portal, node_rec_t *rec) + return rc; + } + +-int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec) ++int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, int overwrite) + { + node_rec_t rec; + char *node_portal, *disc_portal; + int rc; + +- if (!idbm_rec_read(db, &rec, newrec->name, newrec->tpgt, ++ if (!idbm_rec_read(&rec, newrec->name, newrec->tpgt, + newrec->conn[0].address, newrec->conn[0].port, + &newrec->iface)) { +- rc = idbm_delete_node(db, NULL, &rec); ++ if (!overwrite) ++ return 0; ++ ++ rc = idbm_delete_node(&rec); + if (rc) + return rc; + log_debug(7, "overwriting existing record"); +@@ -2141,7 +1676,7 @@ int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec) + strcpy(newrec->disc_address, drec->address); + } + +- rc = idbm_rec_write(db, newrec); ++ rc = idbm_rec_write(newrec); + /* + * if a old app passed in a bogus tpgt then we do not create links + * since it will set a different tpgt in another iscsiadm call +@@ -2164,7 +1699,7 @@ int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec) + log_debug(7, "node addition making link from %s to %s", node_portal, + disc_portal); + +- idbm_lock(db); ++ idbm_lock(); + if (symlink(node_portal, disc_portal)) { + if (errno == EEXIST) + log_debug(7, "link from %s to %s exists", node_portal, +@@ -2175,14 +1710,31 @@ int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec) + "node %s", disc_portal, node_portal); + } + } +- idbm_unlock(db); ++ idbm_unlock(); + free_portal: + free(node_portal); + return rc; + } + +-int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, +- struct list_head *ifaces) ++static int idbm_bind_iface_to_node(struct node_rec *new_rec, ++ struct iface_rec *iface, ++ struct list_head *bound_recs) ++{ ++ struct node_rec *clone_rec; ++ ++ clone_rec = calloc(1, sizeof(*clone_rec)); ++ if (!clone_rec) ++ return ENOMEM; ++ ++ memcpy(clone_rec, new_rec, sizeof(*clone_rec)); ++ INIT_LIST_HEAD(&clone_rec->list); ++ iface_copy(&clone_rec->iface, iface); ++ list_add_tail(&clone_rec->list, bound_recs); ++ return 0; ++} ++ ++int idbm_bind_ifaces_to_node(struct node_rec *new_rec, struct list_head *ifaces, ++ struct list_head *bound_recs) + { + struct iface_rec *iface, *tmp; + struct iscsi_transport *t; +@@ -2192,25 +1744,82 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, + struct list_head def_ifaces; + + INIT_LIST_HEAD(&def_ifaces); +- idbm_lock(db); +- idbm_read_def_ifaces(&def_ifaces); +- idbm_unlock(db); ++ iface_link_ifaces(&def_ifaces); + + list_for_each_entry_safe(iface, tmp, &def_ifaces, list) { + list_del(&iface->list); + t = get_transport_by_name(iface->transport_name); +- if (!t) { ++ /* only auto bind to software iscsi */ ++ if (!t || t->caps & CAP_FW_DB || ++ t->caps & CAP_DATA_PATH_OFFLOAD) { + free(iface); + continue; + } + +- if (t->caps & CAP_FW_DB) { ++ rc = idbm_bind_iface_to_node(new_rec, iface, ++ bound_recs); ++ free(iface); ++ if (rc) ++ return rc; ++ found = 1; ++ } ++ ++ /* create default iface with old/default behavior */ ++ if (!found) { ++ struct iface_rec def_iface; ++ ++ iface_setup_defaults(&def_iface); ++ return idbm_bind_iface_to_node(new_rec, &def_iface, ++ bound_recs); ++ } ++ } else { ++ list_for_each_entry(iface, ifaces, list) { ++ if (strcmp(iface->name, DEFAULT_IFACENAME) && ++ !iface_is_valid(iface)) { ++ log_error("iface %s is not valid. Will not " ++ "bind node to it. Iface settings " ++ iface_fmt, iface->name, ++ iface_str(iface)); ++ continue; ++ } ++ ++ rc = idbm_bind_iface_to_node(new_rec, iface, ++ bound_recs); ++ if (rc) ++ return rc; ++ } ++ } ++ return 0; ++} ++ ++/* ++ * remove this when isns is converted ++ */ ++int idbm_add_nodes(node_rec_t *newrec, discovery_rec_t *drec, ++ struct list_head *ifaces, int update) ++{ ++ struct iface_rec *iface, *tmp; ++ struct iscsi_transport *t; ++ int rc = 0, found = 0; ++ ++ if (!ifaces || list_empty(ifaces)) { ++ struct list_head def_ifaces; ++ ++ INIT_LIST_HEAD(&def_ifaces); ++ iface_link_ifaces(&def_ifaces); ++ ++ list_for_each_entry_safe(iface, tmp, &def_ifaces, list) { ++ list_del(&iface->list); ++ t = get_transport_by_name(iface->transport_name); ++ /* only auto bind to software iscsi */ ++ if (!t || t->caps & CAP_FW_DB || ++ t->caps & CAP_DATA_PATH_OFFLOAD) { + free(iface); + continue; + } + + iface_copy(&newrec->iface, iface); +- rc = idbm_add_node(db, newrec, drec); ++ rc = idbm_add_node(newrec, drec, update); + free(iface); + if (rc) + return rc; +@@ -2219,13 +1828,22 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, + + /* create default iface with old/default behavior */ + if (!found) { +- iface_init(&newrec->iface); +- return idbm_add_node(db, newrec, drec); ++ iface_setup_defaults(&newrec->iface); ++ return idbm_add_node(newrec, drec, update); } } else { list_for_each_entry(iface, ifaces, list) { + if (strcmp(iface->name, DEFAULT_IFACENAME) && -+ !iface_is_bound(iface)) { -+ log_error("iface %s is not bound. Will not " ++ !iface_is_valid(iface)) { ++ log_error("iface %s is not valid. Will not " + "bind node to it. Iface settings " + iface_fmt, iface->name, + iface_str(iface)); @@ -8730,39 +12185,233 @@ index dcdae56..bd46824 100644 + } + iface_copy(&newrec->iface, iface); - rc = idbm_add_node(db, newrec, drec); +- rc = idbm_add_node(db, newrec, drec); ++ rc = idbm_add_node(newrec, drec, update); if (rc) -@@ -2524,23 +2573,32 @@ idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec) + return rc; + } +@@ -2233,14 +1851,7 @@ int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec, + return 0; } - idbm_t* --idbm_init(char *configfile) -+idbm_init(idbm_get_config_file_fn *fn) +-void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec) +-{ +- idbm_delete_discovery(db, drec); +- if (idbm_add_discovery(db, drec)) +- log_error("can not update discovery record."); +-} +- +-static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir) ++static void idbm_rm_disc_node_links(char *disc_dir) { - idbm_t *db; + char *target = NULL, *tpgt = NULL, *port = NULL; + char *address = NULL, *iface_id = NULL; +@@ -2279,7 +1890,7 @@ static void idbm_rm_disc_node_links(idbm_t *db, char *disc_dir) + strncpy(rec->conn[0].address, address, NI_MAXHOST); + strncpy(rec->iface.name, iface_id, ISCSI_MAX_IFACE_LEN); +- if (idbm_delete_node(db, NULL, rec)) ++ if (idbm_delete_node(rec)) + log_error("Could not delete node %s/%s/%s,%s/%s", + NODE_CONFIG_DIR, target, address, port, + iface_id); +@@ -2290,7 +1901,7 @@ free_rec: + free(rec); + } + +-int idbm_delete_discovery(idbm_t *db, discovery_rec_t *drec) ++int idbm_delete_discovery(discovery_rec_t *drec) + { + char *portal; + struct stat statb; +@@ -2321,7 +1932,7 @@ int idbm_delete_discovery(idbm_t *db, discovery_rec_t *drec) + memset(portal, 0, PATH_MAX); + snprintf(portal, PATH_MAX, "%s/%s,%d", ST_CONFIG_DIR, + drec->address, drec->port); +- idbm_rm_disc_node_links(db, portal); ++ idbm_rm_disc_node_links(portal); + + /* rm portal dir */ + if (S_ISDIR(statb.st_mode)) { +@@ -2341,7 +1952,7 @@ free_portal: + * if there is no link then this is pre svn 780 version where + * we did not link the disc source and node + */ +-static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec, ++static int idbm_remove_disc_to_node_link(node_rec_t *rec, + char *portal) + { + int rc = 0; +@@ -2357,7 +1968,7 @@ static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec, + rec->name, rec->conn[0].address, rec->conn[0].port, rec->tpgt, + rec->iface.name); + +- rc = __idbm_rec_read(db, tmprec, portal); ++ rc = __idbm_rec_read(tmprec, portal); + if (rc) { + /* old style recs will not have tpgt or a link so skip */ + rc = 0; +@@ -2372,7 +1983,7 @@ static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec, + if (rc) + goto done; + +- idbm_lock(db); ++ idbm_lock(); + if (!stat(portal, &statb)) { + if (unlink(portal)) { + log_error("Could not remove link %s err %d\n", +@@ -2382,14 +1993,14 @@ static int idbm_remove_disc_to_node_link(idbm_t *db, node_rec_t *rec, + log_debug(7, "rmd %s", portal); + } else + log_debug(7, "Could not stat %s", portal); +- idbm_unlock(db); ++ idbm_unlock(); + + done: + free(tmprec); + return rc; + } + +-int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec) ++int idbm_delete_node(node_rec_t *rec) + { + struct stat statb; + char *portal; +@@ -2399,7 +2010,7 @@ int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec) + if (!portal) + return ENOMEM; + +- rc = idbm_remove_disc_to_node_link(db, rec, portal); ++ rc = idbm_remove_disc_to_node_link(rec, portal); + if (rc) + goto free_portal; + +@@ -2409,7 +2020,7 @@ int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec) + log_debug(5, "Removing config file %s iface id %s\n", + portal, rec->iface.name); + +- idbm_lock(db); ++ idbm_lock(); + if (!stat(portal, &statb)) + goto rm_conf; + +@@ -2445,7 +2056,7 @@ rm_conf: + snprintf(portal, PATH_MAX, "%s/%s/%s,%d,%d", NODE_CONFIG_DIR, + rec->name, rec->conn[0].address, rec->conn[0].port, + rec->tpgt); +- n = scandir(portal, &namelist, st_disc_filter, versionsort); ++ n = scandir(portal, &namelist, st_disc_filter, direntcmp); + if (n < 0) + goto free_portal; + if (n == 0) +@@ -2462,29 +2073,28 @@ rm_conf: + rmdir(portal); + } + unlock: +- idbm_unlock(db); ++ idbm_unlock(); + free_portal: + free(portal); + return rc; + } + + void +-idbm_sendtargets_defaults(idbm_t *db, struct iscsi_sendtargets_config *cfg) ++idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg) + { +- idbm_sync_config(db); ++ idbm_sync_config(); + memcpy(cfg, &db->drec_st.u.sendtargets, + sizeof(struct iscsi_sendtargets_config)); + } + + void +-idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg) ++idbm_slp_defaults(struct iscsi_slp_config *cfg) + { + memcpy(cfg, &db->drec_slp.u.slp, + sizeof(struct iscsi_slp_config)); + } + +-int +-idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec) ++int idbm_node_set_param(void *data, node_rec_t *rec) + { + struct db_set_param *param = data; + recinfo_t *info; +@@ -2496,51 +2106,46 @@ idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec) + + idbm_recinfo_node(rec, info); + +- /* +- * Another compat hack!!!!: in the future we will have a common +- * way to define node wide vs iface wide values and it will +- * nicely obey some hierd, but for now this one sits between both +- * and if someone tries to set it using the old values then +- * we update it for them. +- */ +- if (!strcmp("node.transport_name", param->name)) +- rc = idbm_node_update_param(info, "iface.transport_name", +- param->value, 0); +- else +- rc = idbm_node_update_param(info, param->name, param->value, 0); +- if (rc) { +- free(info); +- return EIO; +- } ++ rc = idbm_verify_param(info, param->name); ++ if (rc) ++ goto free_info; + +- rc = idbm_rec_write(param->db, rec); +- if (rc) { +- free(info); +- return rc; +- } ++ rc = idbm_rec_update_param(info, param->name, param->value, 0); ++ if (rc) ++ goto free_info; + ++ rc = idbm_rec_write(rec); ++ if (rc) ++ goto free_info; ++ ++free_info: + free(info); +- return 0; ++ return rc; + } + +-idbm_t* +-idbm_init(char *configfile) ++int idbm_init(idbm_get_config_file_fn *fn) + { +- idbm_t *db; + /* make sure root db dir is there */ + if (access(ISCSI_CONFIG_ROOT, F_OK) != 0) { + if (mkdir(ISCSI_CONFIG_ROOT, 0660) != 0) { + log_error("Could not make %s %d\n", ISCSI_CONFIG_ROOT, + errno); -+ return NULL; ++ return errno; + } + } -+ + db = malloc(sizeof(idbm_t)); if (!db) { log_error("out of memory on idbm allocation"); - return NULL; +- return NULL; ++ return ENOMEM; } memset(db, 0, sizeof(idbm_t)); - db->configfile = strdup(configfile); +- return db; + db->get_config_file = fn; - return db; ++ return 0; } - void - idbm_terminate(idbm_t *db) +-void +-idbm_terminate(idbm_t *db) ++void idbm_terminate(void) { - free(db->configfile); - free(db); @@ -8770,11 +12419,27 @@ index dcdae56..bd46824 100644 + free(db); } diff --git a/usr/idbm.h b/usr/idbm.h -index 5d809f2..9664031 100644 +index 5d809f2..edd85ca 100644 --- a/usr/idbm.h +++ b/usr/idbm.h -@@ -52,11 +52,14 @@ typedef struct recinfo { +@@ -27,7 +27,6 @@ + #include "config.h" + + #define NODE_CONFIG_DIR ISCSI_CONFIG_ROOT"nodes" +-#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" + #define SLP_CONFIG_DIR ISCSI_CONFIG_ROOT"slp" + #define ISNS_CONFIG_DIR ISCSI_CONFIG_ROOT"isns" + #define STATIC_CONFIG_DIR ISCSI_CONFIG_ROOT"static" +@@ -50,13 +49,22 @@ typedef struct recinfo { + int visible; + char* opts[OPTS_MAXVAL]; int numopts; ++ /* ++ * bool indicating if we can change it or not. ++ * TODO: make it a enum that can indicate wheter it also requires ++ * a relogin to pick up if a session is running. ++ */ ++ int can_modify; } recinfo_t; +typedef char *(idbm_get_config_file_fn)(void); @@ -8788,42 +12453,901 @@ index 5d809f2..9664031 100644 node_rec_t nrec; recinfo_t ninfo[MAX_KEYS]; discovery_rec_t drec_st; -@@ -93,7 +96,8 @@ extern int idbm_for_each_rec(idbm_t *db, int *found, void *data, +@@ -70,13 +78,12 @@ typedef struct idbm { + struct db_set_param { + char *name; + char *value; +- struct idbm *db; + }; + +-typedef int (idbm_iface_op_fn)(idbm_t *db, void *data, node_rec_t *rec); +-typedef int (idbm_portal_op_fn)(idbm_t *db,int *found, void *data, ++typedef int (idbm_iface_op_fn)(void *data, node_rec_t *rec); ++typedef int (idbm_portal_op_fn)(int *found, void *data, + char *targetname, int tpgt, char *ip, int port); +-typedef int (idbm_node_op_fn)(idbm_t *db, int *found, void *data, ++typedef int (idbm_node_op_fn)(int *found, void *data, + char *targetname); + + struct rec_op_data { +@@ -84,73 +91,64 @@ struct rec_op_data { + node_rec_t *match_rec; + idbm_iface_op_fn *fn; + }; +-extern int idbm_for_each_portal(idbm_t *db, int *found, void *data, ++extern int idbm_for_each_portal(int *found, void *data, + idbm_portal_op_fn *fn, char *targetname); +-extern int idbm_for_each_node(idbm_t *db, int *found, void *data, ++extern int idbm_for_each_node(int *found, void *data, + idbm_node_op_fn *fn); +-extern int idbm_for_each_rec(idbm_t *db, int *found, void *data, ++extern int idbm_for_each_rec(int *found, void *data, + idbm_iface_op_fn *fn); extern char* get_iscsi_initiatorname(char *pathname); extern char* get_iscsi_initiatoralias(char *pathname); -extern idbm_t* idbm_init(char *configfile); -+extern idbm_t *idbm_init(idbm_get_config_file_fn *fn); -+ - extern void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec); - extern void idbm_terminate(idbm_t *db); - extern int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec); -@@ -130,7 +134,7 @@ extern int iface_is_bound(struct iface_rec *iface); - extern int iface_match_bind_info(struct iface_rec *pattern, - struct iface_rec *iface); - extern struct iface_rec *iface_alloc(char *ifname, int *err); +-extern void idbm_node_setup_from_conf(idbm_t *db, node_rec_t *rec); +-extern void idbm_terminate(idbm_t *db); +-extern int idbm_print_node_info(idbm_t *db, void *data, node_rec_t *rec); +-extern int idbm_print_node_flat(idbm_t *db, void *data, node_rec_t *rec); +-extern int idbm_print_node_tree(idbm_t *db, void *data, node_rec_t *rec); +-extern int idbm_print_discovery_info(idbm_t *db, discovery_rec_t *rec, +- int show); +-extern int idbm_print_all_discovery(idbm_t *db, int info_level); +-extern int idbm_print_discovered(idbm_t *db, discovery_rec_t *drec, +- int info_level); +-extern int idbm_delete_discovery(idbm_t *db, discovery_rec_t *rec); +-extern void idbm_node_setup_defaults(node_rec_t *rec); +-extern int idbm_delete_node(idbm_t *db, void *data, node_rec_t *rec); +-extern int idbm_add_node(idbm_t *db, node_rec_t *newrec, discovery_rec_t *drec); ++extern int idbm_init(idbm_get_config_file_fn *fn); + ++extern void idbm_node_setup_from_conf(node_rec_t *rec); ++extern void idbm_terminate(void); ++extern int idbm_print_iface_info(void *data, struct iface_rec *iface); ++extern int idbm_print_node_info(void *data, node_rec_t *rec); ++extern int idbm_print_node_flat(void *data, node_rec_t *rec); ++extern int idbm_print_node_tree(void *data, node_rec_t *rec); ++extern int idbm_print_discovery_info(discovery_rec_t *rec, int show); ++extern int idbm_print_all_discovery(int info_level); ++extern int idbm_print_discovered(discovery_rec_t *drec, int info_level); ++extern int idbm_delete_discovery(discovery_rec_t *rec); ++extern void idbm_node_setup_defaults(node_rec_t *rec); ++extern int idbm_delete_node(node_rec_t *rec); ++extern int idbm_add_node(node_rec_t *newrec, discovery_rec_t *drec, ++ int overwrite); + struct list_head; +-extern int idbm_add_nodes(idbm_t *db, node_rec_t *newrec, +- discovery_rec_t *drec, struct list_head *ifaces); +-extern void idbm_new_discovery(idbm_t *db, discovery_rec_t *drec); +-extern void idbm_sendtargets_defaults(idbm_t *db, +- struct iscsi_sendtargets_config *cfg); +-extern void idbm_slp_defaults(idbm_t *db, struct iscsi_slp_config *cfg); +-extern int idbm_discovery_read(idbm_t *db, discovery_rec_t *rec, char *addr, ++extern int idbm_bind_ifaces_to_node(struct node_rec *new_rec, ++ struct list_head *ifaces, ++ struct list_head *bound_recs); ++extern int idbm_add_nodes(node_rec_t *newrec, ++ discovery_rec_t *drec, struct list_head *ifaces, ++ int overwrite); ++extern int idbm_add_discovery(discovery_rec_t *newrec, int overwrite); ++extern void idbm_sendtargets_defaults(struct iscsi_sendtargets_config *cfg); ++extern void idbm_slp_defaults(struct iscsi_slp_config *cfg); ++extern int idbm_discovery_read(discovery_rec_t *rec, char *addr, + int port); +-extern int idbm_rec_read(idbm_t *db, node_rec_t *out_rec, char *target_name, ++extern int idbm_rec_read(node_rec_t *out_rec, char *target_name, + int tpgt, char *addr, int port, + struct iface_rec *iface); +-extern int idbm_node_set_param(idbm_t *db, void *data, node_rec_t *rec); ++extern int idbm_node_set_param(void *data, node_rec_t *rec); + +-/* TODO: seperate iface, node and core idbm code */ +-extern int iface_id_is_mac(char *iface_id); +-extern void iface_copy(struct iface_rec *dst, struct iface_rec *src); +-extern int iface_is_bound(struct iface_rec *iface); +-extern int iface_match_bind_info(struct iface_rec *pattern, +- struct iface_rec *iface); +-extern struct iface_rec *iface_alloc(char *ifname, int *err); -extern int iface_conf_read(struct iface_rec *iface); -+extern int iface_conf_read(idbm_t *db, struct iface_rec *iface); - extern void iface_init(struct iface_rec *iface); - extern int iface_is_bound_by_hwaddr(struct iface_rec *iface); - extern int iface_is_bound_by_netdev(struct iface_rec *iface); -@@ -142,11 +146,10 @@ extern int iface_print_flat(void *data, struct iface_rec *iface); - extern void iface_setup_host_bindings(idbm_t *db); - extern int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern, - struct iface_rec *out_rec); +-extern void iface_init(struct iface_rec *iface); +-extern int iface_is_bound_by_hwaddr(struct iface_rec *iface); +-extern int iface_is_bound_by_netdev(struct iface_rec *iface); +-extern int iface_is_bound_by_ipaddr(struct iface_rec *iface); +-typedef int (iface_op_fn)(void *data, struct iface_rec *iface); +-extern int iface_for_each_iface(idbm_t *db, void *data, int *nr_found, +- iface_op_fn *fn); +-extern int iface_print_flat(void *data, struct iface_rec *iface); +-extern void iface_setup_host_bindings(idbm_t *db); +-extern int iface_get_by_bind_info(idbm_t *db, struct iface_rec *pattern, +- struct iface_rec *out_rec); -extern int iface_conf_update(struct db_set_param *set_param, -+extern int iface_conf_update(idbm_t *db, struct db_set_param *set_param, - struct iface_rec *iface); +- struct iface_rec *iface); -extern int iface_conf_write(struct iface_rec *iface); -extern int iface_conf_delete(struct iface_rec *iface); -extern int iface_conf_read(struct iface_rec *iface); -+extern int iface_conf_write(idbm_t *db, struct iface_rec *iface); -+extern int iface_conf_delete(idbm_t *db, struct iface_rec *iface); ++/* lower level idbm functions for use by iface.c */ ++extern void idbm_recinfo_config(recinfo_t *info, FILE *f); ++extern void idbm_recinfo_iface(struct iface_rec *r, recinfo_t *ri); ++extern int idbm_lock(void); ++extern void idbm_unlock(void); ++extern recinfo_t *idbm_recinfo_alloc(int max_keys); ++extern int idbm_verify_param(recinfo_t *info, char *name); ++extern int idbm_rec_update_param(recinfo_t *info, char *name, char *value, ++ int line_number); ++ ++enum { ++ IDBM_PRINT_TYPE_DISCOVERY, ++ IDBM_PRINT_TYPE_NODE, ++ IDBM_PRINT_TYPE_IFACE, ++}; - #define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]" - #define iface_str(_iface) \ +-#define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]" +-#define iface_str(_iface) \ +- (_iface)->hwaddress, (_iface)->ipaddress, (_iface)->netdev, \ +- (_iface)->name ++extern void idbm_print(int type, void *rec, int show, FILE *f); + + #endif /* IDBM_H */ +diff --git a/usr/iface.c b/usr/iface.c +new file mode 100644 +index 0000000..c23e5d8 +--- /dev/null ++++ b/usr/iface.c +@@ -0,0 +1,688 @@ ++/* ++ * iSCSI iface helpers ++ * ++ * Copyright (C) 2008 Mike Christie ++ * Copyright (C) 2008 Red Hat, Inc. All rights reserved. ++ * maintained by open-iscsi@@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "log.h" ++#include "list.h" ++#include "iscsi_sysfs.h" ++#include "iscsi_settings.h" ++#include "config.h" ++#include "transport.h" ++#include "idbm.h" ++#include "iface.h" ++ ++/* ++ * Default ifaces for use with transports that do not bind to hardware ++ * by defaults (transports that let the interconnect layer to the routing ++ * by defaults). ++ */ ++ ++/* ++ * iSCSI over TCP/IP ++ */ ++static struct iface_rec iface_default = { ++ .name = "default", ++ .transport_name = "tcp", ++ .netdev = DEFAULT_NETDEV, ++ .hwaddress = DEFAULT_HWADDRESS, ++}; ++ ++/* ++ * iSER ++ */ ++static struct iface_rec iface_iser = { ++ .name = "iser", ++ .transport_name = "iser", ++ .netdev = DEFAULT_NETDEV, ++ .hwaddress = DEFAULT_HWADDRESS, ++}; ++ ++/* ++ * Broadcom bnx2i ++ */ ++static struct iface_rec iface_bnx2i = { ++ .name = "bnx2i", ++ .transport_name = "bnx2i", ++ .netdev = DEFAULT_NETDEV, ++ .hwaddress = DEFAULT_HWADDRESS, ++}; ++ ++static struct iface_rec *default_ifaces[] = { ++ &iface_default, ++ &iface_iser, ++ &iface_bnx2i, ++ NULL, ++}; ++ ++static struct iface_rec *iface_match_default(struct iface_rec *iface) ++{ ++ struct iface_rec *def_iface; ++ int i = 0; ++ ++ while ((def_iface = default_ifaces[i++])) { ++ if (!strcmp(iface->name, def_iface->name)) ++ return def_iface; ++ } ++ return NULL; ++} ++ ++static void iface_init(struct iface_rec *iface) ++{ ++ if (!strlen(iface->name)) ++ sprintf(iface->name, DEFAULT_IFACENAME); ++} ++ ++/* ++ * default is to use tcp through whatever the network layer ++ * selects for us with the /etc/iscsi/initiatorname.iscsi iname. ++ */ ++void iface_setup_defaults(struct iface_rec *iface) ++{ ++ sprintf(iface->netdev, DEFAULT_NETDEV); ++// sprintf(iface->ipaddress, DEFAULT_IPADDRESS); ++ sprintf(iface->hwaddress, DEFAULT_HWADDRESS); ++ sprintf(iface->transport_name, DEFAULT_TRANSPORT); ++ iface_init(iface); ++} ++ ++struct iface_rec *iface_alloc(char *ifname, int *err) ++{ ++ struct iface_rec *iface; ++ ++ if (!strlen(ifname) || strlen(ifname) + 1 > ISCSI_MAX_IFACE_LEN) { ++ *err = EINVAL; ++ return NULL; ++ } ++ ++ iface = calloc(1, sizeof(*iface)); ++ if (!iface) { ++ *err = ENOMEM; ++ return NULL; ++ } ++ ++ strncpy(iface->name, ifname, ISCSI_MAX_IFACE_LEN); ++ INIT_LIST_HEAD(&iface->list); ++ return iface; ++} ++ ++static int __iface_conf_read(struct iface_rec *iface) ++{ ++ char *iface_conf; ++ recinfo_t *info; ++ FILE *f; ++ int rc = 0; ++ ++ iface_conf = calloc(1, PATH_MAX); ++ if (!iface_conf) ++ return ENOMEM; ++ ++ info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!info) { ++ rc = ENOMEM; ++ goto free_conf; ++ } ++ ++ snprintf(iface_conf, PATH_MAX, "%s/%s", IFACE_CONFIG_DIR, ++ iface->name); ++ ++ log_debug(5, "looking for iface conf %s", iface_conf); ++ f = fopen(iface_conf, "r"); ++ if (!f) { ++ /* ++ * if someone passes in default but has not defined ++ * a iface with default then we do it for them ++ */ ++ if (!strcmp(iface->name, DEFAULT_IFACENAME)) { ++ iface_setup_defaults(iface); ++ rc = 0; ++ } else ++ rc = errno; ++ goto free_info; ++ } ++ ++ iface_init(iface); ++ idbm_recinfo_iface(iface, info); ++ idbm_recinfo_config(info, f); ++ fclose(f); ++ ++free_info: ++ free(info); ++free_conf: ++ free(iface_conf); ++ return rc; ++} ++ ++int iface_conf_read(struct iface_rec *iface) ++{ ++ struct iface_rec *def_iface; ++ int rc; ++ ++ def_iface = iface_match_default(iface); ++ if (def_iface) { ++ iface_init(iface); ++ iface_copy(iface, def_iface); ++ return 0; ++ } ++ ++ idbm_lock(); ++ rc = __iface_conf_read(iface); ++ idbm_unlock(); ++ return rc; ++} ++ ++int iface_conf_delete(struct iface_rec *iface) ++{ ++ struct iface_rec *def_iface; ++ char *iface_conf; ++ int rc = 0; ++ ++ def_iface = iface_match_default(iface); ++ if (def_iface) { ++ log_error("iface %s is a special interface and " ++ "cannot be deleted.\n", iface->name); ++ return EINVAL; ++ } ++ ++ iface_conf = calloc(1, PATH_MAX); ++ if (!iface_conf) ++ return ENOMEM; ++ ++ sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name); ++ idbm_lock(); ++ if (unlink(iface_conf)) ++ rc = errno; ++ idbm_unlock(); ++ ++ free(iface_conf); ++ return rc; ++} ++ ++int iface_conf_write(struct iface_rec *iface) ++{ ++ struct iface_rec *def_iface; ++ char *iface_conf; ++ FILE *f; ++ int rc = 0; ++ ++ def_iface = iface_match_default(iface); ++ if (def_iface) { ++ log_error("iface %s is a special interface and " ++ "is not stored in %s.\n", iface->name, ++ IFACE_CONFIG_DIR); ++ return EINVAL; ++ } ++ ++ iface_conf = calloc(1, PATH_MAX); ++ if (!iface_conf) ++ return ENOMEM; ++ ++ sprintf(iface_conf, "%s/%s", IFACE_CONFIG_DIR, iface->name); ++ f = fopen(iface_conf, "w"); ++ if (!f) { ++ rc = errno; ++ goto free_conf; ++ } ++ ++ idbm_lock(); ++ idbm_print(IDBM_PRINT_TYPE_IFACE, iface, 1, f); ++ idbm_unlock(); ++ ++ fclose(f); ++free_conf: ++ free(iface_conf); ++ return rc; ++} ++ ++int iface_conf_update(struct db_set_param *param, ++ struct iface_rec *iface) ++{ ++ struct iface_rec *def_iface; ++ recinfo_t *info; ++ int rc = 0; ++ ++ def_iface = iface_match_default(iface); ++ if (def_iface) { ++ log_error("iface %s is a special interface and " ++ "cannot be modified.\n", iface->name); ++ return EINVAL; ++ } ++ ++ info = idbm_recinfo_alloc(MAX_KEYS); ++ if (!info) ++ return ENOMEM; ++ ++ idbm_recinfo_iface(iface, info); ++ rc = idbm_verify_param(info, param->name); ++ if (rc) ++ goto free_info; ++ ++ rc = idbm_rec_update_param(info, param->name, param->value, 0); ++ if (rc) { ++ rc = EIO; ++ goto free_info; ++ } ++ ++ rc = iface_conf_write(iface); ++free_info: ++ free(info); ++ return rc; ++} ++ ++static int iface_get_next_id(void) ++{ ++ struct stat statb; ++ char *iface_conf; ++ int i, rc = ENOSPC; ++ ++ iface_conf = calloc(1, PATH_MAX); ++ if (!iface_conf) ++ return ENOMEM; ++ ++ for (i = 0; i < INT_MAX; i++) { ++ memset(iface_conf, 0, PATH_MAX); ++ /* check len */ ++ snprintf(iface_conf, PATH_MAX, "iface%d", i); ++ if (strlen(iface_conf) > ISCSI_MAX_IFACE_LEN - 1) { ++ log_error("iface namespace is full. Remove unused " ++ "iface definitions from %s or send mail " ++ "to open-iscsi@googlegroups.com to report " ++ "the problem", IFACE_CONFIG_DIR); ++ rc = ENOSPC; ++ break; ++ } ++ memset(iface_conf, 0, PATH_MAX); ++ snprintf(iface_conf, PATH_MAX, "%s/iface%d", IFACE_CONFIG_DIR, ++ i); ++ ++ if (!stat(iface_conf, &statb)) ++ continue; ++ if (errno == ENOENT) { ++ rc = i; ++ break; ++ } ++ } ++ ++ free(iface_conf); ++ return rc; ++} ++ ++struct iface_search { ++ struct iface_rec *pattern; ++ struct iface_rec *found; ++}; ++ ++static int __iface_get_by_net_binding(void *data, struct iface_rec *iface) ++{ ++ struct iface_search *search = data; ++ ++ if (!strcmp(search->pattern->name, iface->name)) { ++ iface_copy(search->found, iface); ++ return 1; ++ } ++ ++ if (iface_is_bound_by_hwaddr(search->pattern)) { ++ if (!strcmp(iface->hwaddress, search->pattern->hwaddress)) { ++ iface_copy(search->found, iface); ++ return 1; ++ } else ++ return 0; ++ } ++ ++ if (iface_is_bound_by_netdev(search->pattern)) { ++ if (!strcmp(iface->netdev, search->pattern->netdev)) { ++ iface_copy(search->found, iface); ++ return 1; ++ } else ++ return 0; ++ } ++ ++/* ++ if (iface_is_bound_by_ipaddr(search->pattern)) { ++ if (!strcmp(iface->ipaddress, search->pattern->ipaddress)) { ++ iface_copy(search->found, iface); ++ return 1; ++ } else ++ return 0; ++ } ++*/ ++ return 0; ++} ++ ++/* ++ * Before 2.0.870, we only could bind by netdeivce or hwaddress, ++ * so we did a simple reverse lookup to go from sysfs info to ++ * the iface name. After 2.0.870 we added a lot of options to the ++ * iface binding so we added the ifacename to the kernel. ++ * ++ * This function is for older kernels that do not export the ifacename. ++ * If the user was doing iscsi_tcp session binding or using qla4xxx ++ * we will find the iface by matching the hwaddres or netdev. ++ */ ++int iface_get_by_net_binding(struct iface_rec *pattern, ++ struct iface_rec *out_rec) ++{ ++ int num_found = 0, rc; ++ struct iface_search search; ++ ++ search.pattern = pattern; ++ search.found = out_rec; ++ ++ rc = iface_for_each_iface(&search, &num_found, ++ __iface_get_by_net_binding); ++ if (rc == 1) ++ return 0; ++ ++ if (iface_is_bound_by_hwaddr(pattern) || ++ iface_is_bound_by_netdev(pattern)) ++ return ENODEV; ++ ++ /* ++ * compat for default behavior ++ */ ++ if (!strlen(pattern->name) || ++ !strcmp(pattern->name, DEFAULT_IFACENAME)) { ++ iface_setup_defaults(out_rec); ++ return 0; ++ } ++ ++ return ENODEV; ++} ++ ++static int __iface_setup_host_bindings(void *data, struct host_info *info) ++{ ++ struct iface_rec iface; ++ struct iscsi_transport *t; ++ int id; ++ ++ t = get_transport_by_hba(info->host_no); ++ if (!t) ++ return 0; ++ /* ++ * if software or partial offload do not touch the bindngs. ++ * They do not need it and may not support it ++ */ ++ if (!(t->caps & CAP_FW_DB)) ++ return 0; ++ ++ /* ++ * since this is only for qla4xxx we only care about finding ++ * a iface with a matching hwaddress. ++ */ ++ if (iface_get_by_net_binding(&info->iface, &iface)) { ++ /* Must be a new port */ ++ id = iface_get_next_id(); ++ if (id < 0) { ++ log_error("Could not add iface for %s.", ++ info->iface.hwaddress); ++ return 0; ++ } ++ memset(&iface, 0, sizeof(struct iface_rec)); ++ strcpy(iface.hwaddress, info->iface.hwaddress); ++ strcpy(iface.transport_name, info->iface.transport_name); ++ sprintf(iface.name, "iface%d", id); ++ if (iface_conf_write(&iface)) ++ log_error("Could not write iface conf for %s %s", ++ iface.name, iface.hwaddress); ++ /* fall through - will not be persistent */ ++ } ++ return 0; ++} ++ ++/* ++ * sync hw/offload iscsi scsi_hosts with iface values ++ */ ++void iface_setup_host_bindings(void) ++{ ++ int nr_found = 0; ++ ++ idbm_lock(); ++ if (access(IFACE_CONFIG_DIR, F_OK) != 0) { ++ if (mkdir(IFACE_CONFIG_DIR, 0660) != 0) { ++ log_error("Could not make %s. HW/OFFLOAD iscsi " ++ "may not be supported", IFACE_CONFIG_DIR); ++ idbm_unlock(); ++ return; ++ } ++ } ++ idbm_unlock(); ++ ++ if (sysfs_for_each_host(NULL, &nr_found, __iface_setup_host_bindings)) ++ log_error("Could not scan scsi hosts. HW/OFFLOAD iscsi " ++ "operations may not be supported."); ++} ++ ++void iface_copy(struct iface_rec *dst, struct iface_rec *src) ++{ ++ if (strlen(src->name)) ++ strcpy(dst->name, src->name); ++ if (strlen(src->netdev)) ++ strcpy(dst->netdev, src->netdev); ++// if (strlen(src->ipaddress)) ++// strcpy(dst->ipaddress, src->ipaddress); ++ if (strlen(src->hwaddress)) ++ strcpy(dst->hwaddress, src->hwaddress); ++ if (strlen(src->transport_name)) ++ strcpy(dst->transport_name, src->transport_name); ++ if (strlen(src->iname)) ++ strcpy(dst->iname, src->iname); ++} ++ ++int iface_is_valid(struct iface_rec *iface) ++{ ++ if (!iface) ++ return 0; ++ ++ if (!strlen(iface->name)) ++ return 0; ++ ++ if (!strlen(iface->transport_name)) ++ return 0; ++ ++ if (iface_is_bound_by_hwaddr(iface)) ++ return 1; ++ ++ if (iface_is_bound_by_netdev(iface)) ++ return 1; ++// if (iface_is_bound_by_ipaddr(iface)) ++// return 1; ++ ++ /* bound by transport name */ ++ return 1; ++} ++ ++int iface_match(struct iface_rec *pattern, struct iface_rec *iface) ++{ ++ if (!pattern || !iface) ++ return 1; ++ ++ if (!strlen(pattern->name)) ++ return 1; ++ ++ if (!strcmp(pattern->name, iface->name)) ++ return 1; ++ ++ return 0; ++} ++ ++int iface_is_bound_by_hwaddr(struct iface_rec *iface) ++{ ++ if (iface && strlen(iface->hwaddress) && ++ strcmp(iface->hwaddress, DEFAULT_HWADDRESS)) ++ return 1; ++ return 0; ++} ++ ++int iface_is_bound_by_netdev(struct iface_rec *iface) ++{ ++ if (iface && strlen(iface->netdev) && ++ strcmp(iface->netdev, DEFAULT_NETDEV)) ++ return 1; ++ return 0; ++} ++ ++int iface_is_bound_by_ipaddr(struct iface_rec *iface) ++{ ++ return 0; ++/* if (iface && strlen(iface->ipaddress) && ++ strcmp(iface->ipaddress, DEFAULT_NETDEV)) ++ return 1; ++ return 0; ++*/ ++} ++ ++/** ++ * iface_print_node_tree - print out binding info ++ * @iface: iface to print out ++ * ++ * Currently this looks like the iface conf print, because we only ++ * have the binding info. When we store the iface specific node settings ++ * in the iface record then it will look different. ++ */ ++int iface_print_tree(void *data, struct iface_rec *iface) ++{ ++ printf("Name: %s\n", iface->name); ++ printf("\tTransport Name: %s\n", ++ strlen(iface->transport_name) ? iface->transport_name : ++ UNKNOWN_VALUE); ++ printf("\tHW Address: %s\n", ++ strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE); ++ printf("\tNetdev: %s\n", ++ strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE); ++ printf("\tInitiator Name: %s\n", ++ strlen(iface->iname) ? iface->iname : UNKNOWN_VALUE); ++ return 0; ++} ++ ++int iface_print_flat(void *data, struct iface_rec *iface) ++{ ++ printf("%s %s,%s,%s,%s\n", ++ strlen(iface->name) ? iface->name : UNKNOWN_VALUE, ++ strlen(iface->transport_name) ? iface->transport_name : ++ UNKNOWN_VALUE, ++ strlen(iface->hwaddress) ? iface->hwaddress : UNKNOWN_VALUE, ++ strlen(iface->netdev) ? iface->netdev : UNKNOWN_VALUE, ++ strlen(iface->iname) ? iface->iname : UNKNOWN_VALUE); ++ return 0; ++} ++ ++int iface_for_each_iface(void *data, int *nr_found, iface_op_fn *fn) ++{ ++ DIR *iface_dirfd; ++ struct dirent *iface_dent; ++ struct iface_rec *iface, *def_iface; ++ int err = 0, i = 0; ++ ++ while ((def_iface = default_ifaces[i++])) { ++ iface = iface_alloc(def_iface->name, &err); ++ if (!iface) { ++ log_error("Could not add iface %s.", def_iface->name); ++ continue; ++ } ++ iface_copy(iface, def_iface); ++ err = fn(data, iface); ++ free(iface); ++ if (err) ++ return err; ++ (*nr_found)++; ++ } ++ ++ iface_dirfd = opendir(IFACE_CONFIG_DIR); ++ if (!iface_dirfd) ++ return errno; ++ ++ while ((iface_dent = readdir(iface_dirfd))) { ++ if (!strcmp(iface_dent->d_name, ".") || ++ !strcmp(iface_dent->d_name, "..")) ++ continue; ++ ++ log_debug(5, "iface_for_each_iface found %s", ++ iface_dent->d_name); ++ iface = iface_alloc(iface_dent->d_name, &err); ++ if (!iface || err) { ++ if (err == EINVAL) ++ log_error("Invalid iface name %s. Must be " ++ "from 1 to %d characters.", ++ iface_dent->d_name, ++ ISCSI_MAX_IFACE_LEN - 1); ++ else ++ log_error("Could not add iface %s.", ++ iface_dent->d_name); ++ continue; ++ } ++ ++ idbm_lock(); ++ err = __iface_conf_read(iface); ++ idbm_unlock(); ++ if (err) { ++ log_error("Could not read def iface %s (err %d)", ++ iface->name, err); ++ free(iface); ++ continue; ++ } ++ ++ if (!iface_is_valid(iface)) { ++ log_debug(5, "iface is not valid " ++ "Iface settings " iface_fmt, ++ iface_str(iface)); ++ free(iface); ++ continue; ++ } ++ ++ err = fn(data, iface); ++ free(iface); ++ if (err) ++ break; ++ (*nr_found)++; ++ } ++ ++ closedir(iface_dirfd); ++ return err; ++} ++ ++static int iface_link(void *data, struct iface_rec *iface) ++{ ++ struct list_head *ifaces = data; ++ struct iface_rec *iface_copy; ++ ++ iface_copy = calloc(1, sizeof(*iface_copy)); ++ if (!iface_copy) ++ return ENOMEM; ++ ++ memcpy(iface_copy, iface, sizeof(*iface_copy)); ++ INIT_LIST_HEAD(&iface_copy->list); ++ list_add_tail(&iface_copy->list, ifaces); ++ return 0; ++} ++ ++void iface_link_ifaces(struct list_head *ifaces) ++{ ++ int nr_found = 0; ++ ++ iface_for_each_iface(ifaces, &nr_found, iface_link); ++} ++ ++ +diff --git a/usr/iface.h b/usr/iface.h +new file mode 100644 +index 0000000..6da7d45 +--- /dev/null ++++ b/usr/iface.h +@@ -0,0 +1,56 @@ ++/* ++ * iSCSI iface helpers ++ * ++ * Copyright (C) 2008 Mike Christie ++ * Copyright (C) 2008 Red Hat, Inc. All rights reserved. ++ * maintained by open-iscsi@@googlegroups.com ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published ++ * by the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ * ++ * See the file COPYING included with this distribution for more details. ++ */ ++#ifndef ISCSI_IFACE_H ++#define ISCSI_IFACE_H ++ ++#define IFACE_CONFIG_DIR ISCSI_CONFIG_ROOT"ifaces" ++ ++struct iface_rec; ++struct list_head; ++ ++extern void iface_copy(struct iface_rec *dst, struct iface_rec *src); ++extern int iface_match(struct iface_rec *pattern, struct iface_rec *iface); ++extern struct iface_rec *iface_alloc(char *ifname, int *err); ++extern int iface_conf_read(struct iface_rec *iface); ++extern void iface_setup_defaults(struct iface_rec *iface); ++extern int iface_is_bound_by_hwaddr(struct iface_rec *iface); ++extern int iface_is_bound_by_netdev(struct iface_rec *iface); ++extern int iface_is_bound_by_ipaddr(struct iface_rec *iface); ++typedef int (iface_op_fn)(void *data, struct iface_rec *iface); ++extern int iface_for_each_iface(void *data, int *nr_found, ++ iface_op_fn *fn); ++extern int iface_print_flat(void *data, struct iface_rec *iface); ++extern int iface_print_tree(void *data, struct iface_rec *iface); ++extern void iface_setup_host_bindings(void); ++extern int iface_get_by_net_binding(struct iface_rec *pattern, ++ struct iface_rec *out_rec); ++extern int iface_conf_update(struct db_set_param *set_param, ++ struct iface_rec *iface); ++extern int iface_conf_write(struct iface_rec *iface); ++extern int iface_conf_delete(struct iface_rec *iface); ++extern int iface_is_valid(struct iface_rec *iface); ++extern void iface_link_ifaces(struct list_head *ifaces); ++ ++#define iface_fmt "[hw=%s,ip=%s,net_if=%s,iscsi_if=%s]" ++#define iface_str(_iface) \ ++ (_iface)->hwaddress, (_iface)->ipaddress, (_iface)->netdev, \ ++ (_iface)->name ++ ++#endif diff --git a/usr/initiator.c b/usr/initiator.c -index 4831ad8..0ee0938 100644 +index 4831ad8..96f4693 100644 --- a/usr/initiator.c +++ b/usr/initiator.c @@ -20,20 +20,10 @@ @@ -8972,16 +13496,18 @@ index 4831ad8..0ee0938 100644 } static void session_online_devs(int host_no, int sid) -@@ -144,6 +146,8 @@ __login_response_status(iscsi_conn_t *conn, +@@ -144,8 +146,9 @@ __login_response_status(iscsi_conn_t *conn, case LOGIN_OK: /* check the status class and detail */ return CONN_LOGIN_SUCCESS; + case LOGIN_REDIRECT: + return CONN_LOGIN_IMM_REDIRECT_RETRY; case LOGIN_IO_ERROR: - case LOGIN_WRONG_PORTAL_GROUP: +- case LOGIN_WRONG_PORTAL_GROUP: case LOGIN_REDIRECTION_FAILED: -@@ -187,18 +191,10 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, + return CONN_LOGIN_RETRY; + default: +@@ -187,18 +190,10 @@ __check_iscsi_status_class(iscsi_session_t *session, int cid, case ISCSI_STATUS_CLS_INITIATOR_ERR: switch (status_detail) { case ISCSI_LOGIN_STATUS_AUTH_FAILED: @@ -9004,7 +13530,7 @@ index 4831ad8..0ee0938 100644 case ISCSI_LOGIN_STATUS_TGT_FORBIDDEN: log_error("conn %d login rejected: initiator " "failed authorization with target", conn->id); -@@ -326,7 +322,7 @@ setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec) +@@ -326,7 +321,7 @@ setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec) if (resolve_address(conn_rec->address, port, &conn->saddr)) { log_error("cannot resolve host name %s", conn_rec->address); @@ -9013,7 +13539,7 @@ index 4831ad8..0ee0938 100644 } conn->failback_saddr = conn->saddr; -@@ -336,6 +332,67 @@ setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec) +@@ -336,6 +331,80 @@ setup_portal(iscsi_conn_t *conn, conn_rec_t *conn_rec) return 0; } @@ -9050,6 +13576,11 @@ index 4831ad8..0ee0938 100644 + session->initial_r2t_en = rec->session.iscsi.InitialR2T; + session->imm_data_en = rec->session.iscsi.ImmediateData; + session->first_burst = __padding(rec->session.iscsi.FirstBurstLength); ++ /* ++ * some targets like netapp fail the login if sent bad first_burst ++ * and max_burst lens, even when immediate data=no and ++ * initial r2t = Yes, so we always check the user values. ++ */ + if (session->first_burst < ISCSI_MIN_FIRST_BURST_LEN || + session->first_burst > ISCSI_MAX_FIRST_BURST_LEN) { + log_error("Invalid iscsi.FirstBurstLength of %u. Must be " @@ -9073,6 +13604,14 @@ index 4831ad8..0ee0938 100644 + session->max_burst = DEF_INI_MAX_BURST_LEN; + } + ++ if (session->first_burst > session->max_burst) { ++ log_error("Invalid iscsi.FirstBurstLength of %u. Must be " ++ "less than iscsi.MaxBurstLength. Setting to %u\n", ++ session->first_burst, session->max_burst); ++ rec->session.iscsi.FirstBurstLength = session->max_burst; ++ session->first_burst = session->max_burst; ++ } ++ + session->def_time2wait = rec->session.iscsi.DefaultTime2Wait; + session->def_time2retain = rec->session.iscsi.DefaultTime2Retain; + session->erl = rec->session.iscsi.ERL; @@ -9081,7 +13620,7 @@ index 4831ad8..0ee0938 100644 static int __session_conn_create(iscsi_session_t *session, int cid) { -@@ -343,11 +400,13 @@ __session_conn_create(iscsi_session_t *session, int cid) +@@ -343,11 +412,13 @@ __session_conn_create(iscsi_session_t *session, int cid) conn_rec_t *conn_rec = &session->nrec.conn[cid]; int err; @@ -9098,7 +13637,7 @@ index 4831ad8..0ee0938 100644 conn->socket_fd = -1; /* connection's timeouts */ conn->id = cid; -@@ -367,6 +426,8 @@ __session_conn_create(iscsi_session_t *session, int cid) +@@ -367,6 +438,8 @@ __session_conn_create(iscsi_session_t *session, int cid) conn->login_timeout = DEF_LOGIN_TIMEO; } @@ -9107,14 +13646,13 @@ index 4831ad8..0ee0938 100644 /* noop-out setting */ conn->noop_out_interval = conn_rec->timeo.noop_out_interval; conn->noop_out_timeout = conn_rec->timeo.noop_out_timeout; -@@ -381,38 +442,10 @@ __session_conn_create(iscsi_session_t *session, int cid) +@@ -381,38 +454,10 @@ __session_conn_create(iscsi_session_t *session, int cid) log_error("Invalid timeo.noop_out_interval. Must be greater " "than zero. Using default %d.\n", DEF_NOOP_OUT_INTERVAL); - conn->noop_out_timeout = DEF_NOOP_OUT_INTERVAL; -+ conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL; - } - +- } +- - /* - * currently not used (leftover from linux-iscsi which we - * may do one day) @@ -9135,8 +13673,9 @@ index 4831ad8..0ee0938 100644 - ISCSI_MAX_MAX_RECV_SEG_LEN, - DEF_INI_MAX_RECV_SEG_LEN); - conn->max_recv_dlength = DEF_INI_MAX_RECV_SEG_LEN; -- } -- ++ conn->noop_out_interval = DEF_NOOP_OUT_INTERVAL; + } + - /* - * iSCSI default, unless declared otherwise by the - * target during login @@ -9148,7 +13687,7 @@ index 4831ad8..0ee0938 100644 /* TCP options */ conn->tcp_window_size = conn_rec->tcp.window_size; -@@ -422,89 +455,20 @@ __session_conn_create(iscsi_session_t *session, int cid) +@@ -422,89 +467,20 @@ __session_conn_create(iscsi_session_t *session, int cid) err = setup_portal(conn, conn_rec); if (err) return err; @@ -9239,7 +13778,7 @@ index 4831ad8..0ee0938 100644 static iscsi_session_t* __session_create(node_rec_t *rec, struct iscsi_transport *t) { -@@ -518,62 +482,34 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) +@@ -518,62 +494,34 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) log_debug(2, "Allocted session %p", session); INIT_LIST_HEAD(&session->list); @@ -9317,7 +13856,7 @@ index 4831ad8..0ee0938 100644 /* session's eh parameters */ session->replacement_timeout = rec->session.timeo.replacement_timeout; -@@ -582,6 +518,10 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) +@@ -582,6 +530,10 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) "120 seconds\n"); session->replacement_timeout = DEF_REPLACEMENT_TIMEO; } @@ -9328,7 +13867,29 @@ index 4831ad8..0ee0938 100644 /* OUI and uniqifying number */ session->isid[0] = DRIVER_ISID_0; -@@ -610,20 +550,21 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) +@@ -594,36 +546,37 @@ __session_create(node_rec_t *rec, struct iscsi_transport *t) + /* setup authentication variables for the session*/ + __setup_authentication(session, &rec->session.auth); + +- session->param_mask = 0xFFFFFFFF; ++ session->param_mask = ~0ULL; + if (!(t->caps & CAP_MULTI_R2T)) +- session->param_mask &= ~(1 << ISCSI_PARAM_MAX_R2T); ++ session->param_mask &= ~ISCSI_MAX_R2T; + if (!(t->caps & CAP_HDRDGST)) +- session->param_mask &= ~(1 << ISCSI_PARAM_HDRDGST_EN); ++ session->param_mask &= ~ISCSI_HDRDGST_EN; + if (!(t->caps & CAP_DATADGST)) +- session->param_mask &= ~(1 << ISCSI_PARAM_DATADGST_EN); ++ session->param_mask &= ~ISCSI_DATADGST_EN; + if (!(t->caps & CAP_MARKERS)) { +- session->param_mask &= ~(1 << ISCSI_PARAM_IFMARKER_EN); +- session->param_mask &= ~(1 << ISCSI_PARAM_OFMARKER_EN); ++ session->param_mask &= ~ISCSI_IFMARKER_EN; ++ session->param_mask &= ~ISCSI_OFMARKER_EN; + } + + list_add_tail(&session->list, &t->sessions); return session; } @@ -9361,7 +13922,7 @@ index 4831ad8..0ee0938 100644 } } -@@ -632,210 +573,134 @@ __session_destroy(iscsi_session_t *session) +@@ -632,210 +585,136 @@ __session_destroy(iscsi_session_t *session) { log_debug(1, "destroying session\n"); list_del(&session->list); @@ -9381,35 +13942,37 @@ index 4831ad8..0ee0938 100644 - log_debug(3, "conn noop out timer %p stopped\n", - &conn->noop_out_timer); - } --} -- --static void --session_conn_cleanup(queue_task_t *qtask, mgmt_ipc_err_e err) --{ -- iscsi_conn_t *conn = qtask->conn; -- iscsi_session_t *session = conn->session; -- -- mgmt_ipc_write_rsp(qtask, err); -- session_stop_conn_timers(session, conn->id); -- __session_destroy(session); + actor_delete(&conn->login_timer); + actor_delete(&conn->nop_out_timer); } - static mgmt_ipc_err_e --__session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask, -- mgmt_ipc_err_e err) +-static void +-session_conn_cleanup(queue_task_t *qtask, mgmt_ipc_err_e err) ++static mgmt_ipc_err_e +session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask, + mgmt_ipc_err_e err) { +- iscsi_conn_t *conn = qtask->conn; iscsi_session_t *session = conn->session; +- mgmt_ipc_write_rsp(qtask, err); +- session_stop_conn_timers(session, conn->id); +- __session_destroy(session); +-} ++ if (session->id == -1) ++ goto disconnect_conn; + +-static mgmt_ipc_err_e +-__session_conn_shutdown(iscsi_conn_t *conn, queue_task_t *qtask, +- mgmt_ipc_err_e err) +-{ +- iscsi_session_t *session = conn->session; ++ if (!sysfs_session_has_leadconn(session->id)) ++ goto disconnect_conn; + - __conn_noop_out_delete(conn); - actor_delete(&conn->connect_timer); - iscsi_queue_flush(session->queue); -+ if (!conn->ksetup) -+ goto disconnect_conn; -+ + if (conn->state == STATE_IN_LOGIN || + conn->state == STATE_IN_LOGOUT || + conn->state == STATE_LOGGED_IN) { @@ -9428,7 +13991,6 @@ index 4831ad8..0ee0938 100644 log_error("can not safely destroy connection %d", conn->id); return MGMT_IPC_ERR_INTERNAL; } -+ conn->ksetup = 0; + +disconnect_conn: + log_debug(2, "disconnect conn"); @@ -9601,10 +14163,8 @@ index 4831ad8..0ee0938 100644 static void -reset_iscsi_params(iscsi_conn_t *conn) -+__session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, -+ int redirected) - { - iscsi_session_t *session = conn->session; +-{ +- iscsi_session_t *session = conn->session; - conn_rec_t *conn_rec = &session->nrec.conn[conn->id]; - node_rec_t *rec = &session->nrec; - @@ -9631,9 +14191,11 @@ index 4831ad8..0ee0938 100644 - -static int -__session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) --{ ++__session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop, ++ int redirected) + { - int rc, delay; -- iscsi_session_t *session = conn->session; + iscsi_session_t *session = conn->session; + uint32_t delay; log_debug(1, "re-opening session %d (reopen_cnt %d)", session->id, @@ -9653,7 +14215,7 @@ index 4831ad8..0ee0938 100644 conn->state = STATE_XPT_WAIT; if (do_stop) { -@@ -844,6 +709,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) +@@ -844,6 +723,7 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) conn->id, do_stop)) { log_error("can't stop connection %d:%d (%d)", session->id, conn->id, errno); @@ -9661,7 +14223,7 @@ index 4831ad8..0ee0938 100644 goto queue_reopen; } log_debug(3, "connection %d:%d is stopped for recovery", -@@ -851,50 +717,30 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) +@@ -851,50 +731,30 @@ __session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) } conn->session->t->template->ep_disconnect(conn); @@ -9725,7 +14287,7 @@ index 4831ad8..0ee0938 100644 /* * If we were temporarily redirected, we need to fall back to * the original address to see where the target will send us -@@ -903,28 +749,299 @@ session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) +@@ -903,28 +763,299 @@ session_conn_reopen(iscsi_conn_t *conn, queue_task_t *qtask, int do_stop) memset(&conn->saddr, 0, sizeof(struct sockaddr_storage)); conn->saddr = conn->failback_saddr; @@ -9891,7 +14453,7 @@ index 4831ad8..0ee0938 100644 + qtask = session->sync_qtask; + else + qtask = &session->reopen_qtask; -+ iscsi_login_eh(conn, qtask, STOP_CONN_RECOVER); ++ iscsi_login_eh(conn, qtask, MGMT_IPC_ERR_TRANS_FAILURE); + return; + } + log_debug(1, "ignoring conn error in login. " @@ -10035,7 +14597,7 @@ index 4831ad8..0ee0938 100644 } static void -@@ -946,6 +1063,7 @@ void free_initiator(void) +@@ -946,6 +1077,7 @@ void free_initiator(void) list_for_each_entry(t, &transports, list) { list_for_each_entry_safe(session, tmp, &t->sessions, list) { list_del(&session->list); @@ -10043,16 +14605,16 @@ index 4831ad8..0ee0938 100644 session_release(session); } } -@@ -1000,7 +1118,7 @@ mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value) +@@ -1000,7 +1132,7 @@ mgmt_ipc_err_e iscsi_host_set_param(int host_no, int param, char *value) return MGMT_IPC_OK; } -#define MAX_SESSION_PARAMS 24 -+#define MAX_SESSION_PARAMS 29 ++#define MAX_SESSION_PARAMS 30 #define MAX_HOST_PARAMS 3 static void -@@ -1155,30 +1273,35 @@ setup_full_feature_phase(iscsi_conn_t *conn) +@@ -1155,35 +1287,45 @@ setup_full_feature_phase(iscsi_conn_t *conn) .value = session->password_in, .type = ISCSI_STRING, .conn_only = 0, @@ -10081,6 +14643,10 @@ index 4831ad8..0ee0938 100644 + .value = &conn->noop_out_interval, + .type = ISCSI_INT, + .conn_only = 1, ++ }, { ++ .param = ISCSI_PARAM_IFACE_NAME, ++ .value = session->nrec.iface.name, ++ .type = ISCSI_STRING, }, - /* - * FIXME: set these timeouts via set_param() API @@ -10109,7 +14675,14 @@ index 4831ad8..0ee0938 100644 /* Entered full-feature phase! */ for (i = 0; i < MAX_SESSION_PARAMS; i++) { if (conn->id != 0 && !conntbl[i].conn_only) -@@ -1195,11 +1318,16 @@ setup_full_feature_phase(iscsi_conn_t *conn) + continue; +- if (!(session->param_mask & (1 << conntbl[i].param))) ++ ++ if (!(session->param_mask & (1ULL << conntbl[i].param))) + continue; + + rc = ipc->set_param(session->t->handle, session->id, +@@ -1195,11 +1337,16 @@ setup_full_feature_phase(iscsi_conn_t *conn) conntbl[i].param, session->id, conn->id, rc, errno); @@ -10128,7 +14701,7 @@ index 4831ad8..0ee0938 100644 print_param_value(conntbl[i].param, conntbl[i].value, conntbl[i].type); } -@@ -1208,8 +1336,8 @@ setup_full_feature_phase(iscsi_conn_t *conn) +@@ -1208,8 +1355,8 @@ setup_full_feature_phase(iscsi_conn_t *conn) if (__iscsi_host_set_param(session->t, session->hostno, hosttbl[i].param, hosttbl[i].value, hosttbl[i].type)) { @@ -10139,7 +14712,7 @@ index 4831ad8..0ee0938 100644 return; } -@@ -1219,10 +1347,9 @@ setup_full_feature_phase(iscsi_conn_t *conn) +@@ -1219,10 +1366,9 @@ setup_full_feature_phase(iscsi_conn_t *conn) if (ipc->start_conn(session->t->handle, session->id, conn->id, &rc) || rc) { @@ -10151,7 +14724,7 @@ index 4831ad8..0ee0938 100644 return; } -@@ -1255,20 +1382,20 @@ setup_full_feature_phase(iscsi_conn_t *conn) +@@ -1255,20 +1401,20 @@ setup_full_feature_phase(iscsi_conn_t *conn) session->r_stage = R_STAGE_NO_CHANGE; /* noop_out */ @@ -10180,7 +14753,7 @@ index 4831ad8..0ee0938 100644 /* * assume we were in STATE_IN_LOGOUT or there * was some nasty error -@@ -1280,10 +1407,10 @@ static void iscsi_logout_timeout(void *data) +@@ -1280,10 +1426,10 @@ static void iscsi_logout_timeout(void *data) static int iscsi_send_logout(iscsi_conn_t *conn) { struct iscsi_logout hdr; @@ -10194,7 +14767,7 @@ index 4831ad8..0ee0938 100644 memset(&hdr, 0, sizeof(struct iscsi_logout)); hdr.opcode = ISCSI_OP_LOGOUT | ISCSI_OP_IMMEDIATE; -@@ -1293,23 +1420,53 @@ static int iscsi_send_logout(iscsi_conn_t *conn) +@@ -1293,23 +1439,53 @@ static int iscsi_send_logout(iscsi_conn_t *conn) if (!iscsi_io_send_pdu(conn, (struct iscsi_hdr*)&hdr, ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 0)) @@ -10255,7 +14828,7 @@ index 4831ad8..0ee0938 100644 } else /* noop in req */ if (!__send_nopin_rsp(conn, (struct iscsi_nopin*)hdr, conn->data)) { -@@ -1319,7 +1476,13 @@ static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr) +@@ -1319,7 +1495,13 @@ static void iscsi_recv_nop_in(iscsi_conn_t *conn, struct iscsi_hdr *hdr) static void iscsi_recv_logout_rsp(iscsi_conn_t *conn, struct iscsi_hdr *hdr) { @@ -10269,7 +14842,7 @@ index 4831ad8..0ee0938 100644 /* TODO process the hdr */ __conn_error_handle(conn->session, conn); } -@@ -1330,6 +1493,7 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) +@@ -1330,6 +1512,7 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) struct iscsi_async *async_hdr = (struct iscsi_async *)hdr; char *buf = conn->data; unsigned int senselen; @@ -10277,7 +14850,7 @@ index 4831ad8..0ee0938 100644 log_debug(3, "Read AEN %d\n", async_hdr->async_event); -@@ -1338,7 +1502,14 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) +@@ -1338,7 +1521,14 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) senselen = (buf[0] << 8) | buf[1]; buf += 2; @@ -10293,7 +14866,7 @@ index 4831ad8..0ee0938 100644 break; case ISCSI_ASYNC_MSG_REQUEST_LOGOUT: log_warning("Target requests logout within %u seconds for " -@@ -1351,14 +1522,14 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) +@@ -1351,14 +1541,14 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) log_warning("Target dropping connection %u, reconnect min %u " "max %u\n", ntohs(async_hdr->param1), ntohs(async_hdr->param2), ntohs(async_hdr->param3)); @@ -10310,7 +14883,7 @@ index 4831ad8..0ee0938 100644 (uint32_t)ntohs(async_hdr->param2) & 0x0000FFFFFL; break; case ISCSI_ASYNC_MSG_PARAM_NEGOTIATION: -@@ -1372,39 +1543,74 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) +@@ -1372,39 +1562,79 @@ static void iscsi_recv_async_msg(iscsi_conn_t *conn, struct iscsi_hdr *hdr) } } @@ -10368,7 +14941,12 @@ index 4831ad8..0ee0938 100644 +retry: + /* force retry */ + session->r_stage = R_STAGE_SESSION_REOPEN; ++ iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE); ++ return; +failed: ++ /* force faulure */ ++ session->r_stage = R_STAGE_NO_CHANGE; ++ session->reopen_cnt = session->nrec.session.initial_login_retry_max; + iscsi_login_eh(conn, c->qtask, MGMT_IPC_ERR_LOGIN_FAILURE); + return; +} @@ -10412,7 +14990,7 @@ index 4831ad8..0ee0938 100644 break; case STATE_LOGGED_IN: case STATE_IN_LOGOUT: -@@ -1432,59 +1638,56 @@ __session_conn_recv_pdu(queue_item_t *item) +@@ -1432,59 +1662,56 @@ __session_conn_recv_pdu(queue_item_t *item) } break; case STATE_XPT_WAIT: @@ -10494,14 +15072,13 @@ index 4831ad8..0ee0938 100644 if (conn->id == 0 && ipc->create_session(session->t->handle, session->nrec.session.initial_cmdsn, -@@ -1503,12 +1706,14 @@ __session_conn_poll(queue_item_t *item) +@@ -1503,12 +1730,13 @@ __session_conn_poll(queue_item_t *item) log_error("can't create connection (%d)", errno); err = MGMT_IPC_ERR_INTERNAL; - goto s_cleanup; + goto cleanup; } -+ conn->ksetup = 1; log_debug(3, "created new iSCSI connection " "%d:%d", session->id, conn->id); } @@ -10510,7 +15087,7 @@ index 4831ad8..0ee0938 100644 /* * TODO: use the iface number or some other value * so this will be persistent -@@ -1521,14 +1726,12 @@ __session_conn_poll(queue_item_t *item) +@@ -1521,14 +1749,12 @@ __session_conn_poll(queue_item_t *item) log_error("can't bind conn %d:%d to session %d, " "retcode %d (%d)", session->id, conn->id, session->id, rc, errno); @@ -10527,7 +15104,7 @@ index 4831ad8..0ee0938 100644 c->qtask = qtask; c->cid = conn->id; c->buffer = conn->data; -@@ -1537,248 +1740,63 @@ __session_conn_poll(queue_item_t *item) +@@ -1537,250 +1763,65 @@ __session_conn_poll(queue_item_t *item) set_exp_statsn(conn); if (iscsi_login_begin(session, c)) { @@ -10747,17 +15324,17 @@ index 4831ad8..0ee0938 100644 - return; default: - log_debug(8, "invalid state %d\n", conn->state); -+ log_error("Invalid event type %d.", event); - return; - } +- return; +- } - - if (session->r_stage == R_STAGE_SESSION_REOPEN) { - session_conn_reopen(conn, &session->reopen_qtask, - STOP_CONN_RECOVER); -- return; -- } --} -- ++ log_error("Invalid event type %d.", event); + return; + } + } + -static void -__session_conn_error(queue_item_t *item) -{ @@ -10812,10 +15389,22 @@ index 4831ad8..0ee0938 100644 - } - } - session_put(session); +-} +- + iscsi_session_t* + session_find_by_sid(int sid) + { +@@ -1796,8 +1837,7 @@ session_find_by_sid(int sid) + return NULL; } - iscsi_session_t* -@@ -1834,7 +1852,6 @@ int session_is_running(node_rec_t *rec) +-iscsi_session_t* +-session_find_by_rec(node_rec_t *rec) ++static iscsi_session_t* session_find_by_rec(node_rec_t *rec) + { + struct iscsi_transport *t; + iscsi_session_t *session; +@@ -1834,11 +1874,16 @@ int session_is_running(node_rec_t *rec) int session_login_task(node_rec_t *rec, queue_task_t *qtask) { @@ -10823,7 +15412,17 @@ index 4831ad8..0ee0938 100644 iscsi_session_t *session; iscsi_conn_t *conn; struct iscsi_transport *t; -@@ -1904,32 +1921,14 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) + ++ if (session_is_running(rec)) { ++ log_error("session [%s,%s,%d] already running.", rec->name, ++ rec->conn[0].address, rec->conn[0].port); ++ return MGMT_IPC_ERR_EXISTS; ++ } ++ + t = get_transport_by_name(rec->iface.transport_name); + if (!t) + return MGMT_IPC_ERR_TRANS_NOT_FOUND; +@@ -1904,32 +1949,14 @@ session_login_task(node_rec_t *rec, queue_task_t *qtask) conn = &session->conn[0]; qtask->conn = conn; @@ -10858,7 +15457,7 @@ index 4831ad8..0ee0938 100644 return MGMT_IPC_OK; } -@@ -1939,10 +1938,9 @@ sync_conn(iscsi_session_t *session, uint32_t cid) +@@ -1939,10 +1966,9 @@ sync_conn(iscsi_session_t *session, uint32_t cid) iscsi_conn_t *conn; if (__session_conn_create(session, cid)) @@ -10870,7 +15469,7 @@ index 4831ad8..0ee0938 100644 /* TODO: must export via sysfs so we can pick this up */ conn->state = STATE_CLEANUP_WAIT; return 0; -@@ -1963,7 +1961,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) +@@ -1963,7 +1989,7 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) session = __session_create(rec, t); if (!session) @@ -10879,7 +15478,7 @@ index 4831ad8..0ee0938 100644 session->id = sid; session->hostno = get_host_no_from_sid(sid, &err); -@@ -1977,10 +1975,8 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) +@@ -1977,10 +2003,8 @@ iscsi_sync_session(node_rec_t *rec, queue_task_t *qtask, uint32_t sid) err = sync_conn(session, 0); if (err) { @@ -10891,7 +15490,7 @@ index 4831ad8..0ee0938 100644 else err = MGMT_IPC_ERR_INVAL; goto destroy_session; -@@ -1999,6 +1995,17 @@ destroy_session: +@@ -1999,17 +2023,40 @@ destroy_session: return err; } @@ -10907,11 +15506,18 @@ index 4831ad8..0ee0938 100644 +} + int - session_logout_task(iscsi_session_t *session, queue_task_t *qtask) +-session_logout_task(iscsi_session_t *session, queue_task_t *qtask) ++session_logout_task(int sid, queue_task_t *qtask) { -@@ -2006,10 +2013,16 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask) ++ iscsi_session_t *session; + iscsi_conn_t *conn; mgmt_ipc_err_e rc = MGMT_IPC_OK; ++ session = session_find_by_sid(sid); ++ if (!session) { ++ log_debug(1, "session sid %d not found.\n", sid); ++ return MGMT_IPC_ERR_NOT_FOUND; ++ } conn = &session->conn[0]; + /* + * If syncing up or if this is the initial login and mgmt_ipc @@ -10927,7 +15533,7 @@ index 4831ad8..0ee0938 100644 log_error("session in invalid state for logout. " "Try again later\n"); return MGMT_IPC_ERR_INTERNAL; -@@ -2018,6 +2031,8 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask) +@@ -2018,6 +2065,8 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask) /* FIXME: logout all active connections */ conn = &session->conn[0]; /* FIXME: implement Logout Request */ @@ -10936,7 +15542,7 @@ index 4831ad8..0ee0938 100644 qtask->conn = conn; qtask->rsp.command = MGMT_IPC_SESSION_LOGOUT; -@@ -2025,18 +2040,16 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask) +@@ -2025,18 +2074,16 @@ session_logout_task(iscsi_session_t *session, queue_task_t *qtask) switch (conn->state) { case STATE_LOGGED_IN: @@ -10960,7 +15566,7 @@ index 4831ad8..0ee0938 100644 break; } -@@ -2072,6 +2085,15 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login, +@@ -2072,6 +2119,15 @@ iscsi_host_send_targets(queue_task_t *qtask, int host_no, int do_login, */ void iscsi_async_session_creation(uint32_t host_no, uint32_t sid) { @@ -10977,7 +15583,7 @@ index 4831ad8..0ee0938 100644 session_online_devs(host_no, sid); session_scan_host(host_no, NULL); diff --git a/usr/initiator.h b/usr/initiator.h -index 70b5581..221e708 100644 +index 70b5581..594e8f8 100644 --- a/usr/initiator.h +++ b/usr/initiator.h @@ -30,7 +30,6 @@ @@ -11012,7 +15618,17 @@ index 70b5581..221e708 100644 typedef enum conn_login_status_e { CONN_LOGIN_SUCCESS = 0, CONN_LOGIN_FAILED = 1, -@@ -66,18 +82,14 @@ enum iscsi_login_status { +@@ -59,25 +75,20 @@ enum iscsi_login_status { + LOGIN_VERSION_MISMATCH = 3, + LOGIN_NEGOTIATION_FAILED = 4, + LOGIN_AUTHENTICATION_FAILED = 5, +- LOGIN_WRONG_PORTAL_GROUP = 6, +- LOGIN_REDIRECTION_FAILED = 7, +- LOGIN_INVALID_PDU = 8, +- LOGIN_REDIRECT = 9, ++ LOGIN_REDIRECTION_FAILED = 6, ++ LOGIN_INVALID_PDU = 7, ++ LOGIN_REDIRECT = 8, }; typedef enum iscsi_event_e { @@ -11037,7 +15653,7 @@ index 70b5581..221e708 100644 struct queue_task; typedef struct iscsi_login_context { -@@ -100,49 +112,26 @@ typedef struct iscsi_login_context { +@@ -100,49 +111,25 @@ typedef struct iscsi_login_context { struct iscsi_session; struct iscsi_conn; @@ -11060,7 +15676,6 @@ index 70b5581..221e708 100644 - struct qelem item; /* must stay at the top */ uint32_t id; - uintptr_t recv_handle; -+ int ksetup; struct iscsi_session *session; iscsi_login_context_t login_context; + struct iscsi_conn_context *recv_context; @@ -11095,7 +15710,7 @@ index 70b5581..221e708 100644 /* login state machine */ int current_stage; -@@ -169,8 +158,6 @@ typedef struct iscsi_conn { +@@ -169,8 +156,6 @@ typedef struct iscsi_conn { int logout_timeout; int auth_timeout; int active_timeout; @@ -11104,7 +15719,7 @@ index 70b5581..221e708 100644 int noop_out_interval; int noop_out_timeout; -@@ -185,11 +172,22 @@ typedef struct iscsi_conn { +@@ -185,11 +170,22 @@ typedef struct iscsi_conn { uint32_t max_xmit_dlength; /* the value declared by the target */ } iscsi_conn_t; @@ -11127,7 +15742,7 @@ index 70b5581..221e708 100644 } queue_task_t; struct iscsi_transport_template; -@@ -200,7 +198,6 @@ typedef struct iscsi_session { +@@ -200,7 +196,6 @@ typedef struct iscsi_session { struct list_head list; uint32_t id; uint32_t hostno; @@ -11135,7 +15750,7 @@ index 70b5581..221e708 100644 char netdev[IFNAMSIZ]; struct iscsi_transport *t; node_rec_t nrec; /* copy of original Node record in database */ -@@ -213,19 +210,17 @@ typedef struct iscsi_session { +@@ -213,19 +208,17 @@ typedef struct iscsi_session { int erl; uint32_t imm_data_en; uint32_t initial_r2t_en; @@ -11156,7 +15771,16 @@ index 70b5581..221e708 100644 char target_name[TARGET_NAME_MAXLEN + 1]; char *target_alias; char *initiator_name; -@@ -255,41 +250,14 @@ typedef struct iscsi_session { +@@ -247,7 +240,7 @@ typedef struct iscsi_session { + int password_in_length; + iscsi_conn_t conn[ISCSI_CONN_MAX]; + int ctrl_fd; +- uint32_t param_mask; ++ uint64_t param_mask; + + /* connection reopens during recovery */ + int reopen_cnt; +@@ -255,41 +248,14 @@ typedef struct iscsi_session { iscsi_session_r_stage_e r_stage; uint32_t replacement_timeout; @@ -11202,10 +15826,15 @@ index 70b5581..221e708 100644 /* login.c */ #define ISCSI_SESSION_TYPE_NORMAL 0 -@@ -363,8 +331,12 @@ extern int session_logout_task(iscsi_session_t *session, queue_task_t *qtask); +@@ -359,12 +325,14 @@ extern int iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, + + /* initiator.c */ + extern int session_login_task(node_rec_t *rec, queue_task_t *qtask); +-extern int session_logout_task(iscsi_session_t *session, queue_task_t *qtask); ++extern int session_logout_task(int sid, queue_task_t *qtask); extern iscsi_session_t *session_find_by_sid(int sid); - extern iscsi_session_t *session_find_by_rec(node_rec_t *rec); - extern int session_is_running(node_rec_t *rec); +-extern iscsi_session_t *session_find_by_rec(node_rec_t *rec); +-extern int session_is_running(node_rec_t *rec); -extern void* recvpool_get(iscsi_conn_t *conn, int ev_size); -extern void recvpool_put(iscsi_conn_t *conn, void *handle); +extern struct iscsi_conn_context *iscsi_conn_context_get(iscsi_conn_t *conn, @@ -11218,13 +15847,14 @@ index 70b5581..221e708 100644 *tsk, uint32_t sid); extern mgmt_ipc_err_e iscsi_host_send_targets(queue_task_t *qtask, diff --git a/usr/io.c b/usr/io.c -index bb06411..b0664a2 100644 +index bb06411..4efcb6f 100644 --- a/usr/io.c +++ b/usr/io.c -@@ -25,13 +25,8 @@ +@@ -24,14 +24,8 @@ + #include #include #include - #include +-#include -#include #include #include @@ -11235,7 +15865,7 @@ index bb06411..b0664a2 100644 #include #include -@@ -39,10 +34,8 @@ +@@ -39,11 +33,10 @@ #include "iscsi_proto.h" #include "initiator.h" #include "iscsi_ipc.h" @@ -11244,9 +15874,110 @@ index bb06411..b0664a2 100644 #include "transport.h" -#include "iscsi_settings.h" #include "idbm.h" ++#include "iface.h" #define LOG_CONN_CLOSED(conn) \ -@@ -569,7 +562,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, + do { \ +@@ -82,6 +75,8 @@ set_non_blocking(int fd) + + } + ++#if 0 ++/* not used by anyone */ + static int get_hwaddress_from_netdev(char *netdev, char *hwaddress) + { + struct ifaddrs *ifap, *ifa; +@@ -159,6 +154,7 @@ free_ifap: + freeifaddrs(ifap); + return found; + } ++#endif + + /* + * In this mode we do not support interfaces like a bond or alias because +@@ -166,15 +162,14 @@ free_ifap: + */ + static int get_netdev_from_hwaddress(char *hwaddress, char *netdev) + { +- struct ifaddrs *ifap, *ifa; +- struct sockaddr_in *s4; +- struct sockaddr_in6 *s6; ++ struct if_nameindex *ifni; + struct ifreq if_hwaddr; +- int found = 0, sockfd; ++ int found = 0, sockfd, i = 0; + unsigned char *hwaddr; +- char buf[INET6_ADDRSTRLEN], tmp_hwaddress[ISCSI_MAX_IFACE_LEN]; ++ char tmp_hwaddress[ISCSI_MAX_IFACE_LEN]; + +- if (getifaddrs(&ifap)) { ++ ifni = if_nameindex(); ++ if (ifni == NULL) { + log_error("Could not match hwaddress %s to netdev. " + "getifaddrs failed %d", hwaddress, errno); + return 0; +@@ -184,34 +179,13 @@ static int get_netdev_from_hwaddress(char *hwaddress, char *netdev) + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + log_error("Could not open socket for ioctl."); +- goto free_ifap; ++ goto free_ifni; + } + +- for (ifa = ifap; ifa; ifa = ifa->ifa_next) { +- if (!ifa->ifa_addr) +- continue; ++ for (i = 0; ifni[i].if_index && ifni[i].if_name; i++) { ++ struct if_nameindex *n = &ifni[i]; + +- switch (ifa->ifa_addr->sa_family) { +- case AF_INET: +- s4 = (struct sockaddr_in *)(ifa->ifa_addr); +- if (!inet_ntop(ifa->ifa_addr->sa_family, +- (void *)&(s4->sin_addr), buf, +- INET_ADDRSTRLEN)) +- continue; +- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); +- break; +- case AF_INET6: +- s6 = (struct sockaddr_in6 *)(ifa->ifa_addr); +- if (!inet_ntop(ifa->ifa_addr->sa_family, +- (void *)&(s6->sin6_addr), buf, INET6_ADDRSTRLEN)) +- continue; +- log_debug(4, "name %s addr %s\n", ifa->ifa_name, buf); +- break; +- default: +- continue; +- } +- +- strncpy(if_hwaddr.ifr_name, ifa->ifa_name, IFNAMSIZ); ++ strncpy(if_hwaddr.ifr_name, n->if_name, IFNAMSIZ); + if (ioctl(sockfd, SIOCGIFHWADDR, &if_hwaddr) < 0) { + log_error("Could not match %s to netdevice.", + hwaddress); +@@ -231,17 +205,17 @@ static int get_netdev_from_hwaddress(char *hwaddress, char *netdev) + log_debug(4, "Found hardware address %s", tmp_hwaddress); + if (!strcasecmp(tmp_hwaddress, hwaddress)) { + log_debug(4, "Matches %s to %s", hwaddress, +- ifa->ifa_name); ++ n->if_name); + memset(netdev, 0, IFNAMSIZ); +- strncpy(netdev, ifa->ifa_name, IFNAMSIZ); ++ strncpy(netdev, n->if_name, IFNAMSIZ); + found = 1; + break; + } + } + + close(sockfd); +-free_ifap: +- freeifaddrs(ifap); ++free_ifni: ++ if_freenameindex(ifni); + return found; + } + +@@ -569,7 +543,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, /* set a timeout, since the socket calls may take a long time * to timeout on their own */ @@ -11255,7 +15986,7 @@ index bb06411..b0664a2 100644 memset(&action, 0, sizeof (struct sigaction)); memset(&old, 0, sizeof (struct sigaction)); action.sa_sigaction = NULL; -@@ -627,23 +620,21 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -627,23 +601,21 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, end = header + sizeof (*hdr) + hdr->hlength; /* send all the data and any padding */ @@ -11286,7 +16017,7 @@ index bb06411..b0664a2 100644 rc = writev(session->ctrl_fd, vec, 1); else rc = ipc->writev(0, vec, 1); -@@ -671,7 +662,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -671,7 +643,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, vec[1].iov_base = (void *) &pad; vec[1].iov_len = pad_bytes; @@ -11295,7 +16026,7 @@ index bb06411..b0664a2 100644 rc = writev(session->ctrl_fd, vec, 2); else rc = ipc->writev(0, vec, 2); -@@ -695,10 +686,9 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -695,10 +667,9 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, } } @@ -11309,7 +16040,7 @@ index bb06411..b0664a2 100644 ret = 0; goto done; } -@@ -707,7 +697,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -707,7 +678,7 @@ iscsi_io_send_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, ret = 1; done: @@ -11318,7 +16049,7 @@ index bb06411..b0664a2 100644 alarm(0); sigaction(SIGALRM, &old, NULL); timedout = 0; -@@ -732,8 +722,6 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -732,8 +703,6 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, char *end = data + max_data_length; struct sigaction action; struct sigaction old; @@ -11327,7 +16058,7 @@ index bb06411..b0664a2 100644 iscsi_session_t *session = conn->session; memset(data, 0, max_data_length); -@@ -741,7 +729,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -741,7 +710,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, /* set a timeout, since the socket calls may take a long * time to timeout on their own */ @@ -11336,7 +16067,7 @@ index bb06411..b0664a2 100644 memset(&action, 0, sizeof (struct sigaction)); memset(&old, 0, sizeof (struct sigaction)); action.sa_sigaction = NULL; -@@ -751,8 +739,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -751,8 +720,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, timedout = 0; alarm(timeout); } else { @@ -11346,7 +16077,7 @@ index bb06411..b0664a2 100644 failed = 1; goto done; } -@@ -760,7 +747,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -760,7 +728,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, /* read a response header */ do { @@ -11355,7 +16086,16 @@ index bb06411..b0664a2 100644 rlen = read(session->ctrl_fd, header, sizeof (*hdr) - h_bytes); else -@@ -817,7 +804,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -807,7 +775,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, + if (dlength == 0) + goto done; + +- if (data + dlength >= end) { ++ if (data + dlength > end) { + log_warning("buffer size %u too small for data length %u", + max_data_length, dlength); + failed = 1; +@@ -817,7 +785,7 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, /* read the rest into our buffer */ d_bytes = 0; while (d_bytes < dlength) { @@ -11364,7 +16104,7 @@ index bb06411..b0664a2 100644 rlen = read(session->ctrl_fd, data + d_bytes, dlength - d_bytes); else -@@ -843,10 +830,10 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -843,10 +811,10 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, /* handle PDU data padding. * data is padded in case of kernel_io */ @@ -11379,7 +16119,7 @@ index bb06411..b0664a2 100644 while (pad_bytes > 0) { rlen = read(conn->socket_fd, &bytes, pad_bytes); -@@ -900,16 +887,14 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, +@@ -900,16 +868,14 @@ iscsi_io_recv_pdu(iscsi_conn_t *conn, struct iscsi_hdr *hdr, } done: @@ -11435,7 +16175,7 @@ index 87324db..76c485f 100644 #endif /* ISCSI_IPC_H */ diff --git a/usr/iscsi_settings.h b/usr/iscsi_settings.h -index f1d7a1e..107a4f7 100644 +index f1d7a1e..56f505f 100644 --- a/usr/iscsi_settings.h +++ b/usr/iscsi_settings.h @@ -3,12 +3,16 @@ @@ -11445,8 +16185,10 @@ index f1d7a1e..107a4f7 100644 -#define DEF_LOGIN_TIMEO 15 +#define DEF_LOGIN_TIMEO 30 #define DEF_LOGOUT_TIMEO 15 - #define DEF_NOOP_OUT_INTERVAL 10 - #define DEF_NOOP_OUT_TIMEO 15 +-#define DEF_NOOP_OUT_INTERVAL 10 +-#define DEF_NOOP_OUT_TIMEO 15 ++#define DEF_NOOP_OUT_INTERVAL 5 ++#define DEF_NOOP_OUT_TIMEO 5 #define DEF_REPLACEMENT_TIMEO 120 +#define DEF_ABORT_TIMEO 15 @@ -11457,10 +16199,10 @@ index f1d7a1e..107a4f7 100644 #define CMDS_MAX 128 #define QUEUE_DEPTH 32 diff --git a/usr/iscsi_sysfs.c b/usr/iscsi_sysfs.c -index c614192..65c8990 100644 +index c614192..7b65d6d 100644 --- a/usr/iscsi_sysfs.c +++ b/usr/iscsi_sysfs.c -@@ -21,32 +21,20 @@ +@@ -21,40 +21,61 @@ #include #include #include @@ -11481,20 +16223,62 @@ index c614192..65c8990 100644 #include "log.h" #include "initiator.h" #include "transport.h" ++#include "idbm.h" #include "version.h" #include "iscsi_sysfs.h" -#include "list.h" #include "iscsi_settings.h" ++#include "iface.h" #define ISCSI_TRANSPORT_DIR "/sys/class/iscsi_transport" #define ISCSI_SESSION_DIR "/sys/class/iscsi_session" #define ISCSI_CONN_DIR "/sys/class/iscsi_connection" #define ISCSI_HOST_DIR "/sys/class/iscsi_host" ++#define SCSI_HOST_DIR "/sys/class/scsi_host" +#define SCSI_DEVICE_DIR "/sys/bus/scsi/devices" #define ISCSI_MAX_SYSFS_BUFFER NI_MAXHOST -@@ -64,7 +52,7 @@ int read_sysfs_file(char *filename, void *value, char *format) ++/* ++ * TODO: make this into a real API and check inputs better and add doc. ++ * We should also use a common lib and search sysfs according to the sysfs ++ * doc in the kernel documetnation. ++ */ ++ + /* tmp buffer used by sysfs functions */ + static char sysfs_file[PATH_MAX]; +-int num_transports = 0; ++static int num_transports; + LIST_HEAD(transports); + ++/* mini implementation of versionsort for uclibc compatility */ ++int direntcmp(const void *d1, const void *d2) ++{ ++ const char *a = (*(const struct dirent **)d1)->d_name; ++ const char *b = (*(const struct dirent **)d2)->d_name; ++ while (*a && *b) { ++ int mask = (isdigit(*a) != 0) | ((isdigit(*b) != 0) << 1); ++ switch (mask) { ++ case 0: /* none are digit */ ++ if (*a == *b) ++ break; ++ return (*a - *b); ++ case 1: /* a is digit but not b */ ++ return -1; ++ case 2: /* b is digit but not a */ ++ return 1; ++ case 3: /* both ar digits */ ++ return atoi(a) - atoi(b); ++ } ++ a++; b++; ++ } ++ return *a - *b; ++} ++ + int read_sysfs_file(char *filename, void *value, char *format) + { + FILE *file; +@@ -64,7 +85,7 @@ int read_sysfs_file(char *filename, void *value, char *format) file = fopen(filename, "r"); if (file) { line = fgets(buffer, sizeof(buffer), file); @@ -11503,37 +16287,301 @@ index c614192..65c8990 100644 sscanf(buffer, format, value); else { log_debug(5, "Could not read %s.\n", filename); -@@ -543,6 +531,13 @@ int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session) +@@ -88,6 +109,21 @@ void free_transports(void) } + } - memset(sysfs_file, 0, PATH_MAX); ++int free_transport_by_handle(uint64_t handle) ++{ ++ struct iscsi_transport *t; ++ ++ list_for_each_entry(t, &transports, list) { ++ if (t->handle == handle) { ++ list_del(&t->list); ++ free(t); ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ + static int trans_filter(const struct dirent *dir) + { + return strcmp(dir->d_name, ".") && strcmp(dir->d_name, ".."); +@@ -103,7 +139,7 @@ static int read_transports(void) + log_debug(7, "in %s", __FUNCTION__); + + n = scandir(ISCSI_TRANSPORT_DIR, &namelist, trans_filter, +- versionsort); ++ direntcmp); + if (n < 0) { + log_error("Could not scan %s.", ISCSI_TRANSPORT_DIR); + return n; +@@ -373,19 +409,97 @@ uint32_t get_host_no_from_iface(struct iface_rec *iface, int *rc) + return host_no; + } + ++static int sysfs_read_iface(struct iface_rec *iface, int host_no, int sid) ++{ ++ struct iscsi_transport *t; ++ int ret; ++ ++ memset(sysfs_file, 0, PATH_MAX); ++ sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/hwaddress", host_no); ++ /* ++ * backward compat ++ * If we cannot get the address we assume we are doing the old ++ * style and use default. ++ */ ++ sprintf(iface->hwaddress, DEFAULT_HWADDRESS); ++ ret = read_sysfs_file(sysfs_file, iface->hwaddress, "%s\n"); ++ if (ret) ++ log_debug(7, "could not read hwaddress for %s", sysfs_file); ++ ++ t = get_transport_by_hba(host_no); ++ if (!t) ++ log_debug(7, "could not get transport name for host %d", ++ host_no); ++ else ++ strcpy(iface->transport_name, t->name); ++ ++ memset(sysfs_file, 0, PATH_MAX); ++ sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/ipaddress", host_no); ++ /* if not found just print out default */ ++ sprintf(iface->ipaddress, DEFAULT_IPADDRESS); ++ ret = read_sysfs_file(sysfs_file, iface->ipaddress, "%s\n"); ++ if (ret) ++ log_debug(7, "could not read local address for %s", ++ sysfs_file); ++ ++ memset(sysfs_file, 0, PATH_MAX); ++ sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/netdev", host_no); ++ /* if not found just print out default */ ++ sprintf(iface->netdev, DEFAULT_NETDEV); ++ ret = read_sysfs_file(sysfs_file, iface->netdev, "%s\n"); ++ if (ret) ++ log_debug(7, "could not read netdev for %s", ++ sysfs_file); ++ ++ memset(sysfs_file, 0, PATH_MAX); + sprintf(sysfs_file, ISCSI_HOST_DIR"/host%d/initiatorname", host_no); -+ ret = read_sysfs_file(sysfs_file, info->iface.iname, "%s\n"); ++ ret = read_sysfs_file(sysfs_file, iface->iname, "%s\n"); + if (ret) + log_debug(7, "Could not read initiatorname for %s", + sysfs_file); + ++ /* ++ * this is on the session, because we support multiple bindings ++ * per device. ++ */ + memset(sysfs_file, 0, PATH_MAX); - sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/hwaddress", host_no); - /* - * backward compat -@@ -581,12 +576,13 @@ int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session) ++ sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%u/ifacename", sid); ++ /* ++ * this was added after 2.0.869 so we could be doing iscsi_tcp ++ * session binding, but there may not be a ifacename set ++ */ ++ memset(iface->name, 0, sizeof(iface->name)); ++ ret = read_sysfs_file(sysfs_file, iface->name, "%s\n"); ++ if (ret) { ++ log_debug(7, "could not read iface name for %s", ++ sysfs_file); ++ /* ++ * if the ifacename file is not there then we are using a older ++ * kernel and can try to find the binding by the net info ++ * which was used on these older kernels. ++ */ ++ if (!iface_is_bound_by_hwaddr(iface) && ++ !iface_is_bound_by_netdev(iface)) ++ sprintf(iface->name, DEFAULT_IFACENAME); ++ else if (iface_get_by_net_binding(iface, iface)) ++ log_debug(7, "Could not find iface for session bound " ++ "to:" iface_fmt "\n", iface_str(iface)); ++ } ++ return ret; ++} ++ + int sysfs_for_each_host(void *data, int *nr_found, sysfs_host_op_fn *fn) + { + struct dirent **namelist; + int rc = 0, i, n; + struct host_info *info; +- struct iscsi_transport *t; + info = calloc(1, sizeof(*info)); + if (!info) + return ENOMEM; + + n = scandir(ISCSI_HOST_DIR, &namelist, trans_filter, +- versionsort); ++ direntcmp); + if (n <= 0) + goto free_info; + +@@ -397,44 +511,7 @@ int sysfs_for_each_host(void *data, int *nr_found, sysfs_host_op_fn *fn) + break; + } + +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/initiatorname", +- namelist[i]->d_name); +- rc = read_sysfs_file(sysfs_file, info->iname, "%s\n"); +- if (rc) +- log_debug(4, "Could not read initiatorname for host " +- "%u. Error %d\n", info->host_no, rc); +- +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/ipaddress", +- namelist[i]->d_name); +- rc = read_sysfs_file(sysfs_file, info->iface.ipaddress, "%s\n"); +- if (rc) +- log_debug(4, "Could not read ipaddress for host %u. " +- "Error %d\n", info->host_no, rc); +- +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/hwaddress", +- namelist[i]->d_name); +- rc = read_sysfs_file(sysfs_file, info->iface.hwaddress, "%s\n"); +- if (rc) +- log_debug(4, "Could not read hwaddress for host %u. " +- "Error %d\n", info->host_no, rc); +- +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/%s/netdev", +- namelist[i]->d_name); +- rc = read_sysfs_file(sysfs_file, info->iface.netdev, "%s\n"); +- if (rc) +- log_debug(4, "Could not read netdev for host %u. " +- "Error %d\n", info->host_no, rc); +- +- t = get_transport_by_hba(info->host_no); +- if (!t) +- log_debug(4, "could not get transport name for host %d", +- info->host_no); +- else +- strcpy(info->iface.transport_name, t->name); ++ sysfs_read_iface(&info->iface, info->host_no, -1); + + rc = fn(data, info); + if (rc != 0) +@@ -451,11 +528,28 @@ free_info: + return rc; + } + ++/** ++ * sysfs_session_has_leadconn - checks if session has lead conn in kernel ++ * @sid: session id ++ * ++ * return 1 if session has lead conn and 0 if not. ++ */ ++int sysfs_session_has_leadconn(uint32_t sid) ++{ ++ struct stat statb; ++ ++ memset(sysfs_file, 0, PATH_MAX); ++ sprintf(sysfs_file, ISCSI_CONN_DIR"/connection%u:0", sid); ++ if (!stat(sysfs_file, &statb)) ++ return 1; ++ else ++ return 0; ++} ++ + int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session) + { + int ret, pers_failed = 0; + uint32_t host_no; +- struct iscsi_transport *t; + + if (sscanf(session, "session%d", &info->sid) != 1) { + log_error("invalid session '%s'", session); +@@ -542,51 +636,17 @@ int get_sessioninfo_by_sysfs_id(struct session_info *info, char *session) + return ret; + } + +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/hwaddress", host_no); +- /* +- * backward compat +- * If we cannot get the address we assume we are doing the old +- * style and use default. +- */ +- sprintf(info->iface.hwaddress, DEFAULT_HWADDRESS); +- ret = read_sysfs_file(sysfs_file, info->iface.hwaddress, "%s\n"); +- if (ret) +- log_debug(7, "could not read hwaddress for %s", sysfs_file); +- +- t = get_transport_by_sid(info->sid); +- if (!t) +- log_debug(7, "could not get transport name for session %d", +- info->sid); +- else +- strcpy(info->iface.transport_name, t->name); +- +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/ipaddress", host_no); +- /* if not found just print out default */ +- sprintf(info->iface.ipaddress, DEFAULT_IPADDRESS); +- ret = read_sysfs_file(sysfs_file, info->iface.ipaddress, "%s\n"); +- if (ret) +- log_debug(7, "could not read local address for %s", +- sysfs_file); +- +- memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, ISCSI_HOST_DIR"/host%u/netdev", host_no); +- /* if not found just print out default */ +- sprintf(info->iface.netdev, DEFAULT_NETDEV); +- ret = read_sysfs_file(sysfs_file, info->iface.netdev, "%s\n"); +- if (ret) +- log_debug(7, "could not read netdev for %s", +- sysfs_file); +- ++ sysfs_read_iface(&info->iface, host_no, info->sid); ++ log_debug(7, "found targetname %s address %s pers address %s port %d " - "pers port %d driver %s iface ipaddress %s " +- "pers port %d driver %s iface ipaddress %s " - "netdev %s hwaddress %s", ++ "pers port %d driver %s iface name %s ipaddress %s " + "netdev %s hwaddress %s iname %s", info->targetname, info->address ? info->address : "NA", info->persistent_address ? info->persistent_address : "NA", - info->port, info->persistent_port, - info->iface.transport_name, info->iface.ipaddress, +- info->port, info->persistent_port, +- info->iface.transport_name, info->iface.ipaddress, - info->iface.netdev, info->iface.hwaddress); ++ info->port, info->persistent_port, info->iface.transport_name, ++ info->iface.name, info->iface.ipaddress, + info->iface.netdev, info->iface.hwaddress, + info->iface.iname); return 0; } -@@ -643,7 +639,7 @@ int get_host_state(char *state, int host_no) +@@ -602,7 +662,7 @@ int sysfs_for_each_session(void *data, int *nr_found, sysfs_session_op_fn *fn) + + sprintf(sysfs_file, ISCSI_SESSION_DIR); + n = scandir(sysfs_file, &namelist, trans_filter, +- versionsort); ++ direntcmp); + if (n <= 0) + goto free_info; + +@@ -633,17 +693,24 @@ free_info: + return rc; + } + ++int get_session_state(char *state, int sid) ++{ ++ memset(sysfs_file, 0, PATH_MAX); ++ sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/state", sid); ++ return read_sysfs_file(sysfs_file, state, "%s\n"); ++} ++ + int get_host_state(char *state, int host_no) + { + memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, "/sys/class/scsi_host/host%d/state", host_no); ++ sprintf(sysfs_file, SCSI_HOST_DIR"/host%d/state", host_no); + return read_sysfs_file(sysfs_file, state, "%s\n"); + } + int get_device_state(char *state, int host_no, int target, int lun) { memset(sysfs_file, 0, PATH_MAX); @@ -11542,7 +16590,7 @@ index c614192..65c8990 100644 host_no, target, lun); return read_sysfs_file(sysfs_file, state, "%s\n"); } -@@ -654,7 +650,7 @@ char *get_blockdev_from_lun(int host_no, int target, int lun) +@@ -654,7 +721,7 @@ char *get_blockdev_from_lun(int host_no, int target, int lun) struct dirent *dent; char *blockdev, *blockdup = NULL; @@ -11551,7 +16599,25 @@ index c614192..65c8990 100644 host_no, target, lun); dirfd = opendir(sysfs_file); if (!dirfd) -@@ -824,7 +820,7 @@ void set_device_online(int hostno, int target, int lun) +@@ -741,7 +808,7 @@ struct iscsi_transport *get_transport_by_hba(long host_no) + return NULL; + + memset(sysfs_file, 0, PATH_MAX); +- sprintf(sysfs_file, "/sys/class/scsi_host/host%lu/proc_name", host_no); ++ sprintf(sysfs_file, SCSI_HOST_DIR"/host%lu/proc_name", host_no); + rc = read_sysfs_file(sysfs_file, name, "%s\n"); + if (rc) { + log_error("Could not read %s rc %d.", sysfs_file, rc); +@@ -802,7 +869,7 @@ int sysfs_for_each_device(int host_no, uint32_t sid, + sprintf(sysfs_file, ISCSI_SESSION_DIR"/session%d/device/target%d:0:%d", + sid, host_no, target); + n = scandir(sysfs_file, &namelist, trans_filter, +- versionsort); ++ direntcmp); + if (n <= 0) + return 0; + +@@ -824,7 +891,7 @@ void set_device_online(int hostno, int target, int lun) { int fd; @@ -11560,7 +16626,7 @@ index c614192..65c8990 100644 hostno, target, lun); fd = open(sysfs_file, O_WRONLY); if (fd < 0) -@@ -841,7 +837,7 @@ void delete_device(int hostno, int target, int lun) +@@ -841,7 +908,7 @@ void delete_device(int hostno, int target, int lun) { int fd; @@ -11569,7 +16635,7 @@ index c614192..65c8990 100644 hostno, target, lun); fd = open(sysfs_file, O_WRONLY); if (fd < 0) -@@ -851,6 +847,20 @@ void delete_device(int hostno, int target, int lun) +@@ -851,12 +918,26 @@ void delete_device(int hostno, int target, int lun) close(fd); } @@ -11590,19 +16656,56 @@ index c614192..65c8990 100644 pid_t scan_host(int hostno, int async) { pid_t pid = 0; + int fd; + +- sprintf(sysfs_file, "/sys/class/scsi_host/host%d/scan", ++ sprintf(sysfs_file, SCSI_HOST_DIR"/host%d/scan", + hostno); + fd = open(sysfs_file, O_WRONLY); + if (fd < 0) { +@@ -907,7 +988,7 @@ int get_iscsi_kernel_version(char *buf) + return 0; + } + +-void check_class_version(void) ++int check_class_version(void) + { + char version[20]; + int i; +@@ -933,12 +1014,12 @@ void check_class_version(void) + if (!strncmp(version, ISCSI_VERSION_STR, i) || + /* support 2.6.18 */ + !strncmp(version, "1.1", 3)) +- return; ++ return 0; + + fail: + log_error( "Missing or Invalid version from %s. Make sure a up " + "to date scsi_transport_iscsi module is loaded and a up to" + "date version of iscsid is running. Exiting...", + ISCSI_VERSION_FILE); +- exit(1); ++ return -1; + } diff --git a/usr/iscsi_sysfs.h b/usr/iscsi_sysfs.h -index 827b7c1..c91b48b 100644 +index 827b7c1..4282a16 100644 --- a/usr/iscsi_sysfs.h +++ b/usr/iscsi_sysfs.h -@@ -17,7 +17,6 @@ +@@ -17,9 +17,12 @@ #ifndef ISCSI_SYSFS_H #define ISCSI_SYSFS_H -#include #include ++#include "types.h" ++#include "iscsi_proto.h" ++#include "config.h" ++ struct iscsi_session; -@@ -28,6 +27,27 @@ struct iscsi_auth_config; + struct iscsi_conn; + struct iscsi_session_operational_config; +@@ -28,11 +31,33 @@ struct iscsi_auth_config; #define SCSI_MAX_STATE_VALUE 32 @@ -11622,15 +16725,27 @@ index 827b7c1..c91b48b 100644 +}; + +struct host_info { -+ char iname[TARGET_NAME_MAXLEN + 1]; + struct iface_rec iface; + int host_no; +}; + ++extern int direntcmp(const void *d1, const void *d2); extern void free_transports(void); extern int get_iscsi_kernel_version(char *buf); - extern void check_class_version(void); -@@ -60,6 +80,7 @@ extern int get_host_state(char *state, int host_no); +-extern void check_class_version(void); ++extern int check_class_version(void); + extern int get_sessioninfo_by_sysfs_id(struct session_info *info, + char *sys_session); ++extern int sysfs_session_has_leadconn(uint32_t sid); + + typedef int (sysfs_session_op_fn)(void *, struct session_info *); + typedef int (sysfs_host_op_fn)(void *, struct host_info *); +@@ -56,18 +81,20 @@ extern void get_negotiated_session_conf(int sid, + extern void get_negotiated_conn_conf(int sid, + struct iscsi_conn_operational_config *conf); + extern pid_t scan_host(int hostno, int async); ++extern int get_session_state(char *state, int sid); + extern int get_host_state(char *state, int host_no); extern int get_device_state(char *state, int host_no, int target, int lun); extern void set_device_online(int hostno, int target, int lun); extern void delete_device(int hostno, int target, int lun); @@ -11638,8 +16753,17 @@ index 827b7c1..c91b48b 100644 extern int sysfs_for_each_device(int host_no, uint32_t sid, void (* fn)(int host_no, int target, int lun)); extern struct iscsi_transport *get_transport_by_hba(long host_no); + extern struct iscsi_transport *get_transport_by_session(char *sys_session); + extern struct iscsi_transport *get_transport_by_sid(uint32_t sid); + extern struct iscsi_transport *get_transport_by_name(char *transport_name); ++extern int free_transport_by_handle(uint64_t handle); + + extern struct list_head transports; +-extern int num_transports; + + #endif diff --git a/usr/iscsiadm.c b/usr/iscsiadm.c -index 1e706b9..53a848d 100644 +index 1e706b9..5b5aa71 100644 --- a/usr/iscsiadm.c +++ b/usr/iscsiadm.c @@ -19,20 +19,14 @@ @@ -11663,11 +16787,12 @@ index 1e706b9..53a848d 100644 #include "initiator.h" #include "iscsiadm.h" -@@ -45,13 +39,11 @@ +@@ -45,13 +39,12 @@ #include "iscsi_sysfs.h" #include "list.h" #include "iscsi_settings.h" +#include "fw_context.h" ++#include "iface.h" struct iscsi_ipc *ipc = NULL; /* dummy */ static char program_name[] = "iscsiadm"; @@ -11679,7 +16804,7 @@ index 1e706b9..53a848d 100644 enum iscsiadm_mode { MODE_DISCOVERY, -@@ -59,6 +51,7 @@ enum iscsiadm_mode { +@@ -59,13 +52,15 @@ enum iscsiadm_mode { MODE_SESSION, MODE_HOST, MODE_IFACE, @@ -11687,12 +16812,25 @@ index 1e706b9..53a848d 100644 }; enum iscsiadm_op { -@@ -86,13 +79,14 @@ static struct option const long_options[] = +- OP_NEW, +- OP_DELETE, +- OP_UPDATE, +- OP_SHOW, ++ OP_NOOP = 0x0, ++ OP_NEW = 0x1, ++ OP_DELETE = 0x2, ++ OP_UPDATE = 0x4, ++ OP_SHOW = 0x8, + }; + + static struct option const long_options[] = +@@ -86,13 +81,14 @@ static struct option const long_options[] = {"logout", no_argument, NULL, 'u'}, {"logoutall", required_argument, NULL, 'U'}, {"stats", no_argument, NULL, 's'}, +- {"debug", required_argument, NULL, 'g'}, + {"killiscsid", required_argument, NULL, 'k'}, - {"debug", required_argument, NULL, 'g'}, ++ {"debug", required_argument, NULL, 'd'}, {"show", no_argument, NULL, 'S'}, {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, @@ -11703,7 +16841,7 @@ index 1e706b9..53a848d 100644 static void usage(int status) { -@@ -101,12 +95,13 @@ static void usage(int status) +@@ -101,12 +97,14 @@ static void usage(int status) program_name); else { printf("\ @@ -11717,11 +16855,21 @@ index 1e706b9..53a848d 100644 -iscsiadm -m iface [ -dhV ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n"); +iscsiadm -m session [ -hV ] [ -d debug_level ] [ -P printlevel] [ -r sessionid | sysfsdir [ -R | -u | -s ] [ -o operation ] [ -n name ] [ -v value ] ]\n\ +iscsiadm -m iface [ -hV ] [ -d debug_level ] [ -P printlevel ] [ -I ifacename ] [ [ -o operation ] [ -n name ] [ -v value ] ]\n\ ++iscsiadm -m fw [ -l ]\n\ +iscsiadm -k priority\n"); } exit(status == 0 ? 0 : -1); } -@@ -143,6 +138,8 @@ str_to_mode(char *str) +@@ -125,7 +123,7 @@ str_to_op(char *str) + else if (!strcmp("show", str)) + op = OP_SHOW; + else +- op = -1; ++ op = OP_NOOP; + + return op; + } +@@ -143,6 +141,8 @@ str_to_mode(char *str) mode = MODE_SESSION; else if (!strcmp("iface", str)) mode = MODE_IFACE; @@ -11730,7 +16878,7 @@ index 1e706b9..53a848d 100644 else mode = -1; -@@ -161,12 +158,44 @@ str_to_type(char *str) +@@ -161,28 +161,70 @@ str_to_type(char *str) type = DISCOVERY_TYPE_SLP; else if (!strcmp("isns", str)) type = DISCOVERY_TYPE_ISNS; @@ -11773,32 +16921,61 @@ index 1e706b9..53a848d 100644 +} + /* - * TODO: when we get more time we can make add what sessions - * are connected to the host. For now you can see this in session -@@ -190,57 +219,33 @@ static int print_ifaces(idbm_t *db, int info_level) - return err; - } - --static int --session_login(node_rec_t *rec) -+static int iscsid_req_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd) +- * TODO: when we get more time we can make add what sessions +- * are connected to the host. For now you can see this in session +- * mode although with -P 3, althought it is not nicely structured +- * like how you would want ++ * TODO: we can display how the ifaces are related to node records. ++ * And we can add a scsi_host mode which would display how ++ * sessions are related to hosts ++ * (scsi_host and iscsi_sessions are the currently running instance of ++ * a iface or node record). + */ +-static int print_ifaces(idbm_t *db, int info_level) ++static int print_ifaces(int info_level) { - iscsiadm_req_t req; -- iscsiadm_rsp_t rsp; + int err, num_found = 0; - memset(&req, 0, sizeof(iscsiadm_req_t)); -- req.command = MGMT_IPC_SESSION_LOGIN; -+ req.command = cmd; - memcpy(&req.u.session.rec, rec, sizeof(node_rec_t)); +- if (info_level > 0) { +- log_error("Invalid info level %d. Try 0.", info_level); ++ switch (info_level) { ++ case 0: ++ case -1: ++ err = iface_for_each_iface(NULL, &num_found, ++ iface_print_flat); ++ break; ++ case 1: ++ err = iface_for_each_iface(NULL, &num_found, ++ iface_print_tree); ++ break; ++ default: ++ log_error("Invalid info level %d. Try 0 or 1.", info_level); + return EINVAL; + } -- return do_iscsid(&req, &rsp); -+ return iscsid_request(fd, &req); +- err = iface_for_each_iface(db, NULL, &num_found, iface_print_flat); + if (!num_found) { + log_error("No interfaces found."); + err = ENODEV; +@@ -191,59 +233,6 @@ static int print_ifaces(idbm_t *db, int info_level) } + static int +-session_login(node_rec_t *rec) +-{ +- iscsiadm_req_t req; +- iscsiadm_rsp_t rsp; +- +- memset(&req, 0, sizeof(iscsiadm_req_t)); +- req.command = MGMT_IPC_SESSION_LOGIN; +- memcpy(&req.u.session.rec, rec, sizeof(node_rec_t)); +- +- return do_iscsid(&req, &rsp); +-} +- -static int -__delete_target(void *data, struct session_info *info) -+static int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd) - { +-{ - node_rec_t *rec = data; - uint32_t host_no; - int err; @@ -11816,37 +16993,31 @@ index 1e706b9..53a848d 100644 - sysfs_for_each_device(host_no, info->sid, delete_device); - return 0; - } -+ iscsiadm_rsp_t rsp; - +- - /* keep on looking */ - return 0; -+ memset(&rsp, 0, sizeof(iscsiadm_rsp_t)); -+ return iscsid_response(fd, cmd, &rsp); - } - +-} +- -static int -session_logout(node_rec_t *rec) -+static int iscsid_req(iscsiadm_cmd_e cmd, node_rec_t *rec) - { +-{ - iscsiadm_req_t req; - iscsiadm_rsp_t rsp; - int num_found = 0; -+ int err, fd; - +- - memset(&req, 0, sizeof(req)); - req.command = MGMT_IPC_SESSION_LOGOUT; - memcpy(&req.u.session.rec, rec, sizeof(node_rec_t)); - - sysfs_for_each_session(rec, &num_found, __delete_target); - return do_iscsid(&req, &rsp); -+ err = iscsid_req_async(cmd, rec, &fd); -+ if (err) -+ return err; -+ return iscsid_req_wait(cmd, fd); - } - - static int -@@ -271,20 +276,232 @@ match_startup_mode(node_rec_t *rec, char *mode) +-} +- +-static int + match_startup_mode(node_rec_t *rec, char *mode) + { + /* +@@ -271,37 +260,243 @@ match_startup_mode(node_rec_t *rec, char *mode) return -1; } @@ -11916,11 +17087,29 @@ index 1e706b9..53a848d 100644 + return ret; +} + -+static int + static int +-__logout_by_startup(void *data, struct session_info *info) +for_each_session(struct node_rec *rec, sysfs_session_op_fn *fn) -+{ + { +- struct session_mgmt_fn *mgmt = data; +- char *mode = mgmt->mode; +- idbm_t *db = mgmt->db; +- node_rec_t rec; +- int rc = 0; + int err, num_found = 0; -+ + +- if (iface_get_by_bind_info(db, &info->iface, &rec.iface)) { +- /* +- * If someone removed the /etc/iscsi/ifaces file +- * between logins then this will fail. +- * +- * To support that, we would have to throw our ifacename +- * into the kernel. +- */ +- log_debug(7, "could not read data for [%s,%s.%d]\n", +- info->targetname, info->persistent_address, +- info->persistent_port); +- return -1; + err = sysfs_for_each_session(rec, &num_found, fn); + if (err) + log_error("Could not execute operation on all sessions. Err " @@ -11933,11 +17122,20 @@ index 1e706b9..53a848d 100644 + return err; +} + ++struct session_link_info { ++ struct list_head *list; ++ struct session_info *match_info; ++}; ++ +static int link_sessions(void *data, struct session_info *info) +{ -+ struct list_head *list = data; ++ struct session_link_info *link_info = data; ++ struct list_head *list = link_info->list; + struct session_info *new, *curr, *match = NULL; + ++ if (link_info->match_info && link_info->match_info->sid != info->sid) ++ return 0; ++ + new = calloc(1, sizeof(*new)); + if (!new) + return ENOMEM; @@ -11968,7 +17166,7 @@ index 1e706b9..53a848d 100644 + return 0; +} + -+static int link_recs(idbm_t *db, void *data, struct node_rec *rec) ++static int link_recs(void *data, struct node_rec *rec) +{ + struct list_head *list = data; + struct node_rec *rec_copy; @@ -11985,7 +17183,6 @@ index 1e706b9..53a848d 100644 +static int __logout_portal(struct session_info *info, struct list_head *list) +{ + struct iscsid_async_req *async_req = NULL; -+ struct node_rec tmprec; + int fd, rc; + + /* TODO: add fn to add session prefix info like dev_printk */ @@ -11993,22 +17190,18 @@ index 1e706b9..53a848d 100644 + info->sid, info->targetname, info->persistent_address, + info->port); + -+ memset(&tmprec, 0, sizeof(node_rec_t)); -+ strncpy(tmprec.name, info->targetname, TARGET_NAME_MAXLEN); -+ tmprec.conn[0].port = info->persistent_port; -+ strncpy(tmprec.conn[0].address, info->persistent_address, NI_MAXHOST); -+ memcpy(&tmprec.iface, &info->iface, sizeof(struct iface_rec)); -+ + async_req = calloc(1, sizeof(*async_req)); + if (!async_req) { + log_error("Could not allocate memory for async logout " + "handling. Using sequential logout instead."); -+ rc = iscsid_req(MGMT_IPC_SESSION_LOGOUT, &tmprec); ++ rc = iscsid_req_by_sid(MGMT_IPC_SESSION_LOGOUT, info->sid); + } else { + INIT_LIST_HEAD(&async_req->list); -+ rc = iscsid_req_async(MGMT_IPC_SESSION_LOGOUT, &tmprec, &fd); -+ } -+ ++ rc = iscsid_req_by_sid_async(MGMT_IPC_SESSION_LOGOUT, ++ info->sid, &fd); + } + +- if (idbm_rec_read(db, &rec, info->targetname, info->tpgt, + /* we raced with another app or instance of iscsiadm */ + switch (rc) { + case MGMT_IPC_ERR_NOT_FOUND: @@ -12032,31 +17225,32 @@ index 1e706b9..53a848d 100644 + return rc; +} + - static int --__logout_by_startup(void *data, struct session_info *info) -+__logout_portals(idbm_t *db, void *data, int *nr_found, -+ int (*logout_fn)(idbm_t *, void *, struct list_head *, ++static int ++__logout_portals(void *data, int *nr_found, ++ int (*logout_fn)(void *, struct list_head *, + struct session_info *)) - { -- struct session_mgmt_fn *mgmt = data; -- char *mode = mgmt->mode; -- idbm_t *db = mgmt->db; ++{ + struct session_info *curr_info, *tmp; ++ struct session_link_info link_info; + struct list_head session_list, logout_list; + int ret = 0, err; + + INIT_LIST_HEAD(&session_list); + INIT_LIST_HEAD(&logout_list); ++ ++ memset(&link_info, 0, sizeof(link_info)); ++ link_info.list = &session_list; ++ link_info.match_info = NULL; + *nr_found = 0; + -+ err = sysfs_for_each_session(&session_list, nr_found, ++ err = sysfs_for_each_session(&link_info, nr_found, + link_sessions); + if (err || !*nr_found) + return err; + + *nr_found = 0; + list_for_each_entry(curr_info, &session_list, list) { -+ err = logout_fn(db, data, &logout_list, curr_info); ++ err = logout_fn(data, &logout_list, curr_info); + if (err > 0 && !ret) + ret = err; + if (!err) @@ -12075,18 +17269,33 @@ index 1e706b9..53a848d 100644 +} + +static int -+__logout_by_startup(idbm_t *db, void *data, struct list_head *list, ++__logout_by_startup(void *data, struct list_head *list, + struct session_info *info) +{ + char *mode = data; - node_rec_t rec; - int rc = 0; - ++ node_rec_t rec; ++ int rc = 0; ++ + memset(&rec, 0, sizeof(node_rec_t)); - if (iface_get_by_bind_info(db, &info->iface, &rec.iface)) { ++ if (idbm_rec_read(&rec, info->targetname, info->tpgt, + info->persistent_address, +- info->persistent_port, &rec.iface)) { ++ info->persistent_port, &info->iface)) { /* - * If someone removed the /etc/iscsi/ifaces file -@@ -323,29 +540,15 @@ __logout_by_startup(void *data, struct session_info *info) + * this is due to a HW driver or some other driver + * not hooked in +@@ -313,9 +508,8 @@ __logout_by_startup(void *data, struct session_info *info) + } + + /* multiple drivers could be connected to the same portal */ +- if (!iscsi_match_session(&rec, info)) ++ if (strcmp(rec.iface.transport_name, info->iface.transport_name)) + return -1; +- + /* + * we always skip on boot because if the user killed this on + * they would not be able to do anything +@@ -323,29 +517,15 @@ __logout_by_startup(void *data, struct session_info *info) if (rec.startup == ISCSI_STARTUP_ONBOOT) return -1; @@ -12111,7 +17320,8 @@ index 1e706b9..53a848d 100644 } static int - logout_by_startup(idbm_t *db, char *mode) +-logout_by_startup(idbm_t *db, char *mode) ++logout_by_startup(char *mode) { - int num_found; - struct session_mgmt_fn mgmt; @@ -12119,7 +17329,7 @@ index 1e706b9..53a848d 100644 if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") || !strcmp(mode,"manual"))) { -@@ -354,24 +557,21 @@ logout_by_startup(idbm_t *db, char *mode) +@@ -354,24 +534,20 @@ logout_by_startup(idbm_t *db, char *mode) return EINVAL; } @@ -12127,13 +17337,12 @@ index 1e706b9..53a848d 100644 - mgmt.db = db; - - return sysfs_for_each_session(&mgmt, &num_found, __logout_by_startup); -+ return __logout_portals(db, mode, &nr_found, __logout_by_startup); ++ return __logout_portals(mode, &nr_found, __logout_by_startup); } static int -logout_portal(void *data, struct session_info *info) -+logout_portal(idbm_t *db, void *data, struct list_head *list, -+ struct session_info *info) ++logout_portal(void *data, struct list_head *list, struct session_info *info) { - node_rec_t tmprec, *rec = data; + struct node_rec *pattern_rec = data; @@ -12149,7 +17358,7 @@ index 1e706b9..53a848d 100644 return -1; /* we do not support this yet */ -@@ -383,33 +583,19 @@ logout_portal(void *data, struct session_info *info) +@@ -383,33 +559,19 @@ logout_portal(void *data, struct session_info *info) log_error("Logout not supported for driver: %s.", t->name); return -1; } @@ -12180,17 +17389,18 @@ index 1e706b9..53a848d 100644 + int nr_found; - return rc; -+ return __logout_portals(NULL, pattern_rec, &nr_found, logout_portal); ++ return __logout_portals(pattern_rec, &nr_found, logout_portal); } static struct node_rec * - create_node_record(idbm_t *db, char *targetname, int tpgt, char *ip, int port, +-create_node_record(idbm_t *db, char *targetname, int tpgt, char *ip, int port, - struct iface_rec *iface) ++create_node_record(char *targetname, int tpgt, char *ip, int port, + struct iface_rec *iface, int verbose) { struct node_rec *rec; -@@ -429,10 +615,30 @@ create_node_record(idbm_t *db, char *targetname, int tpgt, char *ip, int port, +@@ -429,10 +591,14 @@ create_node_record(idbm_t *db, char *targetname, int tpgt, char *ip, int port, strncpy(rec->conn[0].address, ip, NI_MAXHOST); memset(&rec->iface, 0, sizeof(struct iface_rec)); if (iface) { @@ -12198,25 +17408,9 @@ index 1e706b9..53a848d 100644 - log_error("Could not find iface info for %s.", - iface->name); - goto free_rec; -+ if (!strlen(iface->name)) { -+ if (iface_get_by_bind_info(db, iface, &rec->iface)) { -+ if (verbose) -+ log_error("Could not find iface info."); -+ goto free_rec; -+ } -+ } else if (!strcmp(iface->name, DEFAULT_IFACENAME)) -+ /* -+ * default is a special name and should not be used by -+ * a real iface -+ */ -+ iface_init(&rec->iface); -+ else { -+ /* -+ * the initial iface update will not be able to find -+ * by bind info because there is none. -+ */ -+ iface_copy(&rec->iface, iface); -+ if (iface_conf_read(db, &rec->iface)) { ++ iface_copy(&rec->iface, iface); ++ if (strlen(iface->name)) { ++ if (iface_conf_read(&rec->iface)) { + if (verbose) + log_error("Could not read iface info " + "for %s.", iface->name); @@ -12225,7 +17419,7 @@ index 1e706b9..53a848d 100644 } } return rec; -@@ -441,58 +647,89 @@ free_rec: +@@ -441,58 +607,89 @@ free_rec: return NULL; } @@ -12260,10 +17454,10 @@ index 1e706b9..53a848d 100644 - return err; + if (async_req) -+ rc = iscsid_req_async(MGMT_IPC_SESSION_LOGIN, -+ rec, &fd); ++ rc = iscsid_req_by_rec_async(MGMT_IPC_SESSION_LOGIN, ++ rec, &fd); + else -+ rc = iscsid_req(MGMT_IPC_SESSION_LOGIN, rec); ++ rc = iscsid_req_by_rec(MGMT_IPC_SESSION_LOGIN, rec); + /* we raced with another app or instance of iscsiadm */ + if (rc == MGMT_IPC_ERR_EXISTS) { + if (async_req) @@ -12351,7 +17545,7 @@ index 1e706b9..53a848d 100644 /* * we always skip onboot because this should be handled by * something else -@@ -500,15 +737,18 @@ __login_by_startup(idbm_t *db, void *data, node_rec_t *rec) +@@ -500,15 +697,18 @@ __login_by_startup(idbm_t *db, void *data, node_rec_t *rec) if (rec->startup == ISCSI_STARTUP_ONBOOT) return -1; @@ -12366,7 +17560,8 @@ index 1e706b9..53a848d 100644 } static int - login_by_startup(idbm_t *db, char *mode) +-login_by_startup(idbm_t *db, char *mode) ++login_by_startup(char *mode) { - int nr_found = 0, rc; + int nr_found = 0, rc, err; @@ -12374,13 +17569,13 @@ index 1e706b9..53a848d 100644 if (!mode || !(!strcmp(mode, "automatic") || !strcmp(mode, "all") || !strcmp(mode,"manual"))) { -@@ -517,7 +757,13 @@ login_by_startup(idbm_t *db, char *mode) +@@ -517,7 +717,13 @@ login_by_startup(idbm_t *db, char *mode) return EINVAL; } - rc = idbm_for_each_rec(db, &nr_found, mode, __login_by_startup); + INIT_LIST_HEAD(&rec_list); -+ rc = idbm_for_each_rec(db, &nr_found, &rec_list, link_recs); ++ rc = idbm_for_each_rec(&nr_found, &rec_list, link_recs); + err = __login_portals(mode, &nr_found, &rec_list, + __login_by_startup); + if (err && !rc) @@ -12389,29 +17584,85 @@ index 1e706b9..53a848d 100644 if (rc) log_error("Could not log into all portals. Err %d.", rc); else if (!nr_found) { -@@ -569,6 +815,21 @@ static int for_each_rec(idbm_t *db, struct node_rec *rec, void *data, - return __for_each_rec(db, 1, rec, data, fn); +@@ -527,7 +733,7 @@ login_by_startup(idbm_t *db, char *mode) + return rc; } +-static int iface_fn(idbm_t *db, void *data, node_rec_t *rec) ++static int iface_fn(void *data, node_rec_t *rec) + { + struct rec_op_data *op_data = data; + +@@ -535,10 +741,10 @@ static int iface_fn(idbm_t *db, void *data, node_rec_t *rec) + rec->conn[0].address, rec->conn[0].port, + &rec->iface)) + return -1; +- return op_data->fn(db, op_data->data, rec); ++ return op_data->fn(op_data->data, rec); + } + +-static int __for_each_rec(idbm_t *db, int verbose, struct node_rec *rec, ++static int __for_each_rec(int verbose, struct node_rec *rec, + void *data, idbm_iface_op_fn *fn) + { + struct rec_op_data op_data; +@@ -549,7 +755,7 @@ static int __for_each_rec(idbm_t *db, int verbose, struct node_rec *rec, + op_data.match_rec = rec; + op_data.fn = fn; + +- rc = idbm_for_each_rec(db, &nr_found, &op_data, iface_fn); ++ rc = idbm_for_each_rec(&nr_found, &op_data, iface_fn); + if (rc) { + if (verbose) + log_error("Could not execute operation on all " +@@ -563,13 +769,28 @@ static int __for_each_rec(idbm_t *db, int verbose, struct node_rec *rec, + return rc; + } + +-static int for_each_rec(idbm_t *db, struct node_rec *rec, void *data, ++static int for_each_rec(struct node_rec *rec, void *data, + idbm_iface_op_fn *fn) + { +- return __for_each_rec(db, 1, rec, data, fn); ++ return __for_each_rec(1, rec, data, fn); ++} + -+static int login_portals(idbm_t *db, struct node_rec *pattern_rec) ++ ++static int login_portals(struct node_rec *pattern_rec) +{ + struct list_head rec_list; + int err, ret, nr_found; + + INIT_LIST_HEAD(&rec_list); -+ ret = for_each_rec(db, pattern_rec, &rec_list, link_recs); ++ ret = for_each_rec(pattern_rec, &rec_list, link_recs); + err = __login_portals(NULL, &nr_found, &rec_list, + login_portal); + if (err && !ret) + ret = err; + return ret; -+} -+ - static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec) + } + +-static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec) ++static int print_nodes(int info_level, struct node_rec *rec) { struct node_rec tmp_rec; -@@ -593,47 +854,25 @@ static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec) + int rc = 0; +@@ -577,12 +798,12 @@ static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec) + switch (info_level) { + case 0: + case -1: +- if (for_each_rec(db, rec, NULL, idbm_print_node_flat)) ++ if (for_each_rec(rec, NULL, idbm_print_node_flat)) + rc = -1; + break; + case 1: + memset(&tmp_rec, 0, sizeof(node_rec_t)); +- if (for_each_rec(db, rec, &tmp_rec, idbm_print_node_tree)) ++ if (for_each_rec(rec, &tmp_rec, idbm_print_node_tree)) + rc = -1; + break; + default: +@@ -593,53 +814,35 @@ static int print_nodes(idbm_t *db, int info_level, struct node_rec *rec) return rc; } @@ -12463,7 +17714,17 @@ index 1e706b9..53a848d 100644 } static int print_session_flat(void *data, struct session_info *info) -@@ -653,40 +892,6 @@ static int print_session_flat(void *data, struct session_info *info) + { ++ struct session_info *match_info = data; + struct iscsi_transport *t = get_transport_by_sid(info->sid); + ++ if (match_info && match_info->sid != info->sid) ++ return 0; ++ + if (strchr(info->persistent_address, '.')) + printf("%s: [%d] %s:%d,%d %s\n", + t ? t->name : UNKNOWN_VALUE, +@@ -653,45 +856,13 @@ static int print_session_flat(void *data, struct session_info *info) return 0; } @@ -12504,42 +17765,161 @@ index 1e706b9..53a848d 100644 static int print_iscsi_state(int sid) { iscsiadm_req_t req; -@@ -823,7 +1028,6 @@ static void print_sessions_tree(idbm_t *db, struct list_head *list, int level) + iscsiadm_rsp_t rsp; ++ int err; + char *state = NULL; ++ char state_buff[SCSI_MAX_STATE_VALUE]; + static char *conn_state[] = { + "FREE", + "TRANSPORT WAIT", +@@ -712,23 +883,24 @@ static int print_iscsi_state(int sid) + req.command = MGMT_IPC_SESSION_INFO; + req.u.session.sid = sid; + +- if (do_iscsid(&req, &rsp)) { +- printf("\t\tiSCSI Connection State: Unknown\n"); +- printf("\t\tInternal iscsid Session State: Unknown\n"); +- return ENODEV; +- } +- ++ err = do_iscsid(&req, &rsp); + /* + * for drivers like qla4xxx, iscsid does not display + * anything here since it does not know about it. + */ +- if (rsp.u.session_state.conn_state >= 0 && ++ if (!err && rsp.u.session_state.conn_state >= 0 && + rsp.u.session_state.conn_state <= STATE_CLEANUP_WAIT) + state = conn_state[rsp.u.session_state.conn_state]; + printf("\t\tiSCSI Connection State: %s\n", state ? state : "Unknown"); + state = NULL; + +- if (rsp.u.session_state.session_state >= 0 && ++ memset(state_buff, 0, SCSI_MAX_STATE_VALUE); ++ if (!get_session_state(state_buff, sid)) ++ printf("\t\tiSCSI Session State: %s\n", state_buff); ++ else ++ printf("\t\tiSCSI Session State: Unknown\n"); ++ ++ if (!err && rsp.u.session_state.session_state >= 0 && + rsp.u.session_state.session_state <= R_STAGE_SESSION_REDIRECT) + state = session_state[rsp.u.session_state.session_state]; + printf("\t\tInternal iscsid Session State: %s\n", +@@ -818,12 +990,10 @@ static int print_scsi_state(int sid) + return 0; + } + +-static void print_sessions_tree(idbm_t *db, struct list_head *list, int level) ++static void print_sessions_tree(struct list_head *list, int level) + { struct session_info *curr, *prev = NULL, *tmp; struct iscsi_transport *t; - struct iface_rec iface; +- struct iface_rec iface; - int rc; list_for_each_entry(curr, list, list) { if (!prev || strcmp(prev->targetname, curr->targetname)) { -@@ -857,6 +1061,7 @@ static void print_sessions_tree(idbm_t *db, struct list_head *list, int level) +@@ -856,16 +1026,21 @@ static void print_sessions_tree(idbm_t *db, struct list_head *list, int level) + printf("\t\t**********\n"); printf("\t\tInterface:\n"); printf("\t\t**********\n"); - if (iface_is_bound(&curr->iface)) { -+ memset(&iface, 0, sizeof(struct iface_rec)); - if (iface_get_by_bind_info(db, &curr->iface, &iface)) - printf("\t\tIface Name: %s\n", UNKNOWN_VALUE); - else -@@ -865,6 +1070,9 @@ static void print_sessions_tree(idbm_t *db, struct list_head *list, int level) - printf("\t\tIface Name: %s\n", DEFAULT_IFACENAME); +- if (iface_is_bound(&curr->iface)) { +- if (iface_get_by_bind_info(db, &curr->iface, &iface)) +- printf("\t\tIface Name: %s\n", UNKNOWN_VALUE); +- else +- printf("\t\tIface Name: %s\n", iface.name); +- } else +- printf("\t\tIface Name: %s\n", DEFAULT_IFACENAME); ++ if (strlen(curr->iface.name)) ++ printf("\t\tIface Name: %s\n", curr->iface.name); ++ else ++ printf("\t\tIface Name: %s\n", UNKNOWN_VALUE); printf("\t\tIface Transport: %s\n", t ? t->name : UNKNOWN_VALUE); +- printf("\t\tIface IPaddress: %s\n", curr->iface.ipaddress); + printf("\t\tIface Initiatorname: %s\n", + strlen(curr->iface.iname) ? curr->iface.iname : + UNKNOWN_VALUE); - printf("\t\tIface IPaddress: %s\n", curr->iface.ipaddress); ++ if (strchr(curr->address, '.')) ++ printf("\t\tIface IPaddress: %s\n", ++ curr->iface.ipaddress); ++ else ++ printf("\t\tIface IPaddress: [%s]\n", ++ curr->iface.ipaddress); printf("\t\tIface HWaddress: %s\n", curr->iface.hwaddress); printf("\t\tIface Netdev: %s\n", curr->iface.netdev); -@@ -941,7 +1149,7 @@ static int print_sessions(idbm_t *db, int info_level) + printf("\t\tSID: %d\n", curr->sid); +@@ -888,37 +1063,7 @@ next: + } + } + +-static int print_session(idbm_t *db, int info_level, struct session_info *info) +-{ +- struct list_head list; +- int err; +- +- switch (info_level) { +- case 0: +- case -1: +- err = print_session_flat(NULL, info); +- break; +- case 1: +- case 2: +- case 3: +- INIT_LIST_HEAD(&list); +- +- err = link_sessions(&list, info); +- if (err) +- break; +- print_sessions_tree(db, &list, info_level); +- break; +- default: +- log_error("Invalid info level %d. Try 0 - 3.", info_level); +- return EINVAL; +- } +- +- if (err) +- log_error("Can not get session info (%d)", err); +- return 0; +-} +- +-static int print_sessions(idbm_t *db, int info_level) ++static int print_sessions(int info_level, struct session_info *match_info) + { + struct list_head list; + int num_found = 0, err = 0; +@@ -927,7 +1072,7 @@ static int print_sessions(idbm_t *db, int info_level) + switch (info_level) { + case 0: + case -1: +- err = sysfs_for_each_session(NULL, &num_found, ++ err = sysfs_for_each_session(match_info, &num_found, + print_session_flat); + break; + case 2: +@@ -941,13 +1086,18 @@ static int print_sessions(idbm_t *db, int info_level) /* fall through */ case 1: INIT_LIST_HEAD(&list); - +- err = sysfs_for_each_session(&list, &num_found, ++ struct session_link_info link_info; + - err = sysfs_for_each_session(&list, &num_found, ++ memset(&link_info, 0, sizeof(link_info)); ++ link_info.list = &list; ++ link_info.match_info = match_info; ++ ++ err = sysfs_for_each_session(&link_info, &num_found, link_sessions); if (err || !num_found) -@@ -969,17 +1177,18 @@ static int rescan_portal(void *data, struct session_info *info) + break; + +- print_sessions_tree(db, &list, info_level); ++ print_sessions_tree(&list, info_level); + break; + default: + log_error("Invalid info level %d. Try 0 - 3.", info_level); +@@ -969,17 +1119,18 @@ static int rescan_portal(void *data, struct session_info *info) if (!iscsi_match_session(data, info)) return -1; @@ -12563,7 +17943,7 @@ index 1e706b9..53a848d 100644 scan_host(host_no, 0); return 0; } -@@ -1002,10 +1211,10 @@ session_stats(void *data, struct session_info *info) +@@ -1002,10 +1153,10 @@ session_stats(void *data, struct session_info *info) if (rc) return EIO; @@ -12577,19 +17957,102 @@ index 1e706b9..53a848d 100644 printf( "iSCSI SNMP:\n" -@@ -1098,7 +1307,7 @@ static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt, - strncpy(rec->conn[0].address, ip, NI_MAXHOST); - - if (iface) { -- rc = iface_conf_read(iface); -+ rc = iface_conf_read(db, iface); - if (rc) { - log_error("Could not read iface %s. Error %d", - iface->name, rc); -@@ -1200,16 +1409,47 @@ do_offload_sendtargets(idbm_t *db, discovery_rec_t *drec, - return discovery_offload_sendtargets(db, host_no, do_login, drec); +@@ -1069,7 +1220,7 @@ session_stats(void *data, struct session_info *info) + return 0; } +-static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt, ++static int add_static_rec(int *found, char *targetname, int tpgt, + char *ip, int port, struct iface_rec *iface) + { + node_rec_t *rec; +@@ -1091,7 +1242,7 @@ static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt, + } + drec->type = DISCOVERY_TYPE_STATIC; + +- idbm_node_setup_from_conf(db, rec); ++ idbm_node_setup_from_conf(rec); + strncpy(rec->name, targetname, TARGET_NAME_MAXLEN); + rec->tpgt = tpgt; + rec->conn[0].port = port; +@@ -1108,7 +1259,7 @@ static int add_static_rec(idbm_t *db, int *found, char *targetname, int tpgt, + iface_copy(&rec->iface, iface); + } + +- rc = idbm_add_node(db, rec, drec); ++ rc = idbm_add_node(rec, drec, 1); + if (!rc) { + (*found)++; + printf("New iSCSI node [%s:" iface_fmt " %s,%d,%d %s] added\n", +@@ -1122,7 +1273,7 @@ done: + return rc; + } + +-static int add_static_portal(idbm_t *db, int *found, void *data, ++static int add_static_portal(int *found, void *data, + char *targetname, int tpgt, char *ip, int port) + { + node_rec_t *rec = data; +@@ -1134,11 +1285,11 @@ static int add_static_portal(idbm_t *db, int *found, void *data, + if (rec->conn[0].port != -1 && rec->conn[0].port != port) + return 0; + +- return add_static_rec(db, found, targetname, tpgt, ip, port, ++ return add_static_rec(found, targetname, tpgt, ip, port, + &rec->iface); + } + +-static int add_static_node(idbm_t *db, int *found, void *data, ++static int add_static_node(int *found, void *data, + char *targetname) + { + node_rec_t *rec = data; +@@ -1152,19 +1303,19 @@ static int add_static_node(idbm_t *db, int *found, void *data, + if (!strlen(rec->conn[0].address)) + goto search; + +- return add_static_rec(db, found, targetname, rec->tpgt, ++ return add_static_rec(found, targetname, rec->tpgt, + rec->conn[0].address, + rec->conn[0].port, &rec->iface); + search: +- return idbm_for_each_portal(db, found, data, add_static_portal, ++ return idbm_for_each_portal(found, data, add_static_portal, + targetname); + } + +-static int add_static_recs(idbm_t *db, struct node_rec *rec) ++static int add_static_recs(struct node_rec *rec) + { + int rc, nr_found = 0; + +- rc = idbm_for_each_node(db, &nr_found, rec, add_static_node); ++ rc = idbm_for_each_node(&nr_found, rec, add_static_node); + if (rc) { + log_error("Error while adding records. DB may be in an " + "inconsistent state. Err %d", rc); +@@ -1176,7 +1327,7 @@ static int add_static_recs(idbm_t *db, struct node_rec *rec) + + /* brand new target */ + if (strlen(rec->name) && strlen(rec->conn[0].address)) { +- rc = add_static_rec(db, &nr_found, rec->name, rec->tpgt, ++ rc = add_static_rec(&nr_found, rec->name, rec->tpgt, + rec->conn[0].address, rec->conn[0].port, + &rec->iface); + if (rc) +@@ -1193,29 +1344,193 @@ done: + * particular config + */ + static int +-do_offload_sendtargets(idbm_t *db, discovery_rec_t *drec, +- int host_no, int do_login) ++do_offload_sendtargets(discovery_rec_t *drec, int host_no, int do_login) + { + drec->type = DISCOVERY_TYPE_OFFLOAD_SENDTARGETS; +- return discovery_offload_sendtargets(db, host_no, do_login, drec); ++ return discovery_offload_sendtargets(host_no, do_login, drec); ++} ++ +static int login_discovered_portal(void *data, struct list_head *list, + node_rec_t *rec) +{ @@ -12608,127 +18071,251 @@ index 1e706b9..53a848d 100644 + return 0; +} + - static int - do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec, - struct list_head *ifaces, int info_level, int do_login) - { -- int rc; -+ int rc, err, nr_found = 0; -+ struct list_head rec_list; ++/* TODO merge with initiator.c implementation */ ++/* And add locking */ ++static int check_for_session_through_iface(struct node_rec *rec) ++{ ++ int nr_found = 0; ++ if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) ++ return 1; ++ return 0; ++} ++ ++static int delete_node(void *data, struct node_rec *rec) ++{ ++ if (check_for_session_through_iface(rec)) { ++ /* ++ * We could log out the session for the user, but if ++ * the session is being used the user may get something ++ * they were not expecting (FS errors and a read only ++ * remount). ++ */ ++ log_error("This command will remove the record [iface: %s, " ++ "target: %s, portal: %s,%d], but a session is " ++ "using it. Logout session then rerun command to " ++ "remove record.", rec->iface.name, rec->name, ++ rec->conn[0].address, rec->conn[0].port); ++ return EINVAL; ++ } ++ ++ return idbm_delete_node(rec); ++} ++ ++static int delete_stale_recs(void *data, struct node_rec *rec) ++{ ++ struct list_head *new_rec_list = data; ++ struct node_rec *new_rec; ++ ++ list_for_each_entry(new_rec, new_rec_list, list) { ++ /* ++ * We could also move this to idbm.c and instead of looping ++ * over every node just loop over disc to node links. ++ */ ++ if (rec->disc_type != new_rec->disc_type || ++ rec->disc_port != new_rec->disc_port || ++ strcmp(rec->disc_address, new_rec->disc_address)) ++ /* ++ * if we are not from the same discovery source ++ * ignore it ++ */ ++ return 0; ++ ++ if (__iscsi_match_session(rec, ++ new_rec->name, ++ new_rec->conn[0].address, ++ new_rec->conn[0].port, ++ &new_rec->iface)) ++ return 0; ++ } ++ /* if there is a error we can continue on */ ++ delete_node(NULL, rec); ++ return 0; + } - drec->type = DISCOVERY_TYPE_SENDTARGETS; - rc = discovery_sendtargets(db, drec, ifaces); -- if (!rc) -- idbm_print_discovered(db, drec, info_level); -+ if (rc) -+ return rc; + static int +-do_sofware_sendtargets(idbm_t *db, discovery_rec_t *drec, +- struct list_head *ifaces, int info_level, int do_login) ++update_discovery_recs(discovery_rec_t *drec, ++ struct list_head *new_rec_list, struct list_head *ifaces, ++ int info_level, int do_login, int op) + { ++ int rc, err, found = 0; ++ struct list_head bound_rec_list; ++ struct node_rec *new_rec, *tmp; + -+ idbm_print_discovered(db, drec, info_level); ++ INIT_LIST_HEAD(&bound_rec_list); ++ ++ /* bind ifaces to node recs so we know what we have */ ++ list_for_each_entry(new_rec, new_rec_list, list) { ++ rc = idbm_bind_ifaces_to_node(new_rec, ifaces, ++ &bound_rec_list); ++ if (rc) ++ goto free_bound_recs; ++ } + -+ if (!do_login) -+ return 0; + -+ INIT_LIST_HEAD(&rec_list); -+ rc = idbm_for_each_rec(db, &nr_found, &rec_list, link_recs); -+ err = __login_portals(drec, &nr_found, &rec_list, ++ /* clean up node db */ ++ if (op & OP_DELETE) ++ idbm_for_each_rec(&found, &bound_rec_list, ++ delete_stale_recs); ++ ++ if (op & OP_NEW || op & OP_UPDATE) { ++ /* now add/update records */ ++ list_for_each_entry(new_rec, &bound_rec_list, list) { ++ rc = idbm_add_node(new_rec, drec, op & OP_UPDATE); ++ if (rc) ++ log_error("Could not add/update " ++ "[%s:" iface_fmt " %s,%d,%d %s]", ++ new_rec->iface.transport_name, ++ iface_str(&new_rec->iface), ++ new_rec->conn[0].address, ++ new_rec->conn[0].port, ++ new_rec->tpgt, new_rec->name); ++ } ++ } ++ ++ idbm_print_discovered(drec, info_level); ++ ++ if (!do_login) { ++ rc = 0; ++ goto free_bound_recs; ++ } ++ ++ err = __login_portals(drec, &found, &bound_rec_list, + login_discovered_portal); + if (err && !rc) + rc = err; ++ ++free_bound_recs: ++ list_for_each_entry_safe(new_rec, tmp, &bound_rec_list, list) { ++ list_del(&new_rec->list); ++ free(new_rec); ++ } ++ return rc; ++} ++ ++static int ++do_sofware_sendtargets(discovery_rec_t *drec, struct list_head *ifaces, ++ int info_level, int do_login, ++ int op) ++{ ++ struct list_head new_rec_list; ++ struct node_rec *new_rec, *tmp; + int rc; + ++ INIT_LIST_HEAD(&new_rec_list); ++ /* ++ * compat: if the user did not pass any op then we do all ++ * ops for them ++ */ ++ if (!op) ++ op = OP_NEW | OP_DELETE | OP_UPDATE; ++ + drec->type = DISCOVERY_TYPE_SENDTARGETS; +- rc = discovery_sendtargets(db, drec, ifaces); +- if (!rc) +- idbm_print_discovered(db, drec, info_level); ++ rc = discovery_sendtargets(drec, &new_rec_list); ++ if (rc) ++ return rc; ++ ++ rc = idbm_add_discovery(drec, op & OP_UPDATE); ++ if (rc) { ++ log_error("Could not add new discovery record."); ++ goto free_new_recs; ++ } ++ ++ rc = update_discovery_recs(drec, &new_rec_list, ifaces, ++ info_level, do_login, op); ++ ++free_new_recs: ++ list_for_each_entry_safe(new_rec, tmp, &new_rec_list, list) { ++ list_del(&new_rec->list); ++ free(new_rec); ++ } return rc; } -@@ -1228,7 +1468,7 @@ do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, + static int +-do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, +- int info_level, int do_login) ++do_sendtargets(discovery_rec_t *drec, struct list_head *ifaces, ++ int info_level, int do_login, int op) + { + struct iface_rec *tmp, *iface; + int rc, host_no; +@@ -1239,10 +1554,6 @@ do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, + continue; + } - /* we allow users to mix hw and sw iscsi so we have to sort it out */ - list_for_each_entry_safe(iface, tmp, ifaces, list) { -- rc = iface_conf_read(iface); -+ rc = iface_conf_read(db, iface); - if (rc) { - log_error("Could not read iface info for %s. " - "Make sure a iface config with the file " -@@ -1278,6 +1518,69 @@ sw_st: - return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login); +- /* if no binding it must be software */ +- if (!iface_is_bound(iface)) +- continue; +- + host_no = get_host_no_from_iface(iface, &rc); + if (rc || host_no == -1) { + log_debug(1, "Could not match iface" iface_fmt " to " +@@ -1264,8 +1575,7 @@ do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, + } + + if (t->caps & CAP_SENDTARGETS_OFFLOAD) { +- do_offload_sendtargets(db, drec, host_no, +- do_login); ++ do_offload_sendtargets(drec, host_no, do_login); + list_del(&iface->list); + free(iface); + } +@@ -1275,10 +1585,27 @@ do_sendtargets(idbm_t *db, discovery_rec_t *drec, struct list_head *ifaces, + return ENODEV; + + sw_st: +- return do_sofware_sendtargets(db, drec, ifaces, info_level, do_login); ++ return do_sofware_sendtargets(drec, ifaces, info_level, do_login, ++ op); } +-static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec, +/* TODO: merge this with the idbm code */ +static void print_fw_nodes(struct node_rec *rec, int info_level) +{ + switch (info_level) { + case -1: + case 0: -+ idbm_print_node_flat(NULL, NULL, rec); ++ idbm_print_node_flat(NULL, rec); + break; + case 1: -+ idbm_print_node_tree(NULL, NULL, rec); ++ idbm_print_node_tree(NULL, rec); + break; + default: + log_error("Invalid print level %d. Try 0 or 1.", info_level); + } +} + -+static int do_fw_discovery(idbm_t *db, discovery_rec_t *drec, int do_login, -+ int info_level) -+{ -+ struct boot_context context; -+ struct node_rec *rec; -+ int ret; -+ -+ memset(&context, 0, sizeof(struct boot_context)); -+ ret = fw_get_entry(&context, NULL); -+ if (ret) { -+ log_error("Could not read fw values."); -+ return ret; -+ } -+ /* tpgt hard coded to 1 */ -+ rec = create_node_record(db, context.targetname, 1, -+ context.target_ipaddr, context.target_port, -+ NULL, 1); -+ if (!rec) { -+ log_error("Could not setup rec for fw discovery login."); -+ return ENOMEM; -+ } -+ -+ /* todo - grab mac and set that here */ -+ iface_init(&rec->iface); -+ strncpy(rec->iface.iname, context.initiatorname, -+ sizeof(context.initiatorname)); -+ strncpy(rec->session.auth.username, context.chap_name, -+ sizeof(context.chap_name)); -+ strncpy((char *)rec->session.auth.password, context.chap_password, -+ sizeof(context.chap_password)); -+ strncpy(rec->session.auth.username_in, context.chap_name_in, -+ sizeof(context.chap_name_in)); -+ strncpy((char *)rec->session.auth.password_in, context.chap_password_in, -+ sizeof(context.chap_password_in)); -+ rec->session.auth.password_length = -+ strlen((char *)context.chap_password); -+ rec->session.auth.password_in_length = -+ strlen((char *)context.chap_password_in); -+ -+ print_fw_nodes(rec, info_level); -+ if (do_login) -+ ret = login_portal(db, NULL, rec); -+ free(rec); -+ return ret; -+} -+ -+ - static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec, ++static int isns_dev_attr_query(discovery_rec_t *drec, int info_level) { -@@ -1324,6 +1627,8 @@ static void catch_sigint( int signo ) { + iscsiadm_req_t req; +@@ -1293,7 +1620,7 @@ static int isns_dev_attr_query(idbm_t *db, discovery_rec_t *drec, + iscsid_handle_error(err); + return EIO; + } else { +- idbm_print_discovered(db, drec, info_level); ++ idbm_print_discovered(drec, info_level); + return 0; + } + } +@@ -1324,36 +1651,8 @@ static void catch_sigint( int signo ) { exit(1); } -+/* TODO merge with initiator.c implementation */ -+/* And add locking */ - static int check_for_session_through_iface(struct node_rec *rec) - { - int nr_found = 0; -@@ -1332,27 +1637,6 @@ static int check_for_session_through_iface(struct node_rec *rec) - return 0; - } - +-static int check_for_session_through_iface(struct node_rec *rec) +-{ +- int nr_found = 0; +- if (sysfs_for_each_session(rec, &nr_found, iscsi_match_session)) +- return 1; +- return 0; +-} +- -static struct node_rec *setup_rec_from_iface(struct iface_rec *iface) -{ - struct node_rec *rec; @@ -12750,35 +18337,40 @@ index 1e706b9..53a848d 100644 - return rec; -} - - static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, +-static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, ++/* TODO: merge iter helpers and clean them up, so we can use them here */ ++static int exec_iface_op(int op, int do_show, int info_level, struct iface_rec *iface, char *name, char *value) { -@@ -1368,8 +1652,8 @@ static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, + struct db_set_param set_param; +@@ -1368,16 +1667,13 @@ static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, return EINVAL; } - rec = setup_rec_from_iface(iface); - if (rec) { -+ rec = create_node_record(db, NULL, -1, NULL, -1, iface, 0); -+ if (rec && iface_is_bound(&rec->iface)) { - if (check_for_session_through_iface(rec)) { - rc = EBUSY; - goto new_fail; -@@ -1378,7 +1662,7 @@ static int exec_iface_op(idbm_t *db, int op, int do_show, int info_level, +- if (check_for_session_through_iface(rec)) { +- rc = EBUSY; +- goto new_fail; +- } +- log_warning("Overwriting existing %s.", iface->name); ++ rec = create_node_record(NULL, -1, NULL, -1, iface, 0); ++ if (rec && check_for_session_through_iface(rec)) { ++ rc = EBUSY; ++ goto new_fail; } - iface_init(iface); -- rc = iface_conf_write(iface); -+ rc = iface_conf_write(db, iface); +- iface_init(iface); ++ iface_setup_defaults(iface); + rc = iface_conf_write(iface); if (rc) goto new_fail; - printf("New interface %s added\n", iface->name); -@@ -1393,23 +1677,25 @@ new_fail: +@@ -1393,19 +1689,14 @@ new_fail: return EINVAL; } - rec = setup_rec_from_iface(iface); -+ rec = create_node_record(db, NULL, -1, NULL, -1, iface, 1); ++ rec = create_node_record(NULL, -1, NULL, -1, iface, 1); if (!rec) { rc = EINVAL; goto delete_fail; @@ -12788,128 +18380,151 @@ index 1e706b9..53a848d 100644 - rc = EBUSY; - goto delete_fail; - } -+ if (iface_is_bound(&rec->iface)) { -+ if (check_for_session_through_iface(rec)) { -+ rc = EBUSY; -+ goto delete_fail; -+ } - +- - /* delete node records using it first */ - rc = __for_each_rec(db, 0, rec, NULL, idbm_delete_node); -- if (rc && rc != ENODEV) -- goto delete_fail; -+ /* delete node records using it first */ -+ rc = __for_each_rec(db, 0, rec, NULL, idbm_delete_node); -+ if (rc && rc != ENODEV) -+ goto delete_fail; -+ } - -- rc = iface_conf_delete(iface); -+ rc = iface_conf_delete(db, iface); - if (rc) ++ /* logout and delete records using it first */ ++ rc = __for_each_rec(0, rec, NULL, delete_node); + if (rc && rc != ENODEV) goto delete_fail; -@@ -1427,58 +1713,60 @@ delete_fail: +@@ -1427,7 +1718,7 @@ delete_fail: break; } - rec = setup_rec_from_iface(iface); -+ rec = create_node_record(db, NULL, -1, NULL, -1, iface, 1); ++ rec = create_node_record(NULL, -1, NULL, -1, iface, 1); if (!rec) { rc = EINVAL; goto update_fail; +@@ -1439,46 +1730,44 @@ delete_fail: } -- if (check_for_session_through_iface(rec)) { -- rc = EINVAL; -- goto update_fail; -- } -+ if (iface_is_bound(&rec->iface)) { -+ if (check_for_session_through_iface(rec)) { -+ rc = EINVAL; -+ goto update_fail; -+ } - -- if (!strcmp(name, "iface.iscsi_ifacename")) { + if (!strcmp(name, "iface.iscsi_ifacename")) { - log_error("Can not update iface.iscsi_ifacename. " - "Delete it, and then create a new one."); -- rc = EINVAL; -- break; -- } -+ if (!strcmp(name, "iface.iscsi_ifacename")) { -+ log_error("Can not update " -+ "iface.iscsi_ifacename. Delete it, " -+ "and then create a new one."); -+ rc = EINVAL; -+ break; -+ } ++ log_error("Can not update " ++ "iface.iscsi_ifacename. Delete it, " ++ "and then create a new one."); + rc = EINVAL; + break; + } -- if (iface_is_bound_by_hwaddr(&rec->iface) && -- !strcmp(name, "iface.net_ifacename")) { + if (iface_is_bound_by_hwaddr(&rec->iface) && + !strcmp(name, "iface.net_ifacename")) { - log_error("Can not update interface binding from " - "hwaddress to net_ifacename. "); - log_error("You must delete the interface and create " - "a new one"); -- rc = EINVAL; -- break; -- } -+ if (iface_is_bound_by_hwaddr(&rec->iface) && -+ !strcmp(name, "iface.net_ifacename")) { -+ log_error("Can not update interface binding " -+ "from hwaddress to net_ifacename. "); -+ log_error("You must delete the interface and " -+ "create a new one"); -+ rc = EINVAL; -+ break; -+ } ++ log_error("Can not update interface binding " ++ "from hwaddress to net_ifacename. "); ++ log_error("You must delete the interface and " ++ "create a new one"); + rc = EINVAL; + break; + } -- if (iface_is_bound_by_netdev(&rec->iface) && -- !strcmp(name, "iface.hwaddress")) { + if (iface_is_bound_by_netdev(&rec->iface) && + !strcmp(name, "iface.hwaddress")) { - log_error("Can not update interface binding from " - "net_ifacename to hwaddress. "); - log_error("You must delete the interface and create " - "a new one"); -- rc = EINVAL; -- break; -+ if (iface_is_bound_by_netdev(&rec->iface) && -+ !strcmp(name, "iface.hwaddress")) { -+ log_error("Can not update interface binding " -+ "from net_ifacename to hwaddress. "); -+ log_error("You must delete the interface and " -+ "create a new one"); -+ rc = EINVAL; -+ break; -+ } ++ log_error("Can not update interface binding " ++ "from net_ifacename to hwaddress. "); ++ log_error("You must delete the interface and " ++ "create a new one"); + rc = EINVAL; + break; } - - set_param.db = db; +- set_param.db = db; set_param.name = name; set_param.value = value; -+ /* pass rec's iface because it has the db values */ -+ rc = iface_conf_update(db, &set_param, &rec->iface); -+ if (rc) -+ goto update_fail; -+ - rc = __for_each_rec(db, 0, rec, &set_param, - idbm_node_set_param); - if (rc && rc != ENODEV) - goto update_fail; - -- /* pass rec's iface because it has the db values */ -- rc = iface_conf_update(&set_param, &rec->iface); -- if (rc) +- rc = __for_each_rec(db, 0, rec, &set_param, +- idbm_node_set_param); +- if (rc && rc != ENODEV) - goto update_fail; - + /* pass rec's iface because it has the db values */ + rc = iface_conf_update(&set_param, &rec->iface); + if (rc) + goto update_fail; + ++ rc = __for_each_rec(0, rec, &set_param, idbm_node_set_param); ++ if (rc && rc != ENODEV) ++ goto update_fail; ++ printf("%s updated.\n", iface->name); break; update_fail: -@@ -1551,13 +1839,13 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout, +@@ -1487,10 +1776,19 @@ update_fail: + iface->name); + break; + default: +- if (op < 0 || op == OP_SHOW) +- rc = print_ifaces(db, info_level); +- else +- rc = EINVAL; ++ if (!iface) { ++ if (op == OP_NOOP || op == OP_SHOW) ++ rc = print_ifaces(info_level); ++ else ++ rc = EINVAL; ++ } else { ++ rc = iface_conf_read(iface); ++ if (!rc) ++ idbm_print_iface_info(&do_show, iface); ++ else ++ log_error("Could not read iface %s (%d).", ++ iface->name, rc); ++ } + } + + if (rec) +@@ -1499,7 +1797,7 @@ update_fail: + } + + /* TODO cleanup arguments */ +-static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout, ++static int exec_node_op(int op, int do_login, int do_logout, + int do_show, int do_rescan, int do_stats, + int info_level, struct node_rec *rec, + char *name, char *value) +@@ -1513,7 +1811,7 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout, + rec->name, rec->conn[0].address, rec->conn[0].port); + + if (op == OP_NEW) { +- if (add_static_recs(db, rec)) ++ if (add_static_recs(rec)) + rc = -1; + goto out; + } +@@ -1536,34 +1834,34 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout, + goto out; + } + +- if ((do_login || do_logout) && op >= 0) { ++ if ((do_login || do_logout) && op > OP_NOOP) { + log_error("either operation or login/logout " + "at the time allowed!"); + rc = -1; + goto out; + } + +- if ((!do_login && !do_logout && op < 0) && ++ if ((!do_login && !do_logout && op == OP_NOOP) && + (!strlen(rec->name) && !strlen(rec->conn[0].address) && + !strlen(rec->iface.name))) { +- rc = print_nodes(db, info_level, rec); ++ rc = print_nodes(info_level, rec); + goto out; } if (do_login) { - if (for_each_rec(db, rec, NULL, login_portal)) -+ if (login_portals(db, rec)) ++ if (login_portals(rec)) rc = -1; goto out; } @@ -12920,14 +18535,82 @@ index 1e706b9..53a848d 100644 rc = -1; goto out; } -@@ -1595,6 +1883,22 @@ out: + +- if (op < 0 || (!do_login && !do_logout && op == OP_SHOW)) { +- if (for_each_rec(db, rec, &do_show, idbm_print_node_info)) ++ if (op == OP_NOOP || (!do_login && !do_logout && op == OP_SHOW)) { ++ if (for_each_rec(rec, &do_show, idbm_print_node_info)) + rc = -1; + goto out; + } +@@ -1575,15 +1873,21 @@ static int exec_node_op(idbm_t *db, int op, int do_login, int do_logout, + goto out; + } + +- set_param.db = db; ++ if (!strncmp(name, "iface.", 6)) { ++ log_error("Cannot modify %s. Use iface mode to update " ++ "this value.", name); ++ rc = -1; ++ goto out; ++ } ++ + set_param.name = name; + set_param.value = value; + +- if (for_each_rec(db, rec, &set_param, idbm_node_set_param)) ++ if (for_each_rec(rec, &set_param, idbm_node_set_param)) + rc = -1; + goto out; + } else if (op == OP_DELETE) { +- if (for_each_rec(db, rec, NULL, idbm_delete_node)) ++ if (for_each_rec(rec, NULL, delete_node)) + rc = -1; + goto out; + } else { +@@ -1595,6 +1899,71 @@ out: return rc; } -+static int exec_fw_op(void) ++static struct node_rec * ++fw_create_rec_by_entry(struct boot_context *context) ++{ ++ struct node_rec *rec; ++ ++ /* tpgt hard coded to 1 ??? */ ++ rec = create_node_record(context->targetname, 1, ++ context->target_ipaddr, context->target_port, ++ NULL, 1); ++ if (!rec) { ++ log_error("Could not setup rec for fw discovery login."); ++ return NULL; ++ } ++ ++ /* todo - grab mac and set that here */ ++ iface_setup_defaults(&rec->iface); ++ strncpy(rec->iface.iname, context->initiatorname, ++ sizeof(context->initiatorname)); ++ strncpy(rec->session.auth.username, context->chap_name, ++ sizeof(context->chap_name)); ++ strncpy((char *)rec->session.auth.password, context->chap_password, ++ sizeof(context->chap_password)); ++ strncpy(rec->session.auth.username_in, context->chap_name_in, ++ sizeof(context->chap_name_in)); ++ strncpy((char *)rec->session.auth.password_in, ++ context->chap_password_in, ++ sizeof(context->chap_password_in)); ++ rec->session.auth.password_length = ++ strlen((char *)context->chap_password); ++ rec->session.auth.password_in_length = ++ strlen((char *)context->chap_password_in); ++ return rec; ++} ++ ++static int exec_fw_op(discovery_rec_t *drec, int do_login, int info_level) +{ + struct boot_context context; -+ int ret; ++ struct node_rec *rec; ++ int ret = 0; + + memset(&context, 0, sizeof(struct boot_context)); + ret = fw_get_entry(&context, NULL); @@ -12936,25 +18619,41 @@ index 1e706b9..53a848d 100644 + return ret; + } + -+ fw_print_entry(&context); -+ return 0; ++ rec = fw_create_rec_by_entry(&context); ++ if (!rec) ++ return ENODEV; ++ ++ /* if discovery, print nodes that were found. */ ++ if (drec) ++ print_fw_nodes(rec, info_level); ++ ++ if (do_login) ++ ret = login_portal(NULL, NULL, rec); ++ free(rec); ++ ++ /* print the fw node info if called in fw mode with no params */ ++ if (!do_login && !drec) ++ fw_print_entry(&context); ++ return ret; +} + static int parse_sid(char *session) { struct stat statb; -@@ -1653,8 +1957,8 @@ main(int argc, char **argv) +@@ -1651,10 +2020,9 @@ main(int argc, char **argv) + char *ip = NULL, *name = NULL, *value = NULL; + char *targetname = NULL, *group_session_mgmt_mode = NULL; int ch, longindex, mode=-1, port=-1, do_login=0, do_rescan=0; - int rc=0, sid=-1, op=-1, type=-1, do_logout=0, do_stats=0, do_show=0; +- int rc=0, sid=-1, op=-1, type=-1, do_logout=0, do_stats=0, do_show=0; ++ int rc=0, sid=-1, op=OP_NOOP, type=-1, do_logout=0, do_stats=0; int do_login_all=0, do_logout_all=0, info_level=-1, num_ifaces = 0; - int tpgt = PORTAL_GROUP_TAG_UNKNOWN; - idbm_t *db; -+ int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1; -+ idbm_t *db = NULL; ++ int tpgt = PORTAL_GROUP_TAG_UNKNOWN, killiscsid=-1, do_show=0; struct sigaction sa_old; struct sigaction sa_new; discovery_rec_t drec; -@@ -1664,6 +1968,9 @@ main(int argc, char **argv) +@@ -1664,6 +2032,9 @@ main(int argc, char **argv) INIT_LIST_HEAD(&ifaces); /* do not allow ctrl-c for now... */ @@ -12964,7 +18663,7 @@ index 1e706b9..53a848d 100644 sa_new.sa_handler = catch_sigint; sigemptyset(&sa_new.sa_mask); sa_new.sa_flags = 0; -@@ -1679,6 +1986,15 @@ main(int argc, char **argv) +@@ -1679,12 +2050,21 @@ main(int argc, char **argv) while ((ch = getopt_long(argc, argv, short_options, long_options, &longindex)) >= 0) { switch (ch) { @@ -12980,7 +18679,15 @@ index 1e706b9..53a848d 100644 case 't': type = str_to_type(optarg); break; -@@ -1773,16 +2089,28 @@ main(int argc, char **argv) + case 'o': +- op = str_to_op(optarg); +- if (op < 0) { ++ op |= str_to_op(optarg); ++ if (op == OP_NOOP) { + log_error("can not recognize operation: '%s'", + optarg); + return -1; +@@ -1773,22 +2153,33 @@ main(int argc, char **argv) return -1; } @@ -12997,46 +18704,183 @@ index 1e706b9..53a848d 100644 - log_warning("exiting due to configuration error"); - return -1; + if (mode == MODE_FW) { -+ if ((rc = verify_mode_params(argc, argv, "m", 0))) { ++ if ((rc = verify_mode_params(argc, argv, "ml", 0))) { + log_error("fw mode: option '-%c' is not " + "allowed/supported", rc); + rc = -1; + goto out; + } + -+ rc = exec_fw_op(); ++ rc = exec_fw_op(NULL, do_login, info_level); + goto out; } - db = idbm_init(config_file); +- if (!db) { + increase_max_files(); -+ db = idbm_init(get_config_file); - if (!db) { ++ if (idbm_init(get_config_file)) { log_warning("exiting due to idbm configuration error"); return -1; -@@ -1848,6 +2176,11 @@ main(int argc, char **argv) - if (isns_dev_attr_query(db, &drec, info_level)) + } + +- iface_setup_host_bindings(db); ++ iface_setup_host_bindings(); + + switch (mode) { + case MODE_IFACE: +@@ -1807,7 +2198,7 @@ main(int argc, char **argv) + "interface. Using the first one " + "%s.", iface->name); + } +- rc = exec_iface_op(db, op, do_show, info_level, iface, ++ rc = exec_iface_op(op, do_show, info_level, iface, + name, value); + break; + case MODE_DISCOVERY: +@@ -1827,12 +2218,12 @@ main(int argc, char **argv) + } + + memset(&drec, 0, sizeof(discovery_rec_t)); +- idbm_sendtargets_defaults(db, &drec.u.sendtargets); ++ idbm_sendtargets_defaults(&drec.u.sendtargets); + strncpy(drec.address, ip, sizeof(drec.address)); + drec.port = port; + +- if (do_sendtargets(db, &drec, &ifaces, info_level, +- do_login)) { ++ if (do_sendtargets(&drec, &ifaces, info_level, ++ do_login, op)) { rc = -1; - break; -+ case DISCOVERY_TYPE_FWBOOT: -+ drec.type = DISCOVERY_TYPE_FWBOOT; -+ if (do_fw_discovery(db, &drec, do_login, info_level)) + goto out; + } +@@ -1845,12 +2236,17 @@ main(int argc, char **argv) + case DISCOVERY_TYPE_ISNS: + drec.type = DISCOVERY_TYPE_ISNS; + +- if (isns_dev_attr_query(db, &drec, info_level)) ++ if (isns_dev_attr_query(&drec, info_level)) + rc = -1; + break; ++ case DISCOVERY_TYPE_FWBOOT: ++ drec.type = DISCOVERY_TYPE_FWBOOT; ++ if (exec_fw_op(&drec, do_login, info_level)) + rc = -1; + break; default: if (ip) { - if (idbm_discovery_read(db, &drec, ip, port)) { -@@ -1938,7 +2271,8 @@ main(int argc, char **argv) +- if (idbm_discovery_read(db, &drec, ip, port)) { ++ if (idbm_discovery_read(&drec, ip, port)) { + log_error("discovery record [%s,%d] " + "not found!", ip, port); + rc = -1; +@@ -1858,8 +2254,9 @@ main(int argc, char **argv) + } + if (do_login && + drec.type == DISCOVERY_TYPE_SENDTARGETS) { +- do_sendtargets(db, &drec, &ifaces, +- info_level, do_login); ++ do_sendtargets(&drec, &ifaces, ++ info_level, do_login, ++ op); + } else if (do_login && + drec.type == DISCOVERY_TYPE_SLP) { + log_error("SLP discovery is not fully " +@@ -1872,14 +2269,14 @@ main(int argc, char **argv) + "implemented yet."); + rc = -1; + goto out; +- } else if (op < 0 || op == OP_SHOW) { +- if (!idbm_print_discovery_info(db, +- &drec, do_show)) { ++ } else if (op == OP_NOOP || op == OP_SHOW) { ++ if (!idbm_print_discovery_info(&drec, ++ do_show)) { + log_error("no records found!"); + rc = -1; + } + } else if (op == OP_DELETE) { +- if (idbm_delete_discovery(db, &drec)) { ++ if (idbm_delete_discovery(&drec)) { + log_error("unable to delete " + "record!"); + rc = -1; +@@ -1890,8 +2287,8 @@ main(int argc, char **argv) + goto out; + } + +- } else if (op < 0 || op == OP_SHOW) { +- if (!idbm_print_all_discovery(db, info_level)) ++ } else if (op == OP_NOOP || op == OP_SHOW) { ++ if (!idbm_print_all_discovery(info_level)) + rc = -1; + goto out; + } else if (op == OP_DELETE) { +@@ -1918,12 +2315,12 @@ main(int argc, char **argv) + } + + if (do_login_all) { +- rc = login_by_startup(db, group_session_mgmt_mode); ++ rc = login_by_startup(group_session_mgmt_mode); + goto out; + } + + if (do_logout_all) { +- rc = logout_by_startup(db, group_session_mgmt_mode); ++ rc = logout_by_startup(group_session_mgmt_mode); + goto out; + } + +@@ -1938,13 +2335,13 @@ main(int argc, char **argv) iface->hwaddress, iface->ipaddress); } - rec = create_node_record(db, targetname, tpgt, ip, port, iface); -+ rec = create_node_record(db, targetname, tpgt, ip, port, -+ iface, 1); ++ rec = create_node_record(targetname, tpgt, ip, port, iface, 1); if (!rec) { rc = -1; goto out; -@@ -1993,7 +2327,7 @@ main(int argc, char **argv) + } + +- rc = exec_node_op(db, op, do_login, do_logout, do_show, ++ rc = exec_node_op(op, do_login, do_logout, do_show, + do_rescan, do_stats, info_level, rec, + name, value); + break; +@@ -1958,7 +2355,6 @@ main(int argc, char **argv) + } + if (sid >= 0) { + char session[64]; +- struct iscsi_transport *t; + struct session_info *info; + + snprintf(session, 63, "session%d", sid); +@@ -1977,30 +2373,34 @@ main(int argc, char **argv) + goto free_info; + } + +- t = get_transport_by_sid(sid); +- if (!t) ++ /* ++ * We should be able to go on, but for now ++ * we only support session mode ops if the module ++ * is loaded and we support that module. ++ */ ++ if (!get_transport_by_sid(sid)) + goto free_info; + +- if (!do_logout && !do_rescan && !do_stats && op < 0 && +- info_level > 0) { +- rc = print_session(db, info_level, info); ++ if (!do_logout && !do_rescan && !do_stats && ++ op == OP_NOOP && info_level > 0) { ++ rc = print_sessions(info_level, info); + if (rc) + rc = -1; + goto free_info; + } + +- rec = create_node_record(db, info->targetname, ++ rec = create_node_record(info->targetname, info->tpgt, info->persistent_address, info->persistent_port, @@ -13045,11 +18889,44 @@ index 1e706b9..53a848d 100644 if (!rec) { rc = -1; goto free_info; + } + + /* drop down to node ops */ +- rc = exec_node_op(db, op, do_login, do_logout, do_show, ++ rc = exec_node_op(op, do_login, do_logout, do_show, + do_rescan, do_stats, info_level, + rec, name, value); + free_info: +@@ -2008,13 +2408,13 @@ free_info: + goto out; + } else { + if (do_logout || do_rescan || do_stats) { +- rc = exec_node_op(db, op, do_login, do_logout, ++ rc = exec_node_op(op, do_login, do_logout, + do_show, do_rescan, do_stats, + info_level, NULL, name, value); + goto out; + } + +- rc = print_sessions(db, info_level); ++ rc = print_sessions(info_level, NULL); + } + break; + default: +@@ -2025,7 +2425,7 @@ free_info: + out: + if (rec) + free(rec); +- idbm_terminate(db); ++ idbm_terminate(); + free_ifaces: + list_for_each_entry_safe(iface, tmp, &ifaces, list) { + list_del(&iface->list); diff --git a/usr/iscsiadm.h b/usr/iscsiadm.h -index 7a7278a..f707984 100644 +index 7a7278a..b9302ab 100644 --- a/usr/iscsiadm.h +++ b/usr/iscsiadm.h -@@ -23,9 +23,6 @@ +@@ -23,17 +23,12 @@ #include "strings.h" #include "config.h" @@ -13057,16 +18934,22 @@ index 7a7278a..f707984 100644 -extern char initiator_alias[]; - /* discovery.c */ - struct idbm; +-struct idbm; struct discovery_rec; -@@ -35,5 +32,4 @@ extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec, - struct list_head *ifaces); - extern int discovery_offload_sendtargets(struct idbm *db, int host_no, - int do_login, discovery_rec_t *drec); + struct list_head; + +-extern int discovery_sendtargets(struct idbm *db, struct discovery_rec *drec, +- struct list_head *ifaces); +-extern int discovery_offload_sendtargets(struct idbm *db, int host_no, +- int do_login, discovery_rec_t *drec); - ++extern int discovery_sendtargets(struct discovery_rec *drec, ++ struct list_head *rec_list); ++extern int discovery_offload_sendtargets(int host_no, int do_login, ++ discovery_rec_t *drec); #endif /* ISCSIADM_H */ diff --git a/usr/iscsid.c b/usr/iscsid.c -index 35ceaef..e7f0cc1 100644 +index 35ceaef..68d78cc 100644 --- a/usr/iscsid.c +++ b/usr/iscsid.c @@ -19,7 +19,6 @@ @@ -13091,15 +18974,82 @@ index 35ceaef..e7f0cc1 100644 #include "iscsid.h" #include "mgmt_ipc.h" -@@ -46,7 +40,6 @@ +@@ -46,7 +40,7 @@ #include "idbm.h" #include "version.h" #include "iscsi_sysfs.h" -#include "iscsi_settings.h" ++#include "iface.h" /* global config info */ struct iscsi_daemon_config daemon_config; -@@ -231,6 +224,12 @@ static int sync_session(void *data, struct session_info *info) +@@ -95,14 +89,13 @@ Open-iSCSI initiator daemon.\n\ + } + + static void +-setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec, +- struct session_info *info) ++setup_rec_from_negotiated_values(node_rec_t *rec, struct session_info *info) + { + struct iscsi_session_operational_config session_conf; + struct iscsi_conn_operational_config conn_conf; + struct iscsi_auth_config auth_conf; + +- idbm_node_setup_from_conf(db, rec); ++ idbm_node_setup_from_conf(rec); + strncpy(rec->name, info->targetname, TARGET_NAME_MAXLEN); + rec->conn[0].port = info->persistent_port; + strncpy(rec->conn[0].address, info->persistent_address, NI_MAXHOST); +@@ -183,8 +176,7 @@ setup_rec_from_negotiated_values(idbm_t *db, node_rec_t *rec, + + static int sync_session(void *data, struct session_info *info) + { +- idbm_t *db = data; +- node_rec_t rec; ++ node_rec_t rec, sysfsrec; + iscsiadm_req_t req; + iscsiadm_rsp_t rsp; + struct iscsi_transport *t; +@@ -216,21 +208,44 @@ static int sync_session(void *data, struct session_info *info) + } + + memset(&rec, 0, sizeof(node_rec_t)); +- if (iface_get_by_bind_info(db, &info->iface, &rec.iface)) { +- log_warning("Could not read data from db. Using default and " +- "currently negotiated values\n"); +- setup_rec_from_negotiated_values(db, &rec, info); +- } else if (idbm_rec_read(db, &rec, info->targetname, info->tpgt, ++ if (idbm_rec_read(&rec, info->targetname, info->tpgt, + info->persistent_address, info->persistent_port, +- &rec.iface)) { ++ &info->iface)) { + log_warning("Could not read data from db. Using default and " + "currently negotiated values\n"); +- setup_rec_from_negotiated_values(db, &rec, info); ++ setup_rec_from_negotiated_values(&rec, info); ++ } else { ++ /* ++ * we have a valid record and iface so lets merge ++ * the values from them and sysfs to try and get ++ * the most uptodate values. ++ * ++ * Currenlty that means we will use the CHAP, target and ++ * and portal values from sysfs and use timer, queue depth, ++ * and segment length values from the record. In the future ++ * when boot supports iface binding we will want to use ++ * those values from sysfs. ++ */ ++ memset(&sysfsrec, 0, sizeof(node_rec_t)); ++ setup_rec_from_negotiated_values(&sysfsrec, info); ++ /* ++ * target and portal values have to be the same or ++ * we would not have found the record, so just copy ++ * CHAP. ++ */ ++ memcpy(&rec.session.auth, &sysfsrec.session.auth, ++ sizeof(struct iscsi_auth_config)); + } + /* multiple drivers could be connected to the same portal */ if (!iscsi_match_session(&rec, info)) return -1; @@ -13112,7 +19062,7 @@ index 35ceaef..e7f0cc1 100644 memset(&req, 0, sizeof(req)); req.command = MGMT_IPC_SESSION_SYNC; -@@ -241,33 +240,70 @@ static int sync_session(void *data, struct session_info *info) +@@ -241,33 +256,68 @@ static int sync_session(void *data, struct session_info *info) return 0; } @@ -13123,22 +19073,24 @@ index 35ceaef..e7f0cc1 100644 + static void sync_sessions(void) { - idbm_t *db; +- idbm_t *db; int nr_found = 0; - db = idbm_init(daemon_config.config_file); -+ db = idbm_init(iscsid_get_config_file); - if (!db) +- if (!db) ++ if (idbm_init(iscsid_get_config_file)) return; - sysfs_for_each_session(db, &nr_found, sync_session); - idbm_terminate(db); - } - +- sysfs_for_each_session(db, &nr_found, sync_session); +- idbm_terminate(db); +-} +- -static void catch_signal(int signo) -{ - log_warning("caught signal -%d, ignoring...", signo); --} -- ++ sysfs_for_each_session(NULL, &nr_found, sync_session); ++ idbm_terminate(); + } + static void iscsid_exit(void) { - log_debug(1, "iscsid_exit"); @@ -13192,7 +19144,7 @@ index 35ceaef..e7f0cc1 100644 } int main(int argc, char *argv[]) -@@ -329,19 +365,6 @@ int main(int argc, char *argv[]) +@@ -329,24 +379,14 @@ int main(int argc, char *argv[]) } } @@ -13212,7 +19164,77 @@ index 35ceaef..e7f0cc1 100644 /* initialize logger */ log_pid = log_init(program_name, DEFAULT_AREA_SIZE); if (log_pid < 0) -@@ -407,17 +430,14 @@ int main(int argc, char *argv[]) + exit(1); +- check_class_version(); ++ if (check_class_version()) { ++ log_close(log_pid); ++ exit(1); ++ } + + umask(0177); + +@@ -356,11 +396,14 @@ int main(int argc, char *argv[]) + daemon_config.initiator_alias = NULL; + if (atexit(iscsid_exit)) { + log_error("failed to set exit function\n"); ++ log_close(log_pid); + exit(1); + } + +- if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) +- exit(-1); ++ if ((mgmt_ipc_fd = mgmt_ipc_listen()) < 0) { ++ log_close(log_pid); ++ exit(1); ++ } + + if (log_daemon) { + char buf[64]; +@@ -369,23 +412,28 @@ int main(int argc, char *argv[]) + fd = open(pid_file, O_WRONLY|O_CREAT, 0644); + if (fd < 0) { + log_error("Unable to create pid file"); ++ log_close(log_pid); + exit(1); + } + pid = fork(); + if (pid < 0) { + log_error("Starting daemon failed"); ++ log_close(log_pid); + exit(1); + } else if (pid) { + log_error("iSCSI daemon with pid=%d started!", pid); + exit(0); + } + +- if ((control_fd = ipc->ctldev_open()) < 0) +- exit(-1); ++ if ((control_fd = ipc->ctldev_open()) < 0) { ++ log_close(log_pid); ++ exit(1); ++ } + + chdir("/"); + if (lockf(fd, F_TLOCK, 0) < 0) { + log_error("Unable to lock pid file"); ++ log_close(log_pid); + exit(1); + } + ftruncate(fd, 0); +@@ -394,8 +442,10 @@ int main(int argc, char *argv[]) + + daemon_init(); + } else { +- if ((control_fd = ipc->ctldev_open()) < 0) +- exit(-1); ++ if ((control_fd = ipc->ctldev_open()) < 0) { ++ log_close(log_pid); ++ exit(1); ++ } + } + + if (uid && setuid(uid) < 0) +@@ -407,17 +457,14 @@ int main(int argc, char *argv[]) memset(&daemon_config, 0, sizeof (daemon_config)); daemon_config.pid_file = pid_file; daemon_config.config_file = config_file; @@ -13234,7 +19256,7 @@ index 35ceaef..e7f0cc1 100644 if (!daemon_config.initiator_alias) { memset(&host_info, 0, sizeof (host_info)); if (uname(&host_info) >= 0) { -@@ -426,7 +446,8 @@ int main(int argc, char *argv[]) +@@ -426,7 +473,8 @@ int main(int argc, char *argv[]) } } @@ -13244,7 +19266,11 @@ index 35ceaef..e7f0cc1 100644 log_debug(1, "InitiatorAlias=%s", daemon_config.initiator_alias); pid = fork(); -@@ -450,11 +471,10 @@ int main(int argc, char *argv[]) +@@ -447,14 +495,14 @@ int main(int argc, char *argv[]) + /* we don't want our active sessions to be paged out... */ + if (mlockall(MCL_CURRENT | MCL_FUTURE)) { + log_error("failed to mlockall, exiting..."); ++ log_close(log_pid); exit(1); } @@ -13271,7 +19297,7 @@ index 7437d9e..b646f32 100644 char *initiator_alias; }; diff --git a/usr/iscsistart.c b/usr/iscsistart.c -index 5ef05bb..129fa24 100644 +index 5ef05bb..870f3b0 100644 --- a/usr/iscsistart.c +++ b/usr/iscsistart.c @@ -42,6 +42,7 @@ @@ -13413,8 +19439,19 @@ index 5ef05bb..129fa24 100644 case 'v': printf("%s version %s\n", program_name, ISCSI_VERSION_STR); +@@ -263,7 +305,9 @@ int main(int argc, char *argv[]) + log_daemon = 0; + log_init(program_name, DEFAULT_AREA_SIZE); + +- check_class_version(); ++ if (check_class_version()) ++ exit(1); ++ + if (check_params(initiatorname)) + exit(1); + diff --git a/usr/isns.c b/usr/isns.c -index b823bf4..191b58b 100644 +index b823bf4..e6a4a65 100644 --- a/usr/isns.c +++ b/usr/isns.c @@ -50,16 +50,17 @@ struct isns_task { @@ -13437,7 +19474,7 @@ index b823bf4..191b58b 100644 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define get_hdr_param(hdr, function, length, flags, transaction, sequence) \ -@@ -270,6 +271,11 @@ static int isns_recv_pdu(struct isns_task *task) +@@ -270,17 +271,24 @@ static int isns_recv_pdu(struct isns_task *task) return 0; } @@ -13449,24 +19486,54 @@ index b823bf4..191b58b 100644 static void add_new_target_node(char *targetname, uint8_t *ip, int port, int tag) { -@@ -288,7 +294,7 @@ static void add_new_target_node(char *targetname, uint8_t *ip, int port, + int err; + node_rec_t rec; + discovery_rec_t drec; +- idbm_t *db; + char dst[INET6_ADDRSTRLEN]; + + memset(dst, 0, sizeof(dst)); +- if (!memcmp(ip, dst, 10) && ip[10] == 0xff && ip[11] == 0xff) ++ /* ++ * some servers are sending compat instead of mapped ++ */ ++ if (IN6_IS_ADDR_V4MAPPED(ip) || IN6_IS_ADDR_V4COMPAT(ip)) + inet_ntop(AF_INET, ip + 12, dst, sizeof(dst)); + else + inet_ntop(AF_INET6, ip, dst, sizeof(dst)); +@@ -288,26 +296,26 @@ static void add_new_target_node(char *targetname, uint8_t *ip, int port, log_debug(1, "add a new target node:%s %s,%d %d", targetname, dst, port, tag); - db = idbm_init(dconfig->config_file); -+ db = idbm_init(isns_get_config_file); - if (!db) { +- if (!db) { ++ if (idbm_init(isns_get_config_file)) { log_error("Could not add new target node:%s %s,%d", targetname, dst, port); -@@ -301,6 +307,7 @@ static void add_new_target_node(char *targetname, uint8_t *ip, int port, + return; + } +- idbm_node_setup_from_conf(db, &rec); ++ idbm_node_setup_from_conf(&rec); + strncpy(rec.name, targetname, TARGET_NAME_MAXLEN); + rec.conn[0].port = port; + rec.tpgt = tag; strncpy(rec.conn[0].address, dst, NI_MAXHOST); /* TODO?: shoudl we set the address and port of the server ? */ + memset(&drec, 0, sizeof(discovery_rec_t)); drec.type = DISCOVERY_TYPE_ISNS; - err = idbm_add_nodes(db, &rec, &drec, NULL); +- err = idbm_add_nodes(db, &rec, &drec, NULL); ++ err = idbm_add_nodes(&rec, &drec, NULL, 0); if (err) -@@ -432,8 +439,8 @@ static int isns_task_done(struct isns_task *task) + log_error("Could not add new target node:%s %s,%d", + targetname, dst, port); + +- idbm_terminate(db); ++ idbm_terminate(); + } + + static int qry_rsp_handle(struct isns_hdr *hdr) +@@ -432,8 +440,8 @@ static int isns_task_done(struct isns_task *task) task->len = length + sizeof(*hdr); task->done = 0; @@ -13477,7 +19544,7 @@ index b823bf4..191b58b 100644 finished = 0; break; default: -@@ -502,8 +509,8 @@ int isns_dev_attr_query_task(queue_task_t *qtask) +@@ -502,8 +510,8 @@ int isns_dev_attr_query_task(queue_task_t *qtask) qtask->rsp.command = MGMT_IPC_ISNS_DEV_ATTR_QUERY; @@ -13488,7 +19555,7 @@ index b823bf4..191b58b 100644 return MGMT_IPC_OK; } -@@ -532,15 +539,15 @@ void isns_handle(int listen_fd) +@@ -532,15 +540,15 @@ void isns_handle(int listen_fd) task->state = ISNS_TASK_RECV_PDU; task->fd = fd; @@ -13508,7 +19575,7 @@ index b823bf4..191b58b 100644 struct isns_hdr *hdr = (struct isns_hdr *) task->data; uint16_t function = ntohs(hdr->function); -@@ -573,9 +580,8 @@ static void isns_poll(queue_item_t *item) +@@ -573,9 +581,8 @@ static void isns_poll(queue_item_t *item) goto free_task; } @@ -13520,7 +19587,7 @@ index b823bf4..191b58b 100644 } break; case ISNS_TASK_RECV_PDU: -@@ -590,9 +596,9 @@ static void isns_poll(queue_item_t *item) +@@ -590,9 +597,9 @@ static void isns_poll(queue_item_t *item) goto free_task; } else { /* need to read more */ @@ -13533,7 +19600,7 @@ index b823bf4..191b58b 100644 } } } -@@ -602,8 +608,8 @@ static void isns_poll(queue_item_t *item) +@@ -602,8 +609,8 @@ static void isns_poll(queue_item_t *item) log_error("abort task"); goto abort_task; } else { @@ -13544,7 +19611,7 @@ index b823bf4..191b58b 100644 } } -@@ -615,32 +621,6 @@ free_task: +@@ -615,32 +622,6 @@ free_task: isns_free_task(task); } @@ -13577,7 +19644,7 @@ index b823bf4..191b58b 100644 static int isns_dev_register(void) { struct isns_task *task; -@@ -658,10 +638,9 @@ static int isns_dev_register(void) +@@ -658,10 +639,9 @@ static int isns_dev_register(void) task->state = ISNS_TASK_WAIT_CONN; build_dev_reg_req(task); @@ -13590,7 +19657,7 @@ index b823bf4..191b58b 100644 return 0; } -@@ -722,7 +701,7 @@ int isns_init(void) +@@ -722,7 +702,7 @@ int isns_init(void) int fd = -1, err; FILE *f; @@ -13599,7 +19666,7 @@ index b823bf4..191b58b 100644 if (!f) return -EIO; -@@ -741,62 +720,23 @@ int isns_init(void) +@@ -741,62 +721,23 @@ int isns_init(void) if (!strlen(isns_address)) return -1; @@ -13667,10 +19734,18 @@ index b823bf4..191b58b 100644 + ; } diff --git a/usr/list.h b/usr/list.h -index 3e85c9b..d2e0019 100644 +index 3e85c9b..bbf3425 100644 --- a/usr/list.h +++ b/usr/list.h -@@ -83,4 +83,10 @@ static inline void list_del(struct list_head *entry) +@@ -1,6 +1,7 @@ + #ifndef __LIST_H__ + #define __LIST_H__ + ++#include + /* taken from linux kernel */ + + #undef offsetof +@@ -83,4 +84,10 @@ static inline void list_del(struct list_head *entry) entry->next = entry->prev = NULL; } @@ -13682,7 +19757,7 @@ index 3e85c9b..d2e0019 100644 + #endif diff --git a/usr/log.c b/usr/log.c -index 6746bb3..9b82c46 100644 +index 6746bb3..013caed 100644 --- a/usr/log.c +++ b/usr/log.c @@ -12,6 +12,7 @@ @@ -13693,20 +19768,146 @@ index 6746bb3..9b82c46 100644 #include #include #include -@@ -108,11 +109,10 @@ static int logarea_init (int size) +@@ -36,6 +37,33 @@ int log_level = 0; - static void free_logarea (void) + static int log_stop_daemon = 0; + ++static void free_logarea (void) ++{ ++ int shmid; ++ ++ if (!la) ++ return; ++ ++ if (la->semid != -1) ++ semctl(la->semid, 0, IPC_RMID, la->semarg); ++ if (la->buff) { ++ shmdt(la->buff); ++ shmctl(la->shmid_buff, IPC_RMID, NULL); ++ la->buff = NULL; ++ la->shmid_buff = -1; ++ } ++ if (la->start) { ++ shmdt(la->start); ++ shmctl(la->shmid_msg, IPC_RMID, NULL); ++ la->start = NULL; ++ la->shmid_msg = -1; ++ } ++ shmid = la->shmid; ++ shmdt(la); ++ shmctl(shmid, IPC_RMID, NULL); ++ la = NULL; ++} ++ + static int logarea_init (int size) { -- semctl(la->semid, 0, IPC_RMID, la->semarg); - shmdt(la->buff); - shmdt(la->start); - shmdt(la); -- return; -+ semctl(la->semid, 0, IPC_RMID, la->semarg); + int shmid; +@@ -47,21 +75,28 @@ static int logarea_init (int size) + return 1; + + la = shmat(shmid, NULL, 0); +- if (!la) ++ if (!la) { ++ shmctl(shmid, IPC_RMID, NULL); + return 1; ++ } ++ la->shmid = shmid; ++ la->start = NULL; ++ la->buff = NULL; ++ la->semid = -1; + + if (size < MAX_MSG_SIZE) + size = DEFAULT_AREA_SIZE; + + if ((shmid = shmget(IPC_PRIVATE, size, + 0644 | IPC_CREAT | IPC_EXCL)) == -1) { +- shmdt(la); ++ free_logarea(); + return 1; + } ++ la->shmid_msg = shmid; + +- la->start = shmat(shmid, NULL, 0); ++ la->start = shmat(la->shmid_msg, NULL, 0); + if (!la->start) { +- shmdt(la); ++ free_logarea(); + return 1; + } + memset(la->start, 0, size); +@@ -73,32 +108,27 @@ static int logarea_init (int size) + + if ((shmid = shmget(IPC_PRIVATE, MAX_MSG_SIZE + sizeof(struct logmsg), + 0644 | IPC_CREAT | IPC_EXCL)) == -1) { +- shmdt(la->start); +- shmdt(la); ++ free_logarea(); + return 1; + } + la->buff = shmat(shmid, NULL, 0); + if (!la->buff) { +- shmdt(la->start); +- shmdt(la); ++ free_logarea(); + return 1; + } + + if ((la->semid = semget(SEMKEY, 1, 0600 | IPC_CREAT)) < 0) { +- shmdt(la->buff); +- shmdt(la->start); +- shmdt(la); ++ free_logarea(); + return 1; + } + + la->semarg.val=1; + if (semctl(la->semid, 0, SETVAL, la->semarg) < 0) { +- shmdt(la->buff); +- shmdt(la->start); +- shmdt(la); ++ free_logarea(); + return 1; + } + ++ la->shmid_buff = shmid; + la->ops[0].sem_num = 0; + la->ops[0].sem_flg = 0; + +@@ -106,15 +136,6 @@ static int logarea_init (int size) + } +-static void free_logarea (void) +-{ +- semctl(la->semid, 0, IPC_RMID, la->semarg); +- shmdt(la->buff); +- shmdt(la->start); +- shmdt(la); +- return; +-} +- #if LOGDBG -@@ -233,7 +233,7 @@ static void dolog(int prio, const char *fmt, va_list ap) + static void dump_logarea (void) + { +@@ -196,7 +217,7 @@ int log_dequeue (void * buff) + int len; + + if (la->empty) +- return 1; ++ return 0; + + len = strlen((char *)&src->str) * sizeof(char) + + sizeof(struct logmsg) + 1; +@@ -215,7 +236,7 @@ int log_dequeue (void * buff) + + memset((void *)src, 0, len); + +- return la->empty; ++ return len; + } + + /* +@@ -233,7 +254,7 @@ static void dolog(int prio, const char *fmt, va_list ap) if (log_daemon) { la->ops[0].sem_op = -1; if (semop(la->semid, la->ops, 1) < 0) { @@ -13715,7 +19916,12 @@ index 6746bb3..9b82c46 100644 return; } -@@ -317,7 +317,7 @@ static void log_flush(void) +@@ -314,19 +335,22 @@ static void __dump_char(int level, unsigned char *buf, int *cp, int ch) + + static void log_flush(void) + { ++ int msglen; ++ while (!la->empty) { la->ops[0].sem_op = -1; if (semop(la->semid, la->ops, 1) < 0) { @@ -13723,8 +19929,20 @@ index 6746bb3..9b82c46 100644 + syslog(LOG_ERR, "semop up failed %d", errno); exit(1); } - log_dequeue(la->buff); -@@ -347,7 +347,6 @@ static void catch_signal(int signo) +- log_dequeue(la->buff); ++ msglen = log_dequeue(la->buff); + la->ops[0].sem_op = 1; + if (semop(la->semid, la->ops, 1) < 0) { + syslog(LOG_ERR, "semop down failed"); + exit(1); + } +- log_syslog(la->buff); ++ if (msglen) ++ log_syslog(la->buff); + } + } + +@@ -347,7 +371,6 @@ static void catch_signal(int signo) static void __log_close(void) { if (log_daemon) { @@ -13732,7 +19950,7 @@ index 6746bb3..9b82c46 100644 log_flush(); closelog(); free_logarea(); -@@ -403,7 +402,6 @@ int log_init(char *program_name, int size) +@@ -403,7 +426,6 @@ int log_init(char *program_name, int size) return 0; } @@ -13740,11 +19958,93 @@ index 6746bb3..9b82c46 100644 void log_close(pid_t pid) { int status; +diff --git a/usr/log.h b/usr/log.h +index 4816a1b..4d2a265 100644 +--- a/usr/log.h ++++ b/usr/log.h +@@ -51,6 +51,9 @@ struct logmsg { + }; + + struct logarea { ++ int shmid; ++ int shmid_msg; ++ int shmid_buff; + int empty; + void *head; + void *tail; diff --git a/usr/login.c b/usr/login.c -index 614fd42..f0b9b09 100644 +index 614fd42..7c004cd 100644 --- a/usr/login.c +++ b/usr/login.c -@@ -1399,8 +1399,6 @@ iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c) +@@ -264,24 +264,20 @@ get_security_text_keys(iscsi_session_t *session, int cid, char **data, + &value, &value_end)) { + /* + * We should have already obtained this +- * via discovery. +- * We've already picked an isid, so the +- * most we can do is confirm we reached +- * the portal group we were expecting to ++ * via discovery, but the value could be stale. ++ * If the target was reconfigured it will send us ++ * the updated tpgt. + */ + tag = strtoul(value, NULL, 0); + if (session->portal_group_tag >= 0) { +- if (tag != session->portal_group_tag) { +- log_error("Portal group tag " ++ if (tag != session->portal_group_tag) ++ log_debug(2, "Portal group tag " + "mismatch, expected %u, " +- "received %u", ++ "received %u. Updating", + session->portal_group_tag, tag); +- return LOGIN_WRONG_PORTAL_GROUP; +- } +- } else +- /* we now know the tag */ +- session->portal_group_tag = tag; +- ++ } ++ /* we now know the tag */ ++ session->portal_group_tag = tag; + text = value_end; + } else { + /* +@@ -339,21 +335,22 @@ get_op_params_text_keys(iscsi_session_t *session, int cid, + } + } else if (iscsi_find_key_value("TargetPortalGroupTag", text, end, + &value, &value_end)) { ++ int tag = strtoul(value, NULL, 0); + /* +- * confirm we reached the portal group we were expecting to ++ * We should have already obtained this ++ * via discovery, but the value could be stale. ++ * If the target was reconfigured it will send us ++ * the updated tpgt. + */ +- int tag = strtoul(value, NULL, 0); + if (session->portal_group_tag >= 0) { +- if (tag != session->portal_group_tag) { +- log_error("Portal group tag mismatch, " +- "expected %u, received %u", ++ if (tag != session->portal_group_tag) ++ log_debug(2, "Portal group tag " ++ "mismatch, expected %u, " ++ "received %u. Updating", + session->portal_group_tag, tag); +- return LOGIN_WRONG_PORTAL_GROUP; +- } +- } else +- /* we now know the tag */ +- session->portal_group_tag = tag; +- ++ } ++ /* we now know the tag */ ++ session->portal_group_tag = tag; + text = value_end; + } else if (iscsi_find_key_value("InitialR2T", text, end, &value, + &value_end)) { +@@ -1399,8 +1396,6 @@ iscsi_login_req(iscsi_session_t *session, iscsi_login_context_t *c) c->ret = LOGIN_IO_ERROR; goto done; } @@ -13753,7 +20053,7 @@ index 614fd42..f0b9b09 100644 return 0; done: -@@ -1464,8 +1462,6 @@ iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c) +@@ -1464,8 +1459,6 @@ iscsi_login_rsp(iscsi_session_t *session, iscsi_login_context_t *c) &c->final); if (c->final) goto done; @@ -13762,7 +20062,7 @@ index 614fd42..f0b9b09 100644 return 0; done: -@@ -1501,7 +1497,6 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize, +@@ -1501,7 +1494,6 @@ iscsi_login(iscsi_session_t *session, int cid, char *buffer, size_t bufsize, iscsi_login_context_t *c = &conn->login_context; int ret; @@ -13771,7 +20071,7 @@ index 614fd42..f0b9b09 100644 * assume iscsi_login is only called from discovery, so it is * safe to always set to zero diff --git a/usr/mgmt_ipc.c b/usr/mgmt_ipc.c -index fb2be80..cb6daa1 100644 +index fb2be80..7520c80 100644 --- a/usr/mgmt_ipc.c +++ b/usr/mgmt_ipc.c @@ -21,20 +21,13 @@ @@ -13810,7 +20110,7 @@ index fb2be80..cb6daa1 100644 int mgmt_ipc_listen(void) -@@ -81,11 +76,16 @@ mgmt_ipc_listen(void) +@@ -81,118 +76,129 @@ mgmt_ipc_listen(void) void mgmt_ipc_close(int fd) { @@ -13823,12 +20123,14 @@ index fb2be80..cb6daa1 100644 -mgmt_ipc_session_login(queue_task_t *qtask, node_rec_t *rec) +mgmt_ipc_session_login(queue_task_t *qtask) { -+ node_rec_t *rec = &qtask->req.u.session.rec; -+ - if (session_is_running(rec)) { - log_error("session [%s,%s,%d] already running.", rec->name, - rec->conn[0].address, rec->conn[0].port); -@@ -96,37 +96,46 @@ mgmt_ipc_session_login(queue_task_t *qtask, node_rec_t *rec) +- if (session_is_running(rec)) { +- log_error("session [%s,%s,%d] already running.", rec->name, +- rec->conn[0].address, rec->conn[0].port); +- return MGMT_IPC_ERR_EXISTS; +- } +- +- return session_login_task(rec, qtask); ++ return session_login_task(&qtask->req.u.session.rec, qtask); } static mgmt_ipc_err_e @@ -13874,14 +20176,23 @@ index fb2be80..cb6daa1 100644 - return MGMT_IPC_ERR_NOT_FOUND; + mgmt_ipc_write_rsp(qtask, MGMT_IPC_OK); + return MGMT_IPC_OK; -+} -+ -+static mgmt_ipc_err_e + } + + static mgmt_ipc_err_e +-mgmt_ipc_session_logout(queue_task_t *qtask, node_rec_t *rec) +mgmt_ipc_send_targets(queue_task_t *qtask) -+{ + { +- iscsi_session_t *session; +- +- if (!(session = session_find_by_rec(rec))) { +- log_error("session [%s,%s,%d] not found!", rec->name, +- rec->conn[0].address, rec->conn[0].port); +- return MGMT_IPC_ERR_NOT_FOUND; +- } + iscsiadm_req_t *req = &qtask->req; + mgmt_ipc_err_e err; -+ + +- return session_logout_task(session, qtask); + err = iscsi_host_send_targets(qtask, req->u.st.host_no, + req->u.st.do_login, + &req->u.st.ss); @@ -13890,32 +20201,26 @@ index fb2be80..cb6daa1 100644 } static mgmt_ipc_err_e --mgmt_ipc_session_logout(queue_task_t *qtask, node_rec_t *rec) +-mgmt_ipc_session_sync(queue_task_t *qtask, node_rec_t *rec, int sid) +mgmt_ipc_session_logout(queue_task_t *qtask) { -+ node_rec_t *rec = &qtask->req.u.session.rec; - iscsi_session_t *session; - - if (!(session = session_find_by_rec(rec))) { -@@ -139,22 +148,26 @@ mgmt_ipc_session_logout(queue_task_t *qtask, node_rec_t *rec) - } - - static mgmt_ipc_err_e --mgmt_ipc_session_sync(queue_task_t *qtask, node_rec_t *rec, int sid) -+mgmt_ipc_session_sync(queue_task_t *qtask) - { - return iscsi_sync_session(rec, qtask, sid); -+ struct ipc_msg_session *session= &qtask->req.u.session; -+ -+ return iscsi_sync_session(&session->rec, qtask, session->sid); ++ return session_logout_task(qtask->req.u.session.sid, qtask); } static mgmt_ipc_err_e -mgmt_ipc_cfg_initiatorname(queue_task_t *qtask, iscsiadm_rsp_t *rsp) -+mgmt_ipc_cfg_initiatorname(queue_task_t *qtask) ++mgmt_ipc_session_sync(queue_task_t *qtask) { - strcpy(rsp->u.config.var, dconfig->initiator_name); -- ++ struct ipc_msg_session *session= &qtask->req.u.session; + ++ return iscsi_sync_session(&session->rec, qtask, session->sid); ++} ++ ++static mgmt_ipc_err_e ++mgmt_ipc_cfg_initiatorname(queue_task_t *qtask) ++{ + if (dconfig->initiator_name) + strcpy(qtask->rsp.u.config.var, dconfig->initiator_name); + mgmt_ipc_write_rsp(qtask, MGMT_IPC_OK); @@ -13930,7 +20235,9 @@ index fb2be80..cb6daa1 100644 iscsi_session_t *session; struct ipc_msg_session_state *info; -@@ -163,36 +176,46 @@ mgmt_ipc_session_info(queue_task_t *qtask, int sid, iscsiadm_rsp_t *rsp) + if (!(session = session_find_by_sid(sid))) { +- log_error("session with sid %d not found!", sid); ++ log_debug(1, "session with sid %d not found!", sid); return MGMT_IPC_ERR_NOT_FOUND; } @@ -13986,7 +20293,7 @@ index fb2be80..cb6daa1 100644 { return MGMT_IPC_ERR; } -@@ -203,6 +226,137 @@ mgmt_ipc_isns_dev_attr_query(queue_task_t *qtask) +@@ -203,6 +209,137 @@ mgmt_ipc_isns_dev_attr_query(queue_task_t *qtask) return isns_dev_attr_query_task(qtask); } @@ -14124,7 +20431,7 @@ index fb2be80..cb6daa1 100644 static int mgmt_peeruser(int sock, char *user) { -@@ -287,6 +441,24 @@ mgmt_peeruser(int sock, char *user) +@@ -287,6 +424,24 @@ mgmt_peeruser(int sock, char *user) #endif } @@ -14149,7 +20456,7 @@ index fb2be80..cb6daa1 100644 void mgmt_ipc_write_rsp(queue_task_t *qtask, mgmt_ipc_err_e err) { -@@ -295,135 +467,136 @@ mgmt_ipc_write_rsp(queue_task_t *qtask, mgmt_ipc_err_e err) +@@ -295,135 +450,136 @@ mgmt_ipc_write_rsp(queue_task_t *qtask, mgmt_ipc_err_e err) log_debug(4, "%s: rsp to fd %d", __FUNCTION__, qtask->mgmt_ipc_fd); @@ -14391,7 +20698,7 @@ index fb2be80..cb6daa1 100644 } static int reap_count; -@@ -477,7 +650,8 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, +@@ -477,7 +633,8 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, poll_array[POLL_ISNS].events = POLLIN; } @@ -14401,7 +20708,7 @@ index fb2be80..cb6daa1 100644 res = poll(poll_array, POLL_MAX, ACTOR_RESOLUTION); if (res > 0) { log_debug(6, "poll result %d", res); -@@ -485,8 +659,7 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, +@@ -485,8 +642,7 @@ void event_loop(struct iscsi_ipc *ipc, int control_fd, int mgmt_ipc_fd, ipc->ctldev_handle(); if (poll_array[POLL_IPC].revents) @@ -14470,10 +20777,18 @@ index 3fa7521..e2eaae2 100644 void need_reap(void); diff --git a/usr/netlink.c b/usr/netlink.c -index 12cb7f7..d6ebc86 100644 +index 12cb7f7..f039aff 100644 --- a/usr/netlink.c +++ b/usr/netlink.c -@@ -388,6 +388,27 @@ kdestroy_session(uint64_t transport_handle, uint32_t sid) +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -388,6 +389,27 @@ kdestroy_session(uint64_t transport_handle, uint32_t sid) } static int @@ -14501,7 +20816,7 @@ index 12cb7f7..d6ebc86 100644 kcreate_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, uint32_t *out_cid) { -@@ -668,8 +689,7 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, +@@ -668,8 +690,7 @@ kstart_conn(uint64_t transport_handle, uint32_t sid, uint32_t cid, } static int @@ -14511,7 +20826,7 @@ index 12cb7f7..d6ebc86 100644 { log_debug(7, "in %s", __FUNCTION__); -@@ -677,19 +697,17 @@ krecv_pdu_begin(uint64_t transport_handle, uintptr_t recv_handle, +@@ -677,19 +698,17 @@ krecv_pdu_begin(uint64_t transport_handle, uintptr_t recv_handle, log_error("recv's begin state machine bug?"); return -EIO; } @@ -14534,7 +20849,7 @@ index 12cb7f7..d6ebc86 100644 { log_debug(7, "in %s", __FUNCTION__); -@@ -699,9 +717,10 @@ krecv_pdu_end(uint64_t transport_handle, uintptr_t conn_handle, +@@ -699,9 +718,10 @@ krecv_pdu_end(uint64_t transport_handle, uintptr_t conn_handle, } log_debug(3, "recv PDU finished for pdu handle 0x%p", @@ -14547,7 +20862,28 @@ index 12cb7f7..d6ebc86 100644 recvbuf = NULL; return 0; } -@@ -847,15 +866,14 @@ static void drop_data(struct nlmsghdr *nlh) +@@ -774,7 +794,7 @@ ktransport_ep_disconnect(iscsi_conn_t *conn) + + log_debug(7, "in %s", __FUNCTION__); + +- if (conn->transport_ep_handle < 0) ++ if (conn->transport_ep_handle == -1) + return; + + memset(&ev, 0, sizeof(struct iscsi_uevent)); +@@ -784,8 +804,9 @@ ktransport_ep_disconnect(iscsi_conn_t *conn) + ev.u.ep_disconnect.ep_handle = conn->transport_ep_handle; + + if ((rc = __kipc_call(&ev, sizeof(ev))) < 0) { +- log_error("conn %p session %p transport disconnect failed %d\n", +- conn, conn->session, rc); ++ log_error("connnection %d:%d transport disconnect failed for " ++ "ep %" PRIu64 " with error %d.", conn->session->id, ++ conn->id, conn->transport_ep_handle, rc); + } else + conn->transport_ep_handle = -1; + } +@@ -847,15 +868,14 @@ static void drop_data(struct nlmsghdr *nlh) static int ctldev_handle(void) { @@ -14566,7 +20902,7 @@ index 12cb7f7..d6ebc86 100644 log_debug(7, "in %s", __FUNCTION__); -@@ -870,6 +888,8 @@ static int ctldev_handle(void) +@@ -870,6 +890,8 @@ static int ctldev_handle(void) log_debug(7, "%s got event type %u\n", __FUNCTION__, ev->type); /* drivers like qla4xxx can be inserted after iscsid is started */ switch (ev->type) { @@ -14575,7 +20911,7 @@ index 12cb7f7..d6ebc86 100644 case ISCSI_UEVENT_CREATE_SESSION: drop_data(nlh); iscsi_async_session_creation(ev->r.c_session_ret.host_no, -@@ -880,76 +900,72 @@ static int ctldev_handle(void) +@@ -880,76 +902,82 @@ static int ctldev_handle(void) iscsi_async_session_destruction(ev->r.d_session.host_no, ev->r.d_session.sid); return 0; @@ -14595,7 +20931,7 @@ index 12cb7f7..d6ebc86 100644 ; /* fall through */ } - /* verify connection */ +- /* verify connection */ - list_for_each_entry(t, &transports, list) { - list_for_each_entry(session, &t->sessions, list) { - int i; @@ -14614,11 +20950,19 @@ index 12cb7f7..d6ebc86 100644 - goto verify_conn; - } - } -- } -- } -- ++ /* Handle transport error which is not connection related */ ++ if (ev->type == ISCSI_KEVENT_TRANS_ERROR) { ++ rc = free_transport_by_handle(ev->transport_handle); ++ if (rc) { ++ log_error("Could not release transport 0x%lx\n", ev->transport_handle); + } ++ drop_data(nlh); ++ return rc; + } + -verify_conn: - if (conn == NULL) { ++ /* verify connection */ + session = session_find_by_sid(sid); + if (!session) { log_error("Could not verify connection %d:%d. Dropping " @@ -14688,7 +21032,7 @@ index 12cb7f7..d6ebc86 100644 log_error("unknown kernel event %d", ev->type); return -EEXIST; } -@@ -1028,12 +1044,12 @@ ctldev_close(void) +@@ -1028,12 +1056,12 @@ ctldev_close(void) { log_debug(7, "in %s", __FUNCTION__); @@ -14703,7 +21047,7 @@ index 12cb7f7..d6ebc86 100644 } struct iscsi_ipc nl_ipc = { -@@ -1045,6 +1061,7 @@ struct iscsi_ipc nl_ipc = { +@@ -1045,6 +1073,7 @@ struct iscsi_ipc nl_ipc = { .sendtargets = ksendtargets, .create_session = kcreate_session, .destroy_session = kdestroy_session, @@ -15178,10 +21522,10 @@ index 0000000..d8ef951 + +#endif diff --git a/usr/strings.c b/usr/strings.c -index e885685..8449c3b 100644 +index e885685..aee1de3 100644 --- a/usr/strings.c +++ b/usr/strings.c -@@ -74,14 +74,25 @@ free_string_buffer(struct string_buffer *s) +@@ -74,14 +74,26 @@ free_string_buffer(struct string_buffer *s) void enlarge_data(struct string_buffer *s, int length) { @@ -15189,12 +21533,13 @@ index e885685..8449c3b 100644 + if (s) { s->data_length += length; - if (s->data_length >= s->allocated_length) { +- if (s->data_length >= s->allocated_length) { - /* too big */ - log_error("enlarged buffer %p to %d data bytes, " - "with only %d bytes of buffer space", - s, (int)s->data_length, - (int)s->allocated_length); ++ if (s->data_length > s->allocated_length) { + log_debug(7, "enlarge buffer from %lu to %lu\n", + s->allocated_length, s->data_length); + new_buf = realloc(s->buffer, s->data_length); @@ -15207,12 +21552,13 @@ index e885685..8449c3b 100644 + exit(1); + } + s->buffer = new_buf; -+ memset(s->buffer + s->allocated_length, 0, length); -+ s->allocated_length += length; ++ memset(s->buffer + s->allocated_length, 0, ++ s->data_length - s->allocated_length); ++ s->allocated_length = s->data_length; } } } -@@ -99,29 +110,13 @@ remove_initial(struct string_buffer *s, int length) +@@ -99,29 +111,13 @@ remove_initial(struct string_buffer *s, int length) } } @@ -15244,7 +21590,7 @@ index e885685..8449c3b 100644 if (length <= s->data_length) { s->data_length = length; s->buffer[s->data_length] = '\0'; -@@ -141,100 +136,6 @@ truncate_buffer(struct string_buffer *s, size_t length) +@@ -141,100 +137,6 @@ truncate_buffer(struct string_buffer *s, size_t length) } } @@ -15345,7 +21691,7 @@ index e885685..8449c3b 100644 char * buffer_data(struct string_buffer *s) { -@@ -261,27 +162,3 @@ unused_length(struct string_buffer * s) +@@ -261,27 +163,3 @@ unused_length(struct string_buffer * s) else return 0; } @@ -15401,6 +21747,23 @@ index fd47b8f..8fcc8c7 100644 - return -ENOSYS; + return ENOSYS; } +diff --git a/usr/transport.h b/usr/transport.h +index 2df8d8b..402747f 100644 +--- a/usr/transport.h ++++ b/usr/transport.h +@@ -26,9 +26,9 @@ struct iscsi_conn; + struct iscsi_transport_template { + const char *name; + uint8_t rdma; +- int (*ep_connect) (iscsi_conn_t *conn, int non_blocking); +- int (*ep_poll) (iscsi_conn_t *conn, int timeout_ms); +- void (*ep_disconnect) (iscsi_conn_t *conn); ++ int (*ep_connect) (struct iscsi_conn *conn, int non_blocking); ++ int (*ep_poll) (struct iscsi_conn *conn, int timeout_ms); ++ void (*ep_disconnect) (struct iscsi_conn *conn); + }; + + /* represents data path provider */ diff --git a/usr/types.h b/usr/types.h index 63dd5cc..77e3f97 100644 --- a/usr/types.h @@ -15417,7 +21780,7 @@ index 63dd5cc..77e3f97 100644 /* * using the __be types allows stricter static diff --git a/usr/util.c b/usr/util.c -index ce8333b..59bcf57 100644 +index ce8333b..f3b9afd 100644 --- a/usr/util.c +++ b/usr/util.c @@ -2,15 +2,11 @@ @@ -15438,7 +21801,15 @@ index ce8333b..59bcf57 100644 #include "log.h" #include "actor.h" -@@ -92,6 +88,35 @@ str_to_ipport(char *str, int *port, int *tpgt) +@@ -24,6 +20,7 @@ + #include "iscsi_proto.h" + #include "transport.h" + #include "idbm.h" ++#include "iface.h" + + void daemon_init(void) + { +@@ -92,6 +89,35 @@ str_to_ipport(char *str, int *port, int *tpgt) return ip; } @@ -15474,7 +21845,7 @@ index ce8333b..59bcf57 100644 #define MAXSLEEP 128 static mgmt_ipc_err_e iscsid_connect(int *fd) -@@ -117,6 +142,11 @@ static mgmt_ipc_err_e iscsid_connect(int *fd) +@@ -117,6 +143,11 @@ static mgmt_ipc_err_e iscsid_connect(int *fd) /* Connection established */ return MGMT_IPC_OK; @@ -15486,7 +21857,7 @@ index ce8333b..59bcf57 100644 /* * Delay before trying again */ -@@ -127,27 +157,38 @@ static mgmt_ipc_err_e iscsid_connect(int *fd) +@@ -127,27 +158,38 @@ static mgmt_ipc_err_e iscsid_connect(int *fd) return MGMT_IPC_ERR_ISCSID_COMM_ERR; } @@ -15530,22 +21901,68 @@ index ce8333b..59bcf57 100644 } mgmt_ipc_err_e do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp) -@@ -155,24 +196,11 @@ mgmt_ipc_err_e do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp) +@@ -155,24 +197,61 @@ mgmt_ipc_err_e do_iscsid(iscsiadm_req_t *req, iscsiadm_rsp_t *rsp) int fd; mgmt_ipc_err_e err; - err = iscsid_connect(&fd); -- if (err) -- goto out; -- -- err = iscsid_request(fd, req); + err = iscsid_request(&fd, req); if (err) - goto out; + return err; ++ ++ return iscsid_response(fd, req->command, rsp); ++} ++ ++int iscsid_req_wait(iscsiadm_cmd_e cmd, int fd) ++{ ++ iscsiadm_rsp_t rsp; + +- err = iscsid_request(fd, req); ++ memset(&rsp, 0, sizeof(iscsiadm_rsp_t)); ++ return iscsid_response(fd, cmd, &rsp); ++} ++ ++int iscsid_req_by_rec_async(iscsiadm_cmd_e cmd, node_rec_t *rec, int *fd) ++{ ++ iscsiadm_req_t req; ++ ++ memset(&req, 0, sizeof(iscsiadm_req_t)); ++ req.command = cmd; ++ memcpy(&req.u.session.rec, rec, sizeof(node_rec_t)); ++ ++ return iscsid_request(fd, &req); ++} ++ ++int iscsid_req_by_rec(iscsiadm_cmd_e cmd, node_rec_t *rec) ++{ ++ int err, fd; ++ ++ err = iscsid_req_by_rec_async(cmd, rec, &fd); + if (err) +- goto out; ++ return err; ++ return iscsid_req_wait(cmd, fd); ++} - err = iscsid_response(fd, rsp); -- if (err) ++int iscsid_req_by_sid_async(iscsiadm_cmd_e cmd, int sid, int *fd) ++{ ++ iscsiadm_req_t req; ++ ++ memset(&req, 0, sizeof(iscsiadm_req_t)); ++ req.command = cmd; ++ req.u.session.sid = sid; ++ ++ return iscsid_request(fd, &req); ++} ++ ++int iscsid_req_by_sid(iscsiadm_cmd_e cmd, int sid) ++{ ++ int err, fd; ++ ++ err = iscsid_req_by_sid_async(cmd, sid, &fd); + if (err) - goto out; - - if (!err && req->command != rsp->command) @@ -15554,11 +21971,12 @@ index ce8333b..59bcf57 100644 - if (fd >= 0) - close(fd); - return err; -+ return iscsid_response(fd, req->command, rsp); ++ return err; ++ return iscsid_req_wait(cmd, fd); } void idbm_node_setup_defaults(node_rec_t *rec) -@@ -191,18 +219,20 @@ void idbm_node_setup_defaults(node_rec_t *rec) +@@ -191,43 +270,42 @@ void idbm_node_setup_defaults(node_rec_t *rec) rec->session.auth.authmethod = 0; rec->session.auth.password_length = 0; rec->session.auth.password_in_length = 0; @@ -15581,8 +21999,11 @@ index ce8333b..59bcf57 100644 + rec->session.iscsi.FastAbort = 1; for (i=0; iconn[i].startup = 0; -@@ -212,9 +242,6 @@ void idbm_node_setup_defaults(node_rec_t *rec) +- rec->conn[i].startup = 0; ++ rec->conn[i].startup = ISCSI_STARTUP_MANUAL; + rec->conn[i].port = ISCSI_LISTEN_PORT; + rec->conn[i].tcp.window_size = TCP_WINDOW_SIZE; + rec->conn[i].tcp.type_of_service = 0; rec->conn[i].timeo.login_timeout= DEF_LOGIN_TIMEO; rec->conn[i].timeo.logout_timeout= DEF_LOGOUT_TIMEO; rec->conn[i].timeo.auth_timeout = 45; @@ -15592,11 +22013,39 @@ index ce8333b..59bcf57 100644 rec->conn[i].timeo.noop_out_interval = DEF_NOOP_OUT_INTERVAL; rec->conn[i].timeo.noop_out_timeout = DEF_NOOP_OUT_TIMEO; + + rec->conn[i].iscsi.MaxRecvDataSegmentLength = + DEF_INI_MAX_RECV_SEG_LEN; +- rec->conn[i].iscsi.HeaderDigest = CONFIG_DIGEST_PREFER_OFF; ++ rec->conn[i].iscsi.HeaderDigest = CONFIG_DIGEST_NEVER; + rec->conn[i].iscsi.DataDigest = CONFIG_DIGEST_NEVER; + rec->conn[i].iscsi.IFMarker = 0; + rec->conn[i].iscsi.OFMarker = 0; + } + +- iface_init(&rec->iface); ++ iface_setup_defaults(&rec->iface); + } + + void iscsid_handle_error(mgmt_ipc_err_e err) +@@ -286,11 +364,7 @@ int __iscsi_match_session(node_rec_t *rec, char *targetname, + if (rec->conn[0].port != -1 && port != rec->conn[0].port) + return 0; + +- if (strlen(rec->iface.transport_name) && +- strcmp(rec->iface.transport_name, iface->transport_name)) +- return 0; +- +- if (!iface_match_bind_info(&rec->iface, iface)) ++ if (!iface_match(&rec->iface, iface)) + return 0; + + return 1; diff --git a/usr/util.h b/usr/util.h -index 29ea0bf..9176ca9 100644 +index 29ea0bf..6c4b5e3 100644 --- a/usr/util.h +++ b/usr/util.h -@@ -11,9 +11,12 @@ struct session_info; +@@ -11,9 +11,17 @@ struct session_info; extern int oom_adjust(void); extern void daemon_init(void); @@ -15606,9 +22055,27 @@ index 29ea0bf..9176ca9 100644 extern void iscsid_handle_error(int err); +extern int iscsid_request(int *fd, struct iscsiadm_req *req); +extern int iscsid_response(int fd, int cmd, struct iscsiadm_rsp *rsp); ++extern int iscsid_req_wait(int cmd, int fd); ++extern int iscsid_req_by_rec_async(int cmd, struct node_rec *rec, int *fd); ++extern int iscsid_req_by_rec(int cmd, struct node_rec *rec); ++extern int iscsid_req_by_sid_async(int cmd, int sid, int *fd); ++extern int iscsid_req_by_sid(int cmd, int sid); extern char *str_to_ipport(char *str, int *port, int *tgpt); extern void idbm_node_setup_defaults(struct node_rec *rec); +diff --git a/usr/version.h b/usr/version.h +index 3c540d0..ba23457 100644 +--- a/usr/version.h ++++ b/usr/version.h +@@ -6,7 +6,7 @@ + * This may not be the same value as the kernel versions because + * some other maintainer could merge a patch without going through us + */ +-#define ISCSI_VERSION_STR "2.0-865" ++#define ISCSI_VERSION_STR "2.0-869" + #define ISCSI_VERSION_FILE "/sys/module/scsi_transport_iscsi/version" + + #endif diff --git a/utils/Makefile b/utils/Makefile index b376129..2c7e891 100644 --- a/utils/Makefile @@ -15625,10 +22092,10 @@ index b376129..2c7e891 100644 + +-include .depend diff --git a/utils/fwparam_ibft/Makefile b/utils/fwparam_ibft/Makefile -index ee090c1..35826fe 100644 +index ee090c1..6d7d00a 100644 --- a/utils/fwparam_ibft/Makefile +++ b/utils/fwparam_ibft/Makefile -@@ -1,11 +1,60 @@ +@@ -1,11 +1,42 @@ -OPTFLAGS ?= -O2 -g +# +# Copyright (C) IBM Corporation. 2007 @@ -15655,17 +22122,7 @@ index ee090c1..35826fe 100644 + +OBJS := fwparam_ibft.o fw_entry.o +OBJS += prom_lex.o prom_parse.tab.o fwparam_ppc.o -+GENFILES := prom_lex.c prom_parse.tab.c prom_parse.tab.h -+CLEANFILES = $(OBJS) $(GENFILES) *.output *~ -+ -+BISONFLAGS = -d -+FLEXFLAGS = -t -+# turn off #line number markers -+NOL = 0 -+ifneq (0 ,$(NOL)) -+ FLEXFLAGS += -L -+ BISONFLAGS += --no-lines -+endif # NOL ++CLEANFILES = $(OBJS) *.output *~ + +OPTFLAGS ?= -O2 -g -fPIC WARNFLAGS ?= -Wall -Wstrict-prototypes @@ -15682,14 +22139,6 @@ index ee090c1..35826fe 100644 - rm -f *.o $(PROGRAMS) + rm -f *.o $(CLEANFILES) .depend + -+ %.c : %.l -+ flex ${FLEXFLAGS} $< | perl -pe '/define YYLMAX/ && s{8192}{2048}' >$@ -+ -+ %.tab.c %.tab.h: %.y -+ bison ${BISONFLAGS} $< -+ -+$(GENFILES): Makefile -+ +$(OBJS): prom_parse.tab.h prom_parse.h fwparam_ibft.h + +depend: @@ -15698,10 +22147,10 @@ index ee090c1..35826fe 100644 +-include .depend diff --git a/utils/fwparam_ibft/fw_entry.c b/utils/fwparam_ibft/fw_entry.c new file mode 100644 -index 0000000..617a721 +index 0000000..915bbb7 --- /dev/null +++ b/utils/fwparam_ibft/fw_entry.c -@@ -0,0 +1,87 @@ +@@ -0,0 +1,84 @@ +/* + * Copyright (C) IBM Corporation. 2007 + * Author: Doug Maxey @@ -15747,10 +22196,7 @@ index 0000000..617a721 + if (!strlen(context->mac)) + return; + -+ printf("iface.hwaddress = "); -+ for (i = 0; i < 5; i++) -+ printf("%02x:", context->mac[i]); -+ printf("%02x\n", context->mac[i]); ++ printf("iface.hwaddress = %s\n", context->mac); +} + +static void dump_initiator(struct boot_context *context) @@ -16765,6 +23211,2297 @@ index 0000000..8580052 +void obp_parm_str(struct ofw_dev *ofwdev, const char *parm, const char *str); + +#endif /* ISCSI_OBP_H_ */ +diff --git a/utils/fwparam_ibft/prom_lex.c b/utils/fwparam_ibft/prom_lex.c +new file mode 100644 +index 0000000..704d8ca +--- /dev/null ++++ b/utils/fwparam_ibft/prom_lex.c +@@ -0,0 +1,2285 @@ ++ ++#line 3 "" ++ ++#define YY_INT_ALIGNED short int ++ ++/* A lexical scanner generated by flex */ ++ ++#define FLEX_SCANNER ++#define YY_FLEX_MAJOR_VERSION 2 ++#define YY_FLEX_MINOR_VERSION 5 ++#define YY_FLEX_SUBMINOR_VERSION 33 ++#if YY_FLEX_SUBMINOR_VERSION > 0 ++#define FLEX_BETA ++#endif ++ ++/* First, we deal with platform-specific or compiler-specific issues. */ ++ ++/* begin standard C headers. */ ++#include ++#include ++#include ++#include ++ ++/* end standard C headers. */ ++ ++/* flex integer type definitions */ ++ ++#ifndef FLEXINT_H ++#define FLEXINT_H ++ ++/* C99 systems have . Non-C99 systems may or may not. */ ++ ++#if __STDC_VERSION__ >= 199901L ++ ++/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, ++ * if you want the limit (max/min) macros for int types. ++ */ ++#ifndef __STDC_LIMIT_MACROS ++#define __STDC_LIMIT_MACROS 1 ++#endif ++ ++#include ++typedef int8_t flex_int8_t; ++typedef uint8_t flex_uint8_t; ++typedef int16_t flex_int16_t; ++typedef uint16_t flex_uint16_t; ++typedef int32_t flex_int32_t; ++typedef uint32_t flex_uint32_t; ++#else ++typedef signed char flex_int8_t; ++typedef short int flex_int16_t; ++typedef int flex_int32_t; ++typedef unsigned char flex_uint8_t; ++typedef unsigned short int flex_uint16_t; ++typedef unsigned int flex_uint32_t; ++#endif /* ! C99 */ ++ ++/* Limits of integral types. */ ++#ifndef INT8_MIN ++#define INT8_MIN (-128) ++#endif ++#ifndef INT16_MIN ++#define INT16_MIN (-32767-1) ++#endif ++#ifndef INT32_MIN ++#define INT32_MIN (-2147483647-1) ++#endif ++#ifndef INT8_MAX ++#define INT8_MAX (127) ++#endif ++#ifndef INT16_MAX ++#define INT16_MAX (32767) ++#endif ++#ifndef INT32_MAX ++#define INT32_MAX (2147483647) ++#endif ++#ifndef UINT8_MAX ++#define UINT8_MAX (255U) ++#endif ++#ifndef UINT16_MAX ++#define UINT16_MAX (65535U) ++#endif ++#ifndef UINT32_MAX ++#define UINT32_MAX (4294967295U) ++#endif ++ ++#endif /* ! FLEXINT_H */ ++ ++#ifdef __cplusplus ++ ++/* The "const" storage-class-modifier is valid. */ ++#define YY_USE_CONST ++ ++#else /* ! __cplusplus */ ++ ++#if __STDC__ ++ ++#define YY_USE_CONST ++ ++#endif /* __STDC__ */ ++#endif /* ! __cplusplus */ ++ ++#ifdef YY_USE_CONST ++#define yyconst const ++#else ++#define yyconst ++#endif ++ ++/* Returned upon end-of-file. */ ++#define YY_NULL 0 ++ ++/* Promotes a possibly negative, possibly signed char to an unsigned ++ * integer for use as an array index. If the signed char is negative, ++ * we want to instead treat it as an 8-bit unsigned char, hence the ++ * double cast. ++ */ ++#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) ++ ++/* Enter a start condition. This macro really ought to take a parameter, ++ * but we do it the disgusting crufty way forced on us by the ()-less ++ * definition of BEGIN. ++ */ ++#define BEGIN (yy_start) = 1 + 2 * ++ ++/* Translate the current start state into a value that can be later handed ++ * to BEGIN to return to the state. The YYSTATE alias is for lex ++ * compatibility. ++ */ ++#define YY_START (((yy_start) - 1) / 2) ++#define YYSTATE YY_START ++ ++/* Action number for EOF rule of a given start state. */ ++#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) ++ ++/* Special action meaning "start processing a new file". */ ++#define YY_NEW_FILE yyrestart(yyin ) ++ ++#define YY_END_OF_BUFFER_CHAR 0 ++ ++/* Size of default input buffer. */ ++#ifndef YY_BUF_SIZE ++#define YY_BUF_SIZE 16384 ++#endif ++ ++/* The state buf must be large enough to hold one state per character in the main buffer. ++ */ ++#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) ++ ++#ifndef YY_TYPEDEF_YY_BUFFER_STATE ++#define YY_TYPEDEF_YY_BUFFER_STATE ++typedef struct yy_buffer_state *YY_BUFFER_STATE; ++#endif ++ ++extern int yyleng; ++ ++extern FILE *yyin, *yyout; ++ ++#define EOB_ACT_CONTINUE_SCAN 0 ++#define EOB_ACT_END_OF_FILE 1 ++#define EOB_ACT_LAST_MATCH 2 ++ ++ #define YY_LESS_LINENO(n) ++ ++/* Return all but the first "n" matched characters back to the input stream. */ ++#define yyless(n) \ ++ do \ ++ { \ ++ /* Undo effects of setting up yytext. */ \ ++ int yyless_macro_arg = (n); \ ++ YY_LESS_LINENO(yyless_macro_arg);\ ++ *yy_cp = (yy_hold_char); \ ++ YY_RESTORE_YY_MORE_OFFSET \ ++ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ ++ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ ++ } \ ++ while ( 0 ) ++ ++#define unput(c) yyunput( c, (yytext_ptr) ) ++ ++/* The following is because we cannot portably get our hands on size_t ++ * (without autoconf's help, which isn't available because we want ++ * flex-generated scanners to compile on their own). ++ */ ++ ++#ifndef YY_TYPEDEF_YY_SIZE_T ++#define YY_TYPEDEF_YY_SIZE_T ++typedef unsigned int yy_size_t; ++#endif ++ ++#ifndef YY_STRUCT_YY_BUFFER_STATE ++#define YY_STRUCT_YY_BUFFER_STATE ++struct yy_buffer_state ++ { ++ FILE *yy_input_file; ++ ++ char *yy_ch_buf; /* input buffer */ ++ char *yy_buf_pos; /* current position in input buffer */ ++ ++ /* Size of input buffer in bytes, not including room for EOB ++ * characters. ++ */ ++ yy_size_t yy_buf_size; ++ ++ /* Number of characters read into yy_ch_buf, not including EOB ++ * characters. ++ */ ++ int yy_n_chars; ++ ++ /* Whether we "own" the buffer - i.e., we know we created it, ++ * and can realloc() it to grow it, and should free() it to ++ * delete it. ++ */ ++ int yy_is_our_buffer; ++ ++ /* Whether this is an "interactive" input source; if so, and ++ * if we're using stdio for input, then we want to use getc() ++ * instead of fread(), to make sure we stop fetching input after ++ * each newline. ++ */ ++ int yy_is_interactive; ++ ++ /* Whether we're considered to be at the beginning of a line. ++ * If so, '^' rules will be active on the next match, otherwise ++ * not. ++ */ ++ int yy_at_bol; ++ ++ int yy_bs_lineno; /**< The line count. */ ++ int yy_bs_column; /**< The column count. */ ++ ++ /* Whether to try to fill the input buffer when we reach the ++ * end of it. ++ */ ++ int yy_fill_buffer; ++ ++ int yy_buffer_status; ++ ++#define YY_BUFFER_NEW 0 ++#define YY_BUFFER_NORMAL 1 ++ /* When an EOF's been seen but there's still some text to process ++ * then we mark the buffer as YY_EOF_PENDING, to indicate that we ++ * shouldn't try reading from the input source any more. We might ++ * still have a bunch of tokens to match, though, because of ++ * possible backing-up. ++ * ++ * When we actually see the EOF, we change the status to "new" ++ * (via yyrestart()), so that the user can continue scanning by ++ * just pointing yyin at a new input file. ++ */ ++#define YY_BUFFER_EOF_PENDING 2 ++ ++ }; ++#endif /* !YY_STRUCT_YY_BUFFER_STATE */ ++ ++/* Stack of input buffers. */ ++static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ ++static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ ++static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ ++ ++/* We provide macros for accessing buffer states in case in the ++ * future we want to put the buffer states in a more general ++ * "scanner state". ++ * ++ * Returns the top of the stack, or NULL. ++ */ ++#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ++ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ ++ : NULL) ++ ++/* Same as previous macro, but useful when we know that the buffer stack is not ++ * NULL or when we need an lvalue. For internal use only. ++ */ ++#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] ++ ++/* yy_hold_char holds the character lost when yytext is formed. */ ++static char yy_hold_char; ++static int yy_n_chars; /* number of characters read into yy_ch_buf */ ++int yyleng; ++ ++/* Points to current character in buffer. */ ++static char *yy_c_buf_p = (char *) 0; ++static int yy_init = 0; /* whether we need to initialize */ ++static int yy_start = 0; /* start state number */ ++ ++/* Flag which is used to allow yywrap()'s to do buffer switches ++ * instead of setting up a fresh yyin. A bit of a hack ... ++ */ ++static int yy_did_buffer_switch_on_eof; ++ ++void yyrestart (FILE *input_file ); ++void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); ++YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); ++void yy_delete_buffer (YY_BUFFER_STATE b ); ++void yy_flush_buffer (YY_BUFFER_STATE b ); ++void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); ++void yypop_buffer_state (void ); ++ ++static void yyensure_buffer_stack (void ); ++static void yy_load_buffer_state (void ); ++static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); ++ ++#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) ++ ++YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); ++YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); ++YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); ++ ++void *yyalloc (yy_size_t ); ++void *yyrealloc (void *,yy_size_t ); ++void yyfree (void * ); ++ ++#define yy_new_buffer yy_create_buffer ++ ++#define yy_set_interactive(is_interactive) \ ++ { \ ++ if ( ! YY_CURRENT_BUFFER ){ \ ++ yyensure_buffer_stack (); \ ++ YY_CURRENT_BUFFER_LVALUE = \ ++ yy_create_buffer(yyin,YY_BUF_SIZE ); \ ++ } \ ++ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ ++ } ++ ++#define yy_set_bol(at_bol) \ ++ { \ ++ if ( ! YY_CURRENT_BUFFER ){\ ++ yyensure_buffer_stack (); \ ++ YY_CURRENT_BUFFER_LVALUE = \ ++ yy_create_buffer(yyin,YY_BUF_SIZE ); \ ++ } \ ++ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ ++ } ++ ++#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) ++ ++/* Begin user sect3 */ ++ ++#define yywrap(n) 1 ++#define YY_SKIP_YYWRAP ++ ++typedef unsigned char YY_CHAR; ++ ++FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; ++ ++typedef int yy_state_type; ++ ++extern int yylineno; ++ ++int yylineno = 1; ++ ++extern char yytext[]; ++ ++static yy_state_type yy_get_previous_state (void ); ++static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); ++static int yy_get_next_buffer (void ); ++static void yy_fatal_error (yyconst char msg[] ); ++ ++/* Done after the current pattern has been matched and before the ++ * corresponding action - sets up yytext. ++ */ ++#define YY_DO_BEFORE_ACTION \ ++ (yytext_ptr) = yy_bp; \ ++ yyleng = (size_t) (yy_cp - yy_bp); \ ++ (yy_hold_char) = *yy_cp; \ ++ *yy_cp = '\0'; \ ++ if ( yyleng >= YYLMAX ) \ ++ YY_FATAL_ERROR( "token too large, exceeds YYLMAX" ); \ ++ yy_flex_strncpy( yytext, (yytext_ptr), yyleng + 1 ); \ ++ (yy_c_buf_p) = yy_cp; ++ ++#define YY_NUM_RULES 17 ++#define YY_END_OF_BUFFER 18 ++/* This struct is not used in this scanner, ++ but its presence is necessary. */ ++struct yy_trans_info ++ { ++ flex_int32_t yy_verify; ++ flex_int32_t yy_nxt; ++ }; ++static yyconst flex_int16_t yy_accept[444] = ++ { 0, ++ 0, 0, 18, 16, 15, 15, 12, 12, 16, 12, ++ 12, 12, 12, 12, 12, 16, 16, 16, 16, 16, ++ 16, 16, 16, 16, 16, 15, 0, 12, 12, 14, ++ 0, 0, 0, 12, 0, 0, 12, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, ++ 0, 0, 0, 0, 0, 0, 12, 12, 14, 7, ++ 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, ++ ++ 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, ++ 11, 0, 0, 0, 0, 0, 0, 0, 6, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 13, 0, 0, 6, 0, 0, 0, 0, 0, 0, ++ 0, 3, 0, 9, 6, 0, 0, 5, 0, 0, ++ 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, ++ 0, 0, 0, 9, 0, 0, 0, 0, 0, 8, ++ 0, 13, 0, 0, 0, 0, 0, 9, 0, 0, ++ 0, 0, 0, 0, 2, 8, 13, 1, 0, 9, ++ 0, 0, 0, 0, 0, 0, 8, 13, 0, 9, ++ ++ 0, 0, 10, 0, 0, 0, 13, 0, 9, 0, ++ 0, 0, 0, 0, 13, 0, 9, 0, 0, 0, ++ 13, 0, 9, 0, 0, 13, 9, 0, 0, 13, ++ 9, 13, 9, 13, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, ++ 9, 9, 0 ++ } ; ++ ++static yyconst flex_int32_t yy_ec[256] = ++ { 0, ++ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 4, 5, 1, 6, 6, 7, ++ 6, 6, 6, 8, 6, 6, 6, 9, 1, 1, ++ 1, 1, 1, 1, 10, 10, 10, 10, 10, 10, ++ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, ++ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, ++ 1, 12, 1, 1, 1, 1, 13, 14, 15, 16, ++ ++ 17, 18, 19, 20, 21, 11, 22, 23, 24, 25, ++ 26, 27, 28, 29, 30, 31, 32, 33, 34, 11, ++ 11, 35, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1 ++ } ; ++ ++static yyconst flex_int32_t yy_meta[36] = ++ { 0, ++ 1, 1, 1, 2, 3, 4, 4, 4, 5, 4, ++ 2, 6, 4, 4, 4, 4, 4, 4, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2 ++ } ; ++ ++static yyconst flex_int16_t yy_base[680] = ++ { 0, ++ 0, 0, 1198, 1199, 34, 36, 35, 1192, 0, 39, ++ 40, 41, 47, 42, 44, 29, 67, 1176, 1182, 1179, ++ 1180, 86, 1174, 1161, 1174, 51, 69, 73, 1184, 0, ++ 1175, 1165, 1160, 43, 1172, 1171, 51, 1168, 1152, 1161, ++ 1157, 1166, 1163, 1162, 1156, 1158, 1142, 1160, 25, 1147, ++ 85, 1146, 1153, 1139, 1147, 1133, 1135, 1135, 1199, 1151, ++ 1136, 1148, 1130, 1146, 1142, 80, 1153, 1152, 0, 1199, ++ 1126, 1124, 1128, 1126, 1136, 1199, 1124, 1128, 1132, 1131, ++ 1131, 1116, 1132, 1119, 1119, 1113, 1133, 1135, 1109, 1122, ++ 1107, 1123, 1122, 1130, 1112, 1119, 1110, 1114, 1199, 1104, ++ ++ 1101, 1094, 97, 106, 0, 1105, 42, 1101, 94, 1108, ++ 1090, 1093, 1096, 1104, 1098, 1091, 1100, 1085, 1199, 0, ++ 1094, 1090, 1099, 1086, 1095, 1093, 1105, 1087, 117, 1102, ++ 0, 1071, 1076, 104, 1088, 1069, 1073, 1093, 1075, 1086, ++ 1069, 1199, 99, 0, 1093, 1079, 1069, 1199, 1065, 1062, ++ 1063, 1076, 121, 125, 0, 1073, 1070, 1059, 1056, 1069, ++ 1061, 1068, 1049, 0, 120, 1056, 1077, 1063, 1062, 131, ++ 1073, 0, 1047, 1059, 1055, 1043, 1056, 0, 1046, 1050, ++ 1044, 1038, 1044, 1036, 1199, 134, 0, 1199, 1035, 0, ++ 1039, 1034, 1046, 1046, 1048, 1031, 1199, 0, 1030, 0, ++ ++ 1027, 1035, 1199, 1039, 1025, 1033, 0, 1032, 0, 1039, ++ 137, 1018, 1028, 1032, 0, 1031, 0, 1018, 1025, 1015, ++ 0, 1014, 0, 145, 142, 0, 0, 120, 132, 0, ++ 0, 0, 0, 1199, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 1199, 1199, 149, 152, 156, 159, 163, 144, 166, ++ 143, 170, 142, 174, 131, 178, 115, 182, 112, 186, ++ 92, 190, 89, 194, 87, 198, 85, 202, 67, 206, ++ 56, 210, 214, 218, 222, 226, 230, 234, 238, 242, ++ 246, 250, 254, 258, 262, 266, 270, 274, 278, 282, ++ 286, 290, 294, 298, 302, 306, 310, 314, 318, 322, ++ ++ 326, 330, 334, 338, 342, 346, 350, 354, 358, 362, ++ 366, 370, 374, 378, 382, 386, 390, 394, 398, 402, ++ 406, 410, 414, 418, 422, 426, 430, 434, 438, 442, ++ 446, 450, 454, 458, 462, 466, 470, 474, 478, 482, ++ 486, 490, 494, 498, 502, 506, 510, 514, 518, 522, ++ 526, 530, 534, 538, 542, 546, 550, 554, 558, 562, ++ 566, 570, 574, 578, 582, 586, 590, 594, 598, 602, ++ 606, 610, 614, 618, 622, 626, 630, 634, 638, 642, ++ 646, 650, 654, 658, 662, 666, 670, 674, 678, 682, ++ 686, 690, 694, 698, 702, 706, 710, 714, 718, 722, ++ ++ 726, 730, 734, 738, 742, 746, 750, 754, 758, 762, ++ 766, 770, 774, 778, 782, 786, 790, 794, 798, 802, ++ 806, 810, 814, 818, 822, 826, 830, 834, 838, 842, ++ 846, 850, 854, 858, 862, 866, 870, 874, 878, 882, ++ 886, 890, 894, 898, 902, 906, 910, 914, 918, 922, ++ 926, 930, 934, 938, 942, 946, 950, 954, 958, 962, ++ 966, 970, 974, 978, 982, 986, 990, 994, 998, 1002, ++ 1006, 1010, 1014, 1018, 1022, 1026, 1030, 1034, 1038 ++ } ; ++ ++static yyconst flex_int16_t yy_def[680] = ++ { 0, ++ 443, 1, 443, 443, 443, 443, 444, 444, 445, 444, ++ 444, 444, 444, 444, 444, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 446, 446, 447, ++ 443, 443, 443, 446, 443, 443, 446, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 448, 448, 447, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ ++ 443, 443, 443, 443, 449, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 450, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 451, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 452, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 453, 443, 443, 443, 443, 443, ++ 443, 443, 443, 454, 443, 443, 443, 443, 443, 443, ++ 443, 455, 443, 443, 443, 443, 443, 456, 443, 443, ++ 443, 443, 443, 443, 443, 443, 457, 443, 443, 458, ++ 443, 443, 443, 443, 443, 443, 443, 459, 443, 460, ++ ++ 443, 443, 443, 443, 443, 443, 461, 443, 462, 443, ++ 443, 443, 443, 443, 463, 443, 464, 443, 443, 443, ++ 465, 443, 466, 443, 443, 467, 468, 443, 443, 469, ++ 470, 471, 472, 443, 473, 474, 475, 476, 477, 478, ++ 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, ++ 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, ++ 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, ++ 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, ++ 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, ++ 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, ++ ++ 539, 540, 541, 542, 543, 544, 545, 546, 547, 548, ++ 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, ++ 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, ++ 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, ++ 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, ++ 589, 590, 591, 592, 593, 594, 595, 596, 597, 598, ++ 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, ++ 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, ++ 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, ++ 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, ++ ++ 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, ++ 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, ++ 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, ++ 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, ++ 679, 443, 0, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443 ++ } ; ++ ++static yyconst flex_int16_t yy_nxt[1235] = ++ { 0, ++ 4, 5, 6, 4, 4, 7, 7, 7, 4, 8, ++ 4, 9, 10, 11, 12, 13, 14, 15, 16, 4, ++ 17, 4, 18, 4, 19, 4, 20, 4, 21, 22, ++ 23, 24, 25, 4, 4, 26, 26, 26, 26, 27, ++ 28, 28, 28, 443, 443, 443, 443, 443, 443, 42, ++ 86, 443, 26, 26, 133, 443, 34, 87, 43, 234, ++ 35, 36, 32, 37, 41, 33, 38, 39, 134, 31, ++ 232, 73, 40, 44, 66, 66, 66, 27, 67, 67, ++ 67, 45, 46, 76, 103, 104, 104, 104, 230, 47, ++ 226, 48, 221, 49, 50, 215, 51, 52, 57, 89, ++ ++ 58, 59, 129, 129, 129, 90, 60, 158, 61, 91, ++ 103, 130, 130, 130, 135, 207, 159, 62, 198, 162, ++ 136, 153, 154, 154, 154, 163, 170, 170, 170, 153, ++ 171, 171, 171, 179, 187, 180, 186, 186, 186, 197, ++ 197, 197, 203, 203, 203, 172, 155, 131, 188, 188, ++ 181, 29, 29, 30, 30, 30, 229, 30, 68, 68, ++ 69, 69, 69, 228, 69, 105, 105, 144, 144, 144, ++ 144, 164, 164, 164, 164, 178, 178, 178, 178, 190, ++ 190, 190, 190, 200, 200, 200, 200, 209, 209, 209, ++ 209, 217, 217, 217, 217, 223, 223, 223, 223, 227, ++ ++ 227, 227, 227, 231, 231, 231, 231, 233, 233, 233, ++ 233, 235, 235, 235, 235, 236, 236, 236, 236, 237, ++ 237, 237, 237, 238, 238, 238, 238, 239, 239, 239, ++ 239, 240, 240, 240, 240, 241, 241, 241, 241, 242, ++ 242, 242, 242, 243, 243, 243, 243, 244, 244, 244, ++ 244, 245, 245, 245, 245, 246, 246, 246, 246, 247, ++ 247, 247, 247, 248, 248, 248, 248, 249, 249, 249, ++ 249, 250, 250, 250, 250, 251, 251, 251, 251, 252, ++ 252, 252, 252, 253, 253, 253, 253, 254, 254, 254, ++ 254, 255, 255, 255, 255, 256, 256, 256, 256, 257, ++ ++ 257, 257, 257, 258, 258, 258, 258, 259, 259, 259, ++ 259, 260, 260, 260, 260, 261, 261, 261, 261, 262, ++ 262, 262, 262, 263, 263, 263, 263, 264, 264, 264, ++ 264, 265, 265, 265, 265, 266, 266, 266, 266, 267, ++ 267, 267, 267, 268, 268, 268, 268, 269, 269, 269, ++ 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, ++ 272, 272, 272, 273, 273, 273, 273, 274, 274, 274, ++ 274, 275, 275, 275, 275, 276, 276, 276, 276, 277, ++ 277, 277, 277, 278, 278, 278, 278, 279, 279, 279, ++ 279, 280, 280, 280, 280, 281, 281, 281, 281, 282, ++ ++ 282, 282, 282, 283, 283, 283, 283, 284, 284, 284, ++ 284, 285, 285, 285, 285, 286, 286, 286, 286, 287, ++ 287, 287, 287, 288, 288, 288, 288, 289, 289, 289, ++ 289, 290, 290, 290, 290, 291, 291, 291, 291, 292, ++ 292, 292, 292, 293, 293, 293, 293, 294, 294, 294, ++ 294, 295, 295, 295, 295, 296, 296, 296, 296, 297, ++ 297, 297, 297, 298, 298, 298, 298, 299, 299, 299, ++ 299, 300, 300, 300, 300, 301, 301, 301, 301, 302, ++ 302, 302, 302, 303, 303, 303, 303, 304, 304, 304, ++ 304, 305, 305, 305, 305, 306, 306, 306, 306, 307, ++ ++ 307, 307, 307, 308, 308, 308, 308, 309, 309, 309, ++ 309, 310, 310, 310, 310, 311, 311, 311, 311, 312, ++ 312, 312, 312, 313, 313, 313, 313, 314, 314, 314, ++ 314, 315, 315, 315, 315, 316, 316, 316, 316, 317, ++ 317, 317, 317, 318, 318, 318, 318, 319, 319, 319, ++ 319, 320, 320, 320, 320, 321, 321, 321, 321, 322, ++ 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, ++ 324, 325, 325, 325, 325, 326, 326, 326, 326, 327, ++ 327, 327, 327, 328, 328, 328, 328, 329, 329, 329, ++ 329, 330, 330, 330, 330, 331, 331, 331, 331, 332, ++ ++ 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, ++ 334, 335, 335, 335, 335, 336, 336, 336, 336, 337, ++ 337, 337, 337, 338, 338, 338, 338, 339, 339, 339, ++ 339, 340, 340, 340, 340, 341, 341, 341, 341, 342, ++ 342, 342, 342, 343, 343, 343, 343, 344, 344, 344, ++ 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, ++ 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, ++ 349, 350, 350, 350, 350, 351, 351, 351, 351, 352, ++ 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, ++ 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, ++ ++ 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, ++ 359, 360, 360, 360, 360, 361, 361, 361, 361, 362, ++ 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, ++ 364, 365, 365, 365, 365, 366, 366, 366, 366, 367, ++ 367, 367, 367, 368, 368, 368, 368, 369, 369, 369, ++ 369, 370, 370, 370, 370, 371, 371, 371, 371, 372, ++ 372, 372, 372, 373, 373, 373, 373, 374, 374, 374, ++ 374, 375, 375, 375, 375, 376, 376, 376, 376, 377, ++ 377, 377, 377, 378, 378, 378, 378, 379, 379, 379, ++ 379, 380, 380, 380, 380, 381, 381, 381, 381, 382, ++ ++ 382, 382, 382, 383, 383, 383, 383, 384, 384, 384, ++ 384, 385, 385, 385, 385, 386, 386, 386, 386, 387, ++ 387, 387, 387, 388, 388, 388, 388, 389, 389, 389, ++ 389, 390, 390, 390, 390, 391, 391, 391, 391, 392, ++ 392, 392, 392, 393, 393, 393, 393, 394, 394, 394, ++ 394, 395, 395, 395, 395, 396, 396, 396, 396, 397, ++ 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, ++ 399, 400, 400, 400, 400, 401, 401, 401, 401, 402, ++ 402, 402, 402, 403, 403, 403, 403, 404, 404, 404, ++ 404, 405, 405, 405, 405, 406, 406, 406, 406, 407, ++ ++ 407, 407, 407, 408, 408, 408, 408, 409, 409, 409, ++ 409, 410, 410, 410, 410, 411, 411, 411, 411, 412, ++ 412, 412, 412, 413, 413, 413, 413, 414, 414, 414, ++ 414, 415, 415, 415, 415, 416, 416, 416, 416, 417, ++ 417, 417, 417, 418, 418, 418, 418, 419, 419, 419, ++ 419, 420, 420, 420, 420, 421, 421, 421, 421, 422, ++ 422, 422, 422, 423, 423, 423, 423, 424, 424, 424, ++ 424, 425, 425, 425, 425, 426, 426, 426, 426, 427, ++ 427, 427, 427, 428, 428, 428, 428, 429, 429, 429, ++ 429, 430, 430, 430, 430, 431, 431, 431, 431, 432, ++ ++ 432, 432, 432, 433, 433, 433, 433, 434, 434, 434, ++ 434, 435, 435, 435, 435, 436, 436, 436, 436, 437, ++ 437, 437, 437, 438, 438, 438, 438, 439, 439, 439, ++ 439, 440, 440, 440, 440, 441, 441, 441, 441, 442, ++ 442, 442, 442, 99, 99, 225, 224, 222, 220, 99, ++ 219, 218, 216, 214, 213, 212, 211, 210, 208, 206, ++ 205, 204, 203, 202, 201, 199, 196, 195, 194, 193, ++ 192, 191, 99, 59, 188, 189, 188, 153, 185, 184, ++ 183, 182, 99, 99, 177, 176, 175, 174, 173, 99, ++ 169, 168, 167, 99, 166, 99, 165, 99, 161, 160, ++ ++ 119, 99, 99, 99, 157, 156, 103, 152, 151, 150, ++ 149, 148, 147, 146, 145, 99, 99, 143, 142, 141, ++ 140, 139, 138, 137, 59, 132, 128, 127, 126, 125, ++ 70, 70, 124, 123, 70, 122, 99, 99, 121, 120, ++ 119, 118, 117, 99, 116, 115, 114, 113, 112, 59, ++ 111, 110, 109, 108, 107, 106, 443, 27, 102, 70, ++ 101, 100, 99, 98, 97, 96, 95, 70, 94, 93, ++ 92, 88, 85, 84, 70, 83, 70, 82, 81, 80, ++ 79, 78, 77, 75, 74, 72, 71, 70, 443, 65, ++ 64, 63, 56, 55, 54, 53, 443, 443, 3, 443, ++ ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443 ++ } ; ++ ++static yyconst flex_int16_t yy_chk[1235] = ++ { 0, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ 1, 1, 1, 1, 1, 5, 5, 6, 6, 7, ++ 7, 7, 7, 10, 11, 12, 14, 34, 15, 16, ++ 49, 13, 26, 26, 107, 37, 12, 49, 16, 471, ++ 12, 12, 11, 13, 15, 11, 13, 13, 107, 10, ++ 469, 34, 14, 17, 27, 27, 27, 28, 28, 28, ++ 28, 17, 17, 37, 66, 66, 66, 66, 467, 17, ++ 465, 17, 463, 17, 17, 461, 17, 17, 22, 51, ++ ++ 22, 22, 103, 103, 103, 51, 22, 134, 22, 51, ++ 104, 104, 104, 104, 109, 459, 134, 22, 457, 143, ++ 109, 129, 129, 129, 129, 143, 153, 153, 153, 154, ++ 154, 154, 154, 165, 455, 165, 170, 170, 170, 186, ++ 186, 186, 211, 211, 211, 453, 451, 449, 229, 228, ++ 165, 444, 444, 445, 445, 445, 225, 445, 446, 446, ++ 447, 447, 447, 224, 447, 448, 448, 450, 450, 450, ++ 450, 452, 452, 452, 452, 454, 454, 454, 454, 456, ++ 456, 456, 456, 458, 458, 458, 458, 460, 460, 460, ++ 460, 462, 462, 462, 462, 464, 464, 464, 464, 466, ++ ++ 466, 466, 466, 468, 468, 468, 468, 470, 470, 470, ++ 470, 472, 472, 472, 472, 473, 473, 473, 473, 474, ++ 474, 474, 474, 475, 475, 475, 475, 476, 476, 476, ++ 476, 477, 477, 477, 477, 478, 478, 478, 478, 479, ++ 479, 479, 479, 480, 480, 480, 480, 481, 481, 481, ++ 481, 482, 482, 482, 482, 483, 483, 483, 483, 484, ++ 484, 484, 484, 485, 485, 485, 485, 486, 486, 486, ++ 486, 487, 487, 487, 487, 488, 488, 488, 488, 489, ++ 489, 489, 489, 490, 490, 490, 490, 491, 491, 491, ++ 491, 492, 492, 492, 492, 493, 493, 493, 493, 494, ++ ++ 494, 494, 494, 495, 495, 495, 495, 496, 496, 496, ++ 496, 497, 497, 497, 497, 498, 498, 498, 498, 499, ++ 499, 499, 499, 500, 500, 500, 500, 501, 501, 501, ++ 501, 502, 502, 502, 502, 503, 503, 503, 503, 504, ++ 504, 504, 504, 505, 505, 505, 505, 506, 506, 506, ++ 506, 507, 507, 507, 507, 508, 508, 508, 508, 509, ++ 509, 509, 509, 510, 510, 510, 510, 511, 511, 511, ++ 511, 512, 512, 512, 512, 513, 513, 513, 513, 514, ++ 514, 514, 514, 515, 515, 515, 515, 516, 516, 516, ++ 516, 517, 517, 517, 517, 518, 518, 518, 518, 519, ++ ++ 519, 519, 519, 520, 520, 520, 520, 521, 521, 521, ++ 521, 522, 522, 522, 522, 523, 523, 523, 523, 524, ++ 524, 524, 524, 525, 525, 525, 525, 526, 526, 526, ++ 526, 527, 527, 527, 527, 528, 528, 528, 528, 529, ++ 529, 529, 529, 530, 530, 530, 530, 531, 531, 531, ++ 531, 532, 532, 532, 532, 533, 533, 533, 533, 534, ++ 534, 534, 534, 535, 535, 535, 535, 536, 536, 536, ++ 536, 537, 537, 537, 537, 538, 538, 538, 538, 539, ++ 539, 539, 539, 540, 540, 540, 540, 541, 541, 541, ++ 541, 542, 542, 542, 542, 543, 543, 543, 543, 544, ++ ++ 544, 544, 544, 545, 545, 545, 545, 546, 546, 546, ++ 546, 547, 547, 547, 547, 548, 548, 548, 548, 549, ++ 549, 549, 549, 550, 550, 550, 550, 551, 551, 551, ++ 551, 552, 552, 552, 552, 553, 553, 553, 553, 554, ++ 554, 554, 554, 555, 555, 555, 555, 556, 556, 556, ++ 556, 557, 557, 557, 557, 558, 558, 558, 558, 559, ++ 559, 559, 559, 560, 560, 560, 560, 561, 561, 561, ++ 561, 562, 562, 562, 562, 563, 563, 563, 563, 564, ++ 564, 564, 564, 565, 565, 565, 565, 566, 566, 566, ++ 566, 567, 567, 567, 567, 568, 568, 568, 568, 569, ++ ++ 569, 569, 569, 570, 570, 570, 570, 571, 571, 571, ++ 571, 572, 572, 572, 572, 573, 573, 573, 573, 574, ++ 574, 574, 574, 575, 575, 575, 575, 576, 576, 576, ++ 576, 577, 577, 577, 577, 578, 578, 578, 578, 579, ++ 579, 579, 579, 580, 580, 580, 580, 581, 581, 581, ++ 581, 582, 582, 582, 582, 583, 583, 583, 583, 584, ++ 584, 584, 584, 585, 585, 585, 585, 586, 586, 586, ++ 586, 587, 587, 587, 587, 588, 588, 588, 588, 589, ++ 589, 589, 589, 590, 590, 590, 590, 591, 591, 591, ++ 591, 592, 592, 592, 592, 593, 593, 593, 593, 594, ++ ++ 594, 594, 594, 595, 595, 595, 595, 596, 596, 596, ++ 596, 597, 597, 597, 597, 598, 598, 598, 598, 599, ++ 599, 599, 599, 600, 600, 600, 600, 601, 601, 601, ++ 601, 602, 602, 602, 602, 603, 603, 603, 603, 604, ++ 604, 604, 604, 605, 605, 605, 605, 606, 606, 606, ++ 606, 607, 607, 607, 607, 608, 608, 608, 608, 609, ++ 609, 609, 609, 610, 610, 610, 610, 611, 611, 611, ++ 611, 612, 612, 612, 612, 613, 613, 613, 613, 614, ++ 614, 614, 614, 615, 615, 615, 615, 616, 616, 616, ++ 616, 617, 617, 617, 617, 618, 618, 618, 618, 619, ++ ++ 619, 619, 619, 620, 620, 620, 620, 621, 621, 621, ++ 621, 622, 622, 622, 622, 623, 623, 623, 623, 624, ++ 624, 624, 624, 625, 625, 625, 625, 626, 626, 626, ++ 626, 627, 627, 627, 627, 628, 628, 628, 628, 629, ++ 629, 629, 629, 630, 630, 630, 630, 631, 631, 631, ++ 631, 632, 632, 632, 632, 633, 633, 633, 633, 634, ++ 634, 634, 634, 635, 635, 635, 635, 636, 636, 636, ++ 636, 637, 637, 637, 637, 638, 638, 638, 638, 639, ++ 639, 639, 639, 640, 640, 640, 640, 641, 641, 641, ++ 641, 642, 642, 642, 642, 643, 643, 643, 643, 644, ++ ++ 644, 644, 644, 645, 645, 645, 645, 646, 646, 646, ++ 646, 647, 647, 647, 647, 648, 648, 648, 648, 649, ++ 649, 649, 649, 650, 650, 650, 650, 651, 651, 651, ++ 651, 652, 652, 652, 652, 653, 653, 653, 653, 654, ++ 654, 654, 654, 655, 655, 655, 655, 656, 656, 656, ++ 656, 657, 657, 657, 657, 658, 658, 658, 658, 659, ++ 659, 659, 659, 660, 660, 660, 660, 661, 661, 661, ++ 661, 662, 662, 662, 662, 663, 663, 663, 663, 664, ++ 664, 664, 664, 665, 665, 665, 665, 666, 666, 666, ++ 666, 667, 667, 667, 667, 668, 668, 668, 668, 669, ++ ++ 669, 669, 669, 670, 670, 670, 670, 671, 671, 671, ++ 671, 672, 672, 672, 672, 673, 673, 673, 673, 674, ++ 674, 674, 674, 675, 675, 675, 675, 676, 676, 676, ++ 676, 677, 677, 677, 677, 678, 678, 678, 678, 679, ++ 679, 679, 679, 222, 220, 219, 218, 216, 214, 213, ++ 212, 210, 208, 206, 205, 204, 202, 201, 199, 196, ++ 195, 194, 193, 192, 191, 189, 184, 183, 182, 181, ++ 180, 179, 177, 176, 175, 174, 173, 171, 169, 168, ++ 167, 166, 163, 162, 161, 160, 159, 158, 157, 156, ++ 152, 151, 150, 149, 147, 146, 145, 141, 140, 139, ++ ++ 138, 137, 136, 135, 133, 132, 130, 128, 127, 126, ++ 125, 124, 123, 122, 121, 118, 117, 116, 115, 114, ++ 113, 112, 111, 110, 108, 106, 102, 101, 100, 98, ++ 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, ++ 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, ++ 77, 75, 74, 73, 72, 71, 68, 67, 65, 64, ++ 63, 62, 61, 60, 58, 57, 56, 55, 54, 53, ++ 52, 50, 48, 47, 46, 45, 44, 43, 42, 41, ++ 40, 39, 38, 36, 35, 33, 32, 31, 29, 25, ++ 24, 23, 21, 20, 19, 18, 8, 3, 443, 443, ++ ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443, 443, 443, 443, 443, 443, 443, ++ 443, 443, 443, 443 ++ } ; ++ ++static yy_state_type yy_last_accepting_state; ++static char *yy_last_accepting_cpos; ++ ++extern int yy_flex_debug; ++int yy_flex_debug = 0; ++ ++/* The intent behind this definition is that it'll catch ++ * any uses of REJECT which flex missed. ++ */ ++#define REJECT reject_used_but_not_detected ++#define yymore() yymore_used_but_not_detected ++#define YY_MORE_ADJ 0 ++#define YY_RESTORE_YY_MORE_OFFSET ++#ifndef YYLMAX ++#define YYLMAX 2048 ++#endif ++ ++char yytext[YYLMAX]; ++char *yytext_ptr; ++#line 1 "prom_lex.l" ++/* ++ * Copyright (C) IBM Corporation. 2007 ++ * Author: Doug Maxey ++ * ++ * This program is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program. If not, see . ++ */ ++/* definitions */ ++#line 23 "prom_lex.l" ++#include "prom_parse.h" ++ ++#undef LEXDEBUG ++#ifdef LEXDEBUG ++#define dbg(a) dbgprint((a)) ++#else ++#define dbg(a) do {} while (0) ++#endif /* LEXDEBUG */ ++ ++#define upval(d) \ ++ dbg(#d); \ ++ yylval.str[0] = 0; \ ++ strcat(yylval.str, yytext); \ ++ yylloc.first_column = yylloc.last_column; \ ++ yylloc.last_column += yyleng; \ ++ return d ++ ++void dbgprint(const char *item) { fprintf(stderr, "%s: \"%s\" len=%d ", item, yytext, yyleng);} ++ ++/* CHOSEN uses only boot related paths. */ ++#line 969 "" ++ ++#define INITIAL 0 ++ ++#ifndef YY_NO_UNISTD_H ++/* Special case for "unistd.h", since it is non-ANSI. We include it way ++ * down here because we want the user's section 1 to have been scanned first. ++ * The user has a chance to override it with an option. ++ */ ++#include ++#endif ++ ++#ifndef YY_EXTRA_TYPE ++#define YY_EXTRA_TYPE void * ++#endif ++ ++static int yy_init_globals (void ); ++ ++/* Macros after this point can all be overridden by user definitions in ++ * section 1. ++ */ ++ ++#ifndef YY_SKIP_YYWRAP ++#ifdef __cplusplus ++extern "C" int yywrap (void ); ++#else ++extern int yywrap (void ); ++#endif ++#endif ++ ++ static void yyunput (int c,char *buf_ptr ); ++ ++#ifndef yytext_ptr ++static void yy_flex_strncpy (char *,yyconst char *,int ); ++#endif ++ ++#ifdef YY_NEED_STRLEN ++static int yy_flex_strlen (yyconst char * ); ++#endif ++ ++#ifndef YY_NO_INPUT ++ ++#ifdef __cplusplus ++static int yyinput (void ); ++#else ++static int input (void ); ++#endif ++ ++#endif ++ ++/* Amount of stuff to slurp up with each read. */ ++#ifndef YY_READ_BUF_SIZE ++#define YY_READ_BUF_SIZE 8192 ++#endif ++ ++/* Copy whatever the last rule matched to the standard output. */ ++#ifndef ECHO ++/* This used to be an fputs(), but since the string might contain NUL's, ++ * we now use fwrite(). ++ */ ++#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) ++#endif ++ ++/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, ++ * is returned in "result". ++ */ ++#ifndef YY_INPUT ++#define YY_INPUT(buf,result,max_size) \ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ ++ { \ ++ int c = '*'; \ ++ size_t n; \ ++ for ( n = 0; n < max_size && \ ++ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ ++ buf[n] = (char) c; \ ++ if ( c == '\n' ) \ ++ buf[n++] = (char) c; \ ++ if ( c == EOF && ferror( yyin ) ) \ ++ YY_FATAL_ERROR( "input in flex scanner failed" ); \ ++ result = n; \ ++ } \ ++ else \ ++ { \ ++ errno=0; \ ++ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ ++ { \ ++ if( errno != EINTR) \ ++ { \ ++ YY_FATAL_ERROR( "input in flex scanner failed" ); \ ++ break; \ ++ } \ ++ errno=0; \ ++ clearerr(yyin); \ ++ } \ ++ }\ ++\ ++ ++#endif ++ ++/* No semi-colon after return; correct usage is to write "yyterminate();" - ++ * we don't want an extra ';' after the "return" because that will cause ++ * some compilers to complain about unreachable statements. ++ */ ++#ifndef yyterminate ++#define yyterminate() return YY_NULL ++#endif ++ ++/* Number of entries by which start-condition stack grows. */ ++#ifndef YY_START_STACK_INCR ++#define YY_START_STACK_INCR 25 ++#endif ++ ++/* Report a fatal error. */ ++#ifndef YY_FATAL_ERROR ++#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) ++#endif ++ ++/* end tables serialization structures and prototypes */ ++ ++/* Default declaration of generated scanner - a define so the user can ++ * easily add parameters. ++ */ ++#ifndef YY_DECL ++#define YY_DECL_IS_OURS 1 ++ ++extern int yylex (void); ++ ++#define YY_DECL int yylex (void) ++#endif /* !YY_DECL */ ++ ++/* Code executed at the beginning of each rule, after yytext and yyleng ++ * have been set up. ++ */ ++#ifndef YY_USER_ACTION ++#define YY_USER_ACTION ++#endif ++ ++/* Code executed at the end of each rule. */ ++#ifndef YY_BREAK ++#define YY_BREAK break; ++#endif ++ ++#define YY_RULE_SETUP \ ++ YY_USER_ACTION ++ ++/** The main scanner function which does all the work. ++ */ ++YY_DECL ++{ ++ register yy_state_type yy_current_state; ++ register char *yy_cp, *yy_bp; ++ register int yy_act; ++ ++#line 63 "prom_lex.l" ++ ++ ++#line 1125 "" ++ ++ if ( !(yy_init) ) ++ { ++ (yy_init) = 1; ++ ++#ifdef YY_USER_INIT ++ YY_USER_INIT; ++#endif ++ ++ if ( ! (yy_start) ) ++ (yy_start) = 1; /* first start state */ ++ ++ if ( ! yyin ) ++ yyin = stdin; ++ ++ if ( ! yyout ) ++ yyout = stdout; ++ ++ if ( ! YY_CURRENT_BUFFER ) { ++ yyensure_buffer_stack (); ++ YY_CURRENT_BUFFER_LVALUE = ++ yy_create_buffer(yyin,YY_BUF_SIZE ); ++ } ++ ++ yy_load_buffer_state( ); ++ } ++ ++ while ( 1 ) /* loops until end-of-file is reached */ ++ { ++ yy_cp = (yy_c_buf_p); ++ ++ /* Support of yytext. */ ++ *yy_cp = (yy_hold_char); ++ ++ /* yy_bp points to the position in yy_ch_buf of the start of ++ * the current run. ++ */ ++ yy_bp = yy_cp; ++ ++ yy_current_state = (yy_start); ++yy_match: ++ do ++ { ++ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; ++ if ( yy_accept[yy_current_state] ) ++ { ++ (yy_last_accepting_state) = yy_current_state; ++ (yy_last_accepting_cpos) = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 444 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ ++yy_cp; ++ } ++ while ( yy_current_state != 443 ); ++ yy_cp = (yy_last_accepting_cpos); ++ yy_current_state = (yy_last_accepting_state); ++ ++yy_find_action: ++ yy_act = yy_accept[yy_current_state]; ++ ++ YY_DO_BEFORE_ACTION; ++ ++do_action: /* This label is used only to access EOF actions. */ ++ ++ switch ( yy_act ) ++ { /* beginning of action switch */ ++ case 0: /* must back up */ ++ /* undo the effects of YY_DO_BEFORE_ACTION */ ++ *yy_cp = (yy_hold_char); ++ yy_cp = (yy_last_accepting_cpos); ++ yy_current_state = (yy_last_accepting_state); ++ goto yy_find_action; ++ ++case 1: ++YY_RULE_SETUP ++#line 65 "prom_lex.l" ++{ upval(CHOSEN); } ++ YY_BREAK ++case 2: ++YY_RULE_SETUP ++#line 66 "prom_lex.l" ++{ upval(VDEVICE); } ++ YY_BREAK ++case 3: ++YY_RULE_SETUP ++#line 67 "prom_lex.l" ++{ upval(VDEVINST); } ++ YY_BREAK ++case 4: ++YY_RULE_SETUP ++#line 68 "prom_lex.l" ++{ upval(VDEVDEV); } ++ YY_BREAK ++case 5: ++YY_RULE_SETUP ++#line 69 "prom_lex.l" ++{ upval(VDEVRAW); } ++ YY_BREAK ++case 6: ++YY_RULE_SETUP ++#line 70 "prom_lex.l" ++{ upval(OBPQUAL); } ++ YY_BREAK ++case 7: ++YY_RULE_SETUP ++#line 71 "prom_lex.l" ++{ upval(BUSNAME); } ++ YY_BREAK ++case 8: ++YY_RULE_SETUP ++#line 72 "prom_lex.l" ++{ upval(IPV4); } ++ YY_BREAK ++case 9: ++YY_RULE_SETUP ++#line 73 "prom_lex.l" ++{ upval(IQN); } ++ YY_BREAK ++case 10: ++YY_RULE_SETUP ++#line 74 "prom_lex.l" ++{ upval(BOOTDEV); } ++ YY_BREAK ++case 11: ++YY_RULE_SETUP ++#line 75 "prom_lex.l" ++{ upval(OBPPARM); } ++ YY_BREAK ++case 12: ++YY_RULE_SETUP ++#line 76 "prom_lex.l" ++{ upval(HEX4); } ++ YY_BREAK ++case 13: ++YY_RULE_SETUP ++#line 77 "prom_lex.l" ++{ upval(HEX16); } ++ YY_BREAK ++case 14: ++YY_RULE_SETUP ++#line 78 "prom_lex.l" ++{ upval(FILENAME); } ++ YY_BREAK ++case 15: ++/* rule 15 can match eol */ ++YY_RULE_SETUP ++#line 79 "prom_lex.l" ++{ /* eat all whitespace. */ ++ yylloc.first_column = yylloc.last_column; ++ yylloc.last_column += yyleng; ++} ++ YY_BREAK ++case 16: ++YY_RULE_SETUP ++#line 83 "prom_lex.l" ++{ /* any other single char. */ ++ dbg("??"); ++ yylloc.first_column = yylloc.last_column; ++ yylloc.last_column += yyleng; ++ return *yytext; ++} ++ YY_BREAK ++case YY_STATE_EOF(INITIAL): ++#line 90 "prom_lex.l" ++yyterminate(); ++ YY_BREAK ++case 17: ++YY_RULE_SETUP ++#line 91 "prom_lex.l" ++ECHO; ++ YY_BREAK ++#line 1302 "" ++ ++ case YY_END_OF_BUFFER: ++ { ++ /* Amount of text matched not including the EOB char. */ ++ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; ++ ++ /* Undo the effects of YY_DO_BEFORE_ACTION. */ ++ *yy_cp = (yy_hold_char); ++ YY_RESTORE_YY_MORE_OFFSET ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) ++ { ++ /* We're scanning a new file or input source. It's ++ * possible that this happened because the user ++ * just pointed yyin at a new source and called ++ * yylex(). If so, then we have to assure ++ * consistency between YY_CURRENT_BUFFER and our ++ * globals. Here is the right place to do so, because ++ * this is the first action (other than possibly a ++ * back-up) that will match for the new input source. ++ */ ++ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; ++ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; ++ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; ++ } ++ ++ /* Note that here we test for yy_c_buf_p "<=" to the position ++ * of the first EOB in the buffer, since yy_c_buf_p will ++ * already have been incremented past the NUL character ++ * (since all states make transitions on EOB to the ++ * end-of-buffer state). Contrast this with the test ++ * in input(). ++ */ ++ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) ++ { /* This was really a NUL. */ ++ yy_state_type yy_next_state; ++ ++ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; ++ ++ yy_current_state = yy_get_previous_state( ); ++ ++ /* Okay, we're now positioned to make the NUL ++ * transition. We couldn't have ++ * yy_get_previous_state() go ahead and do it ++ * for us because it doesn't know how to deal ++ * with the possibility of jamming (and we don't ++ * want to build jamming into it because then it ++ * will run more slowly). ++ */ ++ ++ yy_next_state = yy_try_NUL_trans( yy_current_state ); ++ ++ yy_bp = (yytext_ptr) + YY_MORE_ADJ; ++ ++ if ( yy_next_state ) ++ { ++ /* Consume the NUL. */ ++ yy_cp = ++(yy_c_buf_p); ++ yy_current_state = yy_next_state; ++ goto yy_match; ++ } ++ ++ else ++ { ++ yy_cp = (yy_last_accepting_cpos); ++ yy_current_state = (yy_last_accepting_state); ++ goto yy_find_action; ++ } ++ } ++ ++ else switch ( yy_get_next_buffer( ) ) ++ { ++ case EOB_ACT_END_OF_FILE: ++ { ++ (yy_did_buffer_switch_on_eof) = 0; ++ ++ if ( yywrap( ) ) ++ { ++ /* Note: because we've taken care in ++ * yy_get_next_buffer() to have set up ++ * yytext, we can now set up ++ * yy_c_buf_p so that if some total ++ * hoser (like flex itself) wants to ++ * call the scanner after we return the ++ * YY_NULL, it'll still work - another ++ * YY_NULL will get returned. ++ */ ++ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; ++ ++ yy_act = YY_STATE_EOF(YY_START); ++ goto do_action; ++ } ++ ++ else ++ { ++ if ( ! (yy_did_buffer_switch_on_eof) ) ++ YY_NEW_FILE; ++ } ++ break; ++ } ++ ++ case EOB_ACT_CONTINUE_SCAN: ++ (yy_c_buf_p) = ++ (yytext_ptr) + yy_amount_of_matched_text; ++ ++ yy_current_state = yy_get_previous_state( ); ++ ++ yy_cp = (yy_c_buf_p); ++ yy_bp = (yytext_ptr) + YY_MORE_ADJ; ++ goto yy_match; ++ ++ case EOB_ACT_LAST_MATCH: ++ (yy_c_buf_p) = ++ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; ++ ++ yy_current_state = yy_get_previous_state( ); ++ ++ yy_cp = (yy_c_buf_p); ++ yy_bp = (yytext_ptr) + YY_MORE_ADJ; ++ goto yy_find_action; ++ } ++ break; ++ } ++ ++ default: ++ YY_FATAL_ERROR( ++ "fatal flex scanner internal error--no action found" ); ++ } /* end of action switch */ ++ } /* end of scanning one token */ ++} /* end of yylex */ ++ ++/* yy_get_next_buffer - try to read in a new buffer ++ * ++ * Returns a code representing an action: ++ * EOB_ACT_LAST_MATCH - ++ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position ++ * EOB_ACT_END_OF_FILE - end of file ++ */ ++static int yy_get_next_buffer (void) ++{ ++ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; ++ register char *source = (yytext_ptr); ++ register int number_to_move, i; ++ int ret_val; ++ ++ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) ++ YY_FATAL_ERROR( ++ "fatal flex scanner internal error--end of buffer missed" ); ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) ++ { /* Don't try to fill the buffer, so this is an EOF. */ ++ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) ++ { ++ /* We matched a single character, the EOB, so ++ * treat this as a final EOF. ++ */ ++ return EOB_ACT_END_OF_FILE; ++ } ++ ++ else ++ { ++ /* We matched some text prior to the EOB, first ++ * process it. ++ */ ++ return EOB_ACT_LAST_MATCH; ++ } ++ } ++ ++ /* Try to read more data. */ ++ ++ /* First move last chars to start of buffer. */ ++ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; ++ ++ for ( i = 0; i < number_to_move; ++i ) ++ *(dest++) = *(source++); ++ ++ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) ++ /* don't do the read, it's not guaranteed to return an EOF, ++ * just force an EOF ++ */ ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; ++ ++ else ++ { ++ int num_to_read = ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; ++ ++ while ( num_to_read <= 0 ) ++ { /* Not enough room in the buffer - grow it. */ ++ ++ /* just a shorter name for the current buffer */ ++ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; ++ ++ int yy_c_buf_p_offset = ++ (int) ((yy_c_buf_p) - b->yy_ch_buf); ++ ++ if ( b->yy_is_our_buffer ) ++ { ++ int new_size = b->yy_buf_size * 2; ++ ++ if ( new_size <= 0 ) ++ b->yy_buf_size += b->yy_buf_size / 8; ++ else ++ b->yy_buf_size *= 2; ++ ++ b->yy_ch_buf = (char *) ++ /* Include room in for 2 EOB chars. */ ++ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); ++ } ++ else ++ /* Can't grow it, we don't own it. */ ++ b->yy_ch_buf = 0; ++ ++ if ( ! b->yy_ch_buf ) ++ YY_FATAL_ERROR( ++ "fatal error - scanner input buffer overflow" ); ++ ++ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; ++ ++ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - ++ number_to_move - 1; ++ ++ } ++ ++ if ( num_to_read > YY_READ_BUF_SIZE ) ++ num_to_read = YY_READ_BUF_SIZE; ++ ++ /* Read in more data. */ ++ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), ++ (yy_n_chars), num_to_read ); ++ ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); ++ } ++ ++ if ( (yy_n_chars) == 0 ) ++ { ++ if ( number_to_move == YY_MORE_ADJ ) ++ { ++ ret_val = EOB_ACT_END_OF_FILE; ++ yyrestart(yyin ); ++ } ++ ++ else ++ { ++ ret_val = EOB_ACT_LAST_MATCH; ++ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = ++ YY_BUFFER_EOF_PENDING; ++ } ++ } ++ ++ else ++ ret_val = EOB_ACT_CONTINUE_SCAN; ++ ++ (yy_n_chars) += number_to_move; ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; ++ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; ++ ++ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; ++ ++ return ret_val; ++} ++ ++/* yy_get_previous_state - get the state just before the EOB char was reached */ ++ ++ static yy_state_type yy_get_previous_state (void) ++{ ++ register yy_state_type yy_current_state; ++ register char *yy_cp; ++ ++ yy_current_state = (yy_start); ++ ++ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) ++ { ++ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); ++ if ( yy_accept[yy_current_state] ) ++ { ++ (yy_last_accepting_state) = yy_current_state; ++ (yy_last_accepting_cpos) = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 444 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ } ++ ++ return yy_current_state; ++} ++ ++/* yy_try_NUL_trans - try to make a transition on the NUL character ++ * ++ * synopsis ++ * next_state = yy_try_NUL_trans( current_state ); ++ */ ++ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) ++{ ++ register int yy_is_jam; ++ register char *yy_cp = (yy_c_buf_p); ++ ++ register YY_CHAR yy_c = 1; ++ if ( yy_accept[yy_current_state] ) ++ { ++ (yy_last_accepting_state) = yy_current_state; ++ (yy_last_accepting_cpos) = yy_cp; ++ } ++ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) ++ { ++ yy_current_state = (int) yy_def[yy_current_state]; ++ if ( yy_current_state >= 444 ) ++ yy_c = yy_meta[(unsigned int) yy_c]; ++ } ++ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++ yy_is_jam = (yy_current_state == 443); ++ ++ return yy_is_jam ? 0 : yy_current_state; ++} ++ ++ static void yyunput (int c, register char * yy_bp ) ++{ ++ register char *yy_cp; ++ ++ yy_cp = (yy_c_buf_p); ++ ++ /* undo effects of setting up yytext */ ++ *yy_cp = (yy_hold_char); ++ ++ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) ++ { /* need to shift things up to make room */ ++ /* +2 for EOB chars. */ ++ register int number_to_move = (yy_n_chars) + 2; ++ register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; ++ register char *source = ++ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; ++ ++ while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) ++ *--dest = *--source; ++ ++ yy_cp += (int) (dest - source); ++ yy_bp += (int) (dest - source); ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = ++ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; ++ ++ if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) ++ YY_FATAL_ERROR( "flex scanner push-back overflow" ); ++ } ++ ++ *--yy_cp = (char) c; ++ ++ (yytext_ptr) = yy_bp; ++ (yy_hold_char) = *yy_cp; ++ (yy_c_buf_p) = yy_cp; ++} ++ ++#ifndef YY_NO_INPUT ++#ifdef __cplusplus ++ static int yyinput (void) ++#else ++ static int input (void) ++#endif ++ ++{ ++ int c; ++ ++ *(yy_c_buf_p) = (yy_hold_char); ++ ++ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) ++ { ++ /* yy_c_buf_p now points to the character we want to return. ++ * If this occurs *before* the EOB characters, then it's a ++ * valid NUL; if not, then we've hit the end of the buffer. ++ */ ++ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) ++ /* This was really a NUL. */ ++ *(yy_c_buf_p) = '\0'; ++ ++ else ++ { /* need more input */ ++ int offset = (yy_c_buf_p) - (yytext_ptr); ++ ++(yy_c_buf_p); ++ ++ switch ( yy_get_next_buffer( ) ) ++ { ++ case EOB_ACT_LAST_MATCH: ++ /* This happens because yy_g_n_b() ++ * sees that we've accumulated a ++ * token and flags that we need to ++ * try matching the token before ++ * proceeding. But for input(), ++ * there's no matching to consider. ++ * So convert the EOB_ACT_LAST_MATCH ++ * to EOB_ACT_END_OF_FILE. ++ */ ++ ++ /* Reset buffer status. */ ++ yyrestart(yyin ); ++ ++ /*FALLTHROUGH*/ ++ ++ case EOB_ACT_END_OF_FILE: ++ { ++ if ( yywrap( ) ) ++ return EOF; ++ ++ if ( ! (yy_did_buffer_switch_on_eof) ) ++ YY_NEW_FILE; ++#ifdef __cplusplus ++ return yyinput(); ++#else ++ return input(); ++#endif ++ } ++ ++ case EOB_ACT_CONTINUE_SCAN: ++ (yy_c_buf_p) = (yytext_ptr) + offset; ++ break; ++ } ++ } ++ } ++ ++ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ ++ *(yy_c_buf_p) = '\0'; /* preserve yytext */ ++ (yy_hold_char) = *++(yy_c_buf_p); ++ ++ return c; ++} ++#endif /* ifndef YY_NO_INPUT */ ++ ++/** Immediately switch to a different input stream. ++ * @param input_file A readable stream. ++ * ++ * @note This function does not reset the start condition to @c INITIAL . ++ */ ++ void yyrestart (FILE * input_file ) ++{ ++ ++ if ( ! YY_CURRENT_BUFFER ){ ++ yyensure_buffer_stack (); ++ YY_CURRENT_BUFFER_LVALUE = ++ yy_create_buffer(yyin,YY_BUF_SIZE ); ++ } ++ ++ yy_init_buffer(YY_CURRENT_BUFFER,input_file ); ++ yy_load_buffer_state( ); ++} ++ ++/** Switch to a different input buffer. ++ * @param new_buffer The new input buffer. ++ * ++ */ ++ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) ++{ ++ ++ /* TODO. We should be able to replace this entire function body ++ * with ++ * yypop_buffer_state(); ++ * yypush_buffer_state(new_buffer); ++ */ ++ yyensure_buffer_stack (); ++ if ( YY_CURRENT_BUFFER == new_buffer ) ++ return; ++ ++ if ( YY_CURRENT_BUFFER ) ++ { ++ /* Flush out information for old buffer. */ ++ *(yy_c_buf_p) = (yy_hold_char); ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); ++ } ++ ++ YY_CURRENT_BUFFER_LVALUE = new_buffer; ++ yy_load_buffer_state( ); ++ ++ /* We don't actually know whether we did this switch during ++ * EOF (yywrap()) processing, but the only time this flag ++ * is looked at is after yywrap() is called, so it's safe ++ * to go ahead and always set it. ++ */ ++ (yy_did_buffer_switch_on_eof) = 1; ++} ++ ++static void yy_load_buffer_state (void) ++{ ++ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; ++ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; ++ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; ++ (yy_hold_char) = *(yy_c_buf_p); ++} ++ ++/** Allocate and initialize an input buffer state. ++ * @param file A readable stream. ++ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. ++ * ++ * @return the allocated buffer state. ++ */ ++ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) ++{ ++ YY_BUFFER_STATE b; ++ ++ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); ++ if ( ! b ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); ++ ++ b->yy_buf_size = size; ++ ++ /* yy_ch_buf has to be 2 characters longer than the size given because ++ * we need to put in 2 end-of-buffer characters. ++ */ ++ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); ++ if ( ! b->yy_ch_buf ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); ++ ++ b->yy_is_our_buffer = 1; ++ ++ yy_init_buffer(b,file ); ++ ++ return b; ++} ++ ++/** Destroy the buffer. ++ * @param b a buffer created with yy_create_buffer() ++ * ++ */ ++ void yy_delete_buffer (YY_BUFFER_STATE b ) ++{ ++ ++ if ( ! b ) ++ return; ++ ++ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ ++ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; ++ ++ if ( b->yy_is_our_buffer ) ++ yyfree((void *) b->yy_ch_buf ); ++ ++ yyfree((void *) b ); ++} ++ ++/* Initializes or reinitializes a buffer. ++ * This function is sometimes called more than once on the same buffer, ++ * such as during a yyrestart() or at EOF. ++ */ ++ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) ++ ++{ ++ int oerrno = errno; ++ ++ yy_flush_buffer(b ); ++ ++ b->yy_input_file = file; ++ b->yy_fill_buffer = 1; ++ ++ /* If b is the current buffer, then yy_init_buffer was _probably_ ++ * called from yyrestart() or through yy_get_next_buffer. ++ * In that case, we don't want to reset the lineno or column. ++ */ ++ if (b != YY_CURRENT_BUFFER){ ++ b->yy_bs_lineno = 1; ++ b->yy_bs_column = 0; ++ } ++ ++ b->yy_is_interactive = 0; ++ ++ errno = oerrno; ++} ++ ++/** Discard all buffered characters. On the next scan, YY_INPUT will be called. ++ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. ++ * ++ */ ++ void yy_flush_buffer (YY_BUFFER_STATE b ) ++{ ++ if ( ! b ) ++ return; ++ ++ b->yy_n_chars = 0; ++ ++ /* We always need two end-of-buffer characters. The first causes ++ * a transition to the end-of-buffer state. The second causes ++ * a jam in that state. ++ */ ++ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; ++ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; ++ ++ b->yy_buf_pos = &b->yy_ch_buf[0]; ++ ++ b->yy_at_bol = 1; ++ b->yy_buffer_status = YY_BUFFER_NEW; ++ ++ if ( b == YY_CURRENT_BUFFER ) ++ yy_load_buffer_state( ); ++} ++ ++/** Pushes the new state onto the stack. The new state becomes ++ * the current state. This function will allocate the stack ++ * if necessary. ++ * @param new_buffer The new state. ++ * ++ */ ++void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) ++{ ++ if (new_buffer == NULL) ++ return; ++ ++ yyensure_buffer_stack(); ++ ++ /* This block is copied from yy_switch_to_buffer. */ ++ if ( YY_CURRENT_BUFFER ) ++ { ++ /* Flush out information for old buffer. */ ++ *(yy_c_buf_p) = (yy_hold_char); ++ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); ++ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); ++ } ++ ++ /* Only push if top exists. Otherwise, replace top. */ ++ if (YY_CURRENT_BUFFER) ++ (yy_buffer_stack_top)++; ++ YY_CURRENT_BUFFER_LVALUE = new_buffer; ++ ++ /* copied from yy_switch_to_buffer. */ ++ yy_load_buffer_state( ); ++ (yy_did_buffer_switch_on_eof) = 1; ++} ++ ++/** Removes and deletes the top of the stack, if present. ++ * The next element becomes the new top. ++ * ++ */ ++void yypop_buffer_state (void) ++{ ++ if (!YY_CURRENT_BUFFER) ++ return; ++ ++ yy_delete_buffer(YY_CURRENT_BUFFER ); ++ YY_CURRENT_BUFFER_LVALUE = NULL; ++ if ((yy_buffer_stack_top) > 0) ++ --(yy_buffer_stack_top); ++ ++ if (YY_CURRENT_BUFFER) { ++ yy_load_buffer_state( ); ++ (yy_did_buffer_switch_on_eof) = 1; ++ } ++} ++ ++/* Allocates the stack if it does not exist. ++ * Guarantees space for at least one push. ++ */ ++static void yyensure_buffer_stack (void) ++{ ++ int num_to_alloc; ++ ++ if (!(yy_buffer_stack)) { ++ ++ /* First allocation is just for 2 elements, since we don't know if this ++ * scanner will even need a stack. We use 2 instead of 1 to avoid an ++ * immediate realloc on the next call. ++ */ ++ num_to_alloc = 1; ++ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc ++ (num_to_alloc * sizeof(struct yy_buffer_state*) ++ ); ++ ++ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); ++ ++ (yy_buffer_stack_max) = num_to_alloc; ++ (yy_buffer_stack_top) = 0; ++ return; ++ } ++ ++ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ ++ ++ /* Increase the buffer to prepare for a possible push. */ ++ int grow_size = 8 /* arbitrary grow size */; ++ ++ num_to_alloc = (yy_buffer_stack_max) + grow_size; ++ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ++ ((yy_buffer_stack), ++ num_to_alloc * sizeof(struct yy_buffer_state*) ++ ); ++ ++ /* zero only the new slots.*/ ++ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); ++ (yy_buffer_stack_max) = num_to_alloc; ++ } ++} ++ ++/** Setup the input buffer state to scan directly from a user-specified character buffer. ++ * @param base the character buffer ++ * @param size the size in bytes of the character buffer ++ * ++ * @return the newly allocated buffer state object. ++ */ ++YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) ++{ ++ YY_BUFFER_STATE b; ++ ++ if ( size < 2 || ++ base[size-2] != YY_END_OF_BUFFER_CHAR || ++ base[size-1] != YY_END_OF_BUFFER_CHAR ) ++ /* They forgot to leave room for the EOB's. */ ++ return 0; ++ ++ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); ++ if ( ! b ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); ++ ++ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ ++ b->yy_buf_pos = b->yy_ch_buf = base; ++ b->yy_is_our_buffer = 0; ++ b->yy_input_file = 0; ++ b->yy_n_chars = b->yy_buf_size; ++ b->yy_is_interactive = 0; ++ b->yy_at_bol = 1; ++ b->yy_fill_buffer = 0; ++ b->yy_buffer_status = YY_BUFFER_NEW; ++ ++ yy_switch_to_buffer(b ); ++ ++ return b; ++} ++ ++/** Setup the input buffer state to scan a string. The next call to yylex() will ++ * scan from a @e copy of @a str. ++ * @param str a NUL-terminated string to scan ++ * ++ * @return the newly allocated buffer state object. ++ * @note If you want to scan bytes that may contain NUL values, then use ++ * yy_scan_bytes() instead. ++ */ ++YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) ++{ ++ ++ return yy_scan_bytes(yystr,strlen(yystr) ); ++} ++ ++/** Setup the input buffer state to scan the given bytes. The next call to yylex() will ++ * scan from a @e copy of @a bytes. ++ * @param bytes the byte buffer to scan ++ * @param len the number of bytes in the buffer pointed to by @a bytes. ++ * ++ * @return the newly allocated buffer state object. ++ */ ++YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) ++{ ++ YY_BUFFER_STATE b; ++ char *buf; ++ yy_size_t n; ++ int i; ++ ++ /* Get memory for full buffer, including space for trailing EOB's. */ ++ n = _yybytes_len + 2; ++ buf = (char *) yyalloc(n ); ++ if ( ! buf ) ++ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); ++ ++ for ( i = 0; i < _yybytes_len; ++i ) ++ buf[i] = yybytes[i]; ++ ++ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; ++ ++ b = yy_scan_buffer(buf,n ); ++ if ( ! b ) ++ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); ++ ++ /* It's okay to grow etc. this buffer, and we should throw it ++ * away when we're done. ++ */ ++ b->yy_is_our_buffer = 1; ++ ++ return b; ++} ++ ++#ifndef YY_EXIT_FAILURE ++#define YY_EXIT_FAILURE 2 ++#endif ++ ++static void yy_fatal_error (yyconst char* msg ) ++{ ++ (void) fprintf( stderr, "%s\n", msg ); ++ exit( YY_EXIT_FAILURE ); ++} ++ ++/* Redefine yyless() so it works in section 3 code. */ ++ ++#undef yyless ++#define yyless(n) \ ++ do \ ++ { \ ++ /* Undo effects of setting up yytext. */ \ ++ int yyless_macro_arg = (n); \ ++ YY_LESS_LINENO(yyless_macro_arg);\ ++ yytext[yyleng] = (yy_hold_char); \ ++ (yy_c_buf_p) = yytext + yyless_macro_arg; \ ++ (yy_hold_char) = *(yy_c_buf_p); \ ++ *(yy_c_buf_p) = '\0'; \ ++ yyleng = yyless_macro_arg; \ ++ } \ ++ while ( 0 ) ++ ++/* Accessor methods (get/set functions) to struct members. */ ++ ++/** Get the current line number. ++ * ++ */ ++int yyget_lineno (void) ++{ ++ ++ return yylineno; ++} ++ ++/** Get the input stream. ++ * ++ */ ++FILE *yyget_in (void) ++{ ++ return yyin; ++} ++ ++/** Get the output stream. ++ * ++ */ ++FILE *yyget_out (void) ++{ ++ return yyout; ++} ++ ++/** Get the length of the current token. ++ * ++ */ ++int yyget_leng (void) ++{ ++ return yyleng; ++} ++ ++/** Get the current token. ++ * ++ */ ++ ++char *yyget_text (void) ++{ ++ return yytext; ++} ++ ++/** Set the current line number. ++ * @param line_number ++ * ++ */ ++void yyset_lineno (int line_number ) ++{ ++ ++ yylineno = line_number; ++} ++ ++/** Set the input stream. This does not discard the current ++ * input buffer. ++ * @param in_str A readable stream. ++ * ++ * @see yy_switch_to_buffer ++ */ ++void yyset_in (FILE * in_str ) ++{ ++ yyin = in_str ; ++} ++ ++void yyset_out (FILE * out_str ) ++{ ++ yyout = out_str ; ++} ++ ++int yyget_debug (void) ++{ ++ return yy_flex_debug; ++} ++ ++void yyset_debug (int bdebug ) ++{ ++ yy_flex_debug = bdebug ; ++} ++ ++static int yy_init_globals (void) ++{ ++ /* Initialization is the same as for the non-reentrant scanner. ++ * This function is called from yylex_destroy(), so don't allocate here. ++ */ ++ ++ (yy_buffer_stack) = 0; ++ (yy_buffer_stack_top) = 0; ++ (yy_buffer_stack_max) = 0; ++ (yy_c_buf_p) = (char *) 0; ++ (yy_init) = 0; ++ (yy_start) = 0; ++ ++/* Defined in main.c */ ++#ifdef YY_STDINIT ++ yyin = stdin; ++ yyout = stdout; ++#else ++ yyin = (FILE *) 0; ++ yyout = (FILE *) 0; ++#endif ++ ++ /* For future reference: Set errno on error, since we are called by ++ * yylex_init() ++ */ ++ return 0; ++} ++ ++/* yylex_destroy is for both reentrant and non-reentrant scanners. */ ++int yylex_destroy (void) ++{ ++ ++ /* Pop the buffer stack, destroying each element. */ ++ while(YY_CURRENT_BUFFER){ ++ yy_delete_buffer(YY_CURRENT_BUFFER ); ++ YY_CURRENT_BUFFER_LVALUE = NULL; ++ yypop_buffer_state(); ++ } ++ ++ /* Destroy the stack itself. */ ++ yyfree((yy_buffer_stack) ); ++ (yy_buffer_stack) = NULL; ++ ++ /* Reset the globals. This is important in a non-reentrant scanner so the next time ++ * yylex() is called, initialization will occur. */ ++ yy_init_globals( ); ++ ++ return 0; ++} ++ ++/* ++ * Internal utility routines. ++ */ ++ ++#ifndef yytext_ptr ++static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) ++{ ++ register int i; ++ for ( i = 0; i < n; ++i ) ++ s1[i] = s2[i]; ++} ++#endif ++ ++#ifdef YY_NEED_STRLEN ++static int yy_flex_strlen (yyconst char * s ) ++{ ++ register int n; ++ for ( n = 0; s[n]; ++n ) ++ ; ++ ++ return n; ++} ++#endif ++ ++void *yyalloc (yy_size_t size ) ++{ ++ return (void *) malloc( size ); ++} ++ ++void *yyrealloc (void * ptr, yy_size_t size ) ++{ ++ /* The cast to (char *) in the following accommodates both ++ * implementations that use char* generic pointers, and those ++ * that use void* generic pointers. It works with the latter ++ * because both ANSI C and C++ allow castless assignment from ++ * any pointer type to void*, and deal with argument conversions ++ * as though doing an assignment. ++ */ ++ return (void *) realloc( (char *) ptr, size ); ++} ++ ++void yyfree (void * ptr ) ++{ ++ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ ++} ++ ++#define YYTABLES_NAME "yytables" ++ ++#line 91 "prom_lex.l" ++ ++ ++ diff --git a/utils/fwparam_ibft/prom_lex.l b/utils/fwparam_ibft/prom_lex.l new file mode 100644 index 0000000..208046b @@ -16907,6 +25644,2193 @@ index 0000000..00cffff + + +#endif /* PROM_PARSE_H_ */ +diff --git a/utils/fwparam_ibft/prom_parse.tab.c b/utils/fwparam_ibft/prom_parse.tab.c +new file mode 100644 +index 0000000..1694de4 +--- /dev/null ++++ b/utils/fwparam_ibft/prom_parse.tab.c +@@ -0,0 +1,2069 @@ ++/* A Bison parser, made by GNU Bison 2.3. */ ++ ++/* Skeleton implementation for Bison's Yacc-like parsers in C ++ ++ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 ++ Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ Boston, MA 02110-1301, USA. */ ++ ++/* As a special exception, you may create a larger work that contains ++ part or all of the Bison parser skeleton and distribute that work ++ under terms of your choice, so long as that work isn't itself a ++ parser generator using the skeleton or a modified version thereof ++ as a parser skeleton. Alternatively, if you modify or redistribute ++ the parser skeleton itself, you may (at your option) remove this ++ special exception, which will cause the skeleton and the resulting ++ Bison output files to be licensed under the GNU General Public ++ License without this special exception. ++ ++ This special exception was added by the Free Software Foundation in ++ version 2.2 of Bison. */ ++ ++/* C LALR(1) parser skeleton written by Richard Stallman, by ++ simplifying the original so-called "semantic" parser. */ ++ ++/* All symbols defined below should begin with yy or YY, to avoid ++ infringing on user name space. This should be done even for local ++ variables, as they might otherwise be expanded by user macros. ++ There are some unavoidable exceptions within include files to ++ define necessary library symbols; they are noted "INFRINGES ON ++ USER NAME SPACE" below. */ ++ ++/* Identify Bison output. */ ++#define YYBISON 1 ++ ++/* Bison version. */ ++#define YYBISON_VERSION "2.3" ++ ++/* Skeleton name. */ ++#define YYSKELETON_NAME "yacc.c" ++ ++/* Pure parsers. */ ++#define YYPURE 0 ++ ++/* Using locations. */ ++#define YYLSP_NEEDED 1 ++ ++ ++ ++/* Tokens. */ ++#ifndef YYTOKENTYPE ++# define YYTOKENTYPE ++ /* Put the tokens into the symbol table, so that GDB and other debuggers ++ know about them. */ ++ enum yytokentype { ++ BUSNAME = 258, ++ BOOTDEV = 259, ++ IPV4 = 260, ++ IQN = 261, ++ OBPPARM = 262, ++ OBPQUAL = 263, ++ HEX4 = 264, ++ HEX16 = 265, ++ VDEVICE = 266, ++ VDEVINST = 267, ++ VDEVDEV = 268, ++ VDEVRAW = 269, ++ CHOSEN = 270, ++ FILENAME = 271 ++ }; ++#endif ++/* Tokens. */ ++#define BUSNAME 258 ++#define BOOTDEV 259 ++#define IPV4 260 ++#define IQN 261 ++#define OBPPARM 262 ++#define OBPQUAL 263 ++#define HEX4 264 ++#define HEX16 265 ++#define VDEVICE 266 ++#define VDEVINST 267 ++#define VDEVDEV 268 ++#define VDEVRAW 269 ++#define CHOSEN 270 ++#define FILENAME 271 ++ ++ ++ ++ ++/* Copy the first part of user declarations. */ ++#line 21 "prom_parse.y" ++ ++ /* literal block. include lines, decls, defns. */ ++//#define YYDEBUG 1 ++#if YYDEBUG ++#define DPRINT(fmt,...) printf(fmt,__VA_ARGS__) ++#else ++#define DPRINT(fmt,...) do {} while(0) ++#endif ++#include "prom_parse.h" ++#include "iscsi_obp.h" ++ ++ ++ ++/* Enabling traces. */ ++#ifndef YYDEBUG ++# define YYDEBUG 0 ++#endif ++ ++/* Enabling verbose error messages. */ ++#ifdef YYERROR_VERBOSE ++# undef YYERROR_VERBOSE ++# define YYERROR_VERBOSE 1 ++#else ++# define YYERROR_VERBOSE 0 ++#endif ++ ++/* Enabling the token table. */ ++#ifndef YYTOKEN_TABLE ++# define YYTOKEN_TABLE 0 ++#endif ++ ++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED ++typedef union YYSTYPE ++#line 33 "prom_parse.y" ++{ ++ char str[256]; ++} ++/* Line 187 of yacc.c. */ ++#line 145 "prom_parse.tab.c" ++ YYSTYPE; ++# define yystype YYSTYPE /* obsolescent; will be withdrawn */ ++# define YYSTYPE_IS_DECLARED 1 ++# define YYSTYPE_IS_TRIVIAL 1 ++#endif ++ ++#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED ++typedef struct YYLTYPE ++{ ++ int first_line; ++ int first_column; ++ int last_line; ++ int last_column; ++} YYLTYPE; ++# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ ++# define YYLTYPE_IS_DECLARED 1 ++# define YYLTYPE_IS_TRIVIAL 1 ++#endif ++ ++ ++/* Copy the second part of user declarations. */ ++ ++ ++/* Line 216 of yacc.c. */ ++#line 170 "prom_parse.tab.c" ++ ++#ifdef short ++# undef short ++#endif ++ ++#ifdef YYTYPE_UINT8 ++typedef YYTYPE_UINT8 yytype_uint8; ++#else ++typedef unsigned char yytype_uint8; ++#endif ++ ++#ifdef YYTYPE_INT8 ++typedef YYTYPE_INT8 yytype_int8; ++#elif (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++typedef signed char yytype_int8; ++#else ++typedef short int yytype_int8; ++#endif ++ ++#ifdef YYTYPE_UINT16 ++typedef YYTYPE_UINT16 yytype_uint16; ++#else ++typedef unsigned short int yytype_uint16; ++#endif ++ ++#ifdef YYTYPE_INT16 ++typedef YYTYPE_INT16 yytype_int16; ++#else ++typedef short int yytype_int16; ++#endif ++ ++#ifndef YYSIZE_T ++# ifdef __SIZE_TYPE__ ++# define YYSIZE_T __SIZE_TYPE__ ++# elif defined size_t ++# define YYSIZE_T size_t ++# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++# include /* INFRINGES ON USER NAME SPACE */ ++# define YYSIZE_T size_t ++# else ++# define YYSIZE_T unsigned int ++# endif ++#endif ++ ++#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) ++ ++#ifndef YY_ ++# if YYENABLE_NLS ++# if ENABLE_NLS ++# include /* INFRINGES ON USER NAME SPACE */ ++# define YY_(msgid) dgettext ("bison-runtime", msgid) ++# endif ++# endif ++# ifndef YY_ ++# define YY_(msgid) msgid ++# endif ++#endif ++ ++/* Suppress unused-variable warnings by "using" E. */ ++#if ! defined lint || defined __GNUC__ ++# define YYUSE(e) ((void) (e)) ++#else ++# define YYUSE(e) /* empty */ ++#endif ++ ++/* Identity function, used to suppress warnings about constant conditions. */ ++#ifndef lint ++# define YYID(n) (n) ++#else ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static int ++YYID (int i) ++#else ++static int ++YYID (i) ++ int i; ++#endif ++{ ++ return i; ++} ++#endif ++ ++#if ! defined yyoverflow || YYERROR_VERBOSE ++ ++/* The parser invokes alloca or malloc; define the necessary symbols. */ ++ ++# ifdef YYSTACK_USE_ALLOCA ++# if YYSTACK_USE_ALLOCA ++# ifdef __GNUC__ ++# define YYSTACK_ALLOC __builtin_alloca ++# elif defined __BUILTIN_VA_ARG_INCR ++# include /* INFRINGES ON USER NAME SPACE */ ++# elif defined _AIX ++# define YYSTACK_ALLOC __alloca ++# elif defined _MSC_VER ++# include /* INFRINGES ON USER NAME SPACE */ ++# define alloca _alloca ++# else ++# define YYSTACK_ALLOC alloca ++# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++# include /* INFRINGES ON USER NAME SPACE */ ++# ifndef _STDLIB_H ++# define _STDLIB_H 1 ++# endif ++# endif ++# endif ++# endif ++# endif ++ ++# ifdef YYSTACK_ALLOC ++ /* Pacify GCC's `empty if-body' warning. */ ++# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) ++# ifndef YYSTACK_ALLOC_MAXIMUM ++ /* The OS might guarantee only one guard page at the bottom of the stack, ++ and a page size can be as small as 4096 bytes. So we cannot safely ++ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number ++ to allow for a few compiler-allocated temporary stack slots. */ ++# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ ++# endif ++# else ++# define YYSTACK_ALLOC YYMALLOC ++# define YYSTACK_FREE YYFREE ++# ifndef YYSTACK_ALLOC_MAXIMUM ++# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM ++# endif ++# if (defined __cplusplus && ! defined _STDLIB_H \ ++ && ! ((defined YYMALLOC || defined malloc) \ ++ && (defined YYFREE || defined free))) ++# include /* INFRINGES ON USER NAME SPACE */ ++# ifndef _STDLIB_H ++# define _STDLIB_H 1 ++# endif ++# endif ++# ifndef YYMALLOC ++# define YYMALLOC malloc ++# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ ++# endif ++# endif ++# ifndef YYFREE ++# define YYFREE free ++# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++void free (void *); /* INFRINGES ON USER NAME SPACE */ ++# endif ++# endif ++# endif ++#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ ++ ++ ++#if (! defined yyoverflow \ ++ && (! defined __cplusplus \ ++ || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ ++ && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) ++ ++/* A type that is properly aligned for any stack member. */ ++union yyalloc ++{ ++ yytype_int16 yyss; ++ YYSTYPE yyvs; ++ YYLTYPE yyls; ++}; ++ ++/* The size of the maximum gap between one aligned stack and the next. */ ++# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) ++ ++/* The size of an array large to enough to hold all stacks, each with ++ N elements. */ ++# define YYSTACK_BYTES(N) \ ++ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ ++ + 2 * YYSTACK_GAP_MAXIMUM) ++ ++/* Copy COUNT objects from FROM to TO. The source and destination do ++ not overlap. */ ++# ifndef YYCOPY ++# if defined __GNUC__ && 1 < __GNUC__ ++# define YYCOPY(To, From, Count) \ ++ __builtin_memcpy (To, From, (Count) * sizeof (*(From))) ++# else ++# define YYCOPY(To, From, Count) \ ++ do \ ++ { \ ++ YYSIZE_T yyi; \ ++ for (yyi = 0; yyi < (Count); yyi++) \ ++ (To)[yyi] = (From)[yyi]; \ ++ } \ ++ while (YYID (0)) ++# endif ++# endif ++ ++/* Relocate STACK from its old location to the new one. The ++ local variables YYSIZE and YYSTACKSIZE give the old and new number of ++ elements in the stack, and YYPTR gives the new location of the ++ stack. Advance YYPTR to a properly aligned location for the next ++ stack. */ ++# define YYSTACK_RELOCATE(Stack) \ ++ do \ ++ { \ ++ YYSIZE_T yynewbytes; \ ++ YYCOPY (&yyptr->Stack, Stack, yysize); \ ++ Stack = &yyptr->Stack; \ ++ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ ++ yyptr += yynewbytes / sizeof (*yyptr); \ ++ } \ ++ while (YYID (0)) ++ ++#endif ++ ++/* YYFINAL -- State number of the termination state. */ ++#define YYFINAL 8 ++/* YYLAST -- Last index in YYTABLE. */ ++#define YYLAST 103 ++ ++/* YYNTOKENS -- Number of terminals. */ ++#define YYNTOKENS 24 ++/* YYNNTS -- Number of nonterminals. */ ++#define YYNNTS 19 ++/* YYNRULES -- Number of rules. */ ++#define YYNRULES 51 ++/* YYNRULES -- Number of states. */ ++#define YYNSTATES 93 ++ ++/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ ++#define YYUNDEFTOK 2 ++#define YYMAXUTOK 273 ++ ++#define YYTRANSLATE(YYX) \ ++ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) ++ ++/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ ++static const yytype_uint8 yytranslate[] = ++{ ++ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 19, 2, 2, 17, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 20, 2, ++ 2, 21, 2, 2, 18, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, ++ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, ++ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, ++ 15, 16, 22, 23 ++}; ++ ++#if YYDEBUG ++/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in ++ YYRHS. */ ++static const yytype_uint8 yyprhs[] = ++{ ++ 0, 0, 3, 5, 9, 14, 20, 27, 35, 37, ++ 41, 43, 47, 53, 57, 63, 67, 73, 81, 85, ++ 88, 92, 96, 100, 103, 107, 111, 113, 117, 121, ++ 125, 129, 133, 135, 139, 141, 143, 145, 147, 149, ++ 151, 155, 157, 160, 164, 167, 169, 173, 175, 178, ++ 184, 187 ++}; ++ ++/* YYRHS -- A `-1'-separated list of the rules' RHS. */ ++static const yytype_int8 yyrhs[] = ++{ ++ 25, 0, -1, 17, -1, 17, 26, 28, -1, 17, ++ 26, 28, 41, -1, 17, 26, 28, 34, 32, -1, ++ 17, 26, 28, 34, 32, 41, -1, 17, 29, 28, ++ 30, 34, 32, 41, -1, 27, -1, 26, 17, 27, ++ -1, 3, -1, 3, 18, 9, -1, 3, 18, 9, ++ 19, 9, -1, 3, 18, 10, -1, 3, 19, 9, ++ 18, 10, -1, 17, 4, 20, -1, 17, 4, 18, ++ 9, 20, -1, 17, 4, 18, 9, 19, 9, 20, ++ -1, 11, 17, 12, -1, 20, 31, -1, 30, 19, ++ 31, -1, 30, 19, 14, -1, 13, 21, 15, -1, ++ 19, 33, -1, 32, 19, 33, -1, 32, 19, 41, ++ -1, 9, -1, 7, 21, 10, -1, 7, 21, 36, ++ -1, 7, 21, 6, -1, 7, 21, 9, -1, 7, ++ 21, 16, -1, 35, -1, 34, 19, 35, -1, 8, ++ -1, 31, -1, 37, -1, 38, -1, 5, -1, 39, ++ -1, 39, 20, 37, -1, 40, -1, 39, 22, -1, ++ 39, 22, 40, -1, 22, 40, -1, 9, -1, 40, ++ 23, 9, -1, 42, -1, 9, 42, -1, 18, 9, ++ 19, 9, 42, -1, 20, 9, -1, 20, 9, 19, ++ 16, -1 ++}; ++ ++/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ ++static const yytype_uint16 yyrline[] = ++{ ++ 0, 58, 58, 61, 64, 72, 80, 87, 94, 97, ++ 102, 105, 108, 111, 114, 120, 123, 126, 131, 136, ++ 139, 142, 147, 152, 155, 158, 163, 166, 171, 175, ++ 179, 183, 189, 192, 197, 200, 205, 208, 213, 218, ++ 221, 226, 229, 232, 235, 240, 243, 248, 251, 254, ++ 259, 262 ++}; ++#endif ++ ++#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE ++/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. ++ First, the terminals, then, starting at YYNTOKENS, nonterminals. */ ++static const char *const yytname[] = ++{ ++ "$end", "error", "$undefined", "BUSNAME", "BOOTDEV", "IPV4", "IQN", ++ "OBPPARM", "OBPQUAL", "HEX4", "HEX16", "VDEVICE", "VDEVINST", "VDEVDEV", ++ "VDEVRAW", "CHOSEN", "FILENAME", "'/'", "'@'", "','", "':'", "'='", ++ "\"::\"", "\":\"", "$accept", "devpath", "busses", "bus", "bootdev", ++ "vdevice", "vdev_parms", "vdev_parm", "obp_params", "obp_param", ++ "obp_quals", "obp_qual", "ipaddr", "ipv4", "ipv6", "hexpart", "hexseq", ++ "disklabel", "diskpart", 0 ++}; ++#endif ++ ++# ifdef YYPRINT ++/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to ++ token YYLEX-NUM. */ ++static const yytype_uint16 yytoknum[] = ++{ ++ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, ++ 265, 266, 267, 268, 269, 270, 271, 47, 64, 44, ++ 58, 61, 272, 273 ++}; ++# endif ++ ++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ ++static const yytype_uint8 yyr1[] = ++{ ++ 0, 24, 25, 25, 25, 25, 25, 25, 26, 26, ++ 27, 27, 27, 27, 27, 28, 28, 28, 29, 30, ++ 30, 30, 31, 32, 32, 32, 33, 33, 33, 33, ++ 33, 33, 34, 34, 35, 35, 36, 36, 37, 38, ++ 38, 39, 39, 39, 39, 40, 40, 41, 41, 41, ++ 42, 42 ++}; ++ ++/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ ++static const yytype_uint8 yyr2[] = ++{ ++ 0, 2, 1, 3, 4, 5, 6, 7, 1, 3, ++ 1, 3, 5, 3, 5, 3, 5, 7, 3, 2, ++ 3, 3, 3, 2, 3, 3, 1, 3, 3, 3, ++ 3, 3, 1, 3, 1, 1, 1, 1, 1, 1, ++ 3, 1, 2, 3, 2, 1, 3, 1, 2, 5, ++ 2, 4 ++}; ++ ++/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state ++ STATE-NUM when YYTABLE doesn't specify something else to do. Zero ++ means the default is an error. */ ++static const yytype_uint8 yydefact[] = ++{ ++ 0, 2, 0, 10, 0, 0, 8, 0, 1, 0, ++ 0, 0, 0, 3, 0, 0, 11, 13, 0, 18, ++ 0, 9, 34, 0, 0, 0, 0, 35, 0, 32, ++ 4, 47, 0, 0, 0, 0, 0, 15, 48, 0, ++ 0, 50, 0, 5, 19, 0, 0, 12, 14, 0, ++ 22, 0, 0, 0, 26, 23, 33, 0, 6, 21, ++ 20, 0, 0, 16, 0, 51, 0, 26, 24, 25, ++ 7, 0, 49, 38, 29, 30, 27, 31, 0, 28, ++ 36, 37, 39, 41, 17, 45, 44, 0, 42, 0, ++ 40, 43, 46 ++}; ++ ++/* YYDEFGOTO[NTERM-NUM]. */ ++static const yytype_int8 yydefgoto[] = ++{ ++ -1, 2, 5, 6, 13, 7, 33, 27, 43, 55, ++ 28, 29, 79, 80, 81, 82, 83, 30, 31 ++}; ++ ++/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing ++ STATE-NUM. */ ++#define YYPACT_NINF -73 ++static const yytype_int8 yypact[] = ++{ ++ -15, 19, 13, 20, 18, 23, -73, 25, -73, 39, ++ 51, 50, 49, 16, 46, 43, 42, -73, 47, -73, ++ -9, -73, -73, 44, 45, 58, 59, -73, 52, -73, ++ -73, -73, 56, 24, 61, 62, 64, -73, -73, 60, ++ 55, 57, 38, 8, -73, 41, 52, -73, -73, 37, ++ -73, 68, 63, 65, -73, -73, -73, 3, -73, -73, ++ -73, 8, 69, -73, 44, -73, -2, 44, -73, -73, ++ -73, 67, -73, -73, -73, 36, -73, -73, 71, -73, ++ -73, -73, 11, 66, -73, -73, 66, 76, 71, 73, ++ -73, 66, -73 ++}; ++ ++/* YYPGOTO[NTERM-NUM]. */ ++static const yytype_int8 yypgoto[] = ++{ ++ -73, -73, -73, 72, 78, -73, -73, -27, 48, 26, ++ 70, 53, -73, 1, -73, -73, -72, -42, -23 ++}; ++ ++/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If ++ positive, shift that token. If negative, reduce the rule which ++ number is the opposite. If zero, do what YYDEFACT says. ++ If YYTABLE_NINF, syntax error. */ ++#define YYTABLE_NINF -46 ++static const yytype_int8 yytable[] = ++{ ++ 38, 58, 1, 73, 74, 44, 86, 75, 76, 36, ++ 53, 37, 67, 8, 77, 69, 91, 23, 60, 70, ++ 78, 25, 3, 26, 22, 23, 25, 57, 26, 24, ++ 4, 87, 22, 88, 25, 11, 26, 24, 9, 10, ++ 12, 72, 14, 45, 38, 53, 22, 54, 16, 17, ++ 20, 24, 3, 20, 24, 59, 62, 63, -45, -45, ++ 18, 34, 19, 32, 26, 35, 39, 40, 41, 24, ++ 47, 42, 48, 49, 51, 50, 52, 64, 71, 65, ++ 85, 73, 92, 68, 21, 15, 66, 84, 90, 89, ++ 0, 0, 0, 0, 61, 56, 0, 0, 0, 0, ++ 0, 0, 0, 46 ++}; ++ ++static const yytype_int8 yycheck[] = ++{ ++ 23, 43, 17, 5, 6, 32, 78, 9, 10, 18, ++ 7, 20, 9, 0, 16, 57, 88, 9, 45, 61, ++ 22, 18, 3, 20, 8, 9, 18, 19, 20, 13, ++ 11, 20, 8, 22, 18, 17, 20, 13, 18, 19, ++ 17, 64, 17, 19, 67, 7, 8, 9, 9, 10, ++ 4, 13, 3, 4, 13, 14, 19, 20, 22, 23, ++ 9, 19, 12, 20, 20, 18, 21, 9, 9, 13, ++ 9, 19, 10, 9, 19, 15, 19, 9, 9, 16, ++ 9, 5, 9, 57, 12, 7, 21, 20, 87, 23, ++ -1, -1, -1, -1, 46, 42, -1, -1, -1, -1, ++ -1, -1, -1, 33 ++}; ++ ++/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing ++ symbol of state STATE-NUM. */ ++static const yytype_uint8 yystos[] = ++{ ++ 0, 17, 25, 3, 11, 26, 27, 29, 0, 18, ++ 19, 17, 17, 28, 17, 28, 9, 10, 9, 12, ++ 4, 27, 8, 9, 13, 18, 20, 31, 34, 35, ++ 41, 42, 20, 30, 19, 18, 18, 20, 42, 21, ++ 9, 9, 19, 32, 31, 19, 34, 9, 10, 9, ++ 15, 19, 19, 7, 9, 33, 35, 19, 41, 14, ++ 31, 32, 19, 20, 9, 16, 21, 9, 33, 41, ++ 41, 9, 42, 5, 6, 9, 10, 16, 22, 36, ++ 37, 38, 39, 40, 20, 9, 40, 20, 22, 23, ++ 37, 40, 9 ++}; ++ ++#define yyerrok (yyerrstatus = 0) ++#define yyclearin (yychar = YYEMPTY) ++#define YYEMPTY (-2) ++#define YYEOF 0 ++ ++#define YYACCEPT goto yyacceptlab ++#define YYABORT goto yyabortlab ++#define YYERROR goto yyerrorlab ++ ++ ++/* Like YYERROR except do call yyerror. This remains here temporarily ++ to ease the transition to the new meaning of YYERROR, for GCC. ++ Once GCC version 2 has supplanted version 1, this can go. */ ++ ++#define YYFAIL goto yyerrlab ++ ++#define YYRECOVERING() (!!yyerrstatus) ++ ++#define YYBACKUP(Token, Value) \ ++do \ ++ if (yychar == YYEMPTY && yylen == 1) \ ++ { \ ++ yychar = (Token); \ ++ yylval = (Value); \ ++ yytoken = YYTRANSLATE (yychar); \ ++ YYPOPSTACK (1); \ ++ goto yybackup; \ ++ } \ ++ else \ ++ { \ ++ yyerror (ofwdev, YY_("syntax error: cannot back up")); \ ++ YYERROR; \ ++ } \ ++while (YYID (0)) ++ ++ ++#define YYTERROR 1 ++#define YYERRCODE 256 ++ ++ ++/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. ++ If N is 0, then set CURRENT to the empty location which ends ++ the previous symbol: RHS[0] (always defined). */ ++ ++#define YYRHSLOC(Rhs, K) ((Rhs)[K]) ++#ifndef YYLLOC_DEFAULT ++# define YYLLOC_DEFAULT(Current, Rhs, N) \ ++ do \ ++ if (YYID (N)) \ ++ { \ ++ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ ++ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ ++ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ ++ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ ++ } \ ++ else \ ++ { \ ++ (Current).first_line = (Current).last_line = \ ++ YYRHSLOC (Rhs, 0).last_line; \ ++ (Current).first_column = (Current).last_column = \ ++ YYRHSLOC (Rhs, 0).last_column; \ ++ } \ ++ while (YYID (0)) ++#endif ++ ++ ++/* YY_LOCATION_PRINT -- Print the location on the stream. ++ This macro was not mandated originally: define only if we know ++ we won't break user code: when these are the locations we know. */ ++ ++#ifndef YY_LOCATION_PRINT ++# if YYLTYPE_IS_TRIVIAL ++# define YY_LOCATION_PRINT(File, Loc) \ ++ fprintf (File, "%d.%d-%d.%d", \ ++ (Loc).first_line, (Loc).first_column, \ ++ (Loc).last_line, (Loc).last_column) ++# else ++# define YY_LOCATION_PRINT(File, Loc) ((void) 0) ++# endif ++#endif ++ ++ ++/* YYLEX -- calling `yylex' with the right arguments. */ ++ ++#ifdef YYLEX_PARAM ++# define YYLEX yylex (YYLEX_PARAM) ++#else ++# define YYLEX yylex () ++#endif ++ ++/* Enable debugging if requested. */ ++#if YYDEBUG ++ ++# ifndef YYFPRINTF ++# include /* INFRINGES ON USER NAME SPACE */ ++# define YYFPRINTF fprintf ++# endif ++ ++# define YYDPRINTF(Args) \ ++do { \ ++ if (yydebug) \ ++ YYFPRINTF Args; \ ++} while (YYID (0)) ++ ++# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ ++do { \ ++ if (yydebug) \ ++ { \ ++ YYFPRINTF (stderr, "%s ", Title); \ ++ yy_symbol_print (stderr, \ ++ Type, Value, Location, ofwdev); \ ++ YYFPRINTF (stderr, "\n"); \ ++ } \ ++} while (YYID (0)) ++ ++ ++/*--------------------------------. ++| Print this symbol on YYOUTPUT. | ++`--------------------------------*/ ++ ++/*ARGSUSED*/ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static void ++yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct ofw_dev *ofwdev) ++#else ++static void ++yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, ofwdev) ++ FILE *yyoutput; ++ int yytype; ++ YYSTYPE const * const yyvaluep; ++ YYLTYPE const * const yylocationp; ++ struct ofw_dev *ofwdev; ++#endif ++{ ++ if (!yyvaluep) ++ return; ++ YYUSE (yylocationp); ++ YYUSE (ofwdev); ++# ifdef YYPRINT ++ if (yytype < YYNTOKENS) ++ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); ++# else ++ YYUSE (yyoutput); ++# endif ++ switch (yytype) ++ { ++ default: ++ break; ++ } ++} ++ ++ ++/*--------------------------------. ++| Print this symbol on YYOUTPUT. | ++`--------------------------------*/ ++ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static void ++yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, struct ofw_dev *ofwdev) ++#else ++static void ++yy_symbol_print (yyoutput, yytype, yyvaluep, yylocationp, ofwdev) ++ FILE *yyoutput; ++ int yytype; ++ YYSTYPE const * const yyvaluep; ++ YYLTYPE const * const yylocationp; ++ struct ofw_dev *ofwdev; ++#endif ++{ ++ if (yytype < YYNTOKENS) ++ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); ++ else ++ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); ++ ++ YY_LOCATION_PRINT (yyoutput, *yylocationp); ++ YYFPRINTF (yyoutput, ": "); ++ yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, ofwdev); ++ YYFPRINTF (yyoutput, ")"); ++} ++ ++/*------------------------------------------------------------------. ++| yy_stack_print -- Print the state stack from its BOTTOM up to its | ++| TOP (included). | ++`------------------------------------------------------------------*/ ++ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static void ++yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) ++#else ++static void ++yy_stack_print (bottom, top) ++ yytype_int16 *bottom; ++ yytype_int16 *top; ++#endif ++{ ++ YYFPRINTF (stderr, "Stack now"); ++ for (; bottom <= top; ++bottom) ++ YYFPRINTF (stderr, " %d", *bottom); ++ YYFPRINTF (stderr, "\n"); ++} ++ ++# define YY_STACK_PRINT(Bottom, Top) \ ++do { \ ++ if (yydebug) \ ++ yy_stack_print ((Bottom), (Top)); \ ++} while (YYID (0)) ++ ++ ++/*------------------------------------------------. ++| Report that the YYRULE is going to be reduced. | ++`------------------------------------------------*/ ++ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static void ++yy_reduce_print (YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, struct ofw_dev *ofwdev) ++#else ++static void ++yy_reduce_print (yyvsp, yylsp, yyrule, ofwdev) ++ YYSTYPE *yyvsp; ++ YYLTYPE *yylsp; ++ int yyrule; ++ struct ofw_dev *ofwdev; ++#endif ++{ ++ int yynrhs = yyr2[yyrule]; ++ int yyi; ++ unsigned long int yylno = yyrline[yyrule]; ++ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", ++ yyrule - 1, yylno); ++ /* The symbols being reduced. */ ++ for (yyi = 0; yyi < yynrhs; yyi++) ++ { ++ fprintf (stderr, " $%d = ", yyi + 1); ++ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], ++ &(yyvsp[(yyi + 1) - (yynrhs)]) ++ , &(yylsp[(yyi + 1) - (yynrhs)]) , ofwdev); ++ fprintf (stderr, "\n"); ++ } ++} ++ ++# define YY_REDUCE_PRINT(Rule) \ ++do { \ ++ if (yydebug) \ ++ yy_reduce_print (yyvsp, yylsp, Rule, ofwdev); \ ++} while (YYID (0)) ++ ++/* Nonzero means print parse trace. It is left uninitialized so that ++ multiple parsers can coexist. */ ++int yydebug; ++#else /* !YYDEBUG */ ++# define YYDPRINTF(Args) ++# define YY_SYMBOL_PRINT(Title, Type, Value, Location) ++# define YY_STACK_PRINT(Bottom, Top) ++# define YY_REDUCE_PRINT(Rule) ++#endif /* !YYDEBUG */ ++ ++ ++/* YYINITDEPTH -- initial size of the parser's stacks. */ ++#ifndef YYINITDEPTH ++# define YYINITDEPTH 200 ++#endif ++ ++/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only ++ if the built-in stack extension method is used). ++ ++ Do not make this value too large; the results are undefined if ++ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) ++ evaluated with infinite-precision integer arithmetic. */ ++ ++#ifndef YYMAXDEPTH ++# define YYMAXDEPTH 10000 ++#endif ++ ++ ++ ++#if YYERROR_VERBOSE ++ ++# ifndef yystrlen ++# if defined __GLIBC__ && defined _STRING_H ++# define yystrlen strlen ++# else ++/* Return the length of YYSTR. */ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static YYSIZE_T ++yystrlen (const char *yystr) ++#else ++static YYSIZE_T ++yystrlen (yystr) ++ const char *yystr; ++#endif ++{ ++ YYSIZE_T yylen; ++ for (yylen = 0; yystr[yylen]; yylen++) ++ continue; ++ return yylen; ++} ++# endif ++# endif ++ ++# ifndef yystpcpy ++# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE ++# define yystpcpy stpcpy ++# else ++/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in ++ YYDEST. */ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static char * ++yystpcpy (char *yydest, const char *yysrc) ++#else ++static char * ++yystpcpy (yydest, yysrc) ++ char *yydest; ++ const char *yysrc; ++#endif ++{ ++ char *yyd = yydest; ++ const char *yys = yysrc; ++ ++ while ((*yyd++ = *yys++) != '\0') ++ continue; ++ ++ return yyd - 1; ++} ++# endif ++# endif ++ ++# ifndef yytnamerr ++/* Copy to YYRES the contents of YYSTR after stripping away unnecessary ++ quotes and backslashes, so that it's suitable for yyerror. The ++ heuristic is that double-quoting is unnecessary unless the string ++ contains an apostrophe, a comma, or backslash (other than ++ backslash-backslash). YYSTR is taken from yytname. If YYRES is ++ null, do not copy; instead, return the length of what the result ++ would have been. */ ++static YYSIZE_T ++yytnamerr (char *yyres, const char *yystr) ++{ ++ if (*yystr == '"') ++ { ++ YYSIZE_T yyn = 0; ++ char const *yyp = yystr; ++ ++ for (;;) ++ switch (*++yyp) ++ { ++ case '\'': ++ case ',': ++ goto do_not_strip_quotes; ++ ++ case '\\': ++ if (*++yyp != '\\') ++ goto do_not_strip_quotes; ++ /* Fall through. */ ++ default: ++ if (yyres) ++ yyres[yyn] = *yyp; ++ yyn++; ++ break; ++ ++ case '"': ++ if (yyres) ++ yyres[yyn] = '\0'; ++ return yyn; ++ } ++ do_not_strip_quotes: ; ++ } ++ ++ if (! yyres) ++ return yystrlen (yystr); ++ ++ return yystpcpy (yyres, yystr) - yyres; ++} ++# endif ++ ++/* Copy into YYRESULT an error message about the unexpected token ++ YYCHAR while in state YYSTATE. Return the number of bytes copied, ++ including the terminating null byte. If YYRESULT is null, do not ++ copy anything; just return the number of bytes that would be ++ copied. As a special case, return 0 if an ordinary "syntax error" ++ message will do. Return YYSIZE_MAXIMUM if overflow occurs during ++ size calculation. */ ++static YYSIZE_T ++yysyntax_error (char *yyresult, int yystate, int yychar) ++{ ++ int yyn = yypact[yystate]; ++ ++ if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) ++ return 0; ++ else ++ { ++ int yytype = YYTRANSLATE (yychar); ++ YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); ++ YYSIZE_T yysize = yysize0; ++ YYSIZE_T yysize1; ++ int yysize_overflow = 0; ++ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; ++ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; ++ int yyx; ++ ++# if 0 ++ /* This is so xgettext sees the translatable formats that are ++ constructed on the fly. */ ++ YY_("syntax error, unexpected %s"); ++ YY_("syntax error, unexpected %s, expecting %s"); ++ YY_("syntax error, unexpected %s, expecting %s or %s"); ++ YY_("syntax error, unexpected %s, expecting %s or %s or %s"); ++ YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); ++# endif ++ char *yyfmt; ++ char const *yyf; ++ static char const yyunexpected[] = "syntax error, unexpected %s"; ++ static char const yyexpecting[] = ", expecting %s"; ++ static char const yyor[] = " or %s"; ++ char yyformat[sizeof yyunexpected ++ + sizeof yyexpecting - 1 ++ + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) ++ * (sizeof yyor - 1))]; ++ char const *yyprefix = yyexpecting; ++ ++ /* Start YYX at -YYN if negative to avoid negative indexes in ++ YYCHECK. */ ++ int yyxbegin = yyn < 0 ? -yyn : 0; ++ ++ /* Stay within bounds of both yycheck and yytname. */ ++ int yychecklim = YYLAST - yyn + 1; ++ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; ++ int yycount = 1; ++ ++ yyarg[0] = yytname[yytype]; ++ yyfmt = yystpcpy (yyformat, yyunexpected); ++ ++ for (yyx = yyxbegin; yyx < yyxend; ++yyx) ++ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) ++ { ++ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) ++ { ++ yycount = 1; ++ yysize = yysize0; ++ yyformat[sizeof yyunexpected - 1] = '\0'; ++ break; ++ } ++ yyarg[yycount++] = yytname[yyx]; ++ yysize1 = yysize + yytnamerr (0, yytname[yyx]); ++ yysize_overflow |= (yysize1 < yysize); ++ yysize = yysize1; ++ yyfmt = yystpcpy (yyfmt, yyprefix); ++ yyprefix = yyor; ++ } ++ ++ yyf = YY_(yyformat); ++ yysize1 = yysize + yystrlen (yyf); ++ yysize_overflow |= (yysize1 < yysize); ++ yysize = yysize1; ++ ++ if (yysize_overflow) ++ return YYSIZE_MAXIMUM; ++ ++ if (yyresult) ++ { ++ /* Avoid sprintf, as that infringes on the user's name space. ++ Don't have undefined behavior even if the translation ++ produced a string with the wrong number of "%s"s. */ ++ char *yyp = yyresult; ++ int yyi = 0; ++ while ((*yyp = *yyf) != '\0') ++ { ++ if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) ++ { ++ yyp += yytnamerr (yyp, yyarg[yyi++]); ++ yyf += 2; ++ } ++ else ++ { ++ yyp++; ++ yyf++; ++ } ++ } ++ } ++ return yysize; ++ } ++} ++#endif /* YYERROR_VERBOSE */ ++ ++ ++/*-----------------------------------------------. ++| Release the memory associated to this symbol. | ++`-----------------------------------------------*/ ++ ++/*ARGSUSED*/ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++static void ++yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, struct ofw_dev *ofwdev) ++#else ++static void ++yydestruct (yymsg, yytype, yyvaluep, yylocationp, ofwdev) ++ const char *yymsg; ++ int yytype; ++ YYSTYPE *yyvaluep; ++ YYLTYPE *yylocationp; ++ struct ofw_dev *ofwdev; ++#endif ++{ ++ YYUSE (yyvaluep); ++ YYUSE (yylocationp); ++ YYUSE (ofwdev); ++ ++ if (!yymsg) ++ yymsg = "Deleting"; ++ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); ++ ++ switch (yytype) ++ { ++ ++ default: ++ break; ++ } ++} ++ ++ ++/* Prevent warnings from -Wmissing-prototypes. */ ++ ++#ifdef YYPARSE_PARAM ++#if defined __STDC__ || defined __cplusplus ++int yyparse (void *YYPARSE_PARAM); ++#else ++int yyparse (); ++#endif ++#else /* ! YYPARSE_PARAM */ ++#if defined __STDC__ || defined __cplusplus ++int yyparse (struct ofw_dev *ofwdev); ++#else ++int yyparse (); ++#endif ++#endif /* ! YYPARSE_PARAM */ ++ ++ ++ ++/* The look-ahead symbol. */ ++int yychar; ++ ++/* The semantic value of the look-ahead symbol. */ ++YYSTYPE yylval; ++ ++/* Number of syntax errors so far. */ ++int yynerrs; ++/* Location data for the look-ahead symbol. */ ++YYLTYPE yylloc; ++ ++ ++ ++/*----------. ++| yyparse. | ++`----------*/ ++ ++#ifdef YYPARSE_PARAM ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++int ++yyparse (void *YYPARSE_PARAM) ++#else ++int ++yyparse (YYPARSE_PARAM) ++ void *YYPARSE_PARAM; ++#endif ++#else /* ! YYPARSE_PARAM */ ++#if (defined __STDC__ || defined __C99__FUNC__ \ ++ || defined __cplusplus || defined _MSC_VER) ++int ++yyparse (struct ofw_dev *ofwdev) ++#else ++int ++yyparse (ofwdev) ++ struct ofw_dev *ofwdev; ++#endif ++#endif ++{ ++ ++ int yystate; ++ int yyn; ++ int yyresult; ++ /* Number of tokens to shift before error messages enabled. */ ++ int yyerrstatus; ++ /* Look-ahead token as an internal (translated) token number. */ ++ int yytoken = 0; ++#if YYERROR_VERBOSE ++ /* Buffer for error messages, and its allocated size. */ ++ char yymsgbuf[128]; ++ char *yymsg = yymsgbuf; ++ YYSIZE_T yymsg_alloc = sizeof yymsgbuf; ++#endif ++ ++ /* Three stacks and their tools: ++ `yyss': related to states, ++ `yyvs': related to semantic values, ++ `yyls': related to locations. ++ ++ Refer to the stacks thru separate pointers, to allow yyoverflow ++ to reallocate them elsewhere. */ ++ ++ /* The state stack. */ ++ yytype_int16 yyssa[YYINITDEPTH]; ++ yytype_int16 *yyss = yyssa; ++ yytype_int16 *yyssp; ++ ++ /* The semantic value stack. */ ++ YYSTYPE yyvsa[YYINITDEPTH]; ++ YYSTYPE *yyvs = yyvsa; ++ YYSTYPE *yyvsp; ++ ++ /* The location stack. */ ++ YYLTYPE yylsa[YYINITDEPTH]; ++ YYLTYPE *yyls = yylsa; ++ YYLTYPE *yylsp; ++ /* The locations where the error started and ended. */ ++ YYLTYPE yyerror_range[2]; ++ ++#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) ++ ++ YYSIZE_T yystacksize = YYINITDEPTH; ++ ++ /* The variables used to return semantic value and location from the ++ action routines. */ ++ YYSTYPE yyval; ++ YYLTYPE yyloc; ++ ++ /* The number of symbols on the RHS of the reduced rule. ++ Keep to zero when no symbol should be popped. */ ++ int yylen = 0; ++ ++ YYDPRINTF ((stderr, "Starting parse\n")); ++ ++ yystate = 0; ++ yyerrstatus = 0; ++ yynerrs = 0; ++ yychar = YYEMPTY; /* Cause a token to be read. */ ++ ++ /* Initialize stack pointers. ++ Waste one element of value and location stack ++ so that they stay on the same level as the state stack. ++ The wasted elements are never initialized. */ ++ ++ yyssp = yyss; ++ yyvsp = yyvs; ++ yylsp = yyls; ++#if YYLTYPE_IS_TRIVIAL ++ /* Initialize the default location before parsing starts. */ ++ yylloc.first_line = yylloc.last_line = 1; ++ yylloc.first_column = yylloc.last_column = 0; ++#endif ++ ++ goto yysetstate; ++ ++/*------------------------------------------------------------. ++| yynewstate -- Push a new state, which is found in yystate. | ++`------------------------------------------------------------*/ ++ yynewstate: ++ /* In all cases, when you get here, the value and location stacks ++ have just been pushed. So pushing a state here evens the stacks. */ ++ yyssp++; ++ ++ yysetstate: ++ *yyssp = yystate; ++ ++ if (yyss + yystacksize - 1 <= yyssp) ++ { ++ /* Get the current used size of the three stacks, in elements. */ ++ YYSIZE_T yysize = yyssp - yyss + 1; ++ ++#ifdef yyoverflow ++ { ++ /* Give user a chance to reallocate the stack. Use copies of ++ these so that the &'s don't force the real ones into ++ memory. */ ++ YYSTYPE *yyvs1 = yyvs; ++ yytype_int16 *yyss1 = yyss; ++ YYLTYPE *yyls1 = yyls; ++ ++ /* Each stack pointer address is followed by the size of the ++ data in use in that stack, in bytes. This used to be a ++ conditional around just the two extra args, but that might ++ be undefined if yyoverflow is a macro. */ ++ yyoverflow (YY_("memory exhausted"), ++ &yyss1, yysize * sizeof (*yyssp), ++ &yyvs1, yysize * sizeof (*yyvsp), ++ &yyls1, yysize * sizeof (*yylsp), ++ &yystacksize); ++ yyls = yyls1; ++ yyss = yyss1; ++ yyvs = yyvs1; ++ } ++#else /* no yyoverflow */ ++# ifndef YYSTACK_RELOCATE ++ goto yyexhaustedlab; ++# else ++ /* Extend the stack our own way. */ ++ if (YYMAXDEPTH <= yystacksize) ++ goto yyexhaustedlab; ++ yystacksize *= 2; ++ if (YYMAXDEPTH < yystacksize) ++ yystacksize = YYMAXDEPTH; ++ ++ { ++ yytype_int16 *yyss1 = yyss; ++ union yyalloc *yyptr = ++ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); ++ if (! yyptr) ++ goto yyexhaustedlab; ++ YYSTACK_RELOCATE (yyss); ++ YYSTACK_RELOCATE (yyvs); ++ YYSTACK_RELOCATE (yyls); ++# undef YYSTACK_RELOCATE ++ if (yyss1 != yyssa) ++ YYSTACK_FREE (yyss1); ++ } ++# endif ++#endif /* no yyoverflow */ ++ ++ yyssp = yyss + yysize - 1; ++ yyvsp = yyvs + yysize - 1; ++ yylsp = yyls + yysize - 1; ++ ++ YYDPRINTF ((stderr, "Stack size increased to %lu\n", ++ (unsigned long int) yystacksize)); ++ ++ if (yyss + yystacksize - 1 <= yyssp) ++ YYABORT; ++ } ++ ++ YYDPRINTF ((stderr, "Entering state %d\n", yystate)); ++ ++ goto yybackup; ++ ++/*-----------. ++| yybackup. | ++`-----------*/ ++yybackup: ++ ++ /* Do appropriate processing given the current state. Read a ++ look-ahead token if we need one and don't already have one. */ ++ ++ /* First try to decide what to do without reference to look-ahead token. */ ++ yyn = yypact[yystate]; ++ if (yyn == YYPACT_NINF) ++ goto yydefault; ++ ++ /* Not known => get a look-ahead token if don't already have one. */ ++ ++ /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ ++ if (yychar == YYEMPTY) ++ { ++ YYDPRINTF ((stderr, "Reading a token: ")); ++ yychar = YYLEX; ++ } ++ ++ if (yychar <= YYEOF) ++ { ++ yychar = yytoken = YYEOF; ++ YYDPRINTF ((stderr, "Now at end of input.\n")); ++ } ++ else ++ { ++ yytoken = YYTRANSLATE (yychar); ++ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); ++ } ++ ++ /* If the proper action on seeing token YYTOKEN is to reduce or to ++ detect an error, take that action. */ ++ yyn += yytoken; ++ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) ++ goto yydefault; ++ yyn = yytable[yyn]; ++ if (yyn <= 0) ++ { ++ if (yyn == 0 || yyn == YYTABLE_NINF) ++ goto yyerrlab; ++ yyn = -yyn; ++ goto yyreduce; ++ } ++ ++ if (yyn == YYFINAL) ++ YYACCEPT; ++ ++ /* Count tokens shifted since error; after three, turn off error ++ status. */ ++ if (yyerrstatus) ++ yyerrstatus--; ++ ++ /* Shift the look-ahead token. */ ++ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); ++ ++ /* Discard the shifted token unless it is eof. */ ++ if (yychar != YYEOF) ++ yychar = YYEMPTY; ++ ++ yystate = yyn; ++ *++yyvsp = yylval; ++ *++yylsp = yylloc; ++ goto yynewstate; ++ ++ ++/*-----------------------------------------------------------. ++| yydefault -- do the default action for the current state. | ++`-----------------------------------------------------------*/ ++yydefault: ++ yyn = yydefact[yystate]; ++ if (yyn == 0) ++ goto yyerrlab; ++ goto yyreduce; ++ ++ ++/*-----------------------------. ++| yyreduce -- Do a reduction. | ++`-----------------------------*/ ++yyreduce: ++ /* yyn is the number of a rule to reduce with. */ ++ yylen = yyr2[yyn]; ++ ++ /* If YYLEN is nonzero, implement the default value of the action: ++ `$$ = $1'. ++ ++ Otherwise, the following line sets YYVAL to garbage. ++ This behavior is undocumented and Bison ++ users should not rely upon it. Assigning to YYVAL ++ unconditionally makes the parser a bit smaller, and it avoids a ++ GCC warning that YYVAL may be used uninitialized. */ ++ yyval = yyvsp[1-yylen]; ++ ++ /* Default location. */ ++ YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); ++ YY_REDUCE_PRINT (yyn); ++ switch (yyn) ++ { ++ case 2: ++#line 58 "prom_parse.y" ++ { ++ DPRINT("****rootonly: \"%s\"\n", "/"); ++ ;} ++ break; ++ ++ case 3: ++#line 61 "prom_parse.y" ++ { ++ DPRINT("****devpath busses:\n/%s/%s\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 4: ++#line 64 "prom_parse.y" ++ { ++ ofwdev->dev_path = malloc(strlen((yyvsp[(2) - (4)].str)) + ++ strlen((yyvsp[(3) - (4)].str)) + 3); ++ sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str)); ++ DPRINT("****devpath busses bootdev " ++ "disklabel:\n/%s/%s%s\n", ++ (yyvsp[(2) - (4)].str), (yyvsp[(3) - (4)].str), (yyvsp[(4) - (4)].str)); ++ ;} ++ break; ++ ++ case 5: ++#line 72 "prom_parse.y" ++ { ++ ofwdev->dev_path = malloc(strlen((yyvsp[(2) - (5)].str)) + ++ strlen((yyvsp[(3) - (5)].str)) + 3); ++ sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[(2) - (5)].str), (yyvsp[(3) - (5)].str)); ++ DPRINT("****busses bootdev obp_quals obp_parms:\n" ++ "/%s/%s:%s%s\n", ++ (yyvsp[(2) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(4) - (5)].str), (yyvsp[(5) - (5)].str)); ++ ;} ++ break; ++ ++ case 6: ++#line 80 "prom_parse.y" ++ { ++ ofwdev->dev_path = malloc(strlen((yyvsp[(2) - (6)].str)) + ++ strlen((yyvsp[(3) - (6)].str)) + 3); ++ sprintf(ofwdev->dev_path, "/%s%s", (yyvsp[(2) - (6)].str), (yyvsp[(3) - (6)].str)); ++ DPRINT("****busses bootdev obp_quals obp_parms " ++ "disklabel:\n/%s:%s%s%s\n", (yyvsp[(2) - (6)].str), (yyvsp[(4) - (6)].str), (yyvsp[(5) - (6)].str), (yyvsp[(6) - (6)].str)); ++ ;} ++ break; ++ ++ case 7: ++#line 87 "prom_parse.y" ++ { ++ DPRINT("****vdevice bootdev obp_parms " ++ "disklabel:\n/%s:%s%s%s%s\n", ++ (yyvsp[(2) - (7)].str), (yyvsp[(4) - (7)].str), (yyvsp[(5) - (7)].str), (yyvsp[(6) - (7)].str), (yyvsp[(7) - (7)].str)); ++ ;} ++ break; ++ ++ case 8: ++#line 94 "prom_parse.y" ++ { ++ strcpy((yyval.str), (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 9: ++#line 97 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s/%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 10: ++#line 102 "prom_parse.y" ++ { ++ strcpy((yyval.str), (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 11: ++#line 105 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s@%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 12: ++#line 108 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s@%s,%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)); ++ ;} ++ break; ++ ++ case 13: ++#line 111 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s@%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 14: ++#line 114 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s@%s", (yyvsp[(1) - (5)].str), (yyvsp[(3) - (5)].str), (yyvsp[(5) - (5)].str)); ++ ;} ++ break; ++ ++ case 15: ++#line 120 "prom_parse.y" ++ { ++ sprintf((yyval.str), "/%s", (yyvsp[(2) - (3)].str)); ++ ;} ++ break; ++ ++ case 16: ++#line 123 "prom_parse.y" ++ { ++ sprintf((yyval.str), "/%s@%s", (yyvsp[(2) - (5)].str), (yyvsp[(4) - (5)].str)); ++ ;} ++ break; ++ ++ case 17: ++#line 126 "prom_parse.y" ++ { ++ sprintf((yyval.str), "/%s@%s,%s", (yyvsp[(2) - (7)].str), (yyvsp[(4) - (7)].str), (yyvsp[(6) - (7)].str)); ++ ;} ++ break; ++ ++ case 18: ++#line 131 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s/%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 19: ++#line 136 "prom_parse.y" ++ { ++ sprintf((yyval.str), ":%s", (yyvsp[(2) - (2)].str)); ++ ;} ++ break; ++ ++ case 20: ++#line 139 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 21: ++#line 142 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 22: ++#line 147 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 23: ++#line 152 "prom_parse.y" ++ { ++ sprintf((yyval.str), ",%s", (yyvsp[(2) - (2)].str)); ++ ;} ++ break; ++ ++ case 24: ++#line 155 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 25: ++#line 158 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 26: ++#line 163 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 27: ++#line 166 "prom_parse.y" ++ { ++ /* luns > 0 are the SAM-3+ hex representation. */ ++ obp_parm_hexnum(ofwdev, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 28: ++#line 171 "prom_parse.y" ++ { ++ obp_parm_addr(ofwdev, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 29: ++#line 175 "prom_parse.y" ++ { ++ obp_parm_iqn(ofwdev, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 30: ++#line 179 "prom_parse.y" ++ { ++ obp_parm_hexnum(ofwdev, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 31: ++#line 183 "prom_parse.y" ++ { ++ obp_parm_str(ofwdev, (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ sprintf((yyval.str), "%s=%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 32: ++#line 189 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 33: ++#line 192 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s,%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 34: ++#line 197 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", obp_qual_set(ofwdev, (yyvsp[(1) - (1)].str))); ++ ;} ++ break; ++ ++ case 35: ++#line 200 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 36: ++#line 205 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 37: ++#line 208 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 38: ++#line 213 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 39: ++#line 218 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 40: ++#line 221 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 41: ++#line 226 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 42: ++#line 229 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s::", (yyvsp[(1) - (2)].str)); ++ ;} ++ break; ++ ++ case 43: ++#line 232 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s::%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 44: ++#line 235 "prom_parse.y" ++ { ++ sprintf((yyval.str), "::%s", (yyvsp[(2) - (2)].str)); ++ ;} ++ break; ++ ++ case 45: ++#line 240 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 46: ++#line 243 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s:%s", (yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].str)); ++ ;} ++ break; ++ ++ case 47: ++#line 248 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s", (yyvsp[(1) - (1)].str)); ++ ;} ++ break; ++ ++ case 48: ++#line 251 "prom_parse.y" ++ { ++ sprintf((yyval.str), "%s%s", (yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].str)); ++ ;} ++ break; ++ ++ case 49: ++#line 254 "prom_parse.y" ++ { ++ sprintf((yyval.str), "@%s,%s%s", (yyvsp[(2) - (5)].str), (yyvsp[(4) - (5)].str), (yyvsp[(5) - (5)].str)); ++ ;} ++ break; ++ ++ case 50: ++#line 259 "prom_parse.y" ++ { ++ sprintf((yyval.str), ":%s", (yyvsp[(2) - (2)].str)); ++ ;} ++ break; ++ ++ case 51: ++#line 262 "prom_parse.y" ++ { ++ sprintf((yyval.str), ":%s,%s", (yyvsp[(2) - (4)].str), (yyvsp[(4) - (4)].str)); ++ ;} ++ break; ++ ++ ++/* Line 1267 of yacc.c. */ ++#line 1848 "prom_parse.tab.c" ++ default: break; ++ } ++ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); ++ ++ YYPOPSTACK (yylen); ++ yylen = 0; ++ YY_STACK_PRINT (yyss, yyssp); ++ ++ *++yyvsp = yyval; ++ *++yylsp = yyloc; ++ ++ /* Now `shift' the result of the reduction. Determine what state ++ that goes to, based on the state we popped back to and the rule ++ number reduced by. */ ++ ++ yyn = yyr1[yyn]; ++ ++ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; ++ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) ++ yystate = yytable[yystate]; ++ else ++ yystate = yydefgoto[yyn - YYNTOKENS]; ++ ++ goto yynewstate; ++ ++ ++/*------------------------------------. ++| yyerrlab -- here on detecting error | ++`------------------------------------*/ ++yyerrlab: ++ /* If not already recovering from an error, report this error. */ ++ if (!yyerrstatus) ++ { ++ ++yynerrs; ++#if ! YYERROR_VERBOSE ++ yyerror (ofwdev, YY_("syntax error")); ++#else ++ { ++ YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); ++ if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) ++ { ++ YYSIZE_T yyalloc = 2 * yysize; ++ if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) ++ yyalloc = YYSTACK_ALLOC_MAXIMUM; ++ if (yymsg != yymsgbuf) ++ YYSTACK_FREE (yymsg); ++ yymsg = (char *) YYSTACK_ALLOC (yyalloc); ++ if (yymsg) ++ yymsg_alloc = yyalloc; ++ else ++ { ++ yymsg = yymsgbuf; ++ yymsg_alloc = sizeof yymsgbuf; ++ } ++ } ++ ++ if (0 < yysize && yysize <= yymsg_alloc) ++ { ++ (void) yysyntax_error (yymsg, yystate, yychar); ++ yyerror (ofwdev, yymsg); ++ } ++ else ++ { ++ yyerror (ofwdev, YY_("syntax error")); ++ if (yysize != 0) ++ goto yyexhaustedlab; ++ } ++ } ++#endif ++ } ++ ++ yyerror_range[0] = yylloc; ++ ++ if (yyerrstatus == 3) ++ { ++ /* If just tried and failed to reuse look-ahead token after an ++ error, discard it. */ ++ ++ if (yychar <= YYEOF) ++ { ++ /* Return failure if at end of input. */ ++ if (yychar == YYEOF) ++ YYABORT; ++ } ++ else ++ { ++ yydestruct ("Error: discarding", ++ yytoken, &yylval, &yylloc, ofwdev); ++ yychar = YYEMPTY; ++ } ++ } ++ ++ /* Else will try to reuse look-ahead token after shifting the error ++ token. */ ++ goto yyerrlab1; ++ ++ ++/*---------------------------------------------------. ++| yyerrorlab -- error raised explicitly by YYERROR. | ++`---------------------------------------------------*/ ++yyerrorlab: ++ ++ /* Pacify compilers like GCC when the user code never invokes ++ YYERROR and the label yyerrorlab therefore never appears in user ++ code. */ ++ if (/*CONSTCOND*/ 0) ++ goto yyerrorlab; ++ ++ yyerror_range[0] = yylsp[1-yylen]; ++ /* Do not reclaim the symbols of the rule which action triggered ++ this YYERROR. */ ++ YYPOPSTACK (yylen); ++ yylen = 0; ++ YY_STACK_PRINT (yyss, yyssp); ++ yystate = *yyssp; ++ goto yyerrlab1; ++ ++ ++/*-------------------------------------------------------------. ++| yyerrlab1 -- common code for both syntax error and YYERROR. | ++`-------------------------------------------------------------*/ ++yyerrlab1: ++ yyerrstatus = 3; /* Each real token shifted decrements this. */ ++ ++ for (;;) ++ { ++ yyn = yypact[yystate]; ++ if (yyn != YYPACT_NINF) ++ { ++ yyn += YYTERROR; ++ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) ++ { ++ yyn = yytable[yyn]; ++ if (0 < yyn) ++ break; ++ } ++ } ++ ++ /* Pop the current state because it cannot handle the error token. */ ++ if (yyssp == yyss) ++ YYABORT; ++ ++ yyerror_range[0] = *yylsp; ++ yydestruct ("Error: popping", ++ yystos[yystate], yyvsp, yylsp, ofwdev); ++ YYPOPSTACK (1); ++ yystate = *yyssp; ++ YY_STACK_PRINT (yyss, yyssp); ++ } ++ ++ if (yyn == YYFINAL) ++ YYACCEPT; ++ ++ *++yyvsp = yylval; ++ ++ yyerror_range[1] = yylloc; ++ /* Using YYLLOC is tempting, but would change the location of ++ the look-ahead. YYLOC is available though. */ ++ YYLLOC_DEFAULT (yyloc, (yyerror_range - 1), 2); ++ *++yylsp = yyloc; ++ ++ /* Shift the error token. */ ++ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); ++ ++ yystate = yyn; ++ goto yynewstate; ++ ++ ++/*-------------------------------------. ++| yyacceptlab -- YYACCEPT comes here. | ++`-------------------------------------*/ ++yyacceptlab: ++ yyresult = 0; ++ goto yyreturn; ++ ++/*-----------------------------------. ++| yyabortlab -- YYABORT comes here. | ++`-----------------------------------*/ ++yyabortlab: ++ yyresult = 1; ++ goto yyreturn; ++ ++#ifndef yyoverflow ++/*-------------------------------------------------. ++| yyexhaustedlab -- memory exhaustion comes here. | ++`-------------------------------------------------*/ ++yyexhaustedlab: ++ yyerror (ofwdev, YY_("memory exhausted")); ++ yyresult = 2; ++ /* Fall through. */ ++#endif ++ ++yyreturn: ++ if (yychar != YYEOF && yychar != YYEMPTY) ++ yydestruct ("Cleanup: discarding lookahead", ++ yytoken, &yylval, &yylloc, ofwdev); ++ /* Do not reclaim the symbols of the rule which action triggered ++ this YYABORT or YYACCEPT. */ ++ YYPOPSTACK (yylen); ++ YY_STACK_PRINT (yyss, yyssp); ++ while (yyssp != yyss) ++ { ++ yydestruct ("Cleanup: popping", ++ yystos[*yyssp], yyvsp, yylsp, ofwdev); ++ YYPOPSTACK (1); ++ } ++#ifndef yyoverflow ++ if (yyss != yyssa) ++ YYSTACK_FREE (yyss); ++#endif ++#if YYERROR_VERBOSE ++ if (yymsg != yymsgbuf) ++ YYSTACK_FREE (yymsg); ++#endif ++ /* Make sure YYID is used. */ ++ return YYID (yyresult); ++} ++ ++ ++#line 267 "prom_parse.y" ++ ++ +diff --git a/utils/fwparam_ibft/prom_parse.tab.h b/utils/fwparam_ibft/prom_parse.tab.h +new file mode 100644 +index 0000000..d161994 +--- /dev/null ++++ b/utils/fwparam_ibft/prom_parse.tab.h +@@ -0,0 +1,106 @@ ++/* A Bison parser, made by GNU Bison 2.3. */ ++ ++/* Skeleton interface for Bison's Yacc-like parsers in C ++ ++ Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 ++ Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2, or (at your option) ++ any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, ++ Boston, MA 02110-1301, USA. */ ++ ++/* As a special exception, you may create a larger work that contains ++ part or all of the Bison parser skeleton and distribute that work ++ under terms of your choice, so long as that work isn't itself a ++ parser generator using the skeleton or a modified version thereof ++ as a parser skeleton. Alternatively, if you modify or redistribute ++ the parser skeleton itself, you may (at your option) remove this ++ special exception, which will cause the skeleton and the resulting ++ Bison output files to be licensed under the GNU General Public ++ License without this special exception. ++ ++ This special exception was added by the Free Software Foundation in ++ version 2.2 of Bison. */ ++ ++/* Tokens. */ ++#ifndef YYTOKENTYPE ++# define YYTOKENTYPE ++ /* Put the tokens into the symbol table, so that GDB and other debuggers ++ know about them. */ ++ enum yytokentype { ++ BUSNAME = 258, ++ BOOTDEV = 259, ++ IPV4 = 260, ++ IQN = 261, ++ OBPPARM = 262, ++ OBPQUAL = 263, ++ HEX4 = 264, ++ HEX16 = 265, ++ VDEVICE = 266, ++ VDEVINST = 267, ++ VDEVDEV = 268, ++ VDEVRAW = 269, ++ CHOSEN = 270, ++ FILENAME = 271 ++ }; ++#endif ++/* Tokens. */ ++#define BUSNAME 258 ++#define BOOTDEV 259 ++#define IPV4 260 ++#define IQN 261 ++#define OBPPARM 262 ++#define OBPQUAL 263 ++#define HEX4 264 ++#define HEX16 265 ++#define VDEVICE 266 ++#define VDEVINST 267 ++#define VDEVDEV 268 ++#define VDEVRAW 269 ++#define CHOSEN 270 ++#define FILENAME 271 ++ ++ ++ ++ ++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED ++typedef union YYSTYPE ++#line 33 "prom_parse.y" ++{ ++ char str[256]; ++} ++/* Line 1489 of yacc.c. */ ++#line 85 "prom_parse.tab.h" ++ YYSTYPE; ++# define yystype YYSTYPE /* obsolescent; will be withdrawn */ ++# define YYSTYPE_IS_DECLARED 1 ++# define YYSTYPE_IS_TRIVIAL 1 ++#endif ++ ++extern YYSTYPE yylval; ++ ++#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED ++typedef struct YYLTYPE ++{ ++ int first_line; ++ int first_column; ++ int last_line; ++ int last_column; ++} YYLTYPE; ++# define yyltype YYLTYPE /* obsolescent; will be withdrawn */ ++# define YYLTYPE_IS_DECLARED 1 ++# define YYLTYPE_IS_TRIVIAL 1 ++#endif ++ ++extern YYLTYPE yylloc; diff --git a/utils/fwparam_ibft/prom_parse.y b/utils/fwparam_ibft/prom_parse.y new file mode 100644 index 0000000..23302d7 @@ -17180,3 +28104,191 @@ index 0000000..23302d7 + ; + +%% +diff --git a/utils/iscsi_discovery b/utils/iscsi_discovery +old mode 100644 +new mode 100755 +index 7c7083f..9f1e7cf +--- a/utils/iscsi_discovery ++++ b/utils/iscsi_discovery +@@ -24,45 +24,84 @@ + # * tries to login + # * if succeeds, + # o logout, +-# o mark record autmatic ++# o mark record autmatic + # * else + # o reset transport type to TCP + # o try to login + # o if succeeded + # + logout +-# + mark record automatic ++# + mark record automatic + # + ++usage() ++{ ++ echo "Usage: $0 [-p ] [-d] [-t [-f]] [-m] [-l]" ++ echo "Options:" ++ echo "-p set the port number (defualt is 3260)." ++ echo "-d print debugging information" ++ echo "-t set trasnpot (default is tcp)." ++ echo "-f force specific transport -disable the fallback to tcp (default is fallback enabled)." ++ echo " force the transport specified by the argument of the -t flag." ++ echo "-m manual startup - will set manual startup (default is automatic startup)." ++ echo "-l login to the new discovered nodes (defualt is false)." ++} ++ + dbg() + { +- $debug || echo $@ ++ $debug && echo $@ + } + + initialize() + { + trap "exit" 2 +- usage="Usage: $0 [-d] []" + debug=false ++ force="0" ++ log_out="1" ++ startup_manual="0" ++ #set defualt transport to tcp ++ transport=tcp ++ #set defualt port to 3260 ++ port=3260; + } + + parse_cmdline() + { +- if [ "$1" = "-d" ]; then +- debug=true +- shift +- fi + if [ $# -lt 1 ]; then +- echo ${usage} ++ usage + exit 1 + fi + +- ip=$1 +- port=${2:-3260} ++ # check if the IP address is valid ++ ip=`echo $1 | awk -F'.' '$1 != "" && $1 <=255 && $2 != "" && $2 <= 255 && $3 != "" && $3 <= 255 && $4 != "" && $4 <= 255 {print $0}'` ++ if [ -z "$ip" ]; then ++ echo "$1 is not a vaild IP address!" ++ exit 1 ++ fi ++ shift ++ while getopts "dfmlt:p:" options; do ++ case $options in ++ d ) debug=true;; ++ f ) force="1";; ++ t ) transport=$OPTARG;; ++ p ) port=$OPTARG;; ++ m ) startup_manual="1";; ++ l ) log_out=0;; ++ \? ) usage ++ exit 1;; ++ * ) usage ++ exit 1;; ++ esac ++ done + } + +- + discover() + { ++ # If open-iscsi is already logged in to the portal, exit ++ if [ $(iscsiadm -m session | grep -c ${ip}:${port}) -ne 0 ]; then ++ echo "Please logout from all targets on ${ip}:${port} before trying to run discovery on that portal" ++ exit 2 ++ fi ++ + connected=0 + discovered=0 + df=/tmp/discovered.$$ +@@ -79,21 +118,28 @@ discover() + if [ ${discovered} = 0 ]; then + echo "failed to discover targets at ${ip}" + exit 2 +- else +- echo "discovered ${discovered} targets at ${ip}, connected to ${connected}" ++ else ++ echo "discovered ${discovered} targets at ${ip}" + fi + /bin/rm -f ${df} + } + +-set_auto_if_login() ++try_login() + { ++ if [ "$startup_manual" != "1" ]; then ++ iscsiadm -m node --targetname ${target} --portal ${portal} --op update -n node.conn[0].startup -v automatic ++ fi + iscsiadm -m node --targetname ${target} --portal ${portal} --login >/dev/null 2>&1 + ret=$? + if [ ${ret} = 0 ]; then +- iscsiadm -m node --targetname ${target} --portal ${portal} --logout +- iscsiadm -m node --targetname ${target} --portal ${portal} --op update -n node.conn[0].startup -v automatic + echo "Set target ${target} to automatic login over ${transport} to portal ${portal}" + ((connected++)) ++ if [ "$log_out" = "1" ]; then ++ iscsiadm -m node --targetname ${target} --portal ${portal} --logout ++ fi ++ else ++ echo "Cannot login over ${transport} to portal ${portal}" ++ iscsiadm -m node --targetname ${target} --portal ${portal} --op update -n node.conn[0].startup -v manual + fi + return ${ret} + } +@@ -101,24 +147,42 @@ set_auto_if_login() + set_transport() + { + transport=$1 ++ if [ "$transport" == "iser" ];then ++ iscsiadm -m node --targetname ${target} --portal ${portal} \ ++ --op update -n node.conn[0].iscsi.HeaderDigest -v None ++ iscsiadm -m node --targetname ${target} --portal ${portal} \ ++ --op update -n node.conn[0].iscsi.DataDigest -v None ++ fi ++ transport_name=`iscsiadm -m node -p ${portal} -T ${target} |awk '/transport_name/ {print $1}'` + iscsiadm -m node --targetname ${target} --portal ${portal} \ +- --op update -n node.conn[0].iscsi.HeaderDigest -v None +- iscsiadm -m node --targetname ${target} --portal ${portal} \ +- --op update -n node.transport_name -v ${transport} ++ --op update -n ${transport_name} -v ${transport} + } + + select_transport() + { +- set_transport iser +- dbg "Testing iser-login to target ${target} portal ${portal}" +- set_auto_if_login +- if [ $? != 0 ]; then ++ set_transport $transport ++ dbg "Testing $transport-login to target ${target} portal ${portal}" ++ try_login; ++ if [ $? != 0 -a "$force" = "0" ]; then + set_transport tcp + dbg "starting to test tcp-login to target ${target} portal ${portal}" +- set_auto_if_login ++ try_login; ++ fi ++} ++ ++check_iscsid() ++{ ++ #check if iscsid is running ++ pidof iscsid &>/dev/null ++ ret=$? ++ if [ $ret -ne 0 ]; then ++ echo "iscsid is not running" ++ echo "Exiting..." ++ exit 1 + fi + } + ++check_iscsid + initialize + parse_cmdline "$@" + discover diff --git a/open-iscsi-ibft-scan-memory-area b/open-iscsi-ibft-scan-memory-area new file mode 100644 index 0000000..f496eed --- /dev/null +++ b/open-iscsi-ibft-scan-memory-area @@ -0,0 +1,48 @@ +commit a58c90313743e5e1614aa8a0522d6a441dc79ed3 +Author: Hannes Reinecke +Date: Mon Apr 21 11:28:25 2008 +0200 + + Scan Memory area for iBFT correctly + + The iBFT might be constructed in the main memory area, too. + For this we don't have a ROM header, so we have to skip the + checks for this, too. + + Signed-off-by: Hannes Reinecke + +diff --git a/utils/fwparam_ibft/fwparam_ibft.c b/utils/fwparam_ibft/fwparam_ibft.c +index dc0fc6b..84502bb 100644 +--- a/utils/fwparam_ibft/fwparam_ibft.c ++++ b/utils/fwparam_ibft/fwparam_ibft.c +@@ -502,18 +502,24 @@ char *search_ibft(unsigned char *start, int start_addr, int length) + { + unsigned char *cur_ptr, *rom_end; + struct ibft_table_hdr *ibft_hdr; +- unsigned char check_sum, rom_size; ++ unsigned char check_sum; ++ short rom_size = -1; + uint32_t i; + + cur_ptr = (unsigned char *)start; + while (cur_ptr < (start + length)) { +- if (memcmp(cur_ptr, ID_ROMEXT, strlen(ID_ROMEXT)) != 0) { +- /* Skip this block */ +- cur_ptr += 512; +- continue; ++ if (rom_size < 0) { ++ /* Scan the upper memory area */ ++ rom_size = 256; ++ } else { ++ /* Scan extenions in the ROM area */ ++ if (memcmp(cur_ptr, ID_ROMEXT, strlen(ID_ROMEXT)) != 0) { ++ /* Skip this block */ ++ cur_ptr += 512; ++ continue; ++ } ++ memcpy(&rom_size, cur_ptr + 2, 1); + } +- memcpy(&rom_size, cur_ptr + 2, 1); +- + if (debug > 1) + fprintf(stderr, "Found rom at %x of size %d\n", + ((int)(cur_ptr - start) + start_addr), diff --git a/open-iscsi-umount-all-luns b/open-iscsi-umount-all-luns deleted file mode 100644 index 1874452..0000000 --- a/open-iscsi-umount-all-luns +++ /dev/null @@ -1,61 +0,0 @@ -diff --git a/etc/initd/initd.suse b/etc/initd/initd.suse -index 6d4cbd8..ce9fa70 100644 ---- a/etc/initd/initd.suse -+++ b/etc/initd/initd.suse -@@ -77,6 +77,39 @@ iscsi_logout_all_nodes() - return ${RETVAL:-0} - } - -+iscsi_umount_all_luns() -+{ -+ local d m dev p s -+ -+ cat /proc/mounts | sed -ne '/^\/dev\/.*/p' | while read d m t o x; do -+ if [ "$m" = "/" ] ; then -+ continue; -+ fi -+ if [ -L "$d" ] ; then -+ d=$(readlink -f $d) -+ fi -+ dev=${d##/dev} -+ -+ if [ "${dev##/sd}" = "$dev" ] ; then -+ continue; -+ fi -+ p="/sys/block${dev%%[0-9]*}" -+ -+ if [ ! -d ${p} ] && [ ! -d ${p}/device ] ; then -+ continue; -+ fi -+ -+ s=$(cd -P ${p}/device && echo $PWD) -+ -+ case "$s" in -+ */session[0-9]*/*) -+ # This is an iSCSI device -+ umount "$m" -+ ;; -+ esac -+ done -+} -+ - iscsi_list_all_nodes() - { - TARGETS=$($ISCSIADM -m session | sed 's@\[[^:]*:\(.*\)\] .*@\1@g') -@@ -110,6 +143,7 @@ case "$1" in - fi - ;; - stop) -+ iscsi_umount_all_luns - if iscsi_logout_all_nodes ; then - killproc -KILL $DAEMON - RETVAL=$? -diff --git a/include/iscsi_if.h b/include/iscsi_if.h -diff --git a/kernel/iscsi_tcp.c b/kernel/iscsi_tcp.c -diff --git a/kernel/libiscsi.c b/kernel/libiscsi.c -diff --git a/kernel/libiscsi.h b/kernel/libiscsi.h -diff --git a/kernel/scsi_transport_iscsi.c b/kernel/scsi_transport_iscsi.c -diff --git a/usr/discovery.c b/usr/discovery.c -diff --git a/usr/initiator.c b/usr/initiator.c -diff --git a/usr/initiator.h b/usr/initiator.h -diff --git a/usr/iscsid.c b/usr/iscsid.c diff --git a/open-iscsi.changes b/open-iscsi.changes index b53a810..5e9570a 100644 --- a/open-iscsi.changes +++ b/open-iscsi.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Tue Apr 29 09:06:07 CEST 2008 - hare@suse.de + +- Pull in fixes from upstream git repository + +------------------------------------------------------------------- +Mon Apr 21 11:30:28 CEST 2008 - hare@suse.de + +- Scan memory area for iBFT correctly (bnc#378837) + ------------------------------------------------------------------- Tue Apr 15 13:47:21 CEST 2008 - hare@suse.de diff --git a/open-iscsi.spec b/open-iscsi.spec index 308ad04..0568c36 100644 --- a/open-iscsi.spec +++ b/open-iscsi.spec @@ -1,5 +1,5 @@ # -# spec file for package open-iscsi (Version 2.0.865) +# spec file for package open-iscsi (Version 2.0.869) # # Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany. # This file and all modifications and additions to the pristine @@ -18,7 +18,7 @@ License: GPL v2 or later Group: Productivity/Networking/Other PreReq: %fillup_prereq %insserv_prereq AutoReqProv: on -Version: 2.0.865 +Version: 2.0.869 Release: 1 Provides: linux-iscsi Obsoletes: linux-iscsi @@ -28,25 +28,17 @@ Source: %{name}-2.0-865.tar.bz2 Source11: iscsi-gen-initiatorname.sh Patch1: %{name}-866.diff Patch2: %{name}-git-update -Patch3: %{name}-add-discovery-ops -Patch4: %{name}-add-suse-boot-script Patch5: %{name}-format-luns Patch22: %{name}-fwparam-scan-in-blocks -Patch23: %{name}-umount-all-luns Patch24: %{name}-update-nodes -Patch25: %{name}-fixup-init-script -Patch26: %{name}-discover-all-targets -Patch28: %{name}-fixup-debug-option Patch30: %{name}-backport-fwparam_ibft Patch31: %{name}-fix-suse-build Patch32: %{name}-ibft-fill-initiator-values Patch33: %{name}-ibft-print-ifspec -Patch34: %{name}-dont-fail-init-script-on-stop -Patch35: %{name}-check-logmsg-length -Patch36: %{name}-cleanup-IPC Patch37: %{name}-print-ibft-error-to-stderr Patch38: %{name}-teardown-device-stack Patch39: %{name}-fwparam_ppc-string-overflow +Patch40: %{name}-ibft-scan-memory-area BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -78,25 +70,17 @@ Authors: %setup -n %{name}-2.0-865 %patch1 %patch2 -p1 -%patch3 -p1 -%patch4 -p1 %patch5 -p1 %patch22 -p1 -%patch23 -p1 %patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch28 -p1 %patch30 -p1 %patch31 -p1 %patch32 -p1 %patch33 -p1 -%patch34 -p1 -%patch35 -p1 -%patch36 -p1 %patch37 -p1 %patch38 -p1 %patch39 -p1 +%patch40 -p1 cp etc/iface.example . %build @@ -137,6 +121,10 @@ fi %doc %{_mandir}/man8/* %changelog +* Tue Apr 29 2008 hare@suse.de +- Pull in fixes from upstream git repository +* Mon Apr 21 2008 hare@suse.de +- Scan memory area for iBFT correctly (bnc#378837) * Tue Apr 15 2008 hare@suse.de - Synchronize with SLES10 SP2 * Thu Apr 10 2008 hare@suse.de