*/
struct ub_dev;
-#define UB_MAX_REQ_SG 4
+#define UB_MAX_REQ_SG 9 /* cdrecord requires 32KB and maybe a header */
#define UB_MAX_SECTORS 64
/*
int stat_count; /* Retries getting status. */
- /*
- * We do not support transfers from highmem pages
- * because the underlying USB framework does not do what we need.
- */
- char *data; /* Requested buffer */
unsigned int len; /* Requested length */
+ unsigned int current_sg;
+ unsigned int nsg; /* sgv[nsg] */
+ struct scatterlist sgv[UB_MAX_REQ_SG];
struct ub_lun *lun;
void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
void *back;
};
-struct ub_request {
- struct request *rq;
- unsigned char dir;
- unsigned int current_block;
- unsigned int current_sg;
- unsigned int nsg; /* sgv[nsg] */
- struct scatterlist sgv[UB_MAX_REQ_SG];
-};
-
/*
*/
struct ub_capacity {
int readonly;
int first_open; /* Kludge. See ub_bd_open. */
- struct ub_request urq;
-
/* Use Ingo's mempool if or when we have more than one command. */
/*
* Currently we never need more than one command for the whole device.
struct bulk_cs_wrap work_bcs;
struct usb_ctrlrequest work_cr;
- int sg_stat[UB_MAX_REQ_SG+1];
+ int sg_stat[6];
struct ub_scsi_trace tr;
};
/*
*/
static void ub_cleanup(struct ub_dev *sc);
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq);
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq);
-static void ub_scsi_build_block(struct ub_lun *lun,
- struct ub_scsi_cmd *cmd, struct ub_request *urq);
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
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_request_advance(struct ub_dev *sc, struct ub_lun *lun,
- struct ub_request *urq, struct ub_scsi_cmd *cmd);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
static void ub_scsi_action(unsigned long _dev);
static void ub_scsi_dispatch(struct ub_dev *sc);
static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
+static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
"qlen %d qmax %d\n",
sc->cmd_queue.qlen, sc->cmd_queue.qmax);
cnt += sprintf(page + cnt,
- "sg %d %d %d %d %d\n",
+ "sg %d %d %d %d %d .. %d\n",
sc->sg_stat[0],
sc->sg_stat[1],
sc->sg_stat[2],
sc->sg_stat[3],
- sc->sg_stat[4]);
+ sc->sg_stat[4],
+ sc->sg_stat[5]);
list_for_each (p, &sc->luns) {
lun = list_entry(p, struct ub_lun, link);
* The request function is our main entry point
*/
-static void ub_bd_rq_fn(request_queue_t *q)
+static void ub_request_fn(request_queue_t *q)
{
struct ub_lun *lun = q->queuedata;
struct request *rq;
while ((rq = elv_next_request(q)) != NULL) {
- if (ub_bd_rq_fn_1(lun, rq) != 0) {
+ if (ub_request_fn_1(lun, rq) != 0) {
blk_stop_queue(q);
break;
}
}
}
-static int ub_bd_rq_fn_1(struct ub_lun *lun, struct request *rq)
+static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
{
struct ub_dev *sc = lun->udev;
struct ub_scsi_cmd *cmd;
return 0;
}
- if (lun->urq.rq != NULL)
- return -1;
if ((cmd = ub_get_cmd(lun)) == NULL)
return -1;
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
cmd->state = UB_CMDST_INIT;
cmd->lun = lun;
cmd->done = ub_rw_cmd_done;
- cmd->back = &lun->urq;
+ cmd->back = rq;
cmd->tag = sc->tagcnt++;
if (ub_submit_scsi(sc, cmd) != 0) {
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq)
{
- struct ub_request *urq;
int ub_dir;
int n_elem;
-
- urq = &lun->urq;
- memset(urq, 0, sizeof(struct ub_request));
+ unsigned int block, nblks;
if (rq_data_dir(rq) == WRITE)
ub_dir = UB_DIR_WRITE;
else
ub_dir = UB_DIR_READ;
+ cmd->dir = ub_dir;
/*
* get scatterlist from block layer
*/
- n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
+ n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
if (n_elem <= 0) {
printk(KERN_INFO "%s: failed request map (%d)\n",
sc->name, n_elem); /* P3 */
sc->name, n_elem);
return -1;
}
- urq->nsg = n_elem;
- sc->sg_stat[n_elem]++;
+ cmd->nsg = n_elem;
+ sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
/*
* build the command
* The call to blk_queue_hardsect_size() guarantees that request
* is aligned, but it is given in terms of 512 byte units, always.
*/
- urq->current_block = rq->sector >> lun->capacity.bshift;
- // nblks = rq->nr_sectors >> lun->capacity.bshift;
-
- urq->rq = rq;
- urq->current_sg = 0;
- urq->dir = ub_dir;
-
- ub_scsi_build_block(lun, cmd, urq);
- return 0;
-}
+ block = rq->sector >> lun->capacity.bshift;
+ nblks = rq->nr_sectors >> lun->capacity.bshift;
-static void ub_scsi_build_block(struct ub_lun *lun,
- struct ub_scsi_cmd *cmd, struct ub_request *urq)
-{
- struct scatterlist *sg;
- unsigned int block, nblks;
-
- sg = &urq->sgv[urq->current_sg];
-
- block = urq->current_block;
- nblks = sg->length >> (lun->capacity.bshift + 9);
-
- cmd->cdb[0] = (urq->dir == UB_DIR_READ)? READ_10: WRITE_10;
+ 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;
cmd->cdb[3] = block >> 16;
cmd->cdb[8] = nblks;
cmd->cdb_len = 10;
- cmd->dir = urq->dir;
- cmd->data = page_address(sg->page) + sg->offset;
- cmd->len = sg->length;
+ cmd->len = rq->nr_sectors * 512;
+
+ return 0;
}
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct request *rq)
{
- struct ub_request *urq;
-
- urq = &lun->urq;
- memset(urq, 0, sizeof(struct ub_request));
- urq->rq = rq;
- sc->sg_stat[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;
+ int n_elem;
if (rq->data_len == 0) {
cmd->dir = UB_DIR_NONE;
cmd->dir = UB_DIR_WRITE;
else
cmd->dir = UB_DIR_READ;
+
}
- cmd->data = rq->data;
+
+ /*
+ * get scatterlist from block layer
+ */
+ n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
+ if (n_elem < 0) {
+ printk(KERN_INFO "%s: failed request map (%d)\n",
+ sc->name, n_elem); /* P3 */
+ return -1;
+ }
+ if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
+ printk(KERN_WARNING "%s: request with %d segments\n",
+ sc->name, n_elem);
+ return -1;
+ }
+ cmd->nsg = n_elem;
+ sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
+
+ memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
+ cmd->cdb_len = rq->cmd_len;
+
cmd->len = rq->data_len;
return 0;
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
+ struct request *rq = cmd->back;
struct ub_lun *lun = cmd->lun;
- struct ub_request *urq = cmd->back;
- struct request *rq;
int uptodate;
- rq = urq->rq;
-
- 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;
- }
-
- if (cmd->error == 0)
+ if (cmd->error == 0) {
uptodate = 1;
- else
- uptodate = 0;
- if (cmd->error == 0 && urq->current_sg+1 < urq->nsg) {
- if (ub_request_advance(sc, lun, urq, cmd) == 0) {
- /* Stay on target... */
- return;
+ if (blk_pc_request(rq)) {
+ if (cmd->act_len >= rq->data_len)
+ rq->data_len = 0;
+ else
+ rq->data_len -= cmd->act_len;
}
+ } else {
uptodate = 0;
- }
- urq->rq = NULL;
+ 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;
+ if (sc->top_sense[0] != 0)
+ rq->errors = SAM_STAT_CHECK_CONDITION;
+ else
+ rq->errors = DID_ERROR << 16;
+ }
+ }
ub_put_cmd(lun, cmd);
ub_end_rq(rq, uptodate);
end_that_request_last(rq);
}
-static int ub_request_advance(struct ub_dev *sc, struct ub_lun *lun,
- struct ub_request *urq, struct ub_scsi_cmd *cmd)
-{
- struct scatterlist *sg;
- unsigned int nblks;
-
- /* XXX This is temporary, until we sort out S/G in packet requests. */
- if (blk_pc_request(urq->rq)) {
- printk(KERN_WARNING
- "2-segment packet request completed\n"); /* P3 */
- return -1;
- }
-
- sg = &urq->sgv[urq->current_sg];
- nblks = sg->length >> (lun->capacity.bshift + 9);
- urq->current_block += nblks;
- urq->current_sg++;
- sg++;
-
- memset(cmd, 0, sizeof(struct ub_scsi_cmd));
- ub_scsi_build_block(lun, cmd, urq);
- cmd->state = UB_CMDST_INIT;
- cmd->lun = lun;
- cmd->done = ub_rw_cmd_done;
- cmd->back = &lun->urq;
-
- cmd->tag = sc->tagcnt++;
- if (ub_submit_scsi(sc, cmd) != 0) {
- return -1;
- }
-
- return 0;
-}
-
/*
* Submit a regular SCSI operation (not an auto-sense).
*
sc->last_pipe = sc->send_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,
bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);
- sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
/* Fill what we shouldn't be filling, because usb-storage did so. */
sc->work_urb.actual_length = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
/* XXX Clear stalls */
- printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */
ub_complete(&sc->work_done);
return rc;
}
{
struct urb *urb = &sc->work_urb;
struct bulk_cs_wrap *bcs;
- int pipe;
int rc;
if (atomic_read(&sc->poison)) {
return;
}
if (urb->status != 0) {
- printk("ub: cmd #%d cmd status (%d)\n", cmd->tag, urb->status); /* P3 */
goto Bad_End;
}
if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
- printk("ub: cmd #%d xferred %d\n", cmd->tag, urb->actual_length); /* P3 */
/* XXX Must do reset here to unconfuse the device */
goto Bad_End;
}
- if (cmd->dir == UB_DIR_NONE) {
+ if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
ub_state_stat(sc, cmd);
return;
}
- UB_INIT_COMPLETION(sc->work_done);
-
- if (cmd->dir == UB_DIR_READ)
- pipe = sc->recv_bulk_pipe;
- else
- pipe = sc->send_bulk_pipe;
- sc->last_pipe = pipe;
- usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
- cmd->data, cmd->len, ub_urb_complete, sc);
- sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
- sc->work_urb.actual_length = 0;
- sc->work_urb.error_count = 0;
- sc->work_urb.status = 0;
-
- if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
- /* XXX Clear stalls */
- printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */
- ub_complete(&sc->work_done);
- ub_state_done(sc, cmd, rc);
- return;
- }
-
- sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
- add_timer(&sc->work_timer);
-
- cmd->state = UB_CMDST_DATA;
- ub_cmdtr_state(sc, cmd);
+ // udelay(125); // usb-storage has this
+ ub_data_start(sc, cmd);
} else if (cmd->state == UB_CMDST_DATA) {
if (urb->status == -EPIPE) {
if (urb->status == -EOVERFLOW) {
/*
* A babble? Failure, but we must transfer CSW now.
+ * XXX This is going to end in perpetual babble. Reset.
*/
cmd->error = -EOVERFLOW; /* A cheap trick... */
- } else {
- if (urb->status != 0)
- goto Bad_End;
+ ub_state_stat(sc, cmd);
+ return;
}
+ if (urb->status != 0)
+ goto Bad_End;
- cmd->act_len = urb->actual_length;
+ cmd->act_len += urb->actual_length;
ub_cmdtr_act_len(sc, cmd);
+ if (++cmd->current_sg < cmd->nsg) {
+ ub_data_start(sc, cmd);
+ return;
+ }
ub_state_stat(sc, cmd);
} else if (cmd->state == UB_CMDST_STAT) {
/*
* Factorization helper for the command state machine:
+ * Initiate a data segment transfer.
+ */
+static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
+{
+ struct scatterlist *sg = &cmd->sgv[cmd->current_sg];
+ int pipe;
+ int rc;
+
+ UB_INIT_COMPLETION(sc->work_done);
+
+ if (cmd->dir == UB_DIR_READ)
+ pipe = sc->recv_bulk_pipe;
+ else
+ pipe = sc->send_bulk_pipe;
+ sc->last_pipe = pipe;
+ usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,
+ page_address(sg->page) + sg->offset, sg->length,
+ ub_urb_complete, sc);
+ sc->work_urb.actual_length = 0;
+ sc->work_urb.error_count = 0;
+ sc->work_urb.status = 0;
+
+ if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {
+ /* XXX Clear stalls */
+ ub_complete(&sc->work_done);
+ ub_state_done(sc, cmd, rc);
+ return;
+ }
+
+ sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+ add_timer(&sc->work_timer);
+
+ cmd->state = UB_CMDST_DATA;
+ ub_cmdtr_state(sc, cmd);
+}
+
+/*
+ * Factorization helper for the command state machine:
* Finish the command.
*/
static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc)
sc->last_pipe = sc->recv_bulk_pipe;
usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,
&sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc);
- sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{
struct ub_scsi_cmd *scmd;
+ struct scatterlist *sg;
int rc;
if (cmd->cdb[0] == REQUEST_SENSE) {
}
scmd = &sc->top_rqs_cmd;
+ memset(scmd, 0, sizeof(struct ub_scsi_cmd));
scmd->cdb[0] = REQUEST_SENSE;
scmd->cdb[4] = UB_SENSE_SIZE;
scmd->cdb_len = 6;
scmd->dir = UB_DIR_READ;
scmd->state = UB_CMDST_INIT;
- scmd->data = sc->top_sense;
+ scmd->nsg = 1;
+ sg = &scmd->sgv[0];
+ sg->page = virt_to_page(sc->top_sense);
+ sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1);
+ sg->length = UB_SENSE_SIZE;
scmd->len = UB_SENSE_SIZE;
scmd->lun = cmd->lun;
scmd->done = ub_top_sense_done;
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_urb_complete, sc);
- sc->work_urb.transfer_flags = URB_ASYNC_UNLINK;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
*/
static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
{
- unsigned char *sense = scmd->data;
+ unsigned char *sense = sc->top_sense;
struct ub_scsi_cmd *cmd;
/*
struct ub_capacity *ret)
{
struct ub_scsi_cmd *cmd;
+ struct scatterlist *sg;
char *p;
enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };
unsigned long flags;
cmd->cdb_len = 10;
cmd->dir = UB_DIR_READ;
cmd->state = UB_CMDST_INIT;
- cmd->data = p;
+ cmd->nsg = 1;
+ sg = &cmd->sgv[0];
+ sg->page = virt_to_page(p);
+ sg->offset = (unsigned int)p & (PAGE_SIZE-1);
+ sg->length = 8;
cmd->len = 8;
cmd->lun = lun;
cmd->done = ub_probe_done;
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,
(unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);
- sc->work_urb.transfer_flags = 0;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {
if (rc == -EPIPE) {
- printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
+ printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n",
sc->name); /* P3 */
} else {
- printk(KERN_WARNING
+ printk(KERN_NOTICE
"%s: Unable to submit GetMaxLUN (%d)\n",
sc->name, rc);
}
del_timer_sync(&timer);
usb_kill_urb(&sc->work_urb);
+ if ((rc = sc->work_urb.status) < 0) {
+ if (rc == -EPIPE) {
+ printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
+ sc->name); /* P3 */
+ } else {
+ printk(KERN_NOTICE
+ "%s: Error at GetMaxLUN (%d)\n",
+ sc->name, rc);
+ }
+ goto err_io;
+ }
+
if (sc->work_urb.actual_length != 1) {
printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
sc->work_urb.actual_length); /* P3 */
kfree(p);
return nluns;
+err_io:
err_submit:
kfree(p);
err_alloc:
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
(unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl);
- sc->work_urb.transfer_flags = 0;
sc->work_urb.actual_length = 0;
sc->work_urb.error_count = 0;
sc->work_urb.status = 0;
* This is needed to clear toggles. It is a problem only if we do
* `rmmod ub && modprobe ub` without disconnects, but we like that.
*/
+#if 0 /* iPod Mini fails if we do this (big white iPod works) */
ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
ub_probe_clear_stall(sc, sc->send_bulk_pipe);
+#endif
/*
* The way this is used by the startup code is a little specific.
for (i = 0; i < 3; i++) {
if ((rc = ub_sync_getmaxlun(sc)) < 0) {
/*
- * Some devices (i.e. Iomega Zip100) need this --
- * apparently the bulk pipes get STALLed when the
- * GetMaxLUN request is processed.
- * XXX I have a ZIP-100, verify it does this.
+ * This segment is taken from usb-storage. They say
+ * that ZIP-100 needs this, but my own ZIP-100 works
+ * fine without this.
+ * Still, it does not seem to hurt anything.
*/
if (rc == -EPIPE) {
ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
disk->first_minor = lun->id * UB_MINORS_PER_MAJOR;
disk->fops = &ub_bd_fops;
disk->private_data = lun;
- disk->driverfs_dev = &sc->intf->dev; /* XXX Many to one ok? */
+ disk->driverfs_dev = &sc->intf->dev;
rc = -ENOMEM;
- if ((q = blk_init_queue(ub_bd_rq_fn, &sc->lock)) == NULL)
+ if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL)
goto err_blkqinit;
disk->queue = q;
{
int rc;
- /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu ub_lun %zu\n",
- sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev), sizeof(struct ub_lun));
-
if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
goto err_regblkdev;
devfs_mk_dir(DEVFS_NAME);