virtio_net: remove send queue
[safe/jmp/linux-2.6] / drivers / scsi / ses.c
index e1b8c82..55b034b 100644 (file)
@@ -347,6 +347,97 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
        return 0;
 }
 
+#define INIT_ALLOC_SIZE 32
+
+static void ses_enclosure_data_process(struct enclosure_device *edev,
+                                      struct scsi_device *sdev,
+                                      int create)
+{
+       u32 result;
+       unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL;
+       int i, j, page7_len, len, components;
+       struct ses_device *ses_dev = edev->scratch;
+       int types = ses_dev->page1[10];
+       unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL);
+
+       if (!hdr_buf)
+               goto simple_populate;
+
+       /* re-read page 10 */
+       if (ses_dev->page10)
+               ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len);
+       /* Page 7 for the descriptors is optional */
+       result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE);
+       if (result)
+               goto simple_populate;
+
+       page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
+       /* add 1 for trailing '\0' we'll use */
+       buf = kzalloc(len + 1, GFP_KERNEL);
+       if (!buf)
+               goto simple_populate;
+       result = ses_recv_diag(sdev, 7, buf, len);
+       if (result) {
+ simple_populate:
+               kfree(buf);
+               buf = NULL;
+               desc_ptr = NULL;
+               len = 0;
+               page7_len = 0;
+       } else {
+               desc_ptr = buf + 8;
+               len = (desc_ptr[2] << 8) + desc_ptr[3];
+               /* skip past overall descriptor */
+               desc_ptr += len + 4;
+               if (ses_dev->page10)
+                       addl_desc_ptr = ses_dev->page10 + 8;
+       }
+       type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
+       components = 0;
+       for (i = 0; i < types; i++, type_ptr += 4) {
+               for (j = 0; j < type_ptr[1]; j++) {
+                       char *name = NULL;
+                       struct enclosure_component *ecomp;
+
+                       if (desc_ptr) {
+                               if (desc_ptr >= buf + page7_len) {
+                                       desc_ptr = NULL;
+                               } else {
+                                       len = (desc_ptr[2] << 8) + desc_ptr[3];
+                                       desc_ptr += 4;
+                                       /* Add trailing zero - pushes into
+                                        * reserved space */
+                                       desc_ptr[len] = '\0';
+                                       name = desc_ptr;
+                               }
+                       }
+                       if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
+                           type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
+
+                               if (create)
+                                       ecomp = enclosure_component_register(edev,
+                                                                            components++,
+                                                                            type_ptr[0],
+                                                                            name);
+                               else
+                                       ecomp = &edev->component[components++];
+
+                               if (!IS_ERR(ecomp) && addl_desc_ptr)
+                                       ses_process_descriptor(ecomp,
+                                                              addl_desc_ptr);
+                       }
+                       if (desc_ptr)
+                               desc_ptr += len;
+
+                       if (addl_desc_ptr)
+                               addl_desc_ptr += addl_desc_ptr[1] + 2;
+
+               }
+       }
+       kfree(buf);
+       kfree(hdr_buf);
+}
+
 static void ses_match_to_enclosure(struct enclosure_device *edev,
                                   struct scsi_device *sdev)
 {
@@ -361,6 +452,8 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
        if (!buf)
                return;
 
+       ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
+
        vpd_len = ((buf[2] << 8) | buf[3]) + 4;
 
        desc = buf + 4;
@@ -395,18 +488,15 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
        kfree(buf);
 }
 
-#define INIT_ALLOC_SIZE 32
-
 static int ses_intf_add(struct device *cdev,
                        struct class_interface *intf)
 {
        struct scsi_device *sdev = to_scsi_device(cdev->parent);
        struct scsi_device *tmp_sdev;
-       unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL,
-               *addl_desc_ptr = NULL;
+       unsigned char *buf = NULL, *hdr_buf, *type_ptr;
        struct ses_device *ses_dev;
        u32 result;
-       int i, j, types, len, page7_len = 0, components = 0;
+       int i, types, len, components = 0;
        int err = -ENOMEM;
        struct enclosure_device *edev;
        struct ses_component *scomp = NULL;
@@ -501,6 +591,7 @@ static int ses_intf_add(struct device *cdev,
                ses_dev->page10_len = len;
                buf = NULL;
        }
+       kfree(hdr_buf);
 
        scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
        if (!scomp)
@@ -517,72 +608,7 @@ static int ses_intf_add(struct device *cdev,
        for (i = 0; i < components; i++)
                edev->component[i].scratch = scomp + i;
 
-       /* Page 7 for the descriptors is optional */
-       result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE);
-       if (result)
-               goto simple_populate;
-
-       page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
-       /* add 1 for trailing '\0' we'll use */
-       buf = kzalloc(len + 1, GFP_KERNEL);
-       if (!buf)
-               goto simple_populate;
-       result = ses_recv_diag(sdev, 7, buf, len);
-       if (result) {
- simple_populate:
-               kfree(buf);
-               buf = NULL;
-               desc_ptr = NULL;
-               addl_desc_ptr = NULL;
-       } else {
-               desc_ptr = buf + 8;
-               len = (desc_ptr[2] << 8) + desc_ptr[3];
-               /* skip past overall descriptor */
-               desc_ptr += len + 4;
-               if (ses_dev->page10)
-                       addl_desc_ptr = ses_dev->page10 + 8;
-       }
-       type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
-       components = 0;
-       for (i = 0; i < types; i++, type_ptr += 4) {
-               for (j = 0; j < type_ptr[1]; j++) {
-                       char *name = NULL;
-                       struct enclosure_component *ecomp;
-
-                       if (desc_ptr) {
-                               if (desc_ptr >= buf + page7_len) {
-                                       desc_ptr = NULL;
-                               } else {
-                                       len = (desc_ptr[2] << 8) + desc_ptr[3];
-                                       desc_ptr += 4;
-                                       /* Add trailing zero - pushes into
-                                        * reserved space */
-                                       desc_ptr[len] = '\0';
-                                       name = desc_ptr;
-                               }
-                       }
-                       if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
-                           type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
-
-                               ecomp = enclosure_component_register(edev,
-                                                            components++,
-                                                            type_ptr[0],
-                                                            name);
-
-                               if (!IS_ERR(ecomp) && addl_desc_ptr)
-                                       ses_process_descriptor(ecomp,
-                                                              addl_desc_ptr);
-                       }
-                       if (desc_ptr)
-                               desc_ptr += len;
-
-                       if (addl_desc_ptr)
-                               addl_desc_ptr += addl_desc_ptr[1] + 2;
-
-               }
-       }
-       kfree(buf);
-       kfree(hdr_buf);
+       ses_enclosure_data_process(edev, sdev, 1);
 
        /* see if there are any devices matching before
         * we found the enclosure */
@@ -616,18 +642,26 @@ static int ses_remove(struct device *dev)
        return 0;
 }
 
-static void ses_intf_remove(struct device *cdev,
-                           struct class_interface *intf)
+static void ses_intf_remove_component(struct scsi_device *sdev)
+{
+       struct enclosure_device *edev, *prev = NULL;
+
+       while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
+               prev = edev;
+               if (!enclosure_remove_device(edev, &sdev->sdev_gendev))
+                       break;
+       }
+       if (edev)
+               put_device(&edev->edev);
+}
+
+static void ses_intf_remove_enclosure(struct scsi_device *sdev)
 {
-       struct scsi_device *sdev = to_scsi_device(cdev->parent);
        struct enclosure_device *edev;
        struct ses_device *ses_dev;
 
-       if (!scsi_device_enclosure(sdev))
-               return;
-
        /*  exact match to this enclosure */
-       edev = enclosure_find(cdev->parent, NULL);
+       edev = enclosure_find(&sdev->sdev_gendev, NULL);
        if (!edev)
                return;
 
@@ -645,6 +679,17 @@ static void ses_intf_remove(struct device *cdev,
        enclosure_unregister(edev);
 }
 
+static void ses_intf_remove(struct device *cdev,
+                           struct class_interface *intf)
+{
+       struct scsi_device *sdev = to_scsi_device(cdev->parent);
+
+       if (!scsi_device_enclosure(sdev))
+               ses_intf_remove_component(sdev);
+       else
+               ses_intf_remove_enclosure(sdev);
+}
+
 static struct class_interface ses_interface = {
        .add_dev        = ses_intf_add,
        .remove_dev     = ses_intf_remove,