1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
#ifndef SCSI_TRANSPORT_SAS_H
#define SCSI_TRANSPORT_SAS_H
#include <linux/transport_class.h>
#include <linux/types.h>
#include <linux/mutex.h>
struct scsi_transport_template;
struct sas_rphy;
enum sas_device_type {
SAS_PHY_UNUSED,
SAS_END_DEVICE,
SAS_EDGE_EXPANDER_DEVICE,
SAS_FANOUT_EXPANDER_DEVICE,
};
enum sas_protocol {
SAS_PROTOCOL_SATA = 0x01,
SAS_PROTOCOL_SMP = 0x02,
SAS_PROTOCOL_STP = 0x04,
SAS_PROTOCOL_SSP = 0x08,
};
enum sas_linkrate {
SAS_LINK_RATE_UNKNOWN,
SAS_PHY_DISABLED,
SAS_LINK_RATE_FAILED,
SAS_SATA_SPINUP_HOLD,
SAS_SATA_PORT_SELECTOR,
SAS_LINK_RATE_1_5_GBPS,
SAS_LINK_RATE_3_0_GBPS,
SAS_LINK_RATE_6_0_GBPS,
SAS_LINK_VIRTUAL,
};
struct sas_identify {
enum sas_device_type device_type;
enum sas_protocol initiator_port_protocols;
enum sas_protocol target_port_protocols;
u64 sas_address;
u8 phy_identifier;
};
struct sas_phy {
struct device dev;
int number;
/* phy identification */
struct sas_identify identify;
/* phy attributes */
enum sas_linkrate negotiated_linkrate;
enum sas_linkrate minimum_linkrate_hw;
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate_hw;
enum sas_linkrate maximum_linkrate;
/* internal state */
unsigned int local_attached : 1;
/* link error statistics */
u32 invalid_dword_count;
u32 running_disparity_error_count;
u32 loss_of_dword_sync_count;
u32 phy_reset_problem_count;
/* for the list of phys belonging to a port */
struct list_head port_siblings;
};
#define dev_to_phy(d) \
container_of((d), struct sas_phy, dev)
#define transport_class_to_phy(cdev) \
dev_to_phy((cdev)->dev)
#define phy_to_shost(phy) \
dev_to_shost((phy)->dev.parent)
struct sas_rphy {
struct device dev;
struct sas_identify identify;
struct list_head list;
u32 scsi_target_id;
};
#define dev_to_rphy(d) \
container_of((d), struct sas_rphy, dev)
#define transport_class_to_rphy(cdev) \
dev_to_rphy((cdev)->dev)
#define rphy_to_shost(rphy) \
dev_to_shost((rphy)->dev.parent)
#define target_to_rphy(targ) \
dev_to_rphy((targ)->dev.parent)
struct sas_end_device {
struct sas_rphy rphy;
/* flags */
unsigned ready_led_meaning:1;
/* parameters */
u16 I_T_nexus_loss_timeout;
u16 initiator_response_timeout;
};
#define rphy_to_end_device(r) \
container_of((r), struct sas_end_device, rphy)
struct sas_expander_device {
int level;
#define SAS_EXPANDER_VENDOR_ID_LEN 8
char vendor_id[SAS_EXPANDER_VENDOR_ID_LEN+1];
#define SAS_EXPANDER_PRODUCT_ID_LEN 16
char product_id[SAS_EXPANDER_PRODUCT_ID_LEN+1];
#define SAS_EXPANDER_PRODUCT_REV_LEN 4
char product_rev[SAS_EXPANDER_PRODUCT_REV_LEN+1];
#define SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN 8
char component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN+1];
u16 component_id;
u8 component_revision_id;
struct sas_rphy rphy;
};
#define rphy_to_expander_device(r) \
container_of((r), struct sas_expander_device, rphy)
struct sas_port {
struct device dev;
u8 port_identifier;
int num_phys;
/* the other end of the link */
struct sas_rphy *rphy;
struct mutex phy_list_mutex;
struct list_head phy_list;
};
#define dev_to_sas_port(d) \
container_of((d), struct sas_port, dev)
#define transport_class_to_sas_port(cdev) \
dev_to_sas_port((cdev)->dev)
/* The functions by which the transport class and the driver communicate */
struct sas_function_template {
int (*get_linkerrors)(struct sas_phy *);
int (*get_enclosure_identifier)(struct sas_rphy *, u64 *);
int (*get_bay_identifier)(struct sas_rphy *);
int (*phy_reset)(struct sas_phy *, int);
};
void sas_remove_children(struct device *);
extern void sas_remove_host(struct Scsi_Host *);
extern struct sas_phy *sas_phy_alloc(struct device *, int);
extern void sas_phy_free(struct sas_phy *);
extern int sas_phy_add(struct sas_phy *);
extern void sas_phy_delete(struct sas_phy *);
extern int scsi_is_sas_phy(const struct device *);
extern struct sas_rphy *sas_end_device_alloc(struct sas_port *);
extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type);
void sas_rphy_free(struct sas_rphy *);
extern int sas_rphy_add(struct sas_rphy *);
extern void sas_rphy_delete(struct sas_rphy *);
extern int scsi_is_sas_rphy(const struct device *);
struct sas_port *sas_port_alloc(struct device *, int);
int sas_port_add(struct sas_port *);
void sas_port_free(struct sas_port *);
void sas_port_delete(struct sas_port *);
void sas_port_add_phy(struct sas_port *, struct sas_phy *);
void sas_port_delete_phy(struct sas_port *, struct sas_phy *);
int scsi_is_sas_port(const struct device *);
extern struct scsi_transport_template *
sas_attach_transport(struct sas_function_template *);
extern void sas_release_transport(struct scsi_transport_template *);
int sas_read_port_mode_page(struct scsi_device *);
static inline int
scsi_is_sas_expander_device(struct device *dev)
{
struct sas_rphy *rphy;
if (!scsi_is_sas_rphy(dev))
return 0;
rphy = dev_to_rphy(dev);
return rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE ||
rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE;
}
#endif /* SCSI_TRANSPORT_SAS_H */
|