sas_discover.c 15.5 KB
Newer Older
James Bottomley's avatar
James Bottomley committed
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>
James Bottomley's avatar
James Bottomley committed
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>
James Bottomley's avatar
James Bottomley committed
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;
	}
James Bottomley's avatar
James Bottomley committed
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;
James Bottomley's avatar
James Bottomley committed
72

73
	dev = sas_alloc_device();
James Bottomley's avatar
James Bottomley committed
74
75
76
	if (!dev)
		return -ENOMEM;

77
	spin_lock_irq(&port->phy_list_lock);
James Bottomley's avatar
James Bottomley committed
78
	if (list_empty(&port->phy_list)) {
79
		spin_unlock_irq(&port->phy_list_lock);
80
		sas_put_device(dev);
James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
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;
James Bottomley's avatar
James Bottomley committed
97
		else
98
			dev->dev_type = SAS_SATA_DEV;
99
		dev->tproto = SAS_PROTOCOL_SATA;
James Bottomley's avatar
James Bottomley committed
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;
James Bottomley's avatar
James Bottomley committed
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:
James Bottomley's avatar
James Bottomley committed
120
121
		rphy = sas_end_device_alloc(port->port);
		break;
122
	case SAS_EDGE_EXPANDER_DEVICE:
James Bottomley's avatar
James Bottomley committed
123
124
125
		rphy = sas_expander_alloc(port->port,
					  SAS_EDGE_EXPANDER_DEVICE);
		break;
126
	case SAS_FANOUT_EXPANDER_DEVICE:
James Bottomley's avatar
James Bottomley committed
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;
James Bottomley's avatar
James Bottomley committed
139
	}
140

James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
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);
	}
James Bottomley's avatar
James Bottomley committed
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);

James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
193
	}
194
195
	set_bit(SAS_DEV_FOUND, &dev->state);
	kref_get(&dev->kref);
James Bottomley's avatar
James Bottomley committed
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)) {
James Bottomley's avatar
James Bottomley committed
210
		i->dft->lldd_dev_gone(dev);
211
212
		sas_put_device(dev);
	}
James Bottomley's avatar
James Bottomley committed
213
214
}

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);
219
	struct asd_sas_port *port = ev->port;
James Bottomley's avatar
James Bottomley committed
220

221
222
	clear_bit(DISCE_PROBE, &port->disc.pending);

223
224
	/* devices must be domain members before link recovery and probe */
	list_for_each_entry(dev, &port->disco_list, disco_list_node) {
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);
228
	}
229

230
	sas_probe_sata(port);
231

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
239
240
241
			list_del_init(&dev->disco_list_node);
	}
}
James Bottomley's avatar
James Bottomley committed
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);
}

James Bottomley's avatar
James Bottomley committed
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)
296
297
		return res;
	sas_discover_event(dev->port, DISCE_PROBE);
James Bottomley's avatar
James Bottomley committed
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)
James Bottomley's avatar
James Bottomley committed
330
{
331
332
	struct sas_ha_struct *ha = port->ha;

James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
354
355
}

356
static void sas_destruct_devices(struct work_struct *work)
James Bottomley's avatar
James Bottomley committed
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);

James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
388
389
390
	}
}

391
void sas_unregister_domain_devices(struct asd_sas_port *port, int gone)
James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
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);
}

James Bottomley's avatar
James Bottomley committed
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.
 */
David Howells's avatar
David Howells committed
439
static void sas_discover_domain(struct work_struct *work)
James Bottomley's avatar
James Bottomley committed
440
{
441
	struct domain_device *dev;
James Bottomley's avatar
James Bottomley committed
442
	int error = 0;
443
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
David Howells's avatar
David Howells committed
444
	struct asd_sas_port *port = ev->port;
James Bottomley's avatar
James Bottomley committed
445

446
	clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending);
James Bottomley's avatar
James Bottomley committed
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;
James Bottomley's avatar
James Bottomley committed
455
456

	SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
457
		    task_pid_nr(current));
James Bottomley's avatar
James Bottomley committed
458

459
	switch (dev->dev_type) {
460
	case SAS_END_DEVICE:
461
		error = sas_discover_end_dev(dev);
James Bottomley's avatar
James Bottomley committed
462
		break;
463
464
	case SAS_EDGE_EXPANDER_DEVICE:
	case SAS_FANOUT_EXPANDER_DEVICE:
465
		error = sas_discover_root_expander(dev);
James Bottomley's avatar
James Bottomley committed
466
		break;
467
468
	case SAS_SATA_DEV:
	case SAS_SATA_PM:
469
#ifdef CONFIG_SCSI_SAS_ATA
470
		error = sas_discover_sata(dev);
James Bottomley's avatar
James Bottomley committed
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
James Bottomley's avatar
James Bottomley committed
476
	default:
477
		error = -ENXIO;
478
		SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
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);
James Bottomley's avatar
James Bottomley committed
495
496
}

David Howells's avatar
David Howells committed
497
static void sas_revalidate_domain(struct work_struct *work)
James Bottomley's avatar
James Bottomley committed
498
499
{
	int res = 0;
500
	struct sas_discovery_event *ev = to_sas_discovery_event(work);
David Howells's avatar
David Howells committed
501
	struct asd_sas_port *port = ev->port;
502
	struct sas_ha_struct *ha = port->ha;
503
	struct domain_device *ddev = port->port_dev;
504
505
506
507
508
509
510
511

	/* 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;
	}
James Bottomley's avatar
James Bottomley committed
512

513
	clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending);
James Bottomley's avatar
James Bottomley committed
514
515

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

518
519
520
	if (ddev && (ddev->dev_type == SAS_FANOUT_EXPANDER_DEVICE ||
		     ddev->dev_type == SAS_EDGE_EXPANDER_DEVICE))
		res = sas_ex_revalidate_domain(ddev);
James Bottomley's avatar
James Bottomley committed
521
522

	SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
523
		    port->id, task_pid_nr(current), res);
524
525
 out:
	mutex_unlock(&ha->disco_mutex);
James Bottomley's avatar
James Bottomley committed
526
527
528
529
}

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

530
static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw)
531
{
532
533
534
535
536
537
	/* 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);
538
539
540
}

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

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

James Bottomley's avatar
James Bottomley committed
553
554
555
556
557
558
559
560
561
562
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);

563
	sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha);
James Bottomley's avatar
James Bottomley committed
564
565
566
567
568
569
570
571
572
573
574
575
576
577

	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;

David Howells's avatar
David Howells committed
578
	static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = {
James Bottomley's avatar
James Bottomley committed
579
580
		[DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
		[DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
581
		[DISCE_PROBE] = sas_probe_devices,
582
583
		[DISCE_SUSPEND] = sas_suspend_devices,
		[DISCE_RESUME] = sas_resume_devices,
584
		[DISCE_DESTRUCT] = sas_destruct_devices,
James Bottomley's avatar
James Bottomley committed
585
586
587
	};

	disc->pending = 0;
David Howells's avatar
David Howells committed
588
	for (i = 0; i < DISC_NUM_EVENTS; i++) {
589
		INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]);
David Howells's avatar
David Howells committed
590
591
		disc->disc_work[i].port = port;
	}
James Bottomley's avatar
James Bottomley committed
592
}