]> Pileus Git - ~andy/linux/blob - drivers/scsi/mpt2sas/mpt2sas_transport.c
Merge branch 'x86-process-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[~andy/linux] / 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 1 meaning mf should be freed from _base_interrupt
222  *        0 means the mf is freed from this function.
223  */
224 u8
225 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
226     u32 reply)
227 {
228         MPI2DefaultReply_t *mpi_reply;
229
230         mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
231         if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
232                 return 1;
233         if (ioc->transport_cmds.smid != smid)
234                 return 1;
235         ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
236         if (mpi_reply) {
237                 memcpy(ioc->transport_cmds.reply, mpi_reply,
238                     mpi_reply->MsgLength*4);
239                 ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
240         }
241         ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
242         complete(&ioc->transport_cmds.done);
243         return 1;
244 }
245
246 /* report manufacture request structure */
247 struct rep_manu_request{
248         u8 smp_frame_type;
249         u8 function;
250         u8 reserved;
251         u8 request_length;
252 };
253
254 /* report manufacture reply structure */
255 struct rep_manu_reply{
256         u8 smp_frame_type; /* 0x41 */
257         u8 function; /* 0x01 */
258         u8 function_result;
259         u8 response_length;
260         u16 expander_change_count;
261         u8 reserved0[2];
262         u8 sas_format:1;
263         u8 reserved1:7;
264         u8 reserved2[3];
265         u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
266         u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
267         u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
268         u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
269         u16 component_id;
270         u8 component_revision_id;
271         u8 reserved3;
272         u8 vendor_specific[8];
273 };
274
275 /**
276  * _transport_expander_report_manufacture - obtain SMP report_manufacture
277  * @ioc: per adapter object
278  * @sas_address: expander sas address
279  * @edev: the sas_expander_device object
280  *
281  * Fills in the sas_expander_device object when SMP port is created.
282  *
283  * Returns 0 for success, non-zero for failure.
284  */
285 static int
286 _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
287     u64 sas_address, struct sas_expander_device *edev)
288 {
289         Mpi2SmpPassthroughRequest_t *mpi_request;
290         Mpi2SmpPassthroughReply_t *mpi_reply;
291         struct rep_manu_reply *manufacture_reply;
292         struct rep_manu_request *manufacture_request;
293         int rc;
294         u16 smid;
295         u32 ioc_state;
296         unsigned long timeleft;
297         void *psge;
298         u32 sgl_flags;
299         u8 issue_reset = 0;
300         void *data_out = NULL;
301         dma_addr_t data_out_dma;
302         u32 sz;
303         u64 *sas_address_le;
304         u16 wait_state_count;
305
306         if (ioc->shost_recovery) {
307                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
308                     __func__, ioc->name);
309                 return -EFAULT;
310         }
311
312         mutex_lock(&ioc->transport_cmds.mutex);
313
314         if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
315                 printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
316                     ioc->name, __func__);
317                 rc = -EAGAIN;
318                 goto out;
319         }
320         ioc->transport_cmds.status = MPT2_CMD_PENDING;
321
322         wait_state_count = 0;
323         ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
324         while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
325                 if (wait_state_count++ == 10) {
326                         printk(MPT2SAS_ERR_FMT
327                             "%s: failed due to ioc not operational\n",
328                             ioc->name, __func__);
329                         rc = -EFAULT;
330                         goto out;
331                 }
332                 ssleep(1);
333                 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
334                 printk(MPT2SAS_INFO_FMT "%s: waiting for "
335                     "operational state(count=%d)\n", ioc->name,
336                     __func__, wait_state_count);
337         }
338         if (wait_state_count)
339                 printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
340                     ioc->name, __func__);
341
342         smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
343         if (!smid) {
344                 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
345                     ioc->name, __func__);
346                 rc = -EAGAIN;
347                 goto out;
348         }
349
350         rc = 0;
351         mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
352         ioc->transport_cmds.smid = smid;
353
354         sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
355         data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
356
357         if (!data_out) {
358                 printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
359                     __LINE__, __func__);
360                 rc = -ENOMEM;
361                 mpt2sas_base_free_smid(ioc, smid);
362                 goto out;
363         }
364
365         manufacture_request = data_out;
366         manufacture_request->smp_frame_type = 0x40;
367         manufacture_request->function = 1;
368         manufacture_request->reserved = 0;
369         manufacture_request->request_length = 0;
370
371         memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
372         mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
373         mpi_request->PhysicalPort = 0xFF;
374         mpi_request->VF_ID = 0; /* TODO */
375         mpi_request->VP_ID = 0;
376         sas_address_le = (u64 *)&mpi_request->SASAddress;
377         *sas_address_le = cpu_to_le64(sas_address);
378         mpi_request->RequestDataLength = sizeof(struct rep_manu_request);
379         psge = &mpi_request->SGL;
380
381         /* WRITE sgel first */
382         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
383             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
384         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
385         ioc->base_add_sg_single(psge, sgl_flags |
386             sizeof(struct rep_manu_request), data_out_dma);
387
388         /* incr sgel */
389         psge += ioc->sge_size;
390
391         /* READ sgel last */
392         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
393             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
394             MPI2_SGE_FLAGS_END_OF_LIST);
395         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
396         ioc->base_add_sg_single(psge, sgl_flags |
397             sizeof(struct rep_manu_reply), data_out_dma +
398             sizeof(struct rep_manu_request));
399
400         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
401             "send to sas_addr(0x%016llx)\n", ioc->name,
402             (unsigned long long)sas_address));
403         mpt2sas_base_put_smid_default(ioc, smid);
404         init_completion(&ioc->transport_cmds.done);
405         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
406             10*HZ);
407
408         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
409                 printk(MPT2SAS_ERR_FMT "%s: timeout\n",
410                     ioc->name, __func__);
411                 _debug_dump_mf(mpi_request,
412                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
413                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
414                         issue_reset = 1;
415                 goto issue_host_reset;
416         }
417
418         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
419             "complete\n", ioc->name));
420
421         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
422                 u8 *tmp;
423
424                 mpi_reply = ioc->transport_cmds.reply;
425
426                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
427                     "report_manufacture - reply data transfer size(%d)\n",
428                     ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
429
430                 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
431                     sizeof(struct rep_manu_reply))
432                         goto out;
433
434                 manufacture_reply = data_out + sizeof(struct rep_manu_request);
435                 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
436                      SAS_EXPANDER_VENDOR_ID_LEN);
437                 strncpy(edev->product_id, manufacture_reply->product_id,
438                      SAS_EXPANDER_PRODUCT_ID_LEN);
439                 strncpy(edev->product_rev, manufacture_reply->product_rev,
440                      SAS_EXPANDER_PRODUCT_REV_LEN);
441                 edev->level = manufacture_reply->sas_format;
442                 if (manufacture_reply->sas_format) {
443                         strncpy(edev->component_vendor_id,
444                             manufacture_reply->component_vendor_id,
445                              SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
446                         tmp = (u8 *)&manufacture_reply->component_id;
447                         edev->component_id = tmp[0] << 8 | tmp[1];
448                         edev->component_revision_id =
449                             manufacture_reply->component_revision_id;
450                 }
451         } else
452                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
453                     "report_manufacture - no reply\n", ioc->name));
454
455  issue_host_reset:
456         if (issue_reset)
457                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
458                     FORCE_BIG_HAMMER);
459  out:
460         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
461         if (data_out)
462                 pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
463
464         mutex_unlock(&ioc->transport_cmds.mutex);
465         return rc;
466 }
467
468 /**
469  * mpt2sas_transport_port_add - insert port to the list
470  * @ioc: per adapter object
471  * @handle: handle of attached device
472  * @parent_handle: parent handle(either hba or expander)
473  * Context: This function will acquire ioc->sas_node_lock.
474  *
475  * Adding new port object to the sas_node->sas_port_list.
476  *
477  * Returns mpt2sas_port.
478  */
479 struct _sas_port *
480 mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
481     u16 parent_handle)
482 {
483         struct _sas_phy *mpt2sas_phy, *next;
484         struct _sas_port *mpt2sas_port;
485         unsigned long flags;
486         struct _sas_node *sas_node;
487         struct sas_rphy *rphy;
488         int i;
489         struct sas_port *port;
490
491         if (!parent_handle)
492                 return NULL;
493
494         mpt2sas_port = kzalloc(sizeof(struct _sas_port),
495             GFP_KERNEL);
496         if (!mpt2sas_port) {
497                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
498                     ioc->name, __FILE__, __LINE__, __func__);
499                 return NULL;
500         }
501
502         INIT_LIST_HEAD(&mpt2sas_port->port_list);
503         INIT_LIST_HEAD(&mpt2sas_port->phy_list);
504         spin_lock_irqsave(&ioc->sas_node_lock, flags);
505         sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
506         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
507
508         if (!sas_node) {
509                 printk(MPT2SAS_ERR_FMT "%s: Could not find parent(0x%04x)!\n",
510                     ioc->name, __func__, parent_handle);
511                 goto out_fail;
512         }
513
514         mpt2sas_port->handle = parent_handle;
515         mpt2sas_port->sas_address = sas_node->sas_address;
516         if ((_transport_set_identify(ioc, handle,
517             &mpt2sas_port->remote_identify))) {
518                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
519                     ioc->name, __FILE__, __LINE__, __func__);
520                 goto out_fail;
521         }
522
523         if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
524                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
525                     ioc->name, __FILE__, __LINE__, __func__);
526                 goto out_fail;
527         }
528
529         for (i = 0; i < sas_node->num_phys; i++) {
530                 if (sas_node->phy[i].remote_identify.sas_address !=
531                     mpt2sas_port->remote_identify.sas_address)
532                         continue;
533                 list_add_tail(&sas_node->phy[i].port_siblings,
534                     &mpt2sas_port->phy_list);
535                 mpt2sas_port->num_phys++;
536         }
537
538         if (!mpt2sas_port->num_phys) {
539                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
540                     ioc->name, __FILE__, __LINE__, __func__);
541                 goto out_fail;
542         }
543
544         port = sas_port_alloc_num(sas_node->parent_dev);
545         if ((sas_port_add(port))) {
546                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
547                     ioc->name, __FILE__, __LINE__, __func__);
548                 goto out_fail;
549         }
550
551         list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
552             port_siblings) {
553                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
554                         dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
555                             ", sas_addr(0x%016llx), phy(%d)\n", handle,
556                             (unsigned long long)
557                             mpt2sas_port->remote_identify.sas_address,
558                             mpt2sas_phy->phy_id);
559                 sas_port_add_phy(port, mpt2sas_phy->phy);
560         }
561
562         mpt2sas_port->port = port;
563         if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
564                 rphy = sas_end_device_alloc(port);
565         else
566                 rphy = sas_expander_alloc(port,
567                     mpt2sas_port->remote_identify.device_type);
568
569         rphy->identify = mpt2sas_port->remote_identify;
570         if ((sas_rphy_add(rphy))) {
571                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
572                     ioc->name, __FILE__, __LINE__, __func__);
573         }
574         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
575                 dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
576                     "sas_addr(0x%016llx)\n", handle,
577                     (unsigned long long)
578                     mpt2sas_port->remote_identify.sas_address);
579         mpt2sas_port->rphy = rphy;
580         spin_lock_irqsave(&ioc->sas_node_lock, flags);
581         list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
582         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
583
584         /* fill in report manufacture */
585         if (mpt2sas_port->remote_identify.device_type ==
586             MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
587             mpt2sas_port->remote_identify.device_type ==
588             MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
589                 _transport_expander_report_manufacture(ioc,
590                     mpt2sas_port->remote_identify.sas_address,
591                     rphy_to_expander_device(rphy));
592
593         return mpt2sas_port;
594
595  out_fail:
596         list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
597             port_siblings)
598                 list_del(&mpt2sas_phy->port_siblings);
599         kfree(mpt2sas_port);
600         return NULL;
601 }
602
603 /**
604  * mpt2sas_transport_port_remove - remove port from the list
605  * @ioc: per adapter object
606  * @sas_address: sas address of attached device
607  * @parent_handle: handle to the upstream parent(either hba or expander)
608  * Context: This function will acquire ioc->sas_node_lock.
609  *
610  * Removing object and freeing associated memory from the
611  * ioc->sas_port_list.
612  *
613  * Return nothing.
614  */
615 void
616 mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
617     u16 parent_handle)
618 {
619         int i;
620         unsigned long flags;
621         struct _sas_port *mpt2sas_port, *next;
622         struct _sas_node *sas_node;
623         u8 found = 0;
624         struct _sas_phy *mpt2sas_phy, *next_phy;
625
626         spin_lock_irqsave(&ioc->sas_node_lock, flags);
627         sas_node = _transport_sas_node_find_by_handle(ioc, parent_handle);
628         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
629         if (!sas_node)
630                 return;
631         list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
632             port_list) {
633                 if (mpt2sas_port->remote_identify.sas_address != sas_address)
634                         continue;
635                 found = 1;
636                 list_del(&mpt2sas_port->port_list);
637                 goto out;
638         }
639  out:
640         if (!found)
641                 return;
642
643         for (i = 0; i < sas_node->num_phys; i++) {
644                 if (sas_node->phy[i].remote_identify.sas_address == sas_address)
645                         memset(&sas_node->phy[i].remote_identify, 0 ,
646                             sizeof(struct sas_identify));
647         }
648
649         list_for_each_entry_safe(mpt2sas_phy, next_phy,
650             &mpt2sas_port->phy_list, port_siblings) {
651                 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
652                         dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
653                             "remove: parent_handle(0x%04x), "
654                             "sas_addr(0x%016llx), phy(%d)\n", parent_handle,
655                             (unsigned long long)
656                             mpt2sas_port->remote_identify.sas_address,
657                             mpt2sas_phy->phy_id);
658                 sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
659                 list_del(&mpt2sas_phy->port_siblings);
660         }
661         sas_port_delete(mpt2sas_port->port);
662         kfree(mpt2sas_port);
663 }
664
665 /**
666  * mpt2sas_transport_add_host_phy - report sas_host phy to transport
667  * @ioc: per adapter object
668  * @mpt2sas_phy: mpt2sas per phy object
669  * @phy_pg0: sas phy page 0
670  * @parent_dev: parent device class object
671  *
672  * Returns 0 for success, non-zero for failure.
673  */
674 int
675 mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
676     *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
677 {
678         struct sas_phy *phy;
679         int phy_index = mpt2sas_phy->phy_id;
680
681
682         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
683         phy = sas_phy_alloc(parent_dev, phy_index);
684         if (!phy) {
685                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
686                     ioc->name, __FILE__, __LINE__, __func__);
687                 return -1;
688         }
689         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
690             &mpt2sas_phy->identify))) {
691                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
692                     ioc->name, __FILE__, __LINE__, __func__);
693                 return -1;
694         }
695         phy->identify = mpt2sas_phy->identify;
696         mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
697         if (mpt2sas_phy->attached_handle)
698                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
699                     &mpt2sas_phy->remote_identify);
700         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
701         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
702             phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
703         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
704             phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
705         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
706             phy_pg0.HwLinkRate >> 4);
707         phy->minimum_linkrate = _transport_convert_phy_link_rate(
708             phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
709         phy->maximum_linkrate = _transport_convert_phy_link_rate(
710             phy_pg0.ProgrammedLinkRate >> 4);
711
712         if ((sas_phy_add(phy))) {
713                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
714                     ioc->name, __FILE__, __LINE__, __func__);
715                 sas_phy_free(phy);
716                 return -1;
717         }
718         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
719                 dev_printk(KERN_INFO, &phy->dev,
720                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
721                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
722                     mpt2sas_phy->handle, (unsigned long long)
723                     mpt2sas_phy->identify.sas_address,
724                     mpt2sas_phy->attached_handle,
725                     (unsigned long long)
726                     mpt2sas_phy->remote_identify.sas_address);
727         mpt2sas_phy->phy = phy;
728         return 0;
729 }
730
731
732 /**
733  * mpt2sas_transport_add_expander_phy - report expander phy to transport
734  * @ioc: per adapter object
735  * @mpt2sas_phy: mpt2sas per phy object
736  * @expander_pg1: expander page 1
737  * @parent_dev: parent device class object
738  *
739  * Returns 0 for success, non-zero for failure.
740  */
741 int
742 mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
743     *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
744 {
745         struct sas_phy *phy;
746         int phy_index = mpt2sas_phy->phy_id;
747
748         INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
749         phy = sas_phy_alloc(parent_dev, phy_index);
750         if (!phy) {
751                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
752                     ioc->name, __FILE__, __LINE__, __func__);
753                 return -1;
754         }
755         if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
756             &mpt2sas_phy->identify))) {
757                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
758                     ioc->name, __FILE__, __LINE__, __func__);
759                 return -1;
760         }
761         phy->identify = mpt2sas_phy->identify;
762         mpt2sas_phy->attached_handle =
763             le16_to_cpu(expander_pg1.AttachedDevHandle);
764         if (mpt2sas_phy->attached_handle)
765                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
766                     &mpt2sas_phy->remote_identify);
767         phy->identify.phy_identifier = mpt2sas_phy->phy_id;
768         phy->negotiated_linkrate = _transport_convert_phy_link_rate(
769             expander_pg1.NegotiatedLinkRate &
770             MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
771         phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
772             expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
773         phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
774             expander_pg1.HwLinkRate >> 4);
775         phy->minimum_linkrate = _transport_convert_phy_link_rate(
776             expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
777         phy->maximum_linkrate = _transport_convert_phy_link_rate(
778             expander_pg1.ProgrammedLinkRate >> 4);
779
780         if ((sas_phy_add(phy))) {
781                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
782                     ioc->name, __FILE__, __LINE__, __func__);
783                 sas_phy_free(phy);
784                 return -1;
785         }
786         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
787                 dev_printk(KERN_INFO, &phy->dev,
788                     "add: handle(0x%04x), sas_addr(0x%016llx)\n"
789                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
790                     mpt2sas_phy->handle, (unsigned long long)
791                     mpt2sas_phy->identify.sas_address,
792                     mpt2sas_phy->attached_handle,
793                     (unsigned long long)
794                     mpt2sas_phy->remote_identify.sas_address);
795         mpt2sas_phy->phy = phy;
796         return 0;
797 }
798
799 /**
800  * mpt2sas_transport_update_links - refreshing phy link changes
801  * @ioc: per adapter object
802  * @handle: handle to sas_host or expander
803  * @attached_handle: attached device handle
804  * @phy_numberv: phy number
805  * @link_rate: new link rate
806  *
807  * Returns nothing.
808  */
809 void
810 mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
811     u16 handle, u16 attached_handle, u8 phy_number, u8 link_rate)
812 {
813         unsigned long flags;
814         struct _sas_node *sas_node;
815         struct _sas_phy *mpt2sas_phy;
816
817         if (ioc->shost_recovery) {
818                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
819                         __func__, ioc->name);
820                 return;
821         }
822
823         spin_lock_irqsave(&ioc->sas_node_lock, flags);
824         sas_node = _transport_sas_node_find_by_handle(ioc, handle);
825         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
826         if (!sas_node)
827                 return;
828
829         mpt2sas_phy = &sas_node->phy[phy_number];
830         mpt2sas_phy->attached_handle = attached_handle;
831         if (attached_handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5))
832                 _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
833                     &mpt2sas_phy->remote_identify);
834         else
835                 memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
836                     sas_identify));
837
838         if (mpt2sas_phy->phy)
839                 mpt2sas_phy->phy->negotiated_linkrate =
840                     _transport_convert_phy_link_rate(link_rate);
841
842         if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
843                 dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
844                     "refresh: handle(0x%04x), sas_addr(0x%016llx),\n"
845                     "\tlink_rate(0x%02x), phy(%d)\n"
846                     "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
847                     handle, (unsigned long long)
848                     mpt2sas_phy->identify.sas_address, link_rate,
849                     phy_number, attached_handle,
850                     (unsigned long long)
851                     mpt2sas_phy->remote_identify.sas_address);
852 }
853
854 static inline void *
855 phy_to_ioc(struct sas_phy *phy)
856 {
857         struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
858         return shost_priv(shost);
859 }
860
861 static inline void *
862 rphy_to_ioc(struct sas_rphy *rphy)
863 {
864         struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
865         return shost_priv(shost);
866 }
867
868 /**
869  * _transport_get_linkerrors -
870  * @phy: The sas phy object
871  *
872  * Only support sas_host direct attached phys.
873  * Returns 0 for success, non-zero for failure.
874  *
875  */
876 static int
877 _transport_get_linkerrors(struct sas_phy *phy)
878 {
879         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
880         struct _sas_phy *mpt2sas_phy;
881         Mpi2ConfigReply_t mpi_reply;
882         Mpi2SasPhyPage1_t phy_pg1;
883         int i;
884
885         for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
886             !mpt2sas_phy; i++) {
887                 if (ioc->sas_hba.phy[i].phy != phy)
888                         continue;
889                 mpt2sas_phy = &ioc->sas_hba.phy[i];
890         }
891
892         if (!mpt2sas_phy) /* this phy not on sas_host */
893                 return -EINVAL;
894
895         if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
896                     mpt2sas_phy->phy_id))) {
897                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
898                     ioc->name, __FILE__, __LINE__, __func__);
899                 return -ENXIO;
900         }
901
902         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
903                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
904                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
905                     mpt2sas_phy->phy_id,
906                     le16_to_cpu(mpi_reply.IOCStatus),
907                     le32_to_cpu(mpi_reply.IOCLogInfo));
908
909         phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
910         phy->running_disparity_error_count =
911             le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
912         phy->loss_of_dword_sync_count =
913             le32_to_cpu(phy_pg1.LossDwordSynchCount);
914         phy->phy_reset_problem_count =
915             le32_to_cpu(phy_pg1.PhyResetProblemCount);
916         return 0;
917 }
918
919 /**
920  * _transport_get_enclosure_identifier -
921  * @phy: The sas phy object
922  *
923  * Obtain the enclosure logical id for an expander.
924  * Returns 0 for success, non-zero for failure.
925  */
926 static int
927 _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
928 {
929         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
930         struct _sas_node *sas_expander;
931         unsigned long flags;
932
933         spin_lock_irqsave(&ioc->sas_node_lock, flags);
934         sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
935             rphy->identify.sas_address);
936         spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
937
938         if (!sas_expander)
939                 return -ENXIO;
940
941         *identifier = sas_expander->enclosure_logical_id;
942         return 0;
943 }
944
945 /**
946  * _transport_get_bay_identifier -
947  * @phy: The sas phy object
948  *
949  * Returns the slot id for a device that resides inside an enclosure.
950  */
951 static int
952 _transport_get_bay_identifier(struct sas_rphy *rphy)
953 {
954         struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
955         struct _sas_device *sas_device;
956         unsigned long flags;
957
958         spin_lock_irqsave(&ioc->sas_device_lock, flags);
959         sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
960             rphy->identify.sas_address);
961         spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
962
963         if (!sas_device)
964                 return -ENXIO;
965
966         return sas_device->slot;
967 }
968
969 /**
970  * _transport_phy_reset -
971  * @phy: The sas phy object
972  * @hard_reset:
973  *
974  * Only support sas_host direct attached phys.
975  * Returns 0 for success, non-zero for failure.
976  */
977 static int
978 _transport_phy_reset(struct sas_phy *phy, int hard_reset)
979 {
980         struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
981         struct _sas_phy *mpt2sas_phy;
982         Mpi2SasIoUnitControlReply_t mpi_reply;
983         Mpi2SasIoUnitControlRequest_t mpi_request;
984         int i;
985
986         for (i = 0, mpt2sas_phy = NULL; i < ioc->sas_hba.num_phys &&
987             !mpt2sas_phy; i++) {
988                 if (ioc->sas_hba.phy[i].phy != phy)
989                         continue;
990                 mpt2sas_phy = &ioc->sas_hba.phy[i];
991         }
992
993         if (!mpt2sas_phy) /* this phy not on sas_host */
994                 return -EINVAL;
995
996         memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
997         mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
998         mpi_request.Operation = hard_reset ?
999             MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
1000         mpi_request.PhyNum = mpt2sas_phy->phy_id;
1001
1002         if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
1003                 printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1004                     ioc->name, __FILE__, __LINE__, __func__);
1005                 return -ENXIO;
1006         }
1007
1008         if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
1009                 printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
1010                     "(0x%04x), loginfo(0x%08x)\n", ioc->name,
1011                     mpt2sas_phy->phy_id,
1012                     le16_to_cpu(mpi_reply.IOCStatus),
1013                     le32_to_cpu(mpi_reply.IOCLogInfo));
1014
1015         return 0;
1016 }
1017
1018 /**
1019  * _transport_smp_handler - transport portal for smp passthru
1020  * @shost: shost object
1021  * @rphy: sas transport rphy object
1022  * @req:
1023  *
1024  * This used primarily for smp_utils.
1025  * Example:
1026  *           smp_rep_general /sys/class/bsg/expander-5:0
1027  */
1028 static int
1029 _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1030     struct request *req)
1031 {
1032         struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1033         Mpi2SmpPassthroughRequest_t *mpi_request;
1034         Mpi2SmpPassthroughReply_t *mpi_reply;
1035         int rc;
1036         u16 smid;
1037         u32 ioc_state;
1038         unsigned long timeleft;
1039         void *psge;
1040         u32 sgl_flags;
1041         u8 issue_reset = 0;
1042         dma_addr_t dma_addr_in = 0;
1043         dma_addr_t dma_addr_out = 0;
1044         u16 wait_state_count;
1045         struct request *rsp = req->next_rq;
1046
1047         if (!rsp) {
1048                 printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
1049                     "missing\n", ioc->name, __func__);
1050                 return -EINVAL;
1051         }
1052
1053         /* do we need to support multiple segments? */
1054         if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1055                 printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
1056                     "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
1057                     blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
1058                 return -EINVAL;
1059         }
1060
1061         if (ioc->shost_recovery) {
1062                 printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1063                     __func__, ioc->name);
1064                 return -EFAULT;
1065         }
1066
1067         rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
1068         if (rc)
1069                 return rc;
1070
1071         if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1072                 printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
1073                     __func__);
1074                 rc = -EAGAIN;
1075                 goto out;
1076         }
1077         ioc->transport_cmds.status = MPT2_CMD_PENDING;
1078
1079         wait_state_count = 0;
1080         ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1081         while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1082                 if (wait_state_count++ == 10) {
1083                         printk(MPT2SAS_ERR_FMT
1084                             "%s: failed due to ioc not operational\n",
1085                             ioc->name, __func__);
1086                         rc = -EFAULT;
1087                         goto out;
1088                 }
1089                 ssleep(1);
1090                 ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1091                 printk(MPT2SAS_INFO_FMT "%s: waiting for "
1092                     "operational state(count=%d)\n", ioc->name,
1093                     __func__, wait_state_count);
1094         }
1095         if (wait_state_count)
1096                 printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1097                     ioc->name, __func__);
1098
1099         smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1100         if (!smid) {
1101                 printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1102                     ioc->name, __func__);
1103                 rc = -EAGAIN;
1104                 goto out;
1105         }
1106
1107         rc = 0;
1108         mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1109         ioc->transport_cmds.smid = smid;
1110
1111         memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1112         mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1113         mpi_request->PhysicalPort = 0xFF;
1114         mpi_request->VF_ID = 0; /* TODO */
1115         mpi_request->VP_ID = 0;
1116         *((u64 *)&mpi_request->SASAddress) = (rphy) ?
1117             cpu_to_le64(rphy->identify.sas_address) :
1118             cpu_to_le64(ioc->sas_hba.sas_address);
1119         mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
1120         psge = &mpi_request->SGL;
1121
1122         /* WRITE sgel first */
1123         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1124             MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1125         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1126         dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
1127                 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
1128         if (!dma_addr_out) {
1129                 mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
1130                 goto unmap;
1131         }
1132
1133         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
1134             dma_addr_out);
1135
1136         /* incr sgel */
1137         psge += ioc->sge_size;
1138
1139         /* READ sgel last */
1140         sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1141             MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1142             MPI2_SGE_FLAGS_END_OF_LIST);
1143         sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1144         dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
1145                                      blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
1146         if (!dma_addr_in) {
1147                 mpt2sas_base_free_smid(ioc, le16_to_cpu(smid));
1148                 goto unmap;
1149         }
1150
1151         ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
1152             dma_addr_in);
1153
1154         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1155             "sending smp request\n", ioc->name, __func__));
1156
1157         mpt2sas_base_put_smid_default(ioc, smid);
1158         init_completion(&ioc->transport_cmds.done);
1159         timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1160             10*HZ);
1161
1162         if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1163                 printk(MPT2SAS_ERR_FMT "%s : timeout\n",
1164                     __func__, ioc->name);
1165                 _debug_dump_mf(mpi_request,
1166                     sizeof(Mpi2SmpPassthroughRequest_t)/4);
1167                 if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1168                         issue_reset = 1;
1169                 goto issue_host_reset;
1170         }
1171
1172         dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
1173             "complete\n", ioc->name, __func__));
1174
1175         if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1176
1177                 mpi_reply = ioc->transport_cmds.reply;
1178
1179                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1180                     "%s - reply data transfer size(%d)\n",
1181                     ioc->name, __func__,
1182                     le16_to_cpu(mpi_reply->ResponseDataLength)));
1183
1184                 memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
1185                 req->sense_len = sizeof(*mpi_reply);
1186                 req->resid_len = 0;
1187                 rsp->resid_len -= mpi_reply->ResponseDataLength;
1188         } else {
1189                 dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT
1190                     "%s - no reply\n", ioc->name, __func__));
1191                 rc = -ENXIO;
1192         }
1193
1194  issue_host_reset:
1195         if (issue_reset) {
1196                 mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1197                     FORCE_BIG_HAMMER);
1198                 rc = -ETIMEDOUT;
1199         }
1200
1201  unmap:
1202         if (dma_addr_out)
1203                 pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
1204                     PCI_DMA_BIDIRECTIONAL);
1205         if (dma_addr_in)
1206                 pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
1207                     PCI_DMA_BIDIRECTIONAL);
1208
1209  out:
1210         ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
1211         mutex_unlock(&ioc->transport_cmds.mutex);
1212         return rc;
1213 }
1214
1215 struct sas_function_template mpt2sas_transport_functions = {
1216         .get_linkerrors         = _transport_get_linkerrors,
1217         .get_enclosure_identifier = _transport_get_enclosure_identifier,
1218         .get_bay_identifier     = _transport_get_bay_identifier,
1219         .phy_reset              = _transport_phy_reset,
1220         .smp_handler            = _transport_smp_handler,
1221 };
1222
1223 struct scsi_transport_template *mpt2sas_transport_template;