diff options
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/Kconfig | 2 | ||||
-rw-r--r-- | drivers/block/aoe/aoenet.c | 2 | ||||
-rw-r--r-- | drivers/block/as-iosched.c | 10 | ||||
-rw-r--r-- | drivers/block/cciss.c | 49 | ||||
-rw-r--r-- | drivers/block/cciss.h | 4 | ||||
-rw-r--r-- | drivers/block/cfq-iosched.c | 32 | ||||
-rw-r--r-- | drivers/block/cryptoloop.c | 6 | ||||
-rw-r--r-- | drivers/block/floppy.c | 41 | ||||
-rw-r--r-- | drivers/block/ll_rw_blk.c | 18 | ||||
-rw-r--r-- | drivers/block/sx8.c | 4 | ||||
-rw-r--r-- | drivers/block/ub.c | 211 | ||||
-rw-r--r-- | drivers/block/viodasd.c | 2 |
12 files changed, 273 insertions, 108 deletions
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 7cd7bf35d02..6b736364cc5 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -413,7 +413,7 @@ config BLK_DEV_INITRD #for instance. config LBD bool "Support for Large Block Devices" - depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH || UML + depends on X86 || (MIPS && 32BIT) || PPC32 || ARCH_S390_31 || SUPERH || UML help Say Y here if you want to attach large (bigger than 2TB) discs to your machine, or if you want to have a raid or loopback device diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 9e6f51c528b..4be976940f6 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -120,7 +120,7 @@ aoenet_xmit(struct sk_buff *sl) * (1) len doesn't include the header by default. I want this. */ static int -aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt) +aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct net_device *orig_dev) { struct aoe_hdr *h; u32 n; diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c index 91aeb678135..95c0a3690b0 100644 --- a/drivers/block/as-iosched.c +++ b/drivers/block/as-iosched.c @@ -1935,23 +1935,15 @@ struct as_fs_entry { static ssize_t as_var_show(unsigned int var, char *page) { - var = (var * 1000) / HZ; return sprintf(page, "%d\n", var); } static ssize_t as_var_store(unsigned long *var, const char *page, size_t count) { - unsigned long tmp; char *p = (char *) page; - tmp = simple_strtoul(p, &p, 10); - if (tmp != 0) { - tmp = (tmp * HZ) / 1000; - if (tmp == 0) - tmp = 1; - } - *var = tmp; + *var = simple_strtoul(p, &p, 10); return count; } diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 3e9fb6e4a52..418b1469d75 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1135,7 +1135,7 @@ static int revalidate_allvol(ctlr_info_t *host) /* this is for the online array utilities */ if (!drv->heads && i) continue; - blk_queue_hardsect_size(host->queue, drv->block_size); + blk_queue_hardsect_size(drv->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); add_disk(disk); } @@ -1691,7 +1691,7 @@ static int cciss_revalidate(struct gendisk *disk) cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size); cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv); - blk_queue_hardsect_size(h->queue, drv->block_size); + blk_queue_hardsect_size(drv->queue, drv->block_size); set_capacity(disk, drv->nr_blocks); kfree(size_buff); @@ -2248,12 +2248,12 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) * them up. We will also keep track of the next queue to run so * that every queue gets a chance to be started first. */ - for (j=0; j < NWD; j++){ - int curr_queue = (start_queue + j) % NWD; + for (j=0; j < h->highest_lun + 1; j++){ + int curr_queue = (start_queue + j) % (h->highest_lun + 1); /* make sure the disk has been added and the drive is real * because this can be called from the middle of init_one. */ - if(!(h->gendisk[curr_queue]->queue) || + if(!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads)) continue; blk_start_queue(h->gendisk[curr_queue]->queue); @@ -2264,14 +2264,14 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) { if (curr_queue == start_queue){ - h->next_to_run = (start_queue + 1) % NWD; + h->next_to_run = (start_queue + 1) % (h->highest_lun + 1); goto cleanup; } else { h->next_to_run = curr_queue; goto cleanup; } } else { - curr_queue = (curr_queue + 1) % NWD; + curr_queue = (curr_queue + 1) % (h->highest_lun + 1); } } @@ -2279,7 +2279,6 @@ cleanup: spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return IRQ_HANDLED; } - /* * We cannot read the structure directly, for portablity we must use * the io functions. @@ -2789,13 +2788,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, } spin_lock_init(&hba[i]->lock); - q = blk_init_queue(do_cciss_request, &hba[i]->lock); - if (!q) - goto clean4; - - q->backing_dev_info.ra_pages = READ_AHEAD; - hba[i]->queue = q; - q->queuedata = hba[i]; /* Initialize the pdev driver private data. have it point to hba[i]. */ @@ -2817,6 +2809,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, cciss_procinit(i); + for(j=0; j < NWD; j++) { /* mfm */ + drive_info_struct *drv = &(hba[i]->drv[j]); + struct gendisk *disk = hba[i]->gendisk[j]; + + q = blk_init_queue(do_cciss_request, &hba[i]->lock); + if (!q) { + printk(KERN_ERR + "cciss: unable to allocate queue for disk %d\n", + j); + break; + } + drv->queue = q; + + q->backing_dev_info.ra_pages = READ_AHEAD; blk_queue_bounce_limit(q, hba[i]->pdev->dma_mask); /* This is a hardware imposed limit. */ @@ -2827,26 +2833,23 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, blk_queue_max_sectors(q, 512); - - for(j=0; j<NWD; j++) { - drive_info_struct *drv = &(hba[i]->drv[j]); - struct gendisk *disk = hba[i]->gendisk[j]; - + q->queuedata = hba[i]; sprintf(disk->disk_name, "cciss/c%dd%d", i, j); sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j); disk->major = hba[i]->major; disk->first_minor = j << NWD_SHIFT; disk->fops = &cciss_fops; - disk->queue = hba[i]->queue; + disk->queue = q; disk->private_data = drv; /* we must register the controller even if no disks exist */ /* this is for the online array utilities */ if(!drv->heads && j) continue; - blk_queue_hardsect_size(hba[i]->queue, drv->block_size); + blk_queue_hardsect_size(q, drv->block_size); set_capacity(disk, drv->nr_blocks); add_disk(disk); } + return(1); clean4: @@ -2912,10 +2915,10 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) for (j = 0; j < NWD; j++) { struct gendisk *disk = hba[i]->gendisk[j]; if (disk->flags & GENHD_FL_UP) + blk_cleanup_queue(disk->queue); del_gendisk(disk); } - blk_cleanup_queue(hba[i]->queue); pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle); pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct), diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 8fb19206edd..566587d0a50 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -29,6 +29,7 @@ typedef struct _drive_info_struct { __u32 LunID; int usage_count; + struct request_queue *queue; sector_t nr_blocks; int block_size; int heads; @@ -72,7 +73,6 @@ struct ctlr_info unsigned int maxQsinceinit; unsigned int maxSG; spinlock_t lock; - struct request_queue *queue; //* pointers to command and error info pool */ CommandList_struct *cmd_pool; @@ -260,7 +260,7 @@ struct board_type { struct access_method *access; }; -#define CCISS_LOCK(i) (hba[i]->queue->queue_lock) +#define CCISS_LOCK(i) (&hba[i]->lock) #endif /* CCISS_H */ diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c index de5746e38af..cd056e7e64e 100644 --- a/drivers/block/cfq-iosched.c +++ b/drivers/block/cfq-iosched.c @@ -47,7 +47,7 @@ static int cfq_slice_idle = HZ / 100; /* * disable queueing at the driver/hardware level */ -static int cfq_max_depth = 1; +static int cfq_max_depth = 2; /* * for the hash of cfqq inside the cfqd @@ -385,9 +385,15 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2) return crq2; if (crq2 == NULL) return crq1; - if (cfq_crq_requeued(crq1)) + + if (cfq_crq_requeued(crq1) && !cfq_crq_requeued(crq2)) return crq1; - if (cfq_crq_requeued(crq2)) + else if (cfq_crq_requeued(crq2) && !cfq_crq_requeued(crq1)) + return crq2; + + if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2)) + return crq1; + else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1)) return crq2; s1 = crq1->request->sector; @@ -1281,6 +1287,7 @@ dispatch: */ if (!cfq_crq_in_driver(crq) && !cfq_cfqq_idle_window(cfqq) && + !blk_barrier_rq(rq) && cfqd->rq_in_driver >= cfqd->cfq_max_depth) return NULL; @@ -1768,18 +1775,23 @@ static void cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_rq *crq) { - const int sync = cfq_crq_is_sync(crq); + struct cfq_io_context *cic; cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq); - if (sync) { - struct cfq_io_context *cic = crq->io_context; + /* + * we never wait for an async request and we don't allow preemption + * of an async request. so just return early + */ + if (!cfq_crq_is_sync(crq)) + return; - cfq_update_io_thinktime(cfqd, cic); - cfq_update_idle_window(cfqd, cfqq, cic); + cic = crq->io_context; - cic->last_queue = jiffies; - } + cfq_update_io_thinktime(cfqd, cic); + cfq_update_idle_window(cfqd, cfqq, cic); + + cic->last_queue = jiffies; if (cfqq == cfqd->active_queue) { /* diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 5be6f998d8c..3d4261c39f1 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c @@ -57,9 +57,11 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info) mode = strsep(&cmsp, "-"); if (mode == NULL || strcmp(mode, "cbc") == 0) - tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC); + tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC | + CRYPTO_TFM_REQ_MAY_SLEEP); else if (strcmp(mode, "ecb") == 0) - tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB); + tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB | + CRYPTO_TFM_REQ_MAY_SLEEP); if (tfm == NULL) return -EINVAL; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index f0c1084b840..888dad5eef3 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -493,6 +493,8 @@ static struct floppy_struct user_params[N_DRIVE]; static sector_t floppy_sizes[256]; +static char floppy_device_name[] = "floppy"; + /* * The driver is trying to determine the correct media format * while probing is set. rw_interrupt() clears it after a @@ -4191,18 +4193,24 @@ static int __init floppy_setup(char *str) static int have_no_fdc = -ENODEV; +static ssize_t floppy_cmos_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *p; + int drive; + + p = container_of(dev, struct platform_device,dev); + drive = p->id; + return sprintf(buf, "%X\n", UDP->cmos); +} +DEVICE_ATTR(cmos,S_IRUGO,floppy_cmos_show,NULL); + static void floppy_device_release(struct device *dev) { complete(&device_release); } -static struct platform_device floppy_device = { - .name = "floppy", - .id = 0, - .dev = { - .release = floppy_device_release, - } -}; +static struct platform_device floppy_device[N_DRIVE]; static struct kobject *floppy_find(dev_t dev, int *part, void *data) { @@ -4370,20 +4378,26 @@ static int __init floppy_init(void) goto out_flush_work; } - err = platform_device_register(&floppy_device); - if (err) - goto out_flush_work; - for (drive = 0; drive < N_DRIVE; drive++) { if (!(allowed_drive_mask & (1 << drive))) continue; if (fdc_state[FDC(drive)].version == FDC_NONE) continue; + + floppy_device[drive].name = floppy_device_name; + floppy_device[drive].id = drive; + floppy_device[drive].dev.release = floppy_device_release; + + err = platform_device_register(&floppy_device[drive]); + if (err) + goto out_flush_work; + + device_create_file(&floppy_device[drive].dev,&dev_attr_cmos); /* to be cleaned up... */ disks[drive]->private_data = (void *)(long)drive; disks[drive]->queue = floppy_queue; disks[drive]->flags |= GENHD_FL_REMOVABLE; - disks[drive]->driverfs_dev = &floppy_device.dev; + disks[drive]->driverfs_dev = &floppy_device[drive].dev; add_disk(disks[drive]); } @@ -4603,10 +4617,11 @@ void cleanup_module(void) fdc_state[FDC(drive)].version != FDC_NONE) { del_gendisk(disks[drive]); unregister_devfs_entries(drive); + device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos); + platform_device_unregister(&floppy_device[drive]); } put_disk(disks[drive]); } - platform_device_unregister(&floppy_device); devfs_remove("floppy"); del_timer_sync(&fd_timeout); diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 692a5fced76..3c818544475 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -719,7 +719,7 @@ struct request *blk_queue_find_tag(request_queue_t *q, int tag) { struct blk_queue_tag *bqt = q->queue_tags; - if (unlikely(bqt == NULL || tag >= bqt->max_depth)) + if (unlikely(bqt == NULL || tag >= bqt->real_max_depth)) return NULL; return bqt->tag_index[tag]; @@ -798,6 +798,7 @@ init_tag_map(request_queue_t *q, struct blk_queue_tag *tags, int depth) memset(tag_index, 0, depth * sizeof(struct request *)); memset(tag_map, 0, nr_ulongs * sizeof(unsigned long)); + tags->real_max_depth = depth; tags->max_depth = depth; tags->tag_index = tag_index; tags->tag_map = tag_map; @@ -872,11 +873,22 @@ int blk_queue_resize_tags(request_queue_t *q, int new_depth) return -ENXIO; /* + * if we already have large enough real_max_depth. just + * adjust max_depth. *NOTE* as requests with tag value + * between new_depth and real_max_depth can be in-flight, tag + * map can not be shrunk blindly here. + */ + if (new_depth <= bqt->real_max_depth) { + bqt->max_depth = new_depth; + return 0; + } + + /* * save the old state info, so we can copy it back */ tag_index = bqt->tag_index; tag_map = bqt->tag_map; - max_depth = bqt->max_depth; + max_depth = bqt->real_max_depth; if (init_tag_map(q, bqt, new_depth)) return -ENOMEM; @@ -913,7 +925,7 @@ void blk_queue_end_tag(request_queue_t *q, struct request *rq) BUG_ON(tag == -1); - if (unlikely(tag >= bqt->max_depth)) + if (unlikely(tag >= bqt->real_max_depth)) /* * This can happen after tag depth has been reduced. * FIXME: how about a warning or info message here? diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 9db0a9e3e59..d57007b92f7 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -1582,7 +1582,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto err_out; -#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ +#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!rc) { rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); @@ -1601,7 +1601,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_regions; } pci_dac = 0; -#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ +#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ } #endif diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 685f061e69b..a026567f5d1 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -23,6 +23,7 @@ * -- Exterminate P3 printks * -- Resove XXX's * -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=? + * -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring. */ #include <linux/kernel.h> #include <linux/module.h> @@ -38,6 +39,73 @@ #define UB_MAJOR 180 /* + * The command state machine is the key model for understanding of this driver. + * + * The general rule is that all transitions are done towards the bottom + * of the diagram, thus preventing any loops. + * + * An exception to that is how the STAT state is handled. A counter allows it + * to be re-entered along the path marked with [C]. + * + * +--------+ + * ! INIT ! + * +--------+ + * ! + * ub_scsi_cmd_start fails ->--------------------------------------\ + * ! ! + * V ! + * +--------+ ! + * ! CMD ! ! + * +--------+ ! + * ! +--------+ ! + * was -EPIPE -->-------------------------------->! CLEAR ! ! + * ! +--------+ ! + * ! ! ! + * was error -->------------------------------------- ! --------->\ + * ! ! ! + * /--<-- cmd->dir == NONE ? ! ! + * ! ! ! ! + * ! V ! ! + * ! +--------+ ! ! + * ! ! DATA ! ! ! + * ! +--------+ ! ! + * ! ! +---------+ ! ! + * ! was -EPIPE -->--------------->! CLR2STS ! ! ! + * ! ! +---------+ ! ! + * ! ! ! ! ! + * ! ! was error -->---- ! --------->\ + * ! was error -->--------------------- ! ------------- ! --------->\ + * ! ! ! ! ! + * ! V ! ! ! + * \--->+--------+ ! ! ! + * ! STAT !<--------------------------/ ! ! + * /--->+--------+ ! ! + * ! ! ! ! + * [C] was -EPIPE -->-----------\ ! ! + * ! ! ! ! ! + * +<---- len == 0 ! ! ! + * ! ! ! ! ! + * ! was error -->--------------------------------------!---------->\ + * ! ! ! ! ! + * +<---- bad CSW ! ! ! + * +<---- bad tag ! ! ! + * ! ! V ! ! + * ! ! +--------+ ! ! + * ! ! ! CLRRS ! ! ! + * ! ! +--------+ ! ! + * ! ! ! ! ! + * \------- ! --------------------[C]--------\ ! ! + * ! ! ! ! + * cmd->error---\ +--------+ ! ! + * ! +--------------->! SENSE !<----------/ ! + * STAT_FAIL----/ +--------+ ! + * ! ! V + * ! V +--------+ + * \--------------------------------\--------------------->! DONE ! + * +--------+ + */ + +/* * Definitions which have to be scattered once we understand the layout better. */ @@ -91,8 +159,6 @@ struct bulk_cs_wrap { #define US_BULK_CS_WRAP_LEN 13 #define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ -/* This is for Olympus Camedia digital cameras */ -#define US_BULK_CS_OLYMPUS_SIGN 0x55425355 /* spells out 'USBU' */ #define US_BULK_STAT_OK 0 #define US_BULK_STAT_FAIL 1 #define US_BULK_STAT_PHASE 2 @@ -135,6 +201,7 @@ enum ub_scsi_cmd_state { UB_CMDST_CLR2STS, /* Clearing before requesting status */ UB_CMDST_STAT, /* Status phase */ UB_CMDST_CLEAR, /* Clearing a stall (halt, actually) */ + UB_CMDST_CLRRS, /* Clearing before retrying status */ UB_CMDST_SENSE, /* Sending Request Sense */ UB_CMDST_DONE /* Final state */ }; @@ -146,6 +213,7 @@ static char *ub_scsi_cmd_stname[] = { "c2s", "sts", "clr", + "crs", "Sen", "fin" }; @@ -316,6 +384,7 @@ struct ub_dev { struct urb work_urb; struct timer_list work_timer; int last_pipe; /* What might need clearing */ + __le32 signature; /* Learned signature */ struct bulk_cb_wrap work_bcb; struct bulk_cs_wrap work_bcs; struct usb_ctrlrequest work_cr; @@ -339,8 +408,9 @@ 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_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc); -static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd); +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); +static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int stalled_pipe); @@ -1085,6 +1155,28 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ub_state_stat(sc, cmd); + } else if (cmd->state == UB_CMDST_CLRRS) { + if (urb->status == -EPIPE) { + /* + * STALL while clearning STALL. + * The control pipe clears itself - nothing to do. + * XXX Might try to reset the device here and retry. + */ + printk(KERN_NOTICE "%s: stall on control pipe\n", + sc->name); + goto Bad_End; + } + + /* + * We ignore the result for the halt clear. + */ + + /* reset the endpoint toggle */ + usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe), + usb_pipeout(sc->last_pipe), 0); + + ub_state_stat_counted(sc, cmd); + } else if (cmd->state == UB_CMDST_CMD) { if (urb->status == -EPIPE) { rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe); @@ -1190,52 +1282,57 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) */ goto Bad_End; } - cmd->state = UB_CMDST_CLEAR; + + /* + * Having a stall when getting CSW is an error, so + * make sure uppper levels are not oblivious to it. + */ + cmd->error = -EIO; /* A cheap trick... */ + + cmd->state = UB_CMDST_CLRRS; ub_cmdtr_state(sc, cmd); return; } + if (urb->status == -EOVERFLOW) { + /* + * XXX We are screwed here. Retrying is pointless, + * because the pipelined data will not get in until + * we read with a big enough buffer. We must reset XXX. + */ + goto Bad_End; + } if (urb->status != 0) goto Bad_End; if (urb->actual_length == 0) { - /* - * Some broken devices add unnecessary zero-length - * packets to the end of their data transfers. - * Such packets show up as 0-length CSWs. If we - * encounter such a thing, try to read the CSW again. - */ - if (++cmd->stat_count >= 4) { - printk(KERN_NOTICE "%s: unable to get CSW\n", - sc->name); - goto Bad_End; - } - __ub_state_stat(sc, cmd); + ub_state_stat_counted(sc, cmd); return; } /* * Check the returned Bulk protocol status. + * The status block has to be validated first. */ bcs = &sc->work_bcs; - rc = le32_to_cpu(bcs->Residue); - if (rc != cmd->len - cmd->act_len) { + + if (sc->signature == cpu_to_le32(0)) { /* - * It is all right to transfer less, the caller has - * to check. But it's not all right if the device - * counts disagree with our counts. + * This is the first reply, so do not perform the check. + * Instead, remember the signature the device uses + * for future checks. But do not allow a nul. */ - /* P3 */ printk("%s: resid %d len %d act %d\n", - sc->name, rc, cmd->len, cmd->act_len); - goto Bad_End; - } - -#if 0 - if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && - bcs->Signature != cpu_to_le32(US_BULK_CS_OLYMPUS_SIGN)) { - /* Windows ignores signatures, so do we. */ + sc->signature = bcs->Signature; + if (sc->signature == cpu_to_le32(0)) { + ub_state_stat_counted(sc, cmd); + return; + } + } else { + if (bcs->Signature != sc->signature) { + ub_state_stat_counted(sc, cmd); + return; + } } -#endif if (bcs->Tag != cmd->tag) { /* @@ -1245,16 +1342,22 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) * commands and reply at commands we timed out before. * Without flushing these replies we loop forever. */ - if (++cmd->stat_count >= 4) { - printk(KERN_NOTICE "%s: " - "tag mismatch orig 0x%x reply 0x%x\n", - sc->name, cmd->tag, bcs->Tag); - goto Bad_End; - } - __ub_state_stat(sc, cmd); + ub_state_stat_counted(sc, cmd); return; } + rc = le32_to_cpu(bcs->Residue); + if (rc != cmd->len - cmd->act_len) { + /* + * It is all right to transfer less, the caller has + * to check. But it's not all right if the device + * counts disagree with our counts. + */ + /* P3 */ printk("%s: resid %d len %d act %d\n", + sc->name, rc, cmd->len, cmd->act_len); + goto Bad_End; + } + switch (bcs->Status) { case US_BULK_STAT_OK: break; @@ -1272,6 +1375,10 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) } /* Not zeroing error to preserve a babble indicator */ + if (cmd->error != 0) { + ub_state_sense(sc, cmd); + return; + } cmd->state = UB_CMDST_DONE; ub_cmdtr_state(sc, cmd); ub_cmdq_pop(sc); @@ -1310,7 +1417,7 @@ static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc) * Factorization helper for the command state machine: * Submit a CSW read. */ -static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) { int rc; @@ -1328,11 +1435,12 @@ static void __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) /* XXX Clear stalls */ ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); - return; + return -1; } sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; add_timer(&sc->work_timer); + return 0; } /* @@ -1341,7 +1449,9 @@ static void __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) { - __ub_state_stat(sc, cmd); + + if (__ub_state_stat(sc, cmd) != 0) + return; cmd->stat_count = 0; cmd->state = UB_CMDST_STAT; @@ -1350,6 +1460,25 @@ static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) /* * Factorization helper for the command state machine: + * Submit a CSW read and go to STAT state with counter (along [C] path). + */ +static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd) +{ + + if (++cmd->stat_count >= 4) { + ub_state_sense(sc, cmd); + return; + } + + if (__ub_state_stat(sc, cmd) != 0) + return; + + cmd->state = UB_CMDST_STAT; + ub_cmdtr_state(sc, cmd); +} + +/* + * Factorization helper for the command state machine: * Submit a REQUEST SENSE and go to SENSE state. */ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd) diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index 46e56a25d2c..e46ecd23b3a 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -776,7 +776,7 @@ static int viodasd_remove(struct vio_dev *vdev) */ static struct vio_device_id viodasd_device_table[] __devinitdata = { { "viodasd", "" }, - { 0, } + { "", "" } }; MODULE_DEVICE_TABLE(vio, viodasd_device_table); |