2 * driver for Microsemi PQI-based storage controllers
3 * Copyright (c) 2016-2017 Microsemi Corporation
4 * Copyright (c) 2016 PMC-Sierra, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
13 * NON INFRINGEMENT. See the GNU General Public License for more details.
15 * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
19 #include <linux/kernel.h>
20 #include <scsi/scsi_host.h>
21 #include <scsi/scsi_cmnd.h>
22 #include <scsi/scsi_transport_sas.h>
25 static struct pqi_sas_phy
*pqi_alloc_sas_phy(struct pqi_sas_port
*pqi_sas_port
)
27 struct pqi_sas_phy
*pqi_sas_phy
;
30 pqi_sas_phy
= kzalloc(sizeof(*pqi_sas_phy
), GFP_KERNEL
);
34 phy
= sas_phy_alloc(pqi_sas_port
->parent_node
->parent_dev
,
35 pqi_sas_port
->next_phy_index
);
41 pqi_sas_port
->next_phy_index
++;
42 pqi_sas_phy
->phy
= phy
;
43 pqi_sas_phy
->parent_port
= pqi_sas_port
;
48 static void pqi_free_sas_phy(struct pqi_sas_phy
*pqi_sas_phy
)
50 struct sas_phy
*phy
= pqi_sas_phy
->phy
;
52 sas_port_delete_phy(pqi_sas_phy
->parent_port
->port
, phy
);
54 if (pqi_sas_phy
->added_to_port
)
55 list_del(&pqi_sas_phy
->phy_list_entry
);
59 static int pqi_sas_port_add_phy(struct pqi_sas_phy
*pqi_sas_phy
)
62 struct pqi_sas_port
*pqi_sas_port
;
64 struct sas_identify
*identify
;
66 pqi_sas_port
= pqi_sas_phy
->parent_port
;
67 phy
= pqi_sas_phy
->phy
;
69 identify
= &phy
->identify
;
70 memset(identify
, 0, sizeof(*identify
));
71 identify
->sas_address
= pqi_sas_port
->sas_address
;
72 identify
->device_type
= SAS_END_DEVICE
;
73 identify
->initiator_port_protocols
= SAS_PROTOCOL_STP
;
74 identify
->target_port_protocols
= SAS_PROTOCOL_STP
;
75 phy
->minimum_linkrate_hw
= SAS_LINK_RATE_UNKNOWN
;
76 phy
->maximum_linkrate_hw
= SAS_LINK_RATE_UNKNOWN
;
77 phy
->minimum_linkrate
= SAS_LINK_RATE_UNKNOWN
;
78 phy
->maximum_linkrate
= SAS_LINK_RATE_UNKNOWN
;
79 phy
->negotiated_linkrate
= SAS_LINK_RATE_UNKNOWN
;
81 rc
= sas_phy_add(pqi_sas_phy
->phy
);
85 sas_port_add_phy(pqi_sas_port
->port
, pqi_sas_phy
->phy
);
86 list_add_tail(&pqi_sas_phy
->phy_list_entry
,
87 &pqi_sas_port
->phy_list_head
);
88 pqi_sas_phy
->added_to_port
= true;
93 static int pqi_sas_port_add_rphy(struct pqi_sas_port
*pqi_sas_port
,
94 struct sas_rphy
*rphy
)
96 struct sas_identify
*identify
;
98 identify
= &rphy
->identify
;
99 identify
->sas_address
= pqi_sas_port
->sas_address
;
100 identify
->initiator_port_protocols
= SAS_PROTOCOL_STP
;
101 identify
->target_port_protocols
= SAS_PROTOCOL_STP
;
103 return sas_rphy_add(rphy
);
106 static struct pqi_sas_port
*pqi_alloc_sas_port(
107 struct pqi_sas_node
*pqi_sas_node
, u64 sas_address
)
110 struct pqi_sas_port
*pqi_sas_port
;
111 struct sas_port
*port
;
113 pqi_sas_port
= kzalloc(sizeof(*pqi_sas_port
), GFP_KERNEL
);
117 INIT_LIST_HEAD(&pqi_sas_port
->phy_list_head
);
118 pqi_sas_port
->parent_node
= pqi_sas_node
;
120 port
= sas_port_alloc_num(pqi_sas_node
->parent_dev
);
124 rc
= sas_port_add(port
);
128 pqi_sas_port
->port
= port
;
129 pqi_sas_port
->sas_address
= sas_address
;
130 list_add_tail(&pqi_sas_port
->port_list_entry
,
131 &pqi_sas_node
->port_list_head
);
143 static void pqi_free_sas_port(struct pqi_sas_port
*pqi_sas_port
)
145 struct pqi_sas_phy
*pqi_sas_phy
;
146 struct pqi_sas_phy
*next
;
148 list_for_each_entry_safe(pqi_sas_phy
, next
,
149 &pqi_sas_port
->phy_list_head
, phy_list_entry
)
150 pqi_free_sas_phy(pqi_sas_phy
);
152 sas_port_delete(pqi_sas_port
->port
);
153 list_del(&pqi_sas_port
->port_list_entry
);
157 static struct pqi_sas_node
*pqi_alloc_sas_node(struct device
*parent_dev
)
159 struct pqi_sas_node
*pqi_sas_node
;
161 pqi_sas_node
= kzalloc(sizeof(*pqi_sas_node
), GFP_KERNEL
);
163 pqi_sas_node
->parent_dev
= parent_dev
;
164 INIT_LIST_HEAD(&pqi_sas_node
->port_list_head
);
170 static void pqi_free_sas_node(struct pqi_sas_node
*pqi_sas_node
)
172 struct pqi_sas_port
*pqi_sas_port
;
173 struct pqi_sas_port
*next
;
178 list_for_each_entry_safe(pqi_sas_port
, next
,
179 &pqi_sas_node
->port_list_head
, port_list_entry
)
180 pqi_free_sas_port(pqi_sas_port
);
185 struct pqi_scsi_dev
*pqi_find_device_by_sas_rphy(
186 struct pqi_ctrl_info
*ctrl_info
, struct sas_rphy
*rphy
)
188 struct pqi_scsi_dev
*device
;
190 list_for_each_entry(device
, &ctrl_info
->scsi_device_list
,
191 scsi_device_list_entry
) {
192 if (!device
->sas_port
)
194 if (device
->sas_port
->rphy
== rphy
)
201 int pqi_add_sas_host(struct Scsi_Host
*shost
, struct pqi_ctrl_info
*ctrl_info
)
204 struct device
*parent_dev
;
205 struct pqi_sas_node
*pqi_sas_node
;
206 struct pqi_sas_port
*pqi_sas_port
;
207 struct pqi_sas_phy
*pqi_sas_phy
;
209 parent_dev
= &shost
->shost_gendev
;
211 pqi_sas_node
= pqi_alloc_sas_node(parent_dev
);
215 pqi_sas_port
= pqi_alloc_sas_port(pqi_sas_node
, ctrl_info
->sas_address
);
221 pqi_sas_phy
= pqi_alloc_sas_phy(pqi_sas_port
);
227 rc
= pqi_sas_port_add_phy(pqi_sas_phy
);
231 ctrl_info
->sas_host
= pqi_sas_node
;
236 pqi_free_sas_phy(pqi_sas_phy
);
238 pqi_free_sas_port(pqi_sas_port
);
240 pqi_free_sas_node(pqi_sas_node
);
245 void pqi_delete_sas_host(struct pqi_ctrl_info
*ctrl_info
)
247 pqi_free_sas_node(ctrl_info
->sas_host
);
250 int pqi_add_sas_device(struct pqi_sas_node
*pqi_sas_node
,
251 struct pqi_scsi_dev
*device
)
254 struct pqi_sas_port
*pqi_sas_port
;
255 struct sas_rphy
*rphy
;
257 pqi_sas_port
= pqi_alloc_sas_port(pqi_sas_node
, device
->sas_address
);
261 rphy
= sas_end_device_alloc(pqi_sas_port
->port
);
267 pqi_sas_port
->rphy
= rphy
;
268 device
->sas_port
= pqi_sas_port
;
270 rc
= pqi_sas_port_add_rphy(pqi_sas_port
, rphy
);
277 pqi_free_sas_port(pqi_sas_port
);
278 device
->sas_port
= NULL
;
283 void pqi_remove_sas_device(struct pqi_scsi_dev
*device
)
285 if (device
->sas_port
) {
286 pqi_free_sas_port(device
->sas_port
);
287 device
->sas_port
= NULL
;
291 static int pqi_sas_get_linkerrors(struct sas_phy
*phy
)
296 static int pqi_sas_get_enclosure_identifier(struct sas_rphy
*rphy
,
302 static int pqi_sas_get_bay_identifier(struct sas_rphy
*rphy
)
307 static int pqi_sas_phy_reset(struct sas_phy
*phy
, int hard_reset
)
312 static int pqi_sas_phy_enable(struct sas_phy
*phy
, int enable
)
317 static int pqi_sas_phy_setup(struct sas_phy
*phy
)
322 static void pqi_sas_phy_release(struct sas_phy
*phy
)
326 static int pqi_sas_phy_speed(struct sas_phy
*phy
,
327 struct sas_phy_linkrates
*rates
)
332 struct sas_function_template pqi_sas_transport_functions
= {
333 .get_linkerrors
= pqi_sas_get_linkerrors
,
334 .get_enclosure_identifier
= pqi_sas_get_enclosure_identifier
,
335 .get_bay_identifier
= pqi_sas_get_bay_identifier
,
336 .phy_reset
= pqi_sas_phy_reset
,
337 .phy_enable
= pqi_sas_phy_enable
,
338 .phy_setup
= pqi_sas_phy_setup
,
339 .phy_release
= pqi_sas_phy_release
,
340 .set_phy_speed
= pqi_sas_phy_speed
,