]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/scsi/mpt2sas/mpt2sas_transport.c
789f9ee7f00157fa10ec3f292725c9b1ee666d7c
[karo-tx-linux.git] / drivers / scsi / mpt2sas / mpt2sas_transport.c
1 /*
2  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
3  *
4  * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
5  * Copyright (C) 2007-2009  LSI Corporation
6  *  (mailto:DL-MPTFusionLinux@lsi.com)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * NO WARRANTY
19  * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
20  * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
21  * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
22  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
23  * solely responsible for determining the appropriateness of using and
24  * distributing the Program and assumes all risks associated with its
25  * exercise of rights under this Agreement, including but not limited to
26  * the risks and costs of program errors, damage to or loss of data,
27  * programs or equipment, and unavailability or interruption of operations.
28
29  * DISCLAIMER OF LIABILITY
30  * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
31  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
33  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
34  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
35  * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
36  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
37
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
41  * USA.
42  */
43
44 #include <linux/module.h>
45 #include <linux/kernel.h>
46 #include <linux/init.h>
47 #include <linux/errno.h>
48 #include <linux/sched.h>
49 #include <linux/workqueue.h>
50 #include <linux/delay.h>
51 #include <linux/pci.h>
52
53 #include <scsi/scsi.h>
54 #include <scsi/scsi_cmnd.h>
55 #include <scsi/scsi_device.h>
56 #include <scsi/scsi_host.h>
57 #include <scsi/scsi_transport_sas.h>
58 #include <scsi/scsi_dbg.h>
59
60 #include "mpt2sas_base.h"
61 /**
62  * _transport_sas_node_find_by_sas_address - sas node search
63  * @ioc: per adapter object
64  * @sas_address: sas address of expander or sas host
65  * Context: Calling function should acquire ioc->sas_node_lock.
66  *
67  * Search for either hba phys or expander device based on handle, then returns
68  * the sas_node object.
69  */
70 static struct _sas_node *
71 _transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
72     u64 sas_address)
73 {
74         if (ioc->sas_hba.sas_address == sas_address)
75                 return &ioc->sas_hba;
76         else
77                 return mpt2sas_scsih_expander_find_by_sas_address(ioc,
78                     sas_address);
79 }
80
81 /**
82  * _transport_convert_phy_link_rate -
83  * @link_rate: link rate returned from mpt firmware
84  *
85  * Convert link_rate from mpi fusion into sas_transport form.
86  */
87 static enum sas_linkrate
88 _transport_convert_phy_link_rate(u8 link_rate)
89 {
90         enum sas_linkrate rc;
91
92         switch (link_rate) {
93         case MPI2_SAS_NEG_LINK_RATE_1_5:
94                 rc = SAS_LINK_RATE_1_5_GBPS;
95                 break;
96         case MPI2_SAS_NEG_LINK_RATE_3_0:
97                 rc = SAS_LINK_RATE_3_0_GBPS;
98                 break;
99         case MPI2_SAS_NEG_LINK_RATE_6_0:
100                 rc = SAS_LINK_RATE_6_0_GBPS;
101                 break;
102         case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
103                 rc = SAS_PHY_DISABLED;
104                 break;
105         case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
106                 rc = SAS_LINK_RATE_FAILED;
107                 break;
108         case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
109                 rc = SAS_SATA_PORT_SELECTOR;
110                 break;
111         case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
112                 rc = SAS_PHY_RESET_IN_PROGRESS;
113                 break;
114         default:
115         case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
116         case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
117                 rc = SAS_LINK_RATE_UNKNOWN;
118                 break;
119         }
120         return rc;
121 }
122
123 /**
124  * _transport_set_identify - set identify for phys and end devices
125  * @ioc: per adapter object
126  * @handle: device handle
127  * @identify: sas identify info
128  *
129  * Populates sas identify info.
130  *
131  * Returns 0 for success, non-zero for failure.
132  */
133 static int
134 _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
135     struct sas_identify *identify)
136 {
137         Mpi2SasDevicePage0_t sas_device_pg0;
138         Mpi2ConfigReply_t mpi_reply;
139         u32 device_info;
140         u32 ioc_status;
141
142         if (ioc->shost_recovery) {
143                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
144                     __func__, ioc->name);
145                 return -EFAULT;
146         }
147
148         if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
149             MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
150                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
151
152                     ioc->name, __FILE__, __LINE__, __func__);
153                 return -ENXIO;
154         }
155
156         ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
157             MPI2_IOCSTATUS_MASK;
158         if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
159                 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
160                     "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
161                      __FILE__, __LINE__, __func__);
162                 return -EIO;
163         }
164
165         memset(identify, 0, sizeof(identify));
166         device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
167
168         /* sas_address */
169         identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
170
171         /* device_type */
172         switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
173         case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
174                 identify->device_type = SAS_PHY_UNUSED;
175                 break;
176         case MPI2_SAS_DEVICE_INFO_END_DEVICE:
177                 identify->device_type = SAS_END_DEVICE;
178                 break;
179         case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
180                 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
181                 break;
182         case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
183                 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
184                 break;
185         }
186
187         /* initiator_port_protocols */
188         if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
189                 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
190         if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
191                 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
192         if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
193                 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
194         if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
195                 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
196
197         /* target_port_protocols */
198         if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
199                 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
200         if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
201                 identify->target_port_protocols |= SAS_PROTOCOL_STP;
202         if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
203                 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
204         if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
205                 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
206
207         return 0;
208 }
209
210 /**
211  * mpt2sas_transport_done -  internal transport layer callback handler.
212  * @ioc: per adapter object
213  * @smid: system request message index
214  * @msix_index: MSIX table index supplied by the OS
215  * @reply: reply message frame(lower 32bit addr)
216  *
217  * Callback handler when sending internal generated transport cmds.
218  * The callback index passed is `ioc->transport_cb_idx`
219  *
220  * Return 1 meaning mf should be freed from _base_interrupt
221  *        0 means the mf is freed from this function.
222  */
223 u8
224 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
225     u32 reply)
226 {
227         MPI2DefaultReply_t *mpi_reply;
228
229         mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
230         if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
231                 return 1;
232         if (ioc->transport_cmds.smid != smid)
233                 return 1;
234         ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
235         if (mpi_reply) {
236                 memcpy(ioc->transport_cmds.reply, mpi_reply,
237                     mpi_reply->MsgLength*4);
238                 ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
239         }
240         ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
241         complete(&ioc->transport_cmds.done);
242         return 1;
243 }
244
245 /* report manufacture request structure */
246 struct rep_manu_request{
247         u8 smp_frame_type;
248         u8 function;
249         u8 reserved;
250         u8 request_length;
251 };
252
253 /* report manufacture reply structure */
254 struct rep_manu_reply{
255         u8 smp_frame_type; /* 0x41 */
256         u8 function; /* 0x01 */
257         u8 function_result;
258         u8 response_length;
259         u16 expander_change_count;
260         u8 reserved0[2];
261         u8 sas_format;
262         u8 reserved2[3];
263         u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
264         u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
265         u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
266         u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
267         u16 component_id;
268         u8 component_revision_id;
269         u8 reserved3;
270         u8 vendor_specific[8];
271 };
272
273 /**
274  * _transport_expander_report_manufacture - obtain SMP report_manufacture
275  * @ioc: per adapter object
276  * @sas_address: expander sas address
277  * @edev: the sas_expander_device object
278  *
279  * Fills in the sas_expander_device object when SMP port is created.
280  *
281  * Returns 0 for success, non-zero for failure.
282  */
283 static int
284 _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
285     u64 sas_address, struct sas_expander_device *edev)
286 {
287         Mpi2SmpPassthroughRequest_t *mpi_request;
288         Mpi2SmpPassthroughReply_t *mpi_reply;
289         struct rep_manu_reply *manufacture_reply;
290         struct rep_manu_request *manufacture_request;
291         int rc;
292         u16 smid;
293         u32 ioc_state;
294         unsigned long timeleft;
295         void *psge;
296         u32 sgl_flags;
297         u8 issue_reset = 0;
298         void *data_out = NULL;
299         dma_addr_t data_out_dma;
300         u32 sz;
301         u64 *sas_address_le;
302         u16 wait_state_count;
303
304         if (ioc->shost_recovery) {
305                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
306                     __func__, ioc->name);
307                 return -EFAULT;
308         }
309
310         mutex_lock(&ioc->transport_cmds.mutex);
311
312         if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
313                 printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
314                     ioc->name, __func__);
315                 rc = -EAGAIN;
316                 goto out;
317         }
318         ioc->transport_cmds.status = MPT2_CMD_PENDING;
319
320         wait_state_count = 0;
321         ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
322         while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
323                 if (wait_state_count++ == 10) {
324                         printk(MPT2SAS_ERR_FMT
325                             "%s: failed due to ioc not operational\n",
326                             ioc->name, __func__);
327                         rc = -EFAULT;
328                         goto out;
329                 }
330                 ssleep(1);
331                 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
332                 printk(MPT2SAS_INFO_FMT "%s: waiting for "
333                     "operational state(count=%d)\n", ioc->name,
334                     __func__, wait_state_count);
335         }
336         if (wait_state_count)
337                 printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
338                     ioc->name, __func__);
339
340         smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
341         if (!smid) {
342                 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
343                     ioc->name, __func__);
344                 rc = -EAGAIN;
345                 goto out;
346         }
347
348         rc = 0;
349         mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
350         ioc->transport_cmds.smid = smid;
351
352         sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
353         data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
354
355         if (!data_out) {
356                 printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
357                     __LINE__, __func__);
358                 rc = -ENOMEM;
359                 mpt2sas_base_free_smid(ioc, smid);
360                 goto out;
361         }
362
363         manufacture_request = data_out;
364         manufacture_request->smp_frame_type = 0x40;
365         manufacture_request->function = 1;
366         manufacture_request->reserved = 0;
367         manufacture_request->request_length = 0;
368
369         memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
370         mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
371         mpi_request->PhysicalPort = 0xFF;
372         mpi_request->VF_ID = 0; /* TODO */
373         mpi_request->VP_ID = 0;
374         sas_address_le = (u64 *)&mpi_request->SASAddress;
375         *sas_address_le = cpu_to_le64(sas_address);
376         mpi_request->RequestDataLength =
377             cpu_to_le16(sizeof(struct rep_manu_request));
378         psge = &mpi_request->SGL;
379
380         /* WRITE sgel first */
381         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
382             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
383         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
384         ioc->base_add_sg_single(psge, sgl_flags |
385             sizeof(struct rep_manu_request), data_out_dma);
386
387         /* incr sgel */
388         psge += ioc->sge_size;
389
390         /* READ sgel last */
391         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
392             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
393             MPI2_SGE_FLAGS_END_OF_LIST);
394         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
395         ioc->base_add_sg_single(psge, sgl_flags |
396             sizeof(struct rep_manu_reply), data_out_dma +
397             sizeof(struct rep_manu_request));
398
399         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
400             "send to sas_addr(0x%016llx)\n", ioc->name,
401             (unsigned long long)sas_address));
402         mpt2sas_base_put_smid_default(ioc, smid);
403         init_completion(&ioc->transport_cmds.done);
404         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
405             10*HZ);
406
407         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
408                 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
409                     ioc->name, __func__);
410                 _debug_dump_mf(mpi_request,
411                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
412                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
413                         issue_reset = 1;
414                 goto issue_host_reset;
415         }
416
417         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
418             "complete\n", ioc->name));
419
420         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
421                 u8 *tmp;
422
423                 mpi_reply = ioc->transport_cmds.reply;
424
425                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
426                     "report_manufacture - reply data transfer size(%d)\n",
427                     ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
428
429                 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
430                     sizeof(struct rep_manu_reply))
431                         goto out;
432
433                 manufacture_reply = data_out + sizeof(struct rep_manu_request);
434                 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
435                      SAS_EXPANDER_VENDOR_ID_LEN);
436                 strncpy(edev->product_id, manufacture_reply->product_id,
437                      SAS_EXPANDER_PRODUCT_ID_LEN);
438                 strncpy(edev->product_rev, manufacture_reply->product_rev,
439                      SAS_EXPANDER_PRODUCT_REV_LEN);
440                 edev->level = manufacture_reply->sas_format & 1;
441                 if (edev->level) {
442                         strncpy(edev->component_vendor_id,
443                             manufacture_reply->component_vendor_id,
444                              SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
445                         tmp = (u8 *)&manufacture_reply->component_id;
446                         edev->component_id = tmp[0] << 8 | tmp[1];
447                         edev->component_revision_id =
448                             manufacture_reply->component_revision_id;
449                 }
450         } else
451                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
452                     "report_manufacture - no reply\n", ioc->name));
453
454  issue_host_reset:
455         if (issue_reset)
456                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
457                     FORCE_BIG_HAMMER);
458  out:
459         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
460         if (data_out)
461                 pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
462
463         mutex_unlock(&ioc->transport_cmds.mutex);
464         return rc;
465 }
466
467 /**
468  * mpt2sas_transport_port_add - insert port to the list
469  * @ioc: per adapter object
470  * @handle: handle of attached device
471  * @sas_address: sas address of parent expander or sas host
472  * Context: This function will acquire ioc->sas_node_lock.
473  *
474  * Adding new port object to the sas_node->sas_port_list.
475  *
476  * Returns mpt2sas_port.
477  */
478 struct _sas_port *
479 mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
480     u64 sas_address)
481 {
482         struct _sas_phy *mpt2sas_phy, *next;
483         struct _sas_port *mpt2sas_port;
484         unsigned long flags;
485         struct _sas_node *sas_node;
486         struct sas_rphy *rphy;
487         int i;
488         struct sas_port *port;
489
490         mpt2sas_port = kzalloc(sizeof(struct _sas_port),
491             GFP_KERNEL);
492         if (!mpt2sas_port) {
493                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
494                     ioc->name, __FILE__, __LINE__, __func__);
495                 return NULL;
496         }
497
498         INIT_LIST_HEAD(&mpt2sas_port->port_list);
499         INIT_LIST_HEAD(&mpt2sas_port->phy_list);
500         spin_lock_irqsave(&ioc->sas_node_lock, flags);
501         sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
502         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
503
504         if (!sas_node) {
505                 printk(MPT2SAS_ERR_FMT "%s: Could not find "
506                     "parent sas_address(0x%016llx)!\n", ioc->name,
507                     __func__, (unsigned long long)sas_address);
508                 goto out_fail;
509         }
510
511         if ((_transport_set_identify(ioc, handle,
512             &mpt2sas_port->remote_identify))) {
513                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
514                     ioc->name, __FILE__, __LINE__, __func__);
515                 goto out_fail;
516         }
517
518         if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
519                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
520                     ioc->name, __FILE__, __LINE__, __func__);
521                 goto out_fail;
522         }
523
524         for (i = 0; i < sas_node->num_phys; i++) {
525                 if (sas_node->phy[i].remote_identify.sas_address !=
526                     mpt2sas_port->remote_identify.sas_address)
527                         continue;
528                 list_add_tail(&sas_node->phy[i].port_siblings,
529                     &mpt2sas_port->phy_list);
530                 mpt2sas_port->num_phys++;
531         }
532
533         if (!mpt2sas_port->num_phys) {
534                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
535                     ioc->name, __FILE__, __LINE__, __func__);
536                 goto out_fail;
537         }
538
539         port = sas_port_alloc_num(sas_node->parent_dev);
540         if ((sas_port_add(port))) {
541                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
542                     ioc->name, __FILE__, __LINE__, __func__);
543                 goto out_fail;
544         }
545
546         list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
547             port_siblings) {
548                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
549                         dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
550                             ", sas_addr(0x%016llx), phy(%d)\n", handle,
551                             (unsigned long long)
552                             mpt2sas_port->remote_identify.sas_address,
553                             mpt2sas_phy->phy_id);
554                 sas_port_add_phy(port, mpt2sas_phy->phy);
555         }
556
557         mpt2sas_port->port = port;
558         if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
559                 rphy = sas_end_device_alloc(port);
560         else
561                 rphy = sas_expander_alloc(port,
562                     mpt2sas_port->remote_identify.device_type);
563
564         rphy->identify = mpt2sas_port->remote_identify;
565         if ((sas_rphy_add(rphy))) {
566                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
567                     ioc->name, __FILE__, __LINE__, __func__);
568         }
569         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
570                 dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
571                     "sas_addr(0x%016llx)\n", handle,
572                     (unsigned long long)
573                     mpt2sas_port->remote_identify.sas_address);
574         mpt2sas_port->rphy = rphy;
575         spin_lock_irqsave(&ioc->sas_node_lock, flags);
576         list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
577         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
578
579         /* fill in report manufacture */
580         if (mpt2sas_port->remote_identify.device_type ==
581             MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
582             mpt2sas_port->remote_identify.device_type ==
583             MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
584                 _transport_expander_report_manufacture(ioc,
585                     mpt2sas_port->remote_identify.sas_address,
586                     rphy_to_expander_device(rphy));
587
588         return mpt2sas_port;
589
590  out_fail:
591         list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
592             port_siblings)
593                 list_del(&mpt2sas_phy->port_siblings);
594         kfree(mpt2sas_port);
595         return NULL;
596 }
597
598 /**
599  * mpt2sas_transport_port_remove - remove port from the list
600  * @ioc: per adapter object
601  * @sas_address: sas address of attached device
602  * @sas_address_parent: sas address of parent expander or sas host
603  * Context: This function will acquire ioc->sas_node_lock.
604  *
605  * Removing object and freeing associated memory from the
606  * ioc->sas_port_list.
607  *
608  * Return nothing.
609  */
610 void
611 mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
612     u64 sas_address_parent)
613 {
614         int i;
615         unsigned long flags;
616         struct _sas_port *mpt2sas_port, *next;
617         struct _sas_node *sas_node;
618         u8 found = 0;
619         struct _sas_phy *mpt2sas_phy, *next_phy;
620
621         spin_lock_irqsave(&ioc->sas_node_lock, flags);
622         sas_node = _transport_sas_node_find_by_sas_address(ioc,
623             sas_address_parent);
624         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
625         if (!sas_node)
626                 return;
627         list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
628             port_list) {
629                 if (mpt2sas_port->remote_identify.sas_address != sas_address)
630                         continue;
631                 found = 1;
632                 list_del(&mpt2sas_port->port_list);
633                 goto out;
634         }
635  out:
636         if (!found)
637                 return;
638
639         for (i = 0; i < sas_node->num_phys; i++) {
640                 if (sas_node->phy[i].remote_identify.sas_address == sas_address)
641                         memset(&sas_node->phy[i].remote_identify, 0 ,
642                             sizeof(struct sas_identify));
643         }
644
645         list_for_each_entry_safe(mpt2sas_phy, next_phy,
646             &mpt2sas_port->phy_list, port_siblings) {
647                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
648                         dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
649                             "remove: sas_addr(0x%016llx), phy(%d)\n",
650                             (unsigned long long)
651                             mpt2sas_port->remote_identify.sas_address,
652                             mpt2sas_phy->phy_id);
653                 sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
654                 list_del(&mpt2sas_phy->port_siblings);
655         }
656         sas_port_delete(mpt2sas_port->port);
657         kfree(mpt2sas_port);
658 }
659
660 /**
661  * mpt2sas_transport_add_host_phy - report sas_host phy to transport
662  * @ioc: per adapter object
663  * @mpt2sas_phy: mpt2sas per phy object
664  * @phy_pg0: sas phy page 0
665  * @parent_dev: parent device class object
666  *
667  * Returns 0 for success, non-zero for failure.
668  */
669 int
670 mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
671     *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
672 {
673         struct sas_phy *phy;
674         int phy_index = mpt2sas_phy->phy_id;
675
676
677         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
678         phy = sas_phy_alloc(parent_dev, phy_index);
679         if (!phy) {
680                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
681                     ioc->name, __FILE__, __LINE__, __func__);
682                 return -1;
683         }
684         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
685             &mpt2sas_phy->identify))) {
686                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
687                     ioc->name, __FILE__, __LINE__, __func__);
688                 return -1;
689         }
690         phy->identify = mpt2sas_phy->identify;
691         mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
692         if (mpt2sas_phy->attached_handle)
693                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
694                     &mpt2sas_phy->remote_identify);
695         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
696         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
697             phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
698         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
699             phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
700         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
701             phy_pg0.HwLinkRate >> 4);
702         phy->minimum_linkrate = _transport_convert_phy_link_rate(
703             phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
704         phy->maximum_linkrate = _transport_convert_phy_link_rate(
705             phy_pg0.ProgrammedLinkRate >> 4);
706
707         if ((sas_phy_add(phy))) {
708                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
709                     ioc->name, __FILE__, __LINE__, __func__);
710                 sas_phy_free(phy);
711                 return -1;
712         }
713         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
714                 dev_printk(KERN_INFO, &phy->dev,
715                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
716                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
717                     mpt2sas_phy->handle, (unsigned long long)
718                     mpt2sas_phy->identify.sas_address,
719                     mpt2sas_phy->attached_handle,
720                     (unsigned long long)
721                     mpt2sas_phy->remote_identify.sas_address);
722         mpt2sas_phy->phy = phy;
723         return 0;
724 }
725
726
727 /**
728  * mpt2sas_transport_add_expander_phy - report expander phy to transport
729  * @ioc: per adapter object
730  * @mpt2sas_phy: mpt2sas per phy object
731  * @expander_pg1: expander page 1
732  * @parent_dev: parent device class object
733  *
734  * Returns 0 for success, non-zero for failure.
735  */
736 int
737 mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
738     *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
739 {
740         struct sas_phy *phy;
741         int phy_index = mpt2sas_phy->phy_id;
742
743         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
744         phy = sas_phy_alloc(parent_dev, phy_index);
745         if (!phy) {
746                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
747                     ioc->name, __FILE__, __LINE__, __func__);
748                 return -1;
749         }
750         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
751             &mpt2sas_phy->identify))) {
752                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
753                     ioc->name, __FILE__, __LINE__, __func__);
754                 return -1;
755         }
756         phy->identify = mpt2sas_phy->identify;
757         mpt2sas_phy->attached_handle =
758             le16_to_cpu(expander_pg1.AttachedDevHandle);
759         if (mpt2sas_phy->attached_handle)
760                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
761                     &mpt2sas_phy->remote_identify);
762         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
763         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
764             expander_pg1.NegotiatedLinkRate &
765             MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
766         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
767             expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
768         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
769             expander_pg1.HwLinkRate >> 4);
770         phy->minimum_linkrate = _transport_convert_phy_link_rate(
771             expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
772         phy->maximum_linkrate = _transport_convert_phy_link_rate(
773             expander_pg1.ProgrammedLinkRate >> 4);
774
775         if ((sas_phy_add(phy))) {
776                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
777                     ioc->name, __FILE__, __LINE__, __func__);
778                 sas_phy_free(phy);
779                 return -1;
780         }
781         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
782                 dev_printk(KERN_INFO, &phy->dev,
783                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
784                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
785                     mpt2sas_phy->handle, (unsigned long long)
786                     mpt2sas_phy->identify.sas_address,
787                     mpt2sas_phy->attached_handle,
788                     (unsigned long long)
789                     mpt2sas_phy->remote_identify.sas_address);
790         mpt2sas_phy->phy = phy;
791         return 0;
792 }
793
794 /**
795  * mpt2sas_transport_update_links - refreshing phy link changes
796  * @ioc: per adapter object
797  * @sas_address: sas address of parent expander or sas host
798  * @handle: attached device handle
799  * @phy_numberv: phy number
800  * @link_rate: new link rate
801  *
802  * Returns nothing.
803  */
804 void
805 mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
806      u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
807 {
808         unsigned long flags;
809         struct _sas_node *sas_node;
810         struct _sas_phy *mpt2sas_phy;
811
812         if (ioc->shost_recovery)
813                 return;
814
815         spin_lock_irqsave(&ioc->sas_node_lock, flags);
816         sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
817         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
818         if (!sas_node)
819                 return;
820
821         mpt2sas_phy = &sas_node->phy[phy_number];
822         mpt2sas_phy->attached_handle = handle;
823         if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
824                 _transport_set_identify(ioc, handle,
825                     &mpt2sas_phy->remote_identify);
826         else
827                 memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
828                     sas_identify));
829
830         if (mpt2sas_phy->phy)
831                 mpt2sas_phy->phy->negotiated_linkrate =
832                     _transport_convert_phy_link_rate(link_rate);
833
834         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
835                 dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
836                     "refresh: parent sas_addr(0x%016llx),\n"
837                     "\tlink_rate(0x%02x), phy(%d)\n"
838                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
839                     (unsigned long long)sas_address,
840                     link_rate, phy_number, handle, (unsigned long long)
841                     mpt2sas_phy->remote_identify.sas_address);
842 }
843
844 static inline void *
845 phy_to_ioc(struct sas_phy *phy)
846 {
847         struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
848         return shost_priv(shost);
849 }
850
851 static inline void *
852 rphy_to_ioc(struct sas_rphy *rphy)
853 {
854         struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
855         return shost_priv(shost);
856 }
857
858 static struct _sas_phy *
859 _transport_find_local_phy(struct MPT2SAS_ADAPTER *ioc, struct sas_phy *phy)
860 {
861         int i;
862
863         for (i = 0; i < ioc->sas_hba.num_phys; i++)
864                 if (ioc->sas_hba.phy[i].phy == phy)
865                         return(&ioc->sas_hba.phy[i]);
866         return NULL;
867 }
868
869 /**
870  * _transport_get_linkerrors -
871  * @phy: The sas phy object
872  *
873  * Only support sas_host direct attached phys.
874  * Returns 0 for success, non-zero for failure.
875  *
876  */
877 static int
878 _transport_get_linkerrors(struct sas_phy *phy)
879 {
880         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
881         struct _sas_phy *mpt2sas_phy;
882         Mpi2ConfigReply_t mpi_reply;
883         Mpi2SasPhyPage1_t phy_pg1;
884
885         mpt2sas_phy = _transport_find_local_phy(ioc, phy);
886
887         if (!mpt2sas_phy) /* this phy not on sas_host */
888                 return -EINVAL;
889
890         if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
891                     mpt2sas_phy->phy_id))) {
892                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
893                     ioc->name, __FILE__, __LINE__, __func__);
894                 return -ENXIO;
895         }
896
897         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
898                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
899                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
900                     mpt2sas_phy->phy_id,
901                     le16_to_cpu(mpi_reply.IOCStatus),
902                     le32_to_cpu(mpi_reply.IOCLogInfo));
903
904         phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
905         phy->running_disparity_error_count =
906             le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
907         phy->loss_of_dword_sync_count =
908             le32_to_cpu(phy_pg1.LossDwordSynchCount);
909         phy->phy_reset_problem_count =
910             le32_to_cpu(phy_pg1.PhyResetProblemCount);
911         return 0;
912 }
913
914 /**
915  * _transport_get_enclosure_identifier -
916  * @phy: The sas phy object
917  *
918  * Obtain the enclosure logical id for an expander.
919  * Returns 0 for success, non-zero for failure.
920  */
921 static int
922 _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
923 {
924         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
925         struct _sas_node *sas_expander;
926         unsigned long flags;
927
928         spin_lock_irqsave(&ioc->sas_node_lock, flags);
929         sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
930             rphy->identify.sas_address);
931         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
932
933         if (!sas_expander)
934                 return -ENXIO;
935
936         *identifier = sas_expander->enclosure_logical_id;
937         return 0;
938 }
939
940 /**
941  * _transport_get_bay_identifier -
942  * @phy: The sas phy object
943  *
944  * Returns the slot id for a device that resides inside an enclosure.
945  */
946 static int
947 _transport_get_bay_identifier(struct sas_rphy *rphy)
948 {
949         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
950         struct _sas_device *sas_device;
951         unsigned long flags;
952
953         spin_lock_irqsave(&ioc->sas_device_lock, flags);
954         sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
955             rphy->identify.sas_address);
956         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
957
958         if (!sas_device)
959                 return -ENXIO;
960
961         return sas_device->slot;
962 }
963
964 /**
965  * _transport_phy_reset -
966  * @phy: The sas phy object
967  * @hard_reset:
968  *
969  * Only support sas_host direct attached phys.
970  * Returns 0 for success, non-zero for failure.
971  */
972 static int
973 _transport_phy_reset(struct sas_phy *phy, int hard_reset)
974 {
975         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
976         struct _sas_phy *mpt2sas_phy;
977         Mpi2SasIoUnitControlReply_t mpi_reply;
978         Mpi2SasIoUnitControlRequest_t mpi_request;
979
980         mpt2sas_phy = _transport_find_local_phy(ioc, phy);
981
982         if (!mpt2sas_phy) /* this phy not on sas_host */
983                 return -EINVAL;
984
985         memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
986         mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
987         mpi_request.Operation = hard_reset ?
988             MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
989         mpi_request.PhyNum = mpt2sas_phy->phy_id;
990
991         if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
992                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
993                     ioc->name, __FILE__, __LINE__, __func__);
994                 return -ENXIO;
995         }
996
997         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
998                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
999                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
1000                     mpt2sas_phy->phy_id,
1001                     le16_to_cpu(mpi_reply.IOCStatus),
1002                     le32_to_cpu(mpi_reply.IOCLogInfo));
1003
1004         return 0;
1005 }
1006
1007 /**
1008  * _transport_phy_enable - enable/disable phys
1009  * @phy: The sas phy object
1010  * @enable: enable phy when true
1011  *
1012  * Only support sas_host direct attached phys.
1013  * Returns 0 for success, non-zero for failure.
1014  */
1015 static int
1016 _transport_phy_enable(struct sas_phy *phy, int enable)
1017 {
1018         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1019         struct _sas_phy *mpt2sas_phy;
1020         Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1021         Mpi2ConfigReply_t mpi_reply;
1022         u16 ioc_status;
1023         u16 sz;
1024         int rc = 0;
1025
1026         mpt2sas_phy = _transport_find_local_phy(ioc, phy);
1027
1028         if (!mpt2sas_phy) /* this phy not on sas_host */
1029                 return -EINVAL;
1030
1031         /* sas_iounit page 1 */
1032         sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1033             sizeof(Mpi2SasIOUnit1PhyData_t));
1034         sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1035         if (!sas_iounit_pg1) {
1036                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1037                     ioc->name, __FILE__, __LINE__, __func__);
1038                 rc = -ENOMEM;
1039                 goto out;
1040         }
1041         if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1042             sas_iounit_pg1, sz))) {
1043                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1044                     ioc->name, __FILE__, __LINE__, __func__);
1045                 rc = -ENXIO;
1046                 goto out;
1047         }
1048         ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1049             MPI2_IOCSTATUS_MASK;
1050         if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1051                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1052                     ioc->name, __FILE__, __LINE__, __func__);
1053                 rc = -EIO;
1054                 goto out;
1055         }
1056
1057         if (enable)
1058                 sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
1059                     &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1060         else
1061                 sas_iounit_pg1->PhyData[mpt2sas_phy->phy_id].PhyFlags
1062                     |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1063
1064         mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
1065
1066  out:
1067         kfree(sas_iounit_pg1);
1068         return rc;
1069 }
1070
1071 /**
1072  * _transport_phy_speed - set phy min/max link rates
1073  * @phy: The sas phy object
1074  * @rates: rates defined in sas_phy_linkrates
1075  *
1076  * Only support sas_host direct attached phys.
1077  * Returns 0 for success, non-zero for failure.
1078  */
1079 static int
1080 _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
1081 {
1082         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1083         struct _sas_phy *mpt2sas_phy;
1084         Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1085         Mpi2SasPhyPage0_t phy_pg0;
1086         Mpi2ConfigReply_t mpi_reply;
1087         u16 ioc_status;
1088         u16 sz;
1089         int i;
1090         int rc = 0;
1091
1092         mpt2sas_phy = _transport_find_local_phy(ioc, phy);
1093
1094         if (!mpt2sas_phy) /* this phy not on sas_host */
1095                 return -EINVAL;
1096
1097         if (!rates->minimum_linkrate)
1098                 rates->minimum_linkrate = phy->minimum_linkrate;
1099         else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
1100                 rates->minimum_linkrate = phy->minimum_linkrate_hw;
1101
1102         if (!rates->maximum_linkrate)
1103                 rates->maximum_linkrate = phy->maximum_linkrate;
1104         else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
1105                 rates->maximum_linkrate = phy->maximum_linkrate_hw;
1106
1107         /* sas_iounit page 1 */
1108         sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1109             sizeof(Mpi2SasIOUnit1PhyData_t));
1110         sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1111         if (!sas_iounit_pg1) {
1112                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1113                     ioc->name, __FILE__, __LINE__, __func__);
1114                 rc = -ENOMEM;
1115                 goto out;
1116         }
1117         if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1118             sas_iounit_pg1, sz))) {
1119                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1120                     ioc->name, __FILE__, __LINE__, __func__);
1121                 rc = -ENXIO;
1122                 goto out;
1123         }
1124         ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1125             MPI2_IOCSTATUS_MASK;
1126         if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1127                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1128                     ioc->name, __FILE__, __LINE__, __func__);
1129                 rc = -EIO;
1130                 goto out;
1131         }
1132
1133         for (i = 0; i < ioc->sas_hba.num_phys; i++) {
1134                 if (mpt2sas_phy->phy_id != i) {
1135                         sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1136                             (ioc->sas_hba.phy[i].phy->minimum_linkrate +
1137                             (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
1138                 } else {
1139                         sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1140                             (rates->minimum_linkrate +
1141                             (rates->maximum_linkrate << 4));
1142                 }
1143         }
1144
1145         if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
1146             sz)) {
1147                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1148                     ioc->name, __FILE__, __LINE__, __func__);
1149                 rc = -ENXIO;
1150                 goto out;
1151         }
1152
1153         /* link reset */
1154         _transport_phy_reset(phy, 0);
1155
1156         /* read phy page 0, then update the rates in the sas transport phy */
1157         if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
1158             mpt2sas_phy->phy_id)) {
1159                 phy->minimum_linkrate = _transport_convert_phy_link_rate(
1160                     phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
1161                 phy->maximum_linkrate = _transport_convert_phy_link_rate(
1162                     phy_pg0.ProgrammedLinkRate >> 4);
1163                 phy->negotiated_linkrate = _transport_convert_phy_link_rate(
1164                     phy_pg0.NegotiatedLinkRate &
1165                     MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
1166         }
1167
1168  out:
1169         kfree(sas_iounit_pg1);
1170         return rc;
1171 }
1172
1173
1174 /**
1175  * _transport_smp_handler - transport portal for smp passthru
1176  * @shost: shost object
1177  * @rphy: sas transport rphy object
1178  * @req:
1179  *
1180  * This used primarily for smp_utils.
1181  * Example:
1182  *           smp_rep_general /sys/class/bsg/expander-5:0
1183  */
1184 static int
1185 _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1186     struct request *req)
1187 {
1188         struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1189         Mpi2SmpPassthroughRequest_t *mpi_request;
1190         Mpi2SmpPassthroughReply_t *mpi_reply;
1191         int rc;
1192         u16 smid;
1193         u32 ioc_state;
1194         unsigned long timeleft;
1195         void *psge;
1196         u32 sgl_flags;
1197         u8 issue_reset = 0;
1198         dma_addr_t dma_addr_in = 0;
1199         dma_addr_t dma_addr_out = 0;
1200         u16 wait_state_count;
1201         struct request *rsp = req->next_rq;
1202
1203         if (!rsp) {
1204                 printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
1205                     "missing\n", ioc->name, __func__);
1206                 return -EINVAL;
1207         }
1208
1209         /* do we need to support multiple segments? */
1210         if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1211                 printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
1212                     "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
1213                     blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
1214                 return -EINVAL;
1215         }
1216
1217         if (ioc->shost_recovery) {
1218                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1219                     __func__, ioc->name);
1220                 return -EFAULT;
1221         }
1222
1223         rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
1224         if (rc)
1225                 return rc;
1226
1227         if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1228                 printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
1229                     __func__);
1230                 rc = -EAGAIN;
1231                 goto out;
1232         }
1233         ioc->transport_cmds.status = MPT2_CMD_PENDING;
1234
1235         wait_state_count = 0;
1236         ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1237         while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1238                 if (wait_state_count++ == 10) {
1239                         printk(MPT2SAS_ERR_FMT
1240                             "%s: failed due to ioc not operational\n",
1241                             ioc->name, __func__);
1242                         rc = -EFAULT;
1243                         goto out;
1244                 }
1245                 ssleep(1);
1246                 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1247                 printk(MPT2SAS_INFO_FMT "%s: waiting for "
1248                     "operational state(count=%d)\n", ioc->name,
1249                     __func__, wait_state_count);
1250         }
1251         if (wait_state_count)
1252                 printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1253                     ioc->name, __func__);
1254
1255         smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1256         if (!smid) {
1257                 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1258                     ioc->name, __func__);
1259                 rc = -EAGAIN;
1260                 goto out;
1261         }
1262
1263         rc = 0;
1264         mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1265         ioc->transport_cmds.smid = smid;
1266
1267         memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1268         mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1269         mpi_request->PhysicalPort = 0xFF;
1270         mpi_request->VF_ID = 0; /* TODO */
1271         mpi_request->VP_ID = 0;
1272         *((u64 *)&mpi_request->SASAddress) = (rphy) ?
1273             cpu_to_le64(rphy->identify.sas_address) :
1274             cpu_to_le64(ioc->sas_hba.sas_address);
1275         mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
1276         psge = &mpi_request->SGL;
1277
1278         /* WRITE sgel first */
1279         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1280             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1281         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1282         dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
1283                 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
1284         if (!dma_addr_out) {
1285                 mpt2sas_base_free_smid(ioc, smid);
1286                 goto unmap;
1287         }
1288
1289         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
1290             dma_addr_out);
1291
1292         /* incr sgel */
1293         psge += ioc->sge_size;
1294
1295         /* READ sgel last */
1296         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1297             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1298             MPI2_SGE_FLAGS_END_OF_LIST);
1299         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1300         dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
1301                                      blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
1302         if (!dma_addr_in) {
1303                 mpt2sas_base_free_smid(ioc, smid);
1304                 goto unmap;
1305         }
1306
1307         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
1308             dma_addr_in);
1309
1310         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1311             "sending smp request\n", ioc->name, __func__));
1312
1313         mpt2sas_base_put_smid_default(ioc, smid);
1314         init_completion(&ioc->transport_cmds.done);
1315         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1316             10*HZ);
1317
1318         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1319                 printk(MPT2SAS_ERR_FMT "%s : timeout\n",
1320                     __func__, ioc->name);
1321                 _debug_dump_mf(mpi_request,
1322                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
1323                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1324                         issue_reset = 1;
1325                 goto issue_host_reset;
1326         }
1327
1328         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1329             "complete\n", ioc->name, __func__));
1330
1331         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1332
1333                 mpi_reply = ioc->transport_cmds.reply;
1334
1335                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1336                     "%s - reply data transfer size(%d)\n",
1337                     ioc->name, __func__,
1338                     le16_to_cpu(mpi_reply->ResponseDataLength)));
1339
1340                 memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
1341                 req->sense_len = sizeof(*mpi_reply);
1342                 req->resid_len = 0;
1343                 rsp->resid_len -= mpi_reply->ResponseDataLength;
1344         } else {
1345                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1346                     "%s - no reply\n", ioc->name, __func__));
1347                 rc = -ENXIO;
1348         }
1349
1350  issue_host_reset:
1351         if (issue_reset) {
1352                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1353                     FORCE_BIG_HAMMER);
1354                 rc = -ETIMEDOUT;
1355         }
1356
1357  unmap:
1358         if (dma_addr_out)
1359                 pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
1360                     PCI_DMA_BIDIRECTIONAL);
1361         if (dma_addr_in)
1362                 pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
1363                     PCI_DMA_BIDIRECTIONAL);
1364
1365  out:
1366         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
1367         mutex_unlock(&ioc->transport_cmds.mutex);
1368         return rc;
1369 }
1370
1371 struct sas_function_template mpt2sas_transport_functions = {
1372         .get_linkerrors         = _transport_get_linkerrors,
1373         .get_enclosure_identifier = _transport_get_enclosure_identifier,
1374         .get_bay_identifier     = _transport_get_bay_identifier,
1375         .phy_reset              = _transport_phy_reset,
1376         .phy_enable             = _transport_phy_enable,
1377         .set_phy_speed          = _transport_phy_speed,
1378         .smp_handler            = _transport_smp_handler,
1379 };
1380
1381 struct scsi_transport_template *mpt2sas_transport_template;