]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'scsi/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 9 Apr 2015 07:48:08 +0000 (17:48 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 9 Apr 2015 07:48:08 +0000 (17:48 +1000)
24 files changed:
drivers/misc/enclosure.c
drivers/scsi/NCR5380.c
drivers/scsi/aic7xxx/aic79xx_core.c
drivers/scsi/aic7xxx/aic79xx_osm.c
drivers/scsi/aic7xxx/aic7xxx_core.c
drivers/scsi/aic7xxx/aic7xxx_osm.c
drivers/scsi/atari_NCR5380.c
drivers/scsi/atari_scsi.c
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/g_NCR5380.c
drivers/scsi/mac_scsi.c
drivers/scsi/scsi.c
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/sun3_scsi.c
drivers/scsi/ufs/ufs.h
drivers/scsi/ufs/ufshcd.c
include/linux/blk_types.h
include/scsi/scsi.h
include/uapi/scsi/Kbuild
include/uapi/scsi/ufs/Kbuild [new file with mode: 0644]
include/uapi/scsi/ufs/ioctl.h [new file with mode: 0644]
include/uapi/scsi/ufs/ufs.h [new file with mode: 0644]

index 38552a31304aff8cf2747d0f6278897bd6b87d72..65fed7146e9bac2a407df1c05710d6a6eb75e6c4 100644 (file)
@@ -202,16 +202,17 @@ static void enclosure_remove_links(struct enclosure_component *cdev)
 {
        char name[ENCLOSURE_NAME_SIZE];
 
+       enclosure_link_name(cdev, name);
+
        /*
         * In odd circumstances, like multipath devices, something else may
         * already have removed the links, so check for this condition first.
         */
-       if (!cdev->dev->kobj.sd)
-               return;
+       if (cdev->dev->kobj.sd)
+               sysfs_remove_link(&cdev->dev->kobj, name);
 
-       enclosure_link_name(cdev, name);
-       sysfs_remove_link(&cdev->dev->kobj, name);
-       sysfs_remove_link(&cdev->cdev.kobj, "device");
+       if (cdev->cdev.kobj.sd)
+               sysfs_remove_link(&cdev->cdev.kobj, "device");
 }
 
 static int enclosure_add_links(struct enclosure_component *cdev)
index 8981701802ca72720d70c16e56d0dec30cc28b08..a777e5c412df262b3f7fc72b55676d681ade9cb8 100644 (file)
@@ -474,11 +474,11 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
  */
 #ifndef USLEEP_SLEEP
 /* 20 ms (reasonable hard disk speed) */
-#define USLEEP_SLEEP (20*HZ/1000)
+#define USLEEP_SLEEP msecs_to_jiffies(20)
 #endif
 /* 300 RPM (floppy speed) */
 #ifndef USLEEP_POLL
-#define USLEEP_POLL (200*HZ/1000)
+#define USLEEP_POLL msecs_to_jiffies(200)
 #endif
 #ifndef USLEEP_WAITLONG
 /* RvC: (reasonable time to wait on select error) */
@@ -576,7 +576,7 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
                if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
                        trying_irqs |= mask;
 
-       timeout = jiffies + (250 * HZ / 1000);
+       timeout = jiffies + msecs_to_jiffies(250);
        probe_irq = NO_IRQ;
 
        /*
@@ -634,7 +634,7 @@ static void prepare_info(struct Scsi_Host *instance)
                 "sg_tablesize %d, this_id %d, "
                 "flags { %s%s%s}, "
 #if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
-                "USLEEP_POLL %d, USLEEP_WAITLONG %d, "
+                "USLEEP_POLL %lu, USLEEP_WAITLONG %lu, "
 #endif
                 "options { %s} ",
                 instance->hostt->name, instance->io_port, instance->n_io_port,
@@ -1346,7 +1346,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
         * selection.
         */
 
-       timeout = jiffies + (250 * HZ / 1000);
+       timeout = jiffies + msecs_to_jiffies(250);
 
        /* 
         * XXX very interesting - we're seeing a bounce where the BSY we 
index 97f2accd3dbb48ac9d6ecc295756670d3a98cccc..109e2c99e6c162e01a4b569292bad7b4e68fd3dc 100644 (file)
@@ -10437,14 +10437,13 @@ ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
                                return;
                        }
                }
-               lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
+               lstate = kzalloc(sizeof(*lstate), GFP_ATOMIC);
                if (lstate == NULL) {
                        xpt_print_path(ccb->ccb_h.path);
                        printk("Couldn't allocate lstate\n");
                        ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
                        return;
                }
-               memset(lstate, 0, sizeof(*lstate));
                status = xpt_create_path(&lstate->path, /*periph*/NULL,
                                         xpt_path_path_id(ccb->ccb_h.path),
                                         xpt_path_target_id(ccb->ccb_h.path),
index d5c7b193d8d3d6c86e3432d478ce1e6385ddbf06..ce96a0be32820fa6b75460adf9e4b7f48587ab05 100644 (file)
@@ -1326,10 +1326,9 @@ int
 ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
 {
        ahd->platform_data =
-           kmalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC);
+           kzalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC);
        if (ahd->platform_data == NULL)
                return (ENOMEM);
-       memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
        ahd->platform_data->irq = AHD_LINUX_NOIRQ;
        ahd_lockinit(ahd);
        ahd->seltime = (aic79xx_seltime & 0x3) << 4;
index 10172a3af1b9c77563be8c2971498525894edea7..c4829d84b335d4afcab21301a84f1b45a1b4052a 100644 (file)
@@ -4464,10 +4464,9 @@ ahc_softc_init(struct ahc_softc *ahc)
        ahc->pause = ahc->unpause | PAUSE; 
        /* XXX The shared scb data stuff should be deprecated */
        if (ahc->scb_data == NULL) {
-               ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), GFP_ATOMIC);
+               ahc->scb_data = kzalloc(sizeof(*ahc->scb_data), GFP_ATOMIC);
                if (ahc->scb_data == NULL)
                        return (ENOMEM);
-               memset(ahc->scb_data, 0, sizeof(*ahc->scb_data));
        }
 
        return (0);
@@ -4780,10 +4779,10 @@ ahc_init_scbdata(struct ahc_softc *ahc)
        SLIST_INIT(&scb_data->sg_maps);
 
        /* Allocate SCB resources */
-       scb_data->scbarray = kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC);
+       scb_data->scbarray = kzalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC,
+                               GFP_ATOMIC);
        if (scb_data->scbarray == NULL)
                return (ENOMEM);
-       memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
 
        /* Determine the number of hardware SCBs and initialize them */
 
@@ -7558,14 +7557,13 @@ ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
                                return;
                        }
                }
-               lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC);
+               lstate = kzalloc(sizeof(*lstate), GFP_ATOMIC);
                if (lstate == NULL) {
                        xpt_print_path(ccb->ccb_h.path);
                        printk("Couldn't allocate lstate\n");
                        ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
                        return;
                }
-               memset(lstate, 0, sizeof(*lstate));
                status = xpt_create_path(&lstate->path, /*periph*/NULL,
                                         xpt_path_path_id(ccb->ccb_h.path),
                                         xpt_path_target_id(ccb->ccb_h.path),
index 88360116dbcb05787aff6323a41f20411ea53d69..a2f2c774cd6b75f5874d71b5970a739a6923abaa 100644 (file)
@@ -1214,10 +1214,9 @@ ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
 {
 
        ahc->platform_data =
-           kmalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC);
+           kzalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC);
        if (ahc->platform_data == NULL)
                return (ENOMEM);
-       memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
        ahc->platform_data->irq = AHC_LINUX_NOIRQ;
        ahc_lockinit(ahc);
        ahc->seltime = (aic7xxx_seltime & 0x3) << 4;
index a70255413e7f97aa3e786ebe446d435ac4ab3d95..db87ece6edb2cd317d463c1afb21f7b9a9942b33 100644 (file)
@@ -1486,7 +1486,7 @@ static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
         * selection.
         */
 
-       timeout = jiffies + (250 * HZ / 1000);
+       timeout = jiffies + msecs_to_jiffies(250);
 
        /*
         * XXX very interesting - we're seeing a bounce where the BSY we
index d1c37a386947b03d080524dac5f18c244580bd08..5ede3daa93dc546c63a67809882f61009fb29582 100644 (file)
@@ -1014,7 +1014,6 @@ static struct platform_driver atari_scsi_driver = {
        .remove = __exit_p(atari_scsi_remove),
        .driver = {
                .name   = DRV_MODULE_NAME,
-               .owner  = THIS_MODULE,
        },
 };
 
index a7cc618378187fb7d38e504d51befb93e78b223c..923a2b5a24395547212207312588b125f19de3a2 100644 (file)
@@ -5734,9 +5734,9 @@ free_port:
 hba_free:
        if (phba->msix_enabled)
                pci_disable_msix(phba->pcidev);
-       iscsi_host_remove(phba->shost);
        pci_dev_put(phba->pcidev);
        iscsi_host_free(phba->shost);
+       pci_set_drvdata(pcidev, NULL);
 disable_pci:
        pci_disable_device(pcidev);
        return ret;
index f35792f7051c0884e71fa8cbf4041172e5ddadf3..f8d2478b11cc7a53453899db7b256543c7f21a33 100644 (file)
@@ -57,9 +57,9 @@
  */
 
 /* settings for DTC3181E card with only Mustek scanner attached */
-#define USLEEP_POLL    1
-#define USLEEP_SLEEP   20
-#define USLEEP_WAITLONG        500
+#define USLEEP_POLL    msecs_to_jiffies(10)
+#define USLEEP_SLEEP   msecs_to_jiffies(200)
+#define USLEEP_WAITLONG        msecs_to_jiffies(5000)
 
 #define AUTOPROBE_IRQ
 
@@ -723,7 +723,7 @@ module_param(ncr_53c400a, int, 0);
 module_param(dtc_3181e, int, 0);
 MODULE_LICENSE("GPL");
 
-#ifndef SCSI_G_NCR5380_MEM
+#if !defined(SCSI_G_NCR5380_MEM) && defined(MODULE)
 static struct isapnp_device_id id_table[] = {
        {
         ISAPNP_ANY_ID, ISAPNP_ANY_ID,
index 1e85c07e3b6216f8698c21aee23cfb0328768028..d64a769b8155ccda7ab0d0368c9bb84eb717e6a6 100644 (file)
@@ -483,7 +483,6 @@ static struct platform_driver mac_scsi_driver = {
        .remove = __exit_p(mac_scsi_remove),
        .driver = {
                .name   = DRV_MODULE_NAME,
-               .owner  = THIS_MODULE,
        },
 };
 
index c9c3b579eeced06760dec98221547fd0f56a35de..3833bf59fb66a5b143eb7d9fa7145ac817095b6c 100644 (file)
@@ -972,18 +972,24 @@ EXPORT_SYMBOL(scsi_report_opcode);
  * Description: Gets a reference to the scsi_device and increments the use count
  * of the underlying LLDD module.  You must hold host_lock of the
  * parent Scsi_Host or already have a reference when calling this.
+ *
+ * This will fail if a device is deleted or cancelled, or when the LLD module
+ * is in the process of being unloaded.
  */
 int scsi_device_get(struct scsi_device *sdev)
 {
-       if (sdev->sdev_state == SDEV_DEL)
-               return -ENXIO;
+       if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
+               goto fail;
        if (!get_device(&sdev->sdev_gendev))
-               return -ENXIO;
-       /* We can fail try_module_get if we're doing SCSI operations
-        * from module exit (like cache flush) */
-       __module_get(sdev->host->hostt->module);
-
+               goto fail;
+       if (!try_module_get(sdev->host->hostt->module))
+               goto fail_put_device;
        return 0;
+
+fail_put_device:
+       put_device(&sdev->sdev_gendev);
+fail:
+       return -ENXIO;
 }
 EXPORT_SYMBOL(scsi_device_get);
 
index 54d7a6cbb98a48d06b932cce40c488488760da08..b1a263137a23391a1e19c2589f35fdaf2c4f514f 100644 (file)
@@ -1311,9 +1311,11 @@ scsi_prep_state_check(struct scsi_device *sdev, struct request *req)
                                    "rejecting I/O to dead device\n");
                        ret = BLKPREP_KILL;
                        break;
-               case SDEV_QUIESCE:
                case SDEV_BLOCK:
                case SDEV_CREATED_BLOCK:
+                       ret = BLKPREP_DEFER;
+                       break;
+               case SDEV_QUIESCE:
                        /*
                         * If the devices is blocked we defer normal commands.
                         */
index 9c0a520d933c91eaaf793a259ba099d87c8d3176..60aae01caa89d96cd8c78681a8f0a97b44cae8ec 100644 (file)
@@ -1570,16 +1570,15 @@ EXPORT_SYMBOL(scsi_add_device);
 
 void scsi_rescan_device(struct device *dev)
 {
-       if (!dev->driver)
-               return;
-
-       if (try_module_get(dev->driver->owner)) {
+       device_lock(dev);
+       if (dev->driver && try_module_get(dev->driver->owner)) {
                struct scsi_driver *drv = to_scsi_driver(dev->driver);
 
                if (drv->rescan)
                        drv->rescan(dev);
                module_put(dev->driver->owner);
        }
+       device_unlock(dev);
 }
 EXPORT_SYMBOL(scsi_rescan_device);
 
index 6b78476d04bbf6983e43eba95d65fd7bb49082da..9e0c63e57affd837c37ebe0d4b4cbda60e7862f5 100644 (file)
@@ -564,10 +564,12 @@ static int sd_major(int major_idx)
        }
 }
 
-static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
+static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
 {
        struct scsi_disk *sdkp = NULL;
 
+       mutex_lock(&sd_ref_mutex);
+
        if (disk->private_data) {
                sdkp = scsi_disk(disk);
                if (scsi_device_get(sdkp->device) == 0)
@@ -575,27 +577,6 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
                else
                        sdkp = NULL;
        }
-       return sdkp;
-}
-
-static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
-{
-       struct scsi_disk *sdkp;
-
-       mutex_lock(&sd_ref_mutex);
-       sdkp = __scsi_disk_get(disk);
-       mutex_unlock(&sd_ref_mutex);
-       return sdkp;
-}
-
-static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev)
-{
-       struct scsi_disk *sdkp;
-
-       mutex_lock(&sd_ref_mutex);
-       sdkp = dev_get_drvdata(dev);
-       if (sdkp)
-               sdkp = __scsi_disk_get(sdkp->disk);
        mutex_unlock(&sd_ref_mutex);
        return sdkp;
 }
@@ -610,8 +591,6 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
        mutex_unlock(&sd_ref_mutex);
 }
 
-
-
 static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
                                           unsigned int dix, unsigned int dif)
 {
@@ -1525,12 +1504,9 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
 
 static void sd_rescan(struct device *dev)
 {
-       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+       struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
-       if (sdkp) {
-               revalidate_disk(sdkp->disk);
-               scsi_disk_put(sdkp);
-       }
+       revalidate_disk(sdkp->disk);
 }
 
 
@@ -3149,13 +3125,13 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
  */
 static void sd_shutdown(struct device *dev)
 {
-       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+       struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
        if (!sdkp)
                return;         /* this can happen */
 
        if (pm_runtime_suspended(dev))
-               goto exit;
+               return;
 
        if (sdkp->WCE && sdkp->media_present) {
                sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n");
@@ -3166,14 +3142,11 @@ static void sd_shutdown(struct device *dev)
                sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n");
                sd_start_stop_device(sdkp, 0);
        }
-
-exit:
-       scsi_disk_put(sdkp);
 }
 
 static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
 {
-       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+       struct scsi_disk *sdkp = dev_get_drvdata(dev);
        int ret = 0;
 
        if (!sdkp)
@@ -3199,7 +3172,6 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors)
        }
 
 done:
-       scsi_disk_put(sdkp);
        return ret;
 }
 
@@ -3215,18 +3187,13 @@ static int sd_suspend_runtime(struct device *dev)
 
 static int sd_resume(struct device *dev)
 {
-       struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
-       int ret = 0;
+       struct scsi_disk *sdkp = dev_get_drvdata(dev);
 
        if (!sdkp->device->manage_start_stop)
-               goto done;
+               return 0;
 
        sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
-       ret = sd_start_stop_device(sdkp, 1);
-
-done:
-       scsi_disk_put(sdkp);
-       return ret;
+       return sd_start_stop_device(sdkp, 1);
 }
 
 /**
index 2a906d1d34baa87703e0541b93ba8512bf09eddf..22a42836d193a3723c4cb1193a0c72aeb9d99ffe 100644 (file)
@@ -676,7 +676,6 @@ static struct platform_driver sun3_scsi_driver = {
        .remove = __exit_p(sun3_scsi_remove),
        .driver = {
                .name   = DRV_MODULE_NAME,
-               .owner  = THIS_MODULE,
        },
 };
 
index 42c459a9d3fec7bf83aa047e6f3f97054d25bcee..1f023c4634f314471700cdb99035bd317a1f5018 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <linux/mutex.h>
 #include <linux/types.h>
+#include <scsi/ufs/ufs.h>
 
 #define MAX_CDB_SIZE   16
 #define GENERAL_UPIU_REQUEST_SIZE 32
@@ -71,6 +72,16 @@ enum {
        UFS_UPIU_RPMB_WLUN              = 0xC4,
 };
 
+/**
+ * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
+ * @lun: LU number to check
+ * @return: true if the lun has a matching unit descriptor, false otherwise
+ */
+static inline bool ufs_is_valid_unit_desc_lun(u8 lun)
+{
+       return (lun == UFS_UPIU_RPMB_WLUN || (lun < UFS_UPIU_MAX_GENERAL_LUN));
+}
+
 /*
  * UFS Protocol Information Unit related definitions
  */
@@ -126,35 +137,6 @@ enum {
        UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST          = 0x81,
 };
 
-/* Flag idn for Query Requests*/
-enum flag_idn {
-       QUERY_FLAG_IDN_FDEVICEINIT      = 0x01,
-       QUERY_FLAG_IDN_PWR_ON_WPE       = 0x03,
-       QUERY_FLAG_IDN_BKOPS_EN         = 0x04,
-};
-
-/* Attribute idn for Query requests */
-enum attr_idn {
-       QUERY_ATTR_IDN_ACTIVE_ICC_LVL   = 0x03,
-       QUERY_ATTR_IDN_BKOPS_STATUS     = 0x05,
-       QUERY_ATTR_IDN_EE_CONTROL       = 0x0D,
-       QUERY_ATTR_IDN_EE_STATUS        = 0x0E,
-};
-
-/* Descriptor idn for Query requests */
-enum desc_idn {
-       QUERY_DESC_IDN_DEVICE           = 0x0,
-       QUERY_DESC_IDN_CONFIGURAION     = 0x1,
-       QUERY_DESC_IDN_UNIT             = 0x2,
-       QUERY_DESC_IDN_RFU_0            = 0x3,
-       QUERY_DESC_IDN_INTERCONNECT     = 0x4,
-       QUERY_DESC_IDN_STRING           = 0x5,
-       QUERY_DESC_IDN_RFU_1            = 0x6,
-       QUERY_DESC_IDN_GEOMETRY         = 0x7,
-       QUERY_DESC_IDN_POWER            = 0x8,
-       QUERY_DESC_IDN_MAX,
-};
-
 enum desc_header_offset {
        QUERY_DESC_LENGTH_OFFSET        = 0x00,
        QUERY_DESC_DESC_TYPE_OFFSET     = 0x01,
@@ -247,19 +229,6 @@ enum bkops_status {
        BKOPS_STATUS_MAX                 = BKOPS_STATUS_CRITICAL,
 };
 
-/* UTP QUERY Transaction Specific Fields OpCode */
-enum query_opcode {
-       UPIU_QUERY_OPCODE_NOP           = 0x0,
-       UPIU_QUERY_OPCODE_READ_DESC     = 0x1,
-       UPIU_QUERY_OPCODE_WRITE_DESC    = 0x2,
-       UPIU_QUERY_OPCODE_READ_ATTR     = 0x3,
-       UPIU_QUERY_OPCODE_WRITE_ATTR    = 0x4,
-       UPIU_QUERY_OPCODE_READ_FLAG     = 0x5,
-       UPIU_QUERY_OPCODE_SET_FLAG      = 0x6,
-       UPIU_QUERY_OPCODE_CLEAR_FLAG    = 0x7,
-       UPIU_QUERY_OPCODE_TOGGLE_FLAG   = 0x8,
-};
-
 /* Query response result code */
 enum {
        QUERY_RESULT_SUCCESS                    = 0x00,
index 2aa85e398f769e66f14838dbfee94759089c1fea..b5b6fbfdfecf1c2030e0841f200d8c7a37dec4c0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This code is based on drivers/scsi/ufs/ufshcd.c
  * Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
  *
  * Authors:
  *     Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -39,6 +39,7 @@
 
 #include <linux/async.h>
 #include <linux/devfreq.h>
+#include <scsi/ufs/ioctl.h>
 
 #include "ufshcd.h"
 #include "unipro.h"
@@ -74,6 +75,9 @@
 /* Interrupt aggregation default timeout, unit: 40us */
 #define INT_AGGR_DEF_TO        0x02
 
+/* IOCTL opcode for command - ufs set device read only */
+#define UFS_IOCTL_BLKROSET      BLKROSET
+
 #define ufshcd_toggle_vreg(_dev, _vreg, _on)                           \
        ({                                                              \
                int _ret;                                               \
@@ -1882,7 +1886,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba,
         * Unit descriptors are only available for general purpose LUs (LUN id
         * from 0 to 7) and RPMB Well known LU.
         */
-       if (lun != UFS_UPIU_RPMB_WLUN && (lun >= UFS_UPIU_MAX_GENERAL_LUN))
+       if (!ufs_is_valid_unit_desc_lun(lun))
                return -EOPNOTSUPP;
 
        return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -4201,6 +4205,223 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
        ufshcd_probe_hba(hba);
 }
 
+/**
+ * ufshcd_query_ioctl - perform user read queries
+ * @hba: per-adapter instance
+ * @lun: used for lun specific queries
+ * @buffer: user space buffer for reading and submitting query data and params
+ * @return: 0 for success negative error code otherwise
+ *
+ * Expected/Submitted buffer structure is struct ufs_ioctl_query_data.
+ * It will read the opcode, idn and buf_length parameters, and, put the
+ * response in the buffer field while updating the used size in buf_length.
+ */
+static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
+{
+       struct ufs_ioctl_query_data *ioctl_data;
+       int err = 0;
+       int length = 0;
+       void *data_ptr;
+       bool flag;
+       u32 att;
+       u8 index;
+       u8 *desc = NULL;
+
+       if (!buffer) {
+               dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__);
+               return -EINVAL;
+       }
+
+       ioctl_data = kzalloc(sizeof(struct ufs_ioctl_query_data), GFP_KERNEL);
+       if (!ioctl_data) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* extract params from user buffer */
+       err = copy_from_user(ioctl_data, buffer,
+                       sizeof(struct ufs_ioctl_query_data));
+       if (err) {
+               dev_err(hba->dev,
+                       "%s: Failed copying buffer from user, err %d\n",
+                       __func__, err);
+               goto out_release_mem;
+       }
+
+       /* verify legal parameters & send query */
+       switch (ioctl_data->opcode) {
+       case UPIU_QUERY_OPCODE_READ_DESC:
+               switch (ioctl_data->idn) {
+               case QUERY_DESC_IDN_DEVICE:
+               case QUERY_DESC_IDN_CONFIGURAION:
+               case QUERY_DESC_IDN_INTERCONNECT:
+               case QUERY_DESC_IDN_GEOMETRY:
+               case QUERY_DESC_IDN_POWER:
+                       index = 0;
+                       break;
+               case QUERY_DESC_IDN_UNIT:
+                       if (!ufs_is_valid_unit_desc_lun(lun)) {
+                               dev_err(hba->dev,
+                                       "%s: No unit descriptor for lun 0x%x\n",
+                                       __func__, lun);
+                               err = -EINVAL;
+                               goto out_release_mem;
+                       }
+                       index = lun;
+                       break;
+               default:
+                       goto out_einval;
+               }
+               length = min_t(int, QUERY_DESC_MAX_SIZE,
+                               ioctl_data->buf_size);
+               desc = kzalloc(length, GFP_KERNEL);
+               if (!desc) {
+                       dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
+                                       __func__, length);
+                       err = -ENOMEM;
+                       goto out_release_mem;
+               }
+               err = ufshcd_query_descriptor(hba, ioctl_data->opcode,
+                               ioctl_data->idn, index, 0, desc, &length);
+               break;
+       case UPIU_QUERY_OPCODE_READ_ATTR:
+               switch (ioctl_data->idn) {
+               case QUERY_ATTR_IDN_BOOT_LU_EN:
+               case QUERY_ATTR_IDN_POWER_MODE:
+               case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
+               case QUERY_ATTR_IDN_OOO_DATA_EN:
+               case QUERY_ATTR_IDN_BKOPS_STATUS:
+               case QUERY_ATTR_IDN_PURGE_STATUS:
+               case QUERY_ATTR_IDN_MAX_DATA_IN:
+               case QUERY_ATTR_IDN_MAX_DATA_OUT:
+               case QUERY_ATTR_IDN_REF_CLK_FREQ:
+               case QUERY_ATTR_IDN_CONF_DESC_LOCK:
+               case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
+               case QUERY_ATTR_IDN_EE_CONTROL:
+               case QUERY_ATTR_IDN_EE_STATUS:
+               case QUERY_ATTR_IDN_SECONDS_PASSED:
+                       index = 0;
+                       break;
+               case QUERY_ATTR_IDN_DYN_CAP_NEEDED:
+               case QUERY_ATTR_IDN_CORR_PRG_BLK_NUM:
+                       index = lun;
+                       break;
+               default:
+                       goto out_einval;
+               }
+               err = ufshcd_query_attr(hba, ioctl_data->opcode,
+                                       ioctl_data->idn, index, 0, &att);
+               break;
+       case UPIU_QUERY_OPCODE_READ_FLAG:
+               switch (ioctl_data->idn) {
+               case QUERY_FLAG_IDN_FDEVICEINIT:
+               case QUERY_FLAG_IDN_PERMANENT_WPE:
+               case QUERY_FLAG_IDN_PWR_ON_WPE:
+               case QUERY_FLAG_IDN_BKOPS_EN:
+               case QUERY_FLAG_IDN_PURGE_ENABLE:
+               case QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL:
+               case QUERY_FLAG_IDN_BUSY_RTC:
+                       break;
+               default:
+                       goto out_einval;
+               }
+               err = ufshcd_query_flag(hba, ioctl_data->opcode,
+                                       ioctl_data->idn, &flag);
+               break;
+       default:
+               goto out_einval;
+       }
+
+       if (err) {
+               dev_err(hba->dev, "%s: Query for idn %d failed\n", __func__,
+                                       ioctl_data->idn);
+               goto out_release_mem;
+       }
+
+       /*
+        * copy response data
+        * As we might end up reading less data then what is specified in
+        * "ioct_data->buf_size". So we are updating "ioct_data->
+        * buf_size" to what exactly we have read.
+        */
+       switch (ioctl_data->opcode) {
+       case UPIU_QUERY_OPCODE_READ_DESC:
+               ioctl_data->buf_size = min_t(int, ioctl_data->buf_size, length);
+               data_ptr = desc;
+               break;
+       case UPIU_QUERY_OPCODE_READ_ATTR:
+               ioctl_data->buf_size = sizeof(u32);
+               data_ptr = &att;
+               break;
+       case UPIU_QUERY_OPCODE_READ_FLAG:
+               ioctl_data->buf_size = 1;
+               data_ptr = &flag;
+               break;
+       default:
+               BUG_ON(true);
+       }
+
+       /* copy to user */
+       err = copy_to_user(buffer, ioctl_data,
+                       sizeof(struct ufs_ioctl_query_data));
+       if (err)
+               dev_err(hba->dev, "%s: Failed copying back to user.\n",
+                       __func__);
+       err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data),
+                       data_ptr, ioctl_data->buf_size);
+       if (err)
+               dev_err(hba->dev, "%s: err %d copying back to user.\n",
+                               __func__, err);
+       goto out_release_mem;
+
+out_einval:
+       dev_err(hba->dev,
+               "%s: illegal ufs query ioctl data, opcode 0x%x, idn 0x%x\n",
+               __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn);
+       err = -EINVAL;
+out_release_mem:
+       kfree(ioctl_data);
+       kfree(desc);
+out:
+       return err;
+}
+
+/**
+ * ufshcd_ioctl - ufs ioctl callback registered in scsi_host
+ * @dev: scsi device required for per LUN queries
+ * @cmd: command opcode
+ * @buffer: user space buffer for transferring data
+ *
+ * Supported commands:
+ * UFS_IOCTL_QUERY
+ */
+static int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
+{
+       struct ufs_hba *hba = shost_priv(dev->host);
+       int err = 0;
+
+       BUG_ON(!hba);
+
+       switch (cmd) {
+       case UFS_IOCTL_QUERY:
+               pm_runtime_get_sync(hba->dev);
+               err = ufshcd_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun),
+                               buffer);
+               pm_runtime_put_sync(hba->dev);
+               break;
+       case UFS_IOCTL_BLKROSET:
+               err = -ENOIOCTLCMD;
+               break;
+       default:
+               err = -EINVAL;
+               dev_err(hba->dev, "%s: Illegal ufs-IOCTL cmd %d\n", __func__,
+                               cmd);
+               break;
+       }
+
+       return err;
+}
+
 static struct scsi_host_template ufshcd_driver_template = {
        .module                 = THIS_MODULE,
        .name                   = UFSHCD,
@@ -4213,6 +4434,7 @@ static struct scsi_host_template ufshcd_driver_template = {
        .eh_abort_handler       = ufshcd_abort,
        .eh_device_reset_handler = ufshcd_eh_device_reset_handler,
        .eh_host_reset_handler   = ufshcd_eh_host_reset_handler,
+       .ioctl                  = ufshcd_ioctl,
        .this_id                = -1,
        .sg_tablesize           = SG_ALL,
        .cmd_per_lun            = UFSHCD_CMD_PER_LUN,
index c294e3e25e37a50a953a4a0bb3cb1aa66ba904d9..a1b25e35ea5f9fc2978b7f62917c6b4e39c3dc75 100644 (file)
@@ -181,7 +181,9 @@ enum rq_flag_bits {
        __REQ_ELVPRIV,          /* elevator private data attached */
        __REQ_FAILED,           /* set if the request failed */
        __REQ_QUIET,            /* don't worry about errors */
-       __REQ_PREEMPT,          /* set for "ide_preempt" requests */
+       __REQ_PREEMPT,          /* set for "ide_preempt" requests and also
+                                  for requests for which the SCSI "quiesce"
+                                  state must be ignored. */
        __REQ_ALLOCED,          /* request came from our alloc pool */
        __REQ_COPY_USER,        /* contains copies of user pages */
        __REQ_FLUSH_SEQ,        /* request for flush sequence */
index d0a66aa1868d2841f80a52843fb719e6323afe2f..3feb50126777fe6b0f09da75f44fe9625f79ff51 100644 (file)
@@ -569,6 +569,7 @@ static inline int scsi_is_wlun(u64 lun)
  * Here are some scsi specific ioctl commands which are sometimes useful.
  *
  * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395
+ * include/uapi/scsi/ufs/ioctl.h defines 0x5388
  */
 
 /* Used to obtain PUN and LUN info.  Conflicts with CDROMAUDIOBUFSIZ */
index 75746d52f208bfd34724dead19915728e47eafa0..d404525bd5154cc1dfab3a8d0f2253a79b105867 100644 (file)
@@ -1,5 +1,6 @@
 # UAPI Header export list
 header-y += fc/
+header-y += ufs/
 header-y += scsi_bsg_fc.h
 header-y += scsi_netlink.h
 header-y += scsi_netlink_fc.h
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
new file mode 100644 (file)
index 0000000..cc3ef20
--- /dev/null
@@ -0,0 +1,3 @@
+# UAPI Header export list
+header-y += ioctl.h
+header-y += ufs.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
new file mode 100644 (file)
index 0000000..bc4eed7
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef UAPI_UFS_IOCTL_H_
+#define UAPI_UFS_IOCTL_H_
+
+#include <linux/types.h>
+
+/*
+ *  IOCTL opcode for ufs queries has the following opcode after
+ *  SCSI_IOCTL_GET_PCI
+ */
+#define UFS_IOCTL_QUERY                        0x5388
+
+/**
+ * struct ufs_ioctl_query_data - used to transfer data to and from user via ioctl
+ * @opcode: type of data to query (descriptor/attribute/flag)
+ * @idn: id of the data structure
+ * @buf_size: number of allocated bytes/data size on return
+ * @buffer: data location
+ *
+ * Received: buffer and buf_size (available space for transferred data)
+ * Submitted: opcode, idn, length, buf_size
+ */
+struct ufs_ioctl_query_data {
+       /*
+        * User should select one of the opcode defined in "enum query_opcode".
+        * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+        * Note that only UPIU_QUERY_OPCODE_READ_DESC,
+        * UPIU_QUERY_OPCODE_READ_ATTR & UPIU_QUERY_OPCODE_READ_FLAG are
+        * supported as of now. All other query_opcode would be considered
+        * invalid.
+        * As of now only read query operations are supported.
+        */
+       __u32 opcode;
+       /*
+        * User should select one of the idn from "enum flag_idn" or "enum
+        * attr_idn" or "enum desc_idn" based on whether opcode above is
+        * attribute, flag or descriptor.
+        * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+        */
+       __u8 idn;
+       /*
+        * User should specify the size of the buffer (buffer[0] below) where
+        * it wants to read the query data (attribute/flag/descriptor).
+        * As we might end up reading less data then what is specified in
+        * buf_size. So we are updating buf_size to what exactly we have read.
+        */
+       __u16 buf_size;
+       /*
+        * placeholder for the start of the data buffer where kernel will copy
+        * the query data (attribute/flag/descriptor) read from the UFS device
+        * Note:
+        * For Read Attribute you will have to allocate 4 bytes
+        * For Read Flag you will have to allocate 1 byte
+        */
+       __u8 buffer[0];
+};
+
+#endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h
new file mode 100644 (file)
index 0000000..894ea45
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef UAPI_UFS_H_
+#define UAPI_UFS_H_
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+       QUERY_FLAG_IDN_FDEVICEINIT              = 0x01,
+       QUERY_FLAG_IDN_PERMANENT_WPE            = 0x02,
+       QUERY_FLAG_IDN_PWR_ON_WPE               = 0x03,
+       QUERY_FLAG_IDN_BKOPS_EN                 = 0x04,
+       QUERY_FLAG_IDN_RESERVED1                = 0x05,
+       QUERY_FLAG_IDN_PURGE_ENABLE             = 0x06,
+       QUERY_FLAG_IDN_RESERVED2                = 0x07,
+       QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL      = 0x08,
+       QUERY_FLAG_IDN_BUSY_RTC                 = 0x09,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+       QUERY_ATTR_IDN_BOOT_LU_EN               = 0x00,
+       QUERY_ATTR_IDN_RESERVED                 = 0x01,
+       QUERY_ATTR_IDN_POWER_MODE               = 0x02,
+       QUERY_ATTR_IDN_ACTIVE_ICC_LVL           = 0x03,
+       QUERY_ATTR_IDN_OOO_DATA_EN              = 0x04,
+       QUERY_ATTR_IDN_BKOPS_STATUS             = 0x05,
+       QUERY_ATTR_IDN_PURGE_STATUS             = 0x06,
+       QUERY_ATTR_IDN_MAX_DATA_IN              = 0x07,
+       QUERY_ATTR_IDN_MAX_DATA_OUT             = 0x08,
+       QUERY_ATTR_IDN_DYN_CAP_NEEDED           = 0x09,
+       QUERY_ATTR_IDN_REF_CLK_FREQ             = 0x0A,
+       QUERY_ATTR_IDN_CONF_DESC_LOCK           = 0x0B,
+       QUERY_ATTR_IDN_MAX_NUM_OF_RTT           = 0x0C,
+       QUERY_ATTR_IDN_EE_CONTROL               = 0x0D,
+       QUERY_ATTR_IDN_EE_STATUS                = 0x0E,
+       QUERY_ATTR_IDN_SECONDS_PASSED           = 0x0F,
+       QUERY_ATTR_IDN_CNTX_CONF                = 0x10,
+       QUERY_ATTR_IDN_CORR_PRG_BLK_NUM         = 0x11,
+};
+
+/* Descriptor idn for Query requests */
+enum desc_idn {
+       QUERY_DESC_IDN_DEVICE           = 0x0,
+       QUERY_DESC_IDN_CONFIGURAION     = 0x1,
+       QUERY_DESC_IDN_UNIT             = 0x2,
+       QUERY_DESC_IDN_RFU_0            = 0x3,
+       QUERY_DESC_IDN_INTERCONNECT     = 0x4,
+       QUERY_DESC_IDN_STRING           = 0x5,
+       QUERY_DESC_IDN_RFU_1            = 0x6,
+       QUERY_DESC_IDN_GEOMETRY         = 0x7,
+       QUERY_DESC_IDN_POWER            = 0x8,
+       QUERY_DESC_IDN_RFU_2            = 0x9,
+       QUERY_DESC_IDN_MAX,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
+       UPIU_QUERY_OPCODE_NOP           = 0x0,
+       UPIU_QUERY_OPCODE_READ_DESC     = 0x1,
+       UPIU_QUERY_OPCODE_WRITE_DESC    = 0x2,
+       UPIU_QUERY_OPCODE_READ_ATTR     = 0x3,
+       UPIU_QUERY_OPCODE_WRITE_ATTR    = 0x4,
+       UPIU_QUERY_OPCODE_READ_FLAG     = 0x5,
+       UPIU_QUERY_OPCODE_SET_FLAG      = 0x6,
+       UPIU_QUERY_OPCODE_CLEAR_FLAG    = 0x7,
+       UPIU_QUERY_OPCODE_TOGGLE_FLAG   = 0x8,
+};
+#endif /* UAPI_UFS_H_ */