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