X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fblock%2Fub.c;h=fccac18d311121d01f28ca4ce819886f79cf300f;hb=1f6d6e8ebe73ba9d9d4c693f7f6f50f661dbd6e4;hp=e322cce8c12d7870d45b2b202c8ff60e9e924c9f;hpb=ec31b2124158f60c515ed84bd5e40db1a883c7b6;p=linux-2.6-omap-h63xx.git diff --git a/drivers/block/ub.c b/drivers/block/ub.c index e322cce8c12..fccac18d311 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -205,6 +205,7 @@ struct ub_scsi_cmd { unsigned char key, asc, ascq; /* May be valid if error==-EIO */ int stat_count; /* Retries getting status. */ + unsigned int timeo; /* jiffies until rq->timeout changes */ unsigned int len; /* Requested length */ unsigned int current_sg; @@ -318,6 +319,7 @@ struct ub_dev { int openc; /* protected by ub_lock! */ /* kref is too implicit for our taste */ int reset; /* Reset is running */ + int bad_resid; unsigned int tagcnt; char name[12]; struct usb_device *dev; @@ -347,8 +349,6 @@ struct ub_dev { struct work_struct reset_work; wait_queue_head_t reset_wait; - - int sg_stat[6]; }; /* @@ -683,7 +683,6 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq) goto drop; } urq->nsg = n_elem; - sc->sg_stat[n_elem < 5 ? n_elem : 5]++; if (blk_pc_request(rq)) { ub_cmd_build_packet(sc, lun, cmd, urq); @@ -764,6 +763,12 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, cmd->cdb_len = rq->cmd_len; cmd->len = rq->data_len; + + /* + * To reapply this to every URB is not as incorrect as it looks. + * In return, we avoid any complicated tracking calculations. + */ + cmd->timeo = rq->timeout; } static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) @@ -785,10 +790,6 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) scsi_status = 0; } else { if (cmd->act_len != cmd->len) { - if ((cmd->key == MEDIUM_ERROR || - cmd->key == UNIT_ATTENTION) && - ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) - return; scsi_status = SAM_STAT_CHECK_CONDITION; } else { scsi_status = 0; @@ -804,7 +805,10 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) else scsi_status = DID_ERROR << 16; } else { - if (cmd->error == -EIO) { + if (cmd->error == -EIO && + (cmd->key == 0 || + cmd->key == MEDIUM_ERROR || + cmd->key == UNIT_ATTENTION)) { if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0) return; } @@ -1259,14 +1263,19 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } - len = le32_to_cpu(bcs->Residue); - if (len != 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. - */ - goto Bad_End; + if (!sc->bad_resid) { + len = le32_to_cpu(bcs->Residue); + if (len != cmd->len - cmd->act_len) { + /* + * Only start ignoring if this cmd ended well. + */ + if (cmd->len == cmd->act_len) { + printk(KERN_NOTICE "%s: " + "bad residual %d of %d, ignoring\n", + sc->name, len, cmd->len); + sc->bad_resid = 1; + } + } } switch (bcs->Status) { @@ -1297,8 +1306,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ub_state_done(sc, cmd, -EIO); } else { - printk(KERN_WARNING "%s: " - "wrong command state %d\n", + printk(KERN_WARNING "%s: wrong command state %d\n", sc->name, cmd->state); ub_state_done(sc, cmd, -EINVAL); return; @@ -1336,7 +1344,10 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } - sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; + if (cmd->timeo) + sc->work_timer.expires = jiffies + cmd->timeo; + else + sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT; add_timer(&sc->work_timer); cmd->state = UB_CMDST_DATA; @@ -1376,7 +1387,10 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return -1; } - sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; + if (cmd->timeo) + sc->work_timer.expires = jiffies + cmd->timeo; + else + sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT; add_timer(&sc->work_timer); return 0; } @@ -1515,8 +1529,7 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd) return; } if (cmd->state != UB_CMDST_SENSE) { - printk(KERN_WARNING "%s: " - "sense done with bad cmd state %d\n", + printk(KERN_WARNING "%s: sense done with bad cmd state %d\n", sc->name, cmd->state); return; } @@ -1654,10 +1667,9 @@ static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun) * This is mostly needed to keep refcounting, but also to support * media checks on removable media drives. */ -static int ub_bd_open(struct inode *inode, struct file *filp) +static int ub_bd_open(struct block_device *bdev, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; - struct ub_lun *lun = disk->private_data; + struct ub_lun *lun = bdev->bd_disk->private_data; struct ub_dev *sc = lun->udev; unsigned long flags; int rc; @@ -1671,19 +1683,19 @@ static int ub_bd_open(struct inode *inode, struct file *filp) spin_unlock_irqrestore(&ub_lock, flags); if (lun->removable || lun->readonly) - check_disk_change(inode->i_bdev); + check_disk_change(bdev); /* * The sd.c considers ->media_present and ->changed not equivalent, * under some pretty murky conditions (a failure of READ CAPACITY). * We may need it one day. */ - if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) { + if (lun->removable && lun->changed && !(mode & FMODE_NDELAY)) { rc = -ENOMEDIUM; goto err_open; } - if (lun->readonly && (filp->f_mode & FMODE_WRITE)) { + if (lun->readonly && (mode & FMODE_WRITE)) { rc = -EROFS; goto err_open; } @@ -1697,9 +1709,8 @@ err_open: /* */ -static int ub_bd_release(struct inode *inode, struct file *filp) +static int ub_bd_release(struct gendisk *disk, fmode_t mode) { - struct gendisk *disk = inode->i_bdev->bd_disk; struct ub_lun *lun = disk->private_data; struct ub_dev *sc = lun->udev; @@ -1710,17 +1721,17 @@ static int ub_bd_release(struct inode *inode, struct file *filp) /* * The ioctl interface. */ -static int ub_bd_ioctl(struct inode *inode, struct file *filp, +static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = inode->i_bdev->bd_disk; + struct gendisk *disk = bdev->bd_disk; void __user *usermem = (void __user *) arg; - return scsi_cmd_ioctl(filp, disk->queue, disk, cmd, usermem); + return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem); } /* - * This is called once a new disk was seen by the block layer or by ub_probe(). + * This is called by check_disk_change if we reported a media change. * The main onjective here is to discover the features of the media such as * the capacity, read-only status, etc. USB storage generally does not * need to be spun up, but if we needed it, this would be the place. @@ -1780,7 +1791,7 @@ static struct block_device_operations ub_bd_fops = { .owner = THIS_MODULE, .open = ub_bd_open, .release = ub_bd_release, - .ioctl = ub_bd_ioctl, + .locked_ioctl = ub_bd_ioctl, .media_changed = ub_bd_media_changed, .revalidate_disk = ub_bd_revalidate, }; @@ -2136,8 +2147,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev, } if (ep_in == NULL || ep_out == NULL) { - printk(KERN_NOTICE "%s: failed endpoint check\n", - sc->name); + printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name); return -ENODEV; } @@ -2354,7 +2364,7 @@ static void ub_disconnect(struct usb_interface *intf) spin_unlock_irqrestore(&ub_lock, flags); /* - * Fence stall clearnings, operations triggered by unlinkings and so on. + * Fence stall clearings, operations triggered by unlinkings and so on. * We do not attempt to unlink any URBs, because we do not trust the * unlink paths in HC drivers. Also, we get -84 upon disconnect anyway. */ @@ -2417,7 +2427,7 @@ static void ub_disconnect(struct usb_interface *intf) spin_unlock_irqrestore(sc->lock, flags); /* - * There is virtually no chance that other CPU runs times so long + * There is virtually no chance that other CPU runs a timeout so long * after ub_urb_complete should have called del_timer, but only if HCD * didn't forget to deliver a callback on unlink. */