[SCSI] mpt2sas: Copyright change to 2009.
[safe/jmp/linux-2.6] / 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_handle - sas node search
63  * @ioc: per adapter object
64  * @handle: expander or hba handle (assigned by firmware)
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_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
72 {
73         int i;
74
75         for (i = 0; i < ioc->sas_hba.num_phys; i++)
76                 if (ioc->sas_hba.phy[i].handle == handle)
77                         return &ioc->sas_hba;
78
79         return mpt2sas_scsih_expander_find_by_handle(ioc, handle);
80 }
81
82 /**
83  * _transport_convert_phy_link_rate -
84  * @link_rate: link rate returned from mpt firmware
85  *
86  * Convert link_rate from mpi fusion into sas_transport form.
87  */
88 static enum sas_linkrate
89 _transport_convert_phy_link_rate(u8 link_rate)
90 {
91         enum sas_linkrate rc;
92
93         switch (link_rate) {
94         case MPI2_SAS_NEG_LINK_RATE_1_5:
95                 rc = SAS_LINK_RATE_1_5_GBPS;
96                 break;
97         case MPI2_SAS_NEG_LINK_RATE_3_0:
98                 rc = SAS_LINK_RATE_3_0_GBPS;
99                 break;
100         case MPI2_SAS_NEG_LINK_RATE_6_0:
101                 rc = SAS_LINK_RATE_6_0_GBPS;
102                 break;
103         case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
104                 rc = SAS_PHY_DISABLED;
105                 break;
106         case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
107                 rc = SAS_LINK_RATE_FAILED;
108                 break;
109         case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
110                 rc = SAS_SATA_PORT_SELECTOR;
111                 break;
112         case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
113                 rc = SAS_PHY_RESET_IN_PROGRESS;
114                 break;
115         default:
116         case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
117         case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
118                 rc = SAS_LINK_RATE_UNKNOWN;
119                 break;
120         }
121         return rc;
122 }
123
124 /**
125  * _transport_set_identify - set identify for phys and end devices
126  * @ioc: per adapter object
127  * @handle: device handle
128  * @identify: sas identify info
129  *
130  * Populates sas identify info.
131  *
132  * Returns 0 for success, non-zero for failure.
133  */
134 static int
135 _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
136     struct sas_identify *identify)
137 {
138         Mpi2SasDevicePage0_t sas_device_pg0;
139         Mpi2ConfigReply_t mpi_reply;
140         u32 device_info;
141         u32 ioc_status;
142
143         if (ioc->shost_recovery) {
144                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
145                     __func__, ioc->name);
146                 return -EFAULT;
147         }
148
149         if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
150             MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
151                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
152
153                     ioc->name, __FILE__, __LINE__, __func__);
154                 return -ENXIO;
155         }
156
157         ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
158             MPI2_IOCSTATUS_MASK;
159         if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
160                 printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
161                     "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
162                      __FILE__, __LINE__, __func__);
163                 return -EIO;
164         }
165
166         memset(identify, 0, sizeof(identify));
167         device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
168
169         /* sas_address */
170         identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
171
172         /* device_type */
173         switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
174         case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
175                 identify->device_type = SAS_PHY_UNUSED;
176                 break;
177         case MPI2_SAS_DEVICE_INFO_END_DEVICE:
178                 identify->device_type = SAS_END_DEVICE;
179                 break;
180         case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
181                 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
182                 break;
183         case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
184                 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
185                 break;
186         }
187
188         /* initiator_port_protocols */
189         if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
190                 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
191         if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
192                 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
193         if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
194                 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
195         if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
196                 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
197
198         /* target_port_protocols */
199         if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
200                 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
201         if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
202                 identify->target_port_protocols |= SAS_PROTOCOL_STP;
203         if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
204                 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
205         if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
206                 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
207
208         return 0;
209 }
210
211 /**
212  * mpt2sas_transport_done -  internal transport layer callback handler.
213  * @ioc: per adapter object
214  * @smid: system request message index
215  * @msix_index: MSIX table index supplied by the OS
216  * @reply: reply message frame(lower 32bit addr)
217  *
218  * Callback handler when sending internal generated transport cmds.
219  * The callback index passed is `ioc->transport_cb_idx`
220  *
221  * Return nothing.
222  */
223 void
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;
232         if (ioc->transport_cmds.smid != smid)
233                 return;
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 }
243
244 /* report manufacture request structure */
245 struct rep_manu_request{
246         u8 smp_frame_type;
247         u8 function;
248         u8 reserved;
249         u8 request_length;
250 };
251
252 /* report manufacture reply structure */
253 struct rep_manu_reply{
254         u8 smp_frame_type; /* 0x41 */
255         u8 function; /* 0x01 */
256         u8 function_result;
257         u8 response_length;
258         u16 expander_change_count;
259         u8 reserved0[2];
260         u8 sas_format:1;
261         u8 reserved1:7;
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 = sizeof(struct rep_manu_request);
377         psge = &mpi_request->SGL;
378
379         /* WRITE sgel first */
380         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
381             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
382         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
383         ioc->base_add_sg_single(psge, sgl_flags |
384             sizeof(struct rep_manu_request), data_out_dma);
385
386         /* incr sgel */
387         psge += ioc->sge_size;
388
389         /* READ sgel last */
390         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
391             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
392             MPI2_SGE_FLAGS_END_OF_LIST);
393         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
394         ioc->base_add_sg_single(psge, sgl_flags |
395             sizeof(struct rep_manu_reply), data_out_dma +
396             sizeof(struct rep_manu_request));
397
398         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
399             "send to sas_addr(0x%016llx)\n", ioc->name,
400             (unsigned long long)sas_address));
401         mpt2sas_base_put_smid_default(ioc, smid);
402         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
403             10*HZ);
404
405         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
406                 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
407                     ioc->name, __func__);
408                 _debug_dump_mf(mpi_request,
409                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
410                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
411                         issue_reset = 1;
412                 goto issue_host_reset;
413         }
414
415         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
416             "complete\n", ioc->name));
417
418         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
419                 u8 *tmp;
420
421                 mpi_reply = ioc->transport_cmds.reply;
422
423                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
424                     "report_manufacture - reply data transfer size(%d)\n",
425                     ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
426
427                 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
428                     sizeof(struct rep_manu_reply))
429                         goto out;
430
431                 manufacture_reply = data_out + sizeof(struct rep_manu_request);
432                 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
433                      SAS_EXPANDER_VENDOR_ID_LEN);
434                 strncpy(edev->product_id, manufacture_reply->product_id,
435                      SAS_EXPANDER_PRODUCT_ID_LEN);
436                 strncpy(edev->product_rev, manufacture_reply->product_rev,
437                      SAS_EXPANDER_PRODUCT_REV_LEN);
438                 edev->level = manufacture_reply->sas_format;
439                 if (manufacture_reply->sas_format) {
440                         strncpy(edev->component_vendor_id,
441                             manufacture_reply->component_vendor_id,
442                              SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
443                         tmp = (u8 *)&manufacture_reply->component_id;
444                         edev->component_id = tmp[0] << 8 | tmp[1];
445                         edev->component_revision_id =
446                             manufacture_reply->component_revision_id;
447                 }
448         } else
449                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
450                     "report_manufacture - no reply\n", ioc->name));
451
452  issue_host_reset:
453         if (issue_reset)
454                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
455                     FORCE_BIG_HAMMER);
456  out:
457         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
458         if (data_out)
459                 pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
460
461         mutex_unlock(&ioc->transport_cmds.mutex);
462         return rc;
463 }
464
465 /**
466  * mpt2sas_transport_port_add - insert port to the list
467  * @ioc: per adapter object
468  * @handle: handle of attached device
469  * @parent_handle: parent handle(either hba or expander)
470  * Context: This function will acquire ioc->sas_node_lock.
471  *
472  * Adding new port object to the sas_node->sas_port_list.
473  *
474  * Returns mpt2sas_port.
475  */
476 struct _sas_port *
477 mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
478     u16 parent_handle)
479 {
480         struct _sas_phy *mpt2sas_phy, *next;
481         struct _sas_port *mpt2sas_port;
482         unsigned long flags;
483         struct _sas_node *sas_node;
484         struct sas_rphy *rphy;
485         int i;
486         struct sas_port *port;
487
488         if (!parent_handle)
489                 return NULL;
490
491         mpt2sas_port = kzalloc(sizeof(struct _sas_port),
492             GFP_KERNEL);
493         if (!mpt2sas_port) {
494                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
495                     ioc->name, __FILE__, __LINE__, __func__);
496                 return NULL;
497         }
498
499         INIT_LIST_HEAD(&mpt2sas_port->port_list);
500         INIT_LIST_HEAD(&mpt2sas_port->phy_list);
501         spin_lock_irqsave(&ioc->sas_node_lock, flags);
502         sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
503         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
504
505         if (!sas_node) {
506                 printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
507                     ioc->name, __func__, parent_handle);
508                 goto out_fail;
509         }
510
511         mpt2sas_port->handle = parent_handle;
512         mpt2sas_port->sas_address = sas_node->sas_address;
513         if ((_transport_set_identify(ioc, handle,
514             &mpt2sas_port->remote_identify))) {
515                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
516                     ioc->name, __FILE__, __LINE__, __func__);
517                 goto out_fail;
518         }
519
520         if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
521                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
522                     ioc->name, __FILE__, __LINE__, __func__);
523                 goto out_fail;
524         }
525
526         for (i = 0; i < sas_node->num_phys; i++) {
527                 if (sas_node->phy[i].remote_identify.sas_address !=
528                     mpt2sas_port->remote_identify.sas_address)
529                         continue;
530                 list_add_tail(&sas_node->phy[i].port_siblings,
531                     &mpt2sas_port->phy_list);
532                 mpt2sas_port->num_phys++;
533         }
534
535         if (!mpt2sas_port->num_phys) {
536                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
537                     ioc->name, __FILE__, __LINE__, __func__);
538                 goto out_fail;
539         }
540
541         port = sas_port_alloc_num(sas_node->parent_dev);
542         if ((sas_port_add(port))) {
543                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
544                     ioc->name, __FILE__, __LINE__, __func__);
545                 goto out_fail;
546         }
547
548         list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
549             port_siblings) {
550                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
551                         dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
552                             ", sas_addr(0x%016llx), phy(%d)\n", handle,
553                             (unsigned long long)
554                             mpt2sas_port->remote_identify.sas_address,
555                             mpt2sas_phy->phy_id);
556                 sas_port_add_phy(port, mpt2sas_phy->phy);
557         }
558
559         mpt2sas_port->port = port;
560         if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
561                 rphy = sas_end_device_alloc(port);
562         else
563                 rphy = sas_expander_alloc(port,
564                     mpt2sas_port->remote_identify.device_type);
565
566         rphy->identify = mpt2sas_port->remote_identify;
567         if ((sas_rphy_add(rphy))) {
568                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
569                     ioc->name, __FILE__, __LINE__, __func__);
570         }
571         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
572                 dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
573                     "sas_addr(0x%016llx)\n", handle,
574                     (unsigned long long)
575                     mpt2sas_port->remote_identify.sas_address);
576         mpt2sas_port->rphy = rphy;
577         spin_lock_irqsave(&ioc->sas_node_lock, flags);
578         list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
579         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
580
581         /* fill in report manufacture */
582         if (mpt2sas_port->remote_identify.device_type ==
583             MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
584             mpt2sas_port->remote_identify.device_type ==
585             MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
586                 _transport_expander_report_manufacture(ioc,
587                     mpt2sas_port->remote_identify.sas_address,
588                     rphy_to_expander_device(rphy));
589
590         return mpt2sas_port;
591
592  out_fail:
593         list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
594             port_siblings)
595                 list_del(&mpt2sas_phy->port_siblings);
596         kfree(mpt2sas_port);
597         return NULL;
598 }
599
600 /**
601  * mpt2sas_transport_port_remove - remove port from the list
602  * @ioc: per adapter object
603  * @sas_address: sas address of attached device
604  * @parent_handle: handle to the upstream parent(either hba or expander)
605  * Context: This function will acquire ioc->sas_node_lock.
606  *
607  * Removing object and freeing associated memory from the
608  * ioc->sas_port_list.
609  *
610  * Return nothing.
611  */
612 void
613 mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
614     u16 parent_handle)
615 {
616         int i;
617         unsigned long flags;
618         struct _sas_port *mpt2sas_port, *next;
619         struct _sas_node *sas_node;
620         u8 found = 0;
621         struct _sas_phy *mpt2sas_phy, *next_phy;
622
623         spin_lock_irqsave(&ioc->sas_node_lock, flags);
624         sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
625         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
626         if (!sas_node)
627                 return;
628         list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
629             port_list) {
630                 if (mpt2sas_port->remote_identify.sas_address != sas_address)
631                         continue;
632                 found = 1;
633                 list_del(&mpt2sas_port->port_list);
634                 goto out;
635         }
636  out:
637         if (!found)
638                 return;
639
640         for (i = 0; i < sas_node->num_phys; i++) {
641                 if (sas_node->phy[i].remote_identify.sas_address == sas_address)
642                         memset(&sas_node->phy[i].remote_identify, 0 ,
643                             sizeof(struct sas_identify));
644         }
645
646         list_for_each_entry_safe(mpt2sas_phy, next_phy,
647             &mpt2sas_port->phy_list, port_siblings) {
648                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
649                         dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
650                             "remove: parent_handle(0x%04x), "
651                             "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
652                             (unsigned long long)
653                             mpt2sas_port->remote_identify.sas_address,
654                             mpt2sas_phy->phy_id);
655                 sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
656                 list_del(&mpt2sas_phy->port_siblings);
657         }
658         sas_port_delete(mpt2sas_port->port);
659         kfree(mpt2sas_port);
660 }
661
662 /**
663  * mpt2sas_transport_add_host_phy - report sas_host phy to transport
664  * @ioc: per adapter object
665  * @mpt2sas_phy: mpt2sas per phy object
666  * @phy_pg0: sas phy page 0
667  * @parent_dev: parent device class object
668  *
669  * Returns 0 for success, non-zero for failure.
670  */
671 int
672 mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
673     *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
674 {
675         struct sas_phy *phy;
676         int phy_index = mpt2sas_phy->phy_id;
677
678
679         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
680         phy = sas_phy_alloc(parent_dev, phy_index);
681         if (!phy) {
682                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
683                     ioc->name, __FILE__, __LINE__, __func__);
684                 return -1;
685         }
686         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
687             &mpt2sas_phy->identify))) {
688                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
689                     ioc->name, __FILE__, __LINE__, __func__);
690                 return -1;
691         }
692         phy->identify = mpt2sas_phy->identify;
693         mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
694         if (mpt2sas_phy->attached_handle)
695                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
696                     &mpt2sas_phy->remote_identify);
697         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
698         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
699             phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
700         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
701             phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
702         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
703             phy_pg0.HwLinkRate >> 4);
704         phy->minimum_linkrate = _transport_convert_phy_link_rate(
705             phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
706         phy->maximum_linkrate = _transport_convert_phy_link_rate(
707             phy_pg0.ProgrammedLinkRate >> 4);
708
709         if ((sas_phy_add(phy))) {
710                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
711                     ioc->name, __FILE__, __LINE__, __func__);
712                 sas_phy_free(phy);
713                 return -1;
714         }
715         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
716                 dev_printk(KERN_INFO, &phy->dev,
717                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
718                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
719                     mpt2sas_phy->handle, (unsigned long long)
720                     mpt2sas_phy->identify.sas_address,
721                     mpt2sas_phy->attached_handle,
722                     (unsigned long long)
723                     mpt2sas_phy->remote_identify.sas_address);
724         mpt2sas_phy->phy = phy;
725         return 0;
726 }
727
728
729 /**
730  * mpt2sas_transport_add_expander_phy - report expander phy to transport
731  * @ioc: per adapter object
732  * @mpt2sas_phy: mpt2sas per phy object
733  * @expander_pg1: expander page 1
734  * @parent_dev: parent device class object
735  *
736  * Returns 0 for success, non-zero for failure.
737  */
738 int
739 mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
740     *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
741 {
742         struct sas_phy *phy;
743         int phy_index = mpt2sas_phy->phy_id;
744
745         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
746         phy = sas_phy_alloc(parent_dev, phy_index);
747         if (!phy) {
748                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
749                     ioc->name, __FILE__, __LINE__, __func__);
750                 return -1;
751         }
752         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
753             &mpt2sas_phy->identify))) {
754                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
755                     ioc->name, __FILE__, __LINE__, __func__);
756                 return -1;
757         }
758         phy->identify = mpt2sas_phy->identify;
759         mpt2sas_phy->attached_handle =
760             le16_to_cpu(expander_pg1.AttachedDevHandle);
761         if (mpt2sas_phy->attached_handle)
762                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
763                     &mpt2sas_phy->remote_identify);
764         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
765         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
766             expander_pg1.NegotiatedLinkRate &
767             MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
768         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
769             expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
770         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
771             expander_pg1.HwLinkRate >> 4);
772         phy->minimum_linkrate = _transport_convert_phy_link_rate(
773             expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
774         phy->maximum_linkrate = _transport_convert_phy_link_rate(
775             expander_pg1.ProgrammedLinkRate >> 4);
776
777         if ((sas_phy_add(phy))) {
778                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
779                     ioc->name, __FILE__, __LINE__, __func__);
780                 sas_phy_free(phy);
781                 return -1;
782         }
783         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
784                 dev_printk(KERN_INFO, &phy->dev,
785                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
786                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
787                     mpt2sas_phy->handle, (unsigned long long)
788                     mpt2sas_phy->identify.sas_address,
789                     mpt2sas_phy->attached_handle,
790                     (unsigned long long)
791                     mpt2sas_phy->remote_identify.sas_address);
792         mpt2sas_phy->phy = phy;
793         return 0;
794 }
795
796 /**
797  * mpt2sas_transport_update_links - refreshing phy link changes
798  * @ioc: per adapter object
799  * @handle: handle to sas_host or expander
800  * @attached_handle: attached device handle
801  * @phy_numberv: phy number
802  * @link_rate: new link rate
803  *
804  * Returns nothing.
805  */
806 void
807 mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
808     u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
809 {
810         unsigned long flags;
811         struct _sas_node *sas_node;
812         struct _sas_phy *mpt2sas_phy;
813
814         if (ioc->shost_recovery) {
815                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
816                         __func__, ioc->name);
817                 return;
818         }
819
820         spin_lock_irqsave(&ioc->sas_node_lock, flags);
821         sas_node = _transport_sas_node_find_by_handle(ioc, handle);
822         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
823         if (!sas_node)
824                 return;
825
826         mpt2sas_phy = &sas_node->phy[phy_number];
827         mpt2sas_phy->attached_handle = attached_handle;
828         if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
829                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
830                     &mpt2sas_phy->remote_identify);
831         else
832                 memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
833                     sas_identify));
834
835         if (mpt2sas_phy->phy)
836                 mpt2sas_phy->phy->negotiated_linkrate =
837                     _transport_convert_phy_link_rate(link_rate);
838
839         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
840                 dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
841                     "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
842                     "\tlink_rate(0x%02x), phy(%d)\n"
843                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
844                     handle, (unsigned long long)
845                     mpt2sas_phy->identify.sas_address, link_rate,
846                     phy_number, attached_handle,
847                     (unsigned long long)
848                     mpt2sas_phy->remote_identify.sas_address);
849 }
850
851 static inline void *
852 phy_to_ioc(struct sas_phy *phy)
853 {
854         struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
855         return shost_priv(shost);
856 }
857
858 static inline void *
859 rphy_to_ioc(struct sas_rphy *rphy)
860 {
861         struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
862         return shost_priv(shost);
863 }
864
865 /**
866  * _transport_get_linkerrors -
867  * @phy: The sas phy object
868  *
869  * Only support sas_host direct attached phys.
870  * Returns 0 for success, non-zero for failure.
871  *
872  */
873 static int
874 _transport_get_linkerrors(struct sas_phy *phy)
875 {
876         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
877         struct _sas_phy *mpt2sas_phy;
878         Mpi2ConfigReply_t mpi_reply;
879         Mpi2SasPhyPage1_t phy_pg1;
880         int i;
881
882         for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
883             !mpt2sas_phy; i++) {
884                 if (ioc->sas_hba.phy[i].phy != phy)
885                         continue;
886                 mpt2sas_phy = &ioc->sas_hba.phy[i];
887         }
888
889         if (!mpt2sas_phy) /* this phy not on sas_host */
890                 return -EINVAL;
891
892         if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
893                     mpt2sas_phy->phy_id))) {
894                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
895                     ioc->name, __FILE__, __LINE__, __func__);
896                 return -ENXIO;
897         }
898
899         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
900                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
901                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
902                     mpt2sas_phy->phy_id,
903                     le16_to_cpu(mpi_reply.IOCStatus),
904                     le32_to_cpu(mpi_reply.IOCLogInfo));
905
906         phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
907         phy->running_disparity_error_count =
908             le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
909         phy->loss_of_dword_sync_count =
910             le32_to_cpu(phy_pg1.LossDwordSynchCount);
911         phy->phy_reset_problem_count =
912             le32_to_cpu(phy_pg1.PhyResetProblemCount);
913         return 0;
914 }
915
916 /**
917  * _transport_get_enclosure_identifier -
918  * @phy: The sas phy object
919  *
920  * Obtain the enclosure logical id for an expander.
921  * Returns 0 for success, non-zero for failure.
922  */
923 static int
924 _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
925 {
926         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
927         struct _sas_node *sas_expander;
928         unsigned long flags;
929
930         spin_lock_irqsave(&ioc->sas_node_lock, flags);
931         sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
932             rphy->identify.sas_address);
933         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
934
935         if (!sas_expander)
936                 return -ENXIO;
937
938         *identifier = sas_expander->enclosure_logical_id;
939         return 0;
940 }
941
942 /**
943  * _transport_get_bay_identifier -
944  * @phy: The sas phy object
945  *
946  * Returns the slot id for a device that resides inside an enclosure.
947  */
948 static int
949 _transport_get_bay_identifier(struct sas_rphy *rphy)
950 {
951         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
952         struct _sas_device *sas_device;
953         unsigned long flags;
954
955         spin_lock_irqsave(&ioc->sas_device_lock, flags);
956         sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
957             rphy->identify.sas_address);
958         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
959
960         if (!sas_device)
961                 return -ENXIO;
962
963         return sas_device->slot;
964 }
965
966 /**
967  * _transport_phy_reset -
968  * @phy: The sas phy object
969  * @hard_reset:
970  *
971  * Only support sas_host direct attached phys.
972  * Returns 0 for success, non-zero for failure.
973  */
974 static int
975 _transport_phy_reset(struct sas_phy *phy, int hard_reset)
976 {
977         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
978         struct _sas_phy *mpt2sas_phy;
979         Mpi2SasIoUnitControlReply_t mpi_reply;
980         Mpi2SasIoUnitControlRequest_t mpi_request;
981         int i;
982
983         for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
984             !mpt2sas_phy; i++) {
985                 if (ioc->sas_hba.phy[i].phy != phy)
986                         continue;
987                 mpt2sas_phy = &ioc->sas_hba.phy[i];
988         }
989
990         if (!mpt2sas_phy) /* this phy not on sas_host */
991                 return -EINVAL;
992
993         memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
994         mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
995         mpi_request.Operation = hard_reset ?
996             MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
997         mpi_request.PhyNum = mpt2sas_phy->phy_id;
998
999         if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
1000                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1001                     ioc->name, __FILE__, __LINE__, __func__);
1002                 return -ENXIO;
1003         }
1004
1005         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
1006                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
1007                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
1008                     mpt2sas_phy->phy_id,
1009                     le16_to_cpu(mpi_reply.IOCStatus),
1010                     le32_to_cpu(mpi_reply.IOCLogInfo));
1011
1012         return 0;
1013 }
1014
1015 /**
1016  * _transport_smp_handler - transport portal for smp passthru
1017  * @shost: shost object
1018  * @rphy: sas transport rphy object
1019  * @req:
1020  *
1021  * This used primarily for smp_utils.
1022  * Example:
1023  *           smp_rep_general /sys/class/bsg/expander-5:0
1024  */
1025 static int
1026 _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1027     struct request *req)
1028 {
1029         struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1030         Mpi2SmpPassthroughRequest_t *mpi_request;
1031         Mpi2SmpPassthroughReply_t *mpi_reply;
1032         int rc;
1033         u16 smid;
1034         u32 ioc_state;
1035         unsigned long timeleft;
1036         void *psge;
1037         u32 sgl_flags;
1038         u8 issue_reset = 0;
1039         dma_addr_t dma_addr_in = 0;
1040         dma_addr_t dma_addr_out = 0;
1041         u16 wait_state_count;
1042         struct request *rsp = req->next_rq;
1043
1044         if (!rsp) {
1045                 printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
1046                     "missing\n", ioc->name, __func__);
1047                 return -EINVAL;
1048         }
1049
1050         /* do we need to support multiple segments? */
1051         if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1052                 printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
1053                     "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
1054                     blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
1055                 return -EINVAL;
1056         }
1057
1058         if (ioc->shost_recovery) {
1059                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1060                     __func__, ioc->name);
1061                 return -EFAULT;
1062         }
1063
1064         rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
1065         if (rc)
1066                 return rc;
1067
1068         if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1069                 printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
1070                     __func__);
1071                 rc = -EAGAIN;
1072                 goto out;
1073         }
1074         ioc->transport_cmds.status = MPT2_CMD_PENDING;
1075
1076         wait_state_count = 0;
1077         ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1078         while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1079                 if (wait_state_count++ == 10) {
1080                         printk(MPT2SAS_ERR_FMT
1081                             "%s: failed due to ioc not operational\n",
1082                             ioc->name, __func__);
1083                         rc = -EFAULT;
1084                         goto out;
1085                 }
1086                 ssleep(1);
1087                 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1088                 printk(MPT2SAS_INFO_FMT "%s: waiting for "
1089                     "operational state(count=%d)\n", ioc->name,
1090                     __func__, wait_state_count);
1091         }
1092         if (wait_state_count)
1093                 printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1094                     ioc->name, __func__);
1095
1096         smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1097         if (!smid) {
1098                 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1099                     ioc->name, __func__);
1100                 rc = -EAGAIN;
1101                 goto out;
1102         }
1103
1104         rc = 0;
1105         mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1106         ioc->transport_cmds.smid = smid;
1107
1108         memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1109         mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1110         mpi_request->PhysicalPort = 0xFF;
1111         mpi_request->VF_ID = 0; /* TODO */
1112         mpi_request->VP_ID = 0;
1113         *((u64 *)&mpi_request->SASAddress) = (rphy) ?
1114             cpu_to_le64(rphy->identify.sas_address) :
1115             cpu_to_le64(ioc->sas_hba.sas_address);
1116         mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
1117         psge = &mpi_request->SGL;
1118
1119         /* WRITE sgel first */
1120         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1121             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1122         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1123         dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
1124                 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
1125         if (!dma_addr_out) {
1126                 mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
1127                 goto unmap;
1128         }
1129
1130         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
1131             dma_addr_out);
1132
1133         /* incr sgel */
1134         psge += ioc->sge_size;
1135
1136         /* READ sgel last */
1137         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1138             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1139             MPI2_SGE_FLAGS_END_OF_LIST);
1140         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1141         dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
1142                                      blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
1143         if (!dma_addr_in) {
1144                 mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
1145                 goto unmap;
1146         }
1147
1148         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
1149             dma_addr_in);
1150
1151         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1152             "sending smp request\n", ioc->name, __func__));
1153
1154         mpt2sas_base_put_smid_default(ioc, smid);
1155         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1156             10*HZ);
1157
1158         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1159                 printk(MPT2SAS_ERR_FMT "%s : timeout\n",
1160                     __func__, ioc->name);
1161                 _debug_dump_mf(mpi_request,
1162                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
1163                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1164                         issue_reset = 1;
1165                 goto issue_host_reset;
1166         }
1167
1168         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1169             "complete\n", ioc->name, __func__));
1170
1171         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1172
1173                 mpi_reply = ioc->transport_cmds.reply;
1174
1175                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1176                     "%s - reply data transfer size(%d)\n",
1177                     ioc->name, __func__,
1178                     le16_to_cpu(mpi_reply->ResponseDataLength)));
1179
1180                 memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
1181                 req->sense_len = sizeof(*mpi_reply);
1182                 req->resid_len = 0;
1183                 rsp->resid_len -= mpi_reply->ResponseDataLength;
1184         } else {
1185                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1186                     "%s - no reply\n", ioc->name, __func__));
1187                 rc = -ENXIO;
1188         }
1189
1190  issue_host_reset:
1191         if (issue_reset) {
1192                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1193                     FORCE_BIG_HAMMER);
1194                 rc = -ETIMEDOUT;
1195         }
1196
1197  unmap:
1198         if (dma_addr_out)
1199                 pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
1200                     PCI_DMA_BIDIRECTIONAL);
1201         if (dma_addr_in)
1202                 pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
1203                     PCI_DMA_BIDIRECTIONAL);
1204
1205  out:
1206         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
1207         mutex_unlock(&ioc->transport_cmds.mutex);
1208         return rc;
1209 }
1210
1211 struct sas_function_template mpt2sas_transport_functions = {
1212         .get_linkerrors         = _transport_get_linkerrors,
1213         .get_enclosure_identifier = _transport_get_enclosure_identifier,
1214         .get_bay_identifier     = _transport_get_bay_identifier,
1215         .phy_reset              = _transport_phy_reset,
1216         .smp_handler            = _transport_smp_handler,
1217 };
1218
1219 struct scsi_transport_template *mpt2sas_transport_template;