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