usb: gadget: storage: add superspeed support
[pandora-kernel.git] / drivers / usb / gadget / f_mass_storage.c
index 5b93395..52583a2 100644 (file)
  * is not loaded (an empty string as "filename" in the fsg_config
  * structure causes error).  The CD-ROM emulation includes a single
  * data track and no audio tracks; hence there need be only one
- * backing file per LUN.  Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
  *
  *
  * MSF includes support for module parameters.  If gadget using it
@@ -363,7 +362,7 @@ struct fsg_common {
 
        struct fsg_buffhd       *next_buffhd_to_fill;
        struct fsg_buffhd       *next_buffhd_to_drain;
-       struct fsg_buffhd       buffhds[FSG_NUM_BUFFERS];
+       struct fsg_buffhd       *buffhds;
 
        int                     cmnd_size;
        u8                      cmnd[MAX_COMMAND_SIZE];
@@ -745,7 +744,6 @@ static int do_read(struct fsg_common *common)
        u32                     amount_left;
        loff_t                  file_offset, file_offset_tmp;
        unsigned int            amount;
-       unsigned int            partial_page;
        ssize_t                 nread;
 
        /*
@@ -771,7 +769,7 @@ static int do_read(struct fsg_common *common)
                curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
                return -EINVAL;
        }
-       file_offset = ((loff_t) lba) << 9;
+       file_offset = ((loff_t) lba) << curlun->blkbits;
 
        /* Carry out the file reads */
        amount_left = common->data_size_from_cmnd;
@@ -784,18 +782,10 @@ static int do_read(struct fsg_common *common)
                 * Try to read the remaining amount.
                 * But don't read more than the buffer size.
                 * And don't try to read past the end of the file.
-                * Finally, if we're not at a page boundary, don't read past
-                *      the next page.
-                * If this means reading 0 then we were asked to read past
-                *      the end of file.
                 */
                amount = min(amount_left, FSG_BUFLEN);
                amount = min((loff_t)amount,
                             curlun->file_length - file_offset);
-               partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
-               if (partial_page > 0)
-                       amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
-                                            partial_page);
 
                /* Wait for the next buffer to become available */
                bh = common->next_buffhd_to_fill;
@@ -812,7 +802,8 @@ static int do_read(struct fsg_common *common)
                if (amount == 0) {
                        curlun->sense_data =
                                        SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-                       curlun->sense_data_info = file_offset >> 9;
+                       curlun->sense_data_info =
+                                       file_offset >> curlun->blkbits;
                        curlun->info_valid = 1;
                        bh->inreq->length = 0;
                        bh->state = BUF_STATE_FULL;
@@ -835,18 +826,25 @@ static int do_read(struct fsg_common *common)
                } else if (nread < amount) {
                        LDBG(curlun, "partial file read: %d/%u\n",
                             (int)nread, amount);
-                       nread -= (nread & 511); /* Round down to a block */
+                       nread = round_down(nread, curlun->blksize);
                }
                file_offset  += nread;
                amount_left  -= nread;
                common->residue -= nread;
+
+               /*
+                * Except at the end of the transfer, nread will be
+                * equal to the buffer size, which is divisible by the
+                * bulk-in maxpacket size.
+                */
                bh->inreq->length = nread;
                bh->state = BUF_STATE_FULL;
 
                /* If an error occurred, report it and its position */
                if (nread < amount) {
                        curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-                       curlun->sense_data_info = file_offset >> 9;
+                       curlun->sense_data_info =
+                                       file_offset >> curlun->blkbits;
                        curlun->info_valid = 1;
                        break;
                }
@@ -877,7 +875,6 @@ static int do_write(struct fsg_common *common)
        u32                     amount_left_to_req, amount_left_to_write;
        loff_t                  usb_offset, file_offset, file_offset_tmp;
        unsigned int            amount;
-       unsigned int            partial_page;
        ssize_t                 nwritten;
        int                     rc;
 
@@ -921,7 +918,7 @@ static int do_write(struct fsg_common *common)
 
        /* Carry out the file writes */
        get_some_more = 1;
-       file_offset = usb_offset = ((loff_t) lba) << 9;
+       file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
        amount_left_to_req = common->data_size_from_cmnd;
        amount_left_to_write = common->data_size_from_cmnd;
 
@@ -933,41 +930,21 @@ static int do_write(struct fsg_common *common)
 
                        /*
                         * Figure out how much we want to get:
-                        * Try to get the remaining amount.
-                        * But don't get more than the buffer size.
-                        * And don't try to go past the end of the file.
-                        * If we're not at a page boundary,
-                        *      don't go past the next page.
-                        * If this means getting 0, then we were asked
-                        *      to write past the end of file.
-                        * Finally, round down to a block boundary.
+                        * Try to get the remaining amount,
+                        * but not more than the buffer size.
                         */
                        amount = min(amount_left_to_req, FSG_BUFLEN);
-                       amount = min((loff_t)amount,
-                                    curlun->file_length - usb_offset);
-                       partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
-                       if (partial_page > 0)
-                               amount = min(amount,
-       (unsigned int)PAGE_CACHE_SIZE - partial_page);
-
-                       if (amount == 0) {
+
+                       /* Beyond the end of the backing file? */
+                       if (usb_offset >= curlun->file_length) {
                                get_some_more = 0;
                                curlun->sense_data =
                                        SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-                               curlun->sense_data_info = usb_offset >> 9;
+                               curlun->sense_data_info =
+                                       usb_offset >> curlun->blkbits;
                                curlun->info_valid = 1;
                                continue;
                        }
-                       amount -= amount & 511;
-                       if (amount == 0) {
-
-                               /*
-                                * Why were we were asked to transfer a
-                                * partial block?
-                                */
-                               get_some_more = 0;
-                               continue;
-                       }
 
                        /* Get the next buffer */
                        usb_offset += amount;
@@ -977,12 +954,11 @@ static int do_write(struct fsg_common *common)
                                get_some_more = 0;
 
                        /*
-                        * amount is always divisible by 512, hence by
-                        * the bulk-out maxpacket size
+                        * Except at the end of the transfer, amount will be
+                        * equal to the buffer size, which is divisible by
+                        * the bulk-out maxpacket size.
                         */
-                       bh->outreq->length = amount;
-                       bh->bulk_out_intended_length = amount;
-                       bh->outreq->short_not_ok = 1;
+                       set_bulk_out_req_length(common, bh, amount);
                        if (!start_out_transfer(common, bh))
                                /* Dunno what to do if common->fsg is NULL */
                                return -EIO;
@@ -1002,7 +978,8 @@ static int do_write(struct fsg_common *common)
                        /* Did something go wrong with the transfer? */
                        if (bh->outreq->status != 0) {
                                curlun->sense_data = SS_COMMUNICATION_FAILURE;
-                               curlun->sense_data_info = file_offset >> 9;
+                               curlun->sense_data_info =
+                                       file_offset >> curlun->blkbits;
                                curlun->info_valid = 1;
                                break;
                        }
@@ -1016,6 +993,16 @@ static int do_write(struct fsg_common *common)
                                amount = curlun->file_length - file_offset;
                        }
 
+                       /* Don't accept excess data.  The spec doesn't say
+                        * what to do in this case.  We'll ignore the error.
+                        */
+                       amount = min(amount, bh->bulk_out_intended_length);
+
+                       /* Don't write a partial block */
+                       amount = round_down(amount, curlun->blksize);
+                       if (amount == 0)
+                               goto empty_write;
+
                        /* Perform the write */
                        file_offset_tmp = file_offset;
                        nwritten = vfs_write(curlun->filp,
@@ -1033,8 +1020,7 @@ static int do_write(struct fsg_common *common)
                        } else if (nwritten < amount) {
                                LDBG(curlun, "partial file write: %d/%u\n",
                                     (int)nwritten, amount);
-                               nwritten -= (nwritten & 511);
-                               /* Round down to a block */
+                               nwritten = round_down(nwritten, curlun->blksize);
                        }
                        file_offset += nwritten;
                        amount_left_to_write -= nwritten;
@@ -1043,13 +1029,15 @@ static int do_write(struct fsg_common *common)
                        /* If an error occurred, report it and its position */
                        if (nwritten < amount) {
                                curlun->sense_data = SS_WRITE_ERROR;
-                               curlun->sense_data_info = file_offset >> 9;
+                               curlun->sense_data_info =
+                                       file_offset >> curlun->blkbits;
                                curlun->info_valid = 1;
                                break;
                        }
 
+ empty_write:
                        /* Did the host decide to stop early? */
-                       if (bh->outreq->actual != bh->outreq->length) {
+                       if (bh->outreq->actual < bh->bulk_out_intended_length) {
                                common->short_packet_received = 1;
                                break;
                        }
@@ -1129,8 +1117,8 @@ static int do_verify(struct fsg_common *common)
                return -EIO;            /* No default reply */
 
        /* Prepare to carry out the file verify */
-       amount_left = verification_length << 9;
-       file_offset = ((loff_t) lba) << 9;
+       amount_left = verification_length << curlun->blkbits;
+       file_offset = ((loff_t) lba) << curlun->blkbits;
 
        /* Write out all the dirty buffers before invalidating them */
        fsg_lun_fsync_sub(curlun);
@@ -1148,8 +1136,6 @@ static int do_verify(struct fsg_common *common)
                 * Try to read the remaining amount, but not more than
                 * the buffer size.
                 * And don't try to read past the end of the file.
-                * If this means reading 0 then we were asked to read
-                * past the end of file.
                 */
                amount = min(amount_left, FSG_BUFLEN);
                amount = min((loff_t)amount,
@@ -1157,7 +1143,8 @@ static int do_verify(struct fsg_common *common)
                if (amount == 0) {
                        curlun->sense_data =
                                        SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-                       curlun->sense_data_info = file_offset >> 9;
+                       curlun->sense_data_info =
+                               file_offset >> curlun->blkbits;
                        curlun->info_valid = 1;
                        break;
                }
@@ -1179,11 +1166,12 @@ static int do_verify(struct fsg_common *common)
                } else if (nread < amount) {
                        LDBG(curlun, "partial file verify: %d/%u\n",
                             (int)nread, amount);
-                       nread -= nread & 511;   /* Round down to a sector */
+                       nread = round_down(nread, curlun->blksize);
                }
                if (nread == 0) {
                        curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-                       curlun->sense_data_info = file_offset >> 9;
+                       curlun->sense_data_info =
+                               file_offset >> curlun->blkbits;
                        curlun->info_valid = 1;
                        break;
                }
@@ -1289,7 +1277,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
 
        put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
                                                /* Max logical block */
-       put_unaligned_be32(512, &buf[4]);       /* Block length */
+       put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
        return 8;
 }
 
@@ -1527,7 +1515,7 @@ static int do_read_format_capacities(struct fsg_common *common,
 
        put_unaligned_be32(curlun->num_sectors, &buf[0]);
                                                /* Number of blocks */
-       put_unaligned_be32(512, &buf[4]);       /* Block length */
+       put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
        buf[4] = 0x02;                          /* Current capacity */
        return 12;
 }
@@ -1607,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common)
                        common->next_buffhd_to_drain = bh->next;
 
                        /* A short packet or an error ends everything */
-                       if (bh->outreq->actual != bh->outreq->length ||
+                       if (bh->outreq->actual < bh->bulk_out_intended_length ||
                            bh->outreq->status != 0) {
                                raise_exception(common,
                                                FSG_STATE_ABORT_BULK_OUT);
@@ -1623,12 +1611,11 @@ static int throw_away_data(struct fsg_common *common)
                        amount = min(common->usb_amount_left, FSG_BUFLEN);
 
                        /*
-                        * amount is always divisible by 512, hence by
+                        * Except at the end of the transfer, amount will be
+                        * equal to the buffer size, which is divisible by
                         * the bulk-out maxpacket size.
                         */
-                       bh->outreq->length = amount;
-                       bh->bulk_out_intended_length = amount;
-                       bh->outreq->short_not_ok = 1;
+                       set_bulk_out_req_length(common, bh, amount);
                        if (!start_out_transfer(common, bh))
                                /* Dunno what to do if common->fsg is NULL */
                                return -EIO;
@@ -2022,7 +2009,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_6:
                i = common->cmnd[4];
-               common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+               common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+                               common->curlun->blkbits;
                reply = check_command(common, 6, DATA_DIR_TO_HOST,
                                      (7<<1) | (1<<4), 1,
                                      "READ(6)");
@@ -2032,7 +2020,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_10:
                common->data_size_from_cmnd =
-                               get_unaligned_be16(&common->cmnd[7]) << 9;
+                               get_unaligned_be16(&common->cmnd[7]) <<
+                                               common->curlun->blkbits;
                reply = check_command(common, 10, DATA_DIR_TO_HOST,
                                      (1<<1) | (0xf<<2) | (3<<7), 1,
                                      "READ(10)");
@@ -2042,7 +2031,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_12:
                common->data_size_from_cmnd =
-                               get_unaligned_be32(&common->cmnd[6]) << 9;
+                               get_unaligned_be32(&common->cmnd[6]) <<
+                                               common->curlun->blkbits;
                reply = check_command(common, 12, DATA_DIR_TO_HOST,
                                      (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                      "READ(12)");
@@ -2142,7 +2132,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_6:
                i = common->cmnd[4];
-               common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+               common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+                                       common->curlun->blkbits;
                reply = check_command(common, 6, DATA_DIR_FROM_HOST,
                                      (7<<1) | (1<<4), 1,
                                      "WRITE(6)");
@@ -2152,7 +2143,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_10:
                common->data_size_from_cmnd =
-                               get_unaligned_be16(&common->cmnd[7]) << 9;
+                               get_unaligned_be16(&common->cmnd[7]) <<
+                                               common->curlun->blkbits;
                reply = check_command(common, 10, DATA_DIR_FROM_HOST,
                                      (1<<1) | (0xf<<2) | (3<<7), 1,
                                      "WRITE(10)");
@@ -2162,7 +2154,8 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_12:
                common->data_size_from_cmnd =
-                               get_unaligned_be32(&common->cmnd[6]) << 9;
+                               get_unaligned_be32(&common->cmnd[6]) <<
+                                               common->curlun->blkbits;
                reply = check_command(common, 12, DATA_DIR_FROM_HOST,
                                      (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                      "WRITE(12)");
@@ -2297,7 +2290,6 @@ static int get_next_command(struct fsg_common *common)
 
        /* Queue a request to read a Bulk-only CBW */
        set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
-       bh->outreq->short_not_ok = 1;
        if (!start_out_transfer(common, bh))
                /* Don't know what to do if common->fsg is NULL */
                return -EIO;
@@ -2348,7 +2340,7 @@ reset:
        if (common->fsg) {
                fsg = common->fsg;
 
-               for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+               for (i = 0; i < fsg_num_buffers; ++i) {
                        struct fsg_buffhd *bh = &common->buffhds[i];
 
                        if (bh->inreq) {
@@ -2401,12 +2393,11 @@ reset:
                goto reset;
        fsg->bulk_out->driver_data = common;
        fsg->bulk_out_enabled = 1;
-       common->bulk_out_maxpacket =
-               le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
+       common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
        clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
        /* Allocate the requests */
-       for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+       for (i = 0; i < fsg_num_buffers; ++i) {
                struct fsg_buffhd       *bh = &common->buffhds[i];
 
                rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
@@ -2475,7 +2466,7 @@ static void handle_exception(struct fsg_common *common)
 
        /* Cancel all the pending transfers */
        if (likely(common->fsg)) {
-               for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+               for (i = 0; i < fsg_num_buffers; ++i) {
                        bh = &common->buffhds[i];
                        if (bh->inreq_busy)
                                usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
@@ -2487,7 +2478,7 @@ static void handle_exception(struct fsg_common *common)
                /* Wait until everything is idle */
                for (;;) {
                        int num_active = 0;
-                       for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+                       for (i = 0; i < fsg_num_buffers; ++i) {
                                bh = &common->buffhds[i];
                                num_active += bh->inreq_busy + bh->outreq_busy;
                        }
@@ -2510,7 +2501,7 @@ static void handle_exception(struct fsg_common *common)
         */
        spin_lock_irq(&common->lock);
 
-       for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+       for (i = 0; i < fsg_num_buffers; ++i) {
                bh = &common->buffhds[i];
                bh->state = BUF_STATE_EMPTY;
        }
@@ -2719,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
        int nluns, i, rc;
        char *pathbuf;
 
+       rc = fsg_num_buffers_validate();
+       if (rc != 0)
+               return ERR_PTR(rc);
+
        /* Find out how many LUNs there should be */
        nluns = cfg->nluns;
        if (nluns < 1 || nluns > FSG_MAX_LUNS) {
@@ -2737,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
                common->free_storage_on_release = 0;
        }
 
+       common->buffhds = kcalloc(fsg_num_buffers,
+                                 sizeof *(common->buffhds), GFP_KERNEL);
+       if (!common->buffhds) {
+               if (common->free_storage_on_release)
+                       kfree(common);
+               return ERR_PTR(-ENOMEM);
+       }
+
        common->ops = cfg->ops;
        common->private_data = cfg->private_data;
 
@@ -2814,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 
        /* Data buffers cyclic list */
        bh = common->buffhds;
-       i = FSG_NUM_BUFFERS;
+       i = fsg_num_buffers;
        goto buffhds_first_it;
        do {
                bh->next = bh + 1;
@@ -2940,12 +2943,13 @@ static void fsg_common_release(struct kref *ref)
 
        {
                struct fsg_buffhd *bh = common->buffhds;
-               unsigned i = FSG_NUM_BUFFERS;
+               unsigned i = fsg_num_buffers;
                do {
                        kfree(bh->buf);
                } while (++bh, --i);
        }
 
+       kfree(common->buffhds);
        if (common->free_storage_on_release)
                kfree(common);
 }
@@ -3019,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
                }
        }
 
+       if (gadget_is_superspeed(gadget)) {
+               unsigned        max_burst;
+
+               /* Calculate bMaxBurst, we know packet size is 1024 */
+               max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+               fsg_ss_bulk_in_desc.bEndpointAddress =
+                       fsg_fs_bulk_in_desc.bEndpointAddress;
+               fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+               fsg_ss_bulk_out_desc.bEndpointAddress =
+                       fsg_fs_bulk_out_desc.bEndpointAddress;
+               fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+               f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+               if (unlikely(!f->ss_descriptors)) {
+                       usb_free_descriptors(f->hs_descriptors);
+                       usb_free_descriptors(f->descriptors);
+                       return -ENOMEM;
+               }
+       }
+
        return 0;
 
 autoconf_fail: