diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 55 |
1 files changed, 49 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 88d1b5f44e59..ff5d56b3ee4d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { }; #undef SP -static struct kmem_cache *scsi_sdb_cache; +struct kmem_cache *scsi_sdb_cache; static void scsi_run_queue(struct request_queue *q); @@ -787,6 +787,9 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) kmem_cache_free(scsi_sdb_cache, bidi_sdb); cmd->request->next_rq->special = NULL; } + + if (scsi_prot_sg_count(cmd)) + scsi_free_sgtable(cmd->prot_sdb); } EXPORT_SYMBOL(scsi_release_buffers); @@ -947,9 +950,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * 6-byte command. */ scsi_requeue_command(q, cmd); - return; - } else { + } else if (sshdr.asc == 0x10) /* DIX */ + scsi_end_request(cmd, -EIO, this_count, 0); + else scsi_end_request(cmd, -EIO, this_count, 1); + return; + case ABORTED_COMMAND: + if (sshdr.asc == 0x10) { /* DIF */ + scsi_end_request(cmd, -EIO, this_count, 0); return; } break; @@ -1072,6 +1080,26 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) goto err_exit; } + if (blk_integrity_rq(cmd->request)) { + struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; + int ivecs, count; + + BUG_ON(prot_sdb == NULL); + ivecs = blk_rq_count_integrity_sg(cmd->request); + + if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { + error = BLKPREP_DEFER; + goto err_exit; + } + + count = blk_rq_map_integrity_sg(cmd->request, + prot_sdb->table.sgl); + BUG_ON(unlikely(count > ivecs)); + + cmd->prot_sdb = prot_sdb; + cmd->prot_sdb->table.nents = count; + } + return BLKPREP_OK ; err_exit: @@ -1367,7 +1395,7 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) if (unlikely(cmd == NULL)) { printk(KERN_CRIT "impossible request in %s.\n", - __FUNCTION__); + __func__); BUG(); } @@ -1491,12 +1519,27 @@ static void scsi_request_fn(struct request_queue *q) printk(KERN_CRIT "impossible request in %s.\n" "please mail a stack trace to " "linux-scsi@vger.kernel.org\n", - __FUNCTION__); + __func__); blk_dump_rq_flags(req, "foo"); BUG(); } spin_lock(shost->host_lock); + /* + * We hit this when the driver is using a host wide + * tag map. For device level tag maps the queue_depth check + * in the device ready fn would prevent us from trying + * to allocate a tag. Since the map is a shared host resource + * we add the dev to the starved list so it eventually gets + * a run when a tag is freed. + */ + if (blk_queue_tagged(q) && !blk_rq_tagged(req)) { + if (list_empty(&sdev->starved_entry)) + list_add_tail(&sdev->starved_entry, + &shost->starved_list); + goto not_ready; + } + if (!scsi_host_queue_ready(q, shost, sdev)) goto not_ready; if (scsi_target(sdev)->single_lun) { @@ -2486,7 +2529,7 @@ void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, if (unlikely(i == sg_count)) { printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, " "elements %d\n", - __FUNCTION__, sg_len, *offset, sg_count); + __func__, sg_len, *offset, sg_count); WARN_ON(1); return NULL; } |