diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_error.c | 21 | ||||
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 27 |
2 files changed, 43 insertions, 5 deletions
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index bb5a6e0fa49a..6b1423707397 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -63,6 +63,13 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd); static enum scsi_disposition scsi_try_to_abort_cmd(struct scsi_host_template *, struct scsi_cmnd *); +#ifdef CONFIG_AHCI_IMX +extern void *sg_io_buffer_hack; +#else +#define sg_io_buffer_hack NULL +#endif + +/* called with shost->host_lock held */ void scsi_eh_wakeup(struct Scsi_Host *shost) { lockdep_assert_held(shost->host_lock); @@ -72,6 +79,11 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) wake_up_process(shost->ehandler); SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost, "Waking error handler thread\n")); + } else if ((shost->host_failed > 0) || (sg_io_buffer_hack != NULL)) { + trace_scsi_eh_wakeup(shost); + wake_up_process(shost->ehandler); + SCSI_LOG_ERROR_RECOVERY(5, shost_printk(KERN_INFO, shost, + "Waking error handler thread\n")); } } @@ -2242,8 +2254,15 @@ int scsi_error_handler(void *data) if (kthread_should_stop()) break; + /* + * Do not go to sleep, when there is host_failed when the + * one-PRD per command workaroud is triggered. + * Because that ata/scsi subsystem maybe hang, when CD_ROM + * and HDD are accessed simultaneously. + */ if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || - shost->host_failed != scsi_host_busy(shost)) { + ((shost->host_failed != scsi_host_busy(shost)) && + (sg_io_buffer_hack == NULL) && (shost->host_failed > 0))) { SCSI_LOG_ERROR_RECOVERY(1, shost_printk(KERN_INFO, shost, "scsi_eh_%d: sleeping\n", diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 6e2f82152b4a..5f774b8c12be 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -370,6 +370,12 @@ static int scsi_fill_sghdr_rq(struct scsi_device *sdev, struct request *rq, return 0; } +#ifdef CONFIG_AHCI_IMX +extern void *sg_io_buffer_hack; +#else +#define sg_io_buffer_hack NULL +#endif + static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, struct bio *bio) { @@ -401,7 +407,12 @@ static int scsi_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, ret = -EFAULT; } - r = blk_rq_unmap_user(bio); + if (sg_io_buffer_hack && !hdr->iovec_count) + r = copy_to_user(hdr->dxferp, sg_io_buffer_hack, + hdr->dxfer_len); + else + r = blk_rq_unmap_user(bio); + if (!ret) ret = r; @@ -425,6 +436,9 @@ static int sg_io(struct scsi_device *sdev, struct gendisk *disk, if (hdr->dxfer_len > (queue_max_hw_sectors(sdev->request_queue) << 9)) return -EIO; + if (sg_io_buffer_hack && hdr->dxfer_len > 0x10000) + return -EIO; + if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: @@ -471,9 +485,14 @@ static int sg_io(struct scsi_device *sdev, struct gendisk *disk, ret = blk_rq_map_user_iov(rq->q, rq, NULL, &i, GFP_KERNEL); kfree(iov); - } else if (hdr->dxfer_len) - ret = blk_rq_map_user(rq->q, rq, NULL, hdr->dxferp, - hdr->dxfer_len, GFP_KERNEL); + } else if (hdr->dxfer_len) { + if (sg_io_buffer_hack) + ret = blk_rq_map_kern(rq->q, rq, sg_io_buffer_hack, + hdr->dxfer_len, GFP_KERNEL); + else + ret = blk_rq_map_user(rq->q, rq, NULL, hdr->dxferp, + hdr->dxfer_len, GFP_KERNEL); + } if (ret) goto out_free_cdb; |