diff options
Diffstat (limited to 'drivers/scsi/hosts.c')
| -rw-r--r-- | drivers/scsi/hosts.c | 68 |
1 files changed, 47 insertions, 21 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 198edf03f929..1b3fbd328277 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -231,6 +231,12 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, goto fail; } + if (shost->nr_reserved_cmds && !sht->queue_reserved_command) { + shost_printk(KERN_ERR, shost, + "nr_reserved_cmds set but no method to queue\n"); + goto fail; + } + /* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */ shost->cmd_per_lun = min_t(int, shost->cmd_per_lun, shost->can_queue); @@ -292,11 +298,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, } if (shost->transportt->create_work_queue) { - snprintf(shost->work_q_name, sizeof(shost->work_q_name), - "scsi_wq_%d", shost->host_no); - shost->work_q = alloc_workqueue("%s", - WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, - 1, shost->work_q_name); + shost->work_q = alloc_workqueue( + "scsi_wq_%d", + WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, 1, + shost->host_no); if (!shost->work_q) { error = -EINVAL; @@ -308,6 +313,14 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, if (error) goto out_del_dev; + if (shost->nr_reserved_cmds) { + shost->pseudo_sdev = scsi_get_pseudo_sdev(shost); + if (!shost->pseudo_sdev) { + error = -ENOMEM; + goto out_del_dev; + } + } + scsi_proc_host_add(shost); scsi_autopm_put_host(shost); return error; @@ -353,12 +366,13 @@ static void scsi_host_dev_release(struct device *dev) if (shost->shost_state == SHOST_CREATED) { /* - * Free the shost_dev device name here if scsi_host_alloc() - * and scsi_host_put() have been called but neither + * Free the shost_dev device name and remove the proc host dir + * here if scsi_host_{alloc,put}() have been called but neither * scsi_host_add() nor scsi_remove_host() has been called. * This avoids that the memory allocated for the shost_dev - * name is leaked. + * name as well as the proc dir structure are leaked. */ + scsi_proc_hostdir_rm(shost->hostt); kfree(dev_name(&shost->shost_dev)); } @@ -371,7 +385,7 @@ static void scsi_host_dev_release(struct device *dev) kfree(shost); } -static struct device_type scsi_host_type = { +static const struct device_type scsi_host_type = { .name = "scsi_host", .release = scsi_host_dev_release, }; @@ -436,6 +450,7 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv shost->hostt = sht; shost->this_id = sht->this_id; shost->can_queue = sht->can_queue; + shost->nr_reserved_cmds = sht->nr_reserved_cmds; shost->sg_tablesize = sht->sg_tablesize; shost->sg_prot_tablesize = sht->sg_prot_tablesize; shost->cmd_per_lun = sht->cmd_per_lun; @@ -473,10 +488,23 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv else shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; - if (sht->max_segment_size) - shost->max_segment_size = sht->max_segment_size; + shost->virt_boundary_mask = sht->virt_boundary_mask; + if (shost->virt_boundary_mask) { + WARN_ON_ONCE(sht->max_segment_size && + sht->max_segment_size != UINT_MAX); + shost->max_segment_size = UINT_MAX; + } else { + if (sht->max_segment_size) + shost->max_segment_size = sht->max_segment_size; + else + shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; + } + + /* 32-byte (dword) is a common minimum for HBAs. */ + if (sht->dma_alignment) + shost->dma_alignment = sht->dma_alignment; else - shost->max_segment_size = BLK_MAX_SEGMENT_SIZE; + shost->dma_alignment = 3; /* * assume a 4GB boundary, if not set @@ -486,9 +514,6 @@ struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int priv else shost->dma_boundary = 0xffffffff; - if (sht->virt_boundary_mask) - shost->virt_boundary_mask = sht->virt_boundary_mask; - device_initialize(&shost->shost_gendev); dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); shost->shost_gendev.bus = &scsi_bus_type; @@ -537,7 +562,7 @@ EXPORT_SYMBOL(scsi_host_alloc); static int __scsi_host_match(struct device *dev, const void *data) { struct Scsi_Host *p; - const unsigned short *hostnum = data; + const unsigned int *hostnum = data; p = class_to_shost(dev); return p->host_no == *hostnum; @@ -554,7 +579,7 @@ static int __scsi_host_match(struct device *dev, const void *data) * that scsi_host_get() took. The put_device() below dropped * the reference from class_find_device(). **/ -struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) +struct Scsi_Host *scsi_host_lookup(unsigned int hostnum) { struct device *cdev; struct Scsi_Host *shost = NULL; @@ -594,15 +619,16 @@ static bool scsi_host_check_in_flight(struct request *rq, void *data) } /** - * scsi_host_busy - Return the host busy counter - * @shost: Pointer to Scsi_Host to inc. + * scsi_host_busy - Return the count of in-flight commands + * @shost: Pointer to Scsi_Host **/ int scsi_host_busy(struct Scsi_Host *shost) { int cnt = 0; - blk_mq_tagset_busy_iter(&shost->tag_set, - scsi_host_check_in_flight, &cnt); + if (shost->tag_set.ops) + blk_mq_tagset_busy_iter(&shost->tag_set, + scsi_host_check_in_flight, &cnt); return cnt; } EXPORT_SYMBOL(scsi_host_busy); |
