linux/drivers/staging/keucr/scsiglue.c
<<
>>
Prefs
   1#include <linux/slab.h>
   2#include <linux/module.h>
   3#include <linux/mutex.h>
   4
   5#include <scsi/scsi.h>
   6#include <scsi/scsi_cmnd.h>
   7#include <scsi/scsi_devinfo.h>
   8#include <scsi/scsi_device.h>
   9#include <scsi/scsi_eh.h>
  10
  11#include "usb.h"
  12#include "scsiglue.h"
  13#include "transport.h"
  14
  15/* Host functions */
  16//----- host_info() ---------------------
  17static const char* host_info(struct Scsi_Host *host)
  18{
  19        //printk("scsiglue --- host_info\n");
  20        return "SCSI emulation for USB Mass Storage devices";
  21}
  22
  23//----- slave_alloc() ---------------------
  24static int slave_alloc(struct scsi_device *sdev)
  25{
  26        struct us_data *us = host_to_us(sdev->host);
  27
  28        //printk("scsiglue --- slave_alloc\n");
  29        sdev->inquiry_len = 36;
  30
  31        blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
  32
  33        if (us->subclass == USB_SC_UFI)
  34                sdev->sdev_target->pdt_1f_for_no_lun = 1;
  35
  36        return 0;
  37}
  38
  39//----- slave_configure() ---------------------
  40static int slave_configure(struct scsi_device *sdev)
  41{
  42        struct us_data *us = host_to_us(sdev->host);
  43
  44        //printk("scsiglue --- slave_configure\n");
  45        if (us->fflags & (US_FL_MAX_SECTORS_64 | US_FL_MAX_SECTORS_MIN))
  46        {
  47                unsigned int max_sectors = 64;
  48
  49                if (us->fflags & US_FL_MAX_SECTORS_MIN)
  50                        max_sectors = PAGE_CACHE_SIZE >> 9;
  51                if (queue_max_sectors(sdev->request_queue) > max_sectors)
  52                        blk_queue_max_hw_sectors(sdev->request_queue,
  53                                              max_sectors);
  54        }
  55
  56        if (sdev->type == TYPE_DISK)
  57        {
  58                if (us->subclass != USB_SC_SCSI && us->subclass != USB_SC_CYP_ATACB)
  59                        sdev->use_10_for_ms = 1;
  60                sdev->use_192_bytes_for_3f = 1;
  61                if (us->fflags & US_FL_NO_WP_DETECT)
  62                        sdev->skip_ms_page_3f = 1;
  63                sdev->skip_ms_page_8 = 1;
  64                if (us->fflags & US_FL_FIX_CAPACITY)
  65                        sdev->fix_capacity = 1;
  66                if (us->fflags & US_FL_CAPACITY_HEURISTICS)
  67                        sdev->guess_capacity = 1;
  68                if (sdev->scsi_level > SCSI_2)
  69                        sdev->sdev_target->scsi_level = sdev->scsi_level = SCSI_2;
  70                sdev->retry_hwerror = 1;
  71                sdev->allow_restart = 1;
  72                sdev->last_sector_bug = 1;
  73        }
  74        else
  75        {
  76                sdev->use_10_for_ms = 1;
  77        }
  78
  79        if ((us->protocol == USB_PR_CB || us->protocol == USB_PR_CBI) && sdev->scsi_level == SCSI_UNKNOWN)
  80                us->max_lun = 0;
  81
  82        if (us->fflags & US_FL_NOT_LOCKABLE)
  83                sdev->lockable = 0;
  84
  85        return 0;
  86}
  87
  88/* This is always called with scsi_lock(host) held */
  89//----- queuecommand() ---------------------
  90static int queuecommand_lck(struct scsi_cmnd *srb, void (*done)(struct scsi_cmnd *))
  91{
  92        struct us_data *us = host_to_us(srb->device->host);
  93
  94        //printk("scsiglue --- queuecommand\n");
  95
  96        /* check for state-transition errors */
  97        if (us->srb != NULL)
  98        {
  99                printk("Error in %s: us->srb = %p\n", __FUNCTION__, us->srb);
 100                return SCSI_MLQUEUE_HOST_BUSY;
 101        }
 102
 103        /* fail the command if we are disconnecting */
 104        if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags))
 105        {
 106                printk("Fail command during disconnect\n");
 107                srb->result = DID_NO_CONNECT << 16;
 108                done(srb);
 109                return 0;
 110        }
 111
 112        /* enqueue the command and wake up the control thread */
 113        srb->scsi_done = done;
 114        us->srb = srb;
 115        complete(&us->cmnd_ready);
 116
 117        return 0;
 118}
 119
 120static DEF_SCSI_QCMD(queuecommand)
 121
 122/***********************************************************************
 123 * Error handling functions
 124 ***********************************************************************/
 125
 126/* Command timeout and abort */
 127//----- command_abort() ---------------------
 128static int command_abort(struct scsi_cmnd *srb)
 129{
 130        struct us_data *us = host_to_us(srb->device->host);
 131
 132        //printk("scsiglue --- command_abort\n");
 133
 134        scsi_lock(us_to_host(us));
 135        if (us->srb != srb)
 136        {
 137                scsi_unlock(us_to_host(us));
 138                printk ("-- nothing to abort\n");
 139                return FAILED;
 140        }
 141
 142        set_bit(US_FLIDX_TIMED_OUT, &us->dflags);
 143        if (!test_bit(US_FLIDX_RESETTING, &us->dflags))
 144        {
 145                set_bit(US_FLIDX_ABORTING, &us->dflags);
 146                usb_stor_stop_transport(us);
 147        }
 148        scsi_unlock(us_to_host(us));
 149
 150        /* Wait for the aborted command to finish */
 151        wait_for_completion(&us->notify);
 152        return SUCCESS;
 153}
 154
 155/* This invokes the transport reset mechanism to reset the state of the device */
 156//----- device_reset() ---------------------
 157static int device_reset(struct scsi_cmnd *srb)
 158{
 159        struct us_data *us = host_to_us(srb->device->host);
 160        int result;
 161
 162        //printk("scsiglue --- device_reset\n");
 163
 164        /* lock the device pointers and do the reset */
 165        mutex_lock(&(us->dev_mutex));
 166        result = us->transport_reset(us);
 167        mutex_unlock(&us->dev_mutex);
 168
 169        return result < 0 ? FAILED : SUCCESS;
 170}
 171
 172//----- bus_reset() ---------------------
 173static int bus_reset(struct scsi_cmnd *srb)
 174{
 175        struct us_data *us = host_to_us(srb->device->host);
 176        int result;
 177
 178        //printk("scsiglue --- bus_reset\n");
 179        result = usb_stor_port_reset(us);
 180        return result < 0 ? FAILED : SUCCESS;
 181}
 182
 183//----- usb_stor_report_device_reset() ---------------------
 184void usb_stor_report_device_reset(struct us_data *us)
 185{
 186        int i;
 187        struct Scsi_Host *host = us_to_host(us);
 188
 189        //printk("scsiglue --- usb_stor_report_device_reset\n");
 190        scsi_report_device_reset(host, 0, 0);
 191        if (us->fflags & US_FL_SCM_MULT_TARG)
 192        {
 193                for (i = 1; i < host->max_id; ++i)
 194                        scsi_report_device_reset(host, 0, i);
 195        }
 196}
 197
 198//----- usb_stor_report_bus_reset() ---------------------
 199void usb_stor_report_bus_reset(struct us_data *us)
 200{
 201        struct Scsi_Host *host = us_to_host(us);
 202
 203        //printk("scsiglue --- usb_stor_report_bus_reset\n");
 204        scsi_lock(host);
 205        scsi_report_bus_reset(host, 0);
 206        scsi_unlock(host);
 207}
 208
 209/***********************************************************************
 210 * /proc/scsi/ functions
 211 ***********************************************************************/
 212
 213/* we use this macro to help us write into the buffer */
 214#undef SPRINTF
 215#define SPRINTF(args...) \
 216        do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
 217
 218//----- proc_info() ---------------------
 219static int proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
 220{
 221        struct us_data *us = host_to_us(host);
 222        char *pos = buffer;
 223        const char *string;
 224
 225        //printk("scsiglue --- proc_info\n");
 226        if (inout)
 227                return length;
 228
 229        /* print the controller name */
 230        SPRINTF("   Host scsi%d: usb-storage\n", host->host_no);
 231
 232        /* print product, vendor, and serial number strings */
 233        if (us->pusb_dev->manufacturer)
 234                string = us->pusb_dev->manufacturer;
 235        else if (us->unusual_dev->vendorName)
 236                string = us->unusual_dev->vendorName;
 237        else
 238                string = "Unknown";
 239        SPRINTF("       Vendor: %s\n", string);
 240        if (us->pusb_dev->product)
 241                string = us->pusb_dev->product;
 242        else if (us->unusual_dev->productName)
 243                string = us->unusual_dev->productName;
 244        else
 245                string = "Unknown";
 246        SPRINTF("      Product: %s\n", string);
 247        if (us->pusb_dev->serial)
 248                string = us->pusb_dev->serial;
 249        else
 250                string = "None";
 251        SPRINTF("Serial Number: %s\n", string);
 252
 253        /* show the protocol and transport */
 254        SPRINTF("     Protocol: %s\n", us->protocol_name);
 255        SPRINTF("    Transport: %s\n", us->transport_name);
 256
 257        /* show the device flags */
 258        if (pos < buffer + length)
 259        {
 260                pos += sprintf(pos, "       Quirks:");
 261
 262#define US_FLAG(name, value) \
 263        if (us->fflags & value) pos += sprintf(pos, " " #name);
 264US_DO_ALL_FLAGS
 265#undef US_FLAG
 266
 267                *(pos++) = '\n';
 268        }
 269
 270        /* Calculate start of next buffer, and return value. */
 271        *start = buffer + offset;
 272
 273        if ((pos - buffer) < offset)
 274                return (0);
 275        else if ((pos - buffer - offset) < length)
 276                return (pos - buffer - offset);
 277        else
 278                return (length);
 279}
 280
 281/***********************************************************************
 282 * Sysfs interface
 283 ***********************************************************************/
 284
 285/* Output routine for the sysfs max_sectors file */
 286//----- show_max_sectors() ---------------------
 287static ssize_t show_max_sectors(struct device *dev, struct device_attribute *attr, char *buf)
 288{
 289        struct scsi_device *sdev = to_scsi_device(dev);
 290
 291        //printk("scsiglue --- ssize_t show_max_sectors\n");
 292        return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
 293}
 294
 295/* Input routine for the sysfs max_sectors file */
 296//----- store_max_sectors() ---------------------
 297static ssize_t store_max_sectors(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 298{
 299        struct scsi_device *sdev = to_scsi_device(dev);
 300        unsigned short ms;
 301
 302        //printk("scsiglue --- ssize_t store_max_sectors\n");
 303        if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS)
 304        {
 305                blk_queue_max_hw_sectors(sdev->request_queue, ms);
 306                return strlen(buf);
 307        }
 308        return -EINVAL; 
 309}
 310
 311static DEVICE_ATTR(max_sectors, S_IRUGO | S_IWUSR, show_max_sectors, store_max_sectors);
 312static struct device_attribute *sysfs_device_attr_list[] = {&dev_attr_max_sectors, NULL, };
 313
 314/* this defines our host template, with which we'll allocate hosts */
 315
 316//----- usb_stor_host_template() ---------------------
 317struct scsi_host_template usb_stor_host_template = {
 318        /* basic userland interface stuff */
 319        .name =                         "eucr-storage",
 320        .proc_name =                    "eucr-storage",
 321        .proc_info =                    proc_info,
 322        .info =                         host_info,
 323
 324        /* command interface -- queued only */
 325        .queuecommand =                 queuecommand,
 326
 327        /* error and abort handlers */
 328        .eh_abort_handler =             command_abort,
 329        .eh_device_reset_handler =      device_reset,
 330        .eh_bus_reset_handler =         bus_reset,
 331
 332        /* queue commands only, only one command per LUN */
 333        .can_queue =                    1,
 334        .cmd_per_lun =                  1,
 335
 336        /* unknown initiator id */
 337        .this_id =                      -1,
 338
 339        .slave_alloc =                  slave_alloc,
 340        .slave_configure =              slave_configure,
 341
 342        /* lots of sg segments can be handled */
 343        .sg_tablesize =                 SG_ALL,
 344
 345        /* limit the total size of a transfer to 120 KB */
 346        .max_sectors =                  240,
 347
 348        /* merge commands... this seems to help performance, but
 349         * periodically someone should test to see which setting is more
 350         * optimal.
 351         */
 352        .use_clustering =               1,
 353
 354        /* emulated HBA */
 355        .emulated =                     1,
 356
 357        /* we do our own delay after a device or bus reset */
 358        .skip_settle_delay =            1,
 359
 360        /* sysfs device attributes */
 361        .sdev_attrs =                   sysfs_device_attr_list,
 362
 363        /* module management */
 364        .module =                       THIS_MODULE
 365};
 366
 367/* To Report "Illegal Request: Invalid Field in CDB */
 368unsigned char usb_stor_sense_invalidCDB[18] = {
 369        [0]     = 0x70,                     /* current error */
 370        [2]     = ILLEGAL_REQUEST,          /* Illegal Request = 0x05 */
 371        [7]     = 0x0a,                     /* additional length */
 372        [12]    = 0x24                      /* Invalid Field in CDB */
 373};
 374
 375/***********************************************************************
 376 * Scatter-gather transfer buffer access routines
 377 ***********************************************************************/
 378
 379//----- usb_stor_access_xfer_buf() ---------------------
 380unsigned int usb_stor_access_xfer_buf(struct us_data *us, unsigned char *buffer,
 381        unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,
 382        unsigned int *offset, enum xfer_buf_dir dir)
 383{
 384        unsigned int cnt;
 385
 386        //printk("transport --- usb_stor_access_xfer_buf\n");
 387        struct scatterlist *sg = *sgptr;
 388
 389        if (!sg)
 390                sg = scsi_sglist(srb);
 391
 392        cnt = 0;
 393        while (cnt < buflen && sg)
 394        {
 395                struct page *page = sg_page(sg) + ((sg->offset + *offset) >> PAGE_SHIFT);
 396                unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1);
 397                unsigned int sglen = sg->length - *offset;
 398
 399                if (sglen > buflen - cnt)
 400                {
 401                        /* Transfer ends within this s-g entry */
 402                        sglen = buflen - cnt;
 403                        *offset += sglen;
 404                }
 405                else
 406                {
 407                        /* Transfer continues to next s-g entry */
 408                        *offset = 0;
 409                        sg = sg_next(sg);
 410                }
 411
 412                while (sglen > 0)
 413                {
 414                        unsigned int plen = min(sglen, (unsigned int)PAGE_SIZE - poff);
 415                        unsigned char *ptr = kmap(page);
 416
 417                        if (dir == TO_XFER_BUF)
 418                                memcpy(ptr + poff, buffer + cnt, plen);
 419                        else
 420                                memcpy(buffer + cnt, ptr + poff, plen);
 421                        kunmap(page);
 422
 423                        /* Start at the beginning of the next page */
 424                        poff = 0;
 425                        ++page;
 426                        cnt += plen;
 427                        sglen -= plen;
 428                }
 429        }
 430        *sgptr = sg;
 431
 432        /* Return the amount actually transferred */
 433        return cnt;
 434}
 435
 436/* Store the contents of buffer into srb's transfer buffer and set the SCSI residue. */
 437//----- usb_stor_set_xfer_buf() ---------------------
 438void usb_stor_set_xfer_buf(struct us_data *us, unsigned char *buffer, unsigned int buflen, struct scsi_cmnd *srb,
 439        unsigned int dir)
 440{
 441        unsigned int offset = 0;
 442        struct scatterlist *sg = NULL;
 443
 444        //printk("transport --- usb_stor_set_xfer_buf\n");
 445        // TO_XFER_BUF = 0, FROM_XFER_BUF = 1
 446        buflen = min(buflen, scsi_bufflen(srb));
 447        buflen = usb_stor_access_xfer_buf(us, buffer, buflen, srb, &sg, &offset, dir);
 448        if (buflen < scsi_bufflen(srb))
 449                scsi_set_resid(srb, scsi_bufflen(srb) - buflen);
 450}
 451