1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Driver for Broadcom MPI3 Storage Controllers
4 *
5 * Copyright (C) 2017-2023 Broadcom Inc.
6 * (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
7 *
8 */
9
10 #include <linux/vmalloc.h>
11
12 #include "mpi3mr.h"
13
14 /**
15 * mpi3mr_post_transport_req - Issue transport requests and wait
16 * @mrioc: Adapter instance reference
17 * @request: Properly populated MPI3 request
18 * @request_sz: Size of the MPI3 request
19 * @reply: Pointer to return MPI3 reply
20 * @reply_sz: Size of the MPI3 reply buffer
21 * @timeout: Timeout in seconds
22 * @ioc_status: Pointer to return ioc status
23 *
24 * A generic function for posting MPI3 requests from the SAS
25 * transport layer that uses transport command infrastructure.
26 * This blocks for the completion of request for timeout seconds
27 * and if the request times out this function faults the
28 * controller with proper reason code.
29 *
30 * On successful completion of the request this function returns
31 * appropriate ioc status from the firmware back to the caller.
32 *
33 * Return: 0 on success, non-zero on failure.
34 */
mpi3mr_post_transport_req(struct mpi3mr_ioc * mrioc,void * request,u16 request_sz,void * reply,u16 reply_sz,int timeout,u16 * ioc_status)35 static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
36 u16 request_sz, void *reply, u16 reply_sz, int timeout,
37 u16 *ioc_status)
38 {
39 int retval = 0;
40
41 mutex_lock(&mrioc->transport_cmds.mutex);
42 if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
43 retval = -1;
44 ioc_err(mrioc, "sending transport request failed due to command in use\n");
45 mutex_unlock(&mrioc->transport_cmds.mutex);
46 goto out;
47 }
48 mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
49 mrioc->transport_cmds.is_waiting = 1;
50 mrioc->transport_cmds.callback = NULL;
51 mrioc->transport_cmds.ioc_status = 0;
52 mrioc->transport_cmds.ioc_loginfo = 0;
53
54 init_completion(&mrioc->transport_cmds.done);
55 dprint_cfg_info(mrioc, "posting transport request\n");
56 if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
57 dprint_dump(request, request_sz, "transport_req");
58 retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1);
59 if (retval) {
60 ioc_err(mrioc, "posting transport request failed\n");
61 goto out_unlock;
62 }
63 wait_for_completion_timeout(&mrioc->transport_cmds.done,
64 (timeout * HZ));
65 if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
66 mpi3mr_check_rh_fault_ioc(mrioc,
67 MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
68 ioc_err(mrioc, "transport request timed out\n");
69 retval = -1;
70 goto out_unlock;
71 }
72 *ioc_status = mrioc->transport_cmds.ioc_status &
73 MPI3_IOCSTATUS_STATUS_MASK;
74 if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
75 dprint_transport_err(mrioc,
76 "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
77 *ioc_status, mrioc->transport_cmds.ioc_loginfo);
78
79 if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
80 memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
81
82 out_unlock:
83 mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
84 mutex_unlock(&mrioc->transport_cmds.mutex);
85
86 out:
87 return retval;
88 }
89
90 /* report manufacture request structure */
91 struct rep_manu_request {
92 u8 smp_frame_type;
93 u8 function;
94 u8 reserved;
95 u8 request_length;
96 };
97
98 /* report manufacture reply structure */
99 struct rep_manu_reply {
100 u8 smp_frame_type; /* 0x41 */
101 u8 function; /* 0x01 */
102 u8 function_result;
103 u8 response_length;
104 u16 expander_change_count;
105 u8 reserved0[2];
106 u8 sas_format;
107 u8 reserved2[3];
108 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN] __nonstring;
109 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN] __nonstring;
110 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN] __nonstring;
111 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN] __nonstring;
112 u16 component_id;
113 u8 component_revision_id;
114 u8 reserved3;
115 u8 vendor_specific[8];
116 };
117
118 /**
119 * mpi3mr_report_manufacture - obtain SMP report_manufacture
120 * @mrioc: Adapter instance reference
121 * @sas_address: SAS address of the expander device
122 * @edev: SAS transport layer sas_expander_device object
123 * @port_id: ID of the HBA port
124 *
125 * Fills in the sas_expander_device with manufacturing info.
126 *
127 * Return: 0 for success, non-zero for failure.
128 */
mpi3mr_report_manufacture(struct mpi3mr_ioc * mrioc,u64 sas_address,struct sas_expander_device * edev,u8 port_id)129 static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
130 u64 sas_address, struct sas_expander_device *edev, u8 port_id)
131 {
132 struct mpi3_smp_passthrough_request mpi_request;
133 struct mpi3_smp_passthrough_reply mpi_reply;
134 struct rep_manu_reply *manufacture_reply;
135 struct rep_manu_request *manufacture_request;
136 int rc = 0;
137 void *psge;
138 void *data_out = NULL;
139 dma_addr_t data_out_dma;
140 dma_addr_t data_in_dma;
141 size_t data_in_sz;
142 size_t data_out_sz;
143 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
144 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
145 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
146 u16 ioc_status;
147 u8 *tmp;
148
149 if (mrioc->reset_in_progress) {
150 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
151 return -EFAULT;
152 }
153
154 if (mrioc->pci_err_recovery) {
155 ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
156 return -EFAULT;
157 }
158
159 data_out_sz = sizeof(struct rep_manu_request);
160 data_in_sz = sizeof(struct rep_manu_reply);
161 data_out = dma_alloc_coherent(&mrioc->pdev->dev,
162 data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
163 if (!data_out) {
164 rc = -ENOMEM;
165 goto out;
166 }
167
168 data_in_dma = data_out_dma + data_out_sz;
169 manufacture_reply = data_out + data_out_sz;
170
171 manufacture_request = data_out;
172 manufacture_request->smp_frame_type = 0x40;
173 manufacture_request->function = 1;
174 manufacture_request->reserved = 0;
175 manufacture_request->request_length = 0;
176
177 memset(&mpi_request, 0, request_sz);
178 memset(&mpi_reply, 0, reply_sz);
179 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
180 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
181 mpi_request.io_unit_port = (u8) port_id;
182 mpi_request.sas_address = cpu_to_le64(sas_address);
183
184 psge = &mpi_request.request_sge;
185 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
186
187 psge = &mpi_request.response_sge;
188 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
189
190 dprint_transport_info(mrioc,
191 "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
192 (unsigned long long)sas_address, port_id);
193
194 rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
195 &mpi_reply, reply_sz,
196 MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
197 if (rc)
198 goto out;
199
200 dprint_transport_info(mrioc,
201 "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
202 ioc_status);
203
204 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
205 rc = -EINVAL;
206 goto out;
207 }
208
209 dprint_transport_info(mrioc,
210 "report manufacturer - reply data transfer size(%d)\n",
211 le16_to_cpu(mpi_reply.response_data_length));
212
213 if (le16_to_cpu(mpi_reply.response_data_length) !=
214 sizeof(struct rep_manu_reply)) {
215 rc = -EINVAL;
216 goto out;
217 }
218
219 memtostr(edev->vendor_id, manufacture_reply->vendor_id);
220 memtostr(edev->product_id, manufacture_reply->product_id);
221 memtostr(edev->product_rev, manufacture_reply->product_rev);
222 edev->level = manufacture_reply->sas_format & 1;
223 if (edev->level) {
224 memtostr(edev->component_vendor_id,
225 manufacture_reply->component_vendor_id);
226 tmp = (u8 *)&manufacture_reply->component_id;
227 edev->component_id = tmp[0] << 8 | tmp[1];
228 edev->component_revision_id =
229 manufacture_reply->component_revision_id;
230 }
231
232 out:
233 if (data_out)
234 dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
235 data_out, data_out_dma);
236
237 return rc;
238 }
239
240 /**
241 * __mpi3mr_expander_find_by_handle - expander search by handle
242 * @mrioc: Adapter instance reference
243 * @handle: Firmware device handle of the expander
244 *
245 * Context: The caller should acquire sas_node_lock
246 *
247 * This searches for expander device based on handle, then
248 * returns the sas_node object.
249 *
250 * Return: Expander sas_node object reference or NULL
251 */
__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc * mrioc,u16 handle)252 struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc
253 *mrioc, u16 handle)
254 {
255 struct mpi3mr_sas_node *sas_expander, *r;
256
257 r = NULL;
258 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
259 if (sas_expander->handle != handle)
260 continue;
261 r = sas_expander;
262 goto out;
263 }
264 out:
265 return r;
266 }
267
268 /**
269 * mpi3mr_is_expander_device - if device is an expander
270 * @device_info: Bitfield providing information about the device
271 *
272 * Return: 1 if the device is expander device, else 0.
273 */
mpi3mr_is_expander_device(u16 device_info)274 u8 mpi3mr_is_expander_device(u16 device_info)
275 {
276 if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) ==
277 MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER)
278 return 1;
279 else
280 return 0;
281 }
282
283 /**
284 * mpi3mr_get_sas_address - retrieve sas_address for handle
285 * @mrioc: Adapter instance reference
286 * @handle: Firmware device handle
287 * @sas_address: Address to hold sas address
288 *
289 * This function issues device page0 read for a given device
290 * handle and gets the SAS address and return it back
291 *
292 * Return: 0 for success, non-zero for failure
293 */
mpi3mr_get_sas_address(struct mpi3mr_ioc * mrioc,u16 handle,u64 * sas_address)294 static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle,
295 u64 *sas_address)
296 {
297 struct mpi3_device_page0 dev_pg0;
298 u16 ioc_status;
299 struct mpi3_device0_sas_sata_format *sasinf;
300
301 *sas_address = 0;
302
303 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
304 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
305 handle))) {
306 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
307 return -ENXIO;
308 }
309
310 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
311 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
312 handle, ioc_status, __FILE__, __LINE__, __func__);
313 return -ENXIO;
314 }
315
316 if (le16_to_cpu(dev_pg0.flags) &
317 MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE)
318 *sas_address = mrioc->sas_hba.sas_address;
319 else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) {
320 sasinf = &dev_pg0.device_specific.sas_sata_format;
321 *sas_address = le64_to_cpu(sasinf->sas_address);
322 } else {
323 ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n",
324 __func__, dev_pg0.device_form);
325 return -ENXIO;
326 }
327 return 0;
328 }
329
330 /**
331 * __mpi3mr_get_tgtdev_by_addr - target device search
332 * @mrioc: Adapter instance reference
333 * @sas_address: SAS address of the device
334 * @hba_port: HBA port entry
335 *
336 * This searches for target device from sas address and hba port
337 * pointer then return mpi3mr_tgt_dev object.
338 *
339 * Return: Valid tget_dev or NULL
340 */
__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)341 static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
342 u64 sas_address, struct mpi3mr_hba_port *hba_port)
343 {
344 struct mpi3mr_tgt_dev *tgtdev;
345
346 assert_spin_locked(&mrioc->tgtdev_lock);
347
348 list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
349 if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
350 (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
351 && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port))
352 goto found_device;
353 return NULL;
354 found_device:
355 mpi3mr_tgtdev_get(tgtdev);
356 return tgtdev;
357 }
358
359 /**
360 * mpi3mr_get_tgtdev_by_addr - target device search
361 * @mrioc: Adapter instance reference
362 * @sas_address: SAS address of the device
363 * @hba_port: HBA port entry
364 *
365 * This searches for target device from sas address and hba port
366 * pointer then return mpi3mr_tgt_dev object.
367 *
368 * Context: This function will acquire tgtdev_lock and will
369 * release before returning the mpi3mr_tgt_dev object.
370 *
371 * Return: Valid tget_dev or NULL
372 */
mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)373 static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
374 u64 sas_address, struct mpi3mr_hba_port *hba_port)
375 {
376 struct mpi3mr_tgt_dev *tgtdev = NULL;
377 unsigned long flags;
378
379 if (!hba_port)
380 goto out;
381
382 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
383 tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port);
384 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
385
386 out:
387 return tgtdev;
388 }
389
390 /**
391 * mpi3mr_remove_device_by_sas_address - remove the device
392 * @mrioc: Adapter instance reference
393 * @sas_address: SAS address of the device
394 * @hba_port: HBA port entry
395 *
396 * This searches for target device using sas address and hba
397 * port pointer then removes it from the OS.
398 *
399 * Return: None
400 */
mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)401 static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
402 u64 sas_address, struct mpi3mr_hba_port *hba_port)
403 {
404 struct mpi3mr_tgt_dev *tgtdev = NULL;
405 unsigned long flags;
406 u8 was_on_tgtdev_list = 0;
407
408 if (!hba_port)
409 return;
410
411 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
412 tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,
413 sas_address, hba_port);
414 if (tgtdev) {
415 if (!list_empty(&tgtdev->list)) {
416 was_on_tgtdev_list = 1;
417 if (tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) {
418 list_del_init(&tgtdev->list);
419 mpi3mr_tgtdev_put(tgtdev);
420 }
421 }
422 }
423 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
424 if (was_on_tgtdev_list) {
425 if (tgtdev->host_exposed)
426 mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
427 mpi3mr_tgtdev_put(tgtdev);
428 }
429 }
430
431 /**
432 * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
433 * @mrioc: Adapter instance reference
434 * @sas_address: SAS address of the device
435 * @rphy: SAS transport layer rphy object
436 *
437 * This searches for target device from sas address and rphy
438 * pointer then return mpi3mr_tgt_dev object.
439 *
440 * Return: Valid tget_dev or NULL
441 */
__mpi3mr_get_tgtdev_by_addr_and_rphy(struct mpi3mr_ioc * mrioc,u64 sas_address,struct sas_rphy * rphy)442 struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
443 struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
444 {
445 struct mpi3mr_tgt_dev *tgtdev;
446
447 assert_spin_locked(&mrioc->tgtdev_lock);
448
449 list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
450 if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
451 (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
452 && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))
453 goto found_device;
454 return NULL;
455 found_device:
456 mpi3mr_tgtdev_get(tgtdev);
457 return tgtdev;
458 }
459
460 /**
461 * mpi3mr_expander_find_by_sas_address - sas expander search
462 * @mrioc: Adapter instance reference
463 * @sas_address: SAS address of expander
464 * @hba_port: HBA port entry
465 *
466 * Return: A valid SAS expander node or NULL.
467 *
468 */
mpi3mr_expander_find_by_sas_address(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)469 static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(
470 struct mpi3mr_ioc *mrioc, u64 sas_address,
471 struct mpi3mr_hba_port *hba_port)
472 {
473 struct mpi3mr_sas_node *sas_expander, *r = NULL;
474
475 if (!hba_port)
476 goto out;
477
478 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
479 if ((sas_expander->sas_address != sas_address) ||
480 (sas_expander->hba_port != hba_port))
481 continue;
482 r = sas_expander;
483 goto out;
484 }
485 out:
486 return r;
487 }
488
489 /**
490 * __mpi3mr_sas_node_find_by_sas_address - sas node search
491 * @mrioc: Adapter instance reference
492 * @sas_address: SAS address of expander or sas host
493 * @hba_port: HBA port entry
494 * Context: Caller should acquire mrioc->sas_node_lock.
495 *
496 * If the SAS address indicates the device is direct attached to
497 * the controller (controller's SAS address) then the SAS node
498 * associated with the controller is returned back else the SAS
499 * address and hba port are used to identify the exact expander
500 * and the associated sas_node object is returned. If there is
501 * no match NULL is returned.
502 *
503 * Return: A valid SAS node or NULL.
504 *
505 */
__mpi3mr_sas_node_find_by_sas_address(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)506 static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(
507 struct mpi3mr_ioc *mrioc, u64 sas_address,
508 struct mpi3mr_hba_port *hba_port)
509 {
510
511 if (mrioc->sas_hba.sas_address == sas_address)
512 return &mrioc->sas_hba;
513 return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
514 hba_port);
515 }
516
517 /**
518 * mpi3mr_parent_present - Is parent present for a phy
519 * @mrioc: Adapter instance reference
520 * @phy: SAS transport layer phy object
521 *
522 * Return: 0 if parent is present else non-zero
523 */
mpi3mr_parent_present(struct mpi3mr_ioc * mrioc,struct sas_phy * phy)524 static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)
525 {
526 unsigned long flags;
527 struct mpi3mr_hba_port *hba_port = phy->hostdata;
528
529 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
530 if (__mpi3mr_sas_node_find_by_sas_address(mrioc,
531 phy->identify.sas_address,
532 hba_port) == NULL) {
533 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
534 return -1;
535 }
536 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
537 return 0;
538 }
539
540 /**
541 * mpi3mr_convert_phy_link_rate -
542 * @link_rate: link rate as defined in the MPI header
543 *
544 * Convert link_rate from mpi format into sas_transport layer
545 * form.
546 *
547 * Return: A valid SAS transport layer defined link rate
548 */
mpi3mr_convert_phy_link_rate(u8 link_rate)549 static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
550 {
551 enum sas_linkrate rc;
552
553 switch (link_rate) {
554 case MPI3_SAS_NEG_LINK_RATE_1_5:
555 rc = SAS_LINK_RATE_1_5_GBPS;
556 break;
557 case MPI3_SAS_NEG_LINK_RATE_3_0:
558 rc = SAS_LINK_RATE_3_0_GBPS;
559 break;
560 case MPI3_SAS_NEG_LINK_RATE_6_0:
561 rc = SAS_LINK_RATE_6_0_GBPS;
562 break;
563 case MPI3_SAS_NEG_LINK_RATE_12_0:
564 rc = SAS_LINK_RATE_12_0_GBPS;
565 break;
566 case MPI3_SAS_NEG_LINK_RATE_22_5:
567 rc = SAS_LINK_RATE_22_5_GBPS;
568 break;
569 case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
570 rc = SAS_PHY_DISABLED;
571 break;
572 case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
573 rc = SAS_LINK_RATE_FAILED;
574 break;
575 case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
576 rc = SAS_SATA_PORT_SELECTOR;
577 break;
578 case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
579 rc = SAS_PHY_RESET_IN_PROGRESS;
580 break;
581 case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
582 case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
583 default:
584 rc = SAS_LINK_RATE_UNKNOWN;
585 break;
586 }
587 return rc;
588 }
589
590 /**
591 * mpi3mr_delete_sas_phy - Remove a single phy from port
592 * @mrioc: Adapter instance reference
593 * @mr_sas_port: Internal Port object
594 * @mr_sas_phy: Internal Phy object
595 * @host_node: Flag to indicate this is a host_node
596 *
597 * Return: None.
598 */
mpi3mr_delete_sas_phy(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_port * mr_sas_port,struct mpi3mr_sas_phy * mr_sas_phy,u8 host_node)599 static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
600 struct mpi3mr_sas_port *mr_sas_port,
601 struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
602 {
603 u64 sas_address = mr_sas_port->remote_identify.sas_address;
604
605 dev_info(&mr_sas_phy->phy->dev,
606 "remove: sas_address(0x%016llx), phy(%d)\n",
607 (unsigned long long) sas_address, mr_sas_phy->phy_id);
608
609 list_del(&mr_sas_phy->port_siblings);
610 mr_sas_port->num_phys--;
611
612 if (host_node) {
613 mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
614
615 if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
616 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
617 }
618 sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
619 mr_sas_phy->phy_belongs_to_port = 0;
620 }
621
622 /**
623 * mpi3mr_add_sas_phy - Adding a single phy to a port
624 * @mrioc: Adapter instance reference
625 * @mr_sas_port: Internal Port object
626 * @mr_sas_phy: Internal Phy object
627 * @host_node: Flag to indicate this is a host_node
628 *
629 * Return: None.
630 */
mpi3mr_add_sas_phy(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_port * mr_sas_port,struct mpi3mr_sas_phy * mr_sas_phy,u8 host_node)631 static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
632 struct mpi3mr_sas_port *mr_sas_port,
633 struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
634 {
635 u64 sas_address = mr_sas_port->remote_identify.sas_address;
636
637 dev_info(&mr_sas_phy->phy->dev,
638 "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
639 sas_address, mr_sas_phy->phy_id);
640
641 list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
642 mr_sas_port->num_phys++;
643 if (host_node) {
644 mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
645
646 if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
647 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
648 }
649 sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
650 mr_sas_phy->phy_belongs_to_port = 1;
651 }
652
653 /**
654 * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
655 * @mrioc: Adapter instance reference
656 * @mr_sas_node: Internal sas node object (expander or host)
657 * @mr_sas_phy: Internal Phy object *
658 * @sas_address: SAS address of device/expander were phy needs
659 * to be added to
660 * @hba_port: HBA port entry
661 *
662 * Return: None.
663 */
mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * mr_sas_node,struct mpi3mr_sas_phy * mr_sas_phy,u64 sas_address,struct mpi3mr_hba_port * hba_port)664 static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
665 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
666 u64 sas_address, struct mpi3mr_hba_port *hba_port)
667 {
668 struct mpi3mr_sas_port *mr_sas_port;
669 struct mpi3mr_sas_phy *srch_phy;
670
671 if (mr_sas_phy->phy_belongs_to_port == 1)
672 return;
673
674 if (!hba_port)
675 return;
676
677 list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,
678 port_list) {
679 if (mr_sas_port->remote_identify.sas_address !=
680 sas_address)
681 continue;
682 if (mr_sas_port->hba_port != hba_port)
683 continue;
684 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
685 port_siblings) {
686 if (srch_phy == mr_sas_phy)
687 return;
688 }
689 mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy, mr_sas_node->host_node);
690 return;
691 }
692 }
693
694 /**
695 * mpi3mr_delete_sas_port - helper function to removing a port
696 * @mrioc: Adapter instance reference
697 * @mr_sas_port: Internal Port object
698 *
699 * Return: None.
700 */
mpi3mr_delete_sas_port(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_port * mr_sas_port)701 static void mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,
702 struct mpi3mr_sas_port *mr_sas_port)
703 {
704 u64 sas_address = mr_sas_port->remote_identify.sas_address;
705 struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;
706 enum sas_device_type device_type =
707 mr_sas_port->remote_identify.device_type;
708
709 dev_info(&mr_sas_port->port->dev,
710 "remove: sas_address(0x%016llx)\n",
711 (unsigned long long) sas_address);
712
713 if (device_type == SAS_END_DEVICE)
714 mpi3mr_remove_device_by_sas_address(mrioc, sas_address,
715 hba_port);
716
717 else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
718 device_type == SAS_FANOUT_EXPANDER_DEVICE)
719 mpi3mr_expander_remove(mrioc, sas_address, hba_port);
720 }
721
722 /**
723 * mpi3mr_del_phy_from_an_existing_port - del phy from a port
724 * @mrioc: Adapter instance reference
725 * @mr_sas_node: Internal sas node object (expander or host)
726 * @mr_sas_phy: Internal Phy object
727 *
728 * Return: None.
729 */
mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * mr_sas_node,struct mpi3mr_sas_phy * mr_sas_phy)730 static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
731 struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
732 {
733 struct mpi3mr_sas_port *mr_sas_port, *next;
734 struct mpi3mr_sas_phy *srch_phy;
735
736 if (mr_sas_phy->phy_belongs_to_port == 0)
737 return;
738
739 list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
740 port_list) {
741 list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
742 port_siblings) {
743 if (srch_phy != mr_sas_phy)
744 continue;
745 if ((mr_sas_port->num_phys == 1) &&
746 !mrioc->reset_in_progress)
747 mpi3mr_delete_sas_port(mrioc, mr_sas_port);
748 else
749 mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
750 mr_sas_phy, mr_sas_node->host_node);
751 return;
752 }
753 }
754 }
755
756 /**
757 * mpi3mr_sas_port_sanity_check - sanity check while adding port
758 * @mrioc: Adapter instance reference
759 * @mr_sas_node: Internal sas node object (expander or host)
760 * @sas_address: SAS address of device/expander
761 * @hba_port: HBA port entry
762 *
763 * Verifies whether the Phys attached to a device with the given
764 * SAS address already belongs to an existing sas port if so
765 * will remove those phys from the sas port
766 *
767 * Return: None.
768 */
mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * mr_sas_node,u64 sas_address,struct mpi3mr_hba_port * hba_port)769 static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
770 struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
771 struct mpi3mr_hba_port *hba_port)
772 {
773 int i;
774
775 for (i = 0; i < mr_sas_node->num_phys; i++) {
776 if ((mr_sas_node->phy[i].remote_identify.sas_address !=
777 sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
778 continue;
779 if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
780 mpi3mr_del_phy_from_an_existing_port(mrioc,
781 mr_sas_node, &mr_sas_node->phy[i]);
782 }
783 }
784
785 /**
786 * mpi3mr_set_identify - set identify for phys and end devices
787 * @mrioc: Adapter instance reference
788 * @handle: Firmware device handle
789 * @identify: SAS transport layer's identify info
790 *
791 * Populates sas identify info for a specific device.
792 *
793 * Return: 0 for success, non-zero for failure.
794 */
mpi3mr_set_identify(struct mpi3mr_ioc * mrioc,u16 handle,struct sas_identify * identify)795 static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
796 struct sas_identify *identify)
797 {
798
799 struct mpi3_device_page0 device_pg0;
800 struct mpi3_device0_sas_sata_format *sasinf;
801 u16 device_info;
802 u16 ioc_status;
803
804 if (mrioc->reset_in_progress) {
805 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
806 return -EFAULT;
807 }
808
809 if (mrioc->pci_err_recovery) {
810 ioc_err(mrioc, "%s: pci error recovery in progress!\n",
811 __func__);
812 return -EFAULT;
813 }
814
815 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
816 sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
817 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
818 return -ENXIO;
819 }
820
821 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
822 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
823 handle, ioc_status, __FILE__, __LINE__, __func__);
824 return -EIO;
825 }
826
827 memset(identify, 0, sizeof(struct sas_identify));
828 sasinf = &device_pg0.device_specific.sas_sata_format;
829 device_info = le16_to_cpu(sasinf->device_info);
830
831 /* sas_address */
832 identify->sas_address = le64_to_cpu(sasinf->sas_address);
833
834 /* phy number of the parent device this device is linked to */
835 identify->phy_identifier = sasinf->phy_num;
836
837 /* device_type */
838 switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
839 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
840 identify->device_type = SAS_PHY_UNUSED;
841 break;
842 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
843 identify->device_type = SAS_END_DEVICE;
844 break;
845 case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
846 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
847 break;
848 }
849
850 /* initiator_port_protocols */
851 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
852 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
853 /* MPI3.0 doesn't have define for SATA INIT so setting both here*/
854 if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
855 identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
856 SAS_PROTOCOL_SATA);
857 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
858 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
859
860 /* target_port_protocols */
861 if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
862 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
863 /* MPI3.0 doesn't have define for STP Target so setting both here*/
864 if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
865 identify->target_port_protocols |= (SAS_PROTOCOL_STP |
866 SAS_PROTOCOL_SATA);
867 if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
868 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
869 return 0;
870 }
871
872 /**
873 * mpi3mr_add_host_phy - report sas_host phy to SAS transport
874 * @mrioc: Adapter instance reference
875 * @mr_sas_phy: Internal Phy object
876 * @phy_pg0: SAS phy page 0
877 * @parent_dev: Prent device class object
878 *
879 * Return: 0 for success, non-zero for failure.
880 */
mpi3mr_add_host_phy(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_phy * mr_sas_phy,struct mpi3_sas_phy_page0 phy_pg0,struct device * parent_dev)881 static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
882 struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
883 struct device *parent_dev)
884 {
885 struct sas_phy *phy;
886 int phy_index = mr_sas_phy->phy_id;
887
888
889 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
890 phy = sas_phy_alloc(parent_dev, phy_index);
891 if (!phy) {
892 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
893 __FILE__, __LINE__, __func__);
894 return -1;
895 }
896 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
897 &mr_sas_phy->identify))) {
898 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
899 __FILE__, __LINE__, __func__);
900 sas_phy_free(phy);
901 return -1;
902 }
903 phy->identify = mr_sas_phy->identify;
904 mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
905 if (mr_sas_phy->attached_handle)
906 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
907 &mr_sas_phy->remote_identify);
908 phy->identify.phy_identifier = mr_sas_phy->phy_id;
909 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
910 (phy_pg0.negotiated_link_rate &
911 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
912 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
913 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
914 phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
915 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
916 phy_pg0.hw_link_rate >> 4);
917 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
918 phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
919 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
920 phy_pg0.programmed_link_rate >> 4);
921 phy->hostdata = mr_sas_phy->hba_port;
922
923 if ((sas_phy_add(phy))) {
924 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
925 __FILE__, __LINE__, __func__);
926 sas_phy_free(phy);
927 return -1;
928 }
929 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
930 dev_info(&phy->dev,
931 "add: handle(0x%04x), sas_address(0x%016llx)\n"
932 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
933 mr_sas_phy->handle, (unsigned long long)
934 mr_sas_phy->identify.sas_address,
935 mr_sas_phy->attached_handle,
936 (unsigned long long)
937 mr_sas_phy->remote_identify.sas_address);
938 mr_sas_phy->phy = phy;
939 return 0;
940 }
941
942 /**
943 * mpi3mr_add_expander_phy - report expander phy to transport
944 * @mrioc: Adapter instance reference
945 * @mr_sas_phy: Internal Phy object
946 * @expander_pg1: SAS Expander page 1
947 * @parent_dev: Parent device class object
948 *
949 * Return: 0 for success, non-zero for failure.
950 */
mpi3mr_add_expander_phy(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_phy * mr_sas_phy,struct mpi3_sas_expander_page1 expander_pg1,struct device * parent_dev)951 static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
952 struct mpi3mr_sas_phy *mr_sas_phy,
953 struct mpi3_sas_expander_page1 expander_pg1,
954 struct device *parent_dev)
955 {
956 struct sas_phy *phy;
957 int phy_index = mr_sas_phy->phy_id;
958
959 INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
960 phy = sas_phy_alloc(parent_dev, phy_index);
961 if (!phy) {
962 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
963 __FILE__, __LINE__, __func__);
964 return -1;
965 }
966 if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
967 &mr_sas_phy->identify))) {
968 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
969 __FILE__, __LINE__, __func__);
970 sas_phy_free(phy);
971 return -1;
972 }
973 phy->identify = mr_sas_phy->identify;
974 mr_sas_phy->attached_handle =
975 le16_to_cpu(expander_pg1.attached_dev_handle);
976 if (mr_sas_phy->attached_handle)
977 mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
978 &mr_sas_phy->remote_identify);
979 phy->identify.phy_identifier = mr_sas_phy->phy_id;
980 phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
981 (expander_pg1.negotiated_link_rate &
982 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
983 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
984 phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
985 expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
986 phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
987 expander_pg1.hw_link_rate >> 4);
988 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
989 expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
990 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
991 expander_pg1.programmed_link_rate >> 4);
992 phy->hostdata = mr_sas_phy->hba_port;
993
994 if ((sas_phy_add(phy))) {
995 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
996 __FILE__, __LINE__, __func__);
997 sas_phy_free(phy);
998 return -1;
999 }
1000 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1001 dev_info(&phy->dev,
1002 "add: handle(0x%04x), sas_address(0x%016llx)\n"
1003 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1004 mr_sas_phy->handle, (unsigned long long)
1005 mr_sas_phy->identify.sas_address,
1006 mr_sas_phy->attached_handle,
1007 (unsigned long long)
1008 mr_sas_phy->remote_identify.sas_address);
1009 mr_sas_phy->phy = phy;
1010 return 0;
1011 }
1012
1013 /**
1014 * mpi3mr_alloc_hba_port - alloc hba port object
1015 * @mrioc: Adapter instance reference
1016 * @port_id: Port number
1017 *
1018 * Alloc memory for hba port object.
1019 */
1020 static struct mpi3mr_hba_port *
mpi3mr_alloc_hba_port(struct mpi3mr_ioc * mrioc,u16 port_id)1021 mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
1022 {
1023 struct mpi3mr_hba_port *hba_port;
1024
1025 hba_port = kzalloc_obj(struct mpi3mr_hba_port);
1026 if (!hba_port)
1027 return NULL;
1028 hba_port->port_id = port_id;
1029 ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
1030 hba_port, hba_port->port_id);
1031 if (mrioc->reset_in_progress ||
1032 mrioc->pci_err_recovery)
1033 hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;
1034 list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
1035 return hba_port;
1036 }
1037
1038 /**
1039 * mpi3mr_get_hba_port_by_id - find hba port by id
1040 * @mrioc: Adapter instance reference
1041 * @port_id: Port ID to search
1042 *
1043 * Return: mpi3mr_hba_port reference for the matched port
1044 */
1045
mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc * mrioc,u8 port_id)1046 struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
1047 u8 port_id)
1048 {
1049 struct mpi3mr_hba_port *port, *port_next;
1050
1051 list_for_each_entry_safe(port, port_next,
1052 &mrioc->hba_port_table_list, list) {
1053 if (port->port_id != port_id)
1054 continue;
1055 if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)
1056 continue;
1057 return port;
1058 }
1059
1060 return NULL;
1061 }
1062
1063 /**
1064 * mpi3mr_update_links - refreshing SAS phy link changes
1065 * @mrioc: Adapter instance reference
1066 * @sas_address_parent: SAS address of parent expander or host
1067 * @handle: Firmware device handle of attached device
1068 * @phy_number: Phy number
1069 * @link_rate: New link rate
1070 * @hba_port: HBA port entry
1071 *
1072 * Return: None.
1073 */
mpi3mr_update_links(struct mpi3mr_ioc * mrioc,u64 sas_address_parent,u16 handle,u8 phy_number,u8 link_rate,struct mpi3mr_hba_port * hba_port)1074 void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
1075 u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
1076 struct mpi3mr_hba_port *hba_port)
1077 {
1078 unsigned long flags;
1079 struct mpi3mr_sas_node *mr_sas_node;
1080 struct mpi3mr_sas_phy *mr_sas_phy;
1081
1082 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
1083 return;
1084
1085 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1086 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1087 sas_address_parent, hba_port);
1088 if (!mr_sas_node) {
1089 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1090 return;
1091 }
1092
1093 mr_sas_phy = &mr_sas_node->phy[phy_number];
1094 mr_sas_phy->attached_handle = handle;
1095 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1096 if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {
1097 mpi3mr_set_identify(mrioc, handle,
1098 &mr_sas_phy->remote_identify);
1099 mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,
1100 mr_sas_phy, mr_sas_phy->remote_identify.sas_address,
1101 hba_port);
1102 } else
1103 memset(&mr_sas_phy->remote_identify, 0, sizeof(struct
1104 sas_identify));
1105
1106 if (mr_sas_phy->phy)
1107 mr_sas_phy->phy->negotiated_linkrate =
1108 mpi3mr_convert_phy_link_rate(link_rate);
1109
1110 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1111 dev_info(&mr_sas_phy->phy->dev,
1112 "refresh: parent sas_address(0x%016llx),\n"
1113 "\tlink_rate(0x%02x), phy(%d)\n"
1114 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1115 (unsigned long long)sas_address_parent,
1116 link_rate, phy_number, handle, (unsigned long long)
1117 mr_sas_phy->remote_identify.sas_address);
1118 }
1119
1120 /**
1121 * mpi3mr_sas_host_refresh - refreshing sas host object contents
1122 * @mrioc: Adapter instance reference
1123 *
1124 * This function refreshes the controllers phy information and
1125 * updates the SAS transport layer with updated information,
1126 * this is executed for each device addition or device info
1127 * change events
1128 *
1129 * Return: None.
1130 */
mpi3mr_sas_host_refresh(struct mpi3mr_ioc * mrioc)1131 void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
1132 {
1133 int i;
1134 u8 link_rate;
1135 u16 sz, port_id, attached_handle;
1136 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1137
1138 dprint_transport_info(mrioc,
1139 "updating handles for sas_host(0x%016llx)\n",
1140 (unsigned long long)mrioc->sas_hba.sas_address);
1141
1142 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1143 (mrioc->sas_hba.num_phys *
1144 sizeof(struct mpi3_sas_io_unit0_phy_data));
1145 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1146 if (!sas_io_unit_pg0)
1147 return;
1148 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1149 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1150 __FILE__, __LINE__, __func__);
1151 goto out;
1152 }
1153
1154 mrioc->sas_hba.handle = 0;
1155 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1156 if (sas_io_unit_pg0->phy_data[i].phy_flags &
1157 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1158 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1159 continue;
1160 link_rate =
1161 sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;
1162 if (!mrioc->sas_hba.handle)
1163 mrioc->sas_hba.handle = le16_to_cpu(
1164 sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1165 port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1166 if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1167 if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1168 goto out;
1169
1170 mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1171 attached_handle = le16_to_cpu(
1172 sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1173 if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
1174 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
1175 mrioc->sas_hba.phy[i].hba_port =
1176 mpi3mr_get_hba_port_by_id(mrioc, port_id);
1177 mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,
1178 attached_handle, i, link_rate,
1179 mrioc->sas_hba.phy[i].hba_port);
1180 }
1181 out:
1182 kfree(sas_io_unit_pg0);
1183 }
1184
1185 /**
1186 * mpi3mr_sas_host_add - create sas host object
1187 * @mrioc: Adapter instance reference
1188 *
1189 * This function creates the controllers phy information and
1190 * updates the SAS transport layer with updated information,
1191 * this is executed for first device addition or device info
1192 * change event.
1193 *
1194 * Return: None.
1195 */
mpi3mr_sas_host_add(struct mpi3mr_ioc * mrioc)1196 void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
1197 {
1198 int i;
1199 u16 sz, num_phys = 1, port_id, ioc_status;
1200 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1201 struct mpi3_sas_phy_page0 phy_pg0;
1202 struct mpi3_device_page0 dev_pg0;
1203 struct mpi3_enclosure_page0 encl_pg0;
1204 struct mpi3_device0_sas_sata_format *sasinf;
1205
1206 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1207 (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1208 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1209 if (!sas_io_unit_pg0)
1210 return;
1211
1212 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1213 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1214 __FILE__, __LINE__, __func__);
1215 goto out;
1216 }
1217 num_phys = sas_io_unit_pg0->num_phys;
1218 kfree(sas_io_unit_pg0);
1219
1220 mrioc->sas_hba.host_node = 1;
1221 INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
1222 mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
1223 mrioc->sas_hba.phy = kzalloc_objs(struct mpi3mr_sas_phy, num_phys);
1224 if (!mrioc->sas_hba.phy)
1225 return;
1226
1227 mrioc->sas_hba.num_phys = num_phys;
1228
1229 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1230 (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1231 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1232 if (!sas_io_unit_pg0)
1233 return;
1234
1235 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1236 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1237 __FILE__, __LINE__, __func__);
1238 goto out;
1239 }
1240
1241 mrioc->sas_hba.handle = 0;
1242 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1243 if (sas_io_unit_pg0->phy_data[i].phy_flags &
1244 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1245 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1246 continue;
1247 if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
1248 sizeof(struct mpi3_sas_phy_page0),
1249 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
1250 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1251 __FILE__, __LINE__, __func__);
1252 goto out;
1253 }
1254 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1255 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1256 __FILE__, __LINE__, __func__);
1257 goto out;
1258 }
1259
1260 if (!mrioc->sas_hba.handle)
1261 mrioc->sas_hba.handle = le16_to_cpu(
1262 sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1263 port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1264
1265 if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1266 if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1267 goto out;
1268
1269 mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1270 mrioc->sas_hba.phy[i].phy_id = i;
1271 mrioc->sas_hba.phy[i].hba_port =
1272 mpi3mr_get_hba_port_by_id(mrioc, port_id);
1273 mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
1274 phy_pg0, mrioc->sas_hba.parent_dev);
1275 }
1276 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1277 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1278 mrioc->sas_hba.handle))) {
1279 ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
1280 goto out;
1281 }
1282 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1283 ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
1284 mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
1285 __func__);
1286 goto out;
1287 }
1288 mrioc->sas_hba.enclosure_handle =
1289 le16_to_cpu(dev_pg0.enclosure_handle);
1290 sasinf = &dev_pg0.device_specific.sas_sata_format;
1291 mrioc->sas_hba.sas_address =
1292 le64_to_cpu(sasinf->sas_address);
1293 ioc_info(mrioc,
1294 "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
1295 mrioc->sas_hba.handle,
1296 (unsigned long long) mrioc->sas_hba.sas_address,
1297 mrioc->sas_hba.num_phys);
1298
1299 if (mrioc->sas_hba.enclosure_handle) {
1300 if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,
1301 &encl_pg0, sizeof(encl_pg0),
1302 MPI3_ENCLOS_PGAD_FORM_HANDLE,
1303 mrioc->sas_hba.enclosure_handle)) &&
1304 (ioc_status == MPI3_IOCSTATUS_SUCCESS))
1305 mrioc->sas_hba.enclosure_logical_id =
1306 le64_to_cpu(encl_pg0.enclosure_logical_id);
1307 }
1308
1309 out:
1310 kfree(sas_io_unit_pg0);
1311 }
1312
1313 /**
1314 * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL
1315 * @mrioc: Adapter instance reference
1316 * @handle: Firmware device handle of the attached device
1317 * @sas_address_parent: sas address of parent expander or host
1318 * @hba_port: HBA port entry
1319 *
1320 * This function creates a new sas port object for the given end
1321 * device matching sas address and hba_port and adds it to the
1322 * sas_node's sas_port_list and expose the attached sas device
1323 * to the SAS transport layer through sas_rphy_add.
1324 *
1325 * Returns a valid mpi3mr_sas_port reference or NULL.
1326 */
mpi3mr_sas_port_add(struct mpi3mr_ioc * mrioc,u16 handle,u64 sas_address_parent,struct mpi3mr_hba_port * hba_port)1327 static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
1328 u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1329 {
1330 struct mpi3mr_sas_phy *mr_sas_phy, *next;
1331 struct mpi3mr_sas_port *mr_sas_port;
1332 unsigned long flags;
1333 struct mpi3mr_sas_node *mr_sas_node;
1334 struct sas_rphy *rphy;
1335 struct mpi3mr_tgt_dev *tgtdev = NULL;
1336 int i;
1337 struct sas_port *port;
1338
1339 if (!hba_port) {
1340 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1341 __FILE__, __LINE__, __func__);
1342 return NULL;
1343 }
1344
1345 mr_sas_port = kzalloc_obj(struct mpi3mr_sas_port);
1346 if (!mr_sas_port)
1347 return NULL;
1348
1349 INIT_LIST_HEAD(&mr_sas_port->port_list);
1350 INIT_LIST_HEAD(&mr_sas_port->phy_list);
1351 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1352 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1353 sas_address_parent, hba_port);
1354 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1355
1356 if (!mr_sas_node) {
1357 ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n",
1358 __func__, (unsigned long long)sas_address_parent);
1359 goto out_fail;
1360 }
1361
1362 if ((mpi3mr_set_identify(mrioc, handle,
1363 &mr_sas_port->remote_identify))) {
1364 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1365 __FILE__, __LINE__, __func__);
1366 goto out_fail;
1367 }
1368
1369 if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
1370 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1371 __FILE__, __LINE__, __func__);
1372 goto out_fail;
1373 }
1374
1375 mr_sas_port->hba_port = hba_port;
1376 mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,
1377 mr_sas_port->remote_identify.sas_address, hba_port);
1378
1379 if (mr_sas_node->host_node && mr_sas_node->num_phys >=
1380 sizeof(mr_sas_port->phy_mask) * 8)
1381 ioc_info(mrioc, "max port count %u could be too high\n",
1382 mr_sas_node->num_phys);
1383
1384 for (i = 0; i < mr_sas_node->num_phys; i++) {
1385 if ((mr_sas_node->phy[i].remote_identify.sas_address !=
1386 mr_sas_port->remote_identify.sas_address) ||
1387 (mr_sas_node->phy[i].hba_port != hba_port))
1388 continue;
1389
1390 if (mr_sas_node->host_node && (i >= sizeof(mr_sas_port->phy_mask) * 8)) {
1391 ioc_warn(mrioc, "skipping port %u, max allowed value is %zu\n",
1392 i, sizeof(mr_sas_port->phy_mask) * 8);
1393 goto out_fail;
1394 }
1395 list_add_tail(&mr_sas_node->phy[i].port_siblings,
1396 &mr_sas_port->phy_list);
1397 mr_sas_port->num_phys++;
1398 if (mr_sas_node->host_node)
1399 mr_sas_port->phy_mask |= (1 << i);
1400 }
1401
1402 if (!mr_sas_port->num_phys) {
1403 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1404 __FILE__, __LINE__, __func__);
1405 goto out_fail;
1406 }
1407
1408 if (mr_sas_node->host_node)
1409 mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
1410
1411 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1412 tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
1413 mr_sas_port->remote_identify.sas_address,
1414 mr_sas_port->hba_port);
1415
1416 if (!tgtdev) {
1417 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1418 __FILE__, __LINE__, __func__);
1419 goto out_fail;
1420 }
1421 tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;
1422 }
1423
1424 if (!mr_sas_node->parent_dev) {
1425 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1426 __FILE__, __LINE__, __func__);
1427 goto out_fail;
1428 }
1429
1430 port = sas_port_alloc_num(mr_sas_node->parent_dev);
1431 if (!port) {
1432 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1433 __FILE__, __LINE__, __func__);
1434 goto out_fail;
1435 }
1436 if ((sas_port_add(port))) {
1437 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1438 __FILE__, __LINE__, __func__);
1439 sas_port_free(port);
1440 goto out_fail;
1441 }
1442
1443 list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,
1444 port_siblings) {
1445 if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1446 dev_info(&port->dev,
1447 "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
1448 handle, (unsigned long long)
1449 mr_sas_port->remote_identify.sas_address,
1450 mr_sas_phy->phy_id);
1451 sas_port_add_phy(port, mr_sas_phy->phy);
1452 mr_sas_phy->phy_belongs_to_port = 1;
1453 mr_sas_phy->hba_port = hba_port;
1454 }
1455
1456 mr_sas_port->port = port;
1457 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1458 rphy = sas_end_device_alloc(port);
1459 tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
1460 } else {
1461 rphy = sas_expander_alloc(port,
1462 mr_sas_port->remote_identify.device_type);
1463 }
1464 rphy->identify = mr_sas_port->remote_identify;
1465
1466 if (mrioc->current_event)
1467 mrioc->current_event->pending_at_sml = 1;
1468
1469 if ((sas_rphy_add(rphy))) {
1470 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1471 __FILE__, __LINE__, __func__);
1472 }
1473 if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1474 tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
1475 tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;
1476 mpi3mr_tgtdev_put(tgtdev);
1477 }
1478
1479 dev_info(&rphy->dev,
1480 "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",
1481 __func__, handle, (unsigned long long)
1482 mr_sas_port->remote_identify.sas_address);
1483
1484 mr_sas_port->rphy = rphy;
1485 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1486 list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
1487 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1488
1489 if (mrioc->current_event) {
1490 mrioc->current_event->pending_at_sml = 0;
1491 if (mrioc->current_event->discard)
1492 mpi3mr_print_device_event_notice(mrioc, true);
1493 }
1494
1495 /* fill in report manufacture */
1496 if (mr_sas_port->remote_identify.device_type ==
1497 SAS_EDGE_EXPANDER_DEVICE ||
1498 mr_sas_port->remote_identify.device_type ==
1499 SAS_FANOUT_EXPANDER_DEVICE)
1500 mpi3mr_report_manufacture(mrioc,
1501 mr_sas_port->remote_identify.sas_address,
1502 rphy_to_expander_device(rphy), hba_port->port_id);
1503
1504 return mr_sas_port;
1505
1506 out_fail:
1507 list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
1508 port_siblings)
1509 list_del(&mr_sas_phy->port_siblings);
1510 if (tgtdev)
1511 mpi3mr_tgtdev_put(tgtdev);
1512 kfree(mr_sas_port);
1513 return NULL;
1514 }
1515
1516 /**
1517 * mpi3mr_sas_port_remove - remove port from the list
1518 * @mrioc: Adapter instance reference
1519 * @sas_address: SAS address of attached device
1520 * @sas_address_parent: SAS address of parent expander or host
1521 * @hba_port: HBA port entry
1522 *
1523 * Removing object and freeing associated memory from the
1524 * sas_port_list.
1525 *
1526 * Return: None
1527 */
mpi3mr_sas_port_remove(struct mpi3mr_ioc * mrioc,u64 sas_address,u64 sas_address_parent,struct mpi3mr_hba_port * hba_port)1528 static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
1529 u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1530 {
1531 int i;
1532 unsigned long flags;
1533 struct mpi3mr_sas_port *mr_sas_port, *next;
1534 struct mpi3mr_sas_node *mr_sas_node;
1535 u8 found = 0;
1536 struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;
1537 struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
1538
1539 if (!hba_port)
1540 return;
1541
1542 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1543 mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1544 sas_address_parent, hba_port);
1545 if (!mr_sas_node) {
1546 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1547 return;
1548 }
1549 list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
1550 port_list) {
1551 if (mr_sas_port->remote_identify.sas_address != sas_address)
1552 continue;
1553 if (mr_sas_port->hba_port != hba_port)
1554 continue;
1555 found = 1;
1556 list_del(&mr_sas_port->port_list);
1557 goto out;
1558 }
1559
1560 out:
1561 if (!found) {
1562 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1563 return;
1564 }
1565
1566 if (mr_sas_node->host_node) {
1567 list_for_each_entry_safe(srch_port, hba_port_next,
1568 &mrioc->hba_port_table_list, list) {
1569 if (srch_port != hba_port)
1570 continue;
1571 ioc_info(mrioc,
1572 "removing hba_port entry: %p port: %d from hba_port list\n",
1573 srch_port, srch_port->port_id);
1574 list_del(&hba_port->list);
1575 kfree(hba_port);
1576 break;
1577 }
1578 }
1579
1580 for (i = 0; i < mr_sas_node->num_phys; i++) {
1581 if (mr_sas_node->phy[i].remote_identify.sas_address ==
1582 sas_address)
1583 memset(&mr_sas_node->phy[i].remote_identify, 0,
1584 sizeof(struct sas_identify));
1585 }
1586
1587 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1588
1589 if (mrioc->current_event)
1590 mrioc->current_event->pending_at_sml = 1;
1591
1592 list_for_each_entry_safe(mr_sas_phy, next_phy,
1593 &mr_sas_port->phy_list, port_siblings) {
1594 if ((!mrioc->stop_drv_processing) &&
1595 (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1596 dev_info(&mr_sas_port->port->dev,
1597 "remove: sas_address(0x%016llx), phy(%d)\n",
1598 (unsigned long long)
1599 mr_sas_port->remote_identify.sas_address,
1600 mr_sas_phy->phy_id);
1601 mr_sas_phy->phy_belongs_to_port = 0;
1602 if (!mrioc->stop_drv_processing)
1603 sas_port_delete_phy(mr_sas_port->port,
1604 mr_sas_phy->phy);
1605 list_del(&mr_sas_phy->port_siblings);
1606 }
1607 if (!mrioc->stop_drv_processing)
1608 sas_port_delete(mr_sas_port->port);
1609 ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
1610 __func__, (unsigned long long)sas_address);
1611
1612 if (mrioc->current_event) {
1613 mrioc->current_event->pending_at_sml = 0;
1614 if (mrioc->current_event->discard)
1615 mpi3mr_print_device_event_notice(mrioc, false);
1616 }
1617
1618 kfree(mr_sas_port);
1619 }
1620
1621 /**
1622 * struct host_port - host port details
1623 * @sas_address: SAS Address of the attached device
1624 * @phy_mask: phy mask of host port
1625 * @handle: Device Handle of attached device
1626 * @iounit_port_id: port ID
1627 * @used: host port is already matched with sas port from sas_port_list
1628 * @lowest_phy: lowest phy ID of host port
1629 */
1630 struct host_port {
1631 u64 sas_address;
1632 u64 phy_mask;
1633 u16 handle;
1634 u8 iounit_port_id;
1635 u8 used;
1636 u8 lowest_phy;
1637 };
1638
1639 /**
1640 * mpi3mr_update_mr_sas_port - update sas port objects during reset
1641 * @mrioc: Adapter instance reference
1642 * @h_port: host_port object
1643 * @mr_sas_port: sas_port objects which needs to be updated
1644 *
1645 * Update the port ID of sas port object. Also add the phys if new phys got
1646 * added to current sas port and remove the phys if some phys are moved
1647 * out of the current sas port.
1648 *
1649 * Return: Nothing.
1650 */
1651 static void
mpi3mr_update_mr_sas_port(struct mpi3mr_ioc * mrioc,struct host_port * h_port,struct mpi3mr_sas_port * mr_sas_port)1652 mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
1653 struct mpi3mr_sas_port *mr_sas_port)
1654 {
1655 struct mpi3mr_sas_phy *mr_sas_phy;
1656 u64 phy_mask_xor;
1657 u64 phys_to_be_added, phys_to_be_removed;
1658 int i;
1659
1660 h_port->used = 1;
1661 mr_sas_port->marked_responding = 1;
1662
1663 dev_info(&mr_sas_port->port->dev,
1664 "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n",
1665 mr_sas_port->remote_identify.sas_address,
1666 mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
1667 h_port->iounit_port_id, h_port->phy_mask);
1668
1669 mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
1670 mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
1671
1672 /* Get the newly added phys bit map & removed phys bit map */
1673 phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
1674 phys_to_be_added = h_port->phy_mask & phy_mask_xor;
1675 phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
1676
1677 /*
1678 * Register these new phys to current mr_sas_port's port.
1679 * if these phys are previously registered with another port
1680 * then delete these phys from that port first.
1681 */
1682 for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {
1683 mr_sas_phy = &mrioc->sas_hba.phy[i];
1684 if (mr_sas_phy->phy_belongs_to_port)
1685 mpi3mr_del_phy_from_an_existing_port(mrioc,
1686 &mrioc->sas_hba, mr_sas_phy);
1687 mpi3mr_add_phy_to_an_existing_port(mrioc,
1688 &mrioc->sas_hba, mr_sas_phy,
1689 mr_sas_port->remote_identify.sas_address,
1690 mr_sas_port->hba_port);
1691 }
1692
1693 /* Delete the phys which are not part of current mr_sas_port's port. */
1694 for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {
1695 mr_sas_phy = &mrioc->sas_hba.phy[i];
1696 if (mr_sas_phy->phy_belongs_to_port)
1697 mpi3mr_del_phy_from_an_existing_port(mrioc,
1698 &mrioc->sas_hba, mr_sas_phy);
1699 }
1700 }
1701
1702 /**
1703 * mpi3mr_refresh_sas_ports - update host's sas ports during reset
1704 * @mrioc: Adapter instance reference
1705 *
1706 * Update the host's sas ports during reset by checking whether
1707 * sas ports are still intact or not. Add/remove phys if any hba
1708 * phys are (moved in)/(moved out) of sas port. Also update
1709 * io_unit_port if it got changed during reset.
1710 *
1711 * Return: Nothing.
1712 */
1713 void
mpi3mr_refresh_sas_ports(struct mpi3mr_ioc * mrioc)1714 mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
1715 {
1716 struct host_port *h_port = NULL;
1717 int i, j, found, host_port_count = 0, port_idx;
1718 u16 sz, attached_handle, ioc_status;
1719 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1720 struct mpi3_device_page0 dev_pg0;
1721 struct mpi3_device0_sas_sata_format *sasinf;
1722 struct mpi3mr_sas_port *mr_sas_port;
1723
1724 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1725 (mrioc->sas_hba.num_phys *
1726 sizeof(struct mpi3_sas_io_unit0_phy_data));
1727 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1728 if (!sas_io_unit_pg0)
1729 return;
1730 h_port = kzalloc_objs(struct host_port, 64);
1731 if (!h_port)
1732 goto out;
1733
1734 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1735 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1736 __FILE__, __LINE__, __func__);
1737 goto out;
1738 }
1739
1740 /* Create a new expander port table */
1741 for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1742 attached_handle = le16_to_cpu(
1743 sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1744 if (!attached_handle)
1745 continue;
1746 found = 0;
1747 for (j = 0; j < host_port_count; j++) {
1748 if (h_port[j].handle == attached_handle) {
1749 h_port[j].phy_mask |= (1 << i);
1750 found = 1;
1751 break;
1752 }
1753 }
1754 if (found)
1755 continue;
1756 if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1757 sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1758 attached_handle))) {
1759 dprint_reset(mrioc,
1760 "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1761 attached_handle, __FILE__, __LINE__, __func__);
1762 continue;
1763 }
1764 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1765 dprint_reset(mrioc,
1766 "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1767 ioc_status, attached_handle,
1768 __FILE__, __LINE__, __func__);
1769 continue;
1770 }
1771 sasinf = &dev_pg0.device_specific.sas_sata_format;
1772
1773 port_idx = host_port_count;
1774 h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
1775 h_port[port_idx].handle = attached_handle;
1776 h_port[port_idx].phy_mask = (1 << i);
1777 h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1778 h_port[port_idx].lowest_phy = sasinf->phy_num;
1779 h_port[port_idx].used = 0;
1780 host_port_count++;
1781 }
1782
1783 if (!host_port_count)
1784 goto out;
1785
1786 if (mrioc->logging_level & MPI3_DEBUG_RESET) {
1787 ioc_info(mrioc, "Host port details before reset\n");
1788 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1789 port_list) {
1790 ioc_info(mrioc,
1791 "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1792 mr_sas_port->hba_port->port_id,
1793 mr_sas_port->remote_identify.sas_address,
1794 mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
1795 }
1796 mr_sas_port = NULL;
1797 ioc_info(mrioc, "Host port details after reset\n");
1798 for (i = 0; i < host_port_count; i++) {
1799 ioc_info(mrioc,
1800 "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1801 h_port[i].iounit_port_id, h_port[i].sas_address,
1802 h_port[i].phy_mask, h_port[i].lowest_phy);
1803 }
1804 }
1805
1806 /* mark all host sas port entries as dirty */
1807 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1808 port_list) {
1809 mr_sas_port->marked_responding = 0;
1810 mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
1811 }
1812
1813 /* First check for matching lowest phy */
1814 for (i = 0; i < host_port_count; i++) {
1815 mr_sas_port = NULL;
1816 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1817 port_list) {
1818 if (mr_sas_port->marked_responding)
1819 continue;
1820 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1821 continue;
1822 if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
1823 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1824 break;
1825 }
1826 }
1827 }
1828
1829 /* In case if lowest phy is got enabled or disabled during reset */
1830 for (i = 0; i < host_port_count; i++) {
1831 if (h_port[i].used)
1832 continue;
1833 mr_sas_port = NULL;
1834 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1835 port_list) {
1836 if (mr_sas_port->marked_responding)
1837 continue;
1838 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1839 continue;
1840 if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
1841 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1842 break;
1843 }
1844 }
1845 }
1846
1847 /* In case if expander cable is removed & connected to another HBA port during reset */
1848 for (i = 0; i < host_port_count; i++) {
1849 if (h_port[i].used)
1850 continue;
1851 mr_sas_port = NULL;
1852 list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1853 port_list) {
1854 if (mr_sas_port->marked_responding)
1855 continue;
1856 if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1857 continue;
1858 mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1859 break;
1860 }
1861 }
1862 out:
1863 kfree(h_port);
1864 kfree(sas_io_unit_pg0);
1865 }
1866
1867 /**
1868 * mpi3mr_refresh_expanders - Refresh expander device exposure
1869 * @mrioc: Adapter instance reference
1870 *
1871 * This is executed post controller reset to identify any
1872 * missing expander devices during reset and remove from the upper layers
1873 * or expose any newly detected expander device to the upper layers.
1874 *
1875 * Return: Nothing.
1876 */
1877 void
mpi3mr_refresh_expanders(struct mpi3mr_ioc * mrioc)1878 mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
1879 {
1880 struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
1881 struct mpi3_sas_expander_page0 expander_pg0;
1882 u16 ioc_status, handle;
1883 u64 sas_address;
1884 int i;
1885 unsigned long flags;
1886 struct mpi3mr_hba_port *hba_port;
1887
1888 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1889 list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
1890 sas_expander->non_responding = 1;
1891 }
1892 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1893
1894 sas_expander = NULL;
1895
1896 handle = 0xffff;
1897
1898 /* Search for responding expander devices and add them if they are newly got added */
1899 while (true) {
1900 if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1901 sizeof(struct mpi3_sas_expander_page0),
1902 MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1903 dprint_reset(mrioc,
1904 "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1905 handle, __FILE__, __LINE__, __func__);
1906 break;
1907 }
1908
1909 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1910 dprint_reset(mrioc,
1911 "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
1912 ioc_status, handle, __FILE__, __LINE__, __func__);
1913 break;
1914 }
1915
1916 handle = le16_to_cpu(expander_pg0.dev_handle);
1917 sas_address = le64_to_cpu(expander_pg0.sas_address);
1918 hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
1919
1920 if (!hba_port) {
1921 mpi3mr_sas_host_refresh(mrioc);
1922 mpi3mr_expander_add(mrioc, handle);
1923 continue;
1924 }
1925
1926 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1927 sas_expander =
1928 mpi3mr_expander_find_by_sas_address(mrioc,
1929 sas_address, hba_port);
1930 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1931
1932 if (!sas_expander) {
1933 mpi3mr_sas_host_refresh(mrioc);
1934 mpi3mr_expander_add(mrioc, handle);
1935 continue;
1936 }
1937
1938 sas_expander->non_responding = 0;
1939 if (sas_expander->handle == handle)
1940 continue;
1941
1942 sas_expander->handle = handle;
1943 for (i = 0 ; i < sas_expander->num_phys ; i++)
1944 sas_expander->phy[i].handle = handle;
1945 }
1946
1947 /*
1948 * Delete non responding expander devices and the corresponding
1949 * hba_port if the non responding expander device's parent device
1950 * is a host node.
1951 */
1952 sas_expander = NULL;
1953 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1954 list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
1955 &mrioc->sas_expander_list, list) {
1956 if (sas_expander->non_responding) {
1957 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1958 mpi3mr_expander_node_remove(mrioc, sas_expander);
1959 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1960 }
1961 }
1962 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1963 }
1964
1965 /**
1966 * mpi3mr_expander_node_add - insert an expander to the list.
1967 * @mrioc: Adapter instance reference
1968 * @sas_expander: Expander sas node
1969 * Context: This function will acquire sas_node_lock.
1970 *
1971 * Adding new object to the ioc->sas_expander_list.
1972 *
1973 * Return: None.
1974 */
mpi3mr_expander_node_add(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * sas_expander)1975 static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,
1976 struct mpi3mr_sas_node *sas_expander)
1977 {
1978 unsigned long flags;
1979
1980 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1981 list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);
1982 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1983 }
1984
1985 /**
1986 * mpi3mr_expander_add - Create expander object
1987 * @mrioc: Adapter instance reference
1988 * @handle: Expander firmware device handle
1989 *
1990 * This function creating expander object, stored in
1991 * sas_expander_list and expose it to the SAS transport
1992 * layer.
1993 *
1994 * Return: 0 for success, non-zero for failure.
1995 */
mpi3mr_expander_add(struct mpi3mr_ioc * mrioc,u16 handle)1996 int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
1997 {
1998 struct mpi3mr_sas_node *sas_expander;
1999 struct mpi3mr_enclosure_node *enclosure_dev;
2000 struct mpi3_sas_expander_page0 expander_pg0;
2001 struct mpi3_sas_expander_page1 expander_pg1;
2002 u16 ioc_status, parent_handle, temp_handle;
2003 u64 sas_address, sas_address_parent = 0;
2004 int i;
2005 unsigned long flags;
2006 u8 port_id, link_rate;
2007 struct mpi3mr_sas_port *mr_sas_port = NULL;
2008 struct mpi3mr_hba_port *hba_port;
2009 u32 phynum_handle;
2010 int rc = 0;
2011
2012 if (!handle)
2013 return -1;
2014
2015 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2016 return -1;
2017
2018 if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
2019 sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {
2020 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2021 __FILE__, __LINE__, __func__);
2022 return -1;
2023 }
2024
2025 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2026 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2027 __FILE__, __LINE__, __func__);
2028 return -1;
2029 }
2030
2031 parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);
2032 if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)
2033 != 0) {
2034 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2035 __FILE__, __LINE__, __func__);
2036 return -1;
2037 }
2038
2039 port_id = expander_pg0.io_unit_port;
2040 hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2041 if (!hba_port) {
2042 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2043 __FILE__, __LINE__, __func__);
2044 return -1;
2045 }
2046
2047 if (sas_address_parent != mrioc->sas_hba.sas_address) {
2048 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2049 sas_expander =
2050 mpi3mr_expander_find_by_sas_address(mrioc,
2051 sas_address_parent, hba_port);
2052 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2053 if (!sas_expander) {
2054 rc = mpi3mr_expander_add(mrioc, parent_handle);
2055 if (rc != 0)
2056 return rc;
2057 } else {
2058 /*
2059 * When there is a parent expander present, update it's
2060 * phys where child expander is connected with the link
2061 * speed, attached dev handle and sas address.
2062 */
2063 for (i = 0 ; i < sas_expander->num_phys ; i++) {
2064 phynum_handle =
2065 (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2066 parent_handle;
2067 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,
2068 &ioc_status, &expander_pg1,
2069 sizeof(expander_pg1),
2070 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2071 phynum_handle)) {
2072 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2073 __FILE__, __LINE__, __func__);
2074 rc = -1;
2075 return rc;
2076 }
2077 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2078 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2079 __FILE__, __LINE__, __func__);
2080 rc = -1;
2081 return rc;
2082 }
2083 temp_handle = le16_to_cpu(
2084 expander_pg1.attached_dev_handle);
2085 if (temp_handle != handle)
2086 continue;
2087 link_rate = (expander_pg1.negotiated_link_rate &
2088 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2089 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2090 if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
2091 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
2092 mpi3mr_update_links(mrioc, sas_address_parent,
2093 handle, i, link_rate, hba_port);
2094 }
2095 }
2096 }
2097
2098 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2099 sas_address = le64_to_cpu(expander_pg0.sas_address);
2100 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2101 sas_address, hba_port);
2102 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2103
2104 if (sas_expander)
2105 return 0;
2106
2107 sas_expander = kzalloc_obj(struct mpi3mr_sas_node);
2108 if (!sas_expander)
2109 return -ENOMEM;
2110
2111 sas_expander->handle = handle;
2112 sas_expander->num_phys = expander_pg0.num_phys;
2113 sas_expander->sas_address_parent = sas_address_parent;
2114 sas_expander->sas_address = sas_address;
2115 sas_expander->hba_port = hba_port;
2116
2117 ioc_info(mrioc,
2118 "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2119 handle, parent_handle, (unsigned long long)
2120 sas_expander->sas_address, sas_expander->num_phys);
2121
2122 if (!sas_expander->num_phys) {
2123 rc = -1;
2124 goto out_fail;
2125 }
2126 sas_expander->phy = kzalloc_objs(struct mpi3mr_sas_phy,
2127 sas_expander->num_phys);
2128 if (!sas_expander->phy) {
2129 rc = -1;
2130 goto out_fail;
2131 }
2132
2133 INIT_LIST_HEAD(&sas_expander->sas_port_list);
2134 mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2135 sas_expander->hba_port);
2136 if (!mr_sas_port) {
2137 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2138 __FILE__, __LINE__, __func__);
2139 rc = -1;
2140 goto out_fail;
2141 }
2142 sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2143 sas_expander->rphy = mr_sas_port->rphy;
2144
2145 for (i = 0 ; i < sas_expander->num_phys ; i++) {
2146 phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2147 handle;
2148 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2149 &expander_pg1, sizeof(expander_pg1),
2150 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2151 phynum_handle)) {
2152 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2153 __FILE__, __LINE__, __func__);
2154 rc = -1;
2155 goto out_fail;
2156 }
2157 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2158 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2159 __FILE__, __LINE__, __func__);
2160 rc = -1;
2161 goto out_fail;
2162 }
2163
2164 sas_expander->phy[i].handle = handle;
2165 sas_expander->phy[i].phy_id = i;
2166 sas_expander->phy[i].hba_port = hba_port;
2167
2168 if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2169 expander_pg1, sas_expander->parent_dev))) {
2170 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2171 __FILE__, __LINE__, __func__);
2172 rc = -1;
2173 goto out_fail;
2174 }
2175 }
2176
2177 if (sas_expander->enclosure_handle) {
2178 enclosure_dev =
2179 mpi3mr_enclosure_find_by_handle(mrioc,
2180 sas_expander->enclosure_handle);
2181 if (enclosure_dev)
2182 sas_expander->enclosure_logical_id = le64_to_cpu(
2183 enclosure_dev->pg0.enclosure_logical_id);
2184 }
2185
2186 mpi3mr_expander_node_add(mrioc, sas_expander);
2187 return 0;
2188
2189 out_fail:
2190
2191 if (mr_sas_port)
2192 mpi3mr_sas_port_remove(mrioc,
2193 sas_expander->sas_address,
2194 sas_address_parent, sas_expander->hba_port);
2195 kfree(sas_expander->phy);
2196 kfree(sas_expander);
2197 return rc;
2198 }
2199
2200 /**
2201 * mpi3mr_expander_node_remove - recursive removal of expander.
2202 * @mrioc: Adapter instance reference
2203 * @sas_expander: Expander device object
2204 *
2205 * Removes expander object and freeing associated memory from
2206 * the sas_expander_list and removes the same from SAS TL, if
2207 * one of the attached device is an expander then it recursively
2208 * removes the expander device too.
2209 *
2210 * Return nothing.
2211 */
mpi3mr_expander_node_remove(struct mpi3mr_ioc * mrioc,struct mpi3mr_sas_node * sas_expander)2212 void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2213 struct mpi3mr_sas_node *sas_expander)
2214 {
2215 struct mpi3mr_sas_port *mr_sas_port, *next;
2216 unsigned long flags;
2217 u8 port_id;
2218
2219 /* remove sibling ports attached to this expander */
2220 list_for_each_entry_safe(mr_sas_port, next,
2221 &sas_expander->sas_port_list, port_list) {
2222 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2223 return;
2224 if (mr_sas_port->remote_identify.device_type ==
2225 SAS_END_DEVICE)
2226 mpi3mr_remove_device_by_sas_address(mrioc,
2227 mr_sas_port->remote_identify.sas_address,
2228 mr_sas_port->hba_port);
2229 else if (mr_sas_port->remote_identify.device_type ==
2230 SAS_EDGE_EXPANDER_DEVICE ||
2231 mr_sas_port->remote_identify.device_type ==
2232 SAS_FANOUT_EXPANDER_DEVICE)
2233 mpi3mr_expander_remove(mrioc,
2234 mr_sas_port->remote_identify.sas_address,
2235 mr_sas_port->hba_port);
2236 }
2237
2238 port_id = sas_expander->hba_port->port_id;
2239 mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2240 sas_expander->sas_address_parent, sas_expander->hba_port);
2241
2242 ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2243 sas_expander->handle, (unsigned long long)
2244 sas_expander->sas_address, port_id);
2245
2246 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2247 list_del(&sas_expander->list);
2248 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2249
2250 kfree(sas_expander->phy);
2251 kfree(sas_expander);
2252 }
2253
2254 /**
2255 * mpi3mr_expander_remove - Remove expander object
2256 * @mrioc: Adapter instance reference
2257 * @sas_address: Remove expander sas_address
2258 * @hba_port: HBA port reference
2259 *
2260 * This function remove expander object, stored in
2261 * mrioc->sas_expander_list and removes it from the SAS TL by
2262 * calling mpi3mr_expander_node_remove().
2263 *
2264 * Return: None
2265 */
mpi3mr_expander_remove(struct mpi3mr_ioc * mrioc,u64 sas_address,struct mpi3mr_hba_port * hba_port)2266 void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2267 struct mpi3mr_hba_port *hba_port)
2268 {
2269 struct mpi3mr_sas_node *sas_expander;
2270 unsigned long flags;
2271
2272 if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
2273 return;
2274
2275 if (!hba_port)
2276 return;
2277
2278 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2279 sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2280 hba_port);
2281 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2282 if (sas_expander)
2283 mpi3mr_expander_node_remove(mrioc, sas_expander);
2284
2285 }
2286
2287 /**
2288 * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2289 * @mrioc: Adapter instance reference
2290 * @tgtdev: Target device
2291 *
2292 * This function first tries to use the link rate from DevicePage0
2293 * (populated by firmware during device discovery). If the cached
2294 * value is not available or invalid, it falls back to reading from
2295 * sas phy page0 or expander phy page1.
2296 *
2297 *
2298 * Return: logical link rate.
2299 */
mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2300 static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2301 struct mpi3mr_tgt_dev *tgtdev)
2302 {
2303 u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2304 struct mpi3_sas_expander_page1 expander_pg1;
2305 struct mpi3_sas_phy_page0 phy_pg0;
2306 u32 phynum_handle;
2307 u16 ioc_status;
2308
2309 /* First, try to use link rate from DevicePage0 (populated by firmware) */
2310 if (tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate >=
2311 MPI3_SAS_NEG_LINK_RATE_1_5) {
2312 link_rate = tgtdev->dev_spec.sas_sata_inf.negotiated_link_rate;
2313 goto out;
2314 }
2315
2316 /* Fallback to reading from phy pages if DevicePage0 value not available */
2317 phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2318 if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2319 phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2320 | tgtdev->parent_handle);
2321 if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2322 &expander_pg1, sizeof(expander_pg1),
2323 MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2324 phynum_handle)) {
2325 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2326 __FILE__, __LINE__, __func__);
2327 goto out;
2328 }
2329 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2330 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2331 __FILE__, __LINE__, __func__);
2332 goto out;
2333 }
2334 link_rate = expander_pg1.negotiated_link_rate;
2335 goto out;
2336 }
2337 if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2338 sizeof(struct mpi3_sas_phy_page0),
2339 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2340 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2341 __FILE__, __LINE__, __func__);
2342 goto out;
2343 }
2344 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2345 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2346 __FILE__, __LINE__, __func__);
2347 goto out;
2348 }
2349 link_rate = phy_pg0.negotiated_link_rate;
2350
2351 out:
2352 return ((link_rate & MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2353 MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
2354 }
2355
2356 /**
2357 * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2358 * @mrioc: Adapter instance reference
2359 * @tgtdev: Target device
2360 *
2361 * This function exposes the target device after
2362 * preparing host_phy, setting up link rate etc.
2363 *
2364 * Return: 0 on success, non-zero for failure.
2365 */
mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2366 int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2367 struct mpi3mr_tgt_dev *tgtdev)
2368 {
2369 int retval = 0;
2370 u8 link_rate, parent_phy_number;
2371 u64 sas_address_parent, sas_address;
2372 struct mpi3mr_hba_port *hba_port;
2373 u8 port_id;
2374
2375 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2376 !mrioc->sas_transport_enabled)
2377 return -1;
2378
2379 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2380 if (!mrioc->sas_hba.num_phys)
2381 mpi3mr_sas_host_add(mrioc);
2382 else
2383 mpi3mr_sas_host_refresh(mrioc);
2384
2385 if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2386 &sas_address_parent) != 0) {
2387 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2388 __FILE__, __LINE__, __func__);
2389 return -1;
2390 }
2391 tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2392
2393 parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2394 port_id = tgtdev->io_unit_port;
2395
2396 hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2397 if (!hba_port) {
2398 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2399 __FILE__, __LINE__, __func__);
2400 return -1;
2401 }
2402 tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2403
2404 link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2405
2406 if (link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
2407 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
2408
2409 mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2410 parent_phy_number, link_rate, hba_port);
2411
2412 tgtdev->host_exposed = 1;
2413 if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2414 sas_address_parent, hba_port)) {
2415 retval = -1;
2416 } else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {
2417 mpi3mr_sas_port_remove(mrioc, sas_address,
2418 sas_address_parent, hba_port);
2419 retval = -1;
2420 }
2421 if (retval) {
2422 tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2423 tgtdev->host_exposed = 0;
2424 }
2425 return retval;
2426 }
2427
2428 /**
2429 * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2430 * @mrioc: Adapter instance reference
2431 * @tgtdev: Target device
2432 *
2433 * This function removes the target device
2434 *
2435 * Return: None.
2436 */
mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc * mrioc,struct mpi3mr_tgt_dev * tgtdev)2437 void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2438 struct mpi3mr_tgt_dev *tgtdev)
2439 {
2440 u64 sas_address_parent, sas_address;
2441 struct mpi3mr_hba_port *hba_port;
2442
2443 if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2444 !mrioc->sas_transport_enabled)
2445 return;
2446
2447 hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2448 sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2449 sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2450 mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2451 hba_port);
2452 tgtdev->host_exposed = 0;
2453 tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2454 }
2455
2456 /**
2457 * mpi3mr_get_port_id_by_sas_phy - Get port ID of the given phy
2458 * @phy: SAS transport layer phy object
2459 *
2460 * Return: Port number for valid ID else 0xFFFF
2461 */
mpi3mr_get_port_id_by_sas_phy(struct sas_phy * phy)2462 static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2463 {
2464 u8 port_id = 0xFF;
2465 struct mpi3mr_hba_port *hba_port = phy->hostdata;
2466
2467 if (hba_port)
2468 port_id = hba_port->port_id;
2469
2470 return port_id;
2471 }
2472
2473 /**
2474 * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2475 *
2476 * @mrioc: Adapter instance reference
2477 * @rphy: SAS transport layer remote phy object
2478 *
2479 * Retrieves HBA port number in which the device pointed by the
2480 * rphy object is attached with.
2481 *
2482 * Return: Valid port number on success else OxFFFF.
2483 */
mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc * mrioc,struct sas_rphy * rphy)2484 static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2485 {
2486 struct mpi3mr_sas_node *sas_expander;
2487 struct mpi3mr_tgt_dev *tgtdev;
2488 unsigned long flags;
2489 u8 port_id = 0xFF;
2490
2491 if (!rphy)
2492 return port_id;
2493
2494 if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2495 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2496 spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2497 list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2498 list) {
2499 if (sas_expander->rphy == rphy) {
2500 port_id = sas_expander->hba_port->port_id;
2501 break;
2502 }
2503 }
2504 spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2505 } else if (rphy->identify.device_type == SAS_END_DEVICE) {
2506 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2507
2508 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2509 rphy->identify.sas_address, rphy);
2510 if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {
2511 port_id =
2512 tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2513 mpi3mr_tgtdev_put(tgtdev);
2514 }
2515 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2516 }
2517 return port_id;
2518 }
2519
phy_to_mrioc(struct sas_phy * phy)2520 static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2521 {
2522 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2523
2524 return shost_priv(shost);
2525 }
2526
rphy_to_mrioc(struct sas_rphy * rphy)2527 static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2528 {
2529 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2530
2531 return shost_priv(shost);
2532 }
2533
2534 /* report phy error log structure */
2535 struct phy_error_log_request {
2536 u8 smp_frame_type; /* 0x40 */
2537 u8 function; /* 0x11 */
2538 u8 allocated_response_length;
2539 u8 request_length; /* 02 */
2540 u8 reserved_1[5];
2541 u8 phy_identifier;
2542 u8 reserved_2[2];
2543 };
2544
2545 /* report phy error log reply structure */
2546 struct phy_error_log_reply {
2547 u8 smp_frame_type; /* 0x41 */
2548 u8 function; /* 0x11 */
2549 u8 function_result;
2550 u8 response_length;
2551 __be16 expander_change_count;
2552 u8 reserved_1[3];
2553 u8 phy_identifier;
2554 u8 reserved_2[2];
2555 __be32 invalid_dword;
2556 __be32 running_disparity_error;
2557 __be32 loss_of_dword_sync;
2558 __be32 phy_reset_problem;
2559 };
2560
2561
2562 /**
2563 * mpi3mr_get_expander_phy_error_log - return expander counters:
2564 * @mrioc: Adapter instance reference
2565 * @phy: The SAS transport layer phy object
2566 *
2567 * Return: 0 for success, non-zero for failure.
2568 *
2569 */
mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc * mrioc,struct sas_phy * phy)2570 static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2571 struct sas_phy *phy)
2572 {
2573 struct mpi3_smp_passthrough_request mpi_request;
2574 struct mpi3_smp_passthrough_reply mpi_reply;
2575 struct phy_error_log_request *phy_error_log_request;
2576 struct phy_error_log_reply *phy_error_log_reply;
2577 int rc;
2578 void *psge;
2579 void *data_out = NULL;
2580 dma_addr_t data_out_dma, data_in_dma;
2581 u32 data_out_sz, data_in_sz, sz;
2582 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2583 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2584 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2585 u16 ioc_status;
2586
2587 if (mrioc->reset_in_progress) {
2588 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2589 return -EFAULT;
2590 }
2591
2592 if (mrioc->pci_err_recovery) {
2593 ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
2594 return -EFAULT;
2595 }
2596
2597 data_out_sz = sizeof(struct phy_error_log_request);
2598 data_in_sz = sizeof(struct phy_error_log_reply);
2599 sz = data_out_sz + data_in_sz;
2600 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2601 GFP_KERNEL);
2602 if (!data_out) {
2603 rc = -ENOMEM;
2604 goto out;
2605 }
2606
2607 data_in_dma = data_out_dma + data_out_sz;
2608 phy_error_log_reply = data_out + data_out_sz;
2609
2610 rc = -EINVAL;
2611 memset(data_out, 0, sz);
2612 phy_error_log_request = data_out;
2613 phy_error_log_request->smp_frame_type = 0x40;
2614 phy_error_log_request->function = 0x11;
2615 phy_error_log_request->request_length = 2;
2616 phy_error_log_request->allocated_response_length = 0;
2617 phy_error_log_request->phy_identifier = phy->number;
2618
2619 memset(&mpi_request, 0, request_sz);
2620 memset(&mpi_reply, 0, reply_sz);
2621 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2622 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2623 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2624 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2625
2626 psge = &mpi_request.request_sge;
2627 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2628
2629 psge = &mpi_request.response_sge;
2630 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2631
2632 dprint_transport_info(mrioc,
2633 "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2634 (unsigned long long)phy->identify.sas_address, phy->number);
2635
2636 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2637 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2638 goto out;
2639
2640 dprint_transport_info(mrioc,
2641 "phy error log SMP request completed with ioc_status(0x%04x)\n",
2642 ioc_status);
2643
2644 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2645 dprint_transport_info(mrioc,
2646 "phy error log - reply data transfer size(%d)\n",
2647 le16_to_cpu(mpi_reply.response_data_length));
2648
2649 if (le16_to_cpu(mpi_reply.response_data_length) !=
2650 sizeof(struct phy_error_log_reply))
2651 goto out;
2652
2653 dprint_transport_info(mrioc,
2654 "phy error log - function_result(%d)\n",
2655 phy_error_log_reply->function_result);
2656
2657 phy->invalid_dword_count =
2658 be32_to_cpu(phy_error_log_reply->invalid_dword);
2659 phy->running_disparity_error_count =
2660 be32_to_cpu(phy_error_log_reply->running_disparity_error);
2661 phy->loss_of_dword_sync_count =
2662 be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2663 phy->phy_reset_problem_count =
2664 be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2665 rc = 0;
2666 }
2667
2668 out:
2669 if (data_out)
2670 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2671 data_out_dma);
2672
2673 return rc;
2674 }
2675
2676 /**
2677 * mpi3mr_transport_get_linkerrors - return phy error counters
2678 * @phy: The SAS transport layer phy object
2679 *
2680 * This function retrieves the phy error log information of the
2681 * HBA or expander for which the phy belongs to
2682 *
2683 * Return: 0 for success, non-zero for failure.
2684 */
mpi3mr_transport_get_linkerrors(struct sas_phy * phy)2685 static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2686 {
2687 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2688 struct mpi3_sas_phy_page1 phy_pg1;
2689 int rc = 0;
2690 u16 ioc_status;
2691
2692 rc = mpi3mr_parent_present(mrioc, phy);
2693 if (rc)
2694 return rc;
2695
2696 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2697 return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2698
2699 memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2700 /* get hba phy error logs */
2701 if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2702 sizeof(struct mpi3_sas_phy_page1),
2703 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2704 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2705 __FILE__, __LINE__, __func__);
2706 return -ENXIO;
2707 }
2708
2709 if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2710 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2711 __FILE__, __LINE__, __func__);
2712 return -ENXIO;
2713 }
2714 phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2715 phy->running_disparity_error_count =
2716 le32_to_cpu(phy_pg1.running_disparity_error_count);
2717 phy->loss_of_dword_sync_count =
2718 le32_to_cpu(phy_pg1.loss_dword_synch_count);
2719 phy->phy_reset_problem_count =
2720 le32_to_cpu(phy_pg1.phy_reset_problem_count);
2721 return 0;
2722 }
2723
2724 /**
2725 * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2726 * @rphy: The SAS transport layer remote phy object
2727 * @identifier: Enclosure identifier to be returned
2728 *
2729 * Returns the enclosure id for the device pointed by the remote
2730 * phy object.
2731 *
2732 * Return: 0 on success or -ENXIO
2733 */
2734 static int
mpi3mr_transport_get_enclosure_identifier(struct sas_rphy * rphy,u64 * identifier)2735 mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2736 u64 *identifier)
2737 {
2738 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2739 struct mpi3mr_tgt_dev *tgtdev = NULL;
2740 unsigned long flags;
2741 int rc;
2742
2743 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2744 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2745 rphy->identify.sas_address, rphy);
2746 if (tgtdev) {
2747 *identifier =
2748 tgtdev->enclosure_logical_id;
2749 rc = 0;
2750 mpi3mr_tgtdev_put(tgtdev);
2751 } else {
2752 *identifier = 0;
2753 rc = -ENXIO;
2754 }
2755 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2756
2757 return rc;
2758 }
2759
2760 /**
2761 * mpi3mr_transport_get_bay_identifier - Get bay ID
2762 * @rphy: The SAS transport layer remote phy object
2763 *
2764 * Returns the slot id for the device pointed by the remote phy
2765 * object.
2766 *
2767 * Return: Valid slot ID on success or -ENXIO
2768 */
2769 static int
mpi3mr_transport_get_bay_identifier(struct sas_rphy * rphy)2770 mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2771 {
2772 struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2773 struct mpi3mr_tgt_dev *tgtdev = NULL;
2774 unsigned long flags;
2775 int rc;
2776
2777 spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2778 tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2779 rphy->identify.sas_address, rphy);
2780 if (tgtdev) {
2781 rc = tgtdev->slot;
2782 mpi3mr_tgtdev_put(tgtdev);
2783 } else
2784 rc = -ENXIO;
2785 spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2786
2787 return rc;
2788 }
2789
2790 /* phy control request structure */
2791 struct phy_control_request {
2792 u8 smp_frame_type; /* 0x40 */
2793 u8 function; /* 0x91 */
2794 u8 allocated_response_length;
2795 u8 request_length; /* 0x09 */
2796 u16 expander_change_count;
2797 u8 reserved_1[3];
2798 u8 phy_identifier;
2799 u8 phy_operation;
2800 u8 reserved_2[13];
2801 u64 attached_device_name;
2802 u8 programmed_min_physical_link_rate;
2803 u8 programmed_max_physical_link_rate;
2804 u8 reserved_3[6];
2805 };
2806
2807 /* phy control reply structure */
2808 struct phy_control_reply {
2809 u8 smp_frame_type; /* 0x41 */
2810 u8 function; /* 0x11 */
2811 u8 function_result;
2812 u8 response_length;
2813 };
2814
2815 #define SMP_PHY_CONTROL_LINK_RESET (0x01)
2816 #define SMP_PHY_CONTROL_HARD_RESET (0x02)
2817 #define SMP_PHY_CONTROL_DISABLE (0x03)
2818
2819 /**
2820 * mpi3mr_expander_phy_control - expander phy control
2821 * @mrioc: Adapter instance reference
2822 * @phy: The SAS transport layer phy object
2823 * @phy_operation: The phy operation to be executed
2824 *
2825 * Issues SMP passthru phy control request to execute a specific
2826 * phy operation for a given expander device.
2827 *
2828 * Return: 0 for success, non-zero for failure.
2829 */
2830 static int
mpi3mr_expander_phy_control(struct mpi3mr_ioc * mrioc,struct sas_phy * phy,u8 phy_operation)2831 mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2832 struct sas_phy *phy, u8 phy_operation)
2833 {
2834 struct mpi3_smp_passthrough_request mpi_request;
2835 struct mpi3_smp_passthrough_reply mpi_reply;
2836 struct phy_control_request *phy_control_request;
2837 struct phy_control_reply *phy_control_reply;
2838 int rc;
2839 void *psge;
2840 void *data_out = NULL;
2841 dma_addr_t data_out_dma;
2842 dma_addr_t data_in_dma;
2843 size_t data_in_sz;
2844 size_t data_out_sz;
2845 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2846 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2847 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2848 u16 ioc_status;
2849 u16 sz;
2850
2851 if (mrioc->reset_in_progress) {
2852 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2853 return -EFAULT;
2854 }
2855
2856 if (mrioc->pci_err_recovery) {
2857 ioc_err(mrioc, "%s: pci error recovery in progress!\n",
2858 __func__);
2859 return -EFAULT;
2860 }
2861
2862 data_out_sz = sizeof(struct phy_control_request);
2863 data_in_sz = sizeof(struct phy_control_reply);
2864 sz = data_out_sz + data_in_sz;
2865 data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2866 GFP_KERNEL);
2867 if (!data_out) {
2868 rc = -ENOMEM;
2869 goto out;
2870 }
2871
2872 data_in_dma = data_out_dma + data_out_sz;
2873 phy_control_reply = data_out + data_out_sz;
2874
2875 rc = -EINVAL;
2876 memset(data_out, 0, sz);
2877
2878 phy_control_request = data_out;
2879 phy_control_request->smp_frame_type = 0x40;
2880 phy_control_request->function = 0x91;
2881 phy_control_request->request_length = 9;
2882 phy_control_request->allocated_response_length = 0;
2883 phy_control_request->phy_identifier = phy->number;
2884 phy_control_request->phy_operation = phy_operation;
2885 phy_control_request->programmed_min_physical_link_rate =
2886 phy->minimum_linkrate << 4;
2887 phy_control_request->programmed_max_physical_link_rate =
2888 phy->maximum_linkrate << 4;
2889
2890 memset(&mpi_request, 0, request_sz);
2891 memset(&mpi_reply, 0, reply_sz);
2892 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2893 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2894 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2895 mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2896
2897 psge = &mpi_request.request_sge;
2898 mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2899
2900 psge = &mpi_request.response_sge;
2901 mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2902
2903 dprint_transport_info(mrioc,
2904 "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2905 (unsigned long long)phy->identify.sas_address, phy->number,
2906 phy_operation);
2907
2908 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2909 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2910 goto out;
2911
2912 dprint_transport_info(mrioc,
2913 "phy control SMP request completed with ioc_status(0x%04x)\n",
2914 ioc_status);
2915
2916 if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2917 dprint_transport_info(mrioc,
2918 "phy control - reply data transfer size(%d)\n",
2919 le16_to_cpu(mpi_reply.response_data_length));
2920
2921 if (le16_to_cpu(mpi_reply.response_data_length) !=
2922 sizeof(struct phy_control_reply))
2923 goto out;
2924 dprint_transport_info(mrioc,
2925 "phy control - function_result(%d)\n",
2926 phy_control_reply->function_result);
2927 rc = 0;
2928 }
2929 out:
2930 if (data_out)
2931 dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2932 data_out_dma);
2933
2934 return rc;
2935 }
2936
2937 /**
2938 * mpi3mr_transport_phy_reset - Reset a given phy
2939 * @phy: The SAS transport layer phy object
2940 * @hard_reset: Flag to indicate the type of reset
2941 *
2942 * Return: 0 for success, non-zero for failure.
2943 */
2944 static int
mpi3mr_transport_phy_reset(struct sas_phy * phy,int hard_reset)2945 mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2946 {
2947 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2948 struct mpi3_iounit_control_request mpi_request;
2949 struct mpi3_iounit_control_reply mpi_reply;
2950 u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2951 u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2952 int rc = 0;
2953 u16 ioc_status;
2954
2955 rc = mpi3mr_parent_present(mrioc, phy);
2956 if (rc)
2957 return rc;
2958
2959 /* handle expander phys */
2960 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2961 return mpi3mr_expander_phy_control(mrioc, phy,
2962 (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2963 SMP_PHY_CONTROL_LINK_RESET);
2964
2965 /* handle hba phys */
2966 memset(&mpi_request, 0, request_sz);
2967 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2968 mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2969 mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2970 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2971 (hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2972 MPI3_CTRL_ACTION_LINK_RESET);
2973 mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2974 phy->number;
2975
2976 dprint_transport_info(mrioc,
2977 "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2978 (unsigned long long)phy->identify.sas_address, phy->number,
2979 hard_reset);
2980
2981 if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2982 &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2983 rc = -EAGAIN;
2984 goto out;
2985 }
2986
2987 dprint_transport_info(mrioc,
2988 "phy reset request completed with ioc_status(0x%04x)\n",
2989 ioc_status);
2990 out:
2991 return rc;
2992 }
2993
2994 /**
2995 * mpi3mr_transport_phy_enable - enable/disable phys
2996 * @phy: The SAS transport layer phy object
2997 * @enable: flag to enable/disable, enable phy when true
2998 *
2999 * This function enables/disables a given by executing required
3000 * configuration page changes or expander phy control command
3001 *
3002 * Return: 0 for success, non-zero for failure.
3003 */
3004 static int
mpi3mr_transport_phy_enable(struct sas_phy * phy,int enable)3005 mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
3006 {
3007 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3008 struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
3009 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3010 u16 sz;
3011 int rc = 0;
3012 int i, discovery_active;
3013
3014 rc = mpi3mr_parent_present(mrioc, phy);
3015 if (rc)
3016 return rc;
3017
3018 /* handle expander phys */
3019 if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
3020 return mpi3mr_expander_phy_control(mrioc, phy,
3021 (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
3022 SMP_PHY_CONTROL_DISABLE);
3023
3024 /* handle hba phys */
3025 sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
3026 (mrioc->sas_hba.num_phys *
3027 sizeof(struct mpi3_sas_io_unit0_phy_data));
3028 sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
3029 if (!sas_io_unit_pg0) {
3030 rc = -ENOMEM;
3031 goto out;
3032 }
3033 if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
3034 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3035 __FILE__, __LINE__, __func__);
3036 rc = -ENXIO;
3037 goto out;
3038 }
3039
3040 /* unable to enable/disable phys when discovery is active */
3041 for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
3042 if (sas_io_unit_pg0->phy_data[i].port_flags &
3043 MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
3044 ioc_err(mrioc,
3045 "discovery is active on port = %d, phy = %d\n"
3046 "\tunable to enable/disable phys, try again later!\n",
3047 sas_io_unit_pg0->phy_data[i].io_unit_port, i);
3048 discovery_active = 1;
3049 }
3050 }
3051
3052 if (discovery_active) {
3053 rc = -EAGAIN;
3054 goto out;
3055 }
3056
3057 if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
3058 (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
3059 MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
3060 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3061 __FILE__, __LINE__, __func__);
3062 rc = -ENXIO;
3063 goto out;
3064 }
3065
3066 /* read sas_iounit page 1 */
3067 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3068 (mrioc->sas_hba.num_phys *
3069 sizeof(struct mpi3_sas_io_unit1_phy_data));
3070 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3071 if (!sas_io_unit_pg1) {
3072 rc = -ENOMEM;
3073 goto out;
3074 }
3075
3076 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3077 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3078 __FILE__, __LINE__, __func__);
3079 rc = -ENXIO;
3080 goto out;
3081 }
3082
3083 if (enable)
3084 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3085 &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3086 else
3087 sas_io_unit_pg1->phy_data[phy->number].phy_flags
3088 |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3089
3090 mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3091
3092 /* link reset */
3093 if (enable)
3094 mpi3mr_transport_phy_reset(phy, 0);
3095
3096 out:
3097 kfree(sas_io_unit_pg1);
3098 kfree(sas_io_unit_pg0);
3099 return rc;
3100 }
3101
3102 /**
3103 * mpi3mr_transport_phy_speed - set phy min/max speed
3104 * @phy: The SAS transport later phy object
3105 * @rates: Rates defined as in sas_phy_linkrates
3106 *
3107 * This function sets the link rates given in the rates
3108 * argument to the given phy by executing required configuration
3109 * page changes or expander phy control command
3110 *
3111 * Return: 0 for success, non-zero for failure.
3112 */
3113 static int
mpi3mr_transport_phy_speed(struct sas_phy * phy,struct sas_phy_linkrates * rates)3114 mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3115 {
3116 struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3117 struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3118 struct mpi3_sas_phy_page0 phy_pg0;
3119 u16 sz, ioc_status;
3120 int rc = 0;
3121
3122 rc = mpi3mr_parent_present(mrioc, phy);
3123 if (rc)
3124 return rc;
3125
3126 if (!rates->minimum_linkrate)
3127 rates->minimum_linkrate = phy->minimum_linkrate;
3128 else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3129 rates->minimum_linkrate = phy->minimum_linkrate_hw;
3130
3131 if (!rates->maximum_linkrate)
3132 rates->maximum_linkrate = phy->maximum_linkrate;
3133 else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3134 rates->maximum_linkrate = phy->maximum_linkrate_hw;
3135
3136 /* handle expander phys */
3137 if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3138 phy->minimum_linkrate = rates->minimum_linkrate;
3139 phy->maximum_linkrate = rates->maximum_linkrate;
3140 return mpi3mr_expander_phy_control(mrioc, phy,
3141 SMP_PHY_CONTROL_LINK_RESET);
3142 }
3143
3144 /* handle hba phys */
3145 sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3146 (mrioc->sas_hba.num_phys *
3147 sizeof(struct mpi3_sas_io_unit1_phy_data));
3148 sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3149 if (!sas_io_unit_pg1) {
3150 rc = -ENOMEM;
3151 goto out;
3152 }
3153
3154 if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3155 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3156 __FILE__, __LINE__, __func__);
3157 rc = -ENXIO;
3158 goto out;
3159 }
3160
3161 sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3162 (rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3163
3164 if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3165 ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3166 __FILE__, __LINE__, __func__);
3167 rc = -ENXIO;
3168 goto out;
3169 }
3170
3171 /* link reset */
3172 mpi3mr_transport_phy_reset(phy, 0);
3173
3174 /* read phy page 0, then update the rates in the sas transport phy */
3175 if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3176 sizeof(struct mpi3_sas_phy_page0),
3177 MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3178 (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3179 phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3180 phy_pg0.programmed_link_rate &
3181 MPI3_SAS_PRATE_MIN_RATE_MASK);
3182 phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3183 phy_pg0.programmed_link_rate >> 4);
3184 phy->negotiated_linkrate =
3185 mpi3mr_convert_phy_link_rate(
3186 (phy_pg0.negotiated_link_rate &
3187 MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3188 >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3189 }
3190
3191 out:
3192 kfree(sas_io_unit_pg1);
3193 return rc;
3194 }
3195
3196 /**
3197 * mpi3mr_map_smp_buffer - map BSG dma buffer
3198 * @dev: Generic device reference
3199 * @buf: BSG buffer pointer
3200 * @dma_addr: Physical address holder
3201 * @dma_len: Mapped DMA buffer length.
3202 * @p: Virtual address holder
3203 *
3204 * This function maps the DMAable buffer
3205 *
3206 * Return: 0 on success, non-zero on failure
3207 */
3208 static int
mpi3mr_map_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t * dma_addr,size_t * dma_len,void ** p)3209 mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3210 dma_addr_t *dma_addr, size_t *dma_len, void **p)
3211 {
3212 /* Check if the request is split across multiple segments */
3213 if (buf->sg_cnt > 1) {
3214 *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3215 GFP_KERNEL);
3216 if (!*p)
3217 return -ENOMEM;
3218 *dma_len = buf->payload_len;
3219 } else {
3220 if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3221 return -ENOMEM;
3222 *dma_addr = sg_dma_address(buf->sg_list);
3223 *dma_len = sg_dma_len(buf->sg_list);
3224 *p = NULL;
3225 }
3226
3227 return 0;
3228 }
3229
3230 /**
3231 * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3232 * @dev: Generic device reference
3233 * @buf: BSG buffer pointer
3234 * @dma_addr: Physical address to be unmapped
3235 * @p: Virtual address
3236 *
3237 * This function unmaps the DMAable buffer
3238 */
3239 static void
mpi3mr_unmap_smp_buffer(struct device * dev,struct bsg_buffer * buf,dma_addr_t dma_addr,void * p)3240 mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3241 dma_addr_t dma_addr, void *p)
3242 {
3243 if (p)
3244 dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3245 else
3246 dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3247 }
3248
3249 /**
3250 * mpi3mr_transport_smp_handler - handler for smp passthru
3251 * @job: BSG job reference
3252 * @shost: SCSI host object reference
3253 * @rphy: SAS transport rphy object pointing the expander
3254 *
3255 * This is used primarily by smp utils for sending the SMP
3256 * commands to the expanders attached to the controller
3257 */
3258 static void
mpi3mr_transport_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)3259 mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3260 struct sas_rphy *rphy)
3261 {
3262 struct mpi3mr_ioc *mrioc = shost_priv(shost);
3263 struct mpi3_smp_passthrough_request mpi_request;
3264 struct mpi3_smp_passthrough_reply mpi_reply;
3265 int rc;
3266 void *psge;
3267 dma_addr_t dma_addr_in;
3268 dma_addr_t dma_addr_out;
3269 void *addr_in = NULL;
3270 void *addr_out = NULL;
3271 size_t dma_len_in;
3272 size_t dma_len_out;
3273 unsigned int reslen = 0;
3274 u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3275 u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3276 u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3277 u16 ioc_status;
3278
3279 if (mrioc->reset_in_progress) {
3280 ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3281 rc = -EFAULT;
3282 goto out;
3283 }
3284
3285 if (mrioc->pci_err_recovery) {
3286 ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);
3287 rc = -EFAULT;
3288 goto out;
3289 }
3290
3291 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3292 &dma_addr_out, &dma_len_out, &addr_out);
3293 if (rc)
3294 goto out;
3295
3296 if (addr_out)
3297 sg_copy_to_buffer(job->request_payload.sg_list,
3298 job->request_payload.sg_cnt, addr_out,
3299 job->request_payload.payload_len);
3300
3301 rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3302 &dma_addr_in, &dma_len_in, &addr_in);
3303 if (rc)
3304 goto unmap_out;
3305
3306 memset(&mpi_request, 0, request_sz);
3307 memset(&mpi_reply, 0, reply_sz);
3308 mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3309 mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3310 mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3311 mpi_request.sas_address = ((rphy) ?
3312 cpu_to_le64(rphy->identify.sas_address) :
3313 cpu_to_le64(mrioc->sas_hba.sas_address));
3314 psge = &mpi_request.request_sge;
3315 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3316
3317 psge = &mpi_request.response_sge;
3318 mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3319
3320 dprint_transport_info(mrioc, "sending SMP request\n");
3321
3322 rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3323 &mpi_reply, reply_sz,
3324 MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
3325 if (rc)
3326 goto unmap_in;
3327
3328 dprint_transport_info(mrioc,
3329 "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3330
3331 dprint_transport_info(mrioc,
3332 "SMP request - reply data transfer size(%d)\n",
3333 le16_to_cpu(mpi_reply.response_data_length));
3334
3335 memcpy(job->reply, &mpi_reply, reply_sz);
3336 job->reply_len = reply_sz;
3337 reslen = le16_to_cpu(mpi_reply.response_data_length);
3338
3339 if (addr_in)
3340 sg_copy_from_buffer(job->reply_payload.sg_list,
3341 job->reply_payload.sg_cnt, addr_in,
3342 job->reply_payload.payload_len);
3343
3344 rc = 0;
3345 unmap_in:
3346 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3347 dma_addr_in, addr_in);
3348 unmap_out:
3349 mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3350 dma_addr_out, addr_out);
3351 out:
3352 bsg_job_done(job, rc, reslen);
3353 }
3354
3355 struct sas_function_template mpi3mr_transport_functions = {
3356 .get_linkerrors = mpi3mr_transport_get_linkerrors,
3357 .get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3358 .get_bay_identifier = mpi3mr_transport_get_bay_identifier,
3359 .phy_reset = mpi3mr_transport_phy_reset,
3360 .phy_enable = mpi3mr_transport_phy_enable,
3361 .set_phy_speed = mpi3mr_transport_phy_speed,
3362 .smp_handler = mpi3mr_transport_smp_handler,
3363 };
3364
3365 struct scsi_transport_template *mpi3mr_transport_template;
3366