zfcp_ccw.c 8.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * zfcp device driver
L
Linus Torvalds 已提交
3
 *
4
 * Registration and callback for the s390 common I/O layer.
L
Linus Torvalds 已提交
5
 *
6
 * Copyright IBM Corporation 2002, 2009
L
Linus Torvalds 已提交
7 8
 */

9 10 11
#define KMSG_COMPONENT "zfcp"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

L
Linus Torvalds 已提交
12 13
#include "zfcp_ext.h"

14 15
#define ZFCP_MODEL_PRIV 0x4

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
static int zfcp_ccw_suspend(struct ccw_device *cdev)

{
	struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);

	down(&zfcp_data.config_sema);

	zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL);
	zfcp_erp_wait(adapter);

	up(&zfcp_data.config_sema);

	return 0;
}

static int zfcp_ccw_activate(struct ccw_device *cdev)

{
	struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev);

	zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL,
				       ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
				"ccresu2", NULL);
	zfcp_erp_wait(adapter);
	flush_work(&adapter->scan_work);

	return 0;
}

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
static struct ccw_device_id zfcp_ccw_device_id[] = {
	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) },
	{ CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) },
	{},
};
MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);

/**
 * zfcp_ccw_priv_sch - check if subchannel is privileged
 * @adapter: Adapter/Subchannel to check
 */
int zfcp_ccw_priv_sch(struct zfcp_adapter *adapter)
{
	return adapter->ccw_device->id.dev_model == ZFCP_MODEL_PRIV;
}

L
Linus Torvalds 已提交
62 63 64 65 66 67 68 69 70 71
/**
 * zfcp_ccw_probe - probe function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and sets up the initial
 * data structures for each fcp adapter, which was detected by the system.
 * Also the sysfs files for this adapter will be created by this function.
 * In addition the nameserver port will be added to the ports of the adapter
 * and its sysfs representation will be created too.
 */
72
static int zfcp_ccw_probe(struct ccw_device *ccw_device)
L
Linus Torvalds 已提交
73 74 75 76
{
	int retval = 0;

	down(&zfcp_data.config_sema);
77
	if (zfcp_adapter_enqueue(ccw_device)) {
78
		dev_err(&ccw_device->dev,
79 80
			"Setting up data structures for the "
			"FCP adapter failed\n");
L
Linus Torvalds 已提交
81
		retval = -EINVAL;
82
	}
L
Linus Torvalds 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95
	up(&zfcp_data.config_sema);
	return retval;
}

/**
 * zfcp_ccw_remove - remove function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and removes an adapter
 * from the system. Task of this function is to get rid of all units and
 * ports that belong to this adapter. And in addition all resources of this
 * adapter will be freed too.
 */
96
static void zfcp_ccw_remove(struct ccw_device *ccw_device)
L
Linus Torvalds 已提交
97 98 99 100
{
	struct zfcp_adapter *adapter;
	struct zfcp_port *port, *p;
	struct zfcp_unit *unit, *u;
101 102
	LIST_HEAD(unit_remove_lh);
	LIST_HEAD(port_remove_lh);
L
Linus Torvalds 已提交
103 104 105 106 107 108 109 110

	ccw_device_set_offline(ccw_device);
	down(&zfcp_data.config_sema);
	adapter = dev_get_drvdata(&ccw_device->dev);

	write_lock_irq(&zfcp_data.config_lock);
	list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
		list_for_each_entry_safe(unit, u, &port->unit_list_head, list) {
111
			list_move(&unit->list, &unit_remove_lh);
L
Linus Torvalds 已提交
112 113 114
			atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE,
					&unit->status);
		}
115
		list_move(&port->list, &port_remove_lh);
L
Linus Torvalds 已提交
116 117 118 119 120
		atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &port->status);
	}
	atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
	write_unlock_irq(&zfcp_data.config_lock);

121 122
	list_for_each_entry_safe(port, p, &port_remove_lh, list) {
		list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
123
			if (unit->device)
124
				scsi_remove_device(unit->device);
L
Linus Torvalds 已提交
125 126 127 128
			zfcp_unit_dequeue(unit);
		}
		zfcp_port_dequeue(port);
	}
129
	wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
L
Linus Torvalds 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143
	zfcp_adapter_dequeue(adapter);

	up(&zfcp_data.config_sema);
}

/**
 * zfcp_ccw_set_online - set_online function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and sets an adapter
 * into state online. Setting an fcp device online means that it will be
 * registered with the SCSI stack, that the QDIO queues will be set up
 * and that the adapter will be opened (asynchronously).
 */
144
static int zfcp_ccw_set_online(struct ccw_device *ccw_device)
L
Linus Torvalds 已提交
145 146 147 148 149 150 151 152
{
	struct zfcp_adapter *adapter;
	int retval;

	down(&zfcp_data.config_sema);
	adapter = dev_get_drvdata(&ccw_device->dev);

	retval = zfcp_erp_thread_setup(adapter);
153
	if (retval)
154
		goto out;
L
Linus Torvalds 已提交
155

156 157 158 159
	/* initialize request counter */
	BUG_ON(!zfcp_reqlist_isempty(adapter));
	adapter->req_no = 0;

160
	zfcp_erp_modify_adapter_status(adapter, "ccsonl1", NULL,
161
				       ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET);
162 163
	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
				"ccsonl2", NULL);
L
Linus Torvalds 已提交
164
	zfcp_erp_wait(adapter);
165 166 167
	up(&zfcp_data.config_sema);
	flush_work(&adapter->scan_work);
	return 0;
L
Linus Torvalds 已提交
168 169 170 171 172 173 174 175 176 177 178

 out:
	up(&zfcp_data.config_sema);
	return retval;
}

/**
 * zfcp_ccw_set_offline - set_offline function of zfcp driver
 * @ccw_device: pointer to belonging ccw device
 *
 * This function gets called by the common i/o layer and sets an adapter
179
 * into state offline.
L
Linus Torvalds 已提交
180
 */
181
static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
L
Linus Torvalds 已提交
182 183 184 185 186
{
	struct zfcp_adapter *adapter;

	down(&zfcp_data.config_sema);
	adapter = dev_get_drvdata(&ccw_device->dev);
187
	zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
L
Linus Torvalds 已提交
188 189 190 191 192 193 194
	zfcp_erp_wait(adapter);
	zfcp_erp_thread_kill(adapter);
	up(&zfcp_data.config_sema);
	return 0;
}

/**
195
 * zfcp_ccw_notify - ccw notify function
L
Linus Torvalds 已提交
196 197 198 199 200 201
 * @ccw_device: pointer to belonging ccw device
 * @event: indicates if adapter was detached or attached
 *
 * This function gets called by the common i/o layer if an adapter has gone
 * or reappeared.
 */
202
static int zfcp_ccw_notify(struct ccw_device *ccw_device, int event)
L
Linus Torvalds 已提交
203
{
204
	struct zfcp_adapter *adapter = dev_get_drvdata(&ccw_device->dev);
L
Linus Torvalds 已提交
205 206 207

	switch (event) {
	case CIO_GONE:
208 209
		dev_warn(&adapter->ccw_device->dev,
			 "The FCP device has been detached\n");
210
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti1", NULL);
L
Linus Torvalds 已提交
211 212
		break;
	case CIO_NO_PATH:
213 214
		dev_warn(&adapter->ccw_device->dev,
			 "The CHPID for the FCP device is offline\n");
215
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti2", NULL);
L
Linus Torvalds 已提交
216 217
		break;
	case CIO_OPER:
218 219
		dev_info(&adapter->ccw_device->dev,
			 "The FCP device is operational again\n");
220
		zfcp_erp_modify_adapter_status(adapter, "ccnoti3", NULL,
L
Linus Torvalds 已提交
221 222
					       ZFCP_STATUS_COMMON_RUNNING,
					       ZFCP_SET);
223
		zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
224
					"ccnoti4", NULL);
L
Linus Torvalds 已提交
225
		break;
226
	case CIO_BOXED:
227 228
		dev_warn(&adapter->ccw_device->dev, "The FCP device "
			 "did not respond within the specified time\n");
229 230
		zfcp_erp_adapter_shutdown(adapter, 0, "ccnoti5", NULL);
		break;
L
Linus Torvalds 已提交
231 232 233 234 235
	}
	return 1;
}

/**
236 237
 * zfcp_ccw_shutdown - handle shutdown from cio
 * @cdev: device for adapter to shutdown.
L
Linus Torvalds 已提交
238
 */
239
static void zfcp_ccw_shutdown(struct ccw_device *cdev)
L
Linus Torvalds 已提交
240 241 242 243
{
	struct zfcp_adapter *adapter;

	down(&zfcp_data.config_sema);
244
	adapter = dev_get_drvdata(&cdev->dev);
245
	zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
L
Linus Torvalds 已提交
246 247 248 249
	zfcp_erp_wait(adapter);
	up(&zfcp_data.config_sema);
}

250 251 252 253 254 255 256 257 258 259
static struct ccw_driver zfcp_ccw_driver = {
	.owner       = THIS_MODULE,
	.name        = "zfcp",
	.ids         = zfcp_ccw_device_id,
	.probe       = zfcp_ccw_probe,
	.remove      = zfcp_ccw_remove,
	.set_online  = zfcp_ccw_set_online,
	.set_offline = zfcp_ccw_set_offline,
	.notify      = zfcp_ccw_notify,
	.shutdown    = zfcp_ccw_shutdown,
260 261 262
	.freeze      = zfcp_ccw_suspend,
	.thaw	     = zfcp_ccw_activate,
	.restore     = zfcp_ccw_activate,
263 264 265 266 267 268 269 270 271 272 273 274
};

/**
 * zfcp_ccw_register - ccw register function
 *
 * Registers the driver at the common i/o layer. This function will be called
 * at module load time/system start.
 */
int __init zfcp_ccw_register(void)
{
	return ccw_driver_register(&zfcp_ccw_driver);
}
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291

/**
 * zfcp_get_adapter_by_busid - find zfcp_adapter struct
 * @busid: bus id string of zfcp adapter to find
 */
struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid)
{
	struct ccw_device *ccw_device;
	struct zfcp_adapter *adapter = NULL;

	ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
	if (ccw_device) {
		adapter = dev_get_drvdata(&ccw_device->dev);
		put_device(&ccw_device->dev);
	}
	return adapter;
}