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 };
351