1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * hosts.c Copyright (C) 1992 Drew Eckhardt
41da177e4SLinus Torvalds * Copyright (C) 1993, 1994, 1995 Eric Youngdale
51da177e4SLinus Torvalds * Copyright (C) 2002-2003 Christoph Hellwig
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * mid to lowlevel SCSI driver interface
81da177e4SLinus Torvalds * Initial versions: Drew Eckhardt
91da177e4SLinus Torvalds * Subsequent revisions: Eric Youngdale
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * <drew@colorado.edu>
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
141da177e4SLinus Torvalds * Added QLOGIC QLA1280 SCSI controller kernel host support.
151da177e4SLinus Torvalds * August 4, 1999 Fred Lewis, Intel DuPont
161da177e4SLinus Torvalds *
171da177e4SLinus Torvalds * Updated to reflect the new initialization scheme for the higher
181da177e4SLinus Torvalds * level of scsi drivers (sd/sr/st)
191da177e4SLinus Torvalds * September 17, 2000 Torben Mathiasen <tmm@image.dk>
201da177e4SLinus Torvalds *
211da177e4SLinus Torvalds * Restructured scsi_host lists and associated functions.
221da177e4SLinus Torvalds * September 04, 2002 Mike Anderson (andmike@us.ibm.com)
231da177e4SLinus Torvalds */
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #include <linux/module.h>
261da177e4SLinus Torvalds #include <linux/blkdev.h>
271da177e4SLinus Torvalds #include <linux/kernel.h>
285a0e3ad6STejun Heo #include <linux/slab.h>
29c5478defSChristoph Hellwig #include <linux/kthread.h>
301da177e4SLinus Torvalds #include <linux/string.h>
311da177e4SLinus Torvalds #include <linux/mm.h>
321da177e4SLinus Torvalds #include <linux/init.h>
331da177e4SLinus Torvalds #include <linux/completion.h>
341da177e4SLinus Torvalds #include <linux/transport_class.h>
35d052d1beSRussell King #include <linux/platform_device.h>
36bc4f2401SAlan Stern #include <linux/pm_runtime.h>
37126a4fe0SLee Duncan #include <linux/idr.h>
381da177e4SLinus Torvalds #include <scsi/scsi_device.h>
391da177e4SLinus Torvalds #include <scsi/scsi_host.h>
401da177e4SLinus Torvalds #include <scsi/scsi_transport.h>
416eb045e0SMing Lei #include <scsi/scsi_cmnd.h>
421da177e4SLinus Torvalds
431da177e4SLinus Torvalds #include "scsi_priv.h"
441da177e4SLinus Torvalds #include "scsi_logging.h"
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds
4798663067SBart Van Assche static int shost_eh_deadline = -1;
4898663067SBart Van Assche
4998663067SBart Van Assche module_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
5098663067SBart Van Assche MODULE_PARM_DESC(eh_deadline,
5198663067SBart Van Assche "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
5298663067SBart Van Assche
53126a4fe0SLee Duncan static DEFINE_IDA(host_index_ida);
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds
scsi_host_cls_release(struct device * dev)56ee959b00STony Jones static void scsi_host_cls_release(struct device *dev)
571da177e4SLinus Torvalds {
58ee959b00STony Jones put_device(&class_to_shost(dev)->shost_gendev);
591da177e4SLinus Torvalds }
601da177e4SLinus Torvalds
611da177e4SLinus Torvalds static struct class shost_class = {
621da177e4SLinus Torvalds .name = "scsi_host",
63ee959b00STony Jones .dev_release = scsi_host_cls_release,
640a84486dSBart Van Assche .dev_groups = scsi_shost_groups,
651da177e4SLinus Torvalds };
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /**
68eb44820cSRob Landley * scsi_host_set_state - Take the given host through the host state model.
69d3301874SMike Anderson * @shost: scsi host to change the state of.
70d3301874SMike Anderson * @state: state to change to.
71d3301874SMike Anderson *
72d3301874SMike Anderson * Returns zero if unsuccessful or an error if the requested
73d3301874SMike Anderson * transition is illegal.
74d3301874SMike Anderson **/
scsi_host_set_state(struct Scsi_Host * shost,enum scsi_host_state state)75d3301874SMike Anderson int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
76d3301874SMike Anderson {
77d3301874SMike Anderson enum scsi_host_state oldstate = shost->shost_state;
78d3301874SMike Anderson
79d3301874SMike Anderson if (state == oldstate)
80d3301874SMike Anderson return 0;
81d3301874SMike Anderson
82d3301874SMike Anderson switch (state) {
83d3301874SMike Anderson case SHOST_CREATED:
84d3301874SMike Anderson /* There are no legal states that come back to
85d3301874SMike Anderson * created. This is the manually initialised start
86d3301874SMike Anderson * state */
87d3301874SMike Anderson goto illegal;
88d3301874SMike Anderson
89d3301874SMike Anderson case SHOST_RUNNING:
90d3301874SMike Anderson switch (oldstate) {
91d3301874SMike Anderson case SHOST_CREATED:
92d3301874SMike Anderson case SHOST_RECOVERY:
93d3301874SMike Anderson break;
94d3301874SMike Anderson default:
95d3301874SMike Anderson goto illegal;
96d3301874SMike Anderson }
97d3301874SMike Anderson break;
98d3301874SMike Anderson
99d3301874SMike Anderson case SHOST_RECOVERY:
100d3301874SMike Anderson switch (oldstate) {
101d3301874SMike Anderson case SHOST_RUNNING:
102d3301874SMike Anderson break;
103d3301874SMike Anderson default:
104d3301874SMike Anderson goto illegal;
105d3301874SMike Anderson }
106d3301874SMike Anderson break;
107d3301874SMike Anderson
108d3301874SMike Anderson case SHOST_CANCEL:
109d3301874SMike Anderson switch (oldstate) {
110d3301874SMike Anderson case SHOST_CREATED:
111d3301874SMike Anderson case SHOST_RUNNING:
112939647eeSJames Bottomley case SHOST_CANCEL_RECOVERY:
113d3301874SMike Anderson break;
114d3301874SMike Anderson default:
115d3301874SMike Anderson goto illegal;
116d3301874SMike Anderson }
117d3301874SMike Anderson break;
118d3301874SMike Anderson
119d3301874SMike Anderson case SHOST_DEL:
120d3301874SMike Anderson switch (oldstate) {
121d3301874SMike Anderson case SHOST_CANCEL:
122939647eeSJames Bottomley case SHOST_DEL_RECOVERY:
123d3301874SMike Anderson break;
124d3301874SMike Anderson default:
125d3301874SMike Anderson goto illegal;
126d3301874SMike Anderson }
127d3301874SMike Anderson break;
128d3301874SMike Anderson
129939647eeSJames Bottomley case SHOST_CANCEL_RECOVERY:
130939647eeSJames Bottomley switch (oldstate) {
131939647eeSJames Bottomley case SHOST_CANCEL:
132939647eeSJames Bottomley case SHOST_RECOVERY:
133939647eeSJames Bottomley break;
134939647eeSJames Bottomley default:
135939647eeSJames Bottomley goto illegal;
136939647eeSJames Bottomley }
137939647eeSJames Bottomley break;
138939647eeSJames Bottomley
139939647eeSJames Bottomley case SHOST_DEL_RECOVERY:
140939647eeSJames Bottomley switch (oldstate) {
141939647eeSJames Bottomley case SHOST_CANCEL_RECOVERY:
142939647eeSJames Bottomley break;
143939647eeSJames Bottomley default:
144939647eeSJames Bottomley goto illegal;
145939647eeSJames Bottomley }
146939647eeSJames Bottomley break;
147d3301874SMike Anderson }
148d3301874SMike Anderson shost->shost_state = state;
149d3301874SMike Anderson return 0;
150d3301874SMike Anderson
151d3301874SMike Anderson illegal:
152d3301874SMike Anderson SCSI_LOG_ERROR_RECOVERY(1,
1539ccfc756SJames Bottomley shost_printk(KERN_ERR, shost,
154d3301874SMike Anderson "Illegal host state transition"
155d3301874SMike Anderson "%s->%s\n",
156d3301874SMike Anderson scsi_host_state_name(oldstate),
157d3301874SMike Anderson scsi_host_state_name(state)));
158d3301874SMike Anderson return -EINVAL;
159d3301874SMike Anderson }
160d3301874SMike Anderson
161d3301874SMike Anderson /**
1621da177e4SLinus Torvalds * scsi_remove_host - remove a scsi host
1631da177e4SLinus Torvalds * @shost: a pointer to a scsi host to remove
1641da177e4SLinus Torvalds **/
scsi_remove_host(struct Scsi_Host * shost)1651da177e4SLinus Torvalds void scsi_remove_host(struct Scsi_Host *shost)
1661da177e4SLinus Torvalds {
167939647eeSJames Bottomley unsigned long flags;
168bc4f2401SAlan Stern
1690b950672SArjan van de Ven mutex_lock(&shost->scan_mutex);
170939647eeSJames Bottomley spin_lock_irqsave(shost->host_lock, flags);
171939647eeSJames Bottomley if (scsi_host_set_state(shost, SHOST_CANCEL))
172939647eeSJames Bottomley if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
173939647eeSJames Bottomley spin_unlock_irqrestore(shost->host_lock, flags);
1740b950672SArjan van de Ven mutex_unlock(&shost->scan_mutex);
175939647eeSJames Bottomley return;
176939647eeSJames Bottomley }
177939647eeSJames Bottomley spin_unlock_irqrestore(shost->host_lock, flags);
178bc4f2401SAlan Stern
179bc4f2401SAlan Stern scsi_autopm_get_host(shost);
180e494f6a7SHannes Reinecke flush_workqueue(shost->tmf_work_q);
1811da177e4SLinus Torvalds scsi_forget_host(shost);
1824e46bf89SAlexey Kuznetsov mutex_unlock(&shost->scan_mutex);
1831da177e4SLinus Torvalds scsi_proc_host_rm(shost);
184fc663711SBart Van Assche scsi_proc_hostdir_rm(shost->hostt);
1851da177e4SLinus Torvalds
1868fe4ce58SBart Van Assche /*
1878fe4ce58SBart Van Assche * New SCSI devices cannot be attached anymore because of the SCSI host
1888fe4ce58SBart Van Assche * state so drop the tag set refcnt. Wait until the tag set refcnt drops
1898fe4ce58SBart Van Assche * to zero because .exit_cmd_priv implementations may need the host
1908fe4ce58SBart Van Assche * pointer.
1918fe4ce58SBart Van Assche */
1928fe4ce58SBart Van Assche kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
1938fe4ce58SBart Van Assche wait_for_completion(&shost->tagset_freed);
1948fe4ce58SBart Van Assche
195939647eeSJames Bottomley spin_lock_irqsave(shost->host_lock, flags);
196939647eeSJames Bottomley if (scsi_host_set_state(shost, SHOST_DEL))
197939647eeSJames Bottomley BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
198939647eeSJames Bottomley spin_unlock_irqrestore(shost->host_lock, flags);
1991da177e4SLinus Torvalds
2001da177e4SLinus Torvalds transport_unregister_device(&shost->shost_gendev);
201ee959b00STony Jones device_unregister(&shost->shost_dev);
2021da177e4SLinus Torvalds device_del(&shost->shost_gendev);
2031da177e4SLinus Torvalds }
2041da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_remove_host);
2051da177e4SLinus Torvalds
2061da177e4SLinus Torvalds /**
207d139b9bdSJames Bottomley * scsi_add_host_with_dma - add a scsi host with dma device
2081da177e4SLinus Torvalds * @shost: scsi host pointer to add
2091da177e4SLinus Torvalds * @dev: a struct device of type scsi class
210d139b9bdSJames Bottomley * @dma_dev: dma device for the host
211d139b9bdSJames Bottomley *
212d139b9bdSJames Bottomley * Note: You rarely need to worry about this unless you're in a
213d139b9bdSJames Bottomley * virtualised host environments, so use the simpler scsi_add_host()
214d139b9bdSJames Bottomley * function instead.
2151da177e4SLinus Torvalds *
2161da177e4SLinus Torvalds * Return value:
2171da177e4SLinus Torvalds * 0 on success / != 0 for error
2181da177e4SLinus Torvalds **/
scsi_add_host_with_dma(struct Scsi_Host * shost,struct device * dev,struct device * dma_dev)219d139b9bdSJames Bottomley int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
220d139b9bdSJames Bottomley struct device *dma_dev)
2211da177e4SLinus Torvalds {
222e0d3f2c6SBart Van Assche const struct scsi_host_template *sht = shost->hostt;
2231da177e4SLinus Torvalds int error = -EINVAL;
2241da177e4SLinus Torvalds
22591921e01SHannes Reinecke shost_printk(KERN_INFO, shost, "%s\n",
2261da177e4SLinus Torvalds sht->info ? sht->info(shost) : sht->name);
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds if (!shost->can_queue) {
22991921e01SHannes Reinecke shost_printk(KERN_ERR, shost,
23091921e01SHannes Reinecke "can_queue = 0 no longer supported\n");
231542bd137SJames Bottomley goto fail;
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds
23450b6cb35SDexuan Cui /* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */
23550b6cb35SDexuan Cui shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
236ea2f0f77SJohn Garry shost->can_queue);
237ea2f0f77SJohn Garry
2380a6ac4eeSChristoph Hellwig error = scsi_init_sense_cache(shost);
2390a6ac4eeSChristoph Hellwig if (error)
2400a6ac4eeSChristoph Hellwig goto fail;
2410a6ac4eeSChristoph Hellwig
2421da177e4SLinus Torvalds if (!shost->shost_gendev.parent)
2431da177e4SLinus Torvalds shost->shost_gendev.parent = dev ? dev : &platform_bus;
2443c8d9a95SJames Bottomley if (!dma_dev)
2453c8d9a95SJames Bottomley dma_dev = shost->shost_gendev.parent;
2463c8d9a95SJames Bottomley
247d139b9bdSJames Bottomley shost->dma_dev = dma_dev;
2481da177e4SLinus Torvalds
249bb7d1283SJohn Garry if (dma_dev->dma_mask) {
250bb7d1283SJohn Garry shost->max_sectors = min_t(unsigned int, shost->max_sectors,
251bb7d1283SJohn Garry dma_max_mapping_size(dma_dev) >> SECTOR_SHIFT);
252bb7d1283SJohn Garry }
253bb7d1283SJohn Garry
254973dac8aSJohn Garry error = scsi_mq_setup_tags(shost);
255973dac8aSJohn Garry if (error)
256973dac8aSJohn Garry goto fail;
257973dac8aSJohn Garry
2588fe4ce58SBart Van Assche kref_init(&shost->tagset_refcnt);
2598fe4ce58SBart Van Assche init_completion(&shost->tagset_freed);
2608fe4ce58SBart Van Assche
2615c6fab9dSMika Westerberg /*
2625c6fab9dSMika Westerberg * Increase usage count temporarily here so that calling
2635c6fab9dSMika Westerberg * scsi_autopm_put_host() will trigger runtime idle if there is
2645c6fab9dSMika Westerberg * nothing else preventing suspending the device.
2655c6fab9dSMika Westerberg */
2665c6fab9dSMika Westerberg pm_runtime_get_noresume(&shost->shost_gendev);
267bc4f2401SAlan Stern pm_runtime_set_active(&shost->shost_gendev);
268bc4f2401SAlan Stern pm_runtime_enable(&shost->shost_gendev);
269bc4f2401SAlan Stern device_enable_async_suspend(&shost->shost_gendev);
270bc4f2401SAlan Stern
2710d5644b7SHeiner Kallweit error = device_add(&shost->shost_gendev);
2720d5644b7SHeiner Kallweit if (error)
273e9c787e6SChristoph Hellwig goto out_disable_runtime_pm;
2740d5644b7SHeiner Kallweit
275d3301874SMike Anderson scsi_host_set_state(shost, SHOST_RUNNING);
2761da177e4SLinus Torvalds get_device(shost->shost_gendev.parent);
2771da177e4SLinus Torvalds
2784cb077d9SRafael J. Wysocki device_enable_async_suspend(&shost->shost_dev);
2794cb077d9SRafael J. Wysocki
28011714026SMing Lei get_device(&shost->shost_gendev);
281ee959b00STony Jones error = device_add(&shost->shost_dev);
2821da177e4SLinus Torvalds if (error)
2831da177e4SLinus Torvalds goto out_del_gendev;
2841da177e4SLinus Torvalds
28577cca462SJames Smart if (shost->transportt->host_size) {
28677cca462SJames Smart shost->shost_data = kzalloc(shost->transportt->host_size,
28777cca462SJames Smart GFP_KERNEL);
28877cca462SJames Smart if (shost->shost_data == NULL) {
28977cca462SJames Smart error = -ENOMEM;
290ee959b00STony Jones goto out_del_dev;
29177cca462SJames Smart }
29277cca462SJames Smart }
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds if (shost->transportt->create_work_queue) {
295aab0de24SKay Sievers snprintf(shost->work_q_name, sizeof(shost->work_q_name),
296aab0de24SKay Sievers "scsi_wq_%d", shost->host_no);
29762921300SBob Liu shost->work_q = alloc_workqueue("%s",
29862921300SBob Liu WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND,
29962921300SBob Liu 1, shost->work_q_name);
30062921300SBob Liu
30177cca462SJames Smart if (!shost->work_q) {
30277cca462SJames Smart error = -EINVAL;
3033719f4ffSMing Lei goto out_del_dev;
3041da177e4SLinus Torvalds }
30577cca462SJames Smart }
3061da177e4SLinus Torvalds
3071da177e4SLinus Torvalds error = scsi_sysfs_add_host(shost);
3081da177e4SLinus Torvalds if (error)
3093719f4ffSMing Lei goto out_del_dev;
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds scsi_proc_host_add(shost);
3125c6fab9dSMika Westerberg scsi_autopm_put_host(shost);
3131da177e4SLinus Torvalds return error;
3141da177e4SLinus Torvalds
3153719f4ffSMing Lei /*
3162b36209cSBart Van Assche * Any host allocation in this function will be freed in
3172b36209cSBart Van Assche * scsi_host_dev_release().
3183719f4ffSMing Lei */
319ee959b00STony Jones out_del_dev:
320ee959b00STony Jones device_del(&shost->shost_dev);
3211da177e4SLinus Torvalds out_del_gendev:
32211714026SMing Lei /*
32311714026SMing Lei * Host state is SHOST_RUNNING so we have to explicitly release
32411714026SMing Lei * ->shost_dev.
32511714026SMing Lei */
32611714026SMing Lei put_device(&shost->shost_dev);
3271da177e4SLinus Torvalds device_del(&shost->shost_gendev);
328e9c787e6SChristoph Hellwig out_disable_runtime_pm:
3290d5644b7SHeiner Kallweit device_disable_async_suspend(&shost->shost_gendev);
3300d5644b7SHeiner Kallweit pm_runtime_disable(&shost->shost_gendev);
3310d5644b7SHeiner Kallweit pm_runtime_set_suspended(&shost->shost_gendev);
3320d5644b7SHeiner Kallweit pm_runtime_put_noidle(&shost->shost_gendev);
3338fe4ce58SBart Van Assche kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
334542bd137SJames Bottomley fail:
3351da177e4SLinus Torvalds return error;
3361da177e4SLinus Torvalds }
337d139b9bdSJames Bottomley EXPORT_SYMBOL(scsi_add_host_with_dma);
3381da177e4SLinus Torvalds
scsi_host_dev_release(struct device * dev)3391da177e4SLinus Torvalds static void scsi_host_dev_release(struct device *dev)
3401da177e4SLinus Torvalds {
3411da177e4SLinus Torvalds struct Scsi_Host *shost = dev_to_shost(dev);
3421da177e4SLinus Torvalds struct device *parent = dev->parent;
3431da177e4SLinus Torvalds
3442dde5c8dSXiang Chen /* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */
3453bd6f43fSBart Van Assche rcu_barrier();
3463bd6f43fSBart Van Assche
347e494f6a7SHannes Reinecke if (shost->tmf_work_q)
348e494f6a7SHannes Reinecke destroy_workqueue(shost->tmf_work_q);
349c5478defSChristoph Hellwig if (shost->ehandler)
350c5478defSChristoph Hellwig kthread_stop(shost->ehandler);
3511da177e4SLinus Torvalds if (shost->work_q)
3521da177e4SLinus Torvalds destroy_workqueue(shost->work_q);
3531da177e4SLinus Torvalds
354b49493f9SBart Van Assche if (shost->shost_state == SHOST_CREATED) {
355b49493f9SBart Van Assche /*
356*d4c34782SGuilherme G. Piccoli * Free the shost_dev device name and remove the proc host dir
357*d4c34782SGuilherme G. Piccoli * here if scsi_host_{alloc,put}() have been called but neither
358f4407e60SBart Van Assche * scsi_host_add() nor scsi_remove_host() has been called.
359b49493f9SBart Van Assche * This avoids that the memory allocated for the shost_dev
360*d4c34782SGuilherme G. Piccoli * name as well as the proc dir structure are leaked.
361b49493f9SBart Van Assche */
362*d4c34782SGuilherme G. Piccoli scsi_proc_hostdir_rm(shost->hostt);
363b49493f9SBart Van Assche kfree(dev_name(&shost->shost_dev));
364b49493f9SBart Van Assche }
365b49493f9SBart Van Assche
3661da177e4SLinus Torvalds kfree(shost->shost_data);
3671da177e4SLinus Torvalds
3683fd3a52cSkeliu ida_free(&host_index_ida, shost->host_no);
369126a4fe0SLee Duncan
3701e0d4e62SMing Lei if (shost->shost_state != SHOST_CREATED)
3711da177e4SLinus Torvalds put_device(parent);
3721da177e4SLinus Torvalds kfree(shost);
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds
375453cd0f3SAdrian Bunk static struct device_type scsi_host_type = {
376b0ed4336SHannes Reinecke .name = "scsi_host",
377b0ed4336SHannes Reinecke .release = scsi_host_dev_release,
378b0ed4336SHannes Reinecke };
379b0ed4336SHannes Reinecke
3801da177e4SLinus Torvalds /**
3811da177e4SLinus Torvalds * scsi_host_alloc - register a scsi host adapter instance.
3821da177e4SLinus Torvalds * @sht: pointer to scsi host template
3831da177e4SLinus Torvalds * @privsize: extra bytes to allocate for driver
3841da177e4SLinus Torvalds *
3851da177e4SLinus Torvalds * Note:
3861da177e4SLinus Torvalds * Allocate a new Scsi_Host and perform basic initialization.
3871da177e4SLinus Torvalds * The host is not published to the scsi midlayer until scsi_add_host
3881da177e4SLinus Torvalds * is called.
3891da177e4SLinus Torvalds *
3901da177e4SLinus Torvalds * Return value:
3911da177e4SLinus Torvalds * Pointer to a new Scsi_Host
3921da177e4SLinus Torvalds **/
scsi_host_alloc(const struct scsi_host_template * sht,int privsize)393e0d3f2c6SBart Van Assche struct Scsi_Host *scsi_host_alloc(const struct scsi_host_template *sht, int privsize)
3941da177e4SLinus Torvalds {
3951da177e4SLinus Torvalds struct Scsi_Host *shost;
3960a84486dSBart Van Assche int index;
3971da177e4SLinus Torvalds
398aaff5ebaSChristoph Hellwig shost = kzalloc(sizeof(struct Scsi_Host) + privsize, GFP_KERNEL);
3991da177e4SLinus Torvalds if (!shost)
4001da177e4SLinus Torvalds return NULL;
4011da177e4SLinus Torvalds
4024f777ed2SChristoph Hellwig shost->host_lock = &shost->default_lock;
4034f777ed2SChristoph Hellwig spin_lock_init(shost->host_lock);
404d3301874SMike Anderson shost->shost_state = SHOST_CREATED;
4051da177e4SLinus Torvalds INIT_LIST_HEAD(&shost->__devices);
4061da177e4SLinus Torvalds INIT_LIST_HEAD(&shost->__targets);
4075ae17501SEwan D. Milne INIT_LIST_HEAD(&shost->eh_abort_list);
4081da177e4SLinus Torvalds INIT_LIST_HEAD(&shost->eh_cmd_q);
4091da177e4SLinus Torvalds INIT_LIST_HEAD(&shost->starved_list);
4101da177e4SLinus Torvalds init_waitqueue_head(&shost->host_wait);
4110b950672SArjan van de Ven mutex_init(&shost->scan_mutex);
4121da177e4SLinus Torvalds
4133fd3a52cSkeliu index = ida_alloc(&host_index_ida, GFP_KERNEL);
41466a834d0SMing Lei if (index < 0) {
41566a834d0SMing Lei kfree(shost);
41666a834d0SMing Lei return NULL;
41766a834d0SMing Lei }
418126a4fe0SLee Duncan shost->host_no = index;
419126a4fe0SLee Duncan
4201da177e4SLinus Torvalds shost->dma_channel = 0xff;
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds /* These three are default values which can be overridden */
4231da177e4SLinus Torvalds shost->max_channel = 0;
4241da177e4SLinus Torvalds shost->max_id = 8;
4251da177e4SLinus Torvalds shost->max_lun = 8;
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds /* Give each shost a default transportt */
4281da177e4SLinus Torvalds shost->transportt = &blank_transport_template;
4291da177e4SLinus Torvalds
4301da177e4SLinus Torvalds /*
4311da177e4SLinus Torvalds * All drivers right now should be able to handle 12 byte
4321da177e4SLinus Torvalds * commands. Every so often there are requests for 16 byte
4331da177e4SLinus Torvalds * commands, but individual low-level drivers need to certify that
4341da177e4SLinus Torvalds * they actually do something sensible with such commands.
4351da177e4SLinus Torvalds */
4361da177e4SLinus Torvalds shost->max_cmd_len = 12;
4371da177e4SLinus Torvalds shost->hostt = sht;
4381da177e4SLinus Torvalds shost->this_id = sht->this_id;
4391da177e4SLinus Torvalds shost->can_queue = sht->can_queue;
4401da177e4SLinus Torvalds shost->sg_tablesize = sht->sg_tablesize;
44113f05c8dSMartin K. Petersen shost->sg_prot_tablesize = sht->sg_prot_tablesize;
4421da177e4SLinus Torvalds shost->cmd_per_lun = sht->cmd_per_lun;
44354b2b50cSMartin K. Petersen shost->no_write_same = sht->no_write_same;
444bdb01301SHannes Reinecke shost->host_tagset = sht->host_tagset;
445b125bb99SBart Van Assche shost->queuecommand_may_block = sht->queuecommand_may_block;
4461da177e4SLinus Torvalds
447ad469a57SHannes Reinecke if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
448bb3b621aSRen Mingxin shost->eh_deadline = -1;
449bb3b621aSRen Mingxin else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
450bb3b621aSRen Mingxin shost_printk(KERN_WARNING, shost,
451bb3b621aSRen Mingxin "eh_deadline %u too large, setting to %u\n",
452bb3b621aSRen Mingxin shost_eh_deadline, INT_MAX / HZ);
453bb3b621aSRen Mingxin shost->eh_deadline = INT_MAX;
454bb3b621aSRen Mingxin } else
455bb3b621aSRen Mingxin shost->eh_deadline = shost_eh_deadline * HZ;
456bb3b621aSRen Mingxin
4577a39ac3fSJames Bottomley if (sht->supported_mode == MODE_UNKNOWN)
4587a39ac3fSJames Bottomley /* means we didn't set it ... default to INITIATOR */
4597a39ac3fSJames Bottomley shost->active_mode = MODE_INITIATOR;
4607a39ac3fSJames Bottomley else
4617a39ac3fSJames Bottomley shost->active_mode = sht->supported_mode;
4627a39ac3fSJames Bottomley
4631da177e4SLinus Torvalds if (sht->max_host_blocked)
4641da177e4SLinus Torvalds shost->max_host_blocked = sht->max_host_blocked;
4651da177e4SLinus Torvalds else
4661da177e4SLinus Torvalds shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
4671da177e4SLinus Torvalds
4681da177e4SLinus Torvalds /*
4691da177e4SLinus Torvalds * If the driver imposes no hard sector transfer limit, start at
4701da177e4SLinus Torvalds * machine infinity initially.
4711da177e4SLinus Torvalds */
4721da177e4SLinus Torvalds if (sht->max_sectors)
4731da177e4SLinus Torvalds shost->max_sectors = sht->max_sectors;
4741da177e4SLinus Torvalds else
4751da177e4SLinus Torvalds shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
4761da177e4SLinus Torvalds
47750c2e910SChristoph Hellwig if (sht->max_segment_size)
47850c2e910SChristoph Hellwig shost->max_segment_size = sht->max_segment_size;
47950c2e910SChristoph Hellwig else
48050c2e910SChristoph Hellwig shost->max_segment_size = BLK_MAX_SEGMENT_SIZE;
48150c2e910SChristoph Hellwig
4821da177e4SLinus Torvalds /*
4831da177e4SLinus Torvalds * assume a 4GB boundary, if not set
4841da177e4SLinus Torvalds */
4851da177e4SLinus Torvalds if (sht->dma_boundary)
4861da177e4SLinus Torvalds shost->dma_boundary = sht->dma_boundary;
4871da177e4SLinus Torvalds else
4881da177e4SLinus Torvalds shost->dma_boundary = 0xffffffff;
4891da177e4SLinus Torvalds
4907ad388d8SChristoph Hellwig if (sht->virt_boundary_mask)
4917ad388d8SChristoph Hellwig shost->virt_boundary_mask = sht->virt_boundary_mask;
4927ad388d8SChristoph Hellwig
4931da177e4SLinus Torvalds device_initialize(&shost->shost_gendev);
49471610f55SKay Sievers dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
495b0ed4336SHannes Reinecke shost->shost_gendev.bus = &scsi_bus_type;
496b0ed4336SHannes Reinecke shost->shost_gendev.type = &scsi_host_type;
497a19a93e4SBart Van Assche scsi_enable_async_suspend(&shost->shost_gendev);
4981da177e4SLinus Torvalds
499ee959b00STony Jones device_initialize(&shost->shost_dev);
500ee959b00STony Jones shost->shost_dev.parent = &shost->shost_gendev;
501ee959b00STony Jones shost->shost_dev.class = &shost_class;
50271610f55SKay Sievers dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
5030a84486dSBart Van Assche shost->shost_dev.groups = sht->shost_groups;
5041da177e4SLinus Torvalds
505c5478defSChristoph Hellwig shost->ehandler = kthread_run(scsi_error_handler, shost,
506c5478defSChristoph Hellwig "scsi_eh_%d", shost->host_no);
507c5478defSChristoph Hellwig if (IS_ERR(shost->ehandler)) {
50891921e01SHannes Reinecke shost_printk(KERN_WARNING, shost,
50991921e01SHannes Reinecke "error handler thread failed to spawn, error = %ld\n",
51091921e01SHannes Reinecke PTR_ERR(shost->ehandler));
51193aa71adSTyrel Datwyler shost->ehandler = NULL;
51266a834d0SMing Lei goto fail;
513c5478defSChristoph Hellwig }
5141da177e4SLinus Torvalds
515e494f6a7SHannes Reinecke shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
51662921300SBob Liu WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS,
517e494f6a7SHannes Reinecke 1, shost->host_no);
518e494f6a7SHannes Reinecke if (!shost->tmf_work_q) {
519a222b1e2SHannes Reinecke shost_printk(KERN_WARNING, shost,
520a222b1e2SHannes Reinecke "failed to create tmf workq\n");
52166a834d0SMing Lei goto fail;
522e494f6a7SHannes Reinecke }
523ecca3f9bSBart Van Assche if (scsi_proc_hostdir_add(shost->hostt) < 0)
524ecca3f9bSBart Van Assche goto fail;
5251da177e4SLinus Torvalds return shost;
52666a834d0SMing Lei fail:
52766a834d0SMing Lei /*
52866a834d0SMing Lei * Host state is still SHOST_CREATED and that is enough to release
52966a834d0SMing Lei * ->shost_gendev. scsi_host_dev_release() will free
53066a834d0SMing Lei * dev_name(&shost->shost_dev).
53166a834d0SMing Lei */
53266a834d0SMing Lei put_device(&shost->shost_gendev);
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds return NULL;
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_host_alloc);
5371da177e4SLinus Torvalds
__scsi_host_match(struct device * dev,const void * data)5389f3b795aSMichał Mirosław static int __scsi_host_match(struct device *dev, const void *data)
5399c770108SDave Young {
5409c770108SDave Young struct Scsi_Host *p;
54162ec2092STony Battersby const unsigned int *hostnum = data;
5429c770108SDave Young
543ee959b00STony Jones p = class_to_shost(dev);
5449c770108SDave Young return p->host_no == *hostnum;
5459c770108SDave Young }
5469c770108SDave Young
5471da177e4SLinus Torvalds /**
5481da177e4SLinus Torvalds * scsi_host_lookup - get a reference to a Scsi_Host by host no
5491da177e4SLinus Torvalds * @hostnum: host number to locate
5501da177e4SLinus Torvalds *
5511da177e4SLinus Torvalds * Return value:
5521da177e4SLinus Torvalds * A pointer to located Scsi_Host or NULL.
5533ed78972SMike Christie *
5543ed78972SMike Christie * The caller must do a scsi_host_put() to drop the reference
5553ed78972SMike Christie * that scsi_host_get() took. The put_device() below dropped
5563ed78972SMike Christie * the reference from class_find_device().
5571da177e4SLinus Torvalds **/
scsi_host_lookup(unsigned int hostnum)55862ec2092STony Battersby struct Scsi_Host *scsi_host_lookup(unsigned int hostnum)
5591da177e4SLinus Torvalds {
560ee959b00STony Jones struct device *cdev;
561315cb0adSJames Smart struct Scsi_Host *shost = NULL;
5621da177e4SLinus Torvalds
563695794aeSGreg Kroah-Hartman cdev = class_find_device(&shost_class, NULL, &hostnum,
564695794aeSGreg Kroah-Hartman __scsi_host_match);
5653ed78972SMike Christie if (cdev) {
5669c770108SDave Young shost = scsi_host_get(class_to_shost(cdev));
5673ed78972SMike Christie put_device(cdev);
5683ed78972SMike Christie }
5691da177e4SLinus Torvalds return shost;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_host_lookup);
5721da177e4SLinus Torvalds
5731da177e4SLinus Torvalds /**
5741da177e4SLinus Torvalds * scsi_host_get - inc a Scsi_Host ref count
5751da177e4SLinus Torvalds * @shost: Pointer to Scsi_Host to inc.
5761da177e4SLinus Torvalds **/
scsi_host_get(struct Scsi_Host * shost)5771da177e4SLinus Torvalds struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
5781da177e4SLinus Torvalds {
579d3301874SMike Anderson if ((shost->shost_state == SHOST_DEL) ||
5801da177e4SLinus Torvalds !get_device(&shost->shost_gendev))
5811da177e4SLinus Torvalds return NULL;
5821da177e4SLinus Torvalds return shost;
5831da177e4SLinus Torvalds }
5841da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_host_get);
5851da177e4SLinus Torvalds
scsi_host_check_in_flight(struct request * rq,void * data)5862dd6532eSJohn Garry static bool scsi_host_check_in_flight(struct request *rq, void *data)
5876eb045e0SMing Lei {
5886eb045e0SMing Lei int *count = data;
5896eb045e0SMing Lei struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
5906eb045e0SMing Lei
5916eb045e0SMing Lei if (test_bit(SCMD_STATE_INFLIGHT, &cmd->state))
5926eb045e0SMing Lei (*count)++;
5936eb045e0SMing Lei
5946eb045e0SMing Lei return true;
5956eb045e0SMing Lei }
5966eb045e0SMing Lei
5971da177e4SLinus Torvalds /**
598c84b023aSMing Lei * scsi_host_busy - Return the host busy counter
599c84b023aSMing Lei * @shost: Pointer to Scsi_Host to inc.
600c84b023aSMing Lei **/
scsi_host_busy(struct Scsi_Host * shost)601c84b023aSMing Lei int scsi_host_busy(struct Scsi_Host *shost)
602c84b023aSMing Lei {
6036eb045e0SMing Lei int cnt = 0;
6046eb045e0SMing Lei
6056eb045e0SMing Lei blk_mq_tagset_busy_iter(&shost->tag_set,
6066eb045e0SMing Lei scsi_host_check_in_flight, &cnt);
6076eb045e0SMing Lei return cnt;
608c84b023aSMing Lei }
609c84b023aSMing Lei EXPORT_SYMBOL(scsi_host_busy);
610c84b023aSMing Lei
611c84b023aSMing Lei /**
6121da177e4SLinus Torvalds * scsi_host_put - dec a Scsi_Host ref count
6131da177e4SLinus Torvalds * @shost: Pointer to Scsi_Host to dec.
6141da177e4SLinus Torvalds **/
scsi_host_put(struct Scsi_Host * shost)6151da177e4SLinus Torvalds void scsi_host_put(struct Scsi_Host *shost)
6161da177e4SLinus Torvalds {
6171da177e4SLinus Torvalds put_device(&shost->shost_gendev);
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_host_put);
6201da177e4SLinus Torvalds
scsi_init_hosts(void)6211da177e4SLinus Torvalds int scsi_init_hosts(void)
6221da177e4SLinus Torvalds {
6231da177e4SLinus Torvalds return class_register(&shost_class);
6241da177e4SLinus Torvalds }
6251da177e4SLinus Torvalds
scsi_exit_hosts(void)6261da177e4SLinus Torvalds void scsi_exit_hosts(void)
6271da177e4SLinus Torvalds {
6281da177e4SLinus Torvalds class_unregister(&shost_class);
629126a4fe0SLee Duncan ida_destroy(&host_index_ida);
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds
scsi_is_host_device(const struct device * dev)6321da177e4SLinus Torvalds int scsi_is_host_device(const struct device *dev)
6331da177e4SLinus Torvalds {
634b0ed4336SHannes Reinecke return dev->type == &scsi_host_type;
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds EXPORT_SYMBOL(scsi_is_host_device);
6371da177e4SLinus Torvalds
6381da177e4SLinus Torvalds /**
6391da177e4SLinus Torvalds * scsi_queue_work - Queue work to the Scsi_Host workqueue.
6401da177e4SLinus Torvalds * @shost: Pointer to Scsi_Host.
6411da177e4SLinus Torvalds * @work: Work to queue for execution.
6421da177e4SLinus Torvalds *
6431da177e4SLinus Torvalds * Return value:
644dd7e2f22SMichael Reed * 1 - work queued for execution
645dd7e2f22SMichael Reed * 0 - work is already queued
646dd7e2f22SMichael Reed * -EINVAL - work queue doesn't exist
6471da177e4SLinus Torvalds **/
scsi_queue_work(struct Scsi_Host * shost,struct work_struct * work)6481da177e4SLinus Torvalds int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
6491da177e4SLinus Torvalds {
6501da177e4SLinus Torvalds if (unlikely(!shost->work_q)) {
65191921e01SHannes Reinecke shost_printk(KERN_ERR, shost,
6521da177e4SLinus Torvalds "ERROR: Scsi host '%s' attempted to queue scsi-work, "
6531da177e4SLinus Torvalds "when no workqueue created.\n", shost->hostt->name);
6541da177e4SLinus Torvalds dump_stack();
6551da177e4SLinus Torvalds
6561da177e4SLinus Torvalds return -EINVAL;
6571da177e4SLinus Torvalds }
6581da177e4SLinus Torvalds
6591da177e4SLinus Torvalds return queue_work(shost->work_q, work);
6601da177e4SLinus Torvalds }
6611da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(scsi_queue_work);
6621da177e4SLinus Torvalds
6631da177e4SLinus Torvalds /**
6641da177e4SLinus Torvalds * scsi_flush_work - Flush a Scsi_Host's workqueue.
6651da177e4SLinus Torvalds * @shost: Pointer to Scsi_Host.
6661da177e4SLinus Torvalds **/
scsi_flush_work(struct Scsi_Host * shost)6671da177e4SLinus Torvalds void scsi_flush_work(struct Scsi_Host *shost)
6681da177e4SLinus Torvalds {
6691da177e4SLinus Torvalds if (!shost->work_q) {
67091921e01SHannes Reinecke shost_printk(KERN_ERR, shost,
6711da177e4SLinus Torvalds "ERROR: Scsi host '%s' attempted to flush scsi-work, "
6721da177e4SLinus Torvalds "when no workqueue created.\n", shost->hostt->name);
6731da177e4SLinus Torvalds dump_stack();
6741da177e4SLinus Torvalds return;
6751da177e4SLinus Torvalds }
6761da177e4SLinus Torvalds
6771da177e4SLinus Torvalds flush_workqueue(shost->work_q);
6781da177e4SLinus Torvalds }
6791da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(scsi_flush_work);
680466552b9SHannes Reinecke
complete_all_cmds_iter(struct request * rq,void * data)6812dd6532eSJohn Garry static bool complete_all_cmds_iter(struct request *rq, void *data)
682466552b9SHannes Reinecke {
683466552b9SHannes Reinecke struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
68462af0ee9SBart Van Assche enum scsi_host_status status = *(enum scsi_host_status *)data;
685466552b9SHannes Reinecke
686466552b9SHannes Reinecke scsi_dma_unmap(scmd);
68762af0ee9SBart Van Assche scmd->result = 0;
68862af0ee9SBart Van Assche set_host_byte(scmd, status);
68911b68e36SBart Van Assche scsi_done(scmd);
690466552b9SHannes Reinecke return true;
691466552b9SHannes Reinecke }
692466552b9SHannes Reinecke
693466552b9SHannes Reinecke /**
694466552b9SHannes Reinecke * scsi_host_complete_all_commands - Terminate all running commands
695466552b9SHannes Reinecke * @shost: Scsi Host on which commands should be terminated
696466552b9SHannes Reinecke * @status: Status to be set for the terminated commands
697466552b9SHannes Reinecke *
698466552b9SHannes Reinecke * There is no protection against modification of the number
699466552b9SHannes Reinecke * of outstanding commands. It is the responsibility of the
700466552b9SHannes Reinecke * caller to ensure that concurrent I/O submission and/or
701466552b9SHannes Reinecke * completion is stopped when calling this function.
702466552b9SHannes Reinecke */
scsi_host_complete_all_commands(struct Scsi_Host * shost,enum scsi_host_status status)70362af0ee9SBart Van Assche void scsi_host_complete_all_commands(struct Scsi_Host *shost,
70462af0ee9SBart Van Assche enum scsi_host_status status)
705466552b9SHannes Reinecke {
706466552b9SHannes Reinecke blk_mq_tagset_busy_iter(&shost->tag_set, complete_all_cmds_iter,
707466552b9SHannes Reinecke &status);
708466552b9SHannes Reinecke }
709466552b9SHannes Reinecke EXPORT_SYMBOL_GPL(scsi_host_complete_all_commands);
710dcece99eSHannes Reinecke
711dcece99eSHannes Reinecke struct scsi_host_busy_iter_data {
7122dd6532eSJohn Garry bool (*fn)(struct scsi_cmnd *, void *);
713dcece99eSHannes Reinecke void *priv;
714dcece99eSHannes Reinecke };
715dcece99eSHannes Reinecke
__scsi_host_busy_iter_fn(struct request * req,void * priv)7162dd6532eSJohn Garry static bool __scsi_host_busy_iter_fn(struct request *req, void *priv)
717dcece99eSHannes Reinecke {
718dcece99eSHannes Reinecke struct scsi_host_busy_iter_data *iter_data = priv;
719dcece99eSHannes Reinecke struct scsi_cmnd *sc = blk_mq_rq_to_pdu(req);
720dcece99eSHannes Reinecke
7212dd6532eSJohn Garry return iter_data->fn(sc, iter_data->priv);
722dcece99eSHannes Reinecke }
723dcece99eSHannes Reinecke
724dcece99eSHannes Reinecke /**
725dcece99eSHannes Reinecke * scsi_host_busy_iter - Iterate over all busy commands
726dcece99eSHannes Reinecke * @shost: Pointer to Scsi_Host.
727dcece99eSHannes Reinecke * @fn: Function to call on each busy command
728dcece99eSHannes Reinecke * @priv: Data pointer passed to @fn
729dcece99eSHannes Reinecke *
730dcece99eSHannes Reinecke * If locking against concurrent command completions is required
731dcece99eSHannes Reinecke * ithas to be provided by the caller
732dcece99eSHannes Reinecke **/
scsi_host_busy_iter(struct Scsi_Host * shost,bool (* fn)(struct scsi_cmnd *,void *),void * priv)733dcece99eSHannes Reinecke void scsi_host_busy_iter(struct Scsi_Host *shost,
7342dd6532eSJohn Garry bool (*fn)(struct scsi_cmnd *, void *),
735dcece99eSHannes Reinecke void *priv)
736dcece99eSHannes Reinecke {
737dcece99eSHannes Reinecke struct scsi_host_busy_iter_data iter_data = {
738dcece99eSHannes Reinecke .fn = fn,
739dcece99eSHannes Reinecke .priv = priv,
740dcece99eSHannes Reinecke };
741dcece99eSHannes Reinecke
742dcece99eSHannes Reinecke blk_mq_tagset_busy_iter(&shost->tag_set, __scsi_host_busy_iter_fn,
743dcece99eSHannes Reinecke &iter_data);
744dcece99eSHannes Reinecke }
745dcece99eSHannes Reinecke EXPORT_SYMBOL_GPL(scsi_host_busy_iter);
746