sas_discover.c 15.4 KB
Newer Older
J
James Bottomley 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * Serial Attached SCSI (SAS) Discover process
 *
 * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
 *
 * This file is licensed under GPLv2.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include <linux/scatterlist.h>
26
#include <linux/slab.h>
27
#include <linux/async.h>
J
James Bottomley 已提交
28 29 30 31 32 33
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
#include "sas_internal.h"

#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_sas.h>
34
#include <scsi/sas_ata.h>
J
James Bottomley 已提交
35 36 37 38 39 40
#include "../scsi_sas_internal.h"

/* ---------- Basic task processing for discovery purposes ---------- */

void sas_init_dev(struct domain_device *dev)
{
41
	switch (dev->dev_type) {
42
	case SAS_END_DEVICE:
43
		INIT_LIST_HEAD(&dev->ssp_dev.eh_list_node);
44
		break;
45 46
	case SAS_EDGE_EXPANDER_DEVICE:
	case SAS_FANOUT_EXPANDER_DEVICE:
47 48 49 50 51 52
		INIT_LIST_HEAD(&dev->ex_dev.children);
		mutex_init(&dev->ex_dev.cmd_mutex);
		break;
	default:
		break;
	}
J
James Bottomley 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
}

/* ---------- Domain device discovery ---------- */

/**
 * sas_get_port_device -- Discover devices which caused port creation
 * @port: pointer to struct sas_port of interest
 *
 * Devices directly attached to a HA port, have no parent.  This is
 * how we know they are (domain) "root" devices.  All other devices
 * do, and should have their "parent" pointer set appropriately as
 * soon as a child device is discovered.
 */
static int sas_get_port_device(struct asd_sas_port *port)
{
	struct asd_sas_phy *phy;
	struct sas_rphy *rphy;
	struct domain_device *dev;
71
	int rc = -ENODEV;
J
James Bottomley 已提交
72

73
	dev = sas_alloc_device();
J
James Bottomley 已提交
74 75 76
	if (!dev)
		return -ENOMEM;

77
	spin_lock_irq(&port->phy_list_lock);
J
James Bottomley 已提交
78
	if (list_empty(&port->phy_list)) {
79
		spin_unlock_irq(&port->phy_list_lock);
80
		sas_put_device(dev);
J
James Bottomley 已提交
81 82 83 84 85 86 87
		return -ENODEV;
	}
	phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
	spin_lock(&phy->frame_rcvd_lock);
	memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
					     (size_t)phy->frame_rcvd_size));
	spin_unlock(&phy->frame_rcvd_lock);
88
	spin_unlock_irq(&port->phy_list_lock);
J
James Bottomley 已提交
89 90 91 92 93 94 95

	if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
		struct dev_to_host_fis *fis =
			(struct dev_to_host_fis *) dev->frame_rcvd;
		if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
		    fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
		    && (fis->device & ~0x10) == 0)
96
			dev->dev_type = SAS_SATA_PM;
J
James Bottomley 已提交
97
		else
98
			dev->dev_type = SAS_SATA_DEV;
99
		dev->tproto = SAS_PROTOCOL_SATA;
J
James Bottomley 已提交
100 101 102 103 104 105 106 107 108 109
	} else {
		struct sas_identify_frame *id =
			(struct sas_identify_frame *) dev->frame_rcvd;
		dev->dev_type = id->dev_type;
		dev->iproto = id->initiator_bits;
		dev->tproto = id->target_bits;
	}

	sas_init_dev(dev);

110
	dev->port = port;
J
James Bottomley 已提交
111
	switch (dev->dev_type) {
112
	case SAS_SATA_DEV:
113 114 115 116 117 118
		rc = sas_ata_init(dev);
		if (rc) {
			rphy = NULL;
			break;
		}
		/* fall through */
119
	case SAS_END_DEVICE:
J
James Bottomley 已提交
120 121
		rphy = sas_end_device_alloc(port->port);
		break;
122
	case SAS_EDGE_EXPANDER_DEVICE:
J
James Bottomley 已提交
123 124 125
		rphy = sas_expander_alloc(port->port,
					  SAS_EDGE_EXPANDER_DEVICE);
		break;
126
	case SAS_FANOUT_EXPANDER_DEVICE:
J
James Bottomley 已提交
127 128 129 130 131 132 133 134 135 136
		rphy = sas_expander_alloc(port->port,
					  SAS_FANOUT_EXPANDER_DEVICE);
		break;
	default:
		printk("ERROR: Unidentified device type %d\n", dev->dev_type);
		rphy = NULL;
		break;
	}

	if (!rphy) {
137
		sas_put_device(dev);
138
		return rc;
J
James Bottomley 已提交
139
	}
140

J
James Bottomley 已提交
141 142 143 144 145 146 147 148 149 150 151 152 153
	rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
	memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
	sas_fill_in_rphy(dev, rphy);
	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
	port->port_dev = dev;
	dev->linkrate = port->linkrate;
	dev->min_linkrate = port->linkrate;
	dev->max_linkrate = port->linkrate;
	dev->pathways = port->num_phys;
	memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
	memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
	memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
	port->disc.max_level = 0;
154
	sas_device_set_phy(dev, port->port);
J
James Bottomley 已提交
155 156

	dev->rphy = rphy;
157
	get_device(&dev->rphy->dev);
158

159
	if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEVICE)
160 161 162 163 164 165
		list_add_tail(&dev->disco_list_node, &port->disco_list);
	else {
		spin_lock_irq(&port->dev_list_lock);
		list_add_tail(&dev->dev_list_node, &port->dev_list);
		spin_unlock_irq(&port->dev_list_lock);
	}
J
James Bottomley 已提交
166

167 168 169 170 171
	spin_lock_irq(&port->phy_list_lock);
	list_for_each_entry(phy, &port->phy_list, port_phy_el)
		sas_phy_set_target(phy, dev);
	spin_unlock_irq(&port->phy_list_lock);

J
James Bottomley 已提交
172 173 174 175 176 177 178 179 180 181 182 183
	return 0;
}

/* ---------- Discover and Revalidate ---------- */

int sas_notify_lldd_dev_found(struct domain_device *dev)
{
	int res = 0;
	struct sas_ha_struct *sas_ha = dev->port->ha;
	struct Scsi_Host *shost = sas_ha->core.shost;
	struct sas_internal *i = to_sas_internal(shost->transportt);

184 185 186 187 188 189 190 191 192
	if (!i->dft->lldd_dev_found)
		return 0;

	res = i->dft->lldd_dev_found(dev);
	if (res) {
		printk("sas: driver on pcidev %s cannot handle "
		       "device %llx, error:%d\n",
		       dev_name(sas_ha->dev),
		       SAS_ADDR(dev->sas_addr), res);
J
James Bottomley 已提交
193
	}
194 195
	set_bit(SAS_DEV_FOUND, &dev->state);
	kref_get(&dev->kref);
J
James Bottomley 已提交
196 197 198 199 200 201 202 203 204 205
	return res;
}


void sas_notify_lldd_dev_gone(struct domain_device *dev)
{
	struct sas_ha_struct *sas_ha = dev->port->ha;
	struct Scsi_Host *shost = sas_ha->core.shost;
	struct sas_internal *i = to_sas_internal(shost->transportt);

206 207 208 209
	if (!i->dft->lldd_dev_gone)
		return;

	if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
J
James Bottomley 已提交
210
		i->dft->lldd_dev_gone(dev);
211 212
		sas_put_device(dev);
	}
J
James Bottomley 已提交
213 214
}

D
Dan Williams 已提交
215 216 217
static void sas_probe_devices(struct work_struct *work)
{
	struct domain_device *dev, *n;
218
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
D
Dan Williams 已提交
219
	struct asd_sas_port *port = ev->port;
J
James Bottomley 已提交
220

D
Dan Williams 已提交
221 222
	clear_bit(DISCE_PROBE, &port->disc.pending);

D
Dan Williams 已提交
223 224
	/* devices must be domain members before link recovery and probe */
	list_for_each_entry(dev, &port->disco_list, disco_list_node) {
D
Dan Williams 已提交
225 226 227
		spin_lock_irq(&port->dev_list_lock);
		list_add_tail(&dev->dev_list_node, &port->dev_list);
		spin_unlock_irq(&port->dev_list_lock);
D
Dan Williams 已提交
228
	}
D
Dan Williams 已提交
229

D
Dan Williams 已提交
230
	sas_probe_sata(port);
D
Dan Williams 已提交
231

D
Dan Williams 已提交
232 233 234 235 236 237 238
	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) {
		int err;

		err = sas_rphy_add(dev->rphy);
		if (err)
			sas_fail_probe(dev, __func__, err);
		else
D
Dan Williams 已提交
239 240 241
			list_del_init(&dev->disco_list_node);
	}
}
J
James Bottomley 已提交
242

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
static void sas_suspend_devices(struct work_struct *work)
{
	struct asd_sas_phy *phy;
	struct domain_device *dev;
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
	struct asd_sas_port *port = ev->port;
	struct Scsi_Host *shost = port->ha->core.shost;
	struct sas_internal *si = to_sas_internal(shost->transportt);

	clear_bit(DISCE_SUSPEND, &port->disc.pending);

	sas_suspend_sata(port);

	/* lldd is free to forget the domain_device across the
	 * suspension, we force the issue here to keep the reference
	 * counts aligned
	 */
	list_for_each_entry(dev, &port->dev_list, dev_list_node)
		sas_notify_lldd_dev_gone(dev);

	/* we are suspending, so we know events are disabled and
	 * phy_list is not being mutated
	 */
	list_for_each_entry(phy, &port->phy_list, port_phy_el) {
		if (si->dft->lldd_port_formed)
			si->dft->lldd_port_deformed(phy);
		phy->suspended = 1;
		port->suspended = 1;
	}
}

static void sas_resume_devices(struct work_struct *work)
{
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
	struct asd_sas_port *port = ev->port;

	clear_bit(DISCE_RESUME, &port->disc.pending);

	sas_resume_sata(port);
}

J
James Bottomley 已提交
284 285 286 287 288 289 290 291 292 293 294 295
/**
 * sas_discover_end_dev -- discover an end device (SSP, etc)
 * @end: pointer to domain device of interest
 *
 * See comment in sas_discover_sata().
 */
int sas_discover_end_dev(struct domain_device *dev)
{
	int res;

	res = sas_notify_lldd_dev_found(dev);
	if (res)
D
Dan Williams 已提交
296 297
		return res;
	sas_discover_event(dev->port, DISCE_PROBE);
J
James Bottomley 已提交
298 299 300 301 302 303

	return 0;
}

/* ---------- Device registration and unregistration ---------- */

304 305 306 307
void sas_free_device(struct kref *kref)
{
	struct domain_device *dev = container_of(kref, typeof(*dev), kref);

308 309 310
	put_device(&dev->rphy->dev);
	dev->rphy = NULL;

311 312 313
	if (dev->parent)
		sas_put_device(dev->parent);

314 315 316
	sas_port_put_phy(dev->phy);
	dev->phy = NULL;

317
	/* remove the phys and ports, everything else should be gone */
318
	if (dev->dev_type == SAS_EDGE_EXPANDER_DEVICE || dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
319 320
		kfree(dev->ex_dev.ex_phy);

321 322 323 324 325
	if (dev_is_sata(dev) && dev->sata_dev.ap) {
		ata_sas_port_destroy(dev->sata_dev.ap);
		dev->sata_dev.ap = NULL;
	}

326 327 328
	kfree(dev);
}

329
static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev)
J
James Bottomley 已提交
330
{
331 332
	struct sas_ha_struct *ha = port->ha;

J
James Bottomley 已提交
333 334 335 336 337
	sas_notify_lldd_dev_gone(dev);
	if (!dev->parent)
		dev->port->port_dev = NULL;
	else
		list_del_init(&dev->siblings);
338 339

	spin_lock_irq(&port->dev_list_lock);
J
James Bottomley 已提交
340
	list_del_init(&dev->dev_list_node);
341 342
	if (dev_is_sata(dev))
		sas_ata_end_eh(dev->sata_dev.ap);
343
	spin_unlock_irq(&port->dev_list_lock);
344

345
	spin_lock_irq(&ha->lock);
346
	if (dev->dev_type == SAS_END_DEVICE &&
347 348 349 350 351 352
	    !list_empty(&dev->ssp_dev.eh_list_node)) {
		list_del_init(&dev->ssp_dev.eh_list_node);
		ha->eh_active--;
	}
	spin_unlock_irq(&ha->lock);

353
	sas_put_device(dev);
J
James Bottomley 已提交
354 355
}

356
static void sas_destruct_devices(struct work_struct *work)
J
James Bottomley 已提交
357
{
358
	struct domain_device *dev, *n;
359
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
360 361 362 363 364 365 366
	struct asd_sas_port *port = ev->port;

	clear_bit(DISCE_DESTRUCT, &port->disc.pending);

	list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) {
		list_del_init(&dev->disco_list_node);

J
James Bottomley 已提交
367 368
		sas_remove_children(&dev->rphy->dev);
		sas_rphy_delete(dev->rphy);
369 370 371 372 373 374 375 376 377 378 379 380
		sas_unregister_common_dev(port, dev);
	}
}

void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev)
{
	if (!test_bit(SAS_DEV_DESTROY, &dev->state) &&
	    !list_empty(&dev->disco_list_node)) {
		/* this rphy never saw sas_rphy_add */
		list_del_init(&dev->disco_list_node);
		sas_rphy_free(dev->rphy);
		sas_unregister_common_dev(port, dev);
381
		return;
382 383
	}

384
	if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) {
385 386 387
		sas_rphy_unlink(dev->rphy);
		list_move_tail(&dev->disco_list_node, &port->destroy_list);
		sas_discover_event(dev->port, DISCE_DESTRUCT);
J
James Bottomley 已提交
388 389 390
	}
}

391
void sas_unregister_domain_devices(struct asd_sas_port *port, int gone)
J
James Bottomley 已提交
392 393 394
{
	struct domain_device *dev, *n;

395 396 397
	list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) {
		if (gone)
			set_bit(SAS_DEV_GONE, &dev->state);
398
		sas_unregister_dev(port, dev);
399 400
	}

401 402
	list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node)
		sas_unregister_dev(port, dev);
J
James Bottomley 已提交
403 404 405 406 407

	port->port->rphy = NULL;

}

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
void sas_device_set_phy(struct domain_device *dev, struct sas_port *port)
{
	struct sas_ha_struct *ha;
	struct sas_phy *new_phy;

	if (!dev)
		return;

	ha = dev->port->ha;
	new_phy = sas_port_get_phy(port);

	/* pin and record last seen phy */
	spin_lock_irq(&ha->phy_port_lock);
	if (new_phy) {
		sas_port_put_phy(dev->phy);
		dev->phy = new_phy;
	}
	spin_unlock_irq(&ha->phy_port_lock);
}

J
James Bottomley 已提交
428 429 430 431 432 433 434 435 436 437 438
/* ---------- Discovery and Revalidation ---------- */

/**
 * sas_discover_domain -- discover the domain
 * @port: port to the domain of interest
 *
 * NOTE: this process _must_ quit (return) as soon as any connection
 * errors are encountered.  Connection recovery is done elsewhere.
 * Discover process only interrogates devices in order to discover the
 * domain.
 */
D
David Howells 已提交
439
static void sas_discover_domain(struct work_struct *work)
J
James Bottomley 已提交
440
{
441
	struct domain_device *dev;
J
James Bottomley 已提交
442
	int error = 0;
443
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
D
David Howells 已提交
444
	struct asd_sas_port *port = ev->port;
J
James Bottomley 已提交
445

446
	clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
J
James Bottomley 已提交
447 448

	if (port->port_dev)
449 450 451 452 453 454
		return;

	error = sas_get_port_device(port);
	if (error)
		return;
	dev = port->port_dev;
J
James Bottomley 已提交
455 456

	SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
457
		    task_pid_nr(current));
J
James Bottomley 已提交
458

459
	switch (dev->dev_type) {
460
	case SAS_END_DEVICE:
461
		error = sas_discover_end_dev(dev);
J
James Bottomley 已提交
462
		break;
463 464
	case SAS_EDGE_EXPANDER_DEVICE:
	case SAS_FANOUT_EXPANDER_DEVICE:
465
		error = sas_discover_root_expander(dev);
J
James Bottomley 已提交
466
		break;
467 468
	case SAS_SATA_DEV:
	case SAS_SATA_PM:
469
#ifdef CONFIG_SCSI_SAS_ATA
470
		error = sas_discover_sata(dev);
J
James Bottomley 已提交
471
		break;
472 473 474
#else
		SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n");
		/* Fall through */
475
#endif
J
James Bottomley 已提交
476
	default:
477
		error = -ENXIO;
478
		SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
J
James Bottomley 已提交
479 480 481 482
		break;
	}

	if (error) {
483
		sas_rphy_free(dev->rphy);
484
		list_del_init(&dev->disco_list_node);
485
		spin_lock_irq(&port->dev_list_lock);
486
		list_del_init(&dev->dev_list_node);
487
		spin_unlock_irq(&port->dev_list_lock);
488

489
		sas_put_device(dev);
J
James Bottomley 已提交
490 491 492 493
		port->port_dev = NULL;
	}

	SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
494
		    task_pid_nr(current), error);
J
James Bottomley 已提交
495 496
}

D
David Howells 已提交
497
static void sas_revalidate_domain(struct work_struct *work)
J
James Bottomley 已提交
498 499
{
	int res = 0;
500
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
D
David Howells 已提交
501
	struct asd_sas_port *port = ev->port;
502 503 504 505 506 507 508 509 510
	struct sas_ha_struct *ha = port->ha;

	/* prevent revalidation from finding sata links in recovery */
	mutex_lock(&ha->disco_mutex);
	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
		SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n",
			    port->id, task_pid_nr(current));
		goto out;
	}
J
James Bottomley 已提交
511

512
	clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending);
J
James Bottomley 已提交
513 514

	SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
515
		    task_pid_nr(current));
516

J
James Bottomley 已提交
517 518 519 520
	if (port->port_dev)
		res = sas_ex_revalidate_domain(port->port_dev);

	SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
521
		    port->id, task_pid_nr(current), res);
522 523
 out:
	mutex_unlock(&ha->disco_mutex);
J
James Bottomley 已提交
524 525 526 527
}

/* ---------- Events ---------- */

528
static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
529
{
530 531 532 533 534 535
	/* chained work is not subject to SA_HA_DRAINING or
	 * SAS_HA_REGISTERED, because it is either submitted in the
	 * workqueue, or known to be submitted from a context that is
	 * not racing against draining
	 */
	scsi_queue_work(ha->core.shost, &sw->work);
536 537 538
}

static void sas_chain_event(int event, unsigned long *pending,
539
			    struct sas_work *sw,
540 541 542 543 544
			    struct sas_ha_struct *ha)
{
	if (!test_and_set_bit(event, pending)) {
		unsigned long flags;

545
		spin_lock_irqsave(&ha->lock, flags);
546
		sas_chain_work(ha, sw);
547
		spin_unlock_irqrestore(&ha->lock, flags);
548 549 550
	}
}

J
James Bottomley 已提交
551 552 553 554 555 556 557 558 559 560
int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
{
	struct sas_discovery *disc;

	if (!port)
		return 0;
	disc = &port->disc;

	BUG_ON(ev >= DISC_NUM_EVENTS);

561
	sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha);
J
James Bottomley 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575

	return 0;
}

/**
 * sas_init_disc -- initialize the discovery struct in the port
 * @port: pointer to struct port
 *
 * Called when the ports are being initialized.
 */
void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
{
	int i;

D
David Howells 已提交
576
	static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
J
James Bottomley 已提交
577 578
		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
D
Dan Williams 已提交
579
		[DISCE_PROBE] = sas_probe_devices,
580 581
		[DISCE_SUSPEND] = sas_suspend_devices,
		[DISCE_RESUME] = sas_resume_devices,
582
		[DISCE_DESTRUCT] = sas_destruct_devices,
J
James Bottomley 已提交
583 584 585
	};

	disc->pending = 0;
D
David Howells 已提交
586
	for (i = 0; i < DISC_NUM_EVENTS; i++) {
587
		INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
D
David Howells 已提交
588 589
		disc->disc_work[i].port = port;
	}
J
James Bottomley 已提交
590
}