blob: a190c052cd9399f15561f06267d8ffb533aaba69 [file] [log] [blame]
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001/*
Christoph Hellwiga0125642006-02-16 13:31:47 +01002 * Copyright (C) 2005-2006 Dell Inc.
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02003 * Released under GPL v2.
4 *
5 * Serial Attached SCSI (SAS) transport class.
6 *
7 * The SAS transport class contains common code to deal with SAS HBAs,
8 * an aproximated representation of SAS topologies in the driver model,
Joe Perchesb1c11812008-02-03 17:28:22 +02009 * and various sysfs attributes to expose these topologies and management
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020010 * interfaces to userspace.
11 *
12 * In addition to the basic SCSI core objects this transport class
13 * introduces two additional intermediate objects: The SAS PHY
14 * as represented by struct sas_phy defines an "outgoing" PHY on
15 * a SAS HBA or Expander, and the SAS remote PHY represented by
16 * struct sas_rphy defines an "incoming" PHY on a SAS Expander or
17 * end device. Note that this is purely a software concept, the
18 * underlying hardware for a PHY and a remote PHY is the exactly
19 * the same.
20 *
21 * There is no concept of a SAS port in this code, users can see
22 * what PHYs form a wide port based on the port_identifier attribute,
23 * which is the same for all PHYs in a port.
24 */
25
26#include <linux/init.h>
27#include <linux/module.h>
Al Virof6a57032006-10-18 01:47:25 -040028#include <linux/jiffies.h>
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020029#include <linux/err.h>
Tim Schmielau8c65b4a2005-11-07 00:59:43 -080030#include <linux/slab.h>
31#include <linux/string.h>
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +090032#include <linux/blkdev.h>
33#include <linux/bsg.h>
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020034
Christoph Hellwige02f3f52006-01-13 19:04:00 +010035#include <scsi/scsi.h>
Bart Van Asscheca18d6f2017-06-20 11:15:41 -070036#include <scsi/scsi_cmnd.h>
Christoph Hellwig82ed4db2017-01-27 09:46:29 +010037#include <scsi/scsi_request.h>
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020038#include <scsi/scsi_device.h>
39#include <scsi/scsi_host.h>
40#include <scsi/scsi_transport.h>
41#include <scsi/scsi_transport_sas.h>
42
James Bottomleyd6159c12006-03-27 16:45:34 -060043#include "scsi_sas_internal.h"
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020044struct sas_host_attrs {
45 struct list_head rphy_list;
Christoph Hellwige02f3f52006-01-13 19:04:00 +010046 struct mutex lock;
James Bottomleyb6aff662007-07-20 11:10:05 -050047 struct request_queue *q;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020048 u32 next_target_id;
James Bottomley79cb1812006-03-13 13:50:04 -060049 u32 next_expander_id;
James Bottomleyc9fefeb2006-07-02 11:10:18 -050050 int next_port_id;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020051};
52#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
53
54
55/*
56 * Hack to allow attributes of the same name in different objects.
57 */
Tony Jonesee959b02008-02-22 00:13:36 +010058#define SAS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
59 struct device_attribute dev_attr_##_prefix##_##_name = \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020060 __ATTR(_name,_mode,_show,_store)
61
62
63/*
64 * Pretty printing helpers
65 */
66
67#define sas_bitfield_name_match(title, table) \
68static ssize_t \
69get_sas_##title##_names(u32 table_key, char *buf) \
70{ \
71 char *prefix = ""; \
72 ssize_t len = 0; \
73 int i; \
74 \
Tobias Klauser6391a112006-06-08 22:23:48 -070075 for (i = 0; i < ARRAY_SIZE(table); i++) { \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +020076 if (table[i].value & table_key) { \
77 len += sprintf(buf + len, "%s%s", \
78 prefix, table[i].name); \
79 prefix = ", "; \
80 } \
81 } \
82 len += sprintf(buf + len, "\n"); \
83 return len; \
84}
85
James Bottomleyd24e1ee2006-09-06 19:25:22 -050086#define sas_bitfield_name_set(title, table) \
87static ssize_t \
88set_sas_##title##_names(u32 *table_key, const char *buf) \
89{ \
90 ssize_t len = 0; \
91 int i; \
92 \
93 for (i = 0; i < ARRAY_SIZE(table); i++) { \
94 len = strlen(table[i].name); \
95 if (strncmp(buf, table[i].name, len) == 0 && \
96 (buf[len] == '\n' || buf[len] == '\0')) { \
97 *table_key = table[i].value; \
98 return 0; \
99 } \
100 } \
101 return -EINVAL; \
102}
103
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200104#define sas_bitfield_name_search(title, table) \
105static ssize_t \
106get_sas_##title##_names(u32 table_key, char *buf) \
107{ \
108 ssize_t len = 0; \
109 int i; \
110 \
Tobias Klauser6391a112006-06-08 22:23:48 -0700111 for (i = 0; i < ARRAY_SIZE(table); i++) { \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200112 if (table[i].value == table_key) { \
113 len += sprintf(buf + len, "%s", \
114 table[i].name); \
115 break; \
116 } \
117 } \
118 len += sprintf(buf + len, "\n"); \
119 return len; \
120}
121
122static struct {
123 u32 value;
124 char *name;
125} sas_device_type_names[] = {
126 { SAS_PHY_UNUSED, "unused" },
127 { SAS_END_DEVICE, "end device" },
128 { SAS_EDGE_EXPANDER_DEVICE, "edge expander" },
129 { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" },
130};
131sas_bitfield_name_search(device_type, sas_device_type_names)
132
133
134static struct {
135 u32 value;
136 char *name;
137} sas_protocol_names[] = {
138 { SAS_PROTOCOL_SATA, "sata" },
139 { SAS_PROTOCOL_SMP, "smp" },
140 { SAS_PROTOCOL_STP, "stp" },
141 { SAS_PROTOCOL_SSP, "ssp" },
142};
143sas_bitfield_name_match(protocol, sas_protocol_names)
144
145static struct {
146 u32 value;
147 char *name;
148} sas_linkspeed_names[] = {
149 { SAS_LINK_RATE_UNKNOWN, "Unknown" },
150 { SAS_PHY_DISABLED, "Phy disabled" },
151 { SAS_LINK_RATE_FAILED, "Link Rate failed" },
152 { SAS_SATA_SPINUP_HOLD, "Spin-up hold" },
153 { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
154 { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
James Bottomley7e6dff62006-03-02 14:12:56 -0600155 { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
Sreekanth Reddyd84fd392012-11-30 07:43:11 +0530156 { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200157};
158sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500159sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200160
James Bottomley0f880092010-01-18 10:14:51 -0600161static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev)
162{
163 struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target);
164 struct sas_end_device *rdev;
165
166 BUG_ON(rphy->identify.device_type != SAS_END_DEVICE);
167
168 rdev = rphy_to_end_device(rphy);
169 return rdev;
170}
171
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900172static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
173 struct sas_rphy *rphy)
174{
175 struct request *req;
Christoph Hellwig2a842ac2017-06-03 09:38:04 +0200176 blk_status_t ret;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900177 int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
178
Jens Axboe7eaceac2011-03-10 08:52:07 +0100179 while ((req = blk_fetch_request(q)) != NULL) {
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900180 spin_unlock_irq(q->queue_lock);
181
Christoph Hellwig82ed4db2017-01-27 09:46:29 +0100182 scsi_req(req)->resid_len = blk_rq_bytes(req);
183 if (req->next_rq)
184 scsi_req(req->next_rq)->resid_len =
185 blk_rq_bytes(req->next_rq);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900186 handler = to_sas_internal(shost->transportt)->f->smp_handler;
187 ret = handler(shost, rphy, req);
Christoph Hellwig17d53632017-04-20 16:03:01 +0200188 scsi_req(req)->result = ret;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900189
Christoph Hellwigd188b902017-04-26 09:34:20 +0200190 blk_end_request_all(req, 0);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900191
FUJITA Tomonori93bdcba2009-06-17 15:10:10 +0900192 spin_lock_irq(q->queue_lock);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900193 }
194}
195
196static void sas_host_smp_request(struct request_queue *q)
197{
198 sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL);
199}
200
201static void sas_non_host_smp_request(struct request_queue *q)
202{
203 struct sas_rphy *rphy = q->queuedata;
204 sas_smp_request(q, rphy_to_shost(rphy), rphy);
205}
206
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900207static void sas_host_release(struct device *dev)
208{
209 struct Scsi_Host *shost = dev_to_shost(dev);
210 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
211 struct request_queue *q = sas_host->q;
212
213 if (q)
214 blk_cleanup_queue(q);
215}
216
James Bottomley39dca552007-07-20 18:22:17 -0500217static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900218{
219 struct request_queue *q;
220 int error;
James Bottomley39dca552007-07-20 18:22:17 -0500221 struct device *dev;
Kay Sievers71610f52008-12-03 22:41:36 +0100222 char namebuf[20];
James Bottomley39dca552007-07-20 18:22:17 -0500223 const char *name;
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900224 void (*release)(struct device *);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900225
226 if (!to_sas_internal(shost->transportt)->f->smp_handler) {
227 printk("%s can't handle SMP requests\n", shost->hostt->name);
228 return 0;
229 }
230
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800231 q = blk_alloc_queue(GFP_KERNEL);
232 if (!q)
233 return -ENOMEM;
Bart Van Asscheca18d6f2017-06-20 11:15:41 -0700234 q->initialize_rq_fn = scsi_initialize_rq;
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800235 q->cmd_size = sizeof(struct scsi_request);
236
James Bottomley39dca552007-07-20 18:22:17 -0500237 if (rphy) {
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800238 q->request_fn = sas_non_host_smp_request;
James Bottomley39dca552007-07-20 18:22:17 -0500239 dev = &rphy->dev;
Kay Sievers71610f52008-12-03 22:41:36 +0100240 name = dev_name(dev);
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900241 release = NULL;
James Bottomley39dca552007-07-20 18:22:17 -0500242 } else {
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800243 q->request_fn = sas_host_smp_request;
James Bottomley39dca552007-07-20 18:22:17 -0500244 dev = &shost->shost_gendev;
245 snprintf(namebuf, sizeof(namebuf),
246 "sas_host%d", shost->host_no);
247 name = namebuf;
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900248 release = sas_host_release;
James Bottomley39dca552007-07-20 18:22:17 -0500249 }
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800250 error = blk_init_allocated_queue(q);
251 if (error)
252 goto out_cleanup_queue;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900253
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900254 error = bsg_register_queue(q, dev, name, release);
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800255 if (error)
256 goto out_cleanup_queue;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900257
258 if (rphy)
James Bottomleyb6aff662007-07-20 11:10:05 -0500259 rphy->q = q;
260 else
261 to_sas_host_attrs(shost)->q = q;
262
263 if (rphy)
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900264 q->queuedata = rphy;
265 else
266 q->queuedata = shost;
267
Nick Piggin75ad23b2008-04-29 14:48:33 +0200268 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
Bart Van Assche9efc1602017-05-31 14:43:46 -0700269 queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900270 return 0;
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800271
272out_cleanup_queue:
273 blk_cleanup_queue(q);
274 return error;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900275}
276
James Bottomleyb6aff662007-07-20 11:10:05 -0500277static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
278{
279 struct request_queue *q;
280
281 if (rphy)
282 q = rphy->q;
283 else
284 q = to_sas_host_attrs(shost)->q;
285
286 if (!q)
287 return;
288
289 bsg_unregister_queue(q);
James Bottomleyb6aff662007-07-20 11:10:05 -0500290}
291
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200292/*
293 * SAS host attributes
294 */
295
James Bottomley37be6ee2005-09-09 18:38:27 -0500296static int sas_host_setup(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +0100297 struct device *cdev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200298{
299 struct Scsi_Host *shost = dev_to_shost(dev);
300 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
301
302 INIT_LIST_HEAD(&sas_host->rphy_list);
Christoph Hellwige02f3f52006-01-13 19:04:00 +0100303 mutex_init(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200304 sas_host->next_target_id = 0;
James Bottomley79cb1812006-03-13 13:50:04 -0600305 sas_host->next_expander_id = 0;
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500306 sas_host->next_port_id = 0;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900307
James Bottomley39dca552007-07-20 18:22:17 -0500308 if (sas_bsg_initialize(shost, NULL))
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900309 dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
310 shost->host_no);
311
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200312 return 0;
313}
314
James Bottomleyb6aff662007-07-20 11:10:05 -0500315static int sas_host_remove(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +0100316 struct device *cdev)
James Bottomleyb6aff662007-07-20 11:10:05 -0500317{
318 struct Scsi_Host *shost = dev_to_shost(dev);
319
320 sas_bsg_remove(shost, NULL);
321
322 return 0;
323}
324
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200325static DECLARE_TRANSPORT_CLASS(sas_host_class,
James Bottomleyb6aff662007-07-20 11:10:05 -0500326 "sas_host", sas_host_setup, sas_host_remove, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200327
328static int sas_host_match(struct attribute_container *cont,
329 struct device *dev)
330{
331 struct Scsi_Host *shost;
332 struct sas_internal *i;
333
334 if (!scsi_is_host_device(dev))
335 return 0;
336 shost = dev_to_shost(dev);
337
338 if (!shost->transportt)
339 return 0;
340 if (shost->transportt->host_attrs.ac.class !=
341 &sas_host_class.class)
342 return 0;
343
344 i = to_sas_internal(shost->transportt);
345 return &i->t.host_attrs.ac == cont;
346}
347
348static int do_sas_phy_delete(struct device *dev, void *data)
349{
James Bottomley65c92b02006-06-28 12:22:50 -0400350 int pass = (int)(unsigned long)data;
351
352 if (pass == 0 && scsi_is_sas_port(dev))
353 sas_port_delete(dev_to_sas_port(dev));
354 else if (pass == 1 && scsi_is_sas_phy(dev))
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200355 sas_phy_delete(dev_to_phy(dev));
356 return 0;
357}
358
359/**
Rob Landleyeb448202007-11-03 13:30:39 -0500360 * sas_remove_children - tear down a devices SAS data structures
James Bottomley65c92b02006-06-28 12:22:50 -0400361 * @dev: device belonging to the sas object
362 *
363 * Removes all SAS PHYs and remote PHYs for a given object
364 */
365void sas_remove_children(struct device *dev)
366{
367 device_for_each_child(dev, (void *)0, do_sas_phy_delete);
368 device_for_each_child(dev, (void *)1, do_sas_phy_delete);
369}
370EXPORT_SYMBOL(sas_remove_children);
371
372/**
Rob Landleyeb448202007-11-03 13:30:39 -0500373 * sas_remove_host - tear down a Scsi_Host's SAS data structures
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200374 * @shost: Scsi Host that is torn down
375 *
Johannes Thumshirnc5ce0ab2017-04-21 14:11:41 +0200376 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the
377 * Scsi_Host as well.
378 *
379 * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is
380 * already removed.
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200381 */
382void sas_remove_host(struct Scsi_Host *shost)
383{
James Bottomley65c92b02006-06-28 12:22:50 -0400384 sas_remove_children(&shost->shost_gendev);
Johannes Thumshirnc5ce0ab2017-04-21 14:11:41 +0200385 scsi_remove_host(shost);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200386}
387EXPORT_SYMBOL(sas_remove_host);
388
James Bottomley0f880092010-01-18 10:14:51 -0600389/**
James Bottomleybcf508c2015-12-09 11:13:35 -0800390 * sas_get_address - return the SAS address of the device
391 * @sdev: scsi device
392 *
393 * Returns the SAS address of the scsi device
394 */
395u64 sas_get_address(struct scsi_device *sdev)
396{
397 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
398
399 return rdev->rphy.identify.sas_address;
400}
401EXPORT_SYMBOL(sas_get_address);
402
403/**
James Bottomley0f880092010-01-18 10:14:51 -0600404 * sas_tlr_supported - checking TLR bit in vpd 0x90
405 * @sdev: scsi device struct
406 *
407 * Check Transport Layer Retries are supported or not.
408 * If vpd page 0x90 is present, TRL is supported.
409 *
410 */
411unsigned int
412sas_tlr_supported(struct scsi_device *sdev)
413{
414 const int vpd_len = 32;
415 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
416 char *buffer = kzalloc(vpd_len, GFP_KERNEL);
417 int ret = 0;
418
419 if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
420 goto out;
421
422 /*
423 * Magic numbers: the VPD Protocol page (0x90)
424 * has a 4 byte header and then one entry per device port
425 * the TLR bit is at offset 8 on each port entry
426 * if we take the first port, that's at total offset 12
427 */
428 ret = buffer[12] & 0x01;
429
430 out:
431 kfree(buffer);
432 rdev->tlr_supported = ret;
433 return ret;
434
435}
436EXPORT_SYMBOL_GPL(sas_tlr_supported);
437
438/**
439 * sas_disable_tlr - setting TLR flags
440 * @sdev: scsi device struct
441 *
442 * Seting tlr_enabled flag to 0.
443 *
444 */
445void
446sas_disable_tlr(struct scsi_device *sdev)
447{
448 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
449
450 rdev->tlr_enabled = 0;
451}
452EXPORT_SYMBOL_GPL(sas_disable_tlr);
453
454/**
455 * sas_enable_tlr - setting TLR flags
456 * @sdev: scsi device struct
457 *
458 * Seting tlr_enabled flag 1.
459 *
460 */
461void sas_enable_tlr(struct scsi_device *sdev)
462{
463 unsigned int tlr_supported = 0;
464 tlr_supported = sas_tlr_supported(sdev);
465
466 if (tlr_supported) {
467 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
468
469 rdev->tlr_enabled = 1;
470 }
471
472 return;
473}
474EXPORT_SYMBOL_GPL(sas_enable_tlr);
475
476unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
477{
478 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
479 return rdev->tlr_enabled;
480}
481EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200482
483/*
James Bottomley65c92b02006-06-28 12:22:50 -0400484 * SAS Phy attributes
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200485 */
486
487#define sas_phy_show_simple(field, name, format_string, cast) \
488static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100489show_sas_phy_##name(struct device *dev, \
490 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200491{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100492 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200493 \
494 return snprintf(buf, 20, format_string, cast phy->field); \
495}
496
497#define sas_phy_simple_attr(field, name, format_string, type) \
498 sas_phy_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +0100499static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200500
501#define sas_phy_show_protocol(field, name) \
502static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100503show_sas_phy_##name(struct device *dev, \
504 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200505{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100506 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200507 \
508 if (!phy->field) \
509 return snprintf(buf, 20, "none\n"); \
510 return get_sas_protocol_names(phy->field, buf); \
511}
512
513#define sas_phy_protocol_attr(field, name) \
514 sas_phy_show_protocol(field, name) \
Tony Jonesee959b02008-02-22 00:13:36 +0100515static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200516
517#define sas_phy_show_linkspeed(field) \
518static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100519show_sas_phy_##field(struct device *dev, \
520 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200521{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100522 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200523 \
524 return get_sas_linkspeed_names(phy->field, buf); \
525}
526
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500527/* Fudge to tell if we're minimum or maximum */
528#define sas_phy_store_linkspeed(field) \
529static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100530store_sas_phy_##field(struct device *dev, \
531 struct device_attribute *attr, \
532 const char *buf, size_t count) \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500533{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100534 struct sas_phy *phy = transport_class_to_phy(dev); \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500535 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
536 struct sas_internal *i = to_sas_internal(shost->transportt); \
537 u32 value; \
538 struct sas_phy_linkrates rates = {0}; \
539 int error; \
540 \
541 error = set_sas_linkspeed_names(&value, buf); \
542 if (error) \
543 return error; \
544 rates.field = value; \
545 error = i->f->set_phy_speed(phy, &rates); \
546 \
547 return error ? error : count; \
548}
549
550#define sas_phy_linkspeed_rw_attr(field) \
551 sas_phy_show_linkspeed(field) \
552 sas_phy_store_linkspeed(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100553static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500554 store_sas_phy_##field)
555
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200556#define sas_phy_linkspeed_attr(field) \
557 sas_phy_show_linkspeed(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100558static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200559
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500560
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200561#define sas_phy_show_linkerror(field) \
562static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100563show_sas_phy_##field(struct device *dev, \
564 struct device_attribute *attr, char *buf) \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200565{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100566 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200567 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
568 struct sas_internal *i = to_sas_internal(shost->transportt); \
569 int error; \
570 \
James Bottomleydd9fbb522006-03-02 16:01:31 -0600571 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200572 if (error) \
573 return error; \
574 return snprintf(buf, 20, "%u\n", phy->field); \
575}
576
577#define sas_phy_linkerror_attr(field) \
578 sas_phy_show_linkerror(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100579static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200580
581
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200582static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +0100583show_sas_device_type(struct device *dev,
584 struct device_attribute *attr, char *buf)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200585{
Tony Jonesee959b02008-02-22 00:13:36 +0100586 struct sas_phy *phy = transport_class_to_phy(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200587
588 if (!phy->identify.device_type)
589 return snprintf(buf, 20, "none\n");
590 return get_sas_device_type_names(phy->identify.device_type, buf);
591}
Tony Jonesee959b02008-02-22 00:13:36 +0100592static DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200593
Tony Jonesee959b02008-02-22 00:13:36 +0100594static ssize_t do_sas_phy_enable(struct device *dev,
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800595 size_t count, int enable)
596{
Tony Jonesee959b02008-02-22 00:13:36 +0100597 struct sas_phy *phy = transport_class_to_phy(dev);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800598 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
599 struct sas_internal *i = to_sas_internal(shost->transportt);
600 int error;
601
602 error = i->f->phy_enable(phy, enable);
603 if (error)
604 return error;
605 phy->enabled = enable;
606 return count;
607};
608
Tony Jonesee959b02008-02-22 00:13:36 +0100609static ssize_t
610store_sas_phy_enable(struct device *dev, struct device_attribute *attr,
611 const char *buf, size_t count)
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800612{
613 if (count < 1)
614 return -EINVAL;
615
616 switch (buf[0]) {
617 case '0':
Tony Jonesee959b02008-02-22 00:13:36 +0100618 do_sas_phy_enable(dev, count, 0);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800619 break;
620 case '1':
Tony Jonesee959b02008-02-22 00:13:36 +0100621 do_sas_phy_enable(dev, count, 1);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800622 break;
623 default:
624 return -EINVAL;
625 }
626
627 return count;
628}
629
Tony Jonesee959b02008-02-22 00:13:36 +0100630static ssize_t
631show_sas_phy_enable(struct device *dev, struct device_attribute *attr,
632 char *buf)
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800633{
Tony Jonesee959b02008-02-22 00:13:36 +0100634 struct sas_phy *phy = transport_class_to_phy(dev);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800635
636 return snprintf(buf, 20, "%d", phy->enabled);
637}
638
Tony Jonesee959b02008-02-22 00:13:36 +0100639static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800640 store_sas_phy_enable);
641
Tony Jonesee959b02008-02-22 00:13:36 +0100642static ssize_t
643do_sas_phy_reset(struct device *dev, size_t count, int hard_reset)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200644{
Tony Jonesee959b02008-02-22 00:13:36 +0100645 struct sas_phy *phy = transport_class_to_phy(dev);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200646 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
647 struct sas_internal *i = to_sas_internal(shost->transportt);
648 int error;
649
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200650 error = i->f->phy_reset(phy, hard_reset);
651 if (error)
652 return error;
Dan Williams16d3db12012-01-30 22:53:51 -0800653 phy->enabled = 1;
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200654 return count;
655};
656
Tony Jonesee959b02008-02-22 00:13:36 +0100657static ssize_t
658store_sas_link_reset(struct device *dev, struct device_attribute *attr,
659 const char *buf, size_t count)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200660{
Tony Jonesee959b02008-02-22 00:13:36 +0100661 return do_sas_phy_reset(dev, count, 0);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200662}
Tony Jonesee959b02008-02-22 00:13:36 +0100663static DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200664
Tony Jonesee959b02008-02-22 00:13:36 +0100665static ssize_t
666store_sas_hard_reset(struct device *dev, struct device_attribute *attr,
667 const char *buf, size_t count)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200668{
Tony Jonesee959b02008-02-22 00:13:36 +0100669 return do_sas_phy_reset(dev, count, 1);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200670}
Tony Jonesee959b02008-02-22 00:13:36 +0100671static DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200672
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200673sas_phy_protocol_attr(identify.initiator_port_protocols,
674 initiator_port_protocols);
675sas_phy_protocol_attr(identify.target_port_protocols,
676 target_port_protocols);
677sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
678 unsigned long long);
679sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500680//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200681sas_phy_linkspeed_attr(negotiated_linkrate);
682sas_phy_linkspeed_attr(minimum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500683sas_phy_linkspeed_rw_attr(minimum_linkrate);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200684sas_phy_linkspeed_attr(maximum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500685sas_phy_linkspeed_rw_attr(maximum_linkrate);
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200686sas_phy_linkerror_attr(invalid_dword_count);
687sas_phy_linkerror_attr(running_disparity_error_count);
688sas_phy_linkerror_attr(loss_of_dword_sync_count);
689sas_phy_linkerror_attr(phy_reset_problem_count);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200690
Dan Williams0b3e09d2011-12-20 01:03:48 -0800691static int sas_phy_setup(struct transport_container *tc, struct device *dev,
692 struct device *cdev)
693{
694 struct sas_phy *phy = dev_to_phy(dev);
695 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
696 struct sas_internal *i = to_sas_internal(shost->transportt);
697
698 if (i->f->phy_setup)
699 i->f->phy_setup(phy);
700
701 return 0;
702}
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200703
704static DECLARE_TRANSPORT_CLASS(sas_phy_class,
Dan Williams0b3e09d2011-12-20 01:03:48 -0800705 "sas_phy", sas_phy_setup, NULL, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200706
707static int sas_phy_match(struct attribute_container *cont, struct device *dev)
708{
709 struct Scsi_Host *shost;
710 struct sas_internal *i;
711
712 if (!scsi_is_sas_phy(dev))
713 return 0;
714 shost = dev_to_shost(dev->parent);
715
716 if (!shost->transportt)
717 return 0;
718 if (shost->transportt->host_attrs.ac.class !=
719 &sas_host_class.class)
720 return 0;
721
722 i = to_sas_internal(shost->transportt);
723 return &i->phy_attr_cont.ac == cont;
724}
725
726static void sas_phy_release(struct device *dev)
727{
728 struct sas_phy *phy = dev_to_phy(dev);
Dan Williams0b3e09d2011-12-20 01:03:48 -0800729 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
730 struct sas_internal *i = to_sas_internal(shost->transportt);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200731
Dan Williams0b3e09d2011-12-20 01:03:48 -0800732 if (i->f->phy_release)
733 i->f->phy_release(phy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200734 put_device(dev->parent);
735 kfree(phy);
736}
737
738/**
Rob Landleyeb448202007-11-03 13:30:39 -0500739 * sas_phy_alloc - allocates and initialize a SAS PHY structure
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200740 * @parent: Parent device
Moore, Ericd99ca412006-01-26 16:20:02 -0700741 * @number: Phy index
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200742 *
743 * Allocates an SAS PHY structure. It will be added in the device tree
744 * below the device specified by @parent, which has to be either a Scsi_Host
745 * or sas_rphy.
746 *
747 * Returns:
748 * SAS PHY allocated or %NULL if the allocation failed.
749 */
750struct sas_phy *sas_phy_alloc(struct device *parent, int number)
751{
752 struct Scsi_Host *shost = dev_to_shost(parent);
753 struct sas_phy *phy;
754
Jes Sorensen24669f752006-01-16 10:31:18 -0500755 phy = kzalloc(sizeof(*phy), GFP_KERNEL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200756 if (!phy)
757 return NULL;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200758
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200759 phy->number = number;
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800760 phy->enabled = 1;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200761
762 device_initialize(&phy->dev);
763 phy->dev.parent = get_device(parent);
764 phy->dev.release = sas_phy_release;
James Bottomley65c92b02006-06-28 12:22:50 -0400765 INIT_LIST_HEAD(&phy->port_siblings);
James Bottomley79cb1812006-03-13 13:50:04 -0600766 if (scsi_is_sas_expander_device(parent)) {
767 struct sas_rphy *rphy = dev_to_rphy(parent);
Kay Sievers71610f52008-12-03 22:41:36 +0100768 dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,
James Bottomley79cb1812006-03-13 13:50:04 -0600769 rphy->scsi_target_id, number);
770 } else
Kay Sievers71610f52008-12-03 22:41:36 +0100771 dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200772
773 transport_setup_device(&phy->dev);
774
775 return phy;
776}
777EXPORT_SYMBOL(sas_phy_alloc);
778
779/**
Rob Landleyeb448202007-11-03 13:30:39 -0500780 * sas_phy_add - add a SAS PHY to the device hierarchy
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200781 * @phy: The PHY to be added
782 *
783 * Publishes a SAS PHY to the rest of the system.
784 */
785int sas_phy_add(struct sas_phy *phy)
786{
787 int error;
788
789 error = device_add(&phy->dev);
790 if (!error) {
791 transport_add_device(&phy->dev);
792 transport_configure_device(&phy->dev);
793 }
794
795 return error;
796}
797EXPORT_SYMBOL(sas_phy_add);
798
799/**
Rob Landleyeb448202007-11-03 13:30:39 -0500800 * sas_phy_free - free a SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200801 * @phy: SAS PHY to free
802 *
803 * Frees the specified SAS PHY.
804 *
805 * Note:
806 * This function must only be called on a PHY that has not
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200807 * successfully been added using sas_phy_add().
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200808 */
809void sas_phy_free(struct sas_phy *phy)
810{
811 transport_destroy_device(&phy->dev);
Mike Anderson92aab642006-03-27 09:37:28 -0800812 put_device(&phy->dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200813}
814EXPORT_SYMBOL(sas_phy_free);
815
816/**
Rob Landleyeb448202007-11-03 13:30:39 -0500817 * sas_phy_delete - remove SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200818 * @phy: SAS PHY to remove
819 *
820 * Removes the specified SAS PHY. If the SAS PHY has an
821 * associated remote PHY it is removed before.
822 */
823void
824sas_phy_delete(struct sas_phy *phy)
825{
826 struct device *dev = &phy->dev;
827
James Bottomley65c92b02006-06-28 12:22:50 -0400828 /* this happens if the phy is still part of a port when deleted */
829 BUG_ON(!list_empty(&phy->port_siblings));
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200830
831 transport_remove_device(dev);
832 device_del(dev);
833 transport_destroy_device(dev);
Mike Anderson92aab642006-03-27 09:37:28 -0800834 put_device(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200835}
836EXPORT_SYMBOL(sas_phy_delete);
837
838/**
Rob Landleyeb448202007-11-03 13:30:39 -0500839 * scsi_is_sas_phy - check if a struct device represents a SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200840 * @dev: device to check
841 *
842 * Returns:
843 * %1 if the device represents a SAS PHY, %0 else
844 */
845int scsi_is_sas_phy(const struct device *dev)
846{
847 return dev->release == sas_phy_release;
848}
849EXPORT_SYMBOL(scsi_is_sas_phy);
850
851/*
James Bottomley65c92b02006-06-28 12:22:50 -0400852 * SAS Port attributes
853 */
854#define sas_port_show_simple(field, name, format_string, cast) \
855static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100856show_sas_port_##name(struct device *dev, \
857 struct device_attribute *attr, char *buf) \
James Bottomley65c92b02006-06-28 12:22:50 -0400858{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100859 struct sas_port *port = transport_class_to_sas_port(dev); \
James Bottomley65c92b02006-06-28 12:22:50 -0400860 \
861 return snprintf(buf, 20, format_string, cast port->field); \
862}
863
864#define sas_port_simple_attr(field, name, format_string, type) \
865 sas_port_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +0100866static DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
James Bottomley65c92b02006-06-28 12:22:50 -0400867
868sas_port_simple_attr(num_phys, num_phys, "%d\n", int);
869
870static DECLARE_TRANSPORT_CLASS(sas_port_class,
871 "sas_port", NULL, NULL, NULL);
872
873static int sas_port_match(struct attribute_container *cont, struct device *dev)
874{
875 struct Scsi_Host *shost;
876 struct sas_internal *i;
877
878 if (!scsi_is_sas_port(dev))
879 return 0;
880 shost = dev_to_shost(dev->parent);
881
882 if (!shost->transportt)
883 return 0;
884 if (shost->transportt->host_attrs.ac.class !=
885 &sas_host_class.class)
886 return 0;
887
888 i = to_sas_internal(shost->transportt);
889 return &i->port_attr_cont.ac == cont;
890}
891
892
893static void sas_port_release(struct device *dev)
894{
895 struct sas_port *port = dev_to_sas_port(dev);
896
897 BUG_ON(!list_empty(&port->phy_list));
898
899 put_device(dev->parent);
900 kfree(port);
901}
902
903static void sas_port_create_link(struct sas_port *port,
904 struct sas_phy *phy)
905{
Darrick J. Wong21434962007-01-26 14:08:46 -0800906 int res;
907
908 res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
Kay Sievers71610f52008-12-03 22:41:36 +0100909 dev_name(&phy->dev));
Darrick J. Wong21434962007-01-26 14:08:46 -0800910 if (res)
911 goto err;
912 res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
913 if (res)
914 goto err;
915 return;
916err:
917 printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700918 __func__, res);
James Bottomley65c92b02006-06-28 12:22:50 -0400919}
920
921static void sas_port_delete_link(struct sas_port *port,
922 struct sas_phy *phy)
923{
Kay Sievers71610f52008-12-03 22:41:36 +0100924 sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));
James Bottomley65c92b02006-06-28 12:22:50 -0400925 sysfs_remove_link(&phy->dev.kobj, "port");
926}
927
928/** sas_port_alloc - allocate and initialize a SAS port structure
929 *
930 * @parent: parent device
931 * @port_id: port number
932 *
933 * Allocates a SAS port structure. It will be added to the device tree
934 * below the device specified by @parent which must be either a Scsi_Host
935 * or a sas_expander_device.
936 *
937 * Returns %NULL on error
938 */
939struct sas_port *sas_port_alloc(struct device *parent, int port_id)
940{
941 struct Scsi_Host *shost = dev_to_shost(parent);
942 struct sas_port *port;
943
944 port = kzalloc(sizeof(*port), GFP_KERNEL);
945 if (!port)
946 return NULL;
947
948 port->port_identifier = port_id;
949
950 device_initialize(&port->dev);
951
952 port->dev.parent = get_device(parent);
953 port->dev.release = sas_port_release;
954
955 mutex_init(&port->phy_list_mutex);
956 INIT_LIST_HEAD(&port->phy_list);
957
958 if (scsi_is_sas_expander_device(parent)) {
959 struct sas_rphy *rphy = dev_to_rphy(parent);
Kay Sievers71610f52008-12-03 22:41:36 +0100960 dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,
961 rphy->scsi_target_id, port->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -0400962 } else
Kay Sievers71610f52008-12-03 22:41:36 +0100963 dev_set_name(&port->dev, "port-%d:%d", shost->host_no,
964 port->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -0400965
966 transport_setup_device(&port->dev);
967
968 return port;
969}
970EXPORT_SYMBOL(sas_port_alloc);
971
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500972/** sas_port_alloc_num - allocate and initialize a SAS port structure
973 *
974 * @parent: parent device
975 *
976 * Allocates a SAS port structure and a number to go with it. This
977 * interface is really for adapters where the port number has no
978 * meansing, so the sas class should manage them. It will be added to
979 * the device tree below the device specified by @parent which must be
980 * either a Scsi_Host or a sas_expander_device.
981 *
982 * Returns %NULL on error
983 */
984struct sas_port *sas_port_alloc_num(struct device *parent)
985{
986 int index;
987 struct Scsi_Host *shost = dev_to_shost(parent);
988 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
989
990 /* FIXME: use idr for this eventually */
991 mutex_lock(&sas_host->lock);
992 if (scsi_is_sas_expander_device(parent)) {
993 struct sas_rphy *rphy = dev_to_rphy(parent);
994 struct sas_expander_device *exp = rphy_to_expander_device(rphy);
995
996 index = exp->next_port_id++;
997 } else
998 index = sas_host->next_port_id++;
999 mutex_unlock(&sas_host->lock);
1000 return sas_port_alloc(parent, index);
1001}
1002EXPORT_SYMBOL(sas_port_alloc_num);
1003
James Bottomley65c92b02006-06-28 12:22:50 -04001004/**
1005 * sas_port_add - add a SAS port to the device hierarchy
James Bottomley65c92b02006-06-28 12:22:50 -04001006 * @port: port to be added
1007 *
1008 * publishes a port to the rest of the system
1009 */
1010int sas_port_add(struct sas_port *port)
1011{
1012 int error;
1013
1014 /* No phys should be added until this is made visible */
1015 BUG_ON(!list_empty(&port->phy_list));
1016
1017 error = device_add(&port->dev);
1018
1019 if (error)
1020 return error;
1021
1022 transport_add_device(&port->dev);
1023 transport_configure_device(&port->dev);
1024
1025 return 0;
1026}
1027EXPORT_SYMBOL(sas_port_add);
1028
1029/**
Rob Landleyeb448202007-11-03 13:30:39 -05001030 * sas_port_free - free a SAS PORT
James Bottomley65c92b02006-06-28 12:22:50 -04001031 * @port: SAS PORT to free
1032 *
1033 * Frees the specified SAS PORT.
1034 *
1035 * Note:
1036 * This function must only be called on a PORT that has not
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001037 * successfully been added using sas_port_add().
James Bottomley65c92b02006-06-28 12:22:50 -04001038 */
1039void sas_port_free(struct sas_port *port)
1040{
1041 transport_destroy_device(&port->dev);
1042 put_device(&port->dev);
1043}
1044EXPORT_SYMBOL(sas_port_free);
1045
1046/**
Rob Landleyeb448202007-11-03 13:30:39 -05001047 * sas_port_delete - remove SAS PORT
James Bottomley65c92b02006-06-28 12:22:50 -04001048 * @port: SAS PORT to remove
1049 *
1050 * Removes the specified SAS PORT. If the SAS PORT has an
1051 * associated phys, unlink them from the port as well.
1052 */
1053void sas_port_delete(struct sas_port *port)
1054{
1055 struct device *dev = &port->dev;
1056 struct sas_phy *phy, *tmp_phy;
1057
1058 if (port->rphy) {
1059 sas_rphy_delete(port->rphy);
1060 port->rphy = NULL;
1061 }
1062
1063 mutex_lock(&port->phy_list_mutex);
1064 list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
1065 port_siblings) {
1066 sas_port_delete_link(port, phy);
1067 list_del_init(&phy->port_siblings);
1068 }
1069 mutex_unlock(&port->phy_list_mutex);
1070
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001071 if (port->is_backlink) {
1072 struct device *parent = port->dev.parent;
1073
Kay Sievers71610f52008-12-03 22:41:36 +01001074 sysfs_remove_link(&port->dev.kobj, dev_name(parent));
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001075 port->is_backlink = 0;
1076 }
1077
James Bottomley65c92b02006-06-28 12:22:50 -04001078 transport_remove_device(dev);
1079 device_del(dev);
1080 transport_destroy_device(dev);
1081 put_device(dev);
1082}
1083EXPORT_SYMBOL(sas_port_delete);
1084
1085/**
Rob Landleyeb448202007-11-03 13:30:39 -05001086 * scsi_is_sas_port - check if a struct device represents a SAS port
James Bottomley65c92b02006-06-28 12:22:50 -04001087 * @dev: device to check
1088 *
1089 * Returns:
1090 * %1 if the device represents a SAS Port, %0 else
1091 */
1092int scsi_is_sas_port(const struct device *dev)
1093{
1094 return dev->release == sas_port_release;
1095}
1096EXPORT_SYMBOL(scsi_is_sas_port);
1097
1098/**
Dan Williamsf41a0c42011-12-21 21:33:17 -08001099 * sas_port_get_phy - try to take a reference on a port member
1100 * @port: port to check
1101 */
1102struct sas_phy *sas_port_get_phy(struct sas_port *port)
1103{
1104 struct sas_phy *phy;
1105
1106 mutex_lock(&port->phy_list_mutex);
1107 if (list_empty(&port->phy_list))
1108 phy = NULL;
1109 else {
1110 struct list_head *ent = port->phy_list.next;
1111
1112 phy = list_entry(ent, typeof(*phy), port_siblings);
1113 get_device(&phy->dev);
1114 }
1115 mutex_unlock(&port->phy_list_mutex);
1116
1117 return phy;
1118}
1119EXPORT_SYMBOL(sas_port_get_phy);
1120
1121/**
James Bottomley65c92b02006-06-28 12:22:50 -04001122 * sas_port_add_phy - add another phy to a port to form a wide port
1123 * @port: port to add the phy to
1124 * @phy: phy to add
1125 *
1126 * When a port is initially created, it is empty (has no phys). All
1127 * ports must have at least one phy to operated, and all wide ports
1128 * must have at least two. The current code makes no difference
1129 * between ports and wide ports, but the only object that can be
1130 * connected to a remote device is a port, so ports must be formed on
1131 * all devices with phys if they're connected to anything.
1132 */
1133void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
1134{
1135 mutex_lock(&port->phy_list_mutex);
1136 if (unlikely(!list_empty(&phy->port_siblings))) {
1137 /* make sure we're already on this port */
1138 struct sas_phy *tmp;
1139
1140 list_for_each_entry(tmp, &port->phy_list, port_siblings)
1141 if (tmp == phy)
1142 break;
1143 /* If this trips, you added a phy that was already
1144 * part of a different port */
1145 if (unlikely(tmp != phy)) {
Kay Sievers71610f52008-12-03 22:41:36 +01001146 dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n",
1147 dev_name(&phy->dev));
James Bottomley65c92b02006-06-28 12:22:50 -04001148 BUG();
1149 }
1150 } else {
1151 sas_port_create_link(port, phy);
1152 list_add_tail(&phy->port_siblings, &port->phy_list);
1153 port->num_phys++;
1154 }
1155 mutex_unlock(&port->phy_list_mutex);
1156}
1157EXPORT_SYMBOL(sas_port_add_phy);
1158
1159/**
1160 * sas_port_delete_phy - remove a phy from a port or wide port
1161 * @port: port to remove the phy from
1162 * @phy: phy to remove
1163 *
1164 * This operation is used for tearing down ports again. It must be
1165 * done to every port or wide port before calling sas_port_delete.
1166 */
1167void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
1168{
1169 mutex_lock(&port->phy_list_mutex);
1170 sas_port_delete_link(port, phy);
1171 list_del_init(&phy->port_siblings);
1172 port->num_phys--;
1173 mutex_unlock(&port->phy_list_mutex);
1174}
1175EXPORT_SYMBOL(sas_port_delete_phy);
1176
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001177void sas_port_mark_backlink(struct sas_port *port)
1178{
Darrick J. Wong21434962007-01-26 14:08:46 -08001179 int res;
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001180 struct device *parent = port->dev.parent->parent->parent;
1181
1182 if (port->is_backlink)
1183 return;
1184 port->is_backlink = 1;
Darrick J. Wong21434962007-01-26 14:08:46 -08001185 res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
Kay Sievers71610f52008-12-03 22:41:36 +01001186 dev_name(parent));
Darrick J. Wong21434962007-01-26 14:08:46 -08001187 if (res)
1188 goto err;
1189 return;
1190err:
1191 printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001192 __func__, res);
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001193
1194}
1195EXPORT_SYMBOL(sas_port_mark_backlink);
1196
James Bottomley65c92b02006-06-28 12:22:50 -04001197/*
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001198 * SAS remote PHY attributes.
1199 */
1200
1201#define sas_rphy_show_simple(field, name, format_string, cast) \
1202static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001203show_sas_rphy_##name(struct device *dev, \
1204 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001205{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001206 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001207 \
1208 return snprintf(buf, 20, format_string, cast rphy->field); \
1209}
1210
1211#define sas_rphy_simple_attr(field, name, format_string, type) \
1212 sas_rphy_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001213static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001214 show_sas_rphy_##name, NULL)
1215
1216#define sas_rphy_show_protocol(field, name) \
1217static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001218show_sas_rphy_##name(struct device *dev, \
1219 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001220{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001221 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001222 \
1223 if (!rphy->field) \
1224 return snprintf(buf, 20, "none\n"); \
1225 return get_sas_protocol_names(rphy->field, buf); \
1226}
1227
1228#define sas_rphy_protocol_attr(field, name) \
1229 sas_rphy_show_protocol(field, name) \
Tony Jonesee959b02008-02-22 00:13:36 +01001230static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001231 show_sas_rphy_##name, NULL)
1232
1233static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001234show_sas_rphy_device_type(struct device *dev,
1235 struct device_attribute *attr, char *buf)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001236{
Tony Jonesee959b02008-02-22 00:13:36 +01001237 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001238
1239 if (!rphy->identify.device_type)
1240 return snprintf(buf, 20, "none\n");
1241 return get_sas_device_type_names(
1242 rphy->identify.device_type, buf);
1243}
1244
Tony Jonesee959b02008-02-22 00:13:36 +01001245static SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001246 show_sas_rphy_device_type, NULL);
1247
Christoph Hellwiga0125642006-02-16 13:31:47 +01001248static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001249show_sas_rphy_enclosure_identifier(struct device *dev,
1250 struct device_attribute *attr, char *buf)
Christoph Hellwiga0125642006-02-16 13:31:47 +01001251{
Tony Jonesee959b02008-02-22 00:13:36 +01001252 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwiga0125642006-02-16 13:31:47 +01001253 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
1254 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
1255 struct sas_internal *i = to_sas_internal(shost->transportt);
1256 u64 identifier;
1257 int error;
1258
Christoph Hellwiga0125642006-02-16 13:31:47 +01001259 error = i->f->get_enclosure_identifier(rphy, &identifier);
1260 if (error)
1261 return error;
1262 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
1263}
1264
Tony Jonesee959b02008-02-22 00:13:36 +01001265static SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
Christoph Hellwiga0125642006-02-16 13:31:47 +01001266 show_sas_rphy_enclosure_identifier, NULL);
1267
1268static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001269show_sas_rphy_bay_identifier(struct device *dev,
1270 struct device_attribute *attr, char *buf)
Christoph Hellwiga0125642006-02-16 13:31:47 +01001271{
Tony Jonesee959b02008-02-22 00:13:36 +01001272 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwiga0125642006-02-16 13:31:47 +01001273 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
1274 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
1275 struct sas_internal *i = to_sas_internal(shost->transportt);
1276 int val;
1277
Christoph Hellwiga0125642006-02-16 13:31:47 +01001278 val = i->f->get_bay_identifier(rphy);
1279 if (val < 0)
1280 return val;
1281 return sprintf(buf, "%d\n", val);
1282}
1283
Tony Jonesee959b02008-02-22 00:13:36 +01001284static SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
Christoph Hellwiga0125642006-02-16 13:31:47 +01001285 show_sas_rphy_bay_identifier, NULL);
1286
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001287sas_rphy_protocol_attr(identify.initiator_port_protocols,
1288 initiator_port_protocols);
1289sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
1290sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
1291 unsigned long long);
1292sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
Hannes Reineckecdc43ae2016-03-14 10:43:08 +01001293sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001294
James Bottomley42ab0362006-03-04 09:10:18 -06001295/* only need 8 bytes of data plus header (4 or 8) */
1296#define BUF_SIZE 64
1297
1298int sas_read_port_mode_page(struct scsi_device *sdev)
1299{
1300 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
James Bottomley0f880092010-01-18 10:14:51 -06001301 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
James Bottomley42ab0362006-03-04 09:10:18 -06001302 struct scsi_mode_data mode_data;
1303 int res, error;
1304
James Bottomley42ab0362006-03-04 09:10:18 -06001305 if (!buffer)
1306 return -ENOMEM;
1307
1308 res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
1309 &mode_data, NULL);
1310
1311 error = -EINVAL;
1312 if (!scsi_status_is_good(res))
1313 goto out;
1314
1315 msdata = buffer + mode_data.header_length +
1316 mode_data.block_descriptor_length;
1317
1318 if (msdata - buffer > BUF_SIZE - 8)
1319 goto out;
1320
1321 error = 0;
1322
1323 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
1324 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
1325 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
1326
1327 out:
1328 kfree(buffer);
1329 return error;
1330}
1331EXPORT_SYMBOL(sas_read_port_mode_page);
1332
James Bottomley79cb1812006-03-13 13:50:04 -06001333static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
1334 "sas_end_device", NULL, NULL, NULL);
1335
James Bottomley42ab0362006-03-04 09:10:18 -06001336#define sas_end_dev_show_simple(field, name, format_string, cast) \
1337static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001338show_sas_end_dev_##name(struct device *dev, \
1339 struct device_attribute *attr, char *buf) \
James Bottomley42ab0362006-03-04 09:10:18 -06001340{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001341 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
James Bottomley42ab0362006-03-04 09:10:18 -06001342 struct sas_end_device *rdev = rphy_to_end_device(rphy); \
1343 \
1344 return snprintf(buf, 20, format_string, cast rdev->field); \
1345}
1346
1347#define sas_end_dev_simple_attr(field, name, format_string, type) \
1348 sas_end_dev_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001349static SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, \
James Bottomley42ab0362006-03-04 09:10:18 -06001350 show_sas_end_dev_##name, NULL)
1351
1352sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
1353sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
1354 "%d\n", int);
1355sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
1356 "%d\n", int);
James Bottomley0f880092010-01-18 10:14:51 -06001357sas_end_dev_simple_attr(tlr_supported, tlr_supported,
1358 "%d\n", int);
1359sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
1360 "%d\n", int);
James Bottomley42ab0362006-03-04 09:10:18 -06001361
James Bottomley79cb1812006-03-13 13:50:04 -06001362static DECLARE_TRANSPORT_CLASS(sas_expander_class,
1363 "sas_expander", NULL, NULL, NULL);
1364
1365#define sas_expander_show_simple(field, name, format_string, cast) \
1366static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001367show_sas_expander_##name(struct device *dev, \
1368 struct device_attribute *attr, char *buf) \
James Bottomley79cb1812006-03-13 13:50:04 -06001369{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001370 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
James Bottomley79cb1812006-03-13 13:50:04 -06001371 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
1372 \
1373 return snprintf(buf, 20, format_string, cast edev->field); \
1374}
1375
1376#define sas_expander_simple_attr(field, name, format_string, type) \
1377 sas_expander_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001378static SAS_DEVICE_ATTR(expander, name, S_IRUGO, \
James Bottomley79cb1812006-03-13 13:50:04 -06001379 show_sas_expander_##name, NULL)
1380
1381sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
1382sas_expander_simple_attr(product_id, product_id, "%s\n", char *);
1383sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
1384sas_expander_simple_attr(component_vendor_id, component_vendor_id,
1385 "%s\n", char *);
1386sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
1387sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
1388 unsigned int);
1389sas_expander_simple_attr(level, level, "%d\n", int);
James Bottomley42ab0362006-03-04 09:10:18 -06001390
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001391static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
James Bottomley2f8600d2006-03-18 15:00:50 -06001392 "sas_device", NULL, NULL, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001393
1394static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
1395{
1396 struct Scsi_Host *shost;
1397 struct sas_internal *i;
1398
1399 if (!scsi_is_sas_rphy(dev))
1400 return 0;
1401 shost = dev_to_shost(dev->parent->parent);
1402
1403 if (!shost->transportt)
1404 return 0;
1405 if (shost->transportt->host_attrs.ac.class !=
1406 &sas_host_class.class)
1407 return 0;
1408
1409 i = to_sas_internal(shost->transportt);
1410 return &i->rphy_attr_cont.ac == cont;
1411}
1412
James Bottomley42ab0362006-03-04 09:10:18 -06001413static int sas_end_dev_match(struct attribute_container *cont,
1414 struct device *dev)
1415{
1416 struct Scsi_Host *shost;
1417 struct sas_internal *i;
1418 struct sas_rphy *rphy;
1419
1420 if (!scsi_is_sas_rphy(dev))
1421 return 0;
1422 shost = dev_to_shost(dev->parent->parent);
1423 rphy = dev_to_rphy(dev);
1424
1425 if (!shost->transportt)
1426 return 0;
1427 if (shost->transportt->host_attrs.ac.class !=
1428 &sas_host_class.class)
1429 return 0;
1430
1431 i = to_sas_internal(shost->transportt);
1432 return &i->end_dev_attr_cont.ac == cont &&
James Bottomley2f8600d2006-03-18 15:00:50 -06001433 rphy->identify.device_type == SAS_END_DEVICE;
James Bottomley42ab0362006-03-04 09:10:18 -06001434}
1435
James Bottomley79cb1812006-03-13 13:50:04 -06001436static int sas_expander_match(struct attribute_container *cont,
1437 struct device *dev)
1438{
1439 struct Scsi_Host *shost;
1440 struct sas_internal *i;
1441 struct sas_rphy *rphy;
1442
1443 if (!scsi_is_sas_rphy(dev))
1444 return 0;
1445 shost = dev_to_shost(dev->parent->parent);
1446 rphy = dev_to_rphy(dev);
1447
1448 if (!shost->transportt)
1449 return 0;
1450 if (shost->transportt->host_attrs.ac.class !=
1451 &sas_host_class.class)
1452 return 0;
1453
1454 i = to_sas_internal(shost->transportt);
1455 return &i->expander_attr_cont.ac == cont &&
1456 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
James Bottomley2f8600d2006-03-18 15:00:50 -06001457 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
James Bottomley79cb1812006-03-13 13:50:04 -06001458}
1459
James Bottomley2f8600d2006-03-18 15:00:50 -06001460static void sas_expander_release(struct device *dev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001461{
1462 struct sas_rphy *rphy = dev_to_rphy(dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001463 struct sas_expander_device *edev = rphy_to_expander_device(rphy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001464
FUJITA Tomonori93c20a52008-04-19 00:43:15 +09001465 if (rphy->q)
1466 blk_cleanup_queue(rphy->q);
1467
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001468 put_device(dev->parent);
James Bottomley2f8600d2006-03-18 15:00:50 -06001469 kfree(edev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001470}
1471
James Bottomley2f8600d2006-03-18 15:00:50 -06001472static void sas_end_device_release(struct device *dev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001473{
James Bottomley2f8600d2006-03-18 15:00:50 -06001474 struct sas_rphy *rphy = dev_to_rphy(dev);
1475 struct sas_end_device *edev = rphy_to_end_device(rphy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001476
FUJITA Tomonori93c20a52008-04-19 00:43:15 +09001477 if (rphy->q)
1478 blk_cleanup_queue(rphy->q);
1479
James Bottomley2f8600d2006-03-18 15:00:50 -06001480 put_device(dev->parent);
1481 kfree(edev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001482}
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001483
1484/**
Masahiro Yamada183b8022017-02-27 14:29:20 -08001485 * sas_rphy_initialize - common rphy initialization
James Bottomleyc5943d32006-06-12 09:09:18 -05001486 * @rphy: rphy to initialise
1487 *
1488 * Used by both sas_end_device_alloc() and sas_expander_alloc() to
1489 * initialise the common rphy component of each.
1490 */
1491static void sas_rphy_initialize(struct sas_rphy *rphy)
1492{
1493 INIT_LIST_HEAD(&rphy->list);
1494}
1495
1496/**
James Bottomley42ab0362006-03-04 09:10:18 -06001497 * sas_end_device_alloc - allocate an rphy for an end device
Rob Landleyeb448202007-11-03 13:30:39 -05001498 * @parent: which port
James Bottomley42ab0362006-03-04 09:10:18 -06001499 *
1500 * Allocates an SAS remote PHY structure, connected to @parent.
1501 *
1502 * Returns:
1503 * SAS PHY allocated or %NULL if the allocation failed.
1504 */
James Bottomley65c92b02006-06-28 12:22:50 -04001505struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
James Bottomley42ab0362006-03-04 09:10:18 -06001506{
1507 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
1508 struct sas_end_device *rdev;
1509
1510 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
1511 if (!rdev) {
James Bottomley42ab0362006-03-04 09:10:18 -06001512 return NULL;
1513 }
1514
1515 device_initialize(&rdev->rphy.dev);
1516 rdev->rphy.dev.parent = get_device(&parent->dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001517 rdev->rphy.dev.release = sas_end_device_release;
James Bottomley65c92b02006-06-28 12:22:50 -04001518 if (scsi_is_sas_expander_device(parent->dev.parent)) {
1519 struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
Kay Sievers71610f52008-12-03 22:41:36 +01001520 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",
1521 shost->host_no, rphy->scsi_target_id,
1522 parent->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -04001523 } else
Kay Sievers71610f52008-12-03 22:41:36 +01001524 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",
1525 shost->host_no, parent->port_identifier);
James Bottomley42ab0362006-03-04 09:10:18 -06001526 rdev->rphy.identify.device_type = SAS_END_DEVICE;
James Bottomleyc5943d32006-06-12 09:09:18 -05001527 sas_rphy_initialize(&rdev->rphy);
James Bottomley42ab0362006-03-04 09:10:18 -06001528 transport_setup_device(&rdev->rphy.dev);
1529
1530 return &rdev->rphy;
1531}
1532EXPORT_SYMBOL(sas_end_device_alloc);
1533
James Bottomley79cb1812006-03-13 13:50:04 -06001534/**
1535 * sas_expander_alloc - allocate an rphy for an end device
Rob Landleyeb448202007-11-03 13:30:39 -05001536 * @parent: which port
1537 * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
James Bottomley79cb1812006-03-13 13:50:04 -06001538 *
1539 * Allocates an SAS remote PHY structure, connected to @parent.
1540 *
1541 * Returns:
1542 * SAS PHY allocated or %NULL if the allocation failed.
1543 */
James Bottomley65c92b02006-06-28 12:22:50 -04001544struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
James Bottomley79cb1812006-03-13 13:50:04 -06001545 enum sas_device_type type)
1546{
1547 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
1548 struct sas_expander_device *rdev;
1549 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1550
1551 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
1552 type != SAS_FANOUT_EXPANDER_DEVICE);
1553
1554 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
1555 if (!rdev) {
James Bottomley79cb1812006-03-13 13:50:04 -06001556 return NULL;
1557 }
1558
1559 device_initialize(&rdev->rphy.dev);
1560 rdev->rphy.dev.parent = get_device(&parent->dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001561 rdev->rphy.dev.release = sas_expander_release;
James Bottomley79cb1812006-03-13 13:50:04 -06001562 mutex_lock(&sas_host->lock);
1563 rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
1564 mutex_unlock(&sas_host->lock);
Kay Sievers71610f52008-12-03 22:41:36 +01001565 dev_set_name(&rdev->rphy.dev, "expander-%d:%d",
1566 shost->host_no, rdev->rphy.scsi_target_id);
James Bottomley79cb1812006-03-13 13:50:04 -06001567 rdev->rphy.identify.device_type = type;
James Bottomleyc5943d32006-06-12 09:09:18 -05001568 sas_rphy_initialize(&rdev->rphy);
James Bottomley79cb1812006-03-13 13:50:04 -06001569 transport_setup_device(&rdev->rphy.dev);
1570
1571 return &rdev->rphy;
1572}
1573EXPORT_SYMBOL(sas_expander_alloc);
James Bottomley42ab0362006-03-04 09:10:18 -06001574
1575/**
Rob Landleyeb448202007-11-03 13:30:39 -05001576 * sas_rphy_add - add a SAS remote PHY to the device hierarchy
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001577 * @rphy: The remote PHY to be added
1578 *
1579 * Publishes a SAS remote PHY to the rest of the system.
1580 */
1581int sas_rphy_add(struct sas_rphy *rphy)
1582{
James Bottomley65c92b02006-06-28 12:22:50 -04001583 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001584 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
1585 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1586 struct sas_identify *identify = &rphy->identify;
1587 int error;
1588
1589 if (parent->rphy)
1590 return -ENXIO;
1591 parent->rphy = rphy;
1592
1593 error = device_add(&rphy->dev);
1594 if (error)
1595 return error;
1596 transport_add_device(&rphy->dev);
1597 transport_configure_device(&rphy->dev);
James Bottomley39dca552007-07-20 18:22:17 -05001598 if (sas_bsg_initialize(shost, rphy))
Kay Sievers71610f52008-12-03 22:41:36 +01001599 printk("fail to a bsg device %s\n", dev_name(&rphy->dev));
James Bottomley39dca552007-07-20 18:22:17 -05001600
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001601
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001602 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001603 list_add_tail(&rphy->list, &sas_host->rphy_list);
1604 if (identify->device_type == SAS_END_DEVICE &&
1605 (identify->target_port_protocols &
1606 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
1607 rphy->scsi_target_id = sas_host->next_target_id++;
James Bottomley7676f832006-04-14 09:47:59 -05001608 else if (identify->device_type == SAS_END_DEVICE)
1609 rphy->scsi_target_id = -1;
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001610 mutex_unlock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001611
James Bottomley79cb1812006-03-13 13:50:04 -06001612 if (identify->device_type == SAS_END_DEVICE &&
1613 rphy->scsi_target_id != -1) {
Dan Williams2fc62e22011-09-20 15:10:19 -07001614 int lun;
1615
1616 if (identify->target_port_protocols & SAS_PROTOCOL_SSP)
1617 lun = SCAN_WILD_CARD;
1618 else
1619 lun = 0;
1620
Hannes Reinecke1d645082016-03-17 08:39:45 +01001621 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun,
1622 SCSI_SCAN_INITIAL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001623 }
1624
1625 return 0;
1626}
1627EXPORT_SYMBOL(sas_rphy_add);
1628
1629/**
Rob Landleyeb448202007-11-03 13:30:39 -05001630 * sas_rphy_free - free a SAS remote PHY
1631 * @rphy: SAS remote PHY to free
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001632 *
1633 * Frees the specified SAS remote PHY.
1634 *
1635 * Note:
1636 * This function must only be called on a remote
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001637 * PHY that has not successfully been added using
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001638 * sas_rphy_add() (or has been sas_rphy_remove()'d)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001639 */
1640void sas_rphy_free(struct sas_rphy *rphy)
1641{
Mike Anderson92aab642006-03-27 09:37:28 -08001642 struct device *dev = &rphy->dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001643 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
1644 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1645
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001646 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001647 list_del(&rphy->list);
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001648 mutex_unlock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001649
Mike Anderson92aab642006-03-27 09:37:28 -08001650 transport_destroy_device(dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001651
Mike Anderson92aab642006-03-27 09:37:28 -08001652 put_device(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001653}
1654EXPORT_SYMBOL(sas_rphy_free);
1655
1656/**
Rob Landleyeb448202007-11-03 13:30:39 -05001657 * sas_rphy_delete - remove and free SAS remote PHY
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001658 * @rphy: SAS remote PHY to remove and free
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001659 *
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001660 * Removes the specified SAS remote PHY and frees it.
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001661 */
1662void
1663sas_rphy_delete(struct sas_rphy *rphy)
1664{
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001665 sas_rphy_remove(rphy);
1666 sas_rphy_free(rphy);
1667}
1668EXPORT_SYMBOL(sas_rphy_delete);
1669
1670/**
Dan Williams87c83312011-11-17 17:59:51 -08001671 * sas_rphy_unlink - unlink SAS remote PHY
1672 * @rphy: SAS remote phy to unlink from its parent port
1673 *
1674 * Removes port reference to an rphy
1675 */
1676void sas_rphy_unlink(struct sas_rphy *rphy)
1677{
1678 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
1679
1680 parent->rphy = NULL;
1681}
1682EXPORT_SYMBOL(sas_rphy_unlink);
1683
1684/**
Rob Landleyeb448202007-11-03 13:30:39 -05001685 * sas_rphy_remove - remove SAS remote PHY
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001686 * @rphy: SAS remote phy to remove
1687 *
1688 * Removes the specified SAS remote PHY.
1689 */
1690void
1691sas_rphy_remove(struct sas_rphy *rphy)
1692{
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001693 struct device *dev = &rphy->dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001694
Christoph Hellwigd4054232006-01-04 13:45:20 +01001695 switch (rphy->identify.device_type) {
1696 case SAS_END_DEVICE:
1697 scsi_remove_target(dev);
1698 break;
1699 case SAS_EDGE_EXPANDER_DEVICE:
1700 case SAS_FANOUT_EXPANDER_DEVICE:
James Bottomley65c92b02006-06-28 12:22:50 -04001701 sas_remove_children(dev);
Christoph Hellwigd4054232006-01-04 13:45:20 +01001702 break;
1703 default:
1704 break;
1705 }
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001706
Dan Williams87c83312011-11-17 17:59:51 -08001707 sas_rphy_unlink(rphy);
Joe Lawrence6aa6caf2014-05-22 17:30:54 -04001708 sas_bsg_remove(NULL, rphy);
Christoph Hellwigfe8b2302005-09-25 23:10:33 +02001709 transport_remove_device(dev);
1710 device_del(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001711}
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001712EXPORT_SYMBOL(sas_rphy_remove);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001713
1714/**
Rob Landleyeb448202007-11-03 13:30:39 -05001715 * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001716 * @dev: device to check
1717 *
1718 * Returns:
1719 * %1 if the device represents a SAS remote PHY, %0 else
1720 */
1721int scsi_is_sas_rphy(const struct device *dev)
1722{
James Bottomley2f8600d2006-03-18 15:00:50 -06001723 return dev->release == sas_end_device_release ||
1724 dev->release == sas_expander_release;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001725}
1726EXPORT_SYMBOL(scsi_is_sas_rphy);
1727
1728
1729/*
1730 * SCSI scan helper
1731 */
1732
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001733static int sas_user_scan(struct Scsi_Host *shost, uint channel,
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02001734 uint id, u64 lun)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001735{
1736 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1737 struct sas_rphy *rphy;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001738
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001739 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001740 list_for_each_entry(rphy, &sas_host->rphy_list, list) {
James Bottomley6d99a3f2006-05-19 10:49:37 -05001741 if (rphy->identify.device_type != SAS_END_DEVICE ||
1742 rphy->scsi_target_id == -1)
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001743 continue;
1744
James Bottomleye8bf3942006-07-11 17:49:34 -04001745 if ((channel == SCAN_WILD_CARD || channel == 0) &&
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001746 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
Hannes Reinecke1d645082016-03-17 08:39:45 +01001747 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
1748 lun, SCSI_SCAN_MANUAL);
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001749 }
1750 }
1751 mutex_unlock(&sas_host->lock);
1752
1753 return 0;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001754}
1755
1756
1757/*
1758 * Setup / Teardown code
1759 */
1760
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001761#define SETUP_TEMPLATE(attrb, field, perm, test) \
Tony Jonesee959b02008-02-22 00:13:36 +01001762 i->private_##attrb[count] = dev_attr_##field; \
James Bottomley42ab0362006-03-04 09:10:18 -06001763 i->private_##attrb[count].attr.mode = perm; \
James Bottomley42ab0362006-03-04 09:10:18 -06001764 i->attrb[count] = &i->private_##attrb[count]; \
1765 if (test) \
1766 count++
1767
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001768#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \
Tony Jonesee959b02008-02-22 00:13:36 +01001769 i->private_##attrb[count] = dev_attr_##field; \
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001770 i->private_##attrb[count].attr.mode = perm; \
1771 if (ro_test) { \
1772 i->private_##attrb[count].attr.mode = ro_perm; \
1773 i->private_##attrb[count].store = NULL; \
1774 } \
1775 i->attrb[count] = &i->private_##attrb[count]; \
1776 if (test) \
1777 count++
James Bottomley42ab0362006-03-04 09:10:18 -06001778
1779#define SETUP_RPORT_ATTRIBUTE(field) \
1780 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001781
James Bottomleydd9fbb522006-03-02 16:01:31 -06001782#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
James Bottomley42ab0362006-03-04 09:10:18 -06001783 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001784
James Bottomley65c92b02006-06-28 12:22:50 -04001785#define SETUP_PHY_ATTRIBUTE(field) \
James Bottomley42ab0362006-03-04 09:10:18 -06001786 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001787
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001788#define SETUP_PHY_ATTRIBUTE_RW(field) \
1789 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1790 !i->f->set_phy_speed, S_IRUGO)
1791
Darrick J. Wongacbf1672007-01-11 14:14:57 -08001792#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \
1793 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1794 !i->f->func, S_IRUGO)
1795
James Bottomley65c92b02006-06-28 12:22:50 -04001796#define SETUP_PORT_ATTRIBUTE(field) \
1797 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
1798
1799#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \
James Bottomley42ab0362006-03-04 09:10:18 -06001800 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001801
James Bottomley65c92b02006-06-28 12:22:50 -04001802#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
Darrick J. Wongfe3b5bf2007-01-11 14:15:35 -08001803 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +02001804
James Bottomley65c92b02006-06-28 12:22:50 -04001805#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
Darrick J. Wongfe3b5bf2007-01-11 14:15:35 -08001806 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001807
James Bottomley42ab0362006-03-04 09:10:18 -06001808#define SETUP_END_DEV_ATTRIBUTE(field) \
1809 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001810
James Bottomley79cb1812006-03-13 13:50:04 -06001811#define SETUP_EXPANDER_ATTRIBUTE(field) \
1812 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
1813
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001814/**
Rob Landleyeb448202007-11-03 13:30:39 -05001815 * sas_attach_transport - instantiate SAS transport template
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001816 * @ft: SAS transport class function template
1817 */
1818struct scsi_transport_template *
1819sas_attach_transport(struct sas_function_template *ft)
1820{
1821 struct sas_internal *i;
1822 int count;
1823
Jes Sorensen24669f752006-01-16 10:31:18 -05001824 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001825 if (!i)
1826 return NULL;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001827
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001828 i->t.user_scan = sas_user_scan;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001829
1830 i->t.host_attrs.ac.attrs = &i->host_attrs[0];
1831 i->t.host_attrs.ac.class = &sas_host_class.class;
1832 i->t.host_attrs.ac.match = sas_host_match;
1833 transport_container_register(&i->t.host_attrs);
1834 i->t.host_size = sizeof(struct sas_host_attrs);
1835
1836 i->phy_attr_cont.ac.class = &sas_phy_class.class;
1837 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
1838 i->phy_attr_cont.ac.match = sas_phy_match;
1839 transport_container_register(&i->phy_attr_cont);
1840
James Bottomley65c92b02006-06-28 12:22:50 -04001841 i->port_attr_cont.ac.class = &sas_port_class.class;
1842 i->port_attr_cont.ac.attrs = &i->port_attrs[0];
1843 i->port_attr_cont.ac.match = sas_port_match;
1844 transport_container_register(&i->port_attr_cont);
1845
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001846 i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
1847 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
1848 i->rphy_attr_cont.ac.match = sas_rphy_match;
1849 transport_container_register(&i->rphy_attr_cont);
1850
James Bottomley42ab0362006-03-04 09:10:18 -06001851 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
1852 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
1853 i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1854 transport_container_register(&i->end_dev_attr_cont);
1855
James Bottomley79cb1812006-03-13 13:50:04 -06001856 i->expander_attr_cont.ac.class = &sas_expander_class.class;
1857 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
1858 i->expander_attr_cont.ac.match = sas_expander_match;
1859 transport_container_register(&i->expander_attr_cont);
1860
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001861 i->f = ft;
1862
1863 count = 0;
James Bottomley65c92b02006-06-28 12:22:50 -04001864 SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
1865 SETUP_PHY_ATTRIBUTE(target_port_protocols);
1866 SETUP_PHY_ATTRIBUTE(device_type);
1867 SETUP_PHY_ATTRIBUTE(sas_address);
1868 SETUP_PHY_ATTRIBUTE(phy_identifier);
1869 //SETUP_PHY_ATTRIBUTE(port_identifier);
1870 SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
1871 SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001872 SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
James Bottomley65c92b02006-06-28 12:22:50 -04001873 SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001874 SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +02001875
James Bottomley65c92b02006-06-28 12:22:50 -04001876 SETUP_PHY_ATTRIBUTE(invalid_dword_count);
1877 SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
1878 SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
1879 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
1880 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
1881 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
Darrick J. Wongacbf1672007-01-11 14:14:57 -08001882 SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001883 i->phy_attrs[count] = NULL;
1884
1885 count = 0;
James Bottomley65c92b02006-06-28 12:22:50 -04001886 SETUP_PORT_ATTRIBUTE(num_phys);
1887 i->port_attrs[count] = NULL;
1888
1889 count = 0;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001890 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
1891 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
1892 SETUP_RPORT_ATTRIBUTE(rphy_device_type);
1893 SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
1894 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
Hannes Reineckecdc43ae2016-03-14 10:43:08 +01001895 SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
James Bottomleydd9fbb522006-03-02 16:01:31 -06001896 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
1897 get_enclosure_identifier);
1898 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
1899 get_bay_identifier);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001900 i->rphy_attrs[count] = NULL;
1901
James Bottomley42ab0362006-03-04 09:10:18 -06001902 count = 0;
1903 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
1904 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
1905 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
James Bottomley0f880092010-01-18 10:14:51 -06001906 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
1907 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
James Bottomley42ab0362006-03-04 09:10:18 -06001908 i->end_dev_attrs[count] = NULL;
1909
James Bottomley79cb1812006-03-13 13:50:04 -06001910 count = 0;
1911 SETUP_EXPANDER_ATTRIBUTE(vendor_id);
1912 SETUP_EXPANDER_ATTRIBUTE(product_id);
1913 SETUP_EXPANDER_ATTRIBUTE(product_rev);
1914 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
1915 SETUP_EXPANDER_ATTRIBUTE(component_id);
1916 SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
1917 SETUP_EXPANDER_ATTRIBUTE(level);
1918 i->expander_attrs[count] = NULL;
1919
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001920 return &i->t;
1921}
1922EXPORT_SYMBOL(sas_attach_transport);
1923
1924/**
Rob Landleyeb448202007-11-03 13:30:39 -05001925 * sas_release_transport - release SAS transport template instance
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001926 * @t: transport template instance
1927 */
1928void sas_release_transport(struct scsi_transport_template *t)
1929{
1930 struct sas_internal *i = to_sas_internal(t);
1931
1932 transport_container_unregister(&i->t.host_attrs);
1933 transport_container_unregister(&i->phy_attr_cont);
James Bottomley65c92b02006-06-28 12:22:50 -04001934 transport_container_unregister(&i->port_attr_cont);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001935 transport_container_unregister(&i->rphy_attr_cont);
James Bottomleydb82f842006-03-09 22:06:36 -05001936 transport_container_unregister(&i->end_dev_attr_cont);
James Bottomley79cb1812006-03-13 13:50:04 -06001937 transport_container_unregister(&i->expander_attr_cont);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001938
1939 kfree(i);
1940}
1941EXPORT_SYMBOL(sas_release_transport);
1942
1943static __init int sas_transport_init(void)
1944{
1945 int error;
1946
1947 error = transport_class_register(&sas_host_class);
1948 if (error)
1949 goto out;
1950 error = transport_class_register(&sas_phy_class);
1951 if (error)
1952 goto out_unregister_transport;
James Bottomley65c92b02006-06-28 12:22:50 -04001953 error = transport_class_register(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001954 if (error)
1955 goto out_unregister_phy;
James Bottomley65c92b02006-06-28 12:22:50 -04001956 error = transport_class_register(&sas_rphy_class);
1957 if (error)
1958 goto out_unregister_port;
James Bottomley42ab0362006-03-04 09:10:18 -06001959 error = transport_class_register(&sas_end_dev_class);
1960 if (error)
1961 goto out_unregister_rphy;
James Bottomley79cb1812006-03-13 13:50:04 -06001962 error = transport_class_register(&sas_expander_class);
1963 if (error)
1964 goto out_unregister_end_dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001965
1966 return 0;
1967
James Bottomley79cb1812006-03-13 13:50:04 -06001968 out_unregister_end_dev:
1969 transport_class_unregister(&sas_end_dev_class);
James Bottomley42ab0362006-03-04 09:10:18 -06001970 out_unregister_rphy:
1971 transport_class_unregister(&sas_rphy_class);
James Bottomley65c92b02006-06-28 12:22:50 -04001972 out_unregister_port:
1973 transport_class_unregister(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001974 out_unregister_phy:
1975 transport_class_unregister(&sas_phy_class);
1976 out_unregister_transport:
1977 transport_class_unregister(&sas_host_class);
1978 out:
1979 return error;
1980
1981}
1982
1983static void __exit sas_transport_exit(void)
1984{
1985 transport_class_unregister(&sas_host_class);
1986 transport_class_unregister(&sas_phy_class);
James Bottomley65c92b02006-06-28 12:22:50 -04001987 transport_class_unregister(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001988 transport_class_unregister(&sas_rphy_class);
James Bottomley42ab0362006-03-04 09:10:18 -06001989 transport_class_unregister(&sas_end_dev_class);
James Bottomley79cb1812006-03-13 13:50:04 -06001990 transport_class_unregister(&sas_expander_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001991}
1992
1993MODULE_AUTHOR("Christoph Hellwig");
Alexis Bruemmer86b9c4c12007-01-16 15:36:12 -08001994MODULE_DESCRIPTION("SAS Transport Attributes");
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001995MODULE_LICENSE("GPL");
1996
1997module_init(sas_transport_init);
1998module_exit(sas_transport_exit);