vsprintf: reduce code size by avoiding extra check
[safe/jmp/linux-2.6] / drivers / scsi / ses.c
index a57fed4..55b034b 100644 (file)
@@ -33,9 +33,9 @@
 #include <scsi/scsi_host.h>
 
 struct ses_device {
-       char *page1;
-       char *page2;
-       char *page10;
+       unsigned char *page1;
+       unsigned char *page2;
+       unsigned char *page10;
        short page1_len;
        short page2_len;
        short page10_len;
@@ -61,13 +61,13 @@ static int ses_probe(struct device *dev)
        return err;
 }
 
-#define SES_TIMEOUT 30
+#define SES_TIMEOUT (30 * HZ)
 #define SES_RETRIES 3
 
 static int ses_recv_diag(struct scsi_device *sdev, int page_code,
                         void *buf, int bufflen)
 {
-       char cmd[] = {
+       unsigned char cmd[] = {
                RECEIVE_DIAGNOSTIC,
                1,              /* Set PCV bit */
                page_code,
@@ -77,7 +77,7 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code,
        };
 
        return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
-                               NULL, SES_TIMEOUT, SES_RETRIES);
+                               NULL, SES_TIMEOUT, SES_RETRIES, NULL);
 }
 
 static int ses_send_diag(struct scsi_device *sdev, int page_code,
@@ -85,7 +85,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
 {
        u32 result;
 
-       char cmd[] = {
+       unsigned char cmd[] = {
                SEND_DIAGNOSTIC,
                0x10,           /* Set PF bit */
                0,
@@ -95,7 +95,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
        };
 
        result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen,
-                                 NULL, SES_TIMEOUT, SES_RETRIES);
+                                 NULL, SES_TIMEOUT, SES_RETRIES, NULL);
        if (result)
                sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n",
                            result);
@@ -104,13 +104,13 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
 
 static int ses_set_page2_descriptor(struct enclosure_device *edev,
                                      struct enclosure_component *ecomp,
-                                     char *desc)
+                                     unsigned char *desc)
 {
        int i, j, count = 0, descriptor = ecomp->number;
-       struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
+       struct scsi_device *sdev = to_scsi_device(edev->edev.parent);
        struct ses_device *ses_dev = edev->scratch;
-       char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
-       char *desc_ptr = ses_dev->page2 + 8;
+       unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
+       unsigned char *desc_ptr = ses_dev->page2 + 8;
 
        /* Clear everything */
        memset(desc_ptr, 0, ses_dev->page2_len - 8);
@@ -133,14 +133,14 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev,
        return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
 }
 
-static char *ses_get_page2_descriptor(struct enclosure_device *edev,
+static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
                                      struct enclosure_component *ecomp)
 {
        int i, j, count = 0, descriptor = ecomp->number;
-       struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
+       struct scsi_device *sdev = to_scsi_device(edev->edev.parent);
        struct ses_device *ses_dev = edev->scratch;
-       char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
-       char *desc_ptr = ses_dev->page2 + 8;
+       unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
+       unsigned char *desc_ptr = ses_dev->page2 + 8;
 
        ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
 
@@ -160,17 +160,18 @@ static char *ses_get_page2_descriptor(struct enclosure_device *edev,
 static void ses_get_fault(struct enclosure_device *edev,
                          struct enclosure_component *ecomp)
 {
-       char *desc;
+       unsigned char *desc;
 
        desc = ses_get_page2_descriptor(edev, ecomp);
-       ecomp->fault = (desc[3] & 0x60) >> 4;
+       if (desc)
+               ecomp->fault = (desc[3] & 0x60) >> 4;
 }
 
 static int ses_set_fault(struct enclosure_device *edev,
                          struct enclosure_component *ecomp,
                         enum enclosure_component_setting val)
 {
-       char desc[4] = {0 };
+       unsigned char desc[4] = {0 };
 
        switch (val) {
        case ENCLOSURE_SETTING_DISABLED:
@@ -190,26 +191,28 @@ static int ses_set_fault(struct enclosure_device *edev,
 static void ses_get_status(struct enclosure_device *edev,
                           struct enclosure_component *ecomp)
 {
-       char *desc;
+       unsigned char *desc;
 
        desc = ses_get_page2_descriptor(edev, ecomp);
-       ecomp->status = (desc[0] & 0x0f);
+       if (desc)
+               ecomp->status = (desc[0] & 0x0f);
 }
 
 static void ses_get_locate(struct enclosure_device *edev,
                           struct enclosure_component *ecomp)
 {
-       char *desc;
+       unsigned char *desc;
 
        desc = ses_get_page2_descriptor(edev, ecomp);
-       ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
+       if (desc)
+               ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
 }
 
 static int ses_set_locate(struct enclosure_device *edev,
                          struct enclosure_component *ecomp,
                          enum enclosure_component_setting val)
 {
-       char desc[4] = {0 };
+       unsigned char desc[4] = {0 };
 
        switch (val) {
        case ENCLOSURE_SETTING_DISABLED:
@@ -229,7 +232,7 @@ static int ses_set_active(struct enclosure_device *edev,
                          struct enclosure_component *ecomp,
                          enum enclosure_component_setting val)
 {
-       char desc[4] = {0 };
+       unsigned char desc[4] = {0 };
 
        switch (val) {
        case ENCLOSURE_SETTING_DISABLED:
@@ -261,15 +264,16 @@ struct ses_host_edev {
        struct enclosure_device *edev;
 };
 
+#if 0
 int ses_match_host(struct enclosure_device *edev, void *data)
 {
        struct ses_host_edev *sed = data;
        struct scsi_device *sdev;
 
-       if (!scsi_is_sdev_device(edev->cdev.dev))
+       if (!scsi_is_sdev_device(edev->edev.parent))
                return 0;
 
-       sdev = to_scsi_device(edev->cdev.dev);
+       sdev = to_scsi_device(edev->edev.parent);
 
        if (sdev->host != sed->shost)
                return 0;
@@ -277,6 +281,7 @@ int ses_match_host(struct enclosure_device *edev, void *data)
        sed->edev = edev;
        return 1;
 }
+#endif  /*  0  */
 
 static void ses_process_descriptor(struct enclosure_component *ecomp,
                                   unsigned char *desc)
@@ -342,36 +347,117 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
        return 0;
 }
 
-#define VPD_INQUIRY_SIZE 512
+#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)
 {
-       unsigned char *buf = kmalloc(VPD_INQUIRY_SIZE, GFP_KERNEL);
+       unsigned char *buf;
        unsigned char *desc;
-       int len;
+       unsigned int vpd_len;
        struct efd efd = {
                .addr = 0,
        };
-       unsigned char cmd[] = {
-               INQUIRY,
-               1,
-               0x83,
-               VPD_INQUIRY_SIZE >> 8,
-               VPD_INQUIRY_SIZE & 0xff,
-               0
-       };
 
+       buf = scsi_get_vpd_page(sdev, 0x83);
        if (!buf)
                return;
 
-       if (scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf,
-                            VPD_INQUIRY_SIZE, NULL, SES_TIMEOUT, SES_RETRIES))
-               goto free;
+       ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
+
+       vpd_len = ((buf[2] << 8) | buf[3]) + 4;
 
-       len = (buf[2] << 8) + buf[3];
        desc = buf + 4;
-       while (desc < buf + len) {
+       while (desc < buf + vpd_len) {
                enum scsi_protocol proto = desc[0] >> 4;
                u8 code_set = desc[0] & 0x0f;
                u8 piv = desc[1] & 0x80;
@@ -379,7 +465,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
                u8 type = desc[1] & 0x0f;
                u8 len = desc[3];
 
-               if (piv && code_set == 1 && assoc == 1 && code_set == 1
+               if (piv && code_set == 1 && assoc == 1
                    && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8)
                        efd.addr = (u64)desc[4] << 56 |
                                (u64)desc[5] << 48 |
@@ -402,28 +488,26 @@ static void ses_match_to_enclosure(struct enclosure_device *edev,
        kfree(buf);
 }
 
-#define INIT_ALLOC_SIZE 32
-
-static int ses_intf_add(struct class_device *cdev,
+static int ses_intf_add(struct device *cdev,
                        struct class_interface *intf)
 {
-       struct scsi_device *sdev = to_scsi_device(cdev->dev);
+       struct scsi_device *sdev = to_scsi_device(cdev->parent);
        struct scsi_device *tmp_sdev;
-       unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr,
-               *addl_desc_ptr;
+       unsigned char *buf = NULL, *hdr_buf, *type_ptr;
        struct ses_device *ses_dev;
        u32 result;
-       int i, j, types, len, components = 0;
+       int i, types, len, components = 0;
        int err = -ENOMEM;
        struct enclosure_device *edev;
        struct ses_component *scomp = NULL;
 
        if (!scsi_device_enclosure(sdev)) {
                /* not an enclosure, but might be in one */
-               edev = enclosure_find(&sdev->host->shost_gendev);
-               if (edev) {
+               struct enclosure_device *prev = NULL;
+
+               while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) {
                        ses_match_to_enclosure(edev, sdev);
-                       class_device_put(&edev->cdev);
+                       prev = edev;
                }
                return -ENODEV;
        }
@@ -447,7 +531,7 @@ static int ses_intf_add(struct class_device *cdev,
                 * traversal routines more complex */
                sdev_printk(KERN_ERR, sdev,
                        "FIXME driver has no support for subenclosures (%d)\n",
-                       buf[1]);
+                       hdr_buf[1]);
                goto err_free;
        }
 
@@ -461,9 +545,8 @@ static int ses_intf_add(struct class_device *cdev,
                goto recv_failed;
 
        types = buf[10];
-       len = buf[11];
 
-       type_ptr = buf + 12 + len;
+       type_ptr = buf + 12 + buf[11];
 
        for (i = 0; i < types; i++, type_ptr += 4) {
                if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
@@ -494,27 +577,27 @@ static int ses_intf_add(struct class_device *cdev,
        /* The additional information page --- allows us
         * to match up the devices */
        result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE);
-       if (result)
-               goto no_page10;
-
-       len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
-       buf = kzalloc(len, GFP_KERNEL);
-       if (!buf)
-               goto err_free;
-
-       result = ses_recv_diag(sdev, 10, buf, len);
-       if (result)
-               goto recv_failed;
-       ses_dev->page10 = buf;
-       ses_dev->page10_len = len;
-       buf = NULL;
+       if (!result) {
+
+               len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
+               buf = kzalloc(len, GFP_KERNEL);
+               if (!buf)
+                       goto err_free;
+
+               result = ses_recv_diag(sdev, 10, buf, len);
+               if (result)
+                       goto recv_failed;
+               ses_dev->page10 = buf;
+               ses_dev->page10_len = len;
+               buf = NULL;
+       }
+       kfree(hdr_buf);
 
- no_page10:
        scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
        if (!scomp)
                goto err_free;
 
-       edev = enclosure_register(cdev->dev, sdev->sdev_gendev.bus_id,
+       edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev),
                                  components, &ses_enclosure_callbacks);
        if (IS_ERR(edev)) {
                err = PTR_ERR(edev);
@@ -525,65 +608,7 @@ static int ses_intf_add(struct class_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;
-
-       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;
-               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) {
-                               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)
-                               continue;
-                       ecomp = enclosure_component_register(edev,
-                                                            components++,
-                                                            type_ptr[0],
-                                                            name);
-                       if (desc_ptr) {
-                               desc_ptr += len;
-                               if (!IS_ERR(ecomp))
-                                       ses_process_descriptor(ecomp,
-                                                              addl_desc_ptr);
-
-                               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 */
@@ -617,17 +642,26 @@ static int ses_remove(struct device *dev)
        return 0;
 }
 
-static void ses_intf_remove(struct class_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->dev);
        struct enclosure_device *edev;
        struct ses_device *ses_dev;
 
-       if (!scsi_device_enclosure(sdev))
-               return;
-
-       edev = enclosure_find(cdev->dev);
+       /*  exact match to this enclosure */
+       edev = enclosure_find(&sdev->sdev_gendev, NULL);
        if (!edev)
                return;
 
@@ -641,13 +675,24 @@ static void ses_intf_remove(struct class_device *cdev,
 
        kfree(edev->component[0].scratch);
 
-       class_device_put(&edev->cdev);
+       put_device(&edev->edev);
        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    = ses_intf_add,
-       .remove = ses_intf_remove,
+       .add_dev        = ses_intf_add,
+       .remove_dev     = ses_intf_remove,
 };
 
 static struct scsi_driver ses_template = {