scsi_transport_iscsi.c 60.3 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2 3 4
 * iSCSI transport class definitions
 *
 * Copyright (C) IBM Corporation, 2004
5 6 7
 * Copyright (C) Mike Christie, 2004 - 2005
 * Copyright (C) Dmitry Yusupov, 2004 - 2005
 * Copyright (C) Alex Aizman, 2004 - 2005
L
Linus Torvalds 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <linux/module.h>
24
#include <linux/mutex.h>
25
#include <linux/slab.h>
26
#include <net/tcp.h>
L
Linus Torvalds 已提交
27 28 29 30 31
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
32
#include <scsi/iscsi_if.h>
33
#include <scsi/scsi_cmnd.h>
L
Linus Torvalds 已提交
34

35
#define ISCSI_SESSION_ATTRS 23
36
#define ISCSI_CONN_ATTRS 13
37
#define ISCSI_HOST_ATTRS 4
38

39
#define ISCSI_TRANSPORT_VERSION "2.0-870"
L
Linus Torvalds 已提交
40

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
static int dbg_session;
module_param_named(debug_session, dbg_session, int,
		   S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_session,
		 "Turn on debugging for sessions in scsi_transport_iscsi "
		 "module. Set to 1 to turn on, and zero to turn off. Default "
		 "is off.");

static int dbg_conn;
module_param_named(debug_conn, dbg_conn, int,
		   S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug_conn,
		 "Turn on debugging for connections in scsi_transport_iscsi "
		 "module. Set to 1 to turn on, and zero to turn off. Default "
		 "is off.");

#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...)		\
	do {								\
		if (dbg_session)					\
			iscsi_cls_session_printk(KERN_INFO, _session,	\
						 "%s: " dbg_fmt,	\
						 __func__, ##arg);	\
	} while (0);

#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...)			\
	do {								\
		if (dbg_conn)						\
			iscsi_cls_conn_printk(KERN_INFO, _conn,		\
					      "%s: " dbg_fmt,		\
					      __func__, ##arg);	\
	} while (0);

L
Linus Torvalds 已提交
73 74
struct iscsi_internal {
	struct scsi_transport_template t;
75 76
	struct iscsi_transport *iscsi_transport;
	struct list_head list;
77
	struct device dev;
M
Mike Christie 已提交
78

79
	struct device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
80
	struct transport_container conn_cont;
81
	struct device_attribute *conn_attrs[ISCSI_CONN_ATTRS + 1];
82
	struct transport_container session_cont;
83
	struct device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
L
Linus Torvalds 已提交
84 85
};

86
static atomic_t iscsi_session_nr; /* sysfs session id for next new session */
87
static struct workqueue_struct *iscsi_eh_timer_workq;
88

89 90 91
/*
 * list of registered transports and lock that must
 * be held while accessing list. The iscsi_transport_lock must
92
 * be acquired after the rx_queue_mutex.
93 94 95 96 97 98 99
 */
static LIST_HEAD(iscsi_transports);
static DEFINE_SPINLOCK(iscsi_transport_lock);

#define to_iscsi_internal(tmpl) \
	container_of(tmpl, struct iscsi_internal, t)

100 101
#define dev_to_iscsi_internal(_dev) \
	container_of(_dev, struct iscsi_internal, dev)
102

103
static void iscsi_transport_release(struct device *dev)
104
{
105
	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
106 107
	kfree(priv);
}
L
Linus Torvalds 已提交
108

109 110 111 112 113 114
/*
 * iscsi_transport_class represents the iscsi_transports that are
 * registered.
 */
static struct class iscsi_transport_class = {
	.name = "iscsi_transport",
115
	.dev_release = iscsi_transport_release,
116 117 118
};

static ssize_t
119 120
show_transport_handle(struct device *dev, struct device_attribute *attr,
		      char *buf)
121
{
122
	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);
123
	return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport));
124
}
125
static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL);
126 127 128

#define show_transport_attr(name, format)				\
static ssize_t								\
129 130
show_transport_##name(struct device *dev, 				\
		      struct device_attribute *attr,char *buf)		\
131
{									\
132
	struct iscsi_internal *priv = dev_to_iscsi_internal(dev);	\
133 134
	return sprintf(buf, format"\n", priv->iscsi_transport->name);	\
}									\
135
static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL);
136 137 138 139

show_transport_attr(caps, "0x%x");

static struct attribute *iscsi_transport_attrs[] = {
140 141
	&dev_attr_handle.attr,
	&dev_attr_caps.attr,
142 143 144 145 146 147 148
	NULL,
};

static struct attribute_group iscsi_transport_group = {
	.attrs = iscsi_transport_attrs,
};

149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
/*
 * iSCSI endpoint attrs
 */
#define iscsi_dev_to_endpoint(_dev) \
	container_of(_dev, struct iscsi_endpoint, dev)

#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store)	\
struct device_attribute dev_attr_##_prefix##_##_name =	\
        __ATTR(_name,_mode,_show,_store)

static void iscsi_endpoint_release(struct device *dev)
{
	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
	kfree(ep);
}

static struct class iscsi_endpoint_class = {
	.name = "iscsi_endpoint",
	.dev_release = iscsi_endpoint_release,
};

static ssize_t
show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
174
	return sprintf(buf, "%llu\n", (unsigned long long) ep->id);
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
}
static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL);

static struct attribute *iscsi_endpoint_attrs[] = {
	&dev_attr_ep_handle.attr,
	NULL,
};

static struct attribute_group iscsi_endpoint_group = {
	.attrs = iscsi_endpoint_attrs,
};

#define ISCSI_MAX_EPID -1

static int iscsi_match_epid(struct device *dev, void *data)
{
	struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev);
192
	uint64_t *epid = (uint64_t *) data;
193 194 195 196 197 198 199 200 201

	return *epid == ep->id;
}

struct iscsi_endpoint *
iscsi_create_endpoint(int dd_size)
{
	struct device *dev;
	struct iscsi_endpoint *ep;
202
	uint64_t id;
203 204 205
	int err;

	for (id = 1; id < ISCSI_MAX_EPID; id++) {
206
		dev = class_find_device(&iscsi_endpoint_class, NULL, &id,
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
					iscsi_match_epid);
		if (!dev)
			break;
	}
	if (id == ISCSI_MAX_EPID) {
		printk(KERN_ERR "Too many connections. Max supported %u\n",
		       ISCSI_MAX_EPID - 1);
		return NULL;
	}

	ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL);
	if (!ep)
		return NULL;

	ep->id = id;
	ep->dev.class = &iscsi_endpoint_class;
223
	dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id);
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
	err = device_register(&ep->dev);
        if (err)
                goto free_ep;

	err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group);
	if (err)
		goto unregister_dev;

	if (dd_size)
		ep->dd_data = &ep[1];
	return ep;

unregister_dev:
	device_unregister(&ep->dev);
	return NULL;

free_ep:
	kfree(ep);
	return NULL;
}
EXPORT_SYMBOL_GPL(iscsi_create_endpoint);

void iscsi_destroy_endpoint(struct iscsi_endpoint *ep)
{
	sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group);
	device_unregister(&ep->dev);
}
EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint);

struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle)
{
255
	struct iscsi_endpoint *ep;
256 257
	struct device *dev;

258
	dev = class_find_device(&iscsi_endpoint_class, NULL, &handle,
259 260 261 262
				iscsi_match_epid);
	if (!dev)
		return NULL;

263 264 265 266 267 268 269
	ep = iscsi_dev_to_endpoint(dev);
	/*
	 * we can drop this now because the interface will prevent
	 * removals and lookups from racing.
	 */
	put_device(dev);
	return ep;
270 271 272
}
EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint);

M
Mike Christie 已提交
273
static int iscsi_setup_host(struct transport_container *tc, struct device *dev,
274
			    struct device *cdev)
M
Mike Christie 已提交
275 276
{
	struct Scsi_Host *shost = dev_to_shost(dev);
277
	struct iscsi_cls_host *ihost = shost->shost_data;
M
Mike Christie 已提交
278 279

	memset(ihost, 0, sizeof(*ihost));
280
	atomic_set(&ihost->nr_scans, 0);
281
	mutex_init(&ihost->mutex);
M
Mike Christie 已提交
282 283 284 285 286 287
	return 0;
}

static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
			       "iscsi_host",
			       iscsi_setup_host,
288
			       NULL,
M
Mike Christie 已提交
289 290
			       NULL);

291 292
static DECLARE_TRANSPORT_CLASS(iscsi_session_class,
			       "iscsi_session",
L
Linus Torvalds 已提交
293 294 295 296
			       NULL,
			       NULL,
			       NULL);

297 298
static DECLARE_TRANSPORT_CLASS(iscsi_connection_class,
			       "iscsi_connection",
L
Linus Torvalds 已提交
299 300 301
			       NULL,
			       NULL,
			       NULL);
302 303

static struct sock *nls;
304
static DEFINE_MUTEX(rx_queue_mutex);
305

306 307
static LIST_HEAD(sesslist);
static DEFINE_SPINLOCK(sesslock);
308 309
static LIST_HEAD(connlist);
static DEFINE_SPINLOCK(connlock);
310

311 312 313 314 315 316 317 318 319 320
static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn)
{
	struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent);
	return sess->sid;
}

/*
 * Returns the matching session to a given sid
 */
static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid)
321 322 323 324 325 326
{
	unsigned long flags;
	struct iscsi_cls_session *sess;

	spin_lock_irqsave(&sesslock, flags);
	list_for_each_entry(sess, &sesslist, sess_list) {
327
		if (sess->sid == sid) {
328 329 330 331 332 333 334 335
			spin_unlock_irqrestore(&sesslock, flags);
			return sess;
		}
	}
	spin_unlock_irqrestore(&sesslock, flags);
	return NULL;
}

336 337 338 339
/*
 * Returns the matching connection to a given sid / cid tuple
 */
static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
340 341 342 343 344 345
{
	unsigned long flags;
	struct iscsi_cls_conn *conn;

	spin_lock_irqsave(&connlock, flags);
	list_for_each_entry(conn, &connlist, conn_list) {
346
		if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) {
347 348 349 350 351 352 353 354
			spin_unlock_irqrestore(&connlock, flags);
			return conn;
		}
	}
	spin_unlock_irqrestore(&connlock, flags);
	return NULL;
}

355 356 357 358
/*
 * The following functions can be used by LLDs that allocate
 * their own scsi_hosts or by software iscsi LLDs
 */
359 360 361 362 363 364 365 366 367
static struct {
	int value;
	char *name;
} iscsi_session_state_names[] = {
	{ ISCSI_SESSION_LOGGED_IN,	"LOGGED_IN" },
	{ ISCSI_SESSION_FAILED,		"FAILED" },
	{ ISCSI_SESSION_FREE,		"FREE" },
};

368
static const char *iscsi_session_state_name(int state)
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
{
	int i;
	char *name = NULL;

	for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) {
		if (iscsi_session_state_names[i].value == state) {
			name = iscsi_session_state_names[i].name;
			break;
		}
	}
	return name;
}

int iscsi_session_chkready(struct iscsi_cls_session *session)
{
	unsigned long flags;
	int err;

	spin_lock_irqsave(&session->lock, flags);
	switch (session->state) {
	case ISCSI_SESSION_LOGGED_IN:
		err = 0;
		break;
	case ISCSI_SESSION_FAILED:
393
		err = DID_IMM_RETRY << 16;
394 395
		break;
	case ISCSI_SESSION_FREE:
396
		err = DID_TRANSPORT_FAILFAST << 16;
397 398 399 400 401 402 403 404 405 406
		break;
	default:
		err = DID_NO_CONNECT << 16;
		break;
	}
	spin_unlock_irqrestore(&session->lock, flags);
	return err;
}
EXPORT_SYMBOL_GPL(iscsi_session_chkready);

407 408 409 410
static void iscsi_session_release(struct device *dev)
{
	struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
	struct Scsi_Host *shost;
411

412 413
	shost = iscsi_session_to_shost(session);
	scsi_host_put(shost);
414
	ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n");
415 416
	kfree(session);
}
417

418 419 420 421
static int iscsi_is_session_dev(const struct device *dev)
{
	return dev->release == iscsi_session_release;
}
422

423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
static int iscsi_iter_session_fn(struct device *dev, void *data)
{
	void (* fn) (struct iscsi_cls_session *) = data;

	if (!iscsi_is_session_dev(dev))
		return 0;
	fn(iscsi_dev_to_session(dev));
	return 0;
}

void iscsi_host_for_each_session(struct Scsi_Host *shost,
				 void (*fn)(struct iscsi_cls_session *))
{
	device_for_each_child(&shost->shost_gendev, fn,
			      iscsi_iter_session_fn);
}
EXPORT_SYMBOL_GPL(iscsi_host_for_each_session);

441 442 443 444 445 446 447 448 449 450
/**
 * iscsi_scan_finished - helper to report when running scans are done
 * @shost: scsi host
 * @time: scan run time
 *
 * This function can be used by drives like qla4xxx to report to the scsi
 * layer when the scans it kicked off at module load time are done.
 */
int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
451
	struct iscsi_cls_host *ihost = shost->shost_data;
452 453 454 455 456 457 458 459
	/*
	 * qla4xxx will have kicked off some session unblocks before calling
	 * scsi_scan_host, so just wait for them to complete.
	 */
	return !atomic_read(&ihost->nr_scans);
}
EXPORT_SYMBOL_GPL(iscsi_scan_finished);

460 461 462 463 464 465 466
struct iscsi_scan_data {
	unsigned int channel;
	unsigned int id;
	unsigned int lun;
};

static int iscsi_user_scan_session(struct device *dev, void *data)
M
Mike Christie 已提交
467
{
468
	struct iscsi_scan_data *scan_data = data;
M
Mike Christie 已提交
469
	struct iscsi_cls_session *session;
470 471 472 473 474 475 476 477 478
	struct Scsi_Host *shost;
	struct iscsi_cls_host *ihost;
	unsigned long flags;
	unsigned int id;

	if (!iscsi_is_session_dev(dev))
		return 0;

	session = iscsi_dev_to_session(dev);
479 480 481

	ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n");

482 483
	shost = iscsi_session_to_shost(session);
	ihost = shost->shost_data;
M
Mike Christie 已提交
484 485

	mutex_lock(&ihost->mutex);
486 487 488
	spin_lock_irqsave(&session->lock, flags);
	if (session->state != ISCSI_SESSION_LOGGED_IN) {
		spin_unlock_irqrestore(&session->lock, flags);
489
		goto user_scan_exit;
M
Mike Christie 已提交
490
	}
491 492
	id = session->target_id;
	spin_unlock_irqrestore(&session->lock, flags);
M
Mike Christie 已提交
493

494 495 496 497 498 499 500 501
	if (id != ISCSI_MAX_TARGET) {
		if ((scan_data->channel == SCAN_WILD_CARD ||
		     scan_data->channel == 0) &&
		    (scan_data->id == SCAN_WILD_CARD ||
		     scan_data->id == id))
			scsi_scan_target(&session->dev, 0, id,
					 scan_data->lun, 1);
	}
502 503

user_scan_exit:
504
	mutex_unlock(&ihost->mutex);
505
	ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n");
M
Mike Christie 已提交
506 507 508
	return 0;
}

509 510 511 512 513 514 515 516 517 518 519 520 521
static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
			   uint id, uint lun)
{
	struct iscsi_scan_data scan_data;

	scan_data.channel = channel;
	scan_data.id = id;
	scan_data.lun = lun;

	return device_for_each_child(&shost->shost_gendev, &scan_data,
				     iscsi_user_scan_session);
}

522 523 524 525
static void iscsi_scan_session(struct work_struct *work)
{
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session, scan_work);
526
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
527
	struct iscsi_cls_host *ihost = shost->shost_data;
528
	struct iscsi_scan_data scan_data;
529

530 531 532
	scan_data.channel = 0;
	scan_data.id = SCAN_WILD_CARD;
	scan_data.lun = SCAN_WILD_CARD;
533

534
	iscsi_user_scan_session(&session->dev, &scan_data);
535
	atomic_dec(&ihost->nr_scans);
536 537
}

538 539
/**
 * iscsi_block_scsi_eh - block scsi eh until session state has transistioned
540
 * @cmd: scsi cmd passed to scsi eh handler
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
 *
 * If the session is down this function will wait for the recovery
 * timer to fire or for the session to be logged back in. If the
 * recovery timer fires then FAST_IO_FAIL is returned. The caller
 * should pass this error value to the scsi eh.
 */
int iscsi_block_scsi_eh(struct scsi_cmnd *cmd)
{
	struct iscsi_cls_session *session =
			starget_to_session(scsi_target(cmd->device));
	unsigned long flags;
	int ret = 0;

	spin_lock_irqsave(&session->lock, flags);
	while (session->state != ISCSI_SESSION_LOGGED_IN) {
		if (session->state == ISCSI_SESSION_FREE) {
			ret = FAST_IO_FAIL;
			break;
		}
		spin_unlock_irqrestore(&session->lock, flags);
		msleep(1000);
		spin_lock_irqsave(&session->lock, flags);
	}
	spin_unlock_irqrestore(&session->lock, flags);
	return ret;
}
EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh);

D
David Howells 已提交
569
static void session_recovery_timedout(struct work_struct *work)
M
Mike Christie 已提交
570
{
D
David Howells 已提交
571 572 573
	struct iscsi_cls_session *session =
		container_of(work, struct iscsi_cls_session,
			     recovery_work.work);
574
	unsigned long flags;
M
Mike Christie 已提交
575

576 577 578
	iscsi_cls_session_printk(KERN_INFO, session,
				 "session recovery timed out after %d secs\n",
				 session->recovery_tmo);
M
Mike Christie 已提交
579

580 581 582 583 584 585 586 587 588 589 590 591 592
	spin_lock_irqsave(&session->lock, flags);
	switch (session->state) {
	case ISCSI_SESSION_FAILED:
		session->state = ISCSI_SESSION_FREE;
		break;
	case ISCSI_SESSION_LOGGED_IN:
	case ISCSI_SESSION_FREE:
		/* we raced with the unblock's flush */
		spin_unlock_irqrestore(&session->lock, flags);
		return;
	}
	spin_unlock_irqrestore(&session->lock, flags);

M
Mike Christie 已提交
593 594 595
	if (session->transport->session_recovery_timedout)
		session->transport->session_recovery_timedout(session);

596
	ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n");
M
Mike Christie 已提交
597
	scsi_target_unblock(&session->dev);
598
	ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n");
M
Mike Christie 已提交
599 600
}

601
static void __iscsi_unblock_session(struct work_struct *work)
602
{
603 604 605
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session,
				     unblock_work);
606
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
607
	struct iscsi_cls_host *ihost = shost->shost_data;
608 609
	unsigned long flags;

610
	ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n");
611 612 613 614 615
	/*
	 * The recovery and unblock work get run from the same workqueue,
	 * so try to cancel it if it was going to run after this unblock.
	 */
	cancel_delayed_work(&session->recovery_work);
616 617 618
	spin_lock_irqsave(&session->lock, flags);
	session->state = ISCSI_SESSION_LOGGED_IN;
	spin_unlock_irqrestore(&session->lock, flags);
619 620
	/* start IO */
	scsi_target_unblock(&session->dev);
621 622 623 624 625 626
	/*
	 * Only do kernel scanning if the driver is properly hooked into
	 * the async scanning code (drivers like iscsi_tcp do login and
	 * scanning from userspace).
	 */
	if (shost->hostt->scan_finished) {
627
		if (scsi_queue_work(shost, &session->scan_work))
628 629
			atomic_inc(&ihost->nr_scans);
	}
630
	ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n");
631
}
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647

/**
 * iscsi_unblock_session - set a session as logged in and start IO.
 * @session: iscsi session
 *
 * Mark a session as ready to accept IO.
 */
void iscsi_unblock_session(struct iscsi_cls_session *session)
{
	queue_work(iscsi_eh_timer_workq, &session->unblock_work);
	/*
	 * make sure all the events have completed before tell the driver
	 * it is safe
	 */
	flush_workqueue(iscsi_eh_timer_workq);
}
M
Mike Christie 已提交
648 649
EXPORT_SYMBOL_GPL(iscsi_unblock_session);

650
static void __iscsi_block_session(struct work_struct *work)
M
Mike Christie 已提交
651
{
652 653 654
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session,
				     block_work);
655 656
	unsigned long flags;

657
	ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n");
658 659 660
	spin_lock_irqsave(&session->lock, flags);
	session->state = ISCSI_SESSION_FAILED;
	spin_unlock_irqrestore(&session->lock, flags);
M
Mike Christie 已提交
661
	scsi_target_block(&session->dev);
662
	ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n");
663 664 665 666
	if (session->recovery_tmo >= 0)
		queue_delayed_work(iscsi_eh_timer_workq,
				   &session->recovery_work,
				   session->recovery_tmo * HZ);
M
Mike Christie 已提交
667
}
668 669 670 671 672

void iscsi_block_session(struct iscsi_cls_session *session)
{
	queue_work(iscsi_eh_timer_workq, &session->block_work);
}
M
Mike Christie 已提交
673 674
EXPORT_SYMBOL_GPL(iscsi_block_session);

M
Mike Christie 已提交
675 676 677 678 679 680
static void __iscsi_unbind_session(struct work_struct *work)
{
	struct iscsi_cls_session *session =
			container_of(work, struct iscsi_cls_session,
				     unbind_work);
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
681
	struct iscsi_cls_host *ihost = shost->shost_data;
682
	unsigned long flags;
M
Mike Christie 已提交
683

684 685
	ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n");

M
Mike Christie 已提交
686 687
	/* Prevent new scans and make sure scanning is not in progress */
	mutex_lock(&ihost->mutex);
688 689 690
	spin_lock_irqsave(&session->lock, flags);
	if (session->target_id == ISCSI_MAX_TARGET) {
		spin_unlock_irqrestore(&session->lock, flags);
M
Mike Christie 已提交
691 692 693
		mutex_unlock(&ihost->mutex);
		return;
	}
694 695
	session->target_id = ISCSI_MAX_TARGET;
	spin_unlock_irqrestore(&session->lock, flags);
M
Mike Christie 已提交
696 697 698 699
	mutex_unlock(&ihost->mutex);

	scsi_remove_target(&session->dev);
	iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION);
700
	ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n");
M
Mike Christie 已提交
701 702
}

703
struct iscsi_cls_session *
704 705
iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
		    int dd_size)
706 707 708
{
	struct iscsi_cls_session *session;

709
	session = kzalloc(sizeof(*session) + dd_size,
710
			  GFP_KERNEL);
711
	if (!session)
712 713
		return NULL;

714
	session->transport = transport;
M
Mike Christie 已提交
715
	session->recovery_tmo = 120;
716
	session->state = ISCSI_SESSION_FREE;
D
David Howells 已提交
717
	INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout);
M
Mike Christie 已提交
718
	INIT_LIST_HEAD(&session->sess_list);
719 720
	INIT_WORK(&session->unblock_work, __iscsi_unblock_session);
	INIT_WORK(&session->block_work, __iscsi_block_session);
M
Mike Christie 已提交
721
	INIT_WORK(&session->unbind_work, __iscsi_unbind_session);
722
	INIT_WORK(&session->scan_work, iscsi_scan_session);
723
	spin_lock_init(&session->lock);
724

725 726
	/* this is released in the dev's release function */
	scsi_host_get(shost);
727 728 729
	session->dev.parent = &shost->shost_gendev;
	session->dev.release = iscsi_session_release;
	device_initialize(&session->dev);
730
	if (dd_size)
731
		session->dd_data = &session[1];
732 733

	ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n");
734 735 736 737
	return session;
}
EXPORT_SYMBOL_GPL(iscsi_alloc_session);

738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
static int iscsi_get_next_target_id(struct device *dev, void *data)
{
	struct iscsi_cls_session *session;
	unsigned long flags;
	int err = 0;

	if (!iscsi_is_session_dev(dev))
		return 0;

	session = iscsi_dev_to_session(dev);
	spin_lock_irqsave(&session->lock, flags);
	if (*((unsigned int *) data) == session->target_id)
		err = -EEXIST;
	spin_unlock_irqrestore(&session->lock, flags);
	return err;
}

755
int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
756 757
{
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
758
	struct iscsi_cls_host *ihost;
M
Mike Christie 已提交
759
	unsigned long flags;
760
	unsigned int id = target_id;
761
	int err;
762

M
Mike Christie 已提交
763
	ihost = shost->shost_data;
764
	session->sid = atomic_add_return(1, &iscsi_session_nr);
765 766 767 768 769 770 771 772 773 774 775 776 777 778

	if (id == ISCSI_MAX_TARGET) {
		for (id = 0; id < ISCSI_MAX_TARGET; id++) {
			err = device_for_each_child(&shost->shost_gendev, &id,
						    iscsi_get_next_target_id);
			if (!err)
				break;
		}

		if (id == ISCSI_MAX_TARGET) {
			iscsi_cls_session_printk(KERN_ERR, session,
						 "Too many iscsi targets. Max "
						 "number of targets is %d.\n",
						 ISCSI_MAX_TARGET - 1);
779
			err = -EOVERFLOW;
780 781 782 783
			goto release_host;
		}
	}
	session->target_id = id;
M
Mike Christie 已提交
784

785
	dev_set_name(&session->dev, "session%u", session->sid);
786
	err = device_add(&session->dev);
787
	if (err) {
788 789
		iscsi_cls_session_printk(KERN_ERR, session,
					 "could not register session's dev\n");
790
		goto release_host;
791 792 793
	}
	transport_register_device(&session->dev);

M
Mike Christie 已提交
794 795 796 797 798
	spin_lock_irqsave(&sesslock, flags);
	list_add(&session->sess_list, &sesslist);
	spin_unlock_irqrestore(&sesslock, flags);

	iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION);
799
	ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n");
800
	return 0;
M
Mike Christie 已提交
801

802 803 804
release_host:
	scsi_host_put(shost);
	return err;
805
}
806
EXPORT_SYMBOL_GPL(iscsi_add_session);
807 808

/**
809 810 811
 * iscsi_create_session - create iscsi class session
 * @shost: scsi host
 * @transport: iscsi transport
812
 * @dd_size: private driver data size
813
 * @target_id: which target
814
 *
815
 * This can be called from a LLD or iscsi_transport.
816
 */
817
struct iscsi_cls_session *
818 819
iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport,
		     int dd_size, unsigned int target_id)
820 821 822
{
	struct iscsi_cls_session *session;

823
	session = iscsi_alloc_session(shost, transport, dd_size);
824 825 826
	if (!session)
		return NULL;

827
	if (iscsi_add_session(session, target_id)) {
828 829 830 831 832 833 834
		iscsi_free_session(session);
		return NULL;
	}
	return session;
}
EXPORT_SYMBOL_GPL(iscsi_create_session);

M
Mike Christie 已提交
835 836 837 838 839
static void iscsi_conn_release(struct device *dev)
{
	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
	struct device *parent = conn->dev.parent;

840
	ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n");
M
Mike Christie 已提交
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
	kfree(conn);
	put_device(parent);
}

static int iscsi_is_conn_dev(const struct device *dev)
{
	return dev->release == iscsi_conn_release;
}

static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data)
{
	if (!iscsi_is_conn_dev(dev))
		return 0;
	return iscsi_destroy_conn(iscsi_dev_to_conn(dev));
}

857
void iscsi_remove_session(struct iscsi_cls_session *session)
858
{
M
Mike Christie 已提交
859
	struct Scsi_Host *shost = iscsi_session_to_shost(session);
M
Mike Christie 已提交
860 861 862
	unsigned long flags;
	int err;

863 864
	ISCSI_DBG_TRANS_SESSION(session, "Removing session\n");

M
Mike Christie 已提交
865 866 867
	spin_lock_irqsave(&sesslock, flags);
	list_del(&session->sess_list);
	spin_unlock_irqrestore(&sesslock, flags);
M
Mike Christie 已提交
868

869 870 871 872 873
	/* make sure there are no blocks/unblocks queued */
	flush_workqueue(iscsi_eh_timer_workq);
	/* make sure the timedout callout is not running */
	if (!cancel_delayed_work(&session->recovery_work))
		flush_workqueue(iscsi_eh_timer_workq);
M
Mike Christie 已提交
874 875 876
	/*
	 * If we are blocked let commands flow again. The lld or iscsi
	 * layer should set up the queuecommand to fail commands.
877 878
	 * We assume that LLD will not be calling block/unblock while
	 * removing the session.
M
Mike Christie 已提交
879
	 */
880 881 882
	spin_lock_irqsave(&session->lock, flags);
	session->state = ISCSI_SESSION_FREE;
	spin_unlock_irqrestore(&session->lock, flags);
883

884 885
	scsi_target_unblock(&session->dev);
	/* flush running scans then delete devices */
886
	scsi_flush_work(shost);
887
	__iscsi_unbind_session(&session->unbind_work);
M
Mike Christie 已提交
888

M
Mike Christie 已提交
889 890 891 892
	/* hw iscsi may not have removed all connections from session */
	err = device_for_each_child(&session->dev, NULL,
				    iscsi_iter_destroy_conn_fn);
	if (err)
893 894 895
		iscsi_cls_session_printk(KERN_ERR, session,
					 "Could not delete all connections "
					 "for session. Error %d.\n", err);
896

897
	transport_unregister_device(&session->dev);
898 899

	ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n");
900 901 902 903 904 905
	device_del(&session->dev);
}
EXPORT_SYMBOL_GPL(iscsi_remove_session);

void iscsi_free_session(struct iscsi_cls_session *session)
{
906
	ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n");
M
Mike Christie 已提交
907
	iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION);
908
	put_device(&session->dev);
909
}
910 911 912 913 914 915 916 917
EXPORT_SYMBOL_GPL(iscsi_free_session);

/**
 * iscsi_destroy_session - destroy iscsi session
 * @session: iscsi_session
 *
 * Can be called by a LLD or iscsi_transport. There must not be
 * any running connections.
918
 */
919 920 921
int iscsi_destroy_session(struct iscsi_cls_session *session)
{
	iscsi_remove_session(session);
922
	ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n");
923 924 925
	iscsi_free_session(session);
	return 0;
}
926 927 928 929 930
EXPORT_SYMBOL_GPL(iscsi_destroy_session);

/**
 * iscsi_create_conn - create iscsi class connection
 * @session: iscsi cls session
931
 * @dd_size: private driver data size
932 933 934 935 936
 * @cid: connection id
 *
 * This can be called from a LLD or iscsi_transport. The connection
 * is child of the session so cid must be unique for all connections
 * on the session.
937 938 939 940 941
 *
 * Since we do not support MCS, cid will normally be zero. In some cases
 * for software iscsi we could be trying to preallocate a connection struct
 * in which case there could be two connection structs and cid would be
 * non-zero.
942
 */
943
struct iscsi_cls_conn *
944
iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid)
945 946 947
{
	struct iscsi_transport *transport = session->transport;
	struct iscsi_cls_conn *conn;
M
Mike Christie 已提交
948
	unsigned long flags;
949 950
	int err;

951
	conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL);
952 953
	if (!conn)
		return NULL;
954
	if (dd_size)
955 956 957 958
		conn->dd_data = &conn[1];

	INIT_LIST_HEAD(&conn->conn_list);
	conn->transport = transport;
959
	conn->cid = cid;
960 961 962

	/* this is released in the dev's release function */
	if (!get_device(&session->dev))
963
		goto free_conn;
964

965
	dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid);
966 967 968 969
	conn->dev.parent = &session->dev;
	conn->dev.release = iscsi_conn_release;
	err = device_register(&conn->dev);
	if (err) {
970 971
		iscsi_cls_session_printk(KERN_ERR, session, "could not "
					 "register connection's dev\n");
972 973 974
		goto release_parent_ref;
	}
	transport_register_device(&conn->dev);
M
Mike Christie 已提交
975 976 977 978 979

	spin_lock_irqsave(&connlock, flags);
	list_add(&conn->conn_list, &connlist);
	conn->active = 1;
	spin_unlock_irqrestore(&connlock, flags);
980 981

	ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n");
982 983 984 985 986 987 988 989 990 991 992 993 994
	return conn;

release_parent_ref:
	put_device(&session->dev);
free_conn:
	kfree(conn);
	return NULL;
}

EXPORT_SYMBOL_GPL(iscsi_create_conn);

/**
 * iscsi_destroy_conn - destroy iscsi class connection
995
 * @conn: iscsi cls session
996
 *
M
Mike Christie 已提交
997
 * This can be called from a LLD or iscsi_transport.
998
 */
999 1000
int iscsi_destroy_conn(struct iscsi_cls_conn *conn)
{
M
Mike Christie 已提交
1001 1002 1003 1004 1005 1006 1007
	unsigned long flags;

	spin_lock_irqsave(&connlock, flags);
	conn->active = 0;
	list_del(&conn->conn_list);
	spin_unlock_irqrestore(&connlock, flags);

1008
	transport_unregister_device(&conn->dev);
1009
	ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n");
1010 1011 1012 1013 1014 1015 1016 1017
	device_unregister(&conn->dev);
	return 0;
}
EXPORT_SYMBOL_GPL(iscsi_destroy_conn);

/*
 * iscsi interface functions
 */
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
static struct iscsi_internal *
iscsi_if_transport_lookup(struct iscsi_transport *tt)
{
	struct iscsi_internal *priv;
	unsigned long flags;

	spin_lock_irqsave(&iscsi_transport_lock, flags);
	list_for_each_entry(priv, &iscsi_transports, list) {
		if (tt == priv->iscsi_transport) {
			spin_unlock_irqrestore(&iscsi_transport_lock, flags);
			return priv;
		}
	}
	spin_unlock_irqrestore(&iscsi_transport_lock, flags);
	return NULL;
}
L
Linus Torvalds 已提交
1034

1035
static int
1036
iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp)
1037
{
1038
	return nlmsg_multicast(nls, skb, 0, group, gfp);
L
Linus Torvalds 已提交
1039 1040
}

1041
int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr,
1042
		   char *data, uint32_t data_size)
L
Linus Torvalds 已提交
1043
{
1044 1045 1046 1047
	struct nlmsghdr	*nlh;
	struct sk_buff *skb;
	struct iscsi_uevent *ev;
	char *pdu;
1048
	struct iscsi_internal *priv;
1049 1050 1051
	int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) +
			      data_size);

1052 1053 1054 1055
	priv = iscsi_if_transport_lookup(conn->transport);
	if (!priv)
		return -EINVAL;

1056
	skb = alloc_skb(len, GFP_ATOMIC);
1057
	if (!skb) {
1058
		iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED);
1059 1060
		iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver "
				      "control PDU: OOM\n");
1061 1062
		return -ENOMEM;
	}
L
Linus Torvalds 已提交
1063

1064
	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
1065 1066 1067 1068
	ev = NLMSG_DATA(nlh);
	memset(ev, 0, sizeof(*ev));
	ev->transport_handle = iscsi_handle(conn->transport);
	ev->type = ISCSI_KEVENT_RECV_PDU;
1069 1070
	ev->r.recv_req.cid = conn->cid;
	ev->r.recv_req.sid = iscsi_conn_get_sid(conn);
1071 1072 1073
	pdu = (char*)ev + sizeof(*ev);
	memcpy(pdu, hdr, sizeof(struct iscsi_hdr));
	memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size);
L
Linus Torvalds 已提交
1074

1075
	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
L
Linus Torvalds 已提交
1076
}
1077
EXPORT_SYMBOL_GPL(iscsi_recv_pdu);
L
Linus Torvalds 已提交
1078

1079 1080 1081 1082 1083 1084 1085 1086 1087
int iscsi_offload_mesg(struct Scsi_Host *shost,
		       struct iscsi_transport *transport, uint32_t type,
		       char *data, uint16_t data_size)
{
	struct nlmsghdr	*nlh;
	struct sk_buff *skb;
	struct iscsi_uevent *ev;
	int len = NLMSG_SPACE(sizeof(*ev) + data_size);

1088
	skb = alloc_skb(len, GFP_ATOMIC);
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
	if (!skb) {
		printk(KERN_ERR "can not deliver iscsi offload message:OOM\n");
		return -ENOMEM;
	}

	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
	ev = NLMSG_DATA(nlh);
	memset(ev, 0, sizeof(*ev));
	ev->type = type;
	ev->transport_handle = iscsi_handle(transport);
	switch (type) {
	case ISCSI_KEVENT_PATH_REQ:
		ev->r.req_path.host_no = shost->host_no;
		break;
	case ISCSI_KEVENT_IF_DOWN:
		ev->r.notify_if_down.host_no = shost->host_no;
		break;
	}

	memcpy((char *)ev + sizeof(*ev), data, data_size);

1110
	return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC);
1111 1112 1113
}
EXPORT_SYMBOL_GPL(iscsi_offload_mesg);

1114
void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error)
L
Linus Torvalds 已提交
1115
{
1116 1117 1118
	struct nlmsghdr	*nlh;
	struct sk_buff	*skb;
	struct iscsi_uevent *ev;
1119
	struct iscsi_internal *priv;
1120 1121
	int len = NLMSG_SPACE(sizeof(*ev));

1122 1123 1124 1125
	priv = iscsi_if_transport_lookup(conn->transport);
	if (!priv)
		return;

1126
	skb = alloc_skb(len, GFP_ATOMIC);
1127
	if (!skb) {
1128 1129
		iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored "
				      "conn error (%d)\n", error);
1130 1131 1132
		return;
	}

1133
	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
1134 1135 1136 1137
	ev = NLMSG_DATA(nlh);
	ev->transport_handle = iscsi_handle(conn->transport);
	ev->type = ISCSI_KEVENT_CONN_ERROR;
	ev->r.connerror.error = error;
1138 1139
	ev->r.connerror.cid = conn->cid;
	ev->r.connerror.sid = iscsi_conn_get_sid(conn);
L
Linus Torvalds 已提交
1140

1141
	iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC);
L
Linus Torvalds 已提交
1142

1143 1144
	iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n",
			      error);
1145
}
1146
EXPORT_SYMBOL_GPL(iscsi_conn_error_event);
1147 1148

static int
1149 1150
iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi,
		    void *payload, int size)
1151 1152 1153 1154 1155 1156 1157
{
	struct sk_buff	*skb;
	struct nlmsghdr	*nlh;
	int len = NLMSG_SPACE(size);
	int flags = multi ? NLM_F_MULTI : 0;
	int t = done ? NLMSG_DONE : type;

1158
	skb = alloc_skb(len, GFP_ATOMIC);
1159 1160 1161 1162
	if (!skb) {
		printk(KERN_ERR "Could not allocate skb to send reply.\n");
		return -ENOMEM;
	}
1163

1164
	nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0);
1165 1166
	nlh->nlmsg_flags = flags;
	memcpy(NLMSG_DATA(nlh), payload, size);
1167
	return iscsi_multicast_skb(skb, group, GFP_ATOMIC);
L
Linus Torvalds 已提交
1168 1169
}

1170
static int
1171
iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
1172 1173 1174 1175 1176 1177 1178
{
	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
	struct iscsi_stats *stats;
	struct sk_buff *skbstat;
	struct iscsi_cls_conn *conn;
	struct nlmsghdr	*nlhstat;
	struct iscsi_uevent *evstat;
1179
	struct iscsi_internal *priv;
1180 1181 1182 1183 1184
	int len = NLMSG_SPACE(sizeof(*ev) +
			      sizeof(struct iscsi_stats) +
			      sizeof(struct iscsi_stats_custom) *
			      ISCSI_STATS_CUSTOM_MAX);
	int err = 0;
1185

1186 1187 1188 1189
	priv = iscsi_if_transport_lookup(transport);
	if (!priv)
		return -EINVAL;

1190
	conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid);
1191 1192
	if (!conn)
		return -EEXIST;
1193

1194 1195
	do {
		int actual_size;
1196

1197
		skbstat = alloc_skb(len, GFP_ATOMIC);
1198
		if (!skbstat) {
1199 1200
			iscsi_cls_conn_printk(KERN_ERR, conn, "can not "
					      "deliver stats: OOM\n");
1201 1202 1203
			return -ENOMEM;
		}

1204
		nlhstat = __nlmsg_put(skbstat, 0, 0, 0,
1205 1206 1207 1208 1209
				      (len - sizeof(*nlhstat)), 0);
		evstat = NLMSG_DATA(nlhstat);
		memset(evstat, 0, sizeof(*evstat));
		evstat->transport_handle = iscsi_handle(conn->transport);
		evstat->type = nlh->nlmsg_type;
1210 1211 1212 1213
		evstat->u.get_stats.cid =
			ev->u.get_stats.cid;
		evstat->u.get_stats.sid =
			ev->u.get_stats.sid;
1214 1215 1216 1217
		stats = (struct iscsi_stats *)
			((char*)evstat + sizeof(*evstat));
		memset(stats, 0, sizeof(*stats));

1218
		transport->get_stats(conn, stats);
1219 1220 1221 1222 1223 1224
		actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) +
					  sizeof(struct iscsi_stats) +
					  sizeof(struct iscsi_stats_custom) *
					  stats->custom_length);
		actual_size -= sizeof(*nlhstat);
		actual_size = NLMSG_LENGTH(actual_size);
1225
		skb_trim(skbstat, NLMSG_ALIGN(actual_size));
1226 1227
		nlhstat->nlmsg_len = actual_size;

1228 1229
		err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID,
					  GFP_ATOMIC);
1230 1231 1232
	} while (err < 0 && err != -ECONNREFUSED);

	return err;
1233 1234
}

1235
/**
M
Mike Christie 已提交
1236 1237 1238
 * iscsi_session_event - send session destr. completion event
 * @session: iscsi class session
 * @event: type of event
1239
 */
M
Mike Christie 已提交
1240 1241
int iscsi_session_event(struct iscsi_cls_session *session,
			enum iscsi_uevent_e event)
1242 1243 1244 1245 1246 1247 1248 1249
{
	struct iscsi_internal *priv;
	struct Scsi_Host *shost;
	struct iscsi_uevent *ev;
	struct sk_buff  *skb;
	struct nlmsghdr *nlh;
	int rc, len = NLMSG_SPACE(sizeof(*ev));

M
Mike Christie 已提交
1250
	priv = iscsi_if_transport_lookup(session->transport);
1251 1252 1253 1254
	if (!priv)
		return -EINVAL;
	shost = iscsi_session_to_shost(session);

1255
	skb = alloc_skb(len, GFP_KERNEL);
1256
	if (!skb) {
1257 1258 1259
		iscsi_cls_session_printk(KERN_ERR, session,
					 "Cannot notify userspace of session "
					 "event %u\n", event);
1260 1261 1262
		return -ENOMEM;
	}

1263
	nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0);
1264
	ev = NLMSG_DATA(nlh);
M
Mike Christie 已提交
1265
	ev->transport_handle = iscsi_handle(session->transport);
1266

M
Mike Christie 已提交
1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
	ev->type = event;
	switch (event) {
	case ISCSI_KEVENT_DESTROY_SESSION:
		ev->r.d_session.host_no = shost->host_no;
		ev->r.d_session.sid = session->sid;
		break;
	case ISCSI_KEVENT_CREATE_SESSION:
		ev->r.c_session_ret.host_no = shost->host_no;
		ev->r.c_session_ret.sid = session->sid;
		break;
	case ISCSI_KEVENT_UNBIND_SESSION:
		ev->r.unbind_session.host_no = shost->host_no;
		ev->r.unbind_session.sid = session->sid;
		break;
	default:
1282 1283
		iscsi_cls_session_printk(KERN_ERR, session, "Invalid event "
					 "%u.\n", event);
M
Mike Christie 已提交
1284
		kfree_skb(skb);
1285 1286 1287 1288 1289 1290 1291
		return -EINVAL;
	}

	/*
	 * this will occur if the daemon is not up, so we just warn
	 * the user and when the daemon is restarted it will handle it
	 */
1292
	rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL);
1293
	if (rc == -ESRCH)
1294 1295 1296 1297
		iscsi_cls_session_printk(KERN_ERR, session,
					 "Cannot notify userspace of session "
					 "event %u. Check iscsi daemon\n",
					 event);
1298 1299 1300

	ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n",
				event, rc);
1301 1302
	return rc;
}
M
Mike Christie 已提交
1303
EXPORT_SYMBOL_GPL(iscsi_session_event);
1304

1305
static int
1306 1307
iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep,
			struct iscsi_uevent *ev, uint32_t initial_cmdsn,
1308
			uint16_t cmds_max, uint16_t queue_depth)
1309 1310
{
	struct iscsi_transport *transport = priv->iscsi_transport;
1311
	struct iscsi_cls_session *session;
1312
	struct Scsi_Host *shost;
1313

1314
	session = transport->create_session(ep, cmds_max, queue_depth,
1315
					    initial_cmdsn);
1316
	if (!session)
1317
		return -ENOMEM;
1318

1319 1320
	shost = iscsi_session_to_shost(session);
	ev->r.c_session_ret.host_no = shost->host_no;
1321
	ev->r.c_session_ret.sid = session->sid;
1322 1323
	ISCSI_DBG_TRANS_SESSION(session,
				"Completed creating transport session\n");
1324 1325 1326 1327
	return 0;
}

static int
1328
iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
1329
{
1330
	struct iscsi_cls_conn *conn;
1331
	struct iscsi_cls_session *session;
1332

1333 1334
	session = iscsi_session_lookup(ev->u.c_conn.sid);
	if (!session) {
1335
		printk(KERN_ERR "iscsi: invalid session %d.\n",
1336
		       ev->u.c_conn.sid);
1337
		return -EINVAL;
1338
	}
1339

1340
	conn = transport->create_conn(session, ev->u.c_conn.cid);
1341
	if (!conn) {
1342 1343
		iscsi_cls_session_printk(KERN_ERR, session,
					 "couldn't create a new connection.");
1344
		return -ENOMEM;
1345
	}
1346

1347 1348
	ev->r.c_conn_ret.sid = session->sid;
	ev->r.c_conn_ret.cid = conn->cid;
1349 1350

	ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n");
1351
	return 0;
L
Linus Torvalds 已提交
1352 1353
}

1354 1355 1356
static int
iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
1357
	struct iscsi_cls_conn *conn;
1358

1359
	conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
1360
	if (!conn)
1361
		return -EINVAL;
1362

1363
	ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n");
1364 1365
	if (transport->destroy_conn)
		transport->destroy_conn(conn);
1366

1367
	return 0;
1368 1369
}

1370 1371 1372 1373 1374 1375
static int
iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
	char *data = (char*)ev + sizeof(*ev);
	struct iscsi_cls_conn *conn;
	struct iscsi_cls_session *session;
1376
	int err = 0, value = 0;
1377 1378 1379 1380 1381 1382 1383

	session = iscsi_session_lookup(ev->u.set_param.sid);
	conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
	if (!conn || !session)
		return -EINVAL;

	switch (ev->u.set_param.param) {
M
Mike Christie 已提交
1384
	case ISCSI_PARAM_SESS_RECOVERY_TMO:
1385
		sscanf(data, "%d", &value);
1386
		session->recovery_tmo = value;
M
Mike Christie 已提交
1387
		break;
1388
	default:
1389 1390
		err = transport->set_param(conn, ev->u.set_param.param,
					   data, ev->u.set_param.len);
1391 1392 1393 1394 1395
	}

	return err;
}

1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
static int iscsi_if_ep_connect(struct iscsi_transport *transport,
			       struct iscsi_uevent *ev, int msg_type)
{
	struct iscsi_endpoint *ep;
	struct sockaddr *dst_addr;
	struct Scsi_Host *shost = NULL;
	int non_blocking, err = 0;

	if (!transport->ep_connect)
		return -EINVAL;

	if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) {
		shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no);
		if (!shost) {
			printk(KERN_ERR "ep connect failed. Could not find "
			       "host no %u\n",
			       ev->u.ep_connect_through_host.host_no);
			return -ENODEV;
		}
		non_blocking = ev->u.ep_connect_through_host.non_blocking;
	} else
		non_blocking = ev->u.ep_connect.non_blocking;

	dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
	ep = transport->ep_connect(shost, dst_addr, non_blocking);
	if (IS_ERR(ep)) {
		err = PTR_ERR(ep);
		goto release_host;
	}

	ev->r.ep_connect_ret.handle = ep->id;
release_host:
	if (shost)
		scsi_host_put(shost);
	return err;
}

1433 1434 1435 1436
static int
iscsi_if_transport_ep(struct iscsi_transport *transport,
		      struct iscsi_uevent *ev, int msg_type)
{
1437
	struct iscsi_endpoint *ep;
1438 1439 1440
	int rc = 0;

	switch (msg_type) {
1441
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
1442
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
1443
		rc = iscsi_if_ep_connect(transport, ev, msg_type);
1444 1445 1446 1447 1448
		break;
	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
		if (!transport->ep_poll)
			return -EINVAL;

1449 1450 1451 1452 1453
		ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle);
		if (!ep)
			return -EINVAL;

		ev->r.retcode = transport->ep_poll(ep,
1454 1455 1456 1457 1458 1459
						   ev->u.ep_poll.timeout_ms);
		break;
	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
		if (!transport->ep_disconnect)
			return -EINVAL;

1460 1461 1462 1463 1464
		ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle);
		if (!ep)
			return -EINVAL;

		transport->ep_disconnect(ep);
1465 1466 1467 1468 1469
		break;
	}
	return rc;
}

1470 1471 1472 1473
static int
iscsi_tgt_dscvr(struct iscsi_transport *transport,
		struct iscsi_uevent *ev)
{
1474
	struct Scsi_Host *shost;
1475
	struct sockaddr *dst_addr;
1476
	int err;
1477 1478 1479 1480

	if (!transport->tgt_dscvr)
		return -EINVAL;

1481
	shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no);
1482
	if (!shost) {
1483 1484 1485 1486 1487 1488
		printk(KERN_ERR "target discovery could not find host no %u\n",
		       ev->u.tgt_dscvr.host_no);
		return -ENODEV;
	}


1489
	dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
1490 1491 1492 1493
	err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type,
				   ev->u.tgt_dscvr.enable, dst_addr);
	scsi_host_put(shost);
	return err;
1494 1495
}

1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
static int
iscsi_set_host_param(struct iscsi_transport *transport,
		     struct iscsi_uevent *ev)
{
	char *data = (char*)ev + sizeof(*ev);
	struct Scsi_Host *shost;
	int err;

	if (!transport->set_host_param)
		return -ENOSYS;

	shost = scsi_host_lookup(ev->u.set_host_param.host_no);
1508
	if (!shost) {
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
		printk(KERN_ERR "set_host_param could not find host no %u\n",
		       ev->u.set_host_param.host_no);
		return -ENODEV;
	}

	err = transport->set_host_param(shost, ev->u.set_host_param.param,
					data, ev->u.set_host_param.len);
	scsi_host_put(shost);
	return err;
}

1520
static int
1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
	struct Scsi_Host *shost;
	struct iscsi_path *params;
	int err;

	if (!transport->set_path)
		return -ENOSYS;

	shost = scsi_host_lookup(ev->u.set_path.host_no);
	if (!shost) {
		printk(KERN_ERR "set path could not find host no %u\n",
		       ev->u.set_path.host_no);
		return -ENODEV;
	}

	params = (struct iscsi_path *)((char *)ev + sizeof(*ev));
	err = transport->set_path(shost, params);

	scsi_host_put(shost);
	return err;
}

static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group)
1546 1547 1548 1549 1550
{
	int err = 0;
	struct iscsi_uevent *ev = NLMSG_DATA(nlh);
	struct iscsi_transport *transport = NULL;
	struct iscsi_internal *priv;
1551 1552
	struct iscsi_cls_session *session;
	struct iscsi_cls_conn *conn;
1553
	struct iscsi_endpoint *ep = NULL;
1554

1555 1556 1557 1558 1559
	if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE)
		*group = ISCSI_NL_GRP_UIP;
	else
		*group = ISCSI_NL_GRP_ISCSID;

1560 1561 1562 1563 1564
	priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle));
	if (!priv)
		return -EINVAL;
	transport = priv->iscsi_transport;

1565 1566 1567
	if (!try_module_get(transport->owner))
		return -EINVAL;

1568 1569
	switch (nlh->nlmsg_type) {
	case ISCSI_UEVENT_CREATE_SESSION:
1570
		err = iscsi_if_create_session(priv, ep, ev,
1571 1572 1573 1574 1575
					      ev->u.c_session.initial_cmdsn,
					      ev->u.c_session.cmds_max,
					      ev->u.c_session.queue_depth);
		break;
	case ISCSI_UEVENT_CREATE_BOUND_SESSION:
1576
		ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle);
1577 1578 1579 1580
		if (!ep) {
			err = -EINVAL;
			break;
		}
1581 1582

		err = iscsi_if_create_session(priv, ep, ev,
1583 1584 1585
					ev->u.c_bound_session.initial_cmdsn,
					ev->u.c_bound_session.cmds_max,
					ev->u.c_bound_session.queue_depth);
1586 1587
		break;
	case ISCSI_UEVENT_DESTROY_SESSION:
1588
		session = iscsi_session_lookup(ev->u.d_session.sid);
M
Mike Christie 已提交
1589
		if (session)
1590
			transport->destroy_session(session);
M
Mike Christie 已提交
1591 1592 1593 1594 1595 1596
		else
			err = -EINVAL;
		break;
	case ISCSI_UEVENT_UNBIND_SESSION:
		session = iscsi_session_lookup(ev->u.d_session.sid);
		if (session)
1597 1598
			scsi_queue_work(iscsi_session_to_shost(session),
					&session->unbind_work);
M
Mike Christie 已提交
1599
		else
1600
			err = -EINVAL;
1601 1602 1603 1604 1605 1606 1607 1608
		break;
	case ISCSI_UEVENT_CREATE_CONN:
		err = iscsi_if_create_conn(transport, ev);
		break;
	case ISCSI_UEVENT_DESTROY_CONN:
		err = iscsi_if_destroy_conn(transport, ev);
		break;
	case ISCSI_UEVENT_BIND_CONN:
1609 1610
		session = iscsi_session_lookup(ev->u.b_conn.sid);
		conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid);
1611 1612 1613

		if (session && conn)
			ev->r.retcode =	transport->bind_conn(session, conn,
1614
					ev->u.b_conn.transport_eph,
1615 1616 1617
					ev->u.b_conn.is_leading);
		else
			err = -EINVAL;
1618 1619
		break;
	case ISCSI_UEVENT_SET_PARAM:
1620
		err = iscsi_set_param(transport, ev);
1621 1622
		break;
	case ISCSI_UEVENT_START_CONN:
1623
		conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid);
1624 1625 1626 1627
		if (conn)
			ev->r.retcode = transport->start_conn(conn);
		else
			err = -EINVAL;
1628 1629
		break;
	case ISCSI_UEVENT_STOP_CONN:
1630
		conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid);
1631 1632 1633 1634
		if (conn)
			transport->stop_conn(conn, ev->u.stop_conn.flag);
		else
			err = -EINVAL;
1635 1636
		break;
	case ISCSI_UEVENT_SEND_PDU:
1637
		conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid);
1638 1639 1640 1641 1642 1643 1644
		if (conn)
			ev->r.retcode =	transport->send_pdu(conn,
				(struct iscsi_hdr*)((char*)ev + sizeof(*ev)),
				(char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size,
				ev->u.send_pdu.data_size);
		else
			err = -EINVAL;
1645 1646
		break;
	case ISCSI_UEVENT_GET_STATS:
1647
		err = iscsi_if_get_stats(transport, nlh);
1648
		break;
1649 1650 1651
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT:
	case ISCSI_UEVENT_TRANSPORT_EP_POLL:
	case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
1652
	case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST:
1653 1654
		err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
		break;
1655 1656 1657
	case ISCSI_UEVENT_TGT_DSCVR:
		err = iscsi_tgt_dscvr(transport, ev);
		break;
1658 1659 1660
	case ISCSI_UEVENT_SET_HOST_PARAM:
		err = iscsi_set_host_param(transport, ev);
		break;
1661 1662 1663
	case ISCSI_UEVENT_PATH_UPDATE:
		err = iscsi_set_path(transport, ev);
		break;
1664
	default:
1665
		err = -ENOSYS;
1666 1667 1668
		break;
	}

1669
	module_put(transport->owner);
1670 1671 1672
	return err;
}

1673
/*
1674 1675
 * Get message from skb.  Each message is processed by iscsi_if_recv_msg.
 * Malformed skbs with wrong lengths or invalid creds are not processed.
1676
 */
1677
static void
1678
iscsi_if_rx(struct sk_buff *skb)
1679
{
1680
	mutex_lock(&rx_queue_mutex);
1681 1682 1683 1684 1685
	while (skb->len >= NLMSG_SPACE(0)) {
		int err;
		uint32_t rlen;
		struct nlmsghdr	*nlh;
		struct iscsi_uevent *ev;
1686
		uint32_t group;
1687 1688 1689 1690 1691

		nlh = nlmsg_hdr(skb);
		if (nlh->nlmsg_len < sizeof(*nlh) ||
		    skb->len < nlh->nlmsg_len) {
			break;
1692 1693
		}

1694 1695 1696 1697
		ev = NLMSG_DATA(nlh);
		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
		if (rlen > skb->len)
			rlen = skb->len;
1698

1699
		err = iscsi_if_recv_msg(skb, nlh, &group);
1700 1701 1702
		if (err) {
			ev->type = ISCSI_KEVENT_IF_ERROR;
			ev->iferror = err;
1703
		}
1704 1705 1706 1707 1708 1709 1710 1711 1712
		do {
			/*
			 * special case for GET_STATS:
			 * on success - sending reply and stats from
			 * inside of if_recv_msg(),
			 * on error - fall through.
			 */
			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
				break;
1713
			err = iscsi_if_send_reply(group, nlh->nlmsg_seq,
1714 1715 1716
				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
		} while (err < 0 && err != -ECONNREFUSED);
		skb_pull(skb, rlen);
1717
	}
1718
	mutex_unlock(&rx_queue_mutex);
1719
}
L
Linus Torvalds 已提交
1720

1721
#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store)		\
1722
struct device_attribute dev_attr_##_prefix##_##_name =	\
1723 1724
	__ATTR(_name,_mode,_show,_store)

L
Linus Torvalds 已提交
1725
/*
1726
 * iSCSI connection attrs
L
Linus Torvalds 已提交
1727
 */
1728
#define iscsi_conn_attr_show(param)					\
1729
static ssize_t								\
1730 1731
show_conn_param_##param(struct device *dev, 				\
			struct device_attribute *attr, char *buf)	\
1732
{									\
1733
	struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent);	\
1734
	struct iscsi_transport *t = conn->transport;			\
1735
	return t->get_conn_param(conn, param, buf);			\
1736 1737
}

1738 1739 1740
#define iscsi_conn_attr(field, param)					\
	iscsi_conn_attr_show(param)					\
static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param,	\
1741
			NULL);
1742

1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753
iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
1754 1755
iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO);
iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO);
L
Linus Torvalds 已提交
1756 1757

/*
1758
 * iSCSI session attrs
L
Linus Torvalds 已提交
1759
 */
1760
#define iscsi_session_attr_show(param, perm)				\
1761
static ssize_t								\
1762 1763
show_session_param_##param(struct device *dev,				\
			   struct device_attribute *attr, char *buf)	\
1764
{									\
1765 1766
	struct iscsi_cls_session *session = 				\
		iscsi_dev_to_session(dev->parent);			\
1767
	struct iscsi_transport *t = session->transport;			\
1768 1769 1770
									\
	if (perm && !capable(CAP_SYS_ADMIN))				\
		return -EACCES;						\
1771
	return t->get_session_param(session, param, buf);		\
1772 1773
}

1774 1775
#define iscsi_session_attr(field, param, perm)				\
	iscsi_session_attr_show(param, perm)				\
1776
static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
1777 1778
			NULL);

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792
iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0);
iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0);
iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0);
iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0);
iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0);
iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0);
iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0);
iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0);
iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0);
iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0);
iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1);
iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1);
iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1);
iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1);
1793 1794 1795
iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0);
iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0);
iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0);
1796
iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0);
1797
iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0);
1798 1799
iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0);
iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0);
L
Linus Torvalds 已提交
1800

1801
static ssize_t
1802 1803
show_priv_session_state(struct device *dev, struct device_attribute *attr,
			char *buf)
1804
{
1805
	struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent);
1806 1807 1808 1809 1810
	return sprintf(buf, "%s\n", iscsi_session_state_name(session->state));
}
static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state,
			NULL);

1811 1812
#define iscsi_priv_session_attr_show(field, format)			\
static ssize_t								\
1813 1814
show_priv_session_##field(struct device *dev, 				\
			  struct device_attribute *attr, char *buf)	\
1815
{									\
1816 1817
	struct iscsi_cls_session *session = 				\
			iscsi_dev_to_session(dev->parent);		\
1818 1819
	if (session->field == -1)					\
		return sprintf(buf, "off\n");				\
1820 1821 1822
	return sprintf(buf, format"\n", session->field);		\
}

1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847
#define iscsi_priv_session_attr_store(field)				\
static ssize_t								\
store_priv_session_##field(struct device *dev,				\
			   struct device_attribute *attr,		\
			   const char *buf, size_t count)		\
{									\
	int val;							\
	char *cp;							\
	struct iscsi_cls_session *session =				\
		iscsi_dev_to_session(dev->parent);			\
	if ((session->state == ISCSI_SESSION_FREE) ||			\
	    (session->state == ISCSI_SESSION_FAILED))			\
		return -EBUSY;						\
	if (strncmp(buf, "off", 3) == 0)				\
		session->field = -1;					\
	else {								\
		val = simple_strtoul(buf, &cp, 0);			\
		if (*cp != '\0' && *cp != '\n')				\
			return -EINVAL;					\
		session->field = val;					\
	}								\
	return count;							\
}

#define iscsi_priv_session_rw_attr(field, format)			\
1848
	iscsi_priv_session_attr_show(field, format)			\
1849 1850 1851 1852 1853
	iscsi_priv_session_attr_store(field)				\
static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUGO,		\
			show_priv_session_##field,			\
			store_priv_session_##field)
iscsi_priv_session_rw_attr(recovery_tmo, "%d");
1854

1855 1856 1857 1858 1859
/*
 * iSCSI host attrs
 */
#define iscsi_host_attr_show(param)					\
static ssize_t								\
1860 1861
show_host_param_##param(struct device *dev, 				\
			struct device_attribute *attr, char *buf)	\
1862
{									\
1863
	struct Scsi_Host *shost = transport_class_to_shost(dev);	\
1864 1865 1866 1867 1868 1869 1870 1871 1872
	struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \
	return priv->iscsi_transport->get_host_param(shost, param, buf); \
}

#define iscsi_host_attr(field, param)					\
	iscsi_host_attr_show(param)					\
static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param,	\
			NULL);

1873
iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME);
1874
iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS);
1875
iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS);
1876
iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME);
1877

1878 1879
#define SETUP_PRIV_SESSION_RD_ATTR(field)				\
do {									\
1880
	priv->session_attrs[count] = &dev_attr_priv_sess_##field; \
1881 1882 1883
	count++;							\
} while (0)

1884 1885 1886 1887 1888
#define SETUP_PRIV_SESSION_RW_ATTR(field)				\
do {									\
	priv->session_attrs[count] = &dev_attr_priv_sess_##field;	\
	count++;							\
} while (0)
1889

1890 1891 1892
#define SETUP_SESSION_RD_ATTR(field, param_flag)			\
do {									\
	if (tt->param_mask & param_flag) {				\
1893
		priv->session_attrs[count] = &dev_attr_sess_##field; \
L
Linus Torvalds 已提交
1894
		count++;						\
1895 1896 1897 1898 1899 1900
	}								\
} while (0)

#define SETUP_CONN_RD_ATTR(field, param_flag)				\
do {									\
	if (tt->param_mask & param_flag) {				\
1901
		priv->conn_attrs[count] = &dev_attr_conn_##field; \
1902 1903 1904
		count++;						\
	}								\
} while (0)
L
Linus Torvalds 已提交
1905

1906 1907 1908
#define SETUP_HOST_RD_ATTR(field, param_flag)				\
do {									\
	if (tt->host_param_mask & param_flag) {				\
1909
		priv->host_attrs[count] = &dev_attr_host_##field; \
1910 1911 1912 1913
		count++;						\
	}								\
} while (0)

1914 1915
static int iscsi_session_match(struct attribute_container *cont,
			   struct device *dev)
L
Linus Torvalds 已提交
1916
{
1917
	struct iscsi_cls_session *session;
L
Linus Torvalds 已提交
1918
	struct Scsi_Host *shost;
1919 1920 1921 1922
	struct iscsi_internal *priv;

	if (!iscsi_is_session_dev(dev))
		return 0;
L
Linus Torvalds 已提交
1923

1924 1925
	session = iscsi_dev_to_session(dev);
	shost = iscsi_session_to_shost(session);
1926
	if (!shost->transportt)
L
Linus Torvalds 已提交
1927 1928
		return 0;

1929 1930
	priv = to_iscsi_internal(shost->transportt);
	if (priv->session_cont.ac.class != &iscsi_session_class.class)
L
Linus Torvalds 已提交
1931 1932
		return 0;

1933
	return &priv->session_cont.ac == cont;
L
Linus Torvalds 已提交
1934 1935
}

1936 1937 1938
static int iscsi_conn_match(struct attribute_container *cont,
			   struct device *dev)
{
1939 1940
	struct iscsi_cls_session *session;
	struct iscsi_cls_conn *conn;
L
Linus Torvalds 已提交
1941
	struct Scsi_Host *shost;
1942
	struct iscsi_internal *priv;
L
Linus Torvalds 已提交
1943

1944
	if (!iscsi_is_conn_dev(dev))
L
Linus Torvalds 已提交
1945 1946
		return 0;

1947 1948 1949 1950
	conn = iscsi_dev_to_conn(dev);
	session = iscsi_dev_to_session(conn->dev.parent);
	shost = iscsi_session_to_shost(session);

1951
	if (!shost->transportt)
L
Linus Torvalds 已提交
1952 1953
		return 0;

1954 1955 1956
	priv = to_iscsi_internal(shost->transportt);
	if (priv->conn_cont.ac.class != &iscsi_connection_class.class)
		return 0;
L
Linus Torvalds 已提交
1957

1958 1959 1960
	return &priv->conn_cont.ac == cont;
}

M
Mike Christie 已提交
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
static int iscsi_host_match(struct attribute_container *cont,
			    struct device *dev)
{
	struct Scsi_Host *shost;
	struct iscsi_internal *priv;

	if (!scsi_is_host_device(dev))
		return 0;

	shost = dev_to_shost(dev);
	if (!shost->transportt  ||
	    shost->transportt->host_attrs.ac.class != &iscsi_host_class.class)
		return 0;

        priv = to_iscsi_internal(shost->transportt);
        return &priv->t.host_attrs.ac == cont;
}

1979 1980
struct scsi_transport_template *
iscsi_register_transport(struct iscsi_transport *tt)
1981 1982 1983 1984 1985 1986 1987 1988 1989
{
	struct iscsi_internal *priv;
	unsigned long flags;
	int count = 0, err;

	BUG_ON(!tt);

	priv = iscsi_if_transport_lookup(tt);
	if (priv)
1990
		return NULL;
1991

J
Jes Sorensen 已提交
1992
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
1993
	if (!priv)
1994
		return NULL;
1995 1996
	INIT_LIST_HEAD(&priv->list);
	priv->iscsi_transport = tt;
M
Mike Christie 已提交
1997
	priv->t.user_scan = iscsi_user_scan;
1998
	priv->t.create_work_queue = 1;
1999

2000
	priv->dev.class = &iscsi_transport_class;
2001
	dev_set_name(&priv->dev, "%s", tt->name);
2002
	err = device_register(&priv->dev);
2003 2004 2005
	if (err)
		goto free_priv;

2006
	err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group);
2007
	if (err)
2008
		goto unregister_dev;
2009

M
Mike Christie 已提交
2010 2011 2012 2013
	/* host parameters */
	priv->t.host_attrs.ac.attrs = &priv->host_attrs[0];
	priv->t.host_attrs.ac.class = &iscsi_host_class.class;
	priv->t.host_attrs.ac.match = iscsi_host_match;
2014
	priv->t.host_size = sizeof(struct iscsi_cls_host);
M
Mike Christie 已提交
2015 2016
	transport_container_register(&priv->t.host_attrs);

2017
	SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME);
2018
	SETUP_HOST_RD_ATTR(ipaddress, ISCSI_HOST_IPADDRESS);
2019
	SETUP_HOST_RD_ATTR(hwaddress, ISCSI_HOST_HWADDRESS);
2020
	SETUP_HOST_RD_ATTR(initiatorname, ISCSI_HOST_INITIATOR_NAME);
2021 2022 2023 2024
	BUG_ON(count > ISCSI_HOST_ATTRS);
	priv->host_attrs[count] = NULL;
	count = 0;

2025 2026 2027 2028 2029
	/* connection parameters */
	priv->conn_cont.ac.attrs = &priv->conn_attrs[0];
	priv->conn_cont.ac.class = &iscsi_connection_class.class;
	priv->conn_cont.ac.match = iscsi_conn_match;
	transport_container_register(&priv->conn_cont);
L
Linus Torvalds 已提交
2030

2031 2032 2033 2034 2035 2036 2037 2038
	SETUP_CONN_RD_ATTR(max_recv_dlength, ISCSI_MAX_RECV_DLENGTH);
	SETUP_CONN_RD_ATTR(max_xmit_dlength, ISCSI_MAX_XMIT_DLENGTH);
	SETUP_CONN_RD_ATTR(header_digest, ISCSI_HDRDGST_EN);
	SETUP_CONN_RD_ATTR(data_digest, ISCSI_DATADGST_EN);
	SETUP_CONN_RD_ATTR(ifmarker, ISCSI_IFMARKER_EN);
	SETUP_CONN_RD_ATTR(ofmarker, ISCSI_OFMARKER_EN);
	SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
	SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
2039
	SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
2040 2041
	SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
	SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
2042 2043
	SETUP_CONN_RD_ATTR(ping_tmo, ISCSI_PING_TMO);
	SETUP_CONN_RD_ATTR(recv_tmo, ISCSI_RECV_TMO);
2044 2045 2046

	BUG_ON(count > ISCSI_CONN_ATTRS);
	priv->conn_attrs[count] = NULL;
L
Linus Torvalds 已提交
2047 2048
	count = 0;

2049 2050 2051 2052 2053 2054
	/* session parameters */
	priv->session_cont.ac.attrs = &priv->session_attrs[0];
	priv->session_cont.ac.class = &iscsi_session_class.class;
	priv->session_cont.ac.match = iscsi_session_match;
	transport_container_register(&priv->session_cont);

2055 2056 2057 2058 2059 2060 2061 2062
	SETUP_SESSION_RD_ATTR(initial_r2t, ISCSI_INITIAL_R2T_EN);
	SETUP_SESSION_RD_ATTR(max_outstanding_r2t, ISCSI_MAX_R2T);
	SETUP_SESSION_RD_ATTR(immediate_data, ISCSI_IMM_DATA_EN);
	SETUP_SESSION_RD_ATTR(first_burst_len, ISCSI_FIRST_BURST);
	SETUP_SESSION_RD_ATTR(max_burst_len, ISCSI_MAX_BURST);
	SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
	SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
	SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
2063 2064
	SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
	SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
2065 2066 2067 2068
	SETUP_SESSION_RD_ATTR(password, ISCSI_USERNAME);
	SETUP_SESSION_RD_ATTR(password_in, ISCSI_USERNAME_IN);
	SETUP_SESSION_RD_ATTR(username, ISCSI_PASSWORD);
	SETUP_SESSION_RD_ATTR(username_in, ISCSI_PASSWORD_IN);
2069
	SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT);
2070 2071
	SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO);
	SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO);
2072
	SETUP_SESSION_RD_ATTR(tgt_reset_tmo,ISCSI_TGT_RESET_TMO);
2073 2074
	SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME);
	SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME);
2075
	SETUP_SESSION_RD_ATTR(targetalias, ISCSI_TARGET_ALIAS);
2076
	SETUP_PRIV_SESSION_RW_ATTR(recovery_tmo);
2077
	SETUP_PRIV_SESSION_RD_ATTR(state);
2078

2079 2080 2081 2082 2083 2084 2085 2086
	BUG_ON(count > ISCSI_SESSION_ATTRS);
	priv->session_attrs[count] = NULL;

	spin_lock_irqsave(&iscsi_transport_lock, flags);
	list_add(&priv->list, &iscsi_transports);
	spin_unlock_irqrestore(&iscsi_transport_lock, flags);

	printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name);
2087
	return &priv->t;
L
Linus Torvalds 已提交
2088

2089 2090
unregister_dev:
	device_unregister(&priv->dev);
2091
	return NULL;
2092 2093
free_priv:
	kfree(priv);
2094
	return NULL;
L
Linus Torvalds 已提交
2095
}
2096 2097 2098 2099 2100 2101 2102 2103 2104
EXPORT_SYMBOL_GPL(iscsi_register_transport);

int iscsi_unregister_transport(struct iscsi_transport *tt)
{
	struct iscsi_internal *priv;
	unsigned long flags;

	BUG_ON(!tt);

2105
	mutex_lock(&rx_queue_mutex);
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115

	priv = iscsi_if_transport_lookup(tt);
	BUG_ON (!priv);

	spin_lock_irqsave(&iscsi_transport_lock, flags);
	list_del(&priv->list);
	spin_unlock_irqrestore(&iscsi_transport_lock, flags);

	transport_container_unregister(&priv->conn_cont);
	transport_container_unregister(&priv->session_cont);
M
Mike Christie 已提交
2116
	transport_container_unregister(&priv->t.host_attrs);
2117

2118 2119
	sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group);
	device_unregister(&priv->dev);
2120
	mutex_unlock(&rx_queue_mutex);
L
Linus Torvalds 已提交
2121

2122 2123 2124
	return 0;
}
EXPORT_SYMBOL_GPL(iscsi_unregister_transport);
L
Linus Torvalds 已提交
2125 2126 2127

static __init int iscsi_transport_init(void)
{
2128
	int err;
L
Linus Torvalds 已提交
2129

M
Meelis Roos 已提交
2130
	printk(KERN_INFO "Loading iSCSI transport class v%s.\n",
2131 2132
		ISCSI_TRANSPORT_VERSION);

2133 2134
	atomic_set(&iscsi_session_nr, 0);

2135
	err = class_register(&iscsi_transport_class);
L
Linus Torvalds 已提交
2136 2137
	if (err)
		return err;
2138

2139
	err = class_register(&iscsi_endpoint_class);
2140 2141 2142
	if (err)
		goto unregister_transport_class;

2143 2144 2145 2146
	err = transport_class_register(&iscsi_host_class);
	if (err)
		goto unregister_endpoint_class;

M
Mike Christie 已提交
2147 2148 2149 2150
	err = transport_class_register(&iscsi_connection_class);
	if (err)
		goto unregister_host_class;

2151 2152 2153 2154
	err = transport_class_register(&iscsi_session_class);
	if (err)
		goto unregister_conn_class;

2155 2156
	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx,
				    NULL, THIS_MODULE);
2157 2158
	if (!nls) {
		err = -ENOBUFS;
2159
		goto unregister_session_class;
2160 2161
	}

2162 2163 2164 2165
	iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh");
	if (!iscsi_eh_timer_workq)
		goto release_nls;

2166
	return 0;
2167

2168
release_nls:
2169
	netlink_kernel_release(nls);
2170 2171 2172 2173
unregister_session_class:
	transport_class_unregister(&iscsi_session_class);
unregister_conn_class:
	transport_class_unregister(&iscsi_connection_class);
M
Mike Christie 已提交
2174 2175
unregister_host_class:
	transport_class_unregister(&iscsi_host_class);
2176 2177
unregister_endpoint_class:
	class_unregister(&iscsi_endpoint_class);
2178 2179 2180
unregister_transport_class:
	class_unregister(&iscsi_transport_class);
	return err;
L
Linus Torvalds 已提交
2181 2182 2183 2184
}

static void __exit iscsi_transport_exit(void)
{
2185
	destroy_workqueue(iscsi_eh_timer_workq);
2186
	netlink_kernel_release(nls);
2187 2188
	transport_class_unregister(&iscsi_connection_class);
	transport_class_unregister(&iscsi_session_class);
M
Mike Christie 已提交
2189
	transport_class_unregister(&iscsi_host_class);
2190
	class_unregister(&iscsi_endpoint_class);
2191
	class_unregister(&iscsi_transport_class);
L
Linus Torvalds 已提交
2192 2193 2194 2195 2196
}

module_init(iscsi_transport_init);
module_exit(iscsi_transport_exit);

2197 2198 2199 2200
MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
	      "Dmitry Yusupov <dmitry_yus@yahoo.com>, "
	      "Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI Transport Interface");
L
Linus Torvalds 已提交
2201
MODULE_LICENSE("GPL");
2202
MODULE_VERSION(ISCSI_TRANSPORT_VERSION);