From 6260a5d221225f4e6befd98c6001325a3007a8c4 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Mon, 27 Feb 2012 03:08:51 -0800 Subject: [SCSI] iscsi_transport: Add support to display CHAP list and delete CHAP entry For offload iSCSI like qla4xxx CHAP entries are stored in FLASH. This patch adds support to list CHAP entries stored in FLASH and delete specified CHAP entry from FLASH using iscsi tools. Signed-off-by: Nilesh Javali Signed-off-by: Vikas Chaudhary Reviewed-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 101 +++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index a20f1813cb51..7bf0dec46271 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -727,10 +727,11 @@ static void iscsi_session_release(struct device *dev) kfree(session); } -static int iscsi_is_session_dev(const struct device *dev) +int iscsi_is_session_dev(const struct device *dev) { return dev->release == iscsi_session_release; } +EXPORT_SYMBOL_GPL(iscsi_is_session_dev); static int iscsi_iter_session_fn(struct device *dev, void *data) { @@ -2001,6 +2002,96 @@ iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev) return err; } +static int +iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh) +{ + struct iscsi_uevent *ev = NLMSG_DATA(nlh); + struct Scsi_Host *shost = NULL; + struct iscsi_chap_rec *chap_rec; + struct iscsi_internal *priv; + struct sk_buff *skbchap; + struct nlmsghdr *nlhchap; + struct iscsi_uevent *evchap; + uint32_t chap_buf_size; + int len, err = 0; + char *buf; + + if (!transport->get_chap) + return -EINVAL; + + priv = iscsi_if_transport_lookup(transport); + if (!priv) + return -EINVAL; + + chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec)); + len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size); + + shost = scsi_host_lookup(ev->u.get_chap.host_no); + if (!shost) { + printk(KERN_ERR "%s: failed. Cound not find host no %u\n", + __func__, ev->u.get_chap.host_no); + return -ENODEV; + } + + do { + int actual_size; + + skbchap = alloc_skb(len, GFP_KERNEL); + if (!skbchap) { + printk(KERN_ERR "can not deliver chap: OOM\n"); + err = -ENOMEM; + goto exit_get_chap; + } + + nlhchap = __nlmsg_put(skbchap, 0, 0, 0, + (len - sizeof(*nlhchap)), 0); + evchap = NLMSG_DATA(nlhchap); + memset(evchap, 0, sizeof(*evchap)); + evchap->transport_handle = iscsi_handle(transport); + evchap->type = nlh->nlmsg_type; + evchap->u.get_chap.host_no = ev->u.get_chap.host_no; + evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx; + evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries; + buf = (char *) ((char *)evchap + sizeof(*evchap)); + memset(buf, 0, chap_buf_size); + + err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx, + &evchap->u.get_chap.num_entries, buf); + + actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size); + skb_trim(skbchap, NLMSG_ALIGN(actual_size)); + nlhchap->nlmsg_len = actual_size; + + err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID, + GFP_KERNEL); + } while (err < 0 && err != -ECONNREFUSED); + +exit_get_chap: + scsi_host_put(shost); + return err; +} + +static int iscsi_delete_chap(struct iscsi_transport *transport, + struct iscsi_uevent *ev) +{ + struct Scsi_Host *shost; + int err = 0; + + if (!transport->delete_chap) + return -ENOSYS; + + shost = scsi_host_lookup(ev->u.delete_chap.host_no); + if (!shost) { + printk(KERN_ERR "%s could not find host no %u\n", + __func__, ev->u.delete_chap.host_no); + return -ENODEV; + } + + err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx); + scsi_host_put(shost); + return err; +} + static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) { @@ -2149,6 +2240,12 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) case ISCSI_UEVENT_PING: err = iscsi_send_ping(transport, ev); break; + case ISCSI_UEVENT_GET_CHAP: + err = iscsi_get_chap(transport, nlh); + break; + case ISCSI_UEVENT_DELETE_CHAP: + err = iscsi_delete_chap(transport, ev); + break; default: err = -ENOSYS; break; @@ -2198,6 +2295,8 @@ iscsi_if_rx(struct sk_buff *skb) */ if (ev->type == ISCSI_UEVENT_GET_STATS && !err) break; + if (ev->type == ISCSI_UEVENT_GET_CHAP && !err) + break; err = iscsi_if_send_reply(group, nlh->nlmsg_seq, nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); -- cgit v1.2.3-55-g7522