summaryrefslogtreecommitdiff
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_error.c21
-rw-r--r--drivers/scsi/scsi_ioctl.c27
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;