Blame view

drivers/scsi/scsi_transport_sas.c 51.8 KB
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1
  /*
a01256413   Christoph Hellwig   [SCSI] sas: add s...
2
   * Copyright (C) 2005-2006 Dell Inc.
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
3
4
5
6
7
8
   *	Released under GPL v2.
   *
   * Serial Attached SCSI (SAS) transport class.
   *
   * The SAS transport class contains common code to deal with SAS HBAs,
   * an aproximated representation of SAS topologies in the driver model,
b1c118121   Joe Perches   drivers/scsi/: Sp...
9
   * and various sysfs attributes to expose these topologies and management
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   * interfaces to userspace.
   *
   * In addition to the basic SCSI core objects this transport class
   * introduces two additional intermediate objects:  The SAS PHY
   * as represented by struct sas_phy defines an "outgoing" PHY on
   * a SAS HBA or Expander, and the SAS remote PHY represented by
   * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
   * end device.  Note that this is purely a software concept, the
   * underlying hardware for a PHY and a remote PHY is the exactly
   * the same.
   *
   * There is no concept of a SAS port in this code, users can see
   * what PHYs form a wide port based on the port_identifier attribute,
   * which is the same for all PHYs in a port.
   */
  
  #include <linux/init.h>
  #include <linux/module.h>
f6a570333   Al Viro   [PATCH] severing ...
28
  #include <linux/jiffies.h>
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
29
  #include <linux/err.h>
8c65b4a60   Tim Schmielau   [PATCH] fix remai...
30
31
  #include <linux/slab.h>
  #include <linux/string.h>
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
32
33
  #include <linux/blkdev.h>
  #include <linux/bsg.h>
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
34

e02f3f592   Christoph Hellwig   [SCSI] remove tar...
35
  #include <scsi/scsi.h>
ca18d6f76   Bart Van Assche   block: Make most ...
36
  #include <scsi/scsi_cmnd.h>
82ed4db49   Christoph Hellwig   block: split scsi...
37
  #include <scsi/scsi_request.h>
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
38
39
40
41
  #include <scsi/scsi_device.h>
  #include <scsi/scsi_host.h>
  #include <scsi/scsi_transport.h>
  #include <scsi/scsi_transport_sas.h>
d6159c17c   James Bottomley   [SCSI] expose sas...
42
  #include "scsi_sas_internal.h"
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
43
44
  struct sas_host_attrs {
  	struct list_head rphy_list;
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
45
  	struct mutex lock;
b6aff6695   James Bottomley   [SCSI] scsi_trans...
46
  	struct request_queue *q;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
47
  	u32 next_target_id;
79cb1819e   James Bottomley   [SCSI] add prelim...
48
  	u32 next_expander_id;
c9fefeb26   James Bottomley   [SCSI] scsi_trans...
49
  	int next_port_id;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
50
51
52
53
54
55
56
  };
  #define to_sas_host_attrs(host)	((struct sas_host_attrs *)(host)->shost_data)
  
  
  /*
   * Hack to allow attributes of the same name in different objects.
   */
ee959b00c   Tony Jones   SCSI: convert str...
57
58
  #define SAS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
  	struct device_attribute dev_attr_##_prefix##_##_name = \
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  	__ATTR(_name,_mode,_show,_store)
  
  
  /*
   * Pretty printing helpers
   */
  
  #define sas_bitfield_name_match(title, table)			\
  static ssize_t							\
  get_sas_##title##_names(u32 table_key, char *buf)		\
  {								\
  	char *prefix = "";					\
  	ssize_t len = 0;					\
  	int i;							\
  								\
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
74
  	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
75
76
77
78
79
80
81
82
83
84
  		if (table[i].value & table_key) {		\
  			len += sprintf(buf + len, "%s%s",	\
  				prefix, table[i].name);		\
  			prefix = ", ";				\
  		}						\
  	}							\
  	len += sprintf(buf + len, "
  ");			\
  	return len;						\
  }
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  #define sas_bitfield_name_set(title, table)			\
  static ssize_t							\
  set_sas_##title##_names(u32 *table_key, const char *buf)	\
  {								\
  	ssize_t len = 0;					\
  	int i;							\
  								\
  	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
  		len = strlen(table[i].name);			\
  		if (strncmp(buf, table[i].name, len) == 0 &&	\
  		    (buf[len] == '
  ' || buf[len] == '\0')) {	\
  			*table_key = table[i].value;		\
  			return 0;				\
  		}						\
  	}							\
  	return -EINVAL;						\
  }
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
103
104
105
106
107
108
109
  #define sas_bitfield_name_search(title, table)			\
  static ssize_t							\
  get_sas_##title##_names(u32 table_key, char *buf)		\
  {								\
  	ssize_t len = 0;					\
  	int i;							\
  								\
6391a1137   Tobias Klauser   [SCSI] drivers/sc...
110
  	for (i = 0; i < ARRAY_SIZE(table); i++) {		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  		if (table[i].value == table_key) {		\
  			len += sprintf(buf + len, "%s",		\
  				table[i].name);			\
  			break;					\
  		}						\
  	}							\
  	len += sprintf(buf + len, "
  ");			\
  	return len;						\
  }
  
  static struct {
  	u32		value;
  	char		*name;
  } sas_device_type_names[] = {
  	{ SAS_PHY_UNUSED,		"unused" },
  	{ SAS_END_DEVICE,		"end device" },
  	{ SAS_EDGE_EXPANDER_DEVICE,	"edge expander" },
  	{ SAS_FANOUT_EXPANDER_DEVICE,	"fanout expander" },
  };
  sas_bitfield_name_search(device_type, sas_device_type_names)
  
  
  static struct {
  	u32		value;
  	char		*name;
  } sas_protocol_names[] = {
  	{ SAS_PROTOCOL_SATA,		"sata" },
  	{ SAS_PROTOCOL_SMP,		"smp" },
  	{ SAS_PROTOCOL_STP,		"stp" },
  	{ SAS_PROTOCOL_SSP,		"ssp" },
  };
  sas_bitfield_name_match(protocol, sas_protocol_names)
  
  static struct {
  	u32		value;
  	char		*name;
  } sas_linkspeed_names[] = {
  	{ SAS_LINK_RATE_UNKNOWN,	"Unknown" },
  	{ SAS_PHY_DISABLED,		"Phy disabled" },
  	{ SAS_LINK_RATE_FAILED,		"Link Rate failed" },
  	{ SAS_SATA_SPINUP_HOLD,		"Spin-up hold" },
  	{ SAS_LINK_RATE_1_5_GBPS,	"1.5 Gbit" },
  	{ SAS_LINK_RATE_3_0_GBPS,	"3.0 Gbit" },
7e6dff62d   James Bottomley   [SCSI] add 6.0 Gb...
155
  	{ SAS_LINK_RATE_6_0_GBPS,	"6.0 Gbit" },
d84fd392b   Sreekanth Reddy   [SCSI] scsi_trans...
156
  	{ SAS_LINK_RATE_12_0_GBPS,	"12.0 Gbit" },
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
157
158
  };
  sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
159
  sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
160

0f88009d5   James Bottomley   [SCSI] scsi_trans...
161
162
163
164
165
166
167
168
169
170
  static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)
  {
  	struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
  	struct sas_end_device *rdev;
  
  	BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
  
  	rdev = rphy_to_end_device(rphy);
  	return rdev;
  }
651a01364   Christoph Hellwig   scsi: scsi_transp...
171
  static int sas_smp_dispatch(struct bsg_job *job)
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
172
  {
651a01364   Christoph Hellwig   scsi: scsi_transp...
173
174
  	struct Scsi_Host *shost = dev_to_shost(job->dev);
  	struct sas_rphy *rphy = NULL;
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
175

651a01364   Christoph Hellwig   scsi: scsi_transp...
176
177
  	if (!scsi_is_host_device(job->dev))
  		rphy = dev_to_rphy(job->dev);
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
178

651a01364   Christoph Hellwig   scsi: scsi_transp...
179
180
181
182
183
  	if (!job->req->next_rq) {
  		dev_warn(job->dev, "space for a smp response is missing
  ");
  		bsg_job_done(job, -EINVAL, 0);
  		return 0;
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
184
  	}
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
185

651a01364   Christoph Hellwig   scsi: scsi_transp...
186
187
  	to_sas_internal(shost->transportt)->f->smp_handler(job, shost, rphy);
  	return 0;
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
188
  }
93c20a59a   FUJITA Tomonori   [SCSI] scsi_trans...
189
190
191
192
193
194
195
196
197
  static void sas_host_release(struct device *dev)
  {
  	struct Scsi_Host *shost = dev_to_shost(dev);
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  	struct request_queue *q = sas_host->q;
  
  	if (q)
  		blk_cleanup_queue(q);
  }
39dca558a   James Bottomley   [SCSI] bsg: make ...
198
  static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
199
200
  {
  	struct request_queue *q;
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
201
202
203
204
205
206
  
  	if (!to_sas_internal(shost->transportt)->f->smp_handler) {
  		printk("%s can't handle SMP requests
  ", shost->hostt->name);
  		return 0;
  	}
39dca558a   James Bottomley   [SCSI] bsg: make ...
207
  	if (rphy) {
651a01364   Christoph Hellwig   scsi: scsi_transp...
208
209
210
211
212
  		q = bsg_setup_queue(&rphy->dev, dev_name(&rphy->dev),
  				sas_smp_dispatch, 0, NULL);
  		if (IS_ERR(q))
  			return PTR_ERR(q);
  		rphy->q = q;
39dca558a   James Bottomley   [SCSI] bsg: make ...
213
  	} else {
651a01364   Christoph Hellwig   scsi: scsi_transp...
214
215
216
217
218
219
220
221
  		char name[20];
  
  		snprintf(name, sizeof(name), "sas_host%d", shost->host_no);
  		q = bsg_setup_queue(&shost->shost_gendev, name,
  				sas_smp_dispatch, 0, sas_host_release);
  		if (IS_ERR(q))
  			return PTR_ERR(q);
  		to_sas_host_attrs(shost)->q = q;
39dca558a   James Bottomley   [SCSI] bsg: make ...
222
  	}
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
223

0bf6595ec   Christoph Hellwig   block: don't set ...
224
225
226
227
  	/*
  	 * by default assume old behaviour and bounce for any highmem page
  	 */
  	blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
75ad23bc0   Nick Piggin   block: make queue...
228
  	queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
9efc160f4   Bart Van Assche   block: Introduce ...
229
  	queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
230
  	return 0;
b6aff6695   James Bottomley   [SCSI] scsi_trans...
231
  }
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
232
233
234
  /*
   * SAS host attributes
   */
37be6eeb4   James Bottomley   [SCSI] SAS transp...
235
  static int sas_host_setup(struct transport_container *tc, struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
236
  			  struct device *cdev)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
237
238
239
240
241
  {
  	struct Scsi_Host *shost = dev_to_shost(dev);
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  
  	INIT_LIST_HEAD(&sas_host->rphy_list);
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
242
  	mutex_init(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
243
  	sas_host->next_target_id = 0;
79cb1819e   James Bottomley   [SCSI] add prelim...
244
  	sas_host->next_expander_id = 0;
c9fefeb26   James Bottomley   [SCSI] scsi_trans...
245
  	sas_host->next_port_id = 0;
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
246

39dca558a   James Bottomley   [SCSI] bsg: make ...
247
  	if (sas_bsg_initialize(shost, NULL))
7aa68e80b   FUJITA Tomonori   [SCSI] transport_...
248
249
250
  		dev_printk(KERN_ERR, dev, "fail to a bsg device %d
  ",
  			   shost->host_no);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
251
252
  	return 0;
  }
b6aff6695   James Bottomley   [SCSI] scsi_trans...
253
  static int sas_host_remove(struct transport_container *tc, struct device *dev,
ee959b00c   Tony Jones   SCSI: convert str...
254
  			   struct device *cdev)
b6aff6695   James Bottomley   [SCSI] scsi_trans...
255
256
  {
  	struct Scsi_Host *shost = dev_to_shost(dev);
651a01364   Christoph Hellwig   scsi: scsi_transp...
257
  	struct request_queue *q = to_sas_host_attrs(shost)->q;
b6aff6695   James Bottomley   [SCSI] scsi_trans...
258

651a01364   Christoph Hellwig   scsi: scsi_transp...
259
260
  	if (q)
  		bsg_unregister_queue(q);
b6aff6695   James Bottomley   [SCSI] scsi_trans...
261
262
  	return 0;
  }
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
263
  static DECLARE_TRANSPORT_CLASS(sas_host_class,
b6aff6695   James Bottomley   [SCSI] scsi_trans...
264
  		"sas_host", sas_host_setup, sas_host_remove, NULL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  
  static int sas_host_match(struct attribute_container *cont,
  			    struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  
  	if (!scsi_is_host_device(dev))
  		return 0;
  	shost = dev_to_shost(dev);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->t.host_attrs.ac == cont;
  }
  
  static int do_sas_phy_delete(struct device *dev, void *data)
  {
65c92b09a   James Bottomley   [SCSI] scsi_trans...
288
289
290
291
292
  	int pass = (int)(unsigned long)data;
  
  	if (pass == 0 && scsi_is_sas_port(dev))
  		sas_port_delete(dev_to_sas_port(dev));
  	else if (pass == 1 && scsi_is_sas_phy(dev))
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
293
294
295
296
297
  		sas_phy_delete(dev_to_phy(dev));
  	return 0;
  }
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
298
   * sas_remove_children  -  tear down a devices SAS data structures
65c92b09a   James Bottomley   [SCSI] scsi_trans...
299
300
301
302
303
304
305
306
307
308
309
310
   * @dev:	device belonging to the sas object
   *
   * Removes all SAS PHYs and remote PHYs for a given object
   */
  void sas_remove_children(struct device *dev)
  {
  	device_for_each_child(dev, (void *)0, do_sas_phy_delete);
  	device_for_each_child(dev, (void *)1, do_sas_phy_delete);
  }
  EXPORT_SYMBOL(sas_remove_children);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
311
   * sas_remove_host  -  tear down a Scsi_Host's SAS data structures
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
312
313
   * @shost:	Scsi Host that is torn down
   *
c5ce0abeb   Johannes Thumshirn   scsi: sas: move s...
314
315
316
317
318
   * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the
   * Scsi_Host as well.
   *
   * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is
   * already removed.
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
319
320
321
   */
  void sas_remove_host(struct Scsi_Host *shost)
  {
65c92b09a   James Bottomley   [SCSI] scsi_trans...
322
  	sas_remove_children(&shost->shost_gendev);
c5ce0abeb   Johannes Thumshirn   scsi: sas: move s...
323
  	scsi_remove_host(shost);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
324
325
  }
  EXPORT_SYMBOL(sas_remove_host);
0f88009d5   James Bottomley   [SCSI] scsi_trans...
326
  /**
bcf508c13   James Bottomley   scsi_transport_sa...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
   * sas_get_address - return the SAS address of the device
   * @sdev: scsi device
   *
   * Returns the SAS address of the scsi device
   */
  u64 sas_get_address(struct scsi_device *sdev)
  {
  	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
  
  	return rdev->rphy.identify.sas_address;
  }
  EXPORT_SYMBOL(sas_get_address);
  
  /**
0f88009d5   James Bottomley   [SCSI] scsi_trans...
341
342
343
344
345
346
347
348
349
350
351
352
353
354
   * sas_tlr_supported - checking TLR bit in vpd 0x90
   * @sdev: scsi device struct
   *
   * Check Transport Layer Retries are supported or not.
   * If vpd page 0x90 is present, TRL is supported.
   *
   */
  unsigned int
  sas_tlr_supported(struct scsi_device *sdev)
  {
  	const int vpd_len = 32;
  	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
  	char *buffer = kzalloc(vpd_len, GFP_KERNEL);
  	int ret = 0;
e1779b4ff   Bart Van Assche   scsi: scsi_transp...
355
356
  	if (!buffer)
  		goto out;
0f88009d5   James Bottomley   [SCSI] scsi_trans...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
  	if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
  		goto out;
  
  	/*
  	 * Magic numbers: the VPD Protocol page (0x90)
  	 * has a 4 byte header and then one entry per device port
  	 * the TLR bit is at offset 8 on each port entry
  	 * if we take the first port, that's at total offset 12
  	 */
  	ret = buffer[12] & 0x01;
  
   out:
  	kfree(buffer);
  	rdev->tlr_supported = ret;
  	return ret;
  
  }
  EXPORT_SYMBOL_GPL(sas_tlr_supported);
  
  /**
   * sas_disable_tlr - setting TLR flags
   * @sdev: scsi device struct
   *
   * Seting tlr_enabled flag to 0.
   *
   */
  void
  sas_disable_tlr(struct scsi_device *sdev)
  {
  	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
  
  	rdev->tlr_enabled = 0;
  }
  EXPORT_SYMBOL_GPL(sas_disable_tlr);
  
  /**
   * sas_enable_tlr - setting TLR flags
   * @sdev: scsi device struct
   *
   * Seting tlr_enabled flag 1.
   *
   */
  void sas_enable_tlr(struct scsi_device *sdev)
  {
  	unsigned int tlr_supported = 0;
  	tlr_supported  = sas_tlr_supported(sdev);
  
  	if (tlr_supported) {
  		struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
  
  		rdev->tlr_enabled = 1;
  	}
  
  	return;
  }
  EXPORT_SYMBOL_GPL(sas_enable_tlr);
  
  unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
  {
  	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
  	return rdev->tlr_enabled;
  }
  EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
420
421
  
  /*
65c92b09a   James Bottomley   [SCSI] scsi_trans...
422
   * SAS Phy attributes
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
423
424
425
426
   */
  
  #define sas_phy_show_simple(field, name, format_string, cast)		\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
427
428
  show_sas_phy_##name(struct device *dev, 				\
  		    struct device_attribute *attr, char *buf)		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
429
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
430
  	struct sas_phy *phy = transport_class_to_phy(dev);		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
431
432
433
434
435
436
  									\
  	return snprintf(buf, 20, format_string, cast phy->field);	\
  }
  
  #define sas_phy_simple_attr(field, name, format_string, type)		\
  	sas_phy_show_simple(field, name, format_string, (type))	\
ee959b00c   Tony Jones   SCSI: convert str...
437
  static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
438
439
440
  
  #define sas_phy_show_protocol(field, name)				\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
441
442
  show_sas_phy_##name(struct device *dev, 				\
  		    struct device_attribute *attr, char *buf)		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
443
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
444
  	struct sas_phy *phy = transport_class_to_phy(dev);		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
445
446
447
448
449
450
451
452
453
  									\
  	if (!phy->field)						\
  		return snprintf(buf, 20, "none
  ");			\
  	return get_sas_protocol_names(phy->field, buf);		\
  }
  
  #define sas_phy_protocol_attr(field, name)				\
  	sas_phy_show_protocol(field, name)				\
ee959b00c   Tony Jones   SCSI: convert str...
454
  static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
455
456
457
  
  #define sas_phy_show_linkspeed(field)					\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
458
459
  show_sas_phy_##field(struct device *dev, 				\
  		     struct device_attribute *attr, char *buf)		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
460
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
461
  	struct sas_phy *phy = transport_class_to_phy(dev);		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
462
463
464
  									\
  	return get_sas_linkspeed_names(phy->field, buf);		\
  }
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
465
466
467
  /* Fudge to tell if we're minimum or maximum */
  #define sas_phy_store_linkspeed(field)					\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
468
469
470
  store_sas_phy_##field(struct device *dev, 				\
  		      struct device_attribute *attr, 			\
  		      const char *buf,	size_t count)			\
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
471
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
472
  	struct sas_phy *phy = transport_class_to_phy(dev);		\
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
  	struct sas_internal *i = to_sas_internal(shost->transportt);	\
  	u32 value;							\
  	struct sas_phy_linkrates rates = {0};				\
  	int error;							\
  									\
  	error = set_sas_linkspeed_names(&value, buf);			\
  	if (error)							\
  		return error;						\
  	rates.field = value;						\
  	error = i->f->set_phy_speed(phy, &rates);			\
  									\
  	return error ? error : count;					\
  }
  
  #define sas_phy_linkspeed_rw_attr(field)				\
  	sas_phy_show_linkspeed(field)					\
  	sas_phy_store_linkspeed(field)					\
ee959b00c   Tony Jones   SCSI: convert str...
491
  static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field,		\
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
492
  	store_sas_phy_##field)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
493
494
  #define sas_phy_linkspeed_attr(field)					\
  	sas_phy_show_linkspeed(field)					\
ee959b00c   Tony Jones   SCSI: convert str...
495
  static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
496

d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
497

c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
498
499
  #define sas_phy_show_linkerror(field)					\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
500
501
  show_sas_phy_##field(struct device *dev, 				\
  		     struct device_attribute *attr, char *buf)		\
c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
502
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
503
  	struct sas_phy *phy = transport_class_to_phy(dev);		\
c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
504
505
506
507
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);	\
  	struct sas_internal *i = to_sas_internal(shost->transportt);	\
  	int error;							\
  									\
dd9fbb521   James Bottomley   [SCSI] make some ...
508
  	error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0;	\
c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
509
510
511
512
513
514
515
516
  	if (error)							\
  		return error;						\
  	return snprintf(buf, 20, "%u
  ", phy->field);			\
  }
  
  #define sas_phy_linkerror_attr(field)					\
  	sas_phy_show_linkerror(field)					\
ee959b00c   Tony Jones   SCSI: convert str...
517
  static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
518

c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
519
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
520
521
  show_sas_device_type(struct device *dev,
  		     struct device_attribute *attr, char *buf)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
522
  {
ee959b00c   Tony Jones   SCSI: convert str...
523
  	struct sas_phy *phy = transport_class_to_phy(dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
524
525
526
527
528
529
  
  	if (!phy->identify.device_type)
  		return snprintf(buf, 20, "none
  ");
  	return get_sas_device_type_names(phy->identify.device_type, buf);
  }
ee959b00c   Tony Jones   SCSI: convert str...
530
  static DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
531

ee959b00c   Tony Jones   SCSI: convert str...
532
  static ssize_t do_sas_phy_enable(struct device *dev,
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
533
534
  		size_t count, int enable)
  {
ee959b00c   Tony Jones   SCSI: convert str...
535
  	struct sas_phy *phy = transport_class_to_phy(dev);
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
536
537
538
539
540
541
542
543
544
545
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
  	int error;
  
  	error = i->f->phy_enable(phy, enable);
  	if (error)
  		return error;
  	phy->enabled = enable;
  	return count;
  };
ee959b00c   Tony Jones   SCSI: convert str...
546
547
548
  static ssize_t
  store_sas_phy_enable(struct device *dev, struct device_attribute *attr,
  		     const char *buf, size_t count)
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
549
550
551
552
553
554
  {
  	if (count < 1)
  		return -EINVAL;
  
  	switch (buf[0]) {
  	case '0':
ee959b00c   Tony Jones   SCSI: convert str...
555
  		do_sas_phy_enable(dev, count, 0);
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
556
557
  		break;
  	case '1':
ee959b00c   Tony Jones   SCSI: convert str...
558
  		do_sas_phy_enable(dev, count, 1);
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
559
560
561
562
563
564
565
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return count;
  }
ee959b00c   Tony Jones   SCSI: convert str...
566
567
568
  static ssize_t
  show_sas_phy_enable(struct device *dev, struct device_attribute *attr,
  		    char *buf)
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
569
  {
ee959b00c   Tony Jones   SCSI: convert str...
570
  	struct sas_phy *phy = transport_class_to_phy(dev);
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
571
572
573
  
  	return snprintf(buf, 20, "%d", phy->enabled);
  }
ee959b00c   Tony Jones   SCSI: convert str...
574
  static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
575
  			 store_sas_phy_enable);
ee959b00c   Tony Jones   SCSI: convert str...
576
577
  static ssize_t
  do_sas_phy_reset(struct device *dev, size_t count, int hard_reset)
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
578
  {
ee959b00c   Tony Jones   SCSI: convert str...
579
  	struct sas_phy *phy = transport_class_to_phy(dev);
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
580
581
582
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
  	int error;
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
583
584
585
  	error = i->f->phy_reset(phy, hard_reset);
  	if (error)
  		return error;
16d3db1b2   Dan Williams   [SCSI] scsi_trans...
586
  	phy->enabled = 1;
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
587
588
  	return count;
  };
ee959b00c   Tony Jones   SCSI: convert str...
589
590
591
  static ssize_t
  store_sas_link_reset(struct device *dev, struct device_attribute *attr,
  		     const char *buf, size_t count)
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
592
  {
ee959b00c   Tony Jones   SCSI: convert str...
593
  	return do_sas_phy_reset(dev, count, 0);
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
594
  }
ee959b00c   Tony Jones   SCSI: convert str...
595
  static DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
596

ee959b00c   Tony Jones   SCSI: convert str...
597
598
599
  static ssize_t
  store_sas_hard_reset(struct device *dev, struct device_attribute *attr,
  		     const char *buf, size_t count)
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
600
  {
ee959b00c   Tony Jones   SCSI: convert str...
601
  	return do_sas_phy_reset(dev, count, 1);
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
602
  }
ee959b00c   Tony Jones   SCSI: convert str...
603
  static DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
604

c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
605
606
607
608
609
610
611
612
613
  sas_phy_protocol_attr(identify.initiator_port_protocols,
  		initiator_port_protocols);
  sas_phy_protocol_attr(identify.target_port_protocols,
  		target_port_protocols);
  sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx
  ",
  		unsigned long long);
  sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d
  ", u8);
c9fefeb26   James Bottomley   [SCSI] scsi_trans...
614
615
  //sas_phy_simple_attr(port_identifier, port_identifier, "%d
  ", int);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
616
617
  sas_phy_linkspeed_attr(negotiated_linkrate);
  sas_phy_linkspeed_attr(minimum_linkrate_hw);
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
618
  sas_phy_linkspeed_rw_attr(minimum_linkrate);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
619
  sas_phy_linkspeed_attr(maximum_linkrate_hw);
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
620
  sas_phy_linkspeed_rw_attr(maximum_linkrate);
c3ee74c4e   Christoph Hellwig   [SCSI] scsi_trans...
621
622
623
624
  sas_phy_linkerror_attr(invalid_dword_count);
  sas_phy_linkerror_attr(running_disparity_error_count);
  sas_phy_linkerror_attr(loss_of_dword_sync_count);
  sas_phy_linkerror_attr(phy_reset_problem_count);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
625

0b3e09da1   Dan Williams   [SCSI] libsas: pe...
626
627
628
629
630
631
632
633
634
635
636
637
  static int sas_phy_setup(struct transport_container *tc, struct device *dev,
  			 struct device *cdev)
  {
  	struct sas_phy *phy = dev_to_phy(dev);
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
  
  	if (i->f->phy_setup)
  		i->f->phy_setup(phy);
  
  	return 0;
  }
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
638
639
  
  static DECLARE_TRANSPORT_CLASS(sas_phy_class,
0b3e09da1   Dan Williams   [SCSI] libsas: pe...
640
  		"sas_phy", sas_phy_setup, NULL, NULL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
  
  static int sas_phy_match(struct attribute_container *cont, struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  
  	if (!scsi_is_sas_phy(dev))
  		return 0;
  	shost = dev_to_shost(dev->parent);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->phy_attr_cont.ac == cont;
  }
  
  static void sas_phy_release(struct device *dev)
  {
  	struct sas_phy *phy = dev_to_phy(dev);
0b3e09da1   Dan Williams   [SCSI] libsas: pe...
664
665
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
666

0b3e09da1   Dan Williams   [SCSI] libsas: pe...
667
668
  	if (i->f->phy_release)
  		i->f->phy_release(phy);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
669
670
671
672
673
  	put_device(dev->parent);
  	kfree(phy);
  }
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
674
   * sas_phy_alloc  -  allocates and initialize a SAS PHY structure
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
675
   * @parent:	Parent device
d99ca4180   Moore, Eric   [SCSI] scsi_trans...
676
   * @number:	Phy index
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
677
678
679
680
681
682
683
684
685
686
687
688
   *
   * Allocates an SAS PHY structure.  It will be added in the device tree
   * below the device specified by @parent, which has to be either a Scsi_Host
   * or sas_rphy.
   *
   * Returns:
   *	SAS PHY allocated or %NULL if the allocation failed.
   */
  struct sas_phy *sas_phy_alloc(struct device *parent, int number)
  {
  	struct Scsi_Host *shost = dev_to_shost(parent);
  	struct sas_phy *phy;
24669f75a   Jes Sorensen   [SCSI] SCSI core ...
689
  	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
690
691
  	if (!phy)
  		return NULL;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
692

c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
693
  	phy->number = number;
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
694
  	phy->enabled = 1;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
695
696
697
698
  
  	device_initialize(&phy->dev);
  	phy->dev.parent = get_device(parent);
  	phy->dev.release = sas_phy_release;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
699
  	INIT_LIST_HEAD(&phy->port_siblings);
79cb1819e   James Bottomley   [SCSI] add prelim...
700
701
  	if (scsi_is_sas_expander_device(parent)) {
  		struct sas_rphy *rphy = dev_to_rphy(parent);
71610f55f   Kay Sievers   [SCSI] struct dev...
702
  		dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,
79cb1819e   James Bottomley   [SCSI] add prelim...
703
704
  			rphy->scsi_target_id, number);
  	} else
71610f55f   Kay Sievers   [SCSI] struct dev...
705
  		dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
706
707
708
709
710
711
712
713
  
  	transport_setup_device(&phy->dev);
  
  	return phy;
  }
  EXPORT_SYMBOL(sas_phy_alloc);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
714
   * sas_phy_add  -  add a SAS PHY to the device hierarchy
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
   * @phy:	The PHY to be added
   *
   * Publishes a SAS PHY to the rest of the system.
   */
  int sas_phy_add(struct sas_phy *phy)
  {
  	int error;
  
  	error = device_add(&phy->dev);
  	if (!error) {
  		transport_add_device(&phy->dev);
  		transport_configure_device(&phy->dev);
  	}
  
  	return error;
  }
  EXPORT_SYMBOL(sas_phy_add);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
734
   * sas_phy_free  -  free a SAS PHY
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
735
736
737
738
739
740
   * @phy:	SAS PHY to free
   *
   * Frees the specified SAS PHY.
   *
   * Note:
   *   This function must only be called on a PHY that has not
af901ca18   André Goddard Rosa   tree-wide: fix as...
741
   *   successfully been added using sas_phy_add().
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
742
743
744
745
   */
  void sas_phy_free(struct sas_phy *phy)
  {
  	transport_destroy_device(&phy->dev);
92aab6464   Mike Anderson   [SCSI] sas transp...
746
  	put_device(&phy->dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
747
748
749
750
  }
  EXPORT_SYMBOL(sas_phy_free);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
751
   * sas_phy_delete  -  remove SAS PHY
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
752
753
754
755
756
757
758
759
760
   * @phy:	SAS PHY to remove
   *
   * Removes the specified SAS PHY.  If the SAS PHY has an
   * associated remote PHY it is removed before.
   */
  void
  sas_phy_delete(struct sas_phy *phy)
  {
  	struct device *dev = &phy->dev;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
761
762
  	/* this happens if the phy is still part of a port when deleted */
  	BUG_ON(!list_empty(&phy->port_siblings));
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
763
764
765
766
  
  	transport_remove_device(dev);
  	device_del(dev);
  	transport_destroy_device(dev);
92aab6464   Mike Anderson   [SCSI] sas transp...
767
  	put_device(dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
768
769
770
771
  }
  EXPORT_SYMBOL(sas_phy_delete);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
772
   * scsi_is_sas_phy  -  check if a struct device represents a SAS PHY
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
773
774
775
776
777
778
779
780
781
782
783
784
   * @dev:	device to check
   *
   * Returns:
   *	%1 if the device represents a SAS PHY, %0 else
   */
  int scsi_is_sas_phy(const struct device *dev)
  {
  	return dev->release == sas_phy_release;
  }
  EXPORT_SYMBOL(scsi_is_sas_phy);
  
  /*
65c92b09a   James Bottomley   [SCSI] scsi_trans...
785
786
787
788
   * SAS Port attributes
   */
  #define sas_port_show_simple(field, name, format_string, cast)		\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
789
790
  show_sas_port_##name(struct device *dev, 				\
  		     struct device_attribute *attr, char *buf)		\
65c92b09a   James Bottomley   [SCSI] scsi_trans...
791
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
792
  	struct sas_port *port = transport_class_to_sas_port(dev);	\
65c92b09a   James Bottomley   [SCSI] scsi_trans...
793
794
795
796
797
798
  									\
  	return snprintf(buf, 20, format_string, cast port->field);	\
  }
  
  #define sas_port_simple_attr(field, name, format_string, type)		\
  	sas_port_show_simple(field, name, format_string, (type))	\
ee959b00c   Tony Jones   SCSI: convert str...
799
  static DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
65c92b09a   James Bottomley   [SCSI] scsi_trans...
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
  
  sas_port_simple_attr(num_phys, num_phys, "%d
  ", int);
  
  static DECLARE_TRANSPORT_CLASS(sas_port_class,
  			       "sas_port", NULL, NULL, NULL);
  
  static int sas_port_match(struct attribute_container *cont, struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  
  	if (!scsi_is_sas_port(dev))
  		return 0;
  	shost = dev_to_shost(dev->parent);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->port_attr_cont.ac == cont;
  }
  
  
  static void sas_port_release(struct device *dev)
  {
  	struct sas_port *port = dev_to_sas_port(dev);
  
  	BUG_ON(!list_empty(&port->phy_list));
  
  	put_device(dev->parent);
  	kfree(port);
  }
  
  static void sas_port_create_link(struct sas_port *port,
  				 struct sas_phy *phy)
  {
214349664   Darrick J. Wong   [SCSI] libsas: Ch...
840
841
842
  	int res;
  
  	res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
71610f55f   Kay Sievers   [SCSI] struct dev...
843
  				dev_name(&phy->dev));
214349664   Darrick J. Wong   [SCSI] libsas: Ch...
844
845
846
847
848
849
850
851
852
  	if (res)
  		goto err;
  	res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
  	if (res)
  		goto err;
  	return;
  err:
  	printk(KERN_ERR "%s: Cannot create port links, err=%d
  ",
cadbd4a5e   Harvey Harrison   [SCSI] replace __...
853
  	       __func__, res);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
854
855
856
857
858
  }
  
  static void sas_port_delete_link(struct sas_port *port,
  				 struct sas_phy *phy)
  {
71610f55f   Kay Sievers   [SCSI] struct dev...
859
  	sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));
65c92b09a   James Bottomley   [SCSI] scsi_trans...
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
  	sysfs_remove_link(&phy->dev.kobj, "port");
  }
  
  /** sas_port_alloc - allocate and initialize a SAS port structure
   *
   * @parent:	parent device
   * @port_id:	port number
   *
   * Allocates a SAS port structure.  It will be added to the device tree
   * below the device specified by @parent which must be either a Scsi_Host
   * or a sas_expander_device.
   *
   * Returns %NULL on error
   */
  struct sas_port *sas_port_alloc(struct device *parent, int port_id)
  {
  	struct Scsi_Host *shost = dev_to_shost(parent);
  	struct sas_port *port;
  
  	port = kzalloc(sizeof(*port), GFP_KERNEL);
  	if (!port)
  		return NULL;
  
  	port->port_identifier = port_id;
  
  	device_initialize(&port->dev);
  
  	port->dev.parent = get_device(parent);
  	port->dev.release = sas_port_release;
  
  	mutex_init(&port->phy_list_mutex);
  	INIT_LIST_HEAD(&port->phy_list);
  
  	if (scsi_is_sas_expander_device(parent)) {
  		struct sas_rphy *rphy = dev_to_rphy(parent);
71610f55f   Kay Sievers   [SCSI] struct dev...
895
896
  		dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,
  			     rphy->scsi_target_id, port->port_identifier);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
897
  	} else
71610f55f   Kay Sievers   [SCSI] struct dev...
898
899
  		dev_set_name(&port->dev, "port-%d:%d", shost->host_no,
  			     port->port_identifier);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
900
901
902
903
904
905
  
  	transport_setup_device(&port->dev);
  
  	return port;
  }
  EXPORT_SYMBOL(sas_port_alloc);
c9fefeb26   James Bottomley   [SCSI] scsi_trans...
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
  /** sas_port_alloc_num - allocate and initialize a SAS port structure
   *
   * @parent:	parent device
   *
   * Allocates a SAS port structure and a number to go with it.  This
   * interface is really for adapters where the port number has no
   * meansing, so the sas class should manage them.  It will be added to
   * the device tree below the device specified by @parent which must be
   * either a Scsi_Host or a sas_expander_device.
   *
   * Returns %NULL on error
   */
  struct sas_port *sas_port_alloc_num(struct device *parent)
  {
  	int index;
  	struct Scsi_Host *shost = dev_to_shost(parent);
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  
  	/* FIXME: use idr for this eventually */
  	mutex_lock(&sas_host->lock);
  	if (scsi_is_sas_expander_device(parent)) {
  		struct sas_rphy *rphy = dev_to_rphy(parent);
  		struct sas_expander_device *exp = rphy_to_expander_device(rphy);
  
  		index = exp->next_port_id++;
  	} else
  		index = sas_host->next_port_id++;
  	mutex_unlock(&sas_host->lock);
  	return sas_port_alloc(parent, index);
  }
  EXPORT_SYMBOL(sas_port_alloc_num);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
937
938
  /**
   * sas_port_add - add a SAS port to the device hierarchy
65c92b09a   James Bottomley   [SCSI] scsi_trans...
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
   * @port:	port to be added
   *
   * publishes a port to the rest of the system
   */
  int sas_port_add(struct sas_port *port)
  {
  	int error;
  
  	/* No phys should be added until this is made visible */
  	BUG_ON(!list_empty(&port->phy_list));
  
  	error = device_add(&port->dev);
  
  	if (error)
  		return error;
  
  	transport_add_device(&port->dev);
  	transport_configure_device(&port->dev);
  
  	return 0;
  }
  EXPORT_SYMBOL(sas_port_add);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
963
   * sas_port_free  -  free a SAS PORT
65c92b09a   James Bottomley   [SCSI] scsi_trans...
964
965
966
967
968
969
   * @port:	SAS PORT to free
   *
   * Frees the specified SAS PORT.
   *
   * Note:
   *   This function must only be called on a PORT that has not
af901ca18   André Goddard Rosa   tree-wide: fix as...
970
   *   successfully been added using sas_port_add().
65c92b09a   James Bottomley   [SCSI] scsi_trans...
971
972
973
974
975
976
977
978
979
   */
  void sas_port_free(struct sas_port *port)
  {
  	transport_destroy_device(&port->dev);
  	put_device(&port->dev);
  }
  EXPORT_SYMBOL(sas_port_free);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
980
   * sas_port_delete  -  remove SAS PORT
65c92b09a   James Bottomley   [SCSI] scsi_trans...
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
   * @port:	SAS PORT to remove
   *
   * Removes the specified SAS PORT.  If the SAS PORT has an
   * associated phys, unlink them from the port as well.
   */
  void sas_port_delete(struct sas_port *port)
  {
  	struct device *dev = &port->dev;
  	struct sas_phy *phy, *tmp_phy;
  
  	if (port->rphy) {
  		sas_rphy_delete(port->rphy);
  		port->rphy = NULL;
  	}
  
  	mutex_lock(&port->phy_list_mutex);
  	list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
  				 port_siblings) {
  		sas_port_delete_link(port, phy);
  		list_del_init(&phy->port_siblings);
  	}
  	mutex_unlock(&port->phy_list_mutex);
a0e1b6ef3   James Bottomley   [SCSI] scsi_trans...
1003
1004
  	if (port->is_backlink) {
  		struct device *parent = port->dev.parent;
71610f55f   Kay Sievers   [SCSI] struct dev...
1005
  		sysfs_remove_link(&port->dev.kobj, dev_name(parent));
a0e1b6ef3   James Bottomley   [SCSI] scsi_trans...
1006
1007
  		port->is_backlink = 0;
  	}
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1008
1009
1010
1011
1012
1013
1014
1015
  	transport_remove_device(dev);
  	device_del(dev);
  	transport_destroy_device(dev);
  	put_device(dev);
  }
  EXPORT_SYMBOL(sas_port_delete);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1016
   * scsi_is_sas_port -  check if a struct device represents a SAS port
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
   * @dev:	device to check
   *
   * Returns:
   *	%1 if the device represents a SAS Port, %0 else
   */
  int scsi_is_sas_port(const struct device *dev)
  {
  	return dev->release == sas_port_release;
  }
  EXPORT_SYMBOL(scsi_is_sas_port);
  
  /**
f41a0c441   Dan Williams   [SCSI] libsas: fi...
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
   * sas_port_get_phy - try to take a reference on a port member
   * @port: port to check
   */
  struct sas_phy *sas_port_get_phy(struct sas_port *port)
  {
  	struct sas_phy *phy;
  
  	mutex_lock(&port->phy_list_mutex);
  	if (list_empty(&port->phy_list))
  		phy = NULL;
  	else {
  		struct list_head *ent = port->phy_list.next;
  
  		phy = list_entry(ent, typeof(*phy), port_siblings);
  		get_device(&phy->dev);
  	}
  	mutex_unlock(&port->phy_list_mutex);
  
  	return phy;
  }
  EXPORT_SYMBOL(sas_port_get_phy);
  
  /**
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
   * sas_port_add_phy - add another phy to a port to form a wide port
   * @port:	port to add the phy to
   * @phy:	phy to add
   *
   * When a port is initially created, it is empty (has no phys).  All
   * ports must have at least one phy to operated, and all wide ports
   * must have at least two.  The current code makes no difference
   * between ports and wide ports, but the only object that can be
   * connected to a remote device is a port, so ports must be formed on
   * all devices with phys if they're connected to anything.
   */
  void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
  {
  	mutex_lock(&port->phy_list_mutex);
  	if (unlikely(!list_empty(&phy->port_siblings))) {
  		/* make sure we're already on this port */
  		struct sas_phy *tmp;
  
  		list_for_each_entry(tmp, &port->phy_list, port_siblings)
  			if (tmp == phy)
  				break;
  		/* If this trips, you added a phy that was already
  		 * part of a different port */
  		if (unlikely(tmp != phy)) {
71610f55f   Kay Sievers   [SCSI] struct dev...
1076
1077
1078
  			dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port
  ",
  				   dev_name(&phy->dev));
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
  			BUG();
  		}
  	} else {
  		sas_port_create_link(port, phy);
  		list_add_tail(&phy->port_siblings, &port->phy_list);
  		port->num_phys++;
  	}
  	mutex_unlock(&port->phy_list_mutex);
  }
  EXPORT_SYMBOL(sas_port_add_phy);
  
  /**
   * sas_port_delete_phy - remove a phy from a port or wide port
   * @port:	port to remove the phy from
   * @phy:	phy to remove
   *
   * This operation is used for tearing down ports again.  It must be
   * done to every port or wide port before calling sas_port_delete.
   */
  void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
  {
  	mutex_lock(&port->phy_list_mutex);
  	sas_port_delete_link(port, phy);
  	list_del_init(&phy->port_siblings);
  	port->num_phys--;
  	mutex_unlock(&port->phy_list_mutex);
  }
  EXPORT_SYMBOL(sas_port_delete_phy);
a0e1b6ef3   James Bottomley   [SCSI] scsi_trans...
1107
1108
  void sas_port_mark_backlink(struct sas_port *port)
  {
214349664   Darrick J. Wong   [SCSI] libsas: Ch...
1109
  	int res;
a0e1b6ef3   James Bottomley   [SCSI] scsi_trans...
1110
1111
1112
1113
1114
  	struct device *parent = port->dev.parent->parent->parent;
  
  	if (port->is_backlink)
  		return;
  	port->is_backlink = 1;
214349664   Darrick J. Wong   [SCSI] libsas: Ch...
1115
  	res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
71610f55f   Kay Sievers   [SCSI] struct dev...
1116
  				dev_name(parent));
214349664   Darrick J. Wong   [SCSI] libsas: Ch...
1117
1118
1119
1120
1121
1122
  	if (res)
  		goto err;
  	return;
  err:
  	printk(KERN_ERR "%s: Cannot create port backlink, err=%d
  ",
cadbd4a5e   Harvey Harrison   [SCSI] replace __...
1123
  	       __func__, res);
a0e1b6ef3   James Bottomley   [SCSI] scsi_trans...
1124
1125
1126
  
  }
  EXPORT_SYMBOL(sas_port_mark_backlink);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1127
  /*
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1128
1129
1130
1131
1132
   * SAS remote PHY attributes.
   */
  
  #define sas_rphy_show_simple(field, name, format_string, cast)		\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
1133
1134
  show_sas_rphy_##name(struct device *dev, 				\
  		     struct device_attribute *attr, char *buf)		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1135
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
1136
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1137
1138
1139
1140
1141
1142
  									\
  	return snprintf(buf, 20, format_string, cast rphy->field);	\
  }
  
  #define sas_rphy_simple_attr(field, name, format_string, type)		\
  	sas_rphy_show_simple(field, name, format_string, (type))	\
ee959b00c   Tony Jones   SCSI: convert str...
1143
  static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, 			\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1144
1145
1146
1147
  		show_sas_rphy_##name, NULL)
  
  #define sas_rphy_show_protocol(field, name)				\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
1148
1149
  show_sas_rphy_##name(struct device *dev, 				\
  		     struct device_attribute *attr, char *buf)		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1150
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
1151
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1152
1153
1154
1155
1156
1157
1158
1159
1160
  									\
  	if (!rphy->field)					\
  		return snprintf(buf, 20, "none
  ");			\
  	return get_sas_protocol_names(rphy->field, buf);	\
  }
  
  #define sas_rphy_protocol_attr(field, name)				\
  	sas_rphy_show_protocol(field, name)				\
ee959b00c   Tony Jones   SCSI: convert str...
1161
  static SAS_DEVICE_ATTR(rphy, name, S_IRUGO,			\
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1162
1163
1164
  		show_sas_rphy_##name, NULL)
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
1165
1166
  show_sas_rphy_device_type(struct device *dev,
  			  struct device_attribute *attr, char *buf)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1167
  {
ee959b00c   Tony Jones   SCSI: convert str...
1168
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1169
1170
1171
1172
1173
1174
1175
  
  	if (!rphy->identify.device_type)
  		return snprintf(buf, 20, "none
  ");
  	return get_sas_device_type_names(
  			rphy->identify.device_type, buf);
  }
ee959b00c   Tony Jones   SCSI: convert str...
1176
  static SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1177
  		show_sas_rphy_device_type, NULL);
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1178
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
1179
1180
  show_sas_rphy_enclosure_identifier(struct device *dev,
  				   struct device_attribute *attr, char *buf)
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1181
  {
ee959b00c   Tony Jones   SCSI: convert str...
1182
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1183
1184
1185
1186
1187
  	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
  	u64 identifier;
  	int error;
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1188
1189
1190
1191
1192
1193
  	error = i->f->get_enclosure_identifier(rphy, &identifier);
  	if (error)
  		return error;
  	return sprintf(buf, "0x%llx
  ", (unsigned long long)identifier);
  }
ee959b00c   Tony Jones   SCSI: convert str...
1194
  static SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1195
1196
1197
  		show_sas_rphy_enclosure_identifier, NULL);
  
  static ssize_t
ee959b00c   Tony Jones   SCSI: convert str...
1198
1199
  show_sas_rphy_bay_identifier(struct device *dev,
  			     struct device_attribute *attr, char *buf)
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1200
  {
ee959b00c   Tony Jones   SCSI: convert str...
1201
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1202
1203
1204
1205
  	struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
  	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
  	struct sas_internal *i = to_sas_internal(shost->transportt);
  	int val;
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1206
1207
1208
1209
1210
1211
  	val = i->f->get_bay_identifier(rphy);
  	if (val < 0)
  		return val;
  	return sprintf(buf, "%d
  ", val);
  }
ee959b00c   Tony Jones   SCSI: convert str...
1212
  static SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
a01256413   Christoph Hellwig   [SCSI] sas: add s...
1213
  		show_sas_rphy_bay_identifier, NULL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1214
1215
1216
1217
1218
1219
1220
1221
  sas_rphy_protocol_attr(identify.initiator_port_protocols,
  		initiator_port_protocols);
  sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
  sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx
  ",
  		unsigned long long);
  sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d
  ", u8);
cdc43ae34   Hannes Reinecke   scsi_transport_sa...
1222
1223
  sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d
  ", u32);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1224

42ab03609   James Bottomley   [PATCH] convert a...
1225
1226
1227
1228
1229
1230
  /* only need 8 bytes of data plus header (4 or 8) */
  #define BUF_SIZE 64
  
  int sas_read_port_mode_page(struct scsi_device *sdev)
  {
  	char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
0f88009d5   James Bottomley   [SCSI] scsi_trans...
1231
  	struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
42ab03609   James Bottomley   [PATCH] convert a...
1232
1233
  	struct scsi_mode_data mode_data;
  	int res, error;
42ab03609   James Bottomley   [PATCH] convert a...
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
  	if (!buffer)
  		return -ENOMEM;
  
  	res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
  			      &mode_data, NULL);
  
  	error = -EINVAL;
  	if (!scsi_status_is_good(res))
  		goto out;
  
  	msdata = buffer +  mode_data.header_length +
  		mode_data.block_descriptor_length;
  
  	if (msdata - buffer > BUF_SIZE - 8)
  		goto out;
  
  	error = 0;
  
  	rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
  	rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
  	rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
  
   out:
  	kfree(buffer);
  	return error;
  }
  EXPORT_SYMBOL(sas_read_port_mode_page);
79cb1819e   James Bottomley   [SCSI] add prelim...
1261
1262
  static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
  			       "sas_end_device", NULL, NULL, NULL);
42ab03609   James Bottomley   [PATCH] convert a...
1263
1264
  #define sas_end_dev_show_simple(field, name, format_string, cast)	\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
1265
1266
  show_sas_end_dev_##name(struct device *dev, 				\
  			struct device_attribute *attr, char *buf)	\
42ab03609   James Bottomley   [PATCH] convert a...
1267
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
1268
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
42ab03609   James Bottomley   [PATCH] convert a...
1269
1270
1271
1272
1273
1274
1275
  	struct sas_end_device *rdev = rphy_to_end_device(rphy);		\
  									\
  	return snprintf(buf, 20, format_string, cast rdev->field);	\
  }
  
  #define sas_end_dev_simple_attr(field, name, format_string, type)	\
  	sas_end_dev_show_simple(field, name, format_string, (type))	\
ee959b00c   Tony Jones   SCSI: convert str...
1276
  static SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, 			\
42ab03609   James Bottomley   [PATCH] convert a...
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
  		show_sas_end_dev_##name, NULL)
  
  sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d
  ", int);
  sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
  			"%d
  ", int);
  sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
  			"%d
  ", int);
0f88009d5   James Bottomley   [SCSI] scsi_trans...
1287
1288
1289
1290
1291
1292
  sas_end_dev_simple_attr(tlr_supported, tlr_supported,
  			"%d
  ", int);
  sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
  			"%d
  ", int);
42ab03609   James Bottomley   [PATCH] convert a...
1293

79cb1819e   James Bottomley   [SCSI] add prelim...
1294
1295
1296
1297
1298
  static DECLARE_TRANSPORT_CLASS(sas_expander_class,
  			       "sas_expander", NULL, NULL, NULL);
  
  #define sas_expander_show_simple(field, name, format_string, cast)	\
  static ssize_t								\
ee959b00c   Tony Jones   SCSI: convert str...
1299
1300
  show_sas_expander_##name(struct device *dev, 				\
  			 struct device_attribute *attr, char *buf)	\
79cb1819e   James Bottomley   [SCSI] add prelim...
1301
  {									\
ee959b00c   Tony Jones   SCSI: convert str...
1302
  	struct sas_rphy *rphy = transport_class_to_rphy(dev);		\
79cb1819e   James Bottomley   [SCSI] add prelim...
1303
1304
1305
1306
1307
1308
1309
  	struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
  									\
  	return snprintf(buf, 20, format_string, cast edev->field);	\
  }
  
  #define sas_expander_simple_attr(field, name, format_string, type)	\
  	sas_expander_show_simple(field, name, format_string, (type))	\
ee959b00c   Tony Jones   SCSI: convert str...
1310
  static SAS_DEVICE_ATTR(expander, name, S_IRUGO, 			\
79cb1819e   James Bottomley   [SCSI] add prelim...
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
  		show_sas_expander_##name, NULL)
  
  sas_expander_simple_attr(vendor_id, vendor_id, "%s
  ", char *);
  sas_expander_simple_attr(product_id, product_id, "%s
  ", char *);
  sas_expander_simple_attr(product_rev, product_rev, "%s
  ", char *);
  sas_expander_simple_attr(component_vendor_id, component_vendor_id,
  			 "%s
  ", char *);
  sas_expander_simple_attr(component_id, component_id, "%u
  ", unsigned int);
  sas_expander_simple_attr(component_revision_id, component_revision_id, "%u
  ",
  			 unsigned int);
  sas_expander_simple_attr(level, level, "%d
  ", int);
42ab03609   James Bottomley   [PATCH] convert a...
1329

c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1330
  static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
2f8600dff   James Bottomley   [SCSI] eliminate ...
1331
  		"sas_device", NULL, NULL, NULL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
  
  static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  
  	if (!scsi_is_sas_rphy(dev))
  		return 0;
  	shost = dev_to_shost(dev->parent->parent);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->rphy_attr_cont.ac == cont;
  }
42ab03609   James Bottomley   [PATCH] convert a...
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
  static int sas_end_dev_match(struct attribute_container *cont,
  			     struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  	struct sas_rphy *rphy;
  
  	if (!scsi_is_sas_rphy(dev))
  		return 0;
  	shost = dev_to_shost(dev->parent->parent);
  	rphy = dev_to_rphy(dev);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->end_dev_attr_cont.ac == cont &&
2f8600dff   James Bottomley   [SCSI] eliminate ...
1371
  		rphy->identify.device_type == SAS_END_DEVICE;
42ab03609   James Bottomley   [PATCH] convert a...
1372
  }
79cb1819e   James Bottomley   [SCSI] add prelim...
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  static int sas_expander_match(struct attribute_container *cont,
  			      struct device *dev)
  {
  	struct Scsi_Host *shost;
  	struct sas_internal *i;
  	struct sas_rphy *rphy;
  
  	if (!scsi_is_sas_rphy(dev))
  		return 0;
  	shost = dev_to_shost(dev->parent->parent);
  	rphy = dev_to_rphy(dev);
  
  	if (!shost->transportt)
  		return 0;
  	if (shost->transportt->host_attrs.ac.class !=
  			&sas_host_class.class)
  		return 0;
  
  	i = to_sas_internal(shost->transportt);
  	return &i->expander_attr_cont.ac == cont &&
  		(rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2f8600dff   James Bottomley   [SCSI] eliminate ...
1394
  		 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
79cb1819e   James Bottomley   [SCSI] add prelim...
1395
  }
2f8600dff   James Bottomley   [SCSI] eliminate ...
1396
  static void sas_expander_release(struct device *dev)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1397
1398
  {
  	struct sas_rphy *rphy = dev_to_rphy(dev);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1399
  	struct sas_expander_device *edev = rphy_to_expander_device(rphy);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1400

93c20a59a   FUJITA Tomonori   [SCSI] scsi_trans...
1401
1402
  	if (rphy->q)
  		blk_cleanup_queue(rphy->q);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1403
  	put_device(dev->parent);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1404
  	kfree(edev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1405
  }
2f8600dff   James Bottomley   [SCSI] eliminate ...
1406
  static void sas_end_device_release(struct device *dev)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1407
  {
2f8600dff   James Bottomley   [SCSI] eliminate ...
1408
1409
  	struct sas_rphy *rphy = dev_to_rphy(dev);
  	struct sas_end_device *edev = rphy_to_end_device(rphy);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1410

93c20a59a   FUJITA Tomonori   [SCSI] scsi_trans...
1411
1412
  	if (rphy->q)
  		blk_cleanup_queue(rphy->q);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1413
1414
  	put_device(dev->parent);
  	kfree(edev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1415
  }
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1416
1417
  
  /**
183b8021f   Masahiro Yamada   scripts/spelling....
1418
   * sas_rphy_initialize - common rphy initialization
c5943d36a   James Bottomley   [SCSI] scsi_trans...
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
   * @rphy:	rphy to initialise
   *
   * Used by both sas_end_device_alloc() and sas_expander_alloc() to
   * initialise the common rphy component of each.
   */
  static void sas_rphy_initialize(struct sas_rphy *rphy)
  {
  	INIT_LIST_HEAD(&rphy->list);
  }
  
  /**
42ab03609   James Bottomley   [PATCH] convert a...
1430
   * sas_end_device_alloc - allocate an rphy for an end device
eb44820c2   Rob Landley   [SCSI] Add Docume...
1431
   * @parent: which port
42ab03609   James Bottomley   [PATCH] convert a...
1432
1433
1434
1435
1436
1437
   *
   * Allocates an SAS remote PHY structure, connected to @parent.
   *
   * Returns:
   *	SAS PHY allocated or %NULL if the allocation failed.
   */
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1438
  struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
42ab03609   James Bottomley   [PATCH] convert a...
1439
1440
1441
1442
1443
1444
  {
  	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
  	struct sas_end_device *rdev;
  
  	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
  	if (!rdev) {
42ab03609   James Bottomley   [PATCH] convert a...
1445
1446
1447
1448
1449
  		return NULL;
  	}
  
  	device_initialize(&rdev->rphy.dev);
  	rdev->rphy.dev.parent = get_device(&parent->dev);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1450
  	rdev->rphy.dev.release = sas_end_device_release;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1451
1452
  	if (scsi_is_sas_expander_device(parent->dev.parent)) {
  		struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
71610f55f   Kay Sievers   [SCSI] struct dev...
1453
1454
1455
  		dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",
  			     shost->host_no, rphy->scsi_target_id,
  			     parent->port_identifier);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1456
  	} else
71610f55f   Kay Sievers   [SCSI] struct dev...
1457
1458
  		dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",
  			     shost->host_no, parent->port_identifier);
42ab03609   James Bottomley   [PATCH] convert a...
1459
  	rdev->rphy.identify.device_type = SAS_END_DEVICE;
c5943d36a   James Bottomley   [SCSI] scsi_trans...
1460
  	sas_rphy_initialize(&rdev->rphy);
42ab03609   James Bottomley   [PATCH] convert a...
1461
1462
1463
1464
1465
  	transport_setup_device(&rdev->rphy.dev);
  
  	return &rdev->rphy;
  }
  EXPORT_SYMBOL(sas_end_device_alloc);
79cb1819e   James Bottomley   [SCSI] add prelim...
1466
1467
  /**
   * sas_expander_alloc - allocate an rphy for an end device
eb44820c2   Rob Landley   [SCSI] Add Docume...
1468
1469
   * @parent: which port
   * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
79cb1819e   James Bottomley   [SCSI] add prelim...
1470
1471
1472
1473
1474
1475
   *
   * Allocates an SAS remote PHY structure, connected to @parent.
   *
   * Returns:
   *	SAS PHY allocated or %NULL if the allocation failed.
   */
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1476
  struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
79cb1819e   James Bottomley   [SCSI] add prelim...
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  				    enum sas_device_type type)
  {
  	struct Scsi_Host *shost = dev_to_shost(&parent->dev);
  	struct sas_expander_device *rdev;
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  
  	BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
  	       type != SAS_FANOUT_EXPANDER_DEVICE);
  
  	rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
  	if (!rdev) {
79cb1819e   James Bottomley   [SCSI] add prelim...
1488
1489
1490
1491
1492
  		return NULL;
  	}
  
  	device_initialize(&rdev->rphy.dev);
  	rdev->rphy.dev.parent = get_device(&parent->dev);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1493
  	rdev->rphy.dev.release = sas_expander_release;
79cb1819e   James Bottomley   [SCSI] add prelim...
1494
1495
1496
  	mutex_lock(&sas_host->lock);
  	rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
  	mutex_unlock(&sas_host->lock);
71610f55f   Kay Sievers   [SCSI] struct dev...
1497
1498
  	dev_set_name(&rdev->rphy.dev, "expander-%d:%d",
  		     shost->host_no, rdev->rphy.scsi_target_id);
79cb1819e   James Bottomley   [SCSI] add prelim...
1499
  	rdev->rphy.identify.device_type = type;
c5943d36a   James Bottomley   [SCSI] scsi_trans...
1500
  	sas_rphy_initialize(&rdev->rphy);
79cb1819e   James Bottomley   [SCSI] add prelim...
1501
1502
1503
1504
1505
  	transport_setup_device(&rdev->rphy.dev);
  
  	return &rdev->rphy;
  }
  EXPORT_SYMBOL(sas_expander_alloc);
42ab03609   James Bottomley   [PATCH] convert a...
1506
1507
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1508
   * sas_rphy_add  -  add a SAS remote PHY to the device hierarchy
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1509
1510
1511
1512
1513
1514
   * @rphy:	The remote PHY to be added
   *
   * Publishes a SAS remote PHY to the rest of the system.
   */
  int sas_rphy_add(struct sas_rphy *rphy)
  {
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1515
  	struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
  	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  	struct sas_identify *identify = &rphy->identify;
  	int error;
  
  	if (parent->rphy)
  		return -ENXIO;
  	parent->rphy = rphy;
  
  	error = device_add(&rphy->dev);
  	if (error)
  		return error;
  	transport_add_device(&rphy->dev);
  	transport_configure_device(&rphy->dev);
39dca558a   James Bottomley   [SCSI] bsg: make ...
1530
  	if (sas_bsg_initialize(shost, rphy))
71610f55f   Kay Sievers   [SCSI] struct dev...
1531
1532
  		printk("fail to a bsg device %s
  ", dev_name(&rphy->dev));
39dca558a   James Bottomley   [SCSI] bsg: make ...
1533

c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1534

e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1535
  	mutex_lock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1536
1537
1538
1539
1540
  	list_add_tail(&rphy->list, &sas_host->rphy_list);
  	if (identify->device_type == SAS_END_DEVICE &&
  	    (identify->target_port_protocols &
  	     (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
  		rphy->scsi_target_id = sas_host->next_target_id++;
7676f83ae   James Bottomley   [SCSI] scsi_trans...
1541
1542
  	else if (identify->device_type == SAS_END_DEVICE)
  		rphy->scsi_target_id = -1;
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1543
  	mutex_unlock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1544

79cb1819e   James Bottomley   [SCSI] add prelim...
1545
1546
  	if (identify->device_type == SAS_END_DEVICE &&
  	    rphy->scsi_target_id != -1) {
2fc62e2ac   Dan Williams   [SCSI] libsas: di...
1547
1548
1549
1550
1551
1552
  		int lun;
  
  		if (identify->target_port_protocols & SAS_PROTOCOL_SSP)
  			lun = SCAN_WILD_CARD;
  		else
  			lun = 0;
1d6450881   Hannes Reinecke   scsi: disable aut...
1553
1554
  		scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun,
  				 SCSI_SCAN_INITIAL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1555
1556
1557
1558
1559
1560
1561
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL(sas_rphy_add);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1562
1563
   * sas_rphy_free  -  free a SAS remote PHY
   * @rphy: SAS remote PHY to free
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1564
1565
1566
1567
1568
   *
   * Frees the specified SAS remote PHY.
   *
   * Note:
   *   This function must only be called on a remote
af901ca18   André Goddard Rosa   tree-wide: fix as...
1569
   *   PHY that has not successfully been added using
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1570
   *   sas_rphy_add() (or has been sas_rphy_remove()'d)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1571
1572
1573
   */
  void sas_rphy_free(struct sas_rphy *rphy)
  {
92aab6464   Mike Anderson   [SCSI] sas transp...
1574
  	struct device *dev = &rphy->dev;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1575
1576
  	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1577
  	mutex_lock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1578
  	list_del(&rphy->list);
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1579
  	mutex_unlock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1580

92aab6464   Mike Anderson   [SCSI] sas transp...
1581
  	transport_destroy_device(dev);
2f8600dff   James Bottomley   [SCSI] eliminate ...
1582

92aab6464   Mike Anderson   [SCSI] sas transp...
1583
  	put_device(dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1584
1585
1586
1587
  }
  EXPORT_SYMBOL(sas_rphy_free);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1588
   * sas_rphy_delete  -  remove and free SAS remote PHY
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1589
   * @rphy:	SAS remote PHY to remove and free
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1590
   *
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1591
   * Removes the specified SAS remote PHY and frees it.
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1592
1593
1594
1595
   */
  void
  sas_rphy_delete(struct sas_rphy *rphy)
  {
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1596
1597
1598
1599
1600
1601
  	sas_rphy_remove(rphy);
  	sas_rphy_free(rphy);
  }
  EXPORT_SYMBOL(sas_rphy_delete);
  
  /**
87c8331fc   Dan Williams   [SCSI] libsas: pr...
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
   * sas_rphy_unlink  -  unlink SAS remote PHY
   * @rphy:	SAS remote phy to unlink from its parent port
   *
   * Removes port reference to an rphy
   */
  void sas_rphy_unlink(struct sas_rphy *rphy)
  {
  	struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
  
  	parent->rphy = NULL;
  }
  EXPORT_SYMBOL(sas_rphy_unlink);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1616
   * sas_rphy_remove  -  remove SAS remote PHY
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1617
1618
1619
1620
1621
1622
1623
   * @rphy:	SAS remote phy to remove
   *
   * Removes the specified SAS remote PHY.
   */
  void
  sas_rphy_remove(struct sas_rphy *rphy)
  {
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1624
  	struct device *dev = &rphy->dev;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1625

d40542399   Christoph Hellwig   [SCSI] sas: fix r...
1626
1627
1628
1629
1630
1631
  	switch (rphy->identify.device_type) {
  	case SAS_END_DEVICE:
  		scsi_remove_target(dev);
  		break;
  	case SAS_EDGE_EXPANDER_DEVICE:
  	case SAS_FANOUT_EXPANDER_DEVICE:
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1632
  		sas_remove_children(dev);
d40542399   Christoph Hellwig   [SCSI] sas: fix r...
1633
1634
1635
1636
  		break;
  	default:
  		break;
  	}
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1637

87c8331fc   Dan Williams   [SCSI] libsas: pr...
1638
  	sas_rphy_unlink(rphy);
651a01364   Christoph Hellwig   scsi: scsi_transp...
1639
1640
  	if (rphy->q)
  		bsg_unregister_queue(rphy->q);
fe8b2304e   Christoph Hellwig   [SCSI] sas: fix r...
1641
1642
  	transport_remove_device(dev);
  	device_del(dev);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1643
  }
6f63caae2   Darrick J. Wong   [SCSI] libsas: Cl...
1644
  EXPORT_SYMBOL(sas_rphy_remove);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1645
1646
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1647
   * scsi_is_sas_rphy  -  check if a struct device represents a SAS remote PHY
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1648
1649
1650
1651
1652
1653
1654
   * @dev:	device to check
   *
   * Returns:
   *	%1 if the device represents a SAS remote PHY, %0 else
   */
  int scsi_is_sas_rphy(const struct device *dev)
  {
2f8600dff   James Bottomley   [SCSI] eliminate ...
1655
1656
  	return dev->release == sas_end_device_release ||
  		dev->release == sas_expander_release;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1657
1658
1659
1660
1661
1662
1663
  }
  EXPORT_SYMBOL(scsi_is_sas_rphy);
  
  
  /*
   * SCSI scan helper
   */
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1664
  static int sas_user_scan(struct Scsi_Host *shost, uint channel,
9cb78c16f   Hannes Reinecke   scsi: use 64-bit ...
1665
  		uint id, u64 lun)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1666
1667
1668
  {
  	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
  	struct sas_rphy *rphy;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1669

e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1670
  	mutex_lock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1671
  	list_for_each_entry(rphy, &sas_host->rphy_list, list) {
6d99a3f37   James Bottomley   [SCSI] scsi_trans...
1672
1673
  		if (rphy->identify.device_type != SAS_END_DEVICE ||
  		    rphy->scsi_target_id == -1)
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1674
  			continue;
e8bf39417   James Bottomley   [SCSI] scsi_trans...
1675
  		if ((channel == SCAN_WILD_CARD || channel == 0) &&
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1676
  		    (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
1d6450881   Hannes Reinecke   scsi: disable aut...
1677
1678
  			scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
  					 lun, SCSI_SCAN_MANUAL);
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1679
  		}
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1680
  	}
e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1681
  	mutex_unlock(&sas_host->lock);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1682

e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1683
  	return 0;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1684
1685
1686
1687
1688
1689
  }
  
  
  /*
   * Setup / Teardown code
   */
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1690
  #define SETUP_TEMPLATE(attrb, field, perm, test)			\
ee959b00c   Tony Jones   SCSI: convert str...
1691
  	i->private_##attrb[count] = dev_attr_##field;		\
42ab03609   James Bottomley   [PATCH] convert a...
1692
  	i->private_##attrb[count].attr.mode = perm;			\
42ab03609   James Bottomley   [PATCH] convert a...
1693
1694
1695
  	i->attrb[count] = &i->private_##attrb[count];			\
  	if (test)							\
  		count++
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1696
  #define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm)	\
ee959b00c   Tony Jones   SCSI: convert str...
1697
  	i->private_##attrb[count] = dev_attr_##field;		\
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1698
1699
1700
1701
1702
1703
1704
1705
  	i->private_##attrb[count].attr.mode = perm;			\
  	if (ro_test) {							\
  		i->private_##attrb[count].attr.mode = ro_perm;		\
  		i->private_##attrb[count].store = NULL;			\
  	}								\
  	i->attrb[count] = &i->private_##attrb[count];			\
  	if (test)							\
  		count++
42ab03609   James Bottomley   [PATCH] convert a...
1706
1707
1708
  
  #define SETUP_RPORT_ATTRIBUTE(field) 					\
  	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1709

dd9fbb521   James Bottomley   [SCSI] make some ...
1710
  #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func)			\
42ab03609   James Bottomley   [PATCH] convert a...
1711
  	SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
dd9fbb521   James Bottomley   [SCSI] make some ...
1712

65c92b09a   James Bottomley   [SCSI] scsi_trans...
1713
  #define SETUP_PHY_ATTRIBUTE(field)					\
42ab03609   James Bottomley   [PATCH] convert a...
1714
  	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1715

d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1716
1717
1718
  #define SETUP_PHY_ATTRIBUTE_RW(field)					\
  	SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1,	\
  			!i->f->set_phy_speed, S_IRUGO)
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
1719
1720
1721
  #define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func)			\
  	SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1,	\
  			  !i->f->func, S_IRUGO)
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1722
1723
1724
1725
  #define SETUP_PORT_ATTRIBUTE(field)					\
  	SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
  
  #define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func)			\
42ab03609   James Bottomley   [PATCH] convert a...
1726
  	SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
dd9fbb521   James Bottomley   [SCSI] make some ...
1727

65c92b09a   James Bottomley   [SCSI] scsi_trans...
1728
  #define SETUP_PHY_ATTRIBUTE_WRONLY(field)				\
fe3b5bfe7   Darrick J. Wong   [SCSI] libsas: sy...
1729
  	SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)
07ba3a954   Christoph Hellwig   [SCSI] sas: add s...
1730

65c92b09a   James Bottomley   [SCSI] scsi_trans...
1731
  #define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func)		\
fe3b5bfe7   Darrick J. Wong   [SCSI] libsas: sy...
1732
  	SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)
dd9fbb521   James Bottomley   [SCSI] make some ...
1733

42ab03609   James Bottomley   [PATCH] convert a...
1734
1735
  #define SETUP_END_DEV_ATTRIBUTE(field)					\
  	SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1736

79cb1819e   James Bottomley   [SCSI] add prelim...
1737
1738
  #define SETUP_EXPANDER_ATTRIBUTE(field)					\
  	SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1739
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1740
   * sas_attach_transport  -  instantiate SAS transport template
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1741
1742
1743
1744
1745
1746
1747
   * @ft:		SAS transport class function template
   */
  struct scsi_transport_template *
  sas_attach_transport(struct sas_function_template *ft)
  {
  	struct sas_internal *i;
  	int count;
24669f75a   Jes Sorensen   [SCSI] SCSI core ...
1748
  	i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1749
1750
  	if (!i)
  		return NULL;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1751

e02f3f592   Christoph Hellwig   [SCSI] remove tar...
1752
  	i->t.user_scan = sas_user_scan;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
  
  	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
  	i->t.host_attrs.ac.class = &sas_host_class.class;
  	i->t.host_attrs.ac.match = sas_host_match;
  	transport_container_register(&i->t.host_attrs);
  	i->t.host_size = sizeof(struct sas_host_attrs);
  
  	i->phy_attr_cont.ac.class = &sas_phy_class.class;
  	i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
  	i->phy_attr_cont.ac.match = sas_phy_match;
  	transport_container_register(&i->phy_attr_cont);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1764
1765
1766
1767
  	i->port_attr_cont.ac.class = &sas_port_class.class;
  	i->port_attr_cont.ac.attrs = &i->port_attrs[0];
  	i->port_attr_cont.ac.match = sas_port_match;
  	transport_container_register(&i->port_attr_cont);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1768
1769
1770
1771
  	i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
  	i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
  	i->rphy_attr_cont.ac.match = sas_rphy_match;
  	transport_container_register(&i->rphy_attr_cont);
42ab03609   James Bottomley   [PATCH] convert a...
1772
1773
1774
1775
  	i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
  	i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
  	i->end_dev_attr_cont.ac.match = sas_end_dev_match;
  	transport_container_register(&i->end_dev_attr_cont);
79cb1819e   James Bottomley   [SCSI] add prelim...
1776
1777
1778
1779
  	i->expander_attr_cont.ac.class = &sas_expander_class.class;
  	i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
  	i->expander_attr_cont.ac.match = sas_expander_match;
  	transport_container_register(&i->expander_attr_cont);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1780
1781
1782
  	i->f = ft;
  
  	count = 0;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1783
1784
1785
1786
1787
1788
1789
1790
  	SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
  	SETUP_PHY_ATTRIBUTE(target_port_protocols);
  	SETUP_PHY_ATTRIBUTE(device_type);
  	SETUP_PHY_ATTRIBUTE(sas_address);
  	SETUP_PHY_ATTRIBUTE(phy_identifier);
  	//SETUP_PHY_ATTRIBUTE(port_identifier);
  	SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
  	SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1791
  	SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1792
  	SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
d24e1eeb3   James Bottomley   [SCSI] scsi_trans...
1793
  	SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1794
1795
1796
1797
1798
1799
1800
  
  	SETUP_PHY_ATTRIBUTE(invalid_dword_count);
  	SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
  	SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
  	SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
  	SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
  	SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
acbf167d4   Darrick J. Wong   [SCSI] libsas: Ad...
1801
  	SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1802
1803
1804
  	i->phy_attrs[count] = NULL;
  
  	count = 0;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1805
1806
1807
1808
  	SETUP_PORT_ATTRIBUTE(num_phys);
  	i->port_attrs[count] = NULL;
  
  	count = 0;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1809
1810
1811
1812
1813
  	SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
  	SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
  	SETUP_RPORT_ATTRIBUTE(rphy_device_type);
  	SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
  	SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
cdc43ae34   Hannes Reinecke   scsi_transport_sa...
1814
  	SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
dd9fbb521   James Bottomley   [SCSI] make some ...
1815
1816
1817
1818
  	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
  				       get_enclosure_identifier);
  	SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
  				       get_bay_identifier);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1819
  	i->rphy_attrs[count] = NULL;
42ab03609   James Bottomley   [PATCH] convert a...
1820
1821
1822
1823
  	count = 0;
  	SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
  	SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
  	SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
0f88009d5   James Bottomley   [SCSI] scsi_trans...
1824
1825
  	SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
  	SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
42ab03609   James Bottomley   [PATCH] convert a...
1826
  	i->end_dev_attrs[count] = NULL;
79cb1819e   James Bottomley   [SCSI] add prelim...
1827
1828
1829
1830
1831
1832
1833
1834
1835
  	count = 0;
  	SETUP_EXPANDER_ATTRIBUTE(vendor_id);
  	SETUP_EXPANDER_ATTRIBUTE(product_id);
  	SETUP_EXPANDER_ATTRIBUTE(product_rev);
  	SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
  	SETUP_EXPANDER_ATTRIBUTE(component_id);
  	SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
  	SETUP_EXPANDER_ATTRIBUTE(level);
  	i->expander_attrs[count] = NULL;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1836
1837
1838
1839
1840
  	return &i->t;
  }
  EXPORT_SYMBOL(sas_attach_transport);
  
  /**
eb44820c2   Rob Landley   [SCSI] Add Docume...
1841
   * sas_release_transport  -  release SAS transport template instance
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1842
1843
1844
1845
1846
1847
1848
1849
   * @t:		transport template instance
   */
  void sas_release_transport(struct scsi_transport_template *t)
  {
  	struct sas_internal *i = to_sas_internal(t);
  
  	transport_container_unregister(&i->t.host_attrs);
  	transport_container_unregister(&i->phy_attr_cont);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1850
  	transport_container_unregister(&i->port_attr_cont);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1851
  	transport_container_unregister(&i->rphy_attr_cont);
db82f8410   James Bottomley   [SCSI] add missin...
1852
  	transport_container_unregister(&i->end_dev_attr_cont);
79cb1819e   James Bottomley   [SCSI] add prelim...
1853
  	transport_container_unregister(&i->expander_attr_cont);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
  
  	kfree(i);
  }
  EXPORT_SYMBOL(sas_release_transport);
  
  static __init int sas_transport_init(void)
  {
  	int error;
  
  	error = transport_class_register(&sas_host_class);
  	if (error)
  		goto out;
  	error = transport_class_register(&sas_phy_class);
  	if (error)
  		goto out_unregister_transport;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1869
  	error = transport_class_register(&sas_port_class);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1870
1871
  	if (error)
  		goto out_unregister_phy;
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1872
1873
1874
  	error = transport_class_register(&sas_rphy_class);
  	if (error)
  		goto out_unregister_port;
42ab03609   James Bottomley   [PATCH] convert a...
1875
1876
1877
  	error = transport_class_register(&sas_end_dev_class);
  	if (error)
  		goto out_unregister_rphy;
79cb1819e   James Bottomley   [SCSI] add prelim...
1878
1879
1880
  	error = transport_class_register(&sas_expander_class);
  	if (error)
  		goto out_unregister_end_dev;
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1881
1882
  
  	return 0;
79cb1819e   James Bottomley   [SCSI] add prelim...
1883
1884
   out_unregister_end_dev:
  	transport_class_unregister(&sas_end_dev_class);
42ab03609   James Bottomley   [PATCH] convert a...
1885
1886
   out_unregister_rphy:
  	transport_class_unregister(&sas_rphy_class);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1887
1888
   out_unregister_port:
  	transport_class_unregister(&sas_port_class);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
   out_unregister_phy:
  	transport_class_unregister(&sas_phy_class);
   out_unregister_transport:
  	transport_class_unregister(&sas_host_class);
   out:
  	return error;
  
  }
  
  static void __exit sas_transport_exit(void)
  {
  	transport_class_unregister(&sas_host_class);
  	transport_class_unregister(&sas_phy_class);
65c92b09a   James Bottomley   [SCSI] scsi_trans...
1902
  	transport_class_unregister(&sas_port_class);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1903
  	transport_class_unregister(&sas_rphy_class);
42ab03609   James Bottomley   [PATCH] convert a...
1904
  	transport_class_unregister(&sas_end_dev_class);
79cb1819e   James Bottomley   [SCSI] add prelim...
1905
  	transport_class_unregister(&sas_expander_class);
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1906
1907
1908
  }
  
  MODULE_AUTHOR("Christoph Hellwig");
86b9c4c16   Alexis Bruemmer   [SCSI] aic94xx: f...
1909
  MODULE_DESCRIPTION("SAS Transport Attributes");
c7ebbbce3   Christoph Hellwig   [SCSI] SAS transp...
1910
1911
1912
1913
  MODULE_LICENSE("GPL");
  
  module_init(sas_transport_init);
  module_exit(sas_transport_exit);