X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fscsi_transport_iscsi.c;h=ea3892e7e0f76a46ef219c12e97b23e13abe326e;hb=e794c01b7de40d180417eacbd910e8f31f2fafeb;hp=0ce5f7cdfe2a182a1e4216377e58476b6e2f1809;hpb=315cb0ad124575e75da2d0e0a95990587fc23485;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 0ce5f7c..ea3892e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -30,14 +30,45 @@ #include #include -#define ISCSI_SESSION_ATTRS 21 +#define ISCSI_SESSION_ATTRS 22 #define ISCSI_CONN_ATTRS 13 #define ISCSI_HOST_ATTRS 4 #define ISCSI_TRANSPORT_VERSION "2.0-870" +static int dbg_session; +module_param_named(debug_session, dbg_session, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_session, + "Turn on debugging for sessions in scsi_transport_iscsi " + "module. Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +static int dbg_conn; +module_param_named(debug_conn, dbg_conn, int, + S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_conn, + "Turn on debugging for connections in scsi_transport_iscsi " + "module. Set to 1 to turn on, and zero to turn off. Default " + "is off."); + +#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \ + do { \ + if (dbg_session) \ + iscsi_cls_session_printk(KERN_INFO, _session, \ + "%s: " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + +#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \ + do { \ + if (dbg_conn) \ + iscsi_cls_conn_printk(KERN_INFO, _conn, \ + "%s: " dbg_fmt, \ + __func__, ##arg); \ + } while (0); + struct iscsi_internal { - int daemon_pid; struct scsi_transport_template t; struct iscsi_transport *iscsi_transport; struct list_head list; @@ -138,7 +169,7 @@ static ssize_t show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) { struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - return sprintf(buf, "%u\n", ep->id); + return sprintf(buf, "%llu\n", (unsigned long long) ep->id); } static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); @@ -156,7 +187,7 @@ static struct attribute_group iscsi_endpoint_group = { static int iscsi_match_epid(struct device *dev, void *data) { struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - unsigned int *epid = (unsigned int *) data; + uint64_t *epid = (uint64_t *) data; return *epid == ep->id; } @@ -166,7 +197,7 @@ iscsi_create_endpoint(int dd_size) { struct device *dev; struct iscsi_endpoint *ep; - unsigned int id; + uint64_t id; int err; for (id = 1; id < ISCSI_MAX_EPID; id++) { @@ -187,7 +218,7 @@ iscsi_create_endpoint(int dd_size) ep->id = id; ep->dev.class = &iscsi_endpoint_class; - snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id); + dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id); err = device_register(&ep->dev); if (err) goto free_ep; @@ -246,30 +277,13 @@ static int iscsi_setup_host(struct transport_container *tc, struct device *dev, memset(ihost, 0, sizeof(*ihost)); atomic_set(&ihost->nr_scans, 0); mutex_init(&ihost->mutex); - - snprintf(ihost->scan_workq_name, sizeof(ihost->scan_workq_name), - "iscsi_scan_%d", shost->host_no); - ihost->scan_workq = create_singlethread_workqueue( - ihost->scan_workq_name); - if (!ihost->scan_workq) - return -ENOMEM; - return 0; -} - -static int iscsi_remove_host(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct iscsi_cls_host *ihost = shost->shost_data; - - destroy_workqueue(ihost->scan_workq); return 0; } static DECLARE_TRANSPORT_CLASS(iscsi_host_class, "iscsi_host", iscsi_setup_host, - iscsi_remove_host, + NULL, NULL); static DECLARE_TRANSPORT_CLASS(iscsi_session_class, @@ -377,7 +391,7 @@ int iscsi_session_chkready(struct iscsi_cls_session *session) err = DID_IMM_RETRY << 16; break; case ISCSI_SESSION_FREE: - err = DID_NO_CONNECT << 16; + err = DID_TRANSPORT_FAILFAST << 16; break; default: err = DID_NO_CONNECT << 16; @@ -395,6 +409,7 @@ static void iscsi_session_release(struct device *dev) shost = iscsi_session_to_shost(session); scsi_host_put(shost); + ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n"); kfree(session); } @@ -459,6 +474,9 @@ static int iscsi_user_scan_session(struct device *dev, void *data) return 0; session = iscsi_dev_to_session(dev); + + ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n"); + shost = iscsi_session_to_shost(session); ihost = shost->shost_data; @@ -466,8 +484,7 @@ static int iscsi_user_scan_session(struct device *dev, void *data) spin_lock_irqsave(&session->lock, flags); if (session->state != ISCSI_SESSION_LOGGED_IN) { spin_unlock_irqrestore(&session->lock, flags); - mutex_unlock(&ihost->mutex); - return 0; + goto user_scan_exit; } id = session->target_id; spin_unlock_irqrestore(&session->lock, flags); @@ -480,7 +497,10 @@ static int iscsi_user_scan_session(struct device *dev, void *data) scsi_scan_target(&session->dev, 0, id, scan_data->lun, 1); } + +user_scan_exit: mutex_unlock(&ihost->mutex); + ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n"); return 0; } @@ -540,7 +560,9 @@ static void session_recovery_timedout(struct work_struct *work) if (session->transport->session_recovery_timedout) session->transport->session_recovery_timedout(session); + ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n"); scsi_target_unblock(&session->dev); + ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n"); } static void __iscsi_unblock_session(struct work_struct *work) @@ -552,6 +574,7 @@ static void __iscsi_unblock_session(struct work_struct *work) struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n"); /* * 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. @@ -568,9 +591,10 @@ static void __iscsi_unblock_session(struct work_struct *work) * scanning from userspace). */ if (shost->hostt->scan_finished) { - if (queue_work(ihost->scan_workq, &session->scan_work)) + if (scsi_queue_work(shost, &session->scan_work)) atomic_inc(&ihost->nr_scans); } + ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n"); } /** @@ -597,12 +621,16 @@ static void __iscsi_block_session(struct work_struct *work) block_work); unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n"); 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); + ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n"); + if (session->recovery_tmo >= 0) + queue_delayed_work(iscsi_eh_timer_workq, + &session->recovery_work, + session->recovery_tmo * HZ); } void iscsi_block_session(struct iscsi_cls_session *session) @@ -620,6 +648,8 @@ static void __iscsi_unbind_session(struct work_struct *work) struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; + ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n"); + /* Prevent new scans and make sure scanning is not in progress */ mutex_lock(&ihost->mutex); spin_lock_irqsave(&session->lock, flags); @@ -634,14 +664,7 @@ static void __iscsi_unbind_session(struct work_struct *work) scsi_remove_target(&session->dev); iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); -} - -static int iscsi_unbind_session(struct iscsi_cls_session *session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; - - return queue_work(ihost->scan_workq, &session->unbind_work); + ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); } struct iscsi_cls_session * @@ -673,6 +696,8 @@ iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, device_initialize(&session->dev); if (dd_size) session->dd_data = &session[1]; + + ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n"); return session; } EXPORT_SYMBOL_GPL(iscsi_alloc_session); @@ -718,13 +743,13 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) "Too many iscsi targets. Max " "number of targets is %d.\n", ISCSI_MAX_TARGET - 1); + err = -EOVERFLOW; goto release_host; } } session->target_id = id; - snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", - session->sid); + dev_set_name(&session->dev, "session%u", session->sid); err = device_add(&session->dev); if (err) { iscsi_cls_session_printk(KERN_ERR, session, @@ -738,6 +763,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) spin_unlock_irqrestore(&sesslock, flags); iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); + ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n"); return 0; release_host: @@ -778,6 +804,7 @@ static void iscsi_conn_release(struct device *dev) struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; + ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n"); kfree(conn); put_device(parent); } @@ -797,10 +824,11 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; unsigned long flags; int err; + ISCSI_DBG_TRANS_SESSION(session, "Removing session\n"); + spin_lock_irqsave(&sesslock, flags); list_del(&session->sess_list); spin_unlock_irqrestore(&sesslock, flags); @@ -822,7 +850,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); + scsi_flush_work(shost); __iscsi_unbind_session(&session->unbind_work); /* hw iscsi may not have removed all connections from session */ @@ -834,12 +862,15 @@ void iscsi_remove_session(struct iscsi_cls_session *session) "for session. Error %d.\n", err); transport_unregister_device(&session->dev); + + ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n"); device_del(&session->dev); } EXPORT_SYMBOL_GPL(iscsi_remove_session); void iscsi_free_session(struct iscsi_cls_session *session) { + ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n"); iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION); put_device(&session->dev); } @@ -855,6 +886,7 @@ EXPORT_SYMBOL_GPL(iscsi_free_session); int iscsi_destroy_session(struct iscsi_cls_session *session) { iscsi_remove_session(session); + ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n"); iscsi_free_session(session); return 0; } @@ -897,8 +929,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) if (!get_device(&session->dev)) goto free_conn; - snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", - session->sid, cid); + dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid); conn->dev.parent = &session->dev; conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); @@ -913,6 +944,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) list_add(&conn->conn_list, &connlist); conn->active = 1; spin_unlock_irqrestore(&connlock, flags); + + ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n"); return conn; release_parent_ref: @@ -940,6 +973,7 @@ int iscsi_destroy_conn(struct iscsi_cls_conn *conn) spin_unlock_irqrestore(&connlock, flags); transport_unregister_device(&conn->dev); + ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n"); device_unregister(&conn->dev); return 0; } @@ -966,31 +1000,9 @@ iscsi_if_transport_lookup(struct iscsi_transport *tt) } static int -iscsi_broadcast_skb(struct sk_buff *skb, gfp_t gfp) +iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp) { - int rc; - - rc = netlink_broadcast(nls, skb, 0, 1, gfp); - if (rc < 0) { - printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); - return rc; - } - - return 0; -} - -static int -iscsi_unicast_skb(struct sk_buff *skb, int pid) -{ - int rc; - - rc = netlink_unicast(nls, skb, pid, MSG_DONTWAIT); - if (rc < 0) { - printk(KERN_ERR "iscsi: can not unicast skb (%d)\n", rc); - return rc; - } - - return 0; + return nlmsg_multicast(nls, skb, 0, group, gfp); } int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, @@ -1010,13 +1022,13 @@ 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); + iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED); iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " "control PDU: OOM\n"); return -ENOMEM; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); memset(ev, 0, sizeof(*ev)); ev->transport_handle = iscsi_handle(conn->transport); @@ -1027,11 +1039,46 @@ int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); - return iscsi_unicast_skb(skb, priv->daemon_pid); + return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); } EXPORT_SYMBOL_GPL(iscsi_recv_pdu); -void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) +int iscsi_offload_mesg(struct Scsi_Host *shost, + struct iscsi_transport *transport, uint32_t type, + char *data, uint16_t data_size) +{ + struct nlmsghdr *nlh; + struct sk_buff *skb; + struct iscsi_uevent *ev; + int len = NLMSG_SPACE(sizeof(*ev) + data_size); + + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + printk(KERN_ERR "can not deliver iscsi offload message:OOM\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + memset(ev, 0, sizeof(*ev)); + ev->type = type; + ev->transport_handle = iscsi_handle(transport); + switch (type) { + case ISCSI_KEVENT_PATH_REQ: + ev->r.req_path.host_no = shost->host_no; + break; + case ISCSI_KEVENT_IF_DOWN: + ev->r.notify_if_down.host_no = shost->host_no; + break; + } + + memcpy((char *)ev + sizeof(*ev), data, data_size); + + return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC); +} +EXPORT_SYMBOL_GPL(iscsi_offload_mesg); + +void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) { struct nlmsghdr *nlh; struct sk_buff *skb; @@ -1050,7 +1097,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) return; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(conn->transport); ev->type = ISCSI_KEVENT_CONN_ERROR; @@ -1058,16 +1105,16 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_broadcast_skb(skb, GFP_ATOMIC); + iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", error); } -EXPORT_SYMBOL_GPL(iscsi_conn_error); +EXPORT_SYMBOL_GPL(iscsi_conn_error_event); static int -iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, - void *payload, int size) +iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, + void *payload, int size) { struct sk_buff *skb; struct nlmsghdr *nlh; @@ -1081,10 +1128,10 @@ iscsi_if_send_reply(int pid, int seq, int type, int done, int multi, return -ENOMEM; } - nlh = __nlmsg_put(skb, pid, seq, t, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0); nlh->nlmsg_flags = flags; memcpy(NLMSG_DATA(nlh), payload, size); - return iscsi_unicast_skb(skb, pid); + return iscsi_multicast_skb(skb, group, GFP_ATOMIC); } static int @@ -1121,7 +1168,7 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return -ENOMEM; } - nlhstat = __nlmsg_put(skbstat, priv->daemon_pid, 0, 0, + nlhstat = __nlmsg_put(skbstat, 0, 0, 0, (len - sizeof(*nlhstat)), 0); evstat = NLMSG_DATA(nlhstat); memset(evstat, 0, sizeof(*evstat)); @@ -1145,7 +1192,8 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) skb_trim(skbstat, NLMSG_ALIGN(actual_size)); nlhstat->nlmsg_len = actual_size; - err = iscsi_unicast_skb(skbstat, priv->daemon_pid); + err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID, + GFP_ATOMIC); } while (err < 0 && err != -ECONNREFUSED); return err; @@ -1179,7 +1227,7 @@ int iscsi_session_event(struct iscsi_cls_session *session, return -ENOMEM; } - nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); ev = NLMSG_DATA(nlh); ev->transport_handle = iscsi_handle(session->transport); @@ -1208,12 +1256,15 @@ int iscsi_session_event(struct iscsi_cls_session *session, * this will occur if the daemon is not up, so we just warn * the user and when the daemon is restarted it will handle it */ - rc = iscsi_broadcast_skb(skb, GFP_KERNEL); - if (rc < 0) + rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL); + if (rc == -ESRCH) iscsi_cls_session_printk(KERN_ERR, session, "Cannot notify userspace of session " "event %u. Check iscsi daemon\n", event); + + ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n", + event, rc); return rc; } EXPORT_SYMBOL_GPL(iscsi_session_event); @@ -1225,15 +1276,18 @@ iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, { struct iscsi_transport *transport = priv->iscsi_transport; struct iscsi_cls_session *session; - uint32_t host_no; + struct Scsi_Host *shost; session = transport->create_session(ep, cmds_max, queue_depth, - initial_cmdsn, &host_no); + initial_cmdsn); if (!session) return -ENOMEM; - ev->r.c_session_ret.host_no = host_no; + shost = iscsi_session_to_shost(session); + ev->r.c_session_ret.host_no = shost->host_no; ev->r.c_session_ret.sid = session->sid; + ISCSI_DBG_TRANS_SESSION(session, + "Completed creating transport session\n"); return 0; } @@ -1259,6 +1313,8 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; + + ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n"); return 0; } @@ -1271,8 +1327,10 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev if (!conn) return -EINVAL; + ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n"); if (transport->destroy_conn) transport->destroy_conn(conn); + return 0; } @@ -1292,8 +1350,7 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: sscanf(data, "%d", &value); - if (value != 0) - session->recovery_tmo = value; + session->recovery_tmo = value; break; default: err = transport->set_param(conn, ev->u.set_param.param, @@ -1303,26 +1360,54 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int iscsi_if_ep_connect(struct iscsi_transport *transport, + struct iscsi_uevent *ev, int msg_type) +{ + struct iscsi_endpoint *ep; + struct sockaddr *dst_addr; + struct Scsi_Host *shost = NULL; + int non_blocking, err = 0; + + if (!transport->ep_connect) + return -EINVAL; + + if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) { + shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no); + if (!shost) { + printk(KERN_ERR "ep connect failed. Could not find " + "host no %u\n", + ev->u.ep_connect_through_host.host_no); + return -ENODEV; + } + non_blocking = ev->u.ep_connect_through_host.non_blocking; + } else + non_blocking = ev->u.ep_connect.non_blocking; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + ep = transport->ep_connect(shost, dst_addr, non_blocking); + if (IS_ERR(ep)) { + err = PTR_ERR(ep); + goto release_host; + } + + ev->r.ep_connect_ret.handle = ep->id; +release_host: + if (shost) + scsi_host_put(shost); + return err; +} + static int iscsi_if_transport_ep(struct iscsi_transport *transport, struct iscsi_uevent *ev, int msg_type) { struct iscsi_endpoint *ep; - struct sockaddr *dst_addr; int rc = 0; switch (msg_type) { + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: - if (!transport->ep_connect) - return -EINVAL; - - dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); - ep = transport->ep_connect(dst_addr, - ev->u.ep_connect.non_blocking); - if (IS_ERR(ep)) - return PTR_ERR(ep); - - ev->r.ep_connect_ret.handle = ep->id; + rc = iscsi_if_ep_connect(transport, ev, msg_type); break; case ISCSI_UEVENT_TRANSPORT_EP_POLL: if (!transport->ep_poll) @@ -1400,7 +1485,31 @@ iscsi_set_host_param(struct iscsi_transport *transport, } static int -iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) +{ + struct Scsi_Host *shost; + struct iscsi_path *params; + int err; + + if (!transport->set_path) + return -ENOSYS; + + shost = scsi_host_lookup(ev->u.set_path.host_no); + if (!shost) { + printk(KERN_ERR "set path could not find host no %u\n", + ev->u.set_path.host_no); + return -ENODEV; + } + + params = (struct iscsi_path *)((char *)ev + sizeof(*ev)); + err = transport->set_path(shost, params); + + scsi_host_put(shost); + return err; +} + +static int +iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { int err = 0; struct iscsi_uevent *ev = NLMSG_DATA(nlh); @@ -1410,6 +1519,11 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) struct iscsi_cls_conn *conn; struct iscsi_endpoint *ep = NULL; + if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE) + *group = ISCSI_NL_GRP_UIP; + else + *group = ISCSI_NL_GRP_ISCSID; + priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); if (!priv) return -EINVAL; @@ -1418,8 +1532,6 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (!try_module_get(transport->owner)) return -EINVAL; - priv->daemon_pid = NETLINK_CREDS(skb)->pid; - switch (nlh->nlmsg_type) { case ISCSI_UEVENT_CREATE_SESSION: err = iscsi_if_create_session(priv, ep, ev, @@ -1449,7 +1561,8 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_UNBIND_SESSION: session = iscsi_session_lookup(ev->u.d_session.sid); if (session) - iscsi_unbind_session(session); + scsi_queue_work(iscsi_session_to_shost(session), + &session->unbind_work); else err = -EINVAL; break; @@ -1503,6 +1616,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: case ISCSI_UEVENT_TRANSPORT_EP_POLL: case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: + case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); break; case ISCSI_UEVENT_TGT_DSCVR: @@ -1511,6 +1625,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_SET_HOST_PARAM: err = iscsi_set_host_param(transport, ev); break; + case ISCSI_UEVENT_PATH_UPDATE: + err = iscsi_set_path(transport, ev); + break; default: err = -ENOSYS; break; @@ -1533,6 +1650,7 @@ iscsi_if_rx(struct sk_buff *skb) uint32_t rlen; struct nlmsghdr *nlh; struct iscsi_uevent *ev; + uint32_t group; nlh = nlmsg_hdr(skb); if (nlh->nlmsg_len < sizeof(*nlh) || @@ -1545,7 +1663,7 @@ iscsi_if_rx(struct sk_buff *skb) if (rlen > skb->len) rlen = skb->len; - err = iscsi_if_recv_msg(skb, nlh); + err = iscsi_if_recv_msg(skb, nlh, &group); if (err) { ev->type = ISCSI_KEVENT_IF_ERROR; ev->iferror = err; @@ -1559,8 +1677,7 @@ iscsi_if_rx(struct sk_buff *skb) */ if (ev->type == ISCSI_UEVENT_GET_STATS && !err) break; - err = iscsi_if_send_reply( - NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq, + err = iscsi_if_send_reply(group, nlh->nlmsg_seq, nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); } while (err < 0 && err != -ECONNREFUSED); skb_pull(skb, rlen); @@ -1643,6 +1760,7 @@ 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(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0); iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0) @@ -1808,14 +1926,12 @@ iscsi_register_transport(struct iscsi_transport *tt) if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); - priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; - if (!(tt->caps & CAP_DATA_PATH_OFFLOAD)) - priv->t.create_work_queue = 1; + priv->t.create_work_queue = 1; priv->dev.class = &iscsi_transport_class; - snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); + dev_set_name(&priv->dev, "%s", tt->name); err = device_register(&priv->dev); if (err) goto free_priv; @@ -1886,6 +2002,7 @@ iscsi_register_transport(struct iscsi_transport *tt) 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(tgt_reset_tmo,ISCSI_TGT_RESET_TMO); SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);