18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  hosts.c Copyright (C) 1992 Drew Eckhardt
48c2ecf20Sopenharmony_ci *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
58c2ecf20Sopenharmony_ci *          Copyright (C) 2002-2003 Christoph Hellwig
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  mid to lowlevel SCSI driver interface
88c2ecf20Sopenharmony_ci *      Initial versions: Drew Eckhardt
98c2ecf20Sopenharmony_ci *      Subsequent revisions: Eric Youngdale
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci *  <drew@colorado.edu>
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
148c2ecf20Sopenharmony_ci *  Added QLOGIC QLA1280 SCSI controller kernel host support.
158c2ecf20Sopenharmony_ci *     August 4, 1999 Fred Lewis, Intel DuPont
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *  Updated to reflect the new initialization scheme for the higher
188c2ecf20Sopenharmony_ci *  level of scsi drivers (sd/sr/st)
198c2ecf20Sopenharmony_ci *  September 17, 2000 Torben Mathiasen <tmm@image.dk>
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci *  Restructured scsi_host lists and associated functions.
228c2ecf20Sopenharmony_ci *  September 04, 2002 Mike Anderson (andmike@us.ibm.com)
238c2ecf20Sopenharmony_ci */
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include <linux/module.h>
268c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
278c2ecf20Sopenharmony_ci#include <linux/kernel.h>
288c2ecf20Sopenharmony_ci#include <linux/slab.h>
298c2ecf20Sopenharmony_ci#include <linux/kthread.h>
308c2ecf20Sopenharmony_ci#include <linux/string.h>
318c2ecf20Sopenharmony_ci#include <linux/mm.h>
328c2ecf20Sopenharmony_ci#include <linux/init.h>
338c2ecf20Sopenharmony_ci#include <linux/completion.h>
348c2ecf20Sopenharmony_ci#include <linux/transport_class.h>
358c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
368c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
378c2ecf20Sopenharmony_ci#include <linux/idr.h>
388c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
398c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h>
408c2ecf20Sopenharmony_ci#include <scsi/scsi_transport.h>
418c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#include "scsi_priv.h"
448c2ecf20Sopenharmony_ci#include "scsi_logging.h"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int shost_eh_deadline = -1;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cimodule_param_named(eh_deadline, shost_eh_deadline, int, S_IRUGO|S_IWUSR);
508c2ecf20Sopenharmony_ciMODULE_PARM_DESC(eh_deadline,
518c2ecf20Sopenharmony_ci		 "SCSI EH timeout in seconds (should be between 0 and 2^31-1)");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic DEFINE_IDA(host_index_ida);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void scsi_host_cls_release(struct device *dev)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	put_device(&class_to_shost(dev)->shost_gendev);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic struct class shost_class = {
628c2ecf20Sopenharmony_ci	.name		= "scsi_host",
638c2ecf20Sopenharmony_ci	.dev_release	= scsi_host_cls_release,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci/**
678c2ecf20Sopenharmony_ci *	scsi_host_set_state - Take the given host through the host state model.
688c2ecf20Sopenharmony_ci *	@shost:	scsi host to change the state of.
698c2ecf20Sopenharmony_ci *	@state:	state to change to.
708c2ecf20Sopenharmony_ci *
718c2ecf20Sopenharmony_ci *	Returns zero if unsuccessful or an error if the requested
728c2ecf20Sopenharmony_ci *	transition is illegal.
738c2ecf20Sopenharmony_ci **/
748c2ecf20Sopenharmony_ciint scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	enum scsi_host_state oldstate = shost->shost_state;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (state == oldstate)
798c2ecf20Sopenharmony_ci		return 0;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	switch (state) {
828c2ecf20Sopenharmony_ci	case SHOST_CREATED:
838c2ecf20Sopenharmony_ci		/* There are no legal states that come back to
848c2ecf20Sopenharmony_ci		 * created.  This is the manually initialised start
858c2ecf20Sopenharmony_ci		 * state */
868c2ecf20Sopenharmony_ci		goto illegal;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	case SHOST_RUNNING:
898c2ecf20Sopenharmony_ci		switch (oldstate) {
908c2ecf20Sopenharmony_ci		case SHOST_CREATED:
918c2ecf20Sopenharmony_ci		case SHOST_RECOVERY:
928c2ecf20Sopenharmony_ci			break;
938c2ecf20Sopenharmony_ci		default:
948c2ecf20Sopenharmony_ci			goto illegal;
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci		break;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	case SHOST_RECOVERY:
998c2ecf20Sopenharmony_ci		switch (oldstate) {
1008c2ecf20Sopenharmony_ci		case SHOST_RUNNING:
1018c2ecf20Sopenharmony_ci			break;
1028c2ecf20Sopenharmony_ci		default:
1038c2ecf20Sopenharmony_ci			goto illegal;
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci		break;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	case SHOST_CANCEL:
1088c2ecf20Sopenharmony_ci		switch (oldstate) {
1098c2ecf20Sopenharmony_ci		case SHOST_CREATED:
1108c2ecf20Sopenharmony_ci		case SHOST_RUNNING:
1118c2ecf20Sopenharmony_ci		case SHOST_CANCEL_RECOVERY:
1128c2ecf20Sopenharmony_ci			break;
1138c2ecf20Sopenharmony_ci		default:
1148c2ecf20Sopenharmony_ci			goto illegal;
1158c2ecf20Sopenharmony_ci		}
1168c2ecf20Sopenharmony_ci		break;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	case SHOST_DEL:
1198c2ecf20Sopenharmony_ci		switch (oldstate) {
1208c2ecf20Sopenharmony_ci		case SHOST_CANCEL:
1218c2ecf20Sopenharmony_ci		case SHOST_DEL_RECOVERY:
1228c2ecf20Sopenharmony_ci			break;
1238c2ecf20Sopenharmony_ci		default:
1248c2ecf20Sopenharmony_ci			goto illegal;
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci		break;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	case SHOST_CANCEL_RECOVERY:
1298c2ecf20Sopenharmony_ci		switch (oldstate) {
1308c2ecf20Sopenharmony_ci		case SHOST_CANCEL:
1318c2ecf20Sopenharmony_ci		case SHOST_RECOVERY:
1328c2ecf20Sopenharmony_ci			break;
1338c2ecf20Sopenharmony_ci		default:
1348c2ecf20Sopenharmony_ci			goto illegal;
1358c2ecf20Sopenharmony_ci		}
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	case SHOST_DEL_RECOVERY:
1398c2ecf20Sopenharmony_ci		switch (oldstate) {
1408c2ecf20Sopenharmony_ci		case SHOST_CANCEL_RECOVERY:
1418c2ecf20Sopenharmony_ci			break;
1428c2ecf20Sopenharmony_ci		default:
1438c2ecf20Sopenharmony_ci			goto illegal;
1448c2ecf20Sopenharmony_ci		}
1458c2ecf20Sopenharmony_ci		break;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	shost->shost_state = state;
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci illegal:
1518c2ecf20Sopenharmony_ci	SCSI_LOG_ERROR_RECOVERY(1,
1528c2ecf20Sopenharmony_ci				shost_printk(KERN_ERR, shost,
1538c2ecf20Sopenharmony_ci					     "Illegal host state transition"
1548c2ecf20Sopenharmony_ci					     "%s->%s\n",
1558c2ecf20Sopenharmony_ci					     scsi_host_state_name(oldstate),
1568c2ecf20Sopenharmony_ci					     scsi_host_state_name(state)));
1578c2ecf20Sopenharmony_ci	return -EINVAL;
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci/**
1618c2ecf20Sopenharmony_ci * scsi_remove_host - remove a scsi host
1628c2ecf20Sopenharmony_ci * @shost:	a pointer to a scsi host to remove
1638c2ecf20Sopenharmony_ci **/
1648c2ecf20Sopenharmony_civoid scsi_remove_host(struct Scsi_Host *shost)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	unsigned long flags;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	mutex_lock(&shost->scan_mutex);
1698c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
1708c2ecf20Sopenharmony_ci	if (scsi_host_set_state(shost, SHOST_CANCEL))
1718c2ecf20Sopenharmony_ci		if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) {
1728c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(shost->host_lock, flags);
1738c2ecf20Sopenharmony_ci			mutex_unlock(&shost->scan_mutex);
1748c2ecf20Sopenharmony_ci			return;
1758c2ecf20Sopenharmony_ci		}
1768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	scsi_autopm_get_host(shost);
1798c2ecf20Sopenharmony_ci	flush_workqueue(shost->tmf_work_q);
1808c2ecf20Sopenharmony_ci	scsi_forget_host(shost);
1818c2ecf20Sopenharmony_ci	mutex_unlock(&shost->scan_mutex);
1828c2ecf20Sopenharmony_ci	scsi_proc_host_rm(shost);
1838c2ecf20Sopenharmony_ci	scsi_proc_hostdir_rm(shost->hostt);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	spin_lock_irqsave(shost->host_lock, flags);
1868c2ecf20Sopenharmony_ci	if (scsi_host_set_state(shost, SHOST_DEL))
1878c2ecf20Sopenharmony_ci		BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY));
1888c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(shost->host_lock, flags);
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	transport_unregister_device(&shost->shost_gendev);
1918c2ecf20Sopenharmony_ci	device_unregister(&shost->shost_dev);
1928c2ecf20Sopenharmony_ci	device_del(&shost->shost_gendev);
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_remove_host);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/**
1978c2ecf20Sopenharmony_ci * scsi_add_host_with_dma - add a scsi host with dma device
1988c2ecf20Sopenharmony_ci * @shost:	scsi host pointer to add
1998c2ecf20Sopenharmony_ci * @dev:	a struct device of type scsi class
2008c2ecf20Sopenharmony_ci * @dma_dev:	dma device for the host
2018c2ecf20Sopenharmony_ci *
2028c2ecf20Sopenharmony_ci * Note: You rarely need to worry about this unless you're in a
2038c2ecf20Sopenharmony_ci * virtualised host environments, so use the simpler scsi_add_host()
2048c2ecf20Sopenharmony_ci * function instead.
2058c2ecf20Sopenharmony_ci *
2068c2ecf20Sopenharmony_ci * Return value:
2078c2ecf20Sopenharmony_ci * 	0 on success / != 0 for error
2088c2ecf20Sopenharmony_ci **/
2098c2ecf20Sopenharmony_ciint scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
2108c2ecf20Sopenharmony_ci			   struct device *dma_dev)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	struct scsi_host_template *sht = shost->hostt;
2138c2ecf20Sopenharmony_ci	int error = -EINVAL;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	shost_printk(KERN_INFO, shost, "%s\n",
2168c2ecf20Sopenharmony_ci			sht->info ? sht->info(shost) : sht->name);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (!shost->can_queue) {
2198c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, shost,
2208c2ecf20Sopenharmony_ci			     "can_queue = 0 no longer supported\n");
2218c2ecf20Sopenharmony_ci		goto fail;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/* Use min_t(int, ...) in case shost->can_queue exceeds SHRT_MAX */
2258c2ecf20Sopenharmony_ci	shost->cmd_per_lun = min_t(int, shost->cmd_per_lun,
2268c2ecf20Sopenharmony_ci				   shost->can_queue);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	error = scsi_init_sense_cache(shost);
2298c2ecf20Sopenharmony_ci	if (error)
2308c2ecf20Sopenharmony_ci		goto fail;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	error = scsi_mq_setup_tags(shost);
2338c2ecf20Sopenharmony_ci	if (error)
2348c2ecf20Sopenharmony_ci		goto fail;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (!shost->shost_gendev.parent)
2378c2ecf20Sopenharmony_ci		shost->shost_gendev.parent = dev ? dev : &platform_bus;
2388c2ecf20Sopenharmony_ci	if (!dma_dev)
2398c2ecf20Sopenharmony_ci		dma_dev = shost->shost_gendev.parent;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	shost->dma_dev = dma_dev;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/*
2448c2ecf20Sopenharmony_ci	 * Increase usage count temporarily here so that calling
2458c2ecf20Sopenharmony_ci	 * scsi_autopm_put_host() will trigger runtime idle if there is
2468c2ecf20Sopenharmony_ci	 * nothing else preventing suspending the device.
2478c2ecf20Sopenharmony_ci	 */
2488c2ecf20Sopenharmony_ci	pm_runtime_get_noresume(&shost->shost_gendev);
2498c2ecf20Sopenharmony_ci	pm_runtime_set_active(&shost->shost_gendev);
2508c2ecf20Sopenharmony_ci	pm_runtime_enable(&shost->shost_gendev);
2518c2ecf20Sopenharmony_ci	device_enable_async_suspend(&shost->shost_gendev);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	error = device_add(&shost->shost_gendev);
2548c2ecf20Sopenharmony_ci	if (error)
2558c2ecf20Sopenharmony_ci		goto out_disable_runtime_pm;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	scsi_host_set_state(shost, SHOST_RUNNING);
2588c2ecf20Sopenharmony_ci	get_device(shost->shost_gendev.parent);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	device_enable_async_suspend(&shost->shost_dev);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	get_device(&shost->shost_gendev);
2638c2ecf20Sopenharmony_ci	error = device_add(&shost->shost_dev);
2648c2ecf20Sopenharmony_ci	if (error)
2658c2ecf20Sopenharmony_ci		goto out_del_gendev;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (shost->transportt->host_size) {
2688c2ecf20Sopenharmony_ci		shost->shost_data = kzalloc(shost->transportt->host_size,
2698c2ecf20Sopenharmony_ci					 GFP_KERNEL);
2708c2ecf20Sopenharmony_ci		if (shost->shost_data == NULL) {
2718c2ecf20Sopenharmony_ci			error = -ENOMEM;
2728c2ecf20Sopenharmony_ci			goto out_del_dev;
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if (shost->transportt->create_work_queue) {
2778c2ecf20Sopenharmony_ci		snprintf(shost->work_q_name, sizeof(shost->work_q_name),
2788c2ecf20Sopenharmony_ci			 "scsi_wq_%d", shost->host_no);
2798c2ecf20Sopenharmony_ci		shost->work_q = alloc_workqueue("%s",
2808c2ecf20Sopenharmony_ci			WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND,
2818c2ecf20Sopenharmony_ci			1, shost->work_q_name);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		if (!shost->work_q) {
2848c2ecf20Sopenharmony_ci			error = -EINVAL;
2858c2ecf20Sopenharmony_ci			goto out_del_dev;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	error = scsi_sysfs_add_host(shost);
2908c2ecf20Sopenharmony_ci	if (error)
2918c2ecf20Sopenharmony_ci		goto out_del_dev;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	scsi_proc_host_add(shost);
2948c2ecf20Sopenharmony_ci	scsi_autopm_put_host(shost);
2958c2ecf20Sopenharmony_ci	return error;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	/*
2988c2ecf20Sopenharmony_ci	 * Any host allocation in this function will be freed in
2998c2ecf20Sopenharmony_ci	 * scsi_host_dev_release().
3008c2ecf20Sopenharmony_ci	 */
3018c2ecf20Sopenharmony_ci out_del_dev:
3028c2ecf20Sopenharmony_ci	device_del(&shost->shost_dev);
3038c2ecf20Sopenharmony_ci out_del_gendev:
3048c2ecf20Sopenharmony_ci	/*
3058c2ecf20Sopenharmony_ci	 * Host state is SHOST_RUNNING so we have to explicitly release
3068c2ecf20Sopenharmony_ci	 * ->shost_dev.
3078c2ecf20Sopenharmony_ci	 */
3088c2ecf20Sopenharmony_ci	put_device(&shost->shost_dev);
3098c2ecf20Sopenharmony_ci	device_del(&shost->shost_gendev);
3108c2ecf20Sopenharmony_ci out_disable_runtime_pm:
3118c2ecf20Sopenharmony_ci	device_disable_async_suspend(&shost->shost_gendev);
3128c2ecf20Sopenharmony_ci	pm_runtime_disable(&shost->shost_gendev);
3138c2ecf20Sopenharmony_ci	pm_runtime_set_suspended(&shost->shost_gendev);
3148c2ecf20Sopenharmony_ci	pm_runtime_put_noidle(&shost->shost_gendev);
3158c2ecf20Sopenharmony_ci fail:
3168c2ecf20Sopenharmony_ci	return error;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_add_host_with_dma);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void scsi_host_dev_release(struct device *dev)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(dev);
3238c2ecf20Sopenharmony_ci	struct device *parent = dev->parent;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	/* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */
3268c2ecf20Sopenharmony_ci	rcu_barrier();
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (shost->tmf_work_q)
3298c2ecf20Sopenharmony_ci		destroy_workqueue(shost->tmf_work_q);
3308c2ecf20Sopenharmony_ci	if (shost->ehandler)
3318c2ecf20Sopenharmony_ci		kthread_stop(shost->ehandler);
3328c2ecf20Sopenharmony_ci	if (shost->work_q)
3338c2ecf20Sopenharmony_ci		destroy_workqueue(shost->work_q);
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (shost->shost_state == SHOST_CREATED) {
3368c2ecf20Sopenharmony_ci		/*
3378c2ecf20Sopenharmony_ci		 * Free the shost_dev device name and remove the proc host dir
3388c2ecf20Sopenharmony_ci		 * here if scsi_host_{alloc,put}() have been called but neither
3398c2ecf20Sopenharmony_ci		 * scsi_host_add() nor scsi_host_remove() has been called.
3408c2ecf20Sopenharmony_ci		 * This avoids that the memory allocated for the shost_dev
3418c2ecf20Sopenharmony_ci		 * name as well as the proc dir structure are leaked.
3428c2ecf20Sopenharmony_ci		 */
3438c2ecf20Sopenharmony_ci		scsi_proc_hostdir_rm(shost->hostt);
3448c2ecf20Sopenharmony_ci		kfree(dev_name(&shost->shost_dev));
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (shost->tag_set.tags)
3488c2ecf20Sopenharmony_ci		scsi_mq_destroy_tags(shost);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	kfree(shost->shost_data);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	ida_simple_remove(&host_index_ida, shost->host_no);
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	if (shost->shost_state != SHOST_CREATED)
3558c2ecf20Sopenharmony_ci		put_device(parent);
3568c2ecf20Sopenharmony_ci	kfree(shost);
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_cistatic struct device_type scsi_host_type = {
3608c2ecf20Sopenharmony_ci	.name =		"scsi_host",
3618c2ecf20Sopenharmony_ci	.release =	scsi_host_dev_release,
3628c2ecf20Sopenharmony_ci};
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci/**
3658c2ecf20Sopenharmony_ci * scsi_host_alloc - register a scsi host adapter instance.
3668c2ecf20Sopenharmony_ci * @sht:	pointer to scsi host template
3678c2ecf20Sopenharmony_ci * @privsize:	extra bytes to allocate for driver
3688c2ecf20Sopenharmony_ci *
3698c2ecf20Sopenharmony_ci * Note:
3708c2ecf20Sopenharmony_ci * 	Allocate a new Scsi_Host and perform basic initialization.
3718c2ecf20Sopenharmony_ci * 	The host is not published to the scsi midlayer until scsi_add_host
3728c2ecf20Sopenharmony_ci * 	is called.
3738c2ecf20Sopenharmony_ci *
3748c2ecf20Sopenharmony_ci * Return value:
3758c2ecf20Sopenharmony_ci * 	Pointer to a new Scsi_Host
3768c2ecf20Sopenharmony_ci **/
3778c2ecf20Sopenharmony_cistruct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
3788c2ecf20Sopenharmony_ci{
3798c2ecf20Sopenharmony_ci	struct Scsi_Host *shost;
3808c2ecf20Sopenharmony_ci	gfp_t gfp_mask = GFP_KERNEL;
3818c2ecf20Sopenharmony_ci	int index;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (sht->unchecked_isa_dma && privsize)
3848c2ecf20Sopenharmony_ci		gfp_mask |= __GFP_DMA;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
3878c2ecf20Sopenharmony_ci	if (!shost)
3888c2ecf20Sopenharmony_ci		return NULL;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	shost->host_lock = &shost->default_lock;
3918c2ecf20Sopenharmony_ci	spin_lock_init(shost->host_lock);
3928c2ecf20Sopenharmony_ci	shost->shost_state = SHOST_CREATED;
3938c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&shost->__devices);
3948c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&shost->__targets);
3958c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&shost->eh_cmd_q);
3968c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&shost->starved_list);
3978c2ecf20Sopenharmony_ci	init_waitqueue_head(&shost->host_wait);
3988c2ecf20Sopenharmony_ci	mutex_init(&shost->scan_mutex);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
4018c2ecf20Sopenharmony_ci	if (index < 0) {
4028c2ecf20Sopenharmony_ci		kfree(shost);
4038c2ecf20Sopenharmony_ci		return NULL;
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci	shost->host_no = index;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	shost->dma_channel = 0xff;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* These three are default values which can be overridden */
4108c2ecf20Sopenharmony_ci	shost->max_channel = 0;
4118c2ecf20Sopenharmony_ci	shost->max_id = 8;
4128c2ecf20Sopenharmony_ci	shost->max_lun = 8;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Give each shost a default transportt */
4158c2ecf20Sopenharmony_ci	shost->transportt = &blank_transport_template;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/*
4188c2ecf20Sopenharmony_ci	 * All drivers right now should be able to handle 12 byte
4198c2ecf20Sopenharmony_ci	 * commands.  Every so often there are requests for 16 byte
4208c2ecf20Sopenharmony_ci	 * commands, but individual low-level drivers need to certify that
4218c2ecf20Sopenharmony_ci	 * they actually do something sensible with such commands.
4228c2ecf20Sopenharmony_ci	 */
4238c2ecf20Sopenharmony_ci	shost->max_cmd_len = 12;
4248c2ecf20Sopenharmony_ci	shost->hostt = sht;
4258c2ecf20Sopenharmony_ci	shost->this_id = sht->this_id;
4268c2ecf20Sopenharmony_ci	shost->can_queue = sht->can_queue;
4278c2ecf20Sopenharmony_ci	shost->sg_tablesize = sht->sg_tablesize;
4288c2ecf20Sopenharmony_ci	shost->sg_prot_tablesize = sht->sg_prot_tablesize;
4298c2ecf20Sopenharmony_ci	shost->cmd_per_lun = sht->cmd_per_lun;
4308c2ecf20Sopenharmony_ci	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
4318c2ecf20Sopenharmony_ci	shost->no_write_same = sht->no_write_same;
4328c2ecf20Sopenharmony_ci	shost->host_tagset = sht->host_tagset;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
4358c2ecf20Sopenharmony_ci		shost->eh_deadline = -1;
4368c2ecf20Sopenharmony_ci	else if ((ulong) shost_eh_deadline * HZ > INT_MAX) {
4378c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
4388c2ecf20Sopenharmony_ci			     "eh_deadline %u too large, setting to %u\n",
4398c2ecf20Sopenharmony_ci			     shost_eh_deadline, INT_MAX / HZ);
4408c2ecf20Sopenharmony_ci		shost->eh_deadline = INT_MAX;
4418c2ecf20Sopenharmony_ci	} else
4428c2ecf20Sopenharmony_ci		shost->eh_deadline = shost_eh_deadline * HZ;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	if (sht->supported_mode == MODE_UNKNOWN)
4458c2ecf20Sopenharmony_ci		/* means we didn't set it ... default to INITIATOR */
4468c2ecf20Sopenharmony_ci		shost->active_mode = MODE_INITIATOR;
4478c2ecf20Sopenharmony_ci	else
4488c2ecf20Sopenharmony_ci		shost->active_mode = sht->supported_mode;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (sht->max_host_blocked)
4518c2ecf20Sopenharmony_ci		shost->max_host_blocked = sht->max_host_blocked;
4528c2ecf20Sopenharmony_ci	else
4538c2ecf20Sopenharmony_ci		shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/*
4568c2ecf20Sopenharmony_ci	 * If the driver imposes no hard sector transfer limit, start at
4578c2ecf20Sopenharmony_ci	 * machine infinity initially.
4588c2ecf20Sopenharmony_ci	 */
4598c2ecf20Sopenharmony_ci	if (sht->max_sectors)
4608c2ecf20Sopenharmony_ci		shost->max_sectors = sht->max_sectors;
4618c2ecf20Sopenharmony_ci	else
4628c2ecf20Sopenharmony_ci		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	if (sht->max_segment_size)
4658c2ecf20Sopenharmony_ci		shost->max_segment_size = sht->max_segment_size;
4668c2ecf20Sopenharmony_ci	else
4678c2ecf20Sopenharmony_ci		shost->max_segment_size = BLK_MAX_SEGMENT_SIZE;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	/*
4708c2ecf20Sopenharmony_ci	 * assume a 4GB boundary, if not set
4718c2ecf20Sopenharmony_ci	 */
4728c2ecf20Sopenharmony_ci	if (sht->dma_boundary)
4738c2ecf20Sopenharmony_ci		shost->dma_boundary = sht->dma_boundary;
4748c2ecf20Sopenharmony_ci	else
4758c2ecf20Sopenharmony_ci		shost->dma_boundary = 0xffffffff;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (sht->virt_boundary_mask)
4788c2ecf20Sopenharmony_ci		shost->virt_boundary_mask = sht->virt_boundary_mask;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	device_initialize(&shost->shost_gendev);
4818c2ecf20Sopenharmony_ci	dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
4828c2ecf20Sopenharmony_ci	shost->shost_gendev.bus = &scsi_bus_type;
4838c2ecf20Sopenharmony_ci	shost->shost_gendev.type = &scsi_host_type;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	device_initialize(&shost->shost_dev);
4868c2ecf20Sopenharmony_ci	shost->shost_dev.parent = &shost->shost_gendev;
4878c2ecf20Sopenharmony_ci	shost->shost_dev.class = &shost_class;
4888c2ecf20Sopenharmony_ci	dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
4898c2ecf20Sopenharmony_ci	shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	shost->ehandler = kthread_run(scsi_error_handler, shost,
4928c2ecf20Sopenharmony_ci			"scsi_eh_%d", shost->host_no);
4938c2ecf20Sopenharmony_ci	if (IS_ERR(shost->ehandler)) {
4948c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
4958c2ecf20Sopenharmony_ci			"error handler thread failed to spawn, error = %ld\n",
4968c2ecf20Sopenharmony_ci			PTR_ERR(shost->ehandler));
4978c2ecf20Sopenharmony_ci		shost->ehandler = NULL;
4988c2ecf20Sopenharmony_ci		goto fail;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	shost->tmf_work_q = alloc_workqueue("scsi_tmf_%d",
5028c2ecf20Sopenharmony_ci					WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS,
5038c2ecf20Sopenharmony_ci					   1, shost->host_no);
5048c2ecf20Sopenharmony_ci	if (!shost->tmf_work_q) {
5058c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
5068c2ecf20Sopenharmony_ci			     "failed to create tmf workq\n");
5078c2ecf20Sopenharmony_ci		goto fail;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci	scsi_proc_hostdir_add(shost->hostt);
5108c2ecf20Sopenharmony_ci	return shost;
5118c2ecf20Sopenharmony_ci fail:
5128c2ecf20Sopenharmony_ci	/*
5138c2ecf20Sopenharmony_ci	 * Host state is still SHOST_CREATED and that is enough to release
5148c2ecf20Sopenharmony_ci	 * ->shost_gendev. scsi_host_dev_release() will free
5158c2ecf20Sopenharmony_ci	 * dev_name(&shost->shost_dev).
5168c2ecf20Sopenharmony_ci	 */
5178c2ecf20Sopenharmony_ci	put_device(&shost->shost_gendev);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	return NULL;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_host_alloc);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic int __scsi_host_match(struct device *dev, const void *data)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct Scsi_Host *p;
5268c2ecf20Sopenharmony_ci	const unsigned int *hostnum = data;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	p = class_to_shost(dev);
5298c2ecf20Sopenharmony_ci	return p->host_no == *hostnum;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci/**
5338c2ecf20Sopenharmony_ci * scsi_host_lookup - get a reference to a Scsi_Host by host no
5348c2ecf20Sopenharmony_ci * @hostnum:	host number to locate
5358c2ecf20Sopenharmony_ci *
5368c2ecf20Sopenharmony_ci * Return value:
5378c2ecf20Sopenharmony_ci *	A pointer to located Scsi_Host or NULL.
5388c2ecf20Sopenharmony_ci *
5398c2ecf20Sopenharmony_ci *	The caller must do a scsi_host_put() to drop the reference
5408c2ecf20Sopenharmony_ci *	that scsi_host_get() took. The put_device() below dropped
5418c2ecf20Sopenharmony_ci *	the reference from class_find_device().
5428c2ecf20Sopenharmony_ci **/
5438c2ecf20Sopenharmony_cistruct Scsi_Host *scsi_host_lookup(unsigned int hostnum)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct device *cdev;
5468c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = NULL;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	cdev = class_find_device(&shost_class, NULL, &hostnum,
5498c2ecf20Sopenharmony_ci				 __scsi_host_match);
5508c2ecf20Sopenharmony_ci	if (cdev) {
5518c2ecf20Sopenharmony_ci		shost = scsi_host_get(class_to_shost(cdev));
5528c2ecf20Sopenharmony_ci		put_device(cdev);
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci	return shost;
5558c2ecf20Sopenharmony_ci}
5568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_host_lookup);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci/**
5598c2ecf20Sopenharmony_ci * scsi_host_get - inc a Scsi_Host ref count
5608c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host to inc.
5618c2ecf20Sopenharmony_ci **/
5628c2ecf20Sopenharmony_cistruct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
5638c2ecf20Sopenharmony_ci{
5648c2ecf20Sopenharmony_ci	if ((shost->shost_state == SHOST_DEL) ||
5658c2ecf20Sopenharmony_ci		!get_device(&shost->shost_gendev))
5668c2ecf20Sopenharmony_ci		return NULL;
5678c2ecf20Sopenharmony_ci	return shost;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_host_get);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic bool scsi_host_check_in_flight(struct request *rq, void *data,
5728c2ecf20Sopenharmony_ci				      bool reserved)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	int *count = data;
5758c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (test_bit(SCMD_STATE_INFLIGHT, &cmd->state))
5788c2ecf20Sopenharmony_ci		(*count)++;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return true;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci/**
5848c2ecf20Sopenharmony_ci * scsi_host_busy - Return the host busy counter
5858c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host to inc.
5868c2ecf20Sopenharmony_ci **/
5878c2ecf20Sopenharmony_ciint scsi_host_busy(struct Scsi_Host *shost)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	int cnt = 0;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set,
5928c2ecf20Sopenharmony_ci				scsi_host_check_in_flight, &cnt);
5938c2ecf20Sopenharmony_ci	return cnt;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_host_busy);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci/**
5988c2ecf20Sopenharmony_ci * scsi_host_put - dec a Scsi_Host ref count
5998c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host to dec.
6008c2ecf20Sopenharmony_ci **/
6018c2ecf20Sopenharmony_civoid scsi_host_put(struct Scsi_Host *shost)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	put_device(&shost->shost_gendev);
6048c2ecf20Sopenharmony_ci}
6058c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_host_put);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ciint scsi_init_hosts(void)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	return class_register(&shost_class);
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_civoid scsi_exit_hosts(void)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	class_unregister(&shost_class);
6158c2ecf20Sopenharmony_ci	ida_destroy(&host_index_ida);
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ciint scsi_is_host_device(const struct device *dev)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	return dev->type == &scsi_host_type;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(scsi_is_host_device);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci/**
6258c2ecf20Sopenharmony_ci * scsi_queue_work - Queue work to the Scsi_Host workqueue.
6268c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host.
6278c2ecf20Sopenharmony_ci * @work:	Work to queue for execution.
6288c2ecf20Sopenharmony_ci *
6298c2ecf20Sopenharmony_ci * Return value:
6308c2ecf20Sopenharmony_ci * 	1 - work queued for execution
6318c2ecf20Sopenharmony_ci *	0 - work is already queued
6328c2ecf20Sopenharmony_ci *	-EINVAL - work queue doesn't exist
6338c2ecf20Sopenharmony_ci **/
6348c2ecf20Sopenharmony_ciint scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
6358c2ecf20Sopenharmony_ci{
6368c2ecf20Sopenharmony_ci	if (unlikely(!shost->work_q)) {
6378c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, shost,
6388c2ecf20Sopenharmony_ci			"ERROR: Scsi host '%s' attempted to queue scsi-work, "
6398c2ecf20Sopenharmony_ci			"when no workqueue created.\n", shost->hostt->name);
6408c2ecf20Sopenharmony_ci		dump_stack();
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		return -EINVAL;
6438c2ecf20Sopenharmony_ci	}
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	return queue_work(shost->work_q, work);
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_queue_work);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci/**
6508c2ecf20Sopenharmony_ci * scsi_flush_work - Flush a Scsi_Host's workqueue.
6518c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host.
6528c2ecf20Sopenharmony_ci **/
6538c2ecf20Sopenharmony_civoid scsi_flush_work(struct Scsi_Host *shost)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	if (!shost->work_q) {
6568c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, shost,
6578c2ecf20Sopenharmony_ci			"ERROR: Scsi host '%s' attempted to flush scsi-work, "
6588c2ecf20Sopenharmony_ci			"when no workqueue created.\n", shost->hostt->name);
6598c2ecf20Sopenharmony_ci		dump_stack();
6608c2ecf20Sopenharmony_ci		return;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	flush_workqueue(shost->work_q);
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_flush_work);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic bool complete_all_cmds_iter(struct request *rq, void *data, bool rsvd)
6688c2ecf20Sopenharmony_ci{
6698c2ecf20Sopenharmony_ci	struct scsi_cmnd *scmd = blk_mq_rq_to_pdu(rq);
6708c2ecf20Sopenharmony_ci	int status = *(int *)data;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	scsi_dma_unmap(scmd);
6738c2ecf20Sopenharmony_ci	scmd->result = status << 16;
6748c2ecf20Sopenharmony_ci	scmd->scsi_done(scmd);
6758c2ecf20Sopenharmony_ci	return true;
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci/**
6798c2ecf20Sopenharmony_ci * scsi_host_complete_all_commands - Terminate all running commands
6808c2ecf20Sopenharmony_ci * @shost:	Scsi Host on which commands should be terminated
6818c2ecf20Sopenharmony_ci * @status:	Status to be set for the terminated commands
6828c2ecf20Sopenharmony_ci *
6838c2ecf20Sopenharmony_ci * There is no protection against modification of the number
6848c2ecf20Sopenharmony_ci * of outstanding commands. It is the responsibility of the
6858c2ecf20Sopenharmony_ci * caller to ensure that concurrent I/O submission and/or
6868c2ecf20Sopenharmony_ci * completion is stopped when calling this function.
6878c2ecf20Sopenharmony_ci */
6888c2ecf20Sopenharmony_civoid scsi_host_complete_all_commands(struct Scsi_Host *shost, int status)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set, complete_all_cmds_iter,
6918c2ecf20Sopenharmony_ci				&status);
6928c2ecf20Sopenharmony_ci}
6938c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_host_complete_all_commands);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistruct scsi_host_busy_iter_data {
6968c2ecf20Sopenharmony_ci	bool (*fn)(struct scsi_cmnd *, void *, bool);
6978c2ecf20Sopenharmony_ci	void *priv;
6988c2ecf20Sopenharmony_ci};
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic bool __scsi_host_busy_iter_fn(struct request *req, void *priv,
7018c2ecf20Sopenharmony_ci				   bool reserved)
7028c2ecf20Sopenharmony_ci{
7038c2ecf20Sopenharmony_ci	struct scsi_host_busy_iter_data *iter_data = priv;
7048c2ecf20Sopenharmony_ci	struct scsi_cmnd *sc = blk_mq_rq_to_pdu(req);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	return iter_data->fn(sc, iter_data->priv, reserved);
7078c2ecf20Sopenharmony_ci}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci/**
7108c2ecf20Sopenharmony_ci * scsi_host_busy_iter - Iterate over all busy commands
7118c2ecf20Sopenharmony_ci * @shost:	Pointer to Scsi_Host.
7128c2ecf20Sopenharmony_ci * @fn:		Function to call on each busy command
7138c2ecf20Sopenharmony_ci * @priv:	Data pointer passed to @fn
7148c2ecf20Sopenharmony_ci *
7158c2ecf20Sopenharmony_ci * If locking against concurrent command completions is required
7168c2ecf20Sopenharmony_ci * ithas to be provided by the caller
7178c2ecf20Sopenharmony_ci **/
7188c2ecf20Sopenharmony_civoid scsi_host_busy_iter(struct Scsi_Host *shost,
7198c2ecf20Sopenharmony_ci			 bool (*fn)(struct scsi_cmnd *, void *, bool),
7208c2ecf20Sopenharmony_ci			 void *priv)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	struct scsi_host_busy_iter_data iter_data = {
7238c2ecf20Sopenharmony_ci		.fn = fn,
7248c2ecf20Sopenharmony_ci		.priv = priv,
7258c2ecf20Sopenharmony_ci	};
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	blk_mq_tagset_busy_iter(&shost->tag_set, __scsi_host_busy_iter_fn,
7288c2ecf20Sopenharmony_ci				&iter_data);
7298c2ecf20Sopenharmony_ci}
7308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(scsi_host_busy_iter);
731