zaitcev@redhat.com [PATCH] USB: Add ioctls to ub ChangeSet 1.2061, 2005/02/17 11:56:54-08:00, zaitcev@redhat.com [PATCH] USB: Add ioctls to ub This patch adds support for ioctls to ub, with the help of scsi_ioctl_cmd(). Now ub can eject CDs. But do not try to burn CDs yet, it's not tested. Original patch from Peter Jones (aka deviant-). Signed-off-by: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman drivers/block/ub.c | 164 +++++++++++++++++++++++++++++++++-------------------- 1 files changed, 103 insertions(+), 61 deletions(-) diff -Nru a/drivers/block/ub.c b/drivers/block/ub.c --- a/drivers/block/ub.c 2005-02-17 12:20:22 -08:00 +++ b/drivers/block/ub.c 2005-02-17 12:20:22 -08:00 @@ -300,6 +300,11 @@ /* */ +static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq); +static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq); +static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq); static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_end_rq(struct request *rq, int uptodate); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); @@ -591,40 +596,73 @@ * The request function is our main entry point */ -static inline int ub_bd_rq_fn_1(request_queue_t *q) +static void ub_bd_rq_fn(request_queue_t *q) { -#if 0 - int writing = 0, pci_dir, i, n_elem; - u32 tmp; - unsigned int msg_size; -#endif struct ub_dev *sc = q->queuedata; struct request *rq; -#if 0 /* We use rq->buffer for now */ - struct scatterlist *sg; - int n_elem; -#endif + + while ((rq = elv_next_request(q)) != NULL) { + if (ub_bd_rq_fn_1(sc, rq) != 0) { + blk_stop_queue(q); + break; + } + } +} + +static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq) +{ struct ub_scsi_cmd *cmd; - int ub_dir; - unsigned int block, nblks; int rc; - if ((rq = elv_next_request(q)) == NULL) - return 1; - if (atomic_read(&sc->poison) || sc->changed) { blkdev_dequeue_request(rq); ub_end_rq(rq, 0); return 0; } - if ((cmd = ub_get_cmd(sc)) == NULL) { - blk_stop_queue(q); - return 1; - } + if ((cmd = ub_get_cmd(sc)) == NULL) + return -1; + memset(cmd, 0, sizeof(struct ub_scsi_cmd)); blkdev_dequeue_request(rq); + if (blk_pc_request(rq)) { + rc = ub_cmd_build_packet(sc, cmd, rq); + } else { + rc = ub_cmd_build_block(sc, cmd, rq); + } + if (rc != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(sc->disk->queue); + return 0; + } + + cmd->state = UB_CMDST_INIT; + cmd->done = ub_rw_cmd_done; + cmd->back = rq; + + cmd->tag = sc->tagcnt++; + if ((rc = ub_submit_scsi(sc, cmd)) != 0) { + ub_put_cmd(sc, cmd); + ub_end_rq(rq, 0); + blk_start_queue(sc->disk->queue); + return 0; + } + + return 0; +} + +static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq) +{ + int ub_dir; +#if 0 /* We use rq->buffer for now */ + struct scatterlist *sg; + int n_elem; +#endif + unsigned int block, nblks; + if (rq_data_dir(rq) == WRITE) ub_dir = UB_DIR_WRITE; else @@ -652,6 +690,7 @@ return 0; } #endif + /* * XXX Unfortunately, this check does not work. It is quite possible * to get bogus non-null rq->buffer if you allow sg by mistake. @@ -663,13 +702,12 @@ */ static int do_print = 1; if (do_print) { - printk(KERN_WARNING "%s: unmapped request\n", sc->name); + printk(KERN_WARNING "%s: unmapped block request" + " flags 0x%lx sectors %lu\n", + sc->name, rq->flags, rq->nr_sectors); do_print = 0; } - ub_put_cmd(sc, cmd); - ub_end_rq(rq, 0); - blk_start_queue(q); - return 0; + return -1; } /* @@ -681,7 +719,6 @@ block = rq->sector >> sc->capacity.bshift; nblks = rq->nr_sectors >> sc->capacity.bshift; - memset(cmd, 0, sizeof(struct ub_scsi_cmd)); cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ cmd->cdb[2] = block >> 24; @@ -691,27 +728,44 @@ cmd->cdb[7] = nblks >> 8; cmd->cdb[8] = nblks; cmd->cdb_len = 10; + cmd->dir = ub_dir; - cmd->state = UB_CMDST_INIT; cmd->data = rq->buffer; cmd->len = rq->nr_sectors * 512; - cmd->done = ub_rw_cmd_done; - cmd->back = rq; - - cmd->tag = sc->tagcnt++; - if ((rc = ub_submit_scsi(sc, cmd)) != 0) { - ub_put_cmd(sc, cmd); - ub_end_rq(rq, 0); - blk_start_queue(q); - return 0; - } return 0; } -static void ub_bd_rq_fn(request_queue_t *q) +static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd, + struct request *rq) { - do { } while (ub_bd_rq_fn_1(q) == 0); + + if (rq->data_len != 0 && rq->data == NULL) { + static int do_print = 1; + if (do_print) { + printk(KERN_WARNING "%s: unmapped packet request" + " flags 0x%lx length %d\n", + sc->name, rq->flags, rq->data_len); + do_print = 0; + } + return -1; + } + + memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); + cmd->cdb_len = rq->cmd_len; + + if (rq->data_len == 0) { + cmd->dir = UB_DIR_NONE; + } else { + if (rq_data_dir(rq) == WRITE) + cmd->dir = UB_DIR_WRITE; + else + cmd->dir = UB_DIR_READ; + } + cmd->data = rq->data; + cmd->len = rq->data_len; + + return 0; } static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) @@ -884,6 +938,7 @@ { struct urb *urb = &sc->work_urb; struct bulk_cs_wrap *bcs; + struct request *rq = cmd->back; int pipe; int rc; @@ -1137,6 +1192,13 @@ (*cmd->done)(sc, cmd); } else if (cmd->state == UB_CMDST_SENSE) { + if (blk_pc_request(rq)) { + /* + * UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE + */ + memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE); + rq->sense_len = UB_SENSE_SIZE; + } ub_state_done(sc, cmd, -EIO); } else { @@ -1495,30 +1557,10 @@ static int ub_bd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { -// void __user *usermem = (void *) arg; -// struct carm_port *port = ino->i_bdev->bd_disk->private_data; -// struct hd_geometry geom; - -#if 0 - switch (cmd) { - case HDIO_GETGEO: - if (usermem == NULL) // XXX Bizzare. Why? - return -EINVAL; - - geom.heads = (u8) port->dev_geom_head; - geom.sectors = (u8) port->dev_geom_sect; - geom.cylinders = port->dev_geom_cyl; - geom.start = get_start_sect(ino->i_bdev); - - if (copy_to_user(usermem, &geom, sizeof(geom))) - return -EFAULT; - return 0; - - default: ; - } -#endif + struct gendisk *disk = inode->i_bdev->bd_disk; + void __user *usermem = (void __user *) arg; - return -ENOTTY; + return scsi_cmd_ioctl(filp, disk, cmd, usermem); } /*