blob: e2e948f1ce28e09254a57758a3c6cd31aff5bb35 [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
Christoph Hellwig0bf6595e2017-06-19 09:26:25 +0200254 /*
255 * by default assume old behaviour and bounce for any highmem page
256 */
257 blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
258
FUJITA Tomonori93c20a52008-04-19 00:43:15 +0900259 error = bsg_register_queue(q, dev, name, release);
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800260 if (error)
261 goto out_cleanup_queue;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900262
263 if (rphy)
James Bottomleyb6aff662007-07-20 11:10:05 -0500264 rphy->q = q;
265 else
266 to_sas_host_attrs(shost)->q = q;
267
268 if (rphy)
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900269 q->queuedata = rphy;
270 else
271 q->queuedata = shost;
272
Nick Piggin75ad23b2008-04-29 14:48:33 +0200273 queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
Bart Van Assche9efc1602017-05-31 14:43:46 -0700274 queue_flag_set_unlocked(QUEUE_FLAG_SCSI_PASSTHROUGH, q);
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900275 return 0;
Omar Sandovalbd1599d2017-02-21 10:03:50 -0800276
277out_cleanup_queue:
278 blk_cleanup_queue(q);
279 return error;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900280}
281
James Bottomleyb6aff662007-07-20 11:10:05 -0500282static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
283{
284 struct request_queue *q;
285
286 if (rphy)
287 q = rphy->q;
288 else
289 q = to_sas_host_attrs(shost)->q;
290
291 if (!q)
292 return;
293
294 bsg_unregister_queue(q);
James Bottomleyb6aff662007-07-20 11:10:05 -0500295}
296
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200297/*
298 * SAS host attributes
299 */
300
James Bottomley37be6ee2005-09-09 18:38:27 -0500301static int sas_host_setup(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +0100302 struct device *cdev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200303{
304 struct Scsi_Host *shost = dev_to_shost(dev);
305 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
306
307 INIT_LIST_HEAD(&sas_host->rphy_list);
Christoph Hellwige02f3f52006-01-13 19:04:00 +0100308 mutex_init(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200309 sas_host->next_target_id = 0;
James Bottomley79cb1812006-03-13 13:50:04 -0600310 sas_host->next_expander_id = 0;
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500311 sas_host->next_port_id = 0;
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900312
James Bottomley39dca552007-07-20 18:22:17 -0500313 if (sas_bsg_initialize(shost, NULL))
FUJITA Tomonori7aa68e82007-07-09 12:52:06 +0900314 dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
315 shost->host_no);
316
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200317 return 0;
318}
319
James Bottomleyb6aff662007-07-20 11:10:05 -0500320static int sas_host_remove(struct transport_container *tc, struct device *dev,
Tony Jonesee959b02008-02-22 00:13:36 +0100321 struct device *cdev)
James Bottomleyb6aff662007-07-20 11:10:05 -0500322{
323 struct Scsi_Host *shost = dev_to_shost(dev);
324
325 sas_bsg_remove(shost, NULL);
326
327 return 0;
328}
329
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200330static DECLARE_TRANSPORT_CLASS(sas_host_class,
James Bottomleyb6aff662007-07-20 11:10:05 -0500331 "sas_host", sas_host_setup, sas_host_remove, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200332
333static int sas_host_match(struct attribute_container *cont,
334 struct device *dev)
335{
336 struct Scsi_Host *shost;
337 struct sas_internal *i;
338
339 if (!scsi_is_host_device(dev))
340 return 0;
341 shost = dev_to_shost(dev);
342
343 if (!shost->transportt)
344 return 0;
345 if (shost->transportt->host_attrs.ac.class !=
346 &sas_host_class.class)
347 return 0;
348
349 i = to_sas_internal(shost->transportt);
350 return &i->t.host_attrs.ac == cont;
351}
352
353static int do_sas_phy_delete(struct device *dev, void *data)
354{
James Bottomley65c92b02006-06-28 12:22:50 -0400355 int pass = (int)(unsigned long)data;
356
357 if (pass == 0 && scsi_is_sas_port(dev))
358 sas_port_delete(dev_to_sas_port(dev));
359 else if (pass == 1 && scsi_is_sas_phy(dev))
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200360 sas_phy_delete(dev_to_phy(dev));
361 return 0;
362}
363
364/**
Rob Landleyeb448202007-11-03 13:30:39 -0500365 * sas_remove_children - tear down a devices SAS data structures
James Bottomley65c92b02006-06-28 12:22:50 -0400366 * @dev: device belonging to the sas object
367 *
368 * Removes all SAS PHYs and remote PHYs for a given object
369 */
370void sas_remove_children(struct device *dev)
371{
372 device_for_each_child(dev, (void *)0, do_sas_phy_delete);
373 device_for_each_child(dev, (void *)1, do_sas_phy_delete);
374}
375EXPORT_SYMBOL(sas_remove_children);
376
377/**
Rob Landleyeb448202007-11-03 13:30:39 -0500378 * sas_remove_host - tear down a Scsi_Host's SAS data structures
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200379 * @shost: Scsi Host that is torn down
380 *
Johannes Thumshirnc5ce0ab2017-04-21 14:11:41 +0200381 * Removes all SAS PHYs and remote PHYs for a given Scsi_Host and remove the
382 * Scsi_Host as well.
383 *
384 * Note: Do not call scsi_remove_host() on the Scsi_Host any more, as it is
385 * already removed.
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200386 */
387void sas_remove_host(struct Scsi_Host *shost)
388{
James Bottomley65c92b02006-06-28 12:22:50 -0400389 sas_remove_children(&shost->shost_gendev);
Johannes Thumshirnc5ce0ab2017-04-21 14:11:41 +0200390 scsi_remove_host(shost);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200391}
392EXPORT_SYMBOL(sas_remove_host);
393
James Bottomley0f880092010-01-18 10:14:51 -0600394/**
James Bottomleybcf508c2015-12-09 11:13:35 -0800395 * sas_get_address - return the SAS address of the device
396 * @sdev: scsi device
397 *
398 * Returns the SAS address of the scsi device
399 */
400u64 sas_get_address(struct scsi_device *sdev)
401{
402 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
403
404 return rdev->rphy.identify.sas_address;
405}
406EXPORT_SYMBOL(sas_get_address);
407
408/**
James Bottomley0f880092010-01-18 10:14:51 -0600409 * sas_tlr_supported - checking TLR bit in vpd 0x90
410 * @sdev: scsi device struct
411 *
412 * Check Transport Layer Retries are supported or not.
413 * If vpd page 0x90 is present, TRL is supported.
414 *
415 */
416unsigned int
417sas_tlr_supported(struct scsi_device *sdev)
418{
419 const int vpd_len = 32;
420 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
421 char *buffer = kzalloc(vpd_len, GFP_KERNEL);
422 int ret = 0;
423
Bart Van Asschee1779b42017-08-25 13:46:40 -0700424 if (!buffer)
425 goto out;
426
James Bottomley0f880092010-01-18 10:14:51 -0600427 if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len))
428 goto out;
429
430 /*
431 * Magic numbers: the VPD Protocol page (0x90)
432 * has a 4 byte header and then one entry per device port
433 * the TLR bit is at offset 8 on each port entry
434 * if we take the first port, that's at total offset 12
435 */
436 ret = buffer[12] & 0x01;
437
438 out:
439 kfree(buffer);
440 rdev->tlr_supported = ret;
441 return ret;
442
443}
444EXPORT_SYMBOL_GPL(sas_tlr_supported);
445
446/**
447 * sas_disable_tlr - setting TLR flags
448 * @sdev: scsi device struct
449 *
450 * Seting tlr_enabled flag to 0.
451 *
452 */
453void
454sas_disable_tlr(struct scsi_device *sdev)
455{
456 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
457
458 rdev->tlr_enabled = 0;
459}
460EXPORT_SYMBOL_GPL(sas_disable_tlr);
461
462/**
463 * sas_enable_tlr - setting TLR flags
464 * @sdev: scsi device struct
465 *
466 * Seting tlr_enabled flag 1.
467 *
468 */
469void sas_enable_tlr(struct scsi_device *sdev)
470{
471 unsigned int tlr_supported = 0;
472 tlr_supported = sas_tlr_supported(sdev);
473
474 if (tlr_supported) {
475 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
476
477 rdev->tlr_enabled = 1;
478 }
479
480 return;
481}
482EXPORT_SYMBOL_GPL(sas_enable_tlr);
483
484unsigned int sas_is_tlr_enabled(struct scsi_device *sdev)
485{
486 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
487 return rdev->tlr_enabled;
488}
489EXPORT_SYMBOL_GPL(sas_is_tlr_enabled);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200490
491/*
James Bottomley65c92b02006-06-28 12:22:50 -0400492 * SAS Phy attributes
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200493 */
494
495#define sas_phy_show_simple(field, name, format_string, cast) \
496static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100497show_sas_phy_##name(struct device *dev, \
498 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200499{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100500 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200501 \
502 return snprintf(buf, 20, format_string, cast phy->field); \
503}
504
505#define sas_phy_simple_attr(field, name, format_string, type) \
506 sas_phy_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +0100507static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200508
509#define sas_phy_show_protocol(field, name) \
510static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100511show_sas_phy_##name(struct device *dev, \
512 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200513{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100514 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200515 \
516 if (!phy->field) \
517 return snprintf(buf, 20, "none\n"); \
518 return get_sas_protocol_names(phy->field, buf); \
519}
520
521#define sas_phy_protocol_attr(field, name) \
522 sas_phy_show_protocol(field, name) \
Tony Jonesee959b02008-02-22 00:13:36 +0100523static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200524
525#define sas_phy_show_linkspeed(field) \
526static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100527show_sas_phy_##field(struct device *dev, \
528 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200529{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100530 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200531 \
532 return get_sas_linkspeed_names(phy->field, buf); \
533}
534
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500535/* Fudge to tell if we're minimum or maximum */
536#define sas_phy_store_linkspeed(field) \
537static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100538store_sas_phy_##field(struct device *dev, \
539 struct device_attribute *attr, \
540 const char *buf, size_t count) \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500541{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100542 struct sas_phy *phy = transport_class_to_phy(dev); \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500543 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
544 struct sas_internal *i = to_sas_internal(shost->transportt); \
545 u32 value; \
546 struct sas_phy_linkrates rates = {0}; \
547 int error; \
548 \
549 error = set_sas_linkspeed_names(&value, buf); \
550 if (error) \
551 return error; \
552 rates.field = value; \
553 error = i->f->set_phy_speed(phy, &rates); \
554 \
555 return error ? error : count; \
556}
557
558#define sas_phy_linkspeed_rw_attr(field) \
559 sas_phy_show_linkspeed(field) \
560 sas_phy_store_linkspeed(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100561static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500562 store_sas_phy_##field)
563
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200564#define sas_phy_linkspeed_attr(field) \
565 sas_phy_show_linkspeed(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100566static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200567
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500568
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200569#define sas_phy_show_linkerror(field) \
570static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100571show_sas_phy_##field(struct device *dev, \
572 struct device_attribute *attr, char *buf) \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200573{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100574 struct sas_phy *phy = transport_class_to_phy(dev); \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200575 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
576 struct sas_internal *i = to_sas_internal(shost->transportt); \
577 int error; \
578 \
James Bottomleydd9fbb522006-03-02 16:01:31 -0600579 error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200580 if (error) \
581 return error; \
582 return snprintf(buf, 20, "%u\n", phy->field); \
583}
584
585#define sas_phy_linkerror_attr(field) \
586 sas_phy_show_linkerror(field) \
Tony Jonesee959b02008-02-22 00:13:36 +0100587static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200588
589
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200590static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +0100591show_sas_device_type(struct device *dev,
592 struct device_attribute *attr, char *buf)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200593{
Tony Jonesee959b02008-02-22 00:13:36 +0100594 struct sas_phy *phy = transport_class_to_phy(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200595
596 if (!phy->identify.device_type)
597 return snprintf(buf, 20, "none\n");
598 return get_sas_device_type_names(phy->identify.device_type, buf);
599}
Tony Jonesee959b02008-02-22 00:13:36 +0100600static DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200601
Tony Jonesee959b02008-02-22 00:13:36 +0100602static ssize_t do_sas_phy_enable(struct device *dev,
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800603 size_t count, int enable)
604{
Tony Jonesee959b02008-02-22 00:13:36 +0100605 struct sas_phy *phy = transport_class_to_phy(dev);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800606 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
607 struct sas_internal *i = to_sas_internal(shost->transportt);
608 int error;
609
610 error = i->f->phy_enable(phy, enable);
611 if (error)
612 return error;
613 phy->enabled = enable;
614 return count;
615};
616
Tony Jonesee959b02008-02-22 00:13:36 +0100617static ssize_t
618store_sas_phy_enable(struct device *dev, struct device_attribute *attr,
619 const char *buf, size_t count)
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800620{
621 if (count < 1)
622 return -EINVAL;
623
624 switch (buf[0]) {
625 case '0':
Tony Jonesee959b02008-02-22 00:13:36 +0100626 do_sas_phy_enable(dev, count, 0);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800627 break;
628 case '1':
Tony Jonesee959b02008-02-22 00:13:36 +0100629 do_sas_phy_enable(dev, count, 1);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800630 break;
631 default:
632 return -EINVAL;
633 }
634
635 return count;
636}
637
Tony Jonesee959b02008-02-22 00:13:36 +0100638static ssize_t
639show_sas_phy_enable(struct device *dev, struct device_attribute *attr,
640 char *buf)
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800641{
Tony Jonesee959b02008-02-22 00:13:36 +0100642 struct sas_phy *phy = transport_class_to_phy(dev);
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800643
644 return snprintf(buf, 20, "%d", phy->enabled);
645}
646
Tony Jonesee959b02008-02-22 00:13:36 +0100647static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable,
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800648 store_sas_phy_enable);
649
Tony Jonesee959b02008-02-22 00:13:36 +0100650static ssize_t
651do_sas_phy_reset(struct device *dev, size_t count, int hard_reset)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200652{
Tony Jonesee959b02008-02-22 00:13:36 +0100653 struct sas_phy *phy = transport_class_to_phy(dev);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200654 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
655 struct sas_internal *i = to_sas_internal(shost->transportt);
656 int error;
657
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200658 error = i->f->phy_reset(phy, hard_reset);
659 if (error)
660 return error;
Dan Williams16d3db12012-01-30 22:53:51 -0800661 phy->enabled = 1;
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200662 return count;
663};
664
Tony Jonesee959b02008-02-22 00:13:36 +0100665static ssize_t
666store_sas_link_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, 0);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200670}
Tony Jonesee959b02008-02-22 00:13:36 +0100671static DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200672
Tony Jonesee959b02008-02-22 00:13:36 +0100673static ssize_t
674store_sas_hard_reset(struct device *dev, struct device_attribute *attr,
675 const char *buf, size_t count)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200676{
Tony Jonesee959b02008-02-22 00:13:36 +0100677 return do_sas_phy_reset(dev, count, 1);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200678}
Tony Jonesee959b02008-02-22 00:13:36 +0100679static DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset);
Christoph Hellwig07ba3a92005-10-19 20:01:31 +0200680
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200681sas_phy_protocol_attr(identify.initiator_port_protocols,
682 initiator_port_protocols);
683sas_phy_protocol_attr(identify.target_port_protocols,
684 target_port_protocols);
685sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
686 unsigned long long);
687sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500688//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200689sas_phy_linkspeed_attr(negotiated_linkrate);
690sas_phy_linkspeed_attr(minimum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500691sas_phy_linkspeed_rw_attr(minimum_linkrate);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200692sas_phy_linkspeed_attr(maximum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -0500693sas_phy_linkspeed_rw_attr(maximum_linkrate);
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +0200694sas_phy_linkerror_attr(invalid_dword_count);
695sas_phy_linkerror_attr(running_disparity_error_count);
696sas_phy_linkerror_attr(loss_of_dword_sync_count);
697sas_phy_linkerror_attr(phy_reset_problem_count);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200698
Dan Williams0b3e09d2011-12-20 01:03:48 -0800699static int sas_phy_setup(struct transport_container *tc, struct device *dev,
700 struct device *cdev)
701{
702 struct sas_phy *phy = dev_to_phy(dev);
703 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
704 struct sas_internal *i = to_sas_internal(shost->transportt);
705
706 if (i->f->phy_setup)
707 i->f->phy_setup(phy);
708
709 return 0;
710}
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200711
712static DECLARE_TRANSPORT_CLASS(sas_phy_class,
Dan Williams0b3e09d2011-12-20 01:03:48 -0800713 "sas_phy", sas_phy_setup, NULL, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200714
715static int sas_phy_match(struct attribute_container *cont, struct device *dev)
716{
717 struct Scsi_Host *shost;
718 struct sas_internal *i;
719
720 if (!scsi_is_sas_phy(dev))
721 return 0;
722 shost = dev_to_shost(dev->parent);
723
724 if (!shost->transportt)
725 return 0;
726 if (shost->transportt->host_attrs.ac.class !=
727 &sas_host_class.class)
728 return 0;
729
730 i = to_sas_internal(shost->transportt);
731 return &i->phy_attr_cont.ac == cont;
732}
733
734static void sas_phy_release(struct device *dev)
735{
736 struct sas_phy *phy = dev_to_phy(dev);
Dan Williams0b3e09d2011-12-20 01:03:48 -0800737 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
738 struct sas_internal *i = to_sas_internal(shost->transportt);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200739
Dan Williams0b3e09d2011-12-20 01:03:48 -0800740 if (i->f->phy_release)
741 i->f->phy_release(phy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200742 put_device(dev->parent);
743 kfree(phy);
744}
745
746/**
Rob Landleyeb448202007-11-03 13:30:39 -0500747 * sas_phy_alloc - allocates and initialize a SAS PHY structure
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200748 * @parent: Parent device
Moore, Ericd99ca412006-01-26 16:20:02 -0700749 * @number: Phy index
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200750 *
751 * Allocates an SAS PHY structure. It will be added in the device tree
752 * below the device specified by @parent, which has to be either a Scsi_Host
753 * or sas_rphy.
754 *
755 * Returns:
756 * SAS PHY allocated or %NULL if the allocation failed.
757 */
758struct sas_phy *sas_phy_alloc(struct device *parent, int number)
759{
760 struct Scsi_Host *shost = dev_to_shost(parent);
761 struct sas_phy *phy;
762
Jes Sorensen24669f752006-01-16 10:31:18 -0500763 phy = kzalloc(sizeof(*phy), GFP_KERNEL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200764 if (!phy)
765 return NULL;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200766
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200767 phy->number = number;
Darrick J. Wongacbf1672007-01-11 14:14:57 -0800768 phy->enabled = 1;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200769
770 device_initialize(&phy->dev);
771 phy->dev.parent = get_device(parent);
772 phy->dev.release = sas_phy_release;
James Bottomley65c92b02006-06-28 12:22:50 -0400773 INIT_LIST_HEAD(&phy->port_siblings);
James Bottomley79cb1812006-03-13 13:50:04 -0600774 if (scsi_is_sas_expander_device(parent)) {
775 struct sas_rphy *rphy = dev_to_rphy(parent);
Kay Sievers71610f52008-12-03 22:41:36 +0100776 dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no,
James Bottomley79cb1812006-03-13 13:50:04 -0600777 rphy->scsi_target_id, number);
778 } else
Kay Sievers71610f52008-12-03 22:41:36 +0100779 dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200780
781 transport_setup_device(&phy->dev);
782
783 return phy;
784}
785EXPORT_SYMBOL(sas_phy_alloc);
786
787/**
Rob Landleyeb448202007-11-03 13:30:39 -0500788 * sas_phy_add - add a SAS PHY to the device hierarchy
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200789 * @phy: The PHY to be added
790 *
791 * Publishes a SAS PHY to the rest of the system.
792 */
793int sas_phy_add(struct sas_phy *phy)
794{
795 int error;
796
797 error = device_add(&phy->dev);
798 if (!error) {
799 transport_add_device(&phy->dev);
800 transport_configure_device(&phy->dev);
801 }
802
803 return error;
804}
805EXPORT_SYMBOL(sas_phy_add);
806
807/**
Rob Landleyeb448202007-11-03 13:30:39 -0500808 * sas_phy_free - free a SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200809 * @phy: SAS PHY to free
810 *
811 * Frees the specified SAS PHY.
812 *
813 * Note:
814 * This function must only be called on a PHY that has not
André Goddard Rosaaf901ca2009-11-14 13:09:05 -0200815 * successfully been added using sas_phy_add().
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200816 */
817void sas_phy_free(struct sas_phy *phy)
818{
819 transport_destroy_device(&phy->dev);
Mike Anderson92aab642006-03-27 09:37:28 -0800820 put_device(&phy->dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200821}
822EXPORT_SYMBOL(sas_phy_free);
823
824/**
Rob Landleyeb448202007-11-03 13:30:39 -0500825 * sas_phy_delete - remove SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200826 * @phy: SAS PHY to remove
827 *
828 * Removes the specified SAS PHY. If the SAS PHY has an
829 * associated remote PHY it is removed before.
830 */
831void
832sas_phy_delete(struct sas_phy *phy)
833{
834 struct device *dev = &phy->dev;
835
James Bottomley65c92b02006-06-28 12:22:50 -0400836 /* this happens if the phy is still part of a port when deleted */
837 BUG_ON(!list_empty(&phy->port_siblings));
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200838
839 transport_remove_device(dev);
840 device_del(dev);
841 transport_destroy_device(dev);
Mike Anderson92aab642006-03-27 09:37:28 -0800842 put_device(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200843}
844EXPORT_SYMBOL(sas_phy_delete);
845
846/**
Rob Landleyeb448202007-11-03 13:30:39 -0500847 * scsi_is_sas_phy - check if a struct device represents a SAS PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +0200848 * @dev: device to check
849 *
850 * Returns:
851 * %1 if the device represents a SAS PHY, %0 else
852 */
853int scsi_is_sas_phy(const struct device *dev)
854{
855 return dev->release == sas_phy_release;
856}
857EXPORT_SYMBOL(scsi_is_sas_phy);
858
859/*
James Bottomley65c92b02006-06-28 12:22:50 -0400860 * SAS Port attributes
861 */
862#define sas_port_show_simple(field, name, format_string, cast) \
863static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +0100864show_sas_port_##name(struct device *dev, \
865 struct device_attribute *attr, char *buf) \
James Bottomley65c92b02006-06-28 12:22:50 -0400866{ \
Tony Jonesee959b02008-02-22 00:13:36 +0100867 struct sas_port *port = transport_class_to_sas_port(dev); \
James Bottomley65c92b02006-06-28 12:22:50 -0400868 \
869 return snprintf(buf, 20, format_string, cast port->field); \
870}
871
872#define sas_port_simple_attr(field, name, format_string, type) \
873 sas_port_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +0100874static DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
James Bottomley65c92b02006-06-28 12:22:50 -0400875
876sas_port_simple_attr(num_phys, num_phys, "%d\n", int);
877
878static DECLARE_TRANSPORT_CLASS(sas_port_class,
879 "sas_port", NULL, NULL, NULL);
880
881static int sas_port_match(struct attribute_container *cont, struct device *dev)
882{
883 struct Scsi_Host *shost;
884 struct sas_internal *i;
885
886 if (!scsi_is_sas_port(dev))
887 return 0;
888 shost = dev_to_shost(dev->parent);
889
890 if (!shost->transportt)
891 return 0;
892 if (shost->transportt->host_attrs.ac.class !=
893 &sas_host_class.class)
894 return 0;
895
896 i = to_sas_internal(shost->transportt);
897 return &i->port_attr_cont.ac == cont;
898}
899
900
901static void sas_port_release(struct device *dev)
902{
903 struct sas_port *port = dev_to_sas_port(dev);
904
905 BUG_ON(!list_empty(&port->phy_list));
906
907 put_device(dev->parent);
908 kfree(port);
909}
910
911static void sas_port_create_link(struct sas_port *port,
912 struct sas_phy *phy)
913{
Darrick J. Wong21434962007-01-26 14:08:46 -0800914 int res;
915
916 res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj,
Kay Sievers71610f52008-12-03 22:41:36 +0100917 dev_name(&phy->dev));
Darrick J. Wong21434962007-01-26 14:08:46 -0800918 if (res)
919 goto err;
920 res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
921 if (res)
922 goto err;
923 return;
924err:
925 printk(KERN_ERR "%s: Cannot create port links, err=%d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700926 __func__, res);
James Bottomley65c92b02006-06-28 12:22:50 -0400927}
928
929static void sas_port_delete_link(struct sas_port *port,
930 struct sas_phy *phy)
931{
Kay Sievers71610f52008-12-03 22:41:36 +0100932 sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev));
James Bottomley65c92b02006-06-28 12:22:50 -0400933 sysfs_remove_link(&phy->dev.kobj, "port");
934}
935
936/** sas_port_alloc - allocate and initialize a SAS port structure
937 *
938 * @parent: parent device
939 * @port_id: port number
940 *
941 * Allocates a SAS port structure. It will be added to the device tree
942 * below the device specified by @parent which must be either a Scsi_Host
943 * or a sas_expander_device.
944 *
945 * Returns %NULL on error
946 */
947struct sas_port *sas_port_alloc(struct device *parent, int port_id)
948{
949 struct Scsi_Host *shost = dev_to_shost(parent);
950 struct sas_port *port;
951
952 port = kzalloc(sizeof(*port), GFP_KERNEL);
953 if (!port)
954 return NULL;
955
956 port->port_identifier = port_id;
957
958 device_initialize(&port->dev);
959
960 port->dev.parent = get_device(parent);
961 port->dev.release = sas_port_release;
962
963 mutex_init(&port->phy_list_mutex);
964 INIT_LIST_HEAD(&port->phy_list);
965
966 if (scsi_is_sas_expander_device(parent)) {
967 struct sas_rphy *rphy = dev_to_rphy(parent);
Kay Sievers71610f52008-12-03 22:41:36 +0100968 dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no,
969 rphy->scsi_target_id, port->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -0400970 } else
Kay Sievers71610f52008-12-03 22:41:36 +0100971 dev_set_name(&port->dev, "port-%d:%d", shost->host_no,
972 port->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -0400973
974 transport_setup_device(&port->dev);
975
976 return port;
977}
978EXPORT_SYMBOL(sas_port_alloc);
979
James Bottomleyc9fefeb2006-07-02 11:10:18 -0500980/** sas_port_alloc_num - allocate and initialize a SAS port structure
981 *
982 * @parent: parent device
983 *
984 * Allocates a SAS port structure and a number to go with it. This
985 * interface is really for adapters where the port number has no
986 * meansing, so the sas class should manage them. It will be added to
987 * the device tree below the device specified by @parent which must be
988 * either a Scsi_Host or a sas_expander_device.
989 *
990 * Returns %NULL on error
991 */
992struct sas_port *sas_port_alloc_num(struct device *parent)
993{
994 int index;
995 struct Scsi_Host *shost = dev_to_shost(parent);
996 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
997
998 /* FIXME: use idr for this eventually */
999 mutex_lock(&sas_host->lock);
1000 if (scsi_is_sas_expander_device(parent)) {
1001 struct sas_rphy *rphy = dev_to_rphy(parent);
1002 struct sas_expander_device *exp = rphy_to_expander_device(rphy);
1003
1004 index = exp->next_port_id++;
1005 } else
1006 index = sas_host->next_port_id++;
1007 mutex_unlock(&sas_host->lock);
1008 return sas_port_alloc(parent, index);
1009}
1010EXPORT_SYMBOL(sas_port_alloc_num);
1011
James Bottomley65c92b02006-06-28 12:22:50 -04001012/**
1013 * sas_port_add - add a SAS port to the device hierarchy
James Bottomley65c92b02006-06-28 12:22:50 -04001014 * @port: port to be added
1015 *
1016 * publishes a port to the rest of the system
1017 */
1018int sas_port_add(struct sas_port *port)
1019{
1020 int error;
1021
1022 /* No phys should be added until this is made visible */
1023 BUG_ON(!list_empty(&port->phy_list));
1024
1025 error = device_add(&port->dev);
1026
1027 if (error)
1028 return error;
1029
1030 transport_add_device(&port->dev);
1031 transport_configure_device(&port->dev);
1032
1033 return 0;
1034}
1035EXPORT_SYMBOL(sas_port_add);
1036
1037/**
Rob Landleyeb448202007-11-03 13:30:39 -05001038 * sas_port_free - free a SAS PORT
James Bottomley65c92b02006-06-28 12:22:50 -04001039 * @port: SAS PORT to free
1040 *
1041 * Frees the specified SAS PORT.
1042 *
1043 * Note:
1044 * This function must only be called on a PORT that has not
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001045 * successfully been added using sas_port_add().
James Bottomley65c92b02006-06-28 12:22:50 -04001046 */
1047void sas_port_free(struct sas_port *port)
1048{
1049 transport_destroy_device(&port->dev);
1050 put_device(&port->dev);
1051}
1052EXPORT_SYMBOL(sas_port_free);
1053
1054/**
Rob Landleyeb448202007-11-03 13:30:39 -05001055 * sas_port_delete - remove SAS PORT
James Bottomley65c92b02006-06-28 12:22:50 -04001056 * @port: SAS PORT to remove
1057 *
1058 * Removes the specified SAS PORT. If the SAS PORT has an
1059 * associated phys, unlink them from the port as well.
1060 */
1061void sas_port_delete(struct sas_port *port)
1062{
1063 struct device *dev = &port->dev;
1064 struct sas_phy *phy, *tmp_phy;
1065
1066 if (port->rphy) {
1067 sas_rphy_delete(port->rphy);
1068 port->rphy = NULL;
1069 }
1070
1071 mutex_lock(&port->phy_list_mutex);
1072 list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
1073 port_siblings) {
1074 sas_port_delete_link(port, phy);
1075 list_del_init(&phy->port_siblings);
1076 }
1077 mutex_unlock(&port->phy_list_mutex);
1078
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001079 if (port->is_backlink) {
1080 struct device *parent = port->dev.parent;
1081
Kay Sievers71610f52008-12-03 22:41:36 +01001082 sysfs_remove_link(&port->dev.kobj, dev_name(parent));
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001083 port->is_backlink = 0;
1084 }
1085
James Bottomley65c92b02006-06-28 12:22:50 -04001086 transport_remove_device(dev);
1087 device_del(dev);
1088 transport_destroy_device(dev);
1089 put_device(dev);
1090}
1091EXPORT_SYMBOL(sas_port_delete);
1092
1093/**
Rob Landleyeb448202007-11-03 13:30:39 -05001094 * scsi_is_sas_port - check if a struct device represents a SAS port
James Bottomley65c92b02006-06-28 12:22:50 -04001095 * @dev: device to check
1096 *
1097 * Returns:
1098 * %1 if the device represents a SAS Port, %0 else
1099 */
1100int scsi_is_sas_port(const struct device *dev)
1101{
1102 return dev->release == sas_port_release;
1103}
1104EXPORT_SYMBOL(scsi_is_sas_port);
1105
1106/**
Dan Williamsf41a0c42011-12-21 21:33:17 -08001107 * sas_port_get_phy - try to take a reference on a port member
1108 * @port: port to check
1109 */
1110struct sas_phy *sas_port_get_phy(struct sas_port *port)
1111{
1112 struct sas_phy *phy;
1113
1114 mutex_lock(&port->phy_list_mutex);
1115 if (list_empty(&port->phy_list))
1116 phy = NULL;
1117 else {
1118 struct list_head *ent = port->phy_list.next;
1119
1120 phy = list_entry(ent, typeof(*phy), port_siblings);
1121 get_device(&phy->dev);
1122 }
1123 mutex_unlock(&port->phy_list_mutex);
1124
1125 return phy;
1126}
1127EXPORT_SYMBOL(sas_port_get_phy);
1128
1129/**
James Bottomley65c92b02006-06-28 12:22:50 -04001130 * sas_port_add_phy - add another phy to a port to form a wide port
1131 * @port: port to add the phy to
1132 * @phy: phy to add
1133 *
1134 * When a port is initially created, it is empty (has no phys). All
1135 * ports must have at least one phy to operated, and all wide ports
1136 * must have at least two. The current code makes no difference
1137 * between ports and wide ports, but the only object that can be
1138 * connected to a remote device is a port, so ports must be formed on
1139 * all devices with phys if they're connected to anything.
1140 */
1141void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
1142{
1143 mutex_lock(&port->phy_list_mutex);
1144 if (unlikely(!list_empty(&phy->port_siblings))) {
1145 /* make sure we're already on this port */
1146 struct sas_phy *tmp;
1147
1148 list_for_each_entry(tmp, &port->phy_list, port_siblings)
1149 if (tmp == phy)
1150 break;
1151 /* If this trips, you added a phy that was already
1152 * part of a different port */
1153 if (unlikely(tmp != phy)) {
Kay Sievers71610f52008-12-03 22:41:36 +01001154 dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n",
1155 dev_name(&phy->dev));
James Bottomley65c92b02006-06-28 12:22:50 -04001156 BUG();
1157 }
1158 } else {
1159 sas_port_create_link(port, phy);
1160 list_add_tail(&phy->port_siblings, &port->phy_list);
1161 port->num_phys++;
1162 }
1163 mutex_unlock(&port->phy_list_mutex);
1164}
1165EXPORT_SYMBOL(sas_port_add_phy);
1166
1167/**
1168 * sas_port_delete_phy - remove a phy from a port or wide port
1169 * @port: port to remove the phy from
1170 * @phy: phy to remove
1171 *
1172 * This operation is used for tearing down ports again. It must be
1173 * done to every port or wide port before calling sas_port_delete.
1174 */
1175void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
1176{
1177 mutex_lock(&port->phy_list_mutex);
1178 sas_port_delete_link(port, phy);
1179 list_del_init(&phy->port_siblings);
1180 port->num_phys--;
1181 mutex_unlock(&port->phy_list_mutex);
1182}
1183EXPORT_SYMBOL(sas_port_delete_phy);
1184
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001185void sas_port_mark_backlink(struct sas_port *port)
1186{
Darrick J. Wong21434962007-01-26 14:08:46 -08001187 int res;
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001188 struct device *parent = port->dev.parent->parent->parent;
1189
1190 if (port->is_backlink)
1191 return;
1192 port->is_backlink = 1;
Darrick J. Wong21434962007-01-26 14:08:46 -08001193 res = sysfs_create_link(&port->dev.kobj, &parent->kobj,
Kay Sievers71610f52008-12-03 22:41:36 +01001194 dev_name(parent));
Darrick J. Wong21434962007-01-26 14:08:46 -08001195 if (res)
1196 goto err;
1197 return;
1198err:
1199 printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001200 __func__, res);
James Bottomleya0e1b6e2006-07-09 12:38:19 -05001201
1202}
1203EXPORT_SYMBOL(sas_port_mark_backlink);
1204
James Bottomley65c92b02006-06-28 12:22:50 -04001205/*
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001206 * SAS remote PHY attributes.
1207 */
1208
1209#define sas_rphy_show_simple(field, name, format_string, cast) \
1210static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001211show_sas_rphy_##name(struct device *dev, \
1212 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001213{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001214 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001215 \
1216 return snprintf(buf, 20, format_string, cast rphy->field); \
1217}
1218
1219#define sas_rphy_simple_attr(field, name, format_string, type) \
1220 sas_rphy_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001221static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001222 show_sas_rphy_##name, NULL)
1223
1224#define sas_rphy_show_protocol(field, name) \
1225static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001226show_sas_rphy_##name(struct device *dev, \
1227 struct device_attribute *attr, char *buf) \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001228{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001229 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001230 \
1231 if (!rphy->field) \
1232 return snprintf(buf, 20, "none\n"); \
1233 return get_sas_protocol_names(rphy->field, buf); \
1234}
1235
1236#define sas_rphy_protocol_attr(field, name) \
1237 sas_rphy_show_protocol(field, name) \
Tony Jonesee959b02008-02-22 00:13:36 +01001238static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001239 show_sas_rphy_##name, NULL)
1240
1241static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001242show_sas_rphy_device_type(struct device *dev,
1243 struct device_attribute *attr, char *buf)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001244{
Tony Jonesee959b02008-02-22 00:13:36 +01001245 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001246
1247 if (!rphy->identify.device_type)
1248 return snprintf(buf, 20, "none\n");
1249 return get_sas_device_type_names(
1250 rphy->identify.device_type, buf);
1251}
1252
Tony Jonesee959b02008-02-22 00:13:36 +01001253static SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO,
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001254 show_sas_rphy_device_type, NULL);
1255
Christoph Hellwiga0125642006-02-16 13:31:47 +01001256static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001257show_sas_rphy_enclosure_identifier(struct device *dev,
1258 struct device_attribute *attr, char *buf)
Christoph Hellwiga0125642006-02-16 13:31:47 +01001259{
Tony Jonesee959b02008-02-22 00:13:36 +01001260 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwiga0125642006-02-16 13:31:47 +01001261 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
1262 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
1263 struct sas_internal *i = to_sas_internal(shost->transportt);
1264 u64 identifier;
1265 int error;
1266
Christoph Hellwiga0125642006-02-16 13:31:47 +01001267 error = i->f->get_enclosure_identifier(rphy, &identifier);
1268 if (error)
1269 return error;
1270 return sprintf(buf, "0x%llx\n", (unsigned long long)identifier);
1271}
1272
Tony Jonesee959b02008-02-22 00:13:36 +01001273static SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO,
Christoph Hellwiga0125642006-02-16 13:31:47 +01001274 show_sas_rphy_enclosure_identifier, NULL);
1275
1276static ssize_t
Tony Jonesee959b02008-02-22 00:13:36 +01001277show_sas_rphy_bay_identifier(struct device *dev,
1278 struct device_attribute *attr, char *buf)
Christoph Hellwiga0125642006-02-16 13:31:47 +01001279{
Tony Jonesee959b02008-02-22 00:13:36 +01001280 struct sas_rphy *rphy = transport_class_to_rphy(dev);
Christoph Hellwiga0125642006-02-16 13:31:47 +01001281 struct sas_phy *phy = dev_to_phy(rphy->dev.parent);
1282 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
1283 struct sas_internal *i = to_sas_internal(shost->transportt);
1284 int val;
1285
Christoph Hellwiga0125642006-02-16 13:31:47 +01001286 val = i->f->get_bay_identifier(rphy);
1287 if (val < 0)
1288 return val;
1289 return sprintf(buf, "%d\n", val);
1290}
1291
Tony Jonesee959b02008-02-22 00:13:36 +01001292static SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO,
Christoph Hellwiga0125642006-02-16 13:31:47 +01001293 show_sas_rphy_bay_identifier, NULL);
1294
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001295sas_rphy_protocol_attr(identify.initiator_port_protocols,
1296 initiator_port_protocols);
1297sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols);
1298sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
1299 unsigned long long);
1300sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
Hannes Reineckecdc43ae2016-03-14 10:43:08 +01001301sas_rphy_simple_attr(scsi_target_id, scsi_target_id, "%d\n", u32);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001302
James Bottomley42ab0362006-03-04 09:10:18 -06001303/* only need 8 bytes of data plus header (4 or 8) */
1304#define BUF_SIZE 64
1305
1306int sas_read_port_mode_page(struct scsi_device *sdev)
1307{
1308 char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata;
James Bottomley0f880092010-01-18 10:14:51 -06001309 struct sas_end_device *rdev = sas_sdev_to_rdev(sdev);
James Bottomley42ab0362006-03-04 09:10:18 -06001310 struct scsi_mode_data mode_data;
1311 int res, error;
1312
James Bottomley42ab0362006-03-04 09:10:18 -06001313 if (!buffer)
1314 return -ENOMEM;
1315
1316 res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3,
1317 &mode_data, NULL);
1318
1319 error = -EINVAL;
1320 if (!scsi_status_is_good(res))
1321 goto out;
1322
1323 msdata = buffer + mode_data.header_length +
1324 mode_data.block_descriptor_length;
1325
1326 if (msdata - buffer > BUF_SIZE - 8)
1327 goto out;
1328
1329 error = 0;
1330
1331 rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0;
1332 rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5];
1333 rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7];
1334
1335 out:
1336 kfree(buffer);
1337 return error;
1338}
1339EXPORT_SYMBOL(sas_read_port_mode_page);
1340
James Bottomley79cb1812006-03-13 13:50:04 -06001341static DECLARE_TRANSPORT_CLASS(sas_end_dev_class,
1342 "sas_end_device", NULL, NULL, NULL);
1343
James Bottomley42ab0362006-03-04 09:10:18 -06001344#define sas_end_dev_show_simple(field, name, format_string, cast) \
1345static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001346show_sas_end_dev_##name(struct device *dev, \
1347 struct device_attribute *attr, char *buf) \
James Bottomley42ab0362006-03-04 09:10:18 -06001348{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001349 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
James Bottomley42ab0362006-03-04 09:10:18 -06001350 struct sas_end_device *rdev = rphy_to_end_device(rphy); \
1351 \
1352 return snprintf(buf, 20, format_string, cast rdev->field); \
1353}
1354
1355#define sas_end_dev_simple_attr(field, name, format_string, type) \
1356 sas_end_dev_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001357static SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, \
James Bottomley42ab0362006-03-04 09:10:18 -06001358 show_sas_end_dev_##name, NULL)
1359
1360sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int);
1361sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout,
1362 "%d\n", int);
1363sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout,
1364 "%d\n", int);
James Bottomley0f880092010-01-18 10:14:51 -06001365sas_end_dev_simple_attr(tlr_supported, tlr_supported,
1366 "%d\n", int);
1367sas_end_dev_simple_attr(tlr_enabled, tlr_enabled,
1368 "%d\n", int);
James Bottomley42ab0362006-03-04 09:10:18 -06001369
James Bottomley79cb1812006-03-13 13:50:04 -06001370static DECLARE_TRANSPORT_CLASS(sas_expander_class,
1371 "sas_expander", NULL, NULL, NULL);
1372
1373#define sas_expander_show_simple(field, name, format_string, cast) \
1374static ssize_t \
Tony Jonesee959b02008-02-22 00:13:36 +01001375show_sas_expander_##name(struct device *dev, \
1376 struct device_attribute *attr, char *buf) \
James Bottomley79cb1812006-03-13 13:50:04 -06001377{ \
Tony Jonesee959b02008-02-22 00:13:36 +01001378 struct sas_rphy *rphy = transport_class_to_rphy(dev); \
James Bottomley79cb1812006-03-13 13:50:04 -06001379 struct sas_expander_device *edev = rphy_to_expander_device(rphy); \
1380 \
1381 return snprintf(buf, 20, format_string, cast edev->field); \
1382}
1383
1384#define sas_expander_simple_attr(field, name, format_string, type) \
1385 sas_expander_show_simple(field, name, format_string, (type)) \
Tony Jonesee959b02008-02-22 00:13:36 +01001386static SAS_DEVICE_ATTR(expander, name, S_IRUGO, \
James Bottomley79cb1812006-03-13 13:50:04 -06001387 show_sas_expander_##name, NULL)
1388
1389sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *);
1390sas_expander_simple_attr(product_id, product_id, "%s\n", char *);
1391sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *);
1392sas_expander_simple_attr(component_vendor_id, component_vendor_id,
1393 "%s\n", char *);
1394sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int);
1395sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n",
1396 unsigned int);
1397sas_expander_simple_attr(level, level, "%d\n", int);
James Bottomley42ab0362006-03-04 09:10:18 -06001398
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001399static DECLARE_TRANSPORT_CLASS(sas_rphy_class,
James Bottomley2f8600d2006-03-18 15:00:50 -06001400 "sas_device", NULL, NULL, NULL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001401
1402static int sas_rphy_match(struct attribute_container *cont, struct device *dev)
1403{
1404 struct Scsi_Host *shost;
1405 struct sas_internal *i;
1406
1407 if (!scsi_is_sas_rphy(dev))
1408 return 0;
1409 shost = dev_to_shost(dev->parent->parent);
1410
1411 if (!shost->transportt)
1412 return 0;
1413 if (shost->transportt->host_attrs.ac.class !=
1414 &sas_host_class.class)
1415 return 0;
1416
1417 i = to_sas_internal(shost->transportt);
1418 return &i->rphy_attr_cont.ac == cont;
1419}
1420
James Bottomley42ab0362006-03-04 09:10:18 -06001421static int sas_end_dev_match(struct attribute_container *cont,
1422 struct device *dev)
1423{
1424 struct Scsi_Host *shost;
1425 struct sas_internal *i;
1426 struct sas_rphy *rphy;
1427
1428 if (!scsi_is_sas_rphy(dev))
1429 return 0;
1430 shost = dev_to_shost(dev->parent->parent);
1431 rphy = dev_to_rphy(dev);
1432
1433 if (!shost->transportt)
1434 return 0;
1435 if (shost->transportt->host_attrs.ac.class !=
1436 &sas_host_class.class)
1437 return 0;
1438
1439 i = to_sas_internal(shost->transportt);
1440 return &i->end_dev_attr_cont.ac == cont &&
James Bottomley2f8600d2006-03-18 15:00:50 -06001441 rphy->identify.device_type == SAS_END_DEVICE;
James Bottomley42ab0362006-03-04 09:10:18 -06001442}
1443
James Bottomley79cb1812006-03-13 13:50:04 -06001444static int sas_expander_match(struct attribute_container *cont,
1445 struct device *dev)
1446{
1447 struct Scsi_Host *shost;
1448 struct sas_internal *i;
1449 struct sas_rphy *rphy;
1450
1451 if (!scsi_is_sas_rphy(dev))
1452 return 0;
1453 shost = dev_to_shost(dev->parent->parent);
1454 rphy = dev_to_rphy(dev);
1455
1456 if (!shost->transportt)
1457 return 0;
1458 if (shost->transportt->host_attrs.ac.class !=
1459 &sas_host_class.class)
1460 return 0;
1461
1462 i = to_sas_internal(shost->transportt);
1463 return &i->expander_attr_cont.ac == cont &&
1464 (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
James Bottomley2f8600d2006-03-18 15:00:50 -06001465 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE);
James Bottomley79cb1812006-03-13 13:50:04 -06001466}
1467
James Bottomley2f8600d2006-03-18 15:00:50 -06001468static void sas_expander_release(struct device *dev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001469{
1470 struct sas_rphy *rphy = dev_to_rphy(dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001471 struct sas_expander_device *edev = rphy_to_expander_device(rphy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001472
FUJITA Tomonori93c20a52008-04-19 00:43:15 +09001473 if (rphy->q)
1474 blk_cleanup_queue(rphy->q);
1475
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001476 put_device(dev->parent);
James Bottomley2f8600d2006-03-18 15:00:50 -06001477 kfree(edev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001478}
1479
James Bottomley2f8600d2006-03-18 15:00:50 -06001480static void sas_end_device_release(struct device *dev)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001481{
James Bottomley2f8600d2006-03-18 15:00:50 -06001482 struct sas_rphy *rphy = dev_to_rphy(dev);
1483 struct sas_end_device *edev = rphy_to_end_device(rphy);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001484
FUJITA Tomonori93c20a52008-04-19 00:43:15 +09001485 if (rphy->q)
1486 blk_cleanup_queue(rphy->q);
1487
James Bottomley2f8600d2006-03-18 15:00:50 -06001488 put_device(dev->parent);
1489 kfree(edev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001490}
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001491
1492/**
Masahiro Yamada183b8022017-02-27 14:29:20 -08001493 * sas_rphy_initialize - common rphy initialization
James Bottomleyc5943d32006-06-12 09:09:18 -05001494 * @rphy: rphy to initialise
1495 *
1496 * Used by both sas_end_device_alloc() and sas_expander_alloc() to
1497 * initialise the common rphy component of each.
1498 */
1499static void sas_rphy_initialize(struct sas_rphy *rphy)
1500{
1501 INIT_LIST_HEAD(&rphy->list);
1502}
1503
1504/**
James Bottomley42ab0362006-03-04 09:10:18 -06001505 * sas_end_device_alloc - allocate an rphy for an end device
Rob Landleyeb448202007-11-03 13:30:39 -05001506 * @parent: which port
James Bottomley42ab0362006-03-04 09:10:18 -06001507 *
1508 * Allocates an SAS remote PHY structure, connected to @parent.
1509 *
1510 * Returns:
1511 * SAS PHY allocated or %NULL if the allocation failed.
1512 */
James Bottomley65c92b02006-06-28 12:22:50 -04001513struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
James Bottomley42ab0362006-03-04 09:10:18 -06001514{
1515 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
1516 struct sas_end_device *rdev;
1517
1518 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
1519 if (!rdev) {
James Bottomley42ab0362006-03-04 09:10:18 -06001520 return NULL;
1521 }
1522
1523 device_initialize(&rdev->rphy.dev);
1524 rdev->rphy.dev.parent = get_device(&parent->dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001525 rdev->rphy.dev.release = sas_end_device_release;
James Bottomley65c92b02006-06-28 12:22:50 -04001526 if (scsi_is_sas_expander_device(parent->dev.parent)) {
1527 struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
Kay Sievers71610f52008-12-03 22:41:36 +01001528 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d",
1529 shost->host_no, rphy->scsi_target_id,
1530 parent->port_identifier);
James Bottomley65c92b02006-06-28 12:22:50 -04001531 } else
Kay Sievers71610f52008-12-03 22:41:36 +01001532 dev_set_name(&rdev->rphy.dev, "end_device-%d:%d",
1533 shost->host_no, parent->port_identifier);
James Bottomley42ab0362006-03-04 09:10:18 -06001534 rdev->rphy.identify.device_type = SAS_END_DEVICE;
James Bottomleyc5943d32006-06-12 09:09:18 -05001535 sas_rphy_initialize(&rdev->rphy);
James Bottomley42ab0362006-03-04 09:10:18 -06001536 transport_setup_device(&rdev->rphy.dev);
1537
1538 return &rdev->rphy;
1539}
1540EXPORT_SYMBOL(sas_end_device_alloc);
1541
James Bottomley79cb1812006-03-13 13:50:04 -06001542/**
1543 * sas_expander_alloc - allocate an rphy for an end device
Rob Landleyeb448202007-11-03 13:30:39 -05001544 * @parent: which port
1545 * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE
James Bottomley79cb1812006-03-13 13:50:04 -06001546 *
1547 * Allocates an SAS remote PHY structure, connected to @parent.
1548 *
1549 * Returns:
1550 * SAS PHY allocated or %NULL if the allocation failed.
1551 */
James Bottomley65c92b02006-06-28 12:22:50 -04001552struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
James Bottomley79cb1812006-03-13 13:50:04 -06001553 enum sas_device_type type)
1554{
1555 struct Scsi_Host *shost = dev_to_shost(&parent->dev);
1556 struct sas_expander_device *rdev;
1557 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1558
1559 BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE &&
1560 type != SAS_FANOUT_EXPANDER_DEVICE);
1561
1562 rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
1563 if (!rdev) {
James Bottomley79cb1812006-03-13 13:50:04 -06001564 return NULL;
1565 }
1566
1567 device_initialize(&rdev->rphy.dev);
1568 rdev->rphy.dev.parent = get_device(&parent->dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001569 rdev->rphy.dev.release = sas_expander_release;
James Bottomley79cb1812006-03-13 13:50:04 -06001570 mutex_lock(&sas_host->lock);
1571 rdev->rphy.scsi_target_id = sas_host->next_expander_id++;
1572 mutex_unlock(&sas_host->lock);
Kay Sievers71610f52008-12-03 22:41:36 +01001573 dev_set_name(&rdev->rphy.dev, "expander-%d:%d",
1574 shost->host_no, rdev->rphy.scsi_target_id);
James Bottomley79cb1812006-03-13 13:50:04 -06001575 rdev->rphy.identify.device_type = type;
James Bottomleyc5943d32006-06-12 09:09:18 -05001576 sas_rphy_initialize(&rdev->rphy);
James Bottomley79cb1812006-03-13 13:50:04 -06001577 transport_setup_device(&rdev->rphy.dev);
1578
1579 return &rdev->rphy;
1580}
1581EXPORT_SYMBOL(sas_expander_alloc);
James Bottomley42ab0362006-03-04 09:10:18 -06001582
1583/**
Rob Landleyeb448202007-11-03 13:30:39 -05001584 * sas_rphy_add - add a SAS remote PHY to the device hierarchy
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001585 * @rphy: The remote PHY to be added
1586 *
1587 * Publishes a SAS remote PHY to the rest of the system.
1588 */
1589int sas_rphy_add(struct sas_rphy *rphy)
1590{
James Bottomley65c92b02006-06-28 12:22:50 -04001591 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001592 struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
1593 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1594 struct sas_identify *identify = &rphy->identify;
1595 int error;
1596
1597 if (parent->rphy)
1598 return -ENXIO;
1599 parent->rphy = rphy;
1600
1601 error = device_add(&rphy->dev);
1602 if (error)
1603 return error;
1604 transport_add_device(&rphy->dev);
1605 transport_configure_device(&rphy->dev);
James Bottomley39dca552007-07-20 18:22:17 -05001606 if (sas_bsg_initialize(shost, rphy))
Kay Sievers71610f52008-12-03 22:41:36 +01001607 printk("fail to a bsg device %s\n", dev_name(&rphy->dev));
James Bottomley39dca552007-07-20 18:22:17 -05001608
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001609
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001610 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001611 list_add_tail(&rphy->list, &sas_host->rphy_list);
1612 if (identify->device_type == SAS_END_DEVICE &&
1613 (identify->target_port_protocols &
1614 (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA)))
1615 rphy->scsi_target_id = sas_host->next_target_id++;
James Bottomley7676f832006-04-14 09:47:59 -05001616 else if (identify->device_type == SAS_END_DEVICE)
1617 rphy->scsi_target_id = -1;
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001618 mutex_unlock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001619
James Bottomley79cb1812006-03-13 13:50:04 -06001620 if (identify->device_type == SAS_END_DEVICE &&
1621 rphy->scsi_target_id != -1) {
Dan Williams2fc62e22011-09-20 15:10:19 -07001622 int lun;
1623
1624 if (identify->target_port_protocols & SAS_PROTOCOL_SSP)
1625 lun = SCAN_WILD_CARD;
1626 else
1627 lun = 0;
1628
Hannes Reinecke1d645082016-03-17 08:39:45 +01001629 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun,
1630 SCSI_SCAN_INITIAL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001631 }
1632
1633 return 0;
1634}
1635EXPORT_SYMBOL(sas_rphy_add);
1636
1637/**
Rob Landleyeb448202007-11-03 13:30:39 -05001638 * sas_rphy_free - free a SAS remote PHY
1639 * @rphy: SAS remote PHY to free
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001640 *
1641 * Frees the specified SAS remote PHY.
1642 *
1643 * Note:
1644 * This function must only be called on a remote
André Goddard Rosaaf901ca2009-11-14 13:09:05 -02001645 * PHY that has not successfully been added using
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001646 * sas_rphy_add() (or has been sas_rphy_remove()'d)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001647 */
1648void sas_rphy_free(struct sas_rphy *rphy)
1649{
Mike Anderson92aab642006-03-27 09:37:28 -08001650 struct device *dev = &rphy->dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001651 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
1652 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1653
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001654 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001655 list_del(&rphy->list);
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001656 mutex_unlock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001657
Mike Anderson92aab642006-03-27 09:37:28 -08001658 transport_destroy_device(dev);
James Bottomley2f8600d2006-03-18 15:00:50 -06001659
Mike Anderson92aab642006-03-27 09:37:28 -08001660 put_device(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001661}
1662EXPORT_SYMBOL(sas_rphy_free);
1663
1664/**
Rob Landleyeb448202007-11-03 13:30:39 -05001665 * sas_rphy_delete - remove and free SAS remote PHY
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001666 * @rphy: SAS remote PHY to remove and free
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001667 *
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001668 * Removes the specified SAS remote PHY and frees it.
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001669 */
1670void
1671sas_rphy_delete(struct sas_rphy *rphy)
1672{
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001673 sas_rphy_remove(rphy);
1674 sas_rphy_free(rphy);
1675}
1676EXPORT_SYMBOL(sas_rphy_delete);
1677
1678/**
Dan Williams87c83312011-11-17 17:59:51 -08001679 * sas_rphy_unlink - unlink SAS remote PHY
1680 * @rphy: SAS remote phy to unlink from its parent port
1681 *
1682 * Removes port reference to an rphy
1683 */
1684void sas_rphy_unlink(struct sas_rphy *rphy)
1685{
1686 struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
1687
1688 parent->rphy = NULL;
1689}
1690EXPORT_SYMBOL(sas_rphy_unlink);
1691
1692/**
Rob Landleyeb448202007-11-03 13:30:39 -05001693 * sas_rphy_remove - remove SAS remote PHY
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001694 * @rphy: SAS remote phy to remove
1695 *
1696 * Removes the specified SAS remote PHY.
1697 */
1698void
1699sas_rphy_remove(struct sas_rphy *rphy)
1700{
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001701 struct device *dev = &rphy->dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001702
Christoph Hellwigd4054232006-01-04 13:45:20 +01001703 switch (rphy->identify.device_type) {
1704 case SAS_END_DEVICE:
1705 scsi_remove_target(dev);
1706 break;
1707 case SAS_EDGE_EXPANDER_DEVICE:
1708 case SAS_FANOUT_EXPANDER_DEVICE:
James Bottomley65c92b02006-06-28 12:22:50 -04001709 sas_remove_children(dev);
Christoph Hellwigd4054232006-01-04 13:45:20 +01001710 break;
1711 default:
1712 break;
1713 }
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001714
Dan Williams87c83312011-11-17 17:59:51 -08001715 sas_rphy_unlink(rphy);
Joe Lawrence6aa6caf2014-05-22 17:30:54 -04001716 sas_bsg_remove(NULL, rphy);
Christoph Hellwigfe8b2302005-09-25 23:10:33 +02001717 transport_remove_device(dev);
1718 device_del(dev);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001719}
Darrick J. Wong6f63caa2007-01-26 14:08:43 -08001720EXPORT_SYMBOL(sas_rphy_remove);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001721
1722/**
Rob Landleyeb448202007-11-03 13:30:39 -05001723 * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001724 * @dev: device to check
1725 *
1726 * Returns:
1727 * %1 if the device represents a SAS remote PHY, %0 else
1728 */
1729int scsi_is_sas_rphy(const struct device *dev)
1730{
James Bottomley2f8600d2006-03-18 15:00:50 -06001731 return dev->release == sas_end_device_release ||
1732 dev->release == sas_expander_release;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001733}
1734EXPORT_SYMBOL(scsi_is_sas_rphy);
1735
1736
1737/*
1738 * SCSI scan helper
1739 */
1740
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001741static int sas_user_scan(struct Scsi_Host *shost, uint channel,
Hannes Reinecke9cb78c12014-06-25 15:27:36 +02001742 uint id, u64 lun)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001743{
1744 struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
1745 struct sas_rphy *rphy;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001746
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001747 mutex_lock(&sas_host->lock);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001748 list_for_each_entry(rphy, &sas_host->rphy_list, list) {
James Bottomley6d99a3f2006-05-19 10:49:37 -05001749 if (rphy->identify.device_type != SAS_END_DEVICE ||
1750 rphy->scsi_target_id == -1)
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001751 continue;
1752
James Bottomleye8bf3942006-07-11 17:49:34 -04001753 if ((channel == SCAN_WILD_CARD || channel == 0) &&
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001754 (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
Hannes Reinecke1d645082016-03-17 08:39:45 +01001755 scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id,
1756 lun, SCSI_SCAN_MANUAL);
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001757 }
1758 }
1759 mutex_unlock(&sas_host->lock);
1760
1761 return 0;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001762}
1763
1764
1765/*
1766 * Setup / Teardown code
1767 */
1768
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001769#define SETUP_TEMPLATE(attrb, field, perm, test) \
Tony Jonesee959b02008-02-22 00:13:36 +01001770 i->private_##attrb[count] = dev_attr_##field; \
James Bottomley42ab0362006-03-04 09:10:18 -06001771 i->private_##attrb[count].attr.mode = perm; \
James Bottomley42ab0362006-03-04 09:10:18 -06001772 i->attrb[count] = &i->private_##attrb[count]; \
1773 if (test) \
1774 count++
1775
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001776#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \
Tony Jonesee959b02008-02-22 00:13:36 +01001777 i->private_##attrb[count] = dev_attr_##field; \
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001778 i->private_##attrb[count].attr.mode = perm; \
1779 if (ro_test) { \
1780 i->private_##attrb[count].attr.mode = ro_perm; \
1781 i->private_##attrb[count].store = NULL; \
1782 } \
1783 i->attrb[count] = &i->private_##attrb[count]; \
1784 if (test) \
1785 count++
James Bottomley42ab0362006-03-04 09:10:18 -06001786
1787#define SETUP_RPORT_ATTRIBUTE(field) \
1788 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001789
James Bottomleydd9fbb522006-03-02 16:01:31 -06001790#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
James Bottomley42ab0362006-03-04 09:10:18 -06001791 SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001792
James Bottomley65c92b02006-06-28 12:22:50 -04001793#define SETUP_PHY_ATTRIBUTE(field) \
James Bottomley42ab0362006-03-04 09:10:18 -06001794 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001795
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001796#define SETUP_PHY_ATTRIBUTE_RW(field) \
1797 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1798 !i->f->set_phy_speed, S_IRUGO)
1799
Darrick J. Wongacbf1672007-01-11 14:14:57 -08001800#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \
1801 SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
1802 !i->f->func, S_IRUGO)
1803
James Bottomley65c92b02006-06-28 12:22:50 -04001804#define SETUP_PORT_ATTRIBUTE(field) \
1805 SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
1806
1807#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \
James Bottomley42ab0362006-03-04 09:10:18 -06001808 SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001809
James Bottomley65c92b02006-06-28 12:22:50 -04001810#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
Darrick J. Wongfe3b5bf2007-01-11 14:15:35 -08001811 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1)
Christoph Hellwig07ba3a92005-10-19 20:01:31 +02001812
James Bottomley65c92b02006-06-28 12:22:50 -04001813#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
Darrick J. Wongfe3b5bf2007-01-11 14:15:35 -08001814 SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func)
James Bottomleydd9fbb522006-03-02 16:01:31 -06001815
James Bottomley42ab0362006-03-04 09:10:18 -06001816#define SETUP_END_DEV_ATTRIBUTE(field) \
1817 SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1)
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001818
James Bottomley79cb1812006-03-13 13:50:04 -06001819#define SETUP_EXPANDER_ATTRIBUTE(field) \
1820 SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1)
1821
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001822/**
Rob Landleyeb448202007-11-03 13:30:39 -05001823 * sas_attach_transport - instantiate SAS transport template
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001824 * @ft: SAS transport class function template
1825 */
1826struct scsi_transport_template *
1827sas_attach_transport(struct sas_function_template *ft)
1828{
1829 struct sas_internal *i;
1830 int count;
1831
Jes Sorensen24669f752006-01-16 10:31:18 -05001832 i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001833 if (!i)
1834 return NULL;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001835
Christoph Hellwige02f3f52006-01-13 19:04:00 +01001836 i->t.user_scan = sas_user_scan;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001837
1838 i->t.host_attrs.ac.attrs = &i->host_attrs[0];
1839 i->t.host_attrs.ac.class = &sas_host_class.class;
1840 i->t.host_attrs.ac.match = sas_host_match;
1841 transport_container_register(&i->t.host_attrs);
1842 i->t.host_size = sizeof(struct sas_host_attrs);
1843
1844 i->phy_attr_cont.ac.class = &sas_phy_class.class;
1845 i->phy_attr_cont.ac.attrs = &i->phy_attrs[0];
1846 i->phy_attr_cont.ac.match = sas_phy_match;
1847 transport_container_register(&i->phy_attr_cont);
1848
James Bottomley65c92b02006-06-28 12:22:50 -04001849 i->port_attr_cont.ac.class = &sas_port_class.class;
1850 i->port_attr_cont.ac.attrs = &i->port_attrs[0];
1851 i->port_attr_cont.ac.match = sas_port_match;
1852 transport_container_register(&i->port_attr_cont);
1853
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001854 i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
1855 i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
1856 i->rphy_attr_cont.ac.match = sas_rphy_match;
1857 transport_container_register(&i->rphy_attr_cont);
1858
James Bottomley42ab0362006-03-04 09:10:18 -06001859 i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class;
1860 i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0];
1861 i->end_dev_attr_cont.ac.match = sas_end_dev_match;
1862 transport_container_register(&i->end_dev_attr_cont);
1863
James Bottomley79cb1812006-03-13 13:50:04 -06001864 i->expander_attr_cont.ac.class = &sas_expander_class.class;
1865 i->expander_attr_cont.ac.attrs = &i->expander_attrs[0];
1866 i->expander_attr_cont.ac.match = sas_expander_match;
1867 transport_container_register(&i->expander_attr_cont);
1868
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001869 i->f = ft;
1870
1871 count = 0;
James Bottomley65c92b02006-06-28 12:22:50 -04001872 SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
1873 SETUP_PHY_ATTRIBUTE(target_port_protocols);
1874 SETUP_PHY_ATTRIBUTE(device_type);
1875 SETUP_PHY_ATTRIBUTE(sas_address);
1876 SETUP_PHY_ATTRIBUTE(phy_identifier);
1877 //SETUP_PHY_ATTRIBUTE(port_identifier);
1878 SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
1879 SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001880 SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
James Bottomley65c92b02006-06-28 12:22:50 -04001881 SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
James Bottomleyd24e1ee2006-09-06 19:25:22 -05001882 SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
Christoph Hellwigc3ee74c2005-09-19 21:59:42 +02001883
James Bottomley65c92b02006-06-28 12:22:50 -04001884 SETUP_PHY_ATTRIBUTE(invalid_dword_count);
1885 SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
1886 SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
1887 SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
1888 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
1889 SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
Darrick J. Wongacbf1672007-01-11 14:14:57 -08001890 SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001891 i->phy_attrs[count] = NULL;
1892
1893 count = 0;
James Bottomley65c92b02006-06-28 12:22:50 -04001894 SETUP_PORT_ATTRIBUTE(num_phys);
1895 i->port_attrs[count] = NULL;
1896
1897 count = 0;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001898 SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
1899 SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
1900 SETUP_RPORT_ATTRIBUTE(rphy_device_type);
1901 SETUP_RPORT_ATTRIBUTE(rphy_sas_address);
1902 SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier);
Hannes Reineckecdc43ae2016-03-14 10:43:08 +01001903 SETUP_RPORT_ATTRIBUTE(rphy_scsi_target_id);
James Bottomleydd9fbb522006-03-02 16:01:31 -06001904 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier,
1905 get_enclosure_identifier);
1906 SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier,
1907 get_bay_identifier);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001908 i->rphy_attrs[count] = NULL;
1909
James Bottomley42ab0362006-03-04 09:10:18 -06001910 count = 0;
1911 SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning);
1912 SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout);
1913 SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout);
James Bottomley0f880092010-01-18 10:14:51 -06001914 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported);
1915 SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled);
James Bottomley42ab0362006-03-04 09:10:18 -06001916 i->end_dev_attrs[count] = NULL;
1917
James Bottomley79cb1812006-03-13 13:50:04 -06001918 count = 0;
1919 SETUP_EXPANDER_ATTRIBUTE(vendor_id);
1920 SETUP_EXPANDER_ATTRIBUTE(product_id);
1921 SETUP_EXPANDER_ATTRIBUTE(product_rev);
1922 SETUP_EXPANDER_ATTRIBUTE(component_vendor_id);
1923 SETUP_EXPANDER_ATTRIBUTE(component_id);
1924 SETUP_EXPANDER_ATTRIBUTE(component_revision_id);
1925 SETUP_EXPANDER_ATTRIBUTE(level);
1926 i->expander_attrs[count] = NULL;
1927
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001928 return &i->t;
1929}
1930EXPORT_SYMBOL(sas_attach_transport);
1931
1932/**
Rob Landleyeb448202007-11-03 13:30:39 -05001933 * sas_release_transport - release SAS transport template instance
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001934 * @t: transport template instance
1935 */
1936void sas_release_transport(struct scsi_transport_template *t)
1937{
1938 struct sas_internal *i = to_sas_internal(t);
1939
1940 transport_container_unregister(&i->t.host_attrs);
1941 transport_container_unregister(&i->phy_attr_cont);
James Bottomley65c92b02006-06-28 12:22:50 -04001942 transport_container_unregister(&i->port_attr_cont);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001943 transport_container_unregister(&i->rphy_attr_cont);
James Bottomleydb82f842006-03-09 22:06:36 -05001944 transport_container_unregister(&i->end_dev_attr_cont);
James Bottomley79cb1812006-03-13 13:50:04 -06001945 transport_container_unregister(&i->expander_attr_cont);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001946
1947 kfree(i);
1948}
1949EXPORT_SYMBOL(sas_release_transport);
1950
1951static __init int sas_transport_init(void)
1952{
1953 int error;
1954
1955 error = transport_class_register(&sas_host_class);
1956 if (error)
1957 goto out;
1958 error = transport_class_register(&sas_phy_class);
1959 if (error)
1960 goto out_unregister_transport;
James Bottomley65c92b02006-06-28 12:22:50 -04001961 error = transport_class_register(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001962 if (error)
1963 goto out_unregister_phy;
James Bottomley65c92b02006-06-28 12:22:50 -04001964 error = transport_class_register(&sas_rphy_class);
1965 if (error)
1966 goto out_unregister_port;
James Bottomley42ab0362006-03-04 09:10:18 -06001967 error = transport_class_register(&sas_end_dev_class);
1968 if (error)
1969 goto out_unregister_rphy;
James Bottomley79cb1812006-03-13 13:50:04 -06001970 error = transport_class_register(&sas_expander_class);
1971 if (error)
1972 goto out_unregister_end_dev;
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001973
1974 return 0;
1975
James Bottomley79cb1812006-03-13 13:50:04 -06001976 out_unregister_end_dev:
1977 transport_class_unregister(&sas_end_dev_class);
James Bottomley42ab0362006-03-04 09:10:18 -06001978 out_unregister_rphy:
1979 transport_class_unregister(&sas_rphy_class);
James Bottomley65c92b02006-06-28 12:22:50 -04001980 out_unregister_port:
1981 transport_class_unregister(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001982 out_unregister_phy:
1983 transport_class_unregister(&sas_phy_class);
1984 out_unregister_transport:
1985 transport_class_unregister(&sas_host_class);
1986 out:
1987 return error;
1988
1989}
1990
1991static void __exit sas_transport_exit(void)
1992{
1993 transport_class_unregister(&sas_host_class);
1994 transport_class_unregister(&sas_phy_class);
James Bottomley65c92b02006-06-28 12:22:50 -04001995 transport_class_unregister(&sas_port_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001996 transport_class_unregister(&sas_rphy_class);
James Bottomley42ab0362006-03-04 09:10:18 -06001997 transport_class_unregister(&sas_end_dev_class);
James Bottomley79cb1812006-03-13 13:50:04 -06001998 transport_class_unregister(&sas_expander_class);
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02001999}
2000
2001MODULE_AUTHOR("Christoph Hellwig");
Alexis Bruemmer86b9c4c12007-01-16 15:36:12 -08002002MODULE_DESCRIPTION("SAS Transport Attributes");
Christoph Hellwigc7ebbbc2005-09-09 16:22:50 +02002003MODULE_LICENSE("GPL");
2004
2005module_init(sas_transport_init);
2006module_exit(sas_transport_exit);