Support a remove of a target from user level.

Signed-off-by: Ishai Rabinovitz <[EMAIL PROTECTED]>
Index: last_stable/drivers/infiniband/ulp/srp/ib_srp.c
===================================================================
--- last_stable.orig/drivers/infiniband/ulp/srp/ib_srp.c        2006-05-01 
12:30:01.000000000 +0300
+++ last_stable/drivers/infiniband/ulp/srp/ib_srp.c     2006-05-01 
12:36:22.000000000 +0300
@@ -960,10 +960,12 @@ static int srp_queuecommand(struct scsi_
        long req_index;
        int len;
 
-       if (target->state == SRP_TARGET_CONNECTING)
+       if (target->state == SRP_TARGET_CONNECTING ||
+           target->state == SRP_TARGET_RECONNECTING)
                goto err;
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED) {
                scmnd->result = DID_BAD_TARGET << 16;
                done(scmnd);
@@ -1254,6 +1256,7 @@ static int srp_send_tsk_mgmt(struct scsi
        spin_lock_irq(target->scsi_host->host_lock);
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED) {
                scmnd->result = DID_BAD_TARGET << 16;
                goto out;
@@ -1359,6 +1362,7 @@ static ssize_t show_ioc_guid(struct clas
        struct srp_target_port *target = host_to_target(class_to_shost(cdev));
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED)
                return -ENODEV;
 
@@ -1371,6 +1375,7 @@ static ssize_t show_service_id(struct cl
        struct srp_target_port *target = host_to_target(class_to_shost(cdev));
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED)
                return -ENODEV;
 
@@ -1383,6 +1388,7 @@ static ssize_t show_pkey(struct class_de
        struct srp_target_port *target = host_to_target(class_to_shost(cdev));
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED)
                return -ENODEV;
 
@@ -1394,6 +1400,8 @@ static ssize_t show_dgid(struct class_de
        struct srp_target_port *target = host_to_target(class_to_shost(cdev));
 
        if (target->state == SRP_TARGET_DEAD ||
+           target->state == SRP_TARGET_DISCONNECTED ||
+           target->state == SRP_TARGET_DISCONNECTED ||
            target->state == SRP_TARGET_REMOVED)
                return -ENODEV;
 
@@ -1447,11 +1455,11 @@ static int srp_add_target(struct srp_hos
        if (scsi_add_host(target->scsi_host, host->dev->dev->dma_device))
                return -ENODEV;
 
-       mutex_lock(&host->target_mutex);
        list_add_tail(&target->list, &host->target_list);
-       mutex_unlock(&host->target_mutex);
 
+       spin_lock_irq(target->scsi_host->host_lock);
        target->state = SRP_TARGET_LIVE;
+       spin_unlock_irq(target->scsi_host->host_lock);
 
        /* XXX: are we supposed to have a definition of SCAN_WILD_CARD ?? */
        scsi_scan_target(&target->scsi_host->shost_gendev,
@@ -1642,7 +1650,6 @@ static ssize_t srp_create_target(struct 
 {
        struct srp_host *host =
                container_of(class_dev, struct srp_host, class_dev);
-       struct Scsi_Host *target_host;
        struct srp_target_port *target, *existing_target = NULL;
        int ret;
        int i;
@@ -1663,6 +1670,7 @@ static ssize_t srp_create_target(struct 
                               buf);
                        ret = -EEXIST;
                        break;
+               case SRP_TARGET_RECONNECTING:
                case SRP_TARGET_CONNECTING:
                        /* It is in the middle of reconnecting */
                        ret = -EALREADY;
@@ -1671,6 +1679,10 @@ static ssize_t srp_create_target(struct 
                        /* It will be removed soon - create a new one */
                case SRP_TARGET_REMOVED:
                        /* target is dead, create a new one */
+                       existing_target = NULL;
+                       break;
+               case SRP_TARGET_DISCONNECTED:
+                       existing_target->state = SRP_TARGET_RECONNECTING;
                        break;
                }
                spin_unlock_irq(existing_target->scsi_host->host_lock);
@@ -1678,26 +1690,30 @@ static ssize_t srp_create_target(struct 
                        goto unlock_mutex;
        }
 
-       /* really create the target */
-       target_host = scsi_host_alloc(&srp_template,
-                                     sizeof (struct srp_target_port));
-       if (!target_host) {
-               ret = -ENOMEM;
-               goto unlock_mutex;
-       }
-
-       target_host->max_lun = SRP_MAX_LUN;
-
-       target = host_to_target(target_host);
-       memset(target, 0, sizeof *target);
+       if (!existing_target) {
+               struct Scsi_Host *target_host;
 
-       target->scsi_host  = target_host;
-       target->srp_host   = host;
-
-       for (i = 0; i < SRP_SQ_SIZE - 1; ++i)
-               target->req_ring[i].next = i + 1;
-       target->req_ring[SRP_SQ_SIZE - 1].next = -1;
-       INIT_LIST_HEAD(&target->req_queue);
+               target_host = scsi_host_alloc(&srp_template,
+                                             sizeof (struct srp_target_port));
+               if (!target_host) {
+                       ret = -ENOMEM;
+                       goto unlock_mutex;
+               }
+
+               target_host->max_lun = SRP_MAX_LUN;
+
+               target = host_to_target(target_host);
+               memset(target, 0, sizeof *target);
+
+               target->scsi_host  = target_host;
+               target->srp_host   = host;
+
+               for (i = 0; i < SRP_SQ_SIZE - 1; ++i)
+                       target->req_ring[i].next = i + 1;
+               target->req_ring[SRP_SQ_SIZE - 1].next = -1;
+               INIT_LIST_HEAD(&target->req_queue);
+       } else
+               target = existing_target;
 
        ret = srp_parse_options(buf, target);
        if (ret)
@@ -1736,9 +1752,15 @@ static ssize_t srp_create_target(struct 
                goto err_cm_id;
        }
 
-       ret = srp_add_target(host, target);
-       if (ret)
-               goto err_disconnect;
+       if (!existing_target) {
+               ret = srp_add_target(host, target);
+               if (ret)
+                       goto err_disconnect;
+       } else {
+               spin_lock_irq(target->scsi_host->host_lock);
+               target->state = SRP_TARGET_LIVE;
+               spin_unlock_irq(target->scsi_host->host_lock);
+       }
 
        ret = count;
        goto unlock_mutex;
@@ -1753,7 +1775,9 @@ err_free:
        srp_free_target_ib(target);
 
 err_put_scsi_host:
-       scsi_host_put(target_host);
+       if (existing_target)
+               list_del(&target->list);
+       scsi_host_put(target->scsi_host);
 
 unlock_mutex:
        mutex_unlock(&host->target_mutex);
@@ -1763,6 +1787,62 @@ unlock_mutex:
 
 static CLASS_DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);
 
+static ssize_t srp_remove_target(struct class_device *class_dev,
+                                const char *buf, size_t count)
+{
+       struct srp_host *host =
+               container_of(class_dev, struct srp_host, class_dev);
+       struct srp_target_port *existing_target;
+       int ret;
+
+       /* first check if the target exists */
+
+       mutex_lock(&host->target_mutex);
+       ret = srp_find_target(buf, host, &existing_target);
+       if (ret)
+               goto unlock_mutex;
+
+       if (!existing_target)  {
+               printk(KERN_WARNING PFX "target %s does not exist\n", buf);
+               ret = -ENOENT;
+               goto unlock_mutex;
+       }
+
+       spin_lock_irq(existing_target->scsi_host->host_lock);
+
+       switch (existing_target->state) {
+       case SRP_TARGET_REMOVED:
+       case SRP_TARGET_DEAD:
+       case SRP_TARGET_DISCONNECTED:
+               /* target not exists */
+               printk(KERN_WARNING PFX "target %s does not exist\n", buf);
+               ret = -ENOENT;
+               break;
+
+       case SRP_TARGET_RECONNECTING:
+       case SRP_TARGET_CONNECTING:
+               ret = -EAGAIN; /* So the caller will try again later -
+                                 after the connection ends one way or another 
*/
+               break;
+
+       case SRP_TARGET_LIVE:
+               existing_target->state = SRP_TARGET_DISCONNECTED;
+               spin_unlock_irq(existing_target->scsi_host->host_lock);
+               mutex_unlock(&host->target_mutex);
+               srp_disconnect_target(existing_target);
+               ib_destroy_cm_id(existing_target->cm_id);
+               srp_free_target_ib(existing_target);
+               return count;
+       }
+
+       spin_unlock_irq(existing_target->scsi_host->host_lock);
+unlock_mutex:
+       mutex_unlock(&host->target_mutex);
+       return ret;
+}
+
+static CLASS_DEVICE_ATTR(remove_target, S_IWUSR, NULL, srp_remove_target);
+
 static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
 {
        struct srp_host *host =
@@ -1809,6 +1889,8 @@ static struct srp_host *srp_add_port(str
                goto free_host;
        if (class_device_create_file(&host->class_dev, 
&class_device_attr_add_target))
                goto err_class;
+       if (class_device_create_file(&host->class_dev, 
&class_device_attr_remove_target))
+               goto err_class;
        if (class_device_create_file(&host->class_dev, 
&class_device_attr_ibdev))
                goto err_class;
        if (class_device_create_file(&host->class_dev, &class_device_attr_port))
Index: last_stable/drivers/infiniband/ulp/srp/ib_srp.h
===================================================================
--- last_stable.orig/drivers/infiniband/ulp/srp/ib_srp.h        2006-05-01 
12:30:01.000000000 +0300
+++ last_stable/drivers/infiniband/ulp/srp/ib_srp.h     2006-05-01 
12:31:06.000000000 +0300
@@ -78,8 +78,10 @@ enum {
 enum srp_target_state {
        SRP_TARGET_LIVE,
        SRP_TARGET_CONNECTING,
+       SRP_TARGET_RECONNECTING,
+       SRP_TARGET_DISCONNECTED,
        SRP_TARGET_DEAD,
-       SRP_TARGET_REMOVED
+       SRP_TARGET_REMOVED,
 };
 
 struct srp_device {
-- 
Ishai Rabinovitz
_______________________________________________
openib-general mailing list
openib-general@openib.org
http://openib.org/mailman/listinfo/openib-general

To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general

Reply via email to