GNU Linux-libre 4.9.318-gnu1
[releases.git] / drivers / scsi / smartpqi / smartpqi_sas_transport.c
1 /*
2  *    driver for Microsemi PQI-based storage controllers
3  *    Copyright (c) 2016 Microsemi Corporation
4  *    Copyright (c) 2016 PMC-Sierra, Inc.
5  *
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.
9  *
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.
14  *
15  *    Questions/Comments/Bugfixes to esc.storagedev@microsemi.com
16  *
17  */
18
19 #include <linux/kernel.h>
20 #include <scsi/scsi_host.h>
21 #include <scsi/scsi_cmnd.h>
22 #include <scsi/scsi_transport_sas.h>
23 #include "smartpqi.h"
24
25 static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port)
26 {
27         struct pqi_sas_phy *pqi_sas_phy;
28         struct sas_phy *phy;
29
30         pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL);
31         if (!pqi_sas_phy)
32                 return NULL;
33
34         phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev,
35                 pqi_sas_port->next_phy_index);
36         if (!phy) {
37                 kfree(pqi_sas_phy);
38                 return NULL;
39         }
40
41         pqi_sas_port->next_phy_index++;
42         pqi_sas_phy->phy = phy;
43         pqi_sas_phy->parent_port = pqi_sas_port;
44
45         return pqi_sas_phy;
46 }
47
48 static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy)
49 {
50         struct sas_phy *phy = pqi_sas_phy->phy;
51
52         sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy);
53         sas_phy_free(phy);
54         if (pqi_sas_phy->added_to_port)
55                 list_del(&pqi_sas_phy->phy_list_entry);
56         kfree(pqi_sas_phy);
57 }
58
59 static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy)
60 {
61         int rc;
62         struct pqi_sas_port *pqi_sas_port;
63         struct sas_phy *phy;
64         struct sas_identify *identify;
65
66         pqi_sas_port = pqi_sas_phy->parent_port;
67         phy = pqi_sas_phy->phy;
68
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;
80
81         rc = sas_phy_add(pqi_sas_phy->phy);
82         if (rc)
83                 return rc;
84
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;
89
90         return 0;
91 }
92
93 static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port,
94         struct sas_rphy *rphy)
95 {
96         struct sas_identify *identify;
97
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;
102
103         return sas_rphy_add(rphy);
104 }
105
106 static struct pqi_sas_port *pqi_alloc_sas_port(
107         struct pqi_sas_node *pqi_sas_node, u64 sas_address)
108 {
109         int rc;
110         struct pqi_sas_port *pqi_sas_port;
111         struct sas_port *port;
112
113         pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL);
114         if (!pqi_sas_port)
115                 return NULL;
116
117         INIT_LIST_HEAD(&pqi_sas_port->phy_list_head);
118         pqi_sas_port->parent_node = pqi_sas_node;
119
120         port = sas_port_alloc_num(pqi_sas_node->parent_dev);
121         if (!port)
122                 goto free_pqi_port;
123
124         rc = sas_port_add(port);
125         if (rc)
126                 goto free_sas_port;
127
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);
132
133         return pqi_sas_port;
134
135 free_sas_port:
136         sas_port_free(port);
137 free_pqi_port:
138         kfree(pqi_sas_port);
139
140         return NULL;
141 }
142
143 static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port)
144 {
145         struct pqi_sas_phy *pqi_sas_phy;
146         struct pqi_sas_phy *next;
147
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);
151
152         sas_port_delete(pqi_sas_port->port);
153         list_del(&pqi_sas_port->port_list_entry);
154         kfree(pqi_sas_port);
155 }
156
157 static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev)
158 {
159         struct pqi_sas_node *pqi_sas_node;
160
161         pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL);
162         if (pqi_sas_node) {
163                 pqi_sas_node->parent_dev = parent_dev;
164                 INIT_LIST_HEAD(&pqi_sas_node->port_list_head);
165         }
166
167         return pqi_sas_node;
168 }
169
170 static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node)
171 {
172         struct pqi_sas_port *pqi_sas_port;
173         struct pqi_sas_port *next;
174
175         if (!pqi_sas_node)
176                 return;
177
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);
181
182         kfree(pqi_sas_node);
183 }
184
185 struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
186         struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy)
187 {
188         struct pqi_scsi_dev *device;
189
190         list_for_each_entry(device, &ctrl_info->scsi_device_list,
191                 scsi_device_list_entry) {
192                 if (!device->sas_port)
193                         continue;
194                 if (device->sas_port->rphy == rphy)
195                         return device;
196         }
197
198         return NULL;
199 }
200
201 int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info)
202 {
203         int rc;
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;
208
209         parent_dev = &shost->shost_gendev;
210
211         pqi_sas_node = pqi_alloc_sas_node(parent_dev);
212         if (!pqi_sas_node)
213                 return -ENOMEM;
214
215         pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, ctrl_info->sas_address);
216         if (!pqi_sas_port) {
217                 rc = -ENODEV;
218                 goto free_sas_node;
219         }
220
221         pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port);
222         if (!pqi_sas_phy) {
223                 rc = -ENODEV;
224                 goto free_sas_port;
225         }
226
227         rc = pqi_sas_port_add_phy(pqi_sas_phy);
228         if (rc)
229                 goto free_sas_phy;
230
231         ctrl_info->sas_host = pqi_sas_node;
232
233         return 0;
234
235 free_sas_phy:
236         pqi_free_sas_phy(pqi_sas_phy);
237 free_sas_port:
238         pqi_free_sas_port(pqi_sas_port);
239 free_sas_node:
240         pqi_free_sas_node(pqi_sas_node);
241
242         return rc;
243 }
244
245 void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info)
246 {
247         pqi_free_sas_node(ctrl_info->sas_host);
248 }
249
250 int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
251         struct pqi_scsi_dev *device)
252 {
253         int rc;
254         struct pqi_sas_port *pqi_sas_port;
255         struct sas_rphy *rphy;
256
257         pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, device->sas_address);
258         if (!pqi_sas_port)
259                 return -ENOMEM;
260
261         rphy = sas_end_device_alloc(pqi_sas_port->port);
262         if (!rphy) {
263                 rc = -ENODEV;
264                 goto free_sas_port;
265         }
266
267         pqi_sas_port->rphy = rphy;
268         device->sas_port = pqi_sas_port;
269
270         rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy);
271         if (rc)
272                 goto free_sas_port;
273
274         return 0;
275
276 free_sas_port:
277         pqi_free_sas_port(pqi_sas_port);
278         device->sas_port = NULL;
279
280         return rc;
281 }
282
283 void pqi_remove_sas_device(struct pqi_scsi_dev *device)
284 {
285         if (device->sas_port) {
286                 pqi_free_sas_port(device->sas_port);
287                 device->sas_port = NULL;
288         }
289 }
290
291 static int pqi_sas_get_linkerrors(struct sas_phy *phy)
292 {
293         return 0;
294 }
295
296 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
297         u64 *identifier)
298 {
299         return 0;
300 }
301
302 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
303 {
304         return -ENXIO;
305 }
306
307 static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset)
308 {
309         return 0;
310 }
311
312 static int pqi_sas_phy_enable(struct sas_phy *phy, int enable)
313 {
314         return 0;
315 }
316
317 static int pqi_sas_phy_setup(struct sas_phy *phy)
318 {
319         return 0;
320 }
321
322 static void pqi_sas_phy_release(struct sas_phy *phy)
323 {
324 }
325
326 static int pqi_sas_phy_speed(struct sas_phy *phy,
327         struct sas_phy_linkrates *rates)
328 {
329         return -EINVAL;
330 }
331
332 /* SMP = Serial Management Protocol */
333
334 static int pqi_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
335         struct request *req)
336 {
337         return -EINVAL;
338 }
339
340 struct sas_function_template pqi_sas_transport_functions = {
341         .get_linkerrors = pqi_sas_get_linkerrors,
342         .get_enclosure_identifier = pqi_sas_get_enclosure_identifier,
343         .get_bay_identifier = pqi_sas_get_bay_identifier,
344         .phy_reset = pqi_sas_phy_reset,
345         .phy_enable = pqi_sas_phy_enable,
346         .phy_setup = pqi_sas_phy_setup,
347         .phy_release = pqi_sas_phy_release,
348         .set_phy_speed = pqi_sas_phy_speed,
349         .smp_handler = pqi_sas_smp_handler,
350 };