2194 lines · c
1/*2 * SAS Transport Layer for MPT (Message Passing Technology) based controllers3 *4 * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c5 * Copyright (C) 2012-2014 LSI Corporation6 * Copyright (C) 2013-2014 Avago Technologies7 * (mailto: MPT-FusionLinux.pdl@avagotech.com)8 *9 * This program is free software; you can redistribute it and/or10 * modify it under the terms of the GNU General Public License11 * as published by the Free Software Foundation; either version 212 * of the License, or (at your option) any later version.13 *14 * This program is distributed in the hope that it will be useful,15 * but WITHOUT ANY WARRANTY; without even the implied warranty of16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the17 * GNU General Public License for more details.18 *19 * NO WARRANTY20 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR21 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT22 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,23 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is24 * solely responsible for determining the appropriateness of using and25 * distributing the Program and assumes all risks associated with its26 * exercise of rights under this Agreement, including but not limited to27 * the risks and costs of program errors, damage to or loss of data,28 * programs or equipment, and unavailability or interruption of operations.29 30 * DISCLAIMER OF LIABILITY31 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL33 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR35 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE36 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED37 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES38 39 * You should have received a copy of the GNU General Public License40 * along with this program; if not, write to the Free Software41 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,42 * USA.43 */44 45#include <linux/module.h>46#include <linux/kernel.h>47#include <linux/init.h>48#include <linux/errno.h>49#include <linux/sched.h>50#include <linux/workqueue.h>51#include <linux/delay.h>52#include <linux/pci.h>53 54#include <scsi/scsi.h>55#include <scsi/scsi_cmnd.h>56#include <scsi/scsi_device.h>57#include <scsi/scsi_host.h>58#include <scsi/scsi_transport_sas.h>59#include <scsi/scsi_dbg.h>60 61#include "mpt3sas_base.h"62 63/**64 * _transport_get_port_id_by_sas_phy - get zone's port id that Phy belong to65 * @phy: sas_phy object66 *67 * Return Port number68 */69static inline u870_transport_get_port_id_by_sas_phy(struct sas_phy *phy)71{72 u8 port_id = 0xFF;73 struct hba_port *port = phy->hostdata;74 75 if (port)76 port_id = port->port_id;77 78 return port_id;79}80 81/**82 * _transport_sas_node_find_by_sas_address - sas node search83 * @ioc: per adapter object84 * @sas_address: sas address of expander or sas host85 * @port: hba port entry86 * Context: Calling function should acquire ioc->sas_node_lock.87 *88 * Search for either hba phys or expander device based on handle, then returns89 * the sas_node object.90 */91static struct _sas_node *92_transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,93 u64 sas_address, struct hba_port *port)94{95 if (ioc->sas_hba.sas_address == sas_address)96 return &ioc->sas_hba;97 else98 return mpt3sas_scsih_expander_find_by_sas_address(ioc,99 sas_address, port);100}101 102/**103 * _transport_get_port_id_by_rphy - Get Port number from rphy object104 * @ioc: per adapter object105 * @rphy: sas_rphy object106 *107 * Returns Port number.108 */109static u8110_transport_get_port_id_by_rphy(struct MPT3SAS_ADAPTER *ioc,111 struct sas_rphy *rphy)112{113 struct _sas_node *sas_expander;114 struct _sas_device *sas_device;115 unsigned long flags;116 u8 port_id = 0xFF;117 118 if (!rphy)119 return port_id;120 121 if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||122 rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {123 spin_lock_irqsave(&ioc->sas_node_lock, flags);124 list_for_each_entry(sas_expander,125 &ioc->sas_expander_list, list) {126 if (sas_expander->rphy == rphy) {127 port_id = sas_expander->port->port_id;128 break;129 }130 }131 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);132 } else if (rphy->identify.device_type == SAS_END_DEVICE) {133 spin_lock_irqsave(&ioc->sas_device_lock, flags);134 sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);135 if (sas_device) {136 port_id = sas_device->port->port_id;137 sas_device_put(sas_device);138 }139 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);140 }141 142 return port_id;143}144 145/**146 * _transport_convert_phy_link_rate -147 * @link_rate: link rate returned from mpt firmware148 *149 * Convert link_rate from mpi fusion into sas_transport form.150 */151static enum sas_linkrate152_transport_convert_phy_link_rate(u8 link_rate)153{154 enum sas_linkrate rc;155 156 switch (link_rate) {157 case MPI2_SAS_NEG_LINK_RATE_1_5:158 rc = SAS_LINK_RATE_1_5_GBPS;159 break;160 case MPI2_SAS_NEG_LINK_RATE_3_0:161 rc = SAS_LINK_RATE_3_0_GBPS;162 break;163 case MPI2_SAS_NEG_LINK_RATE_6_0:164 rc = SAS_LINK_RATE_6_0_GBPS;165 break;166 case MPI25_SAS_NEG_LINK_RATE_12_0:167 rc = SAS_LINK_RATE_12_0_GBPS;168 break;169 case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:170 rc = SAS_PHY_DISABLED;171 break;172 case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:173 rc = SAS_LINK_RATE_FAILED;174 break;175 case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:176 rc = SAS_SATA_PORT_SELECTOR;177 break;178 case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:179 rc = SAS_PHY_RESET_IN_PROGRESS;180 break;181 182 default:183 case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:184 case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:185 rc = SAS_LINK_RATE_UNKNOWN;186 break;187 }188 return rc;189}190 191/**192 * _transport_set_identify - set identify for phys and end devices193 * @ioc: per adapter object194 * @handle: device handle195 * @identify: sas identify info196 *197 * Populates sas identify info.198 *199 * Return: 0 for success, non-zero for failure.200 */201static int202_transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle,203 struct sas_identify *identify)204{205 Mpi2SasDevicePage0_t sas_device_pg0;206 Mpi2ConfigReply_t mpi_reply;207 u32 device_info;208 u32 ioc_status;209 210 if (ioc->shost_recovery || ioc->pci_error_recovery) {211 ioc_info(ioc, "%s: host reset in progress!\n", __func__);212 return -EFAULT;213 }214 215 if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,216 MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {217 ioc_err(ioc, "failure at %s:%d/%s()!\n",218 __FILE__, __LINE__, __func__);219 return -ENXIO;220 }221 222 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &223 MPI2_IOCSTATUS_MASK;224 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {225 ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x) failure at %s:%d/%s()!\n",226 handle, ioc_status, __FILE__, __LINE__, __func__);227 return -EIO;228 }229 230 memset(identify, 0, sizeof(struct sas_identify));231 device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);232 233 /* sas_address */234 identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);235 236 /* phy number of the parent device this device is linked to */237 identify->phy_identifier = sas_device_pg0.PhyNum;238 239 /* device_type */240 switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {241 case MPI2_SAS_DEVICE_INFO_NO_DEVICE:242 identify->device_type = SAS_PHY_UNUSED;243 break;244 case MPI2_SAS_DEVICE_INFO_END_DEVICE:245 identify->device_type = SAS_END_DEVICE;246 break;247 case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:248 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;249 break;250 case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:251 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;252 break;253 }254 255 /* initiator_port_protocols */256 if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)257 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;258 if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)259 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;260 if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)261 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;262 if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)263 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;264 265 /* target_port_protocols */266 if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)267 identify->target_port_protocols |= SAS_PROTOCOL_SSP;268 if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)269 identify->target_port_protocols |= SAS_PROTOCOL_STP;270 if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)271 identify->target_port_protocols |= SAS_PROTOCOL_SMP;272 if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)273 identify->target_port_protocols |= SAS_PROTOCOL_SATA;274 275 return 0;276}277 278/**279 * mpt3sas_transport_done - internal transport layer callback handler.280 * @ioc: per adapter object281 * @smid: system request message index282 * @msix_index: MSIX table index supplied by the OS283 * @reply: reply message frame(lower 32bit addr)284 *285 * Callback handler when sending internal generated transport cmds.286 * The callback index passed is `ioc->transport_cb_idx`287 *288 * Return: 1 meaning mf should be freed from _base_interrupt289 * 0 means the mf is freed from this function.290 */291u8292mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,293 u32 reply)294{295 MPI2DefaultReply_t *mpi_reply;296 297 mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);298 if (ioc->transport_cmds.status == MPT3_CMD_NOT_USED)299 return 1;300 if (ioc->transport_cmds.smid != smid)301 return 1;302 ioc->transport_cmds.status |= MPT3_CMD_COMPLETE;303 if (mpi_reply) {304 memcpy(ioc->transport_cmds.reply, mpi_reply,305 mpi_reply->MsgLength*4);306 ioc->transport_cmds.status |= MPT3_CMD_REPLY_VALID;307 }308 ioc->transport_cmds.status &= ~MPT3_CMD_PENDING;309 complete(&ioc->transport_cmds.done);310 return 1;311}312 313/* report manufacture request structure */314struct rep_manu_request {315 u8 smp_frame_type;316 u8 function;317 u8 reserved;318 u8 request_length;319};320 321/* report manufacture reply structure */322struct rep_manu_reply {323 u8 smp_frame_type; /* 0x41 */324 u8 function; /* 0x01 */325 u8 function_result;326 u8 response_length;327 u16 expander_change_count;328 u8 reserved0[2];329 u8 sas_format;330 u8 reserved2[3];331 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];332 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];333 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];334 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];335 u16 component_id;336 u8 component_revision_id;337 u8 reserved3;338 u8 vendor_specific[8];339};340 341/**342 * _transport_expander_report_manufacture - obtain SMP report_manufacture343 * @ioc: per adapter object344 * @sas_address: expander sas address345 * @edev: the sas_expander_device object346 * @port_id: Port ID number347 *348 * Fills in the sas_expander_device object when SMP port is created.349 *350 * Return: 0 for success, non-zero for failure.351 */352static int353_transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,354 u64 sas_address, struct sas_expander_device *edev, u8 port_id)355{356 Mpi2SmpPassthroughRequest_t *mpi_request;357 Mpi2SmpPassthroughReply_t *mpi_reply;358 struct rep_manu_reply *manufacture_reply;359 struct rep_manu_request *manufacture_request;360 int rc;361 u16 smid;362 void *psge;363 u8 issue_reset = 0;364 void *data_out = NULL;365 dma_addr_t data_out_dma;366 dma_addr_t data_in_dma;367 size_t data_in_sz;368 size_t data_out_sz;369 370 if (ioc->shost_recovery || ioc->pci_error_recovery) {371 ioc_info(ioc, "%s: host reset in progress!\n", __func__);372 return -EFAULT;373 }374 375 mutex_lock(&ioc->transport_cmds.mutex);376 377 if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {378 ioc_err(ioc, "%s: transport_cmds in use\n", __func__);379 rc = -EAGAIN;380 goto out;381 }382 ioc->transport_cmds.status = MPT3_CMD_PENDING;383 384 rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);385 if (rc)386 goto out;387 388 smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);389 if (!smid) {390 ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);391 rc = -EAGAIN;392 goto out;393 }394 395 rc = 0;396 mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);397 ioc->transport_cmds.smid = smid;398 399 data_out_sz = sizeof(struct rep_manu_request);400 data_in_sz = sizeof(struct rep_manu_reply);401 data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,402 &data_out_dma, GFP_KERNEL);403 if (!data_out) {404 pr_err("failure at %s:%d/%s()!\n", __FILE__,405 __LINE__, __func__);406 rc = -ENOMEM;407 mpt3sas_base_free_smid(ioc, smid);408 goto out;409 }410 411 data_in_dma = data_out_dma + sizeof(struct rep_manu_request);412 413 manufacture_request = data_out;414 manufacture_request->smp_frame_type = 0x40;415 manufacture_request->function = 1;416 manufacture_request->reserved = 0;417 manufacture_request->request_length = 0;418 419 memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));420 mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;421 mpi_request->PhysicalPort = port_id;422 mpi_request->SASAddress = cpu_to_le64(sas_address);423 mpi_request->RequestDataLength = cpu_to_le16(data_out_sz);424 psge = &mpi_request->SGL;425 426 ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,427 data_in_sz);428 429 dtransportprintk(ioc,430 ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",431 (u64)sas_address));432 init_completion(&ioc->transport_cmds.done);433 ioc->put_smid_default(ioc, smid);434 wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);435 436 if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {437 ioc_err(ioc, "%s: timeout\n", __func__);438 _debug_dump_mf(mpi_request,439 sizeof(Mpi2SmpPassthroughRequest_t)/4);440 if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))441 issue_reset = 1;442 goto issue_host_reset;443 }444 445 dtransportprintk(ioc, ioc_info(ioc, "report_manufacture - complete\n"));446 447 if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {448 u8 *tmp;449 450 mpi_reply = ioc->transport_cmds.reply;451 452 dtransportprintk(ioc,453 ioc_info(ioc, "report_manufacture - reply data transfer size(%d)\n",454 le16_to_cpu(mpi_reply->ResponseDataLength)));455 456 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=457 sizeof(struct rep_manu_reply))458 goto out;459 460 manufacture_reply = data_out + sizeof(struct rep_manu_request);461 memtostr(edev->vendor_id, manufacture_reply->vendor_id);462 memtostr(edev->product_id, manufacture_reply->product_id);463 memtostr(edev->product_rev, manufacture_reply->product_rev);464 edev->level = manufacture_reply->sas_format & 1;465 if (edev->level) {466 memtostr(edev->component_vendor_id,467 manufacture_reply->component_vendor_id);468 tmp = (u8 *)&manufacture_reply->component_id;469 edev->component_id = tmp[0] << 8 | tmp[1];470 edev->component_revision_id =471 manufacture_reply->component_revision_id;472 }473 } else474 dtransportprintk(ioc,475 ioc_info(ioc, "report_manufacture - no reply\n"));476 477 issue_host_reset:478 if (issue_reset)479 mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);480 out:481 ioc->transport_cmds.status = MPT3_CMD_NOT_USED;482 if (data_out)483 dma_free_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,484 data_out, data_out_dma);485 486 mutex_unlock(&ioc->transport_cmds.mutex);487 return rc;488}489 490 491/**492 * _transport_delete_port - helper function to removing a port493 * @ioc: per adapter object494 * @mpt3sas_port: mpt3sas per port object495 */496static void497_transport_delete_port(struct MPT3SAS_ADAPTER *ioc,498 struct _sas_port *mpt3sas_port)499{500 u64 sas_address = mpt3sas_port->remote_identify.sas_address;501 struct hba_port *port = mpt3sas_port->hba_port;502 enum sas_device_type device_type =503 mpt3sas_port->remote_identify.device_type;504 505 dev_printk(KERN_INFO, &mpt3sas_port->port->dev,506 "remove: sas_addr(0x%016llx)\n",507 (unsigned long long) sas_address);508 509 ioc->logging_level |= MPT_DEBUG_TRANSPORT;510 if (device_type == SAS_END_DEVICE)511 mpt3sas_device_remove_by_sas_address(ioc,512 sas_address, port);513 else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||514 device_type == SAS_FANOUT_EXPANDER_DEVICE)515 mpt3sas_expander_remove(ioc, sas_address, port);516 ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;517}518 519/**520 * _transport_delete_phy - helper function to removing single phy from port521 * @ioc: per adapter object522 * @mpt3sas_port: mpt3sas per port object523 * @mpt3sas_phy: mpt3sas per phy object524 */525static void526_transport_delete_phy(struct MPT3SAS_ADAPTER *ioc,527 struct _sas_port *mpt3sas_port, struct _sas_phy *mpt3sas_phy)528{529 u64 sas_address = mpt3sas_port->remote_identify.sas_address;530 531 dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,532 "remove: sas_addr(0x%016llx), phy(%d)\n",533 (unsigned long long) sas_address, mpt3sas_phy->phy_id);534 535 list_del(&mpt3sas_phy->port_siblings);536 mpt3sas_port->num_phys--;537 sas_port_delete_phy(mpt3sas_port->port, mpt3sas_phy->phy);538 mpt3sas_phy->phy_belongs_to_port = 0;539}540 541/**542 * _transport_add_phy - helper function to adding single phy to port543 * @ioc: per adapter object544 * @mpt3sas_port: mpt3sas per port object545 * @mpt3sas_phy: mpt3sas per phy object546 */547static void548_transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port,549 struct _sas_phy *mpt3sas_phy)550{551 u64 sas_address = mpt3sas_port->remote_identify.sas_address;552 553 dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,554 "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)555 sas_address, mpt3sas_phy->phy_id);556 557 list_add_tail(&mpt3sas_phy->port_siblings, &mpt3sas_port->phy_list);558 mpt3sas_port->num_phys++;559 sas_port_add_phy(mpt3sas_port->port, mpt3sas_phy->phy);560 mpt3sas_phy->phy_belongs_to_port = 1;561}562 563/**564 * mpt3sas_transport_add_phy_to_an_existing_port - adding new phy to existing port565 * @ioc: per adapter object566 * @sas_node: sas node object (either expander or sas host)567 * @mpt3sas_phy: mpt3sas per phy object568 * @sas_address: sas address of device/expander were phy needs to be added to569 * @port: hba port entry570 */571void572mpt3sas_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc,573 struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy,574 u64 sas_address, struct hba_port *port)575{576 struct _sas_port *mpt3sas_port;577 struct _sas_phy *phy_srch;578 579 if (mpt3sas_phy->phy_belongs_to_port == 1)580 return;581 582 if (!port)583 return;584 585 list_for_each_entry(mpt3sas_port, &sas_node->sas_port_list,586 port_list) {587 if (mpt3sas_port->remote_identify.sas_address !=588 sas_address)589 continue;590 if (mpt3sas_port->hba_port != port)591 continue;592 list_for_each_entry(phy_srch, &mpt3sas_port->phy_list,593 port_siblings) {594 if (phy_srch == mpt3sas_phy)595 return;596 }597 _transport_add_phy(ioc, mpt3sas_port, mpt3sas_phy);598 return;599 }600 601}602 603/**604 * mpt3sas_transport_del_phy_from_an_existing_port - delete phy from existing port605 * @ioc: per adapter object606 * @sas_node: sas node object (either expander or sas host)607 * @mpt3sas_phy: mpt3sas per phy object608 */609void610mpt3sas_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc,611 struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy)612{613 struct _sas_port *mpt3sas_port, *next;614 struct _sas_phy *phy_srch;615 616 if (mpt3sas_phy->phy_belongs_to_port == 0)617 return;618 619 list_for_each_entry_safe(mpt3sas_port, next, &sas_node->sas_port_list,620 port_list) {621 list_for_each_entry(phy_srch, &mpt3sas_port->phy_list,622 port_siblings) {623 if (phy_srch != mpt3sas_phy)624 continue;625 626 /*627 * Don't delete port during host reset,628 * just delete phy.629 */630 if (mpt3sas_port->num_phys == 1 && !ioc->shost_recovery)631 _transport_delete_port(ioc, mpt3sas_port);632 else633 _transport_delete_phy(ioc, mpt3sas_port,634 mpt3sas_phy);635 return;636 }637 }638}639 640/**641 * _transport_sanity_check - sanity check when adding a new port642 * @ioc: per adapter object643 * @sas_node: sas node object (either expander or sas host)644 * @sas_address: sas address of device being added645 * @port: hba port entry646 *647 * See the explanation above from _transport_delete_duplicate_port648 */649static void650_transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node,651 u64 sas_address, struct hba_port *port)652{653 int i;654 655 for (i = 0; i < sas_node->num_phys; i++) {656 if (sas_node->phy[i].remote_identify.sas_address != sas_address)657 continue;658 if (sas_node->phy[i].port != port)659 continue;660 if (sas_node->phy[i].phy_belongs_to_port == 1)661 mpt3sas_transport_del_phy_from_an_existing_port(ioc,662 sas_node, &sas_node->phy[i]);663 }664}665 666/**667 * mpt3sas_transport_port_add - insert port to the list668 * @ioc: per adapter object669 * @handle: handle of attached device670 * @sas_address: sas address of parent expander or sas host671 * @hba_port: hba port entry672 * Context: This function will acquire ioc->sas_node_lock.673 *674 * Adding new port object to the sas_node->sas_port_list.675 *676 * Return: mpt3sas_port.677 */678struct _sas_port *679mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,680 u64 sas_address, struct hba_port *hba_port)681{682 struct _sas_phy *mpt3sas_phy, *next;683 struct _sas_port *mpt3sas_port;684 unsigned long flags;685 struct _sas_node *sas_node;686 struct sas_rphy *rphy;687 struct _sas_device *sas_device = NULL;688 int i;689 struct sas_port *port;690 struct virtual_phy *vphy = NULL;691 692 if (!hba_port) {693 ioc_err(ioc, "failure at %s:%d/%s()!\n",694 __FILE__, __LINE__, __func__);695 return NULL;696 }697 698 mpt3sas_port = kzalloc(sizeof(struct _sas_port),699 GFP_KERNEL);700 if (!mpt3sas_port) {701 ioc_err(ioc, "failure at %s:%d/%s()!\n",702 __FILE__, __LINE__, __func__);703 return NULL;704 }705 706 INIT_LIST_HEAD(&mpt3sas_port->port_list);707 INIT_LIST_HEAD(&mpt3sas_port->phy_list);708 spin_lock_irqsave(&ioc->sas_node_lock, flags);709 sas_node = _transport_sas_node_find_by_sas_address(ioc,710 sas_address, hba_port);711 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);712 713 if (!sas_node) {714 ioc_err(ioc, "%s: Could not find parent sas_address(0x%016llx)!\n",715 __func__, (u64)sas_address);716 goto out_fail;717 }718 719 if ((_transport_set_identify(ioc, handle,720 &mpt3sas_port->remote_identify))) {721 ioc_err(ioc, "failure at %s:%d/%s()!\n",722 __FILE__, __LINE__, __func__);723 goto out_fail;724 }725 726 if (mpt3sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {727 ioc_err(ioc, "failure at %s:%d/%s()!\n",728 __FILE__, __LINE__, __func__);729 goto out_fail;730 }731 732 mpt3sas_port->hba_port = hba_port;733 _transport_sanity_check(ioc, sas_node,734 mpt3sas_port->remote_identify.sas_address, hba_port);735 736 for (i = 0; i < sas_node->num_phys; i++) {737 if (sas_node->phy[i].remote_identify.sas_address !=738 mpt3sas_port->remote_identify.sas_address)739 continue;740 if (sas_node->phy[i].port != hba_port)741 continue;742 list_add_tail(&sas_node->phy[i].port_siblings,743 &mpt3sas_port->phy_list);744 mpt3sas_port->num_phys++;745 if (sas_node->handle <= ioc->sas_hba.num_phys) {746 if (!sas_node->phy[i].hba_vphy) {747 hba_port->phy_mask |= (1 << i);748 continue;749 }750 751 vphy = mpt3sas_get_vphy_by_phy(ioc, hba_port, i);752 if (!vphy) {753 ioc_err(ioc, "failure at %s:%d/%s()!\n",754 __FILE__, __LINE__, __func__);755 goto out_fail;756 }757 }758 }759 760 if (!mpt3sas_port->num_phys) {761 ioc_err(ioc, "failure at %s:%d/%s()!\n",762 __FILE__, __LINE__, __func__);763 goto out_fail;764 }765 766 if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {767 sas_device = mpt3sas_get_sdev_by_addr(ioc,768 mpt3sas_port->remote_identify.sas_address,769 mpt3sas_port->hba_port);770 if (!sas_device) {771 ioc_err(ioc, "failure at %s:%d/%s()!\n",772 __FILE__, __LINE__, __func__);773 goto out_fail;774 }775 sas_device->pend_sas_rphy_add = 1;776 }777 778 if (!sas_node->parent_dev) {779 ioc_err(ioc, "failure at %s:%d/%s()!\n",780 __FILE__, __LINE__, __func__);781 goto out_fail;782 }783 port = sas_port_alloc_num(sas_node->parent_dev);784 if (!port || (sas_port_add(port))) {785 ioc_err(ioc, "failure at %s:%d/%s()!\n",786 __FILE__, __LINE__, __func__);787 goto out_fail;788 }789 790 list_for_each_entry(mpt3sas_phy, &mpt3sas_port->phy_list,791 port_siblings) {792 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))793 dev_printk(KERN_INFO, &port->dev,794 "add: handle(0x%04x), sas_addr(0x%016llx), phy(%d)\n",795 handle, (unsigned long long)796 mpt3sas_port->remote_identify.sas_address,797 mpt3sas_phy->phy_id);798 sas_port_add_phy(port, mpt3sas_phy->phy);799 mpt3sas_phy->phy_belongs_to_port = 1;800 mpt3sas_phy->port = hba_port;801 }802 803 mpt3sas_port->port = port;804 if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {805 rphy = sas_end_device_alloc(port);806 sas_device->rphy = rphy;807 if (sas_node->handle <= ioc->sas_hba.num_phys) {808 if (!vphy)809 hba_port->sas_address =810 sas_device->sas_address;811 else812 vphy->sas_address =813 sas_device->sas_address;814 }815 } else {816 rphy = sas_expander_alloc(port,817 mpt3sas_port->remote_identify.device_type);818 if (sas_node->handle <= ioc->sas_hba.num_phys)819 hba_port->sas_address =820 mpt3sas_port->remote_identify.sas_address;821 }822 823 if (!rphy) {824 ioc_err(ioc, "failure at %s:%d/%s()!\n",825 __FILE__, __LINE__, __func__);826 goto out_delete_port;827 }828 829 rphy->identify = mpt3sas_port->remote_identify;830 831 if ((sas_rphy_add(rphy))) {832 ioc_err(ioc, "failure at %s:%d/%s()!\n",833 __FILE__, __LINE__, __func__);834 sas_rphy_free(rphy);835 rphy = NULL;836 goto out_delete_port;837 }838 839 if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {840 sas_device->pend_sas_rphy_add = 0;841 sas_device_put(sas_device);842 }843 844 dev_info(&rphy->dev,845 "add: handle(0x%04x), sas_addr(0x%016llx)\n", handle,846 (unsigned long long)mpt3sas_port->remote_identify.sas_address);847 848 mpt3sas_port->rphy = rphy;849 spin_lock_irqsave(&ioc->sas_node_lock, flags);850 list_add_tail(&mpt3sas_port->port_list, &sas_node->sas_port_list);851 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);852 853 /* fill in report manufacture */854 if (mpt3sas_port->remote_identify.device_type ==855 MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||856 mpt3sas_port->remote_identify.device_type ==857 MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)858 _transport_expander_report_manufacture(ioc,859 mpt3sas_port->remote_identify.sas_address,860 rphy_to_expander_device(rphy), hba_port->port_id);861 return mpt3sas_port;862 863out_delete_port:864 sas_port_delete(port);865 866out_fail:867 list_for_each_entry_safe(mpt3sas_phy, next, &mpt3sas_port->phy_list,868 port_siblings)869 list_del(&mpt3sas_phy->port_siblings);870 kfree(mpt3sas_port);871 return NULL;872}873 874/**875 * mpt3sas_transport_port_remove - remove port from the list876 * @ioc: per adapter object877 * @sas_address: sas address of attached device878 * @sas_address_parent: sas address of parent expander or sas host879 * @port: hba port entry880 * Context: This function will acquire ioc->sas_node_lock.881 *882 * Removing object and freeing associated memory from the883 * ioc->sas_port_list.884 */885void886mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,887 u64 sas_address_parent, struct hba_port *port)888{889 int i;890 unsigned long flags;891 struct _sas_port *mpt3sas_port, *next;892 struct _sas_node *sas_node;893 u8 found = 0;894 struct _sas_phy *mpt3sas_phy, *next_phy;895 struct hba_port *hba_port_next, *hba_port = NULL;896 struct virtual_phy *vphy, *vphy_next = NULL;897 898 if (!port)899 return;900 901 spin_lock_irqsave(&ioc->sas_node_lock, flags);902 sas_node = _transport_sas_node_find_by_sas_address(ioc,903 sas_address_parent, port);904 if (!sas_node) {905 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);906 return;907 }908 list_for_each_entry_safe(mpt3sas_port, next, &sas_node->sas_port_list,909 port_list) {910 if (mpt3sas_port->remote_identify.sas_address != sas_address)911 continue;912 if (mpt3sas_port->hba_port != port)913 continue;914 found = 1;915 list_del(&mpt3sas_port->port_list);916 goto out;917 }918 out:919 if (!found) {920 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);921 return;922 }923 924 if (sas_node->handle <= ioc->sas_hba.num_phys &&925 (ioc->multipath_on_hba)) {926 if (port->vphys_mask) {927 list_for_each_entry_safe(vphy, vphy_next,928 &port->vphys_list, list) {929 if (vphy->sas_address != sas_address)930 continue;931 ioc_info(ioc,932 "remove vphy entry: %p of port:%p,from %d port's vphys list\n",933 vphy, port, port->port_id);934 port->vphys_mask &= ~vphy->phy_mask;935 list_del(&vphy->list);936 kfree(vphy);937 }938 }939 940 list_for_each_entry_safe(hba_port, hba_port_next,941 &ioc->port_table_list, list) {942 if (hba_port != port)943 continue;944 /*945 * Delete hba_port object if946 * - hba_port object's sas address matches with current947 * removed device's sas address and no vphy's948 * associated with it.949 * - Current removed device is a vSES device and950 * none of the other direct attached device have951 * this vSES device's port number (hence hba_port952 * object sas_address field will be zero).953 */954 if ((hba_port->sas_address == sas_address ||955 !hba_port->sas_address) && !hba_port->vphys_mask) {956 ioc_info(ioc,957 "remove hba_port entry: %p port: %d from hba_port list\n",958 hba_port, hba_port->port_id);959 list_del(&hba_port->list);960 kfree(hba_port);961 } else if (hba_port->sas_address == sas_address &&962 hba_port->vphys_mask) {963 /*964 * Current removed device is a non vSES device965 * and a vSES device has the same port number966 * as of current device's port number. Hence967 * only clear the sas_address filed, don't968 * delete the hba_port object.969 */970 ioc_info(ioc,971 "clearing sas_address from hba_port entry: %p port: %d from hba_port list\n",972 hba_port, hba_port->port_id);973 port->sas_address = 0;974 }975 break;976 }977 }978 979 for (i = 0; i < sas_node->num_phys; i++) {980 if (sas_node->phy[i].remote_identify.sas_address == sas_address)981 memset(&sas_node->phy[i].remote_identify, 0 ,982 sizeof(struct sas_identify));983 }984 985 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);986 987 list_for_each_entry_safe(mpt3sas_phy, next_phy,988 &mpt3sas_port->phy_list, port_siblings) {989 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))990 dev_printk(KERN_INFO, &mpt3sas_port->port->dev,991 "remove: sas_addr(0x%016llx), phy(%d)\n",992 (unsigned long long)993 mpt3sas_port->remote_identify.sas_address,994 mpt3sas_phy->phy_id);995 mpt3sas_phy->phy_belongs_to_port = 0;996 if (!ioc->remove_host)997 sas_port_delete_phy(mpt3sas_port->port,998 mpt3sas_phy->phy);999 list_del(&mpt3sas_phy->port_siblings);1000 }1001 if (!ioc->remove_host)1002 sas_port_delete(mpt3sas_port->port);1003 ioc_info(ioc, "%s: removed: sas_addr(0x%016llx)\n",1004 __func__, (unsigned long long)sas_address);1005 kfree(mpt3sas_port);1006}1007 1008/**1009 * mpt3sas_transport_add_host_phy - report sas_host phy to transport1010 * @ioc: per adapter object1011 * @mpt3sas_phy: mpt3sas per phy object1012 * @phy_pg0: sas phy page 01013 * @parent_dev: parent device class object1014 *1015 * Return: 0 for success, non-zero for failure.1016 */1017int1018mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy1019 *mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)1020{1021 struct sas_phy *phy;1022 int phy_index = mpt3sas_phy->phy_id;1023 1024 1025 INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);1026 phy = sas_phy_alloc(parent_dev, phy_index);1027 if (!phy) {1028 ioc_err(ioc, "failure at %s:%d/%s()!\n",1029 __FILE__, __LINE__, __func__);1030 return -1;1031 }1032 if ((_transport_set_identify(ioc, mpt3sas_phy->handle,1033 &mpt3sas_phy->identify))) {1034 ioc_err(ioc, "failure at %s:%d/%s()!\n",1035 __FILE__, __LINE__, __func__);1036 sas_phy_free(phy);1037 return -1;1038 }1039 phy->identify = mpt3sas_phy->identify;1040 mpt3sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);1041 if (mpt3sas_phy->attached_handle)1042 _transport_set_identify(ioc, mpt3sas_phy->attached_handle,1043 &mpt3sas_phy->remote_identify);1044 phy->identify.phy_identifier = mpt3sas_phy->phy_id;1045 phy->negotiated_linkrate = _transport_convert_phy_link_rate(1046 phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1047 phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(1048 phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);1049 phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(1050 phy_pg0.HwLinkRate >> 4);1051 phy->minimum_linkrate = _transport_convert_phy_link_rate(1052 phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1053 phy->maximum_linkrate = _transport_convert_phy_link_rate(1054 phy_pg0.ProgrammedLinkRate >> 4);1055 phy->hostdata = mpt3sas_phy->port;1056 1057 if ((sas_phy_add(phy))) {1058 ioc_err(ioc, "failure at %s:%d/%s()!\n",1059 __FILE__, __LINE__, __func__);1060 sas_phy_free(phy);1061 return -1;1062 }1063 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1064 dev_printk(KERN_INFO, &phy->dev,1065 "add: handle(0x%04x), sas_addr(0x%016llx)\n"1066 "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1067 mpt3sas_phy->handle, (unsigned long long)1068 mpt3sas_phy->identify.sas_address,1069 mpt3sas_phy->attached_handle,1070 (unsigned long long)1071 mpt3sas_phy->remote_identify.sas_address);1072 mpt3sas_phy->phy = phy;1073 return 0;1074}1075 1076 1077/**1078 * mpt3sas_transport_add_expander_phy - report expander phy to transport1079 * @ioc: per adapter object1080 * @mpt3sas_phy: mpt3sas per phy object1081 * @expander_pg1: expander page 11082 * @parent_dev: parent device class object1083 *1084 * Return: 0 for success, non-zero for failure.1085 */1086int1087mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy1088 *mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1,1089 struct device *parent_dev)1090{1091 struct sas_phy *phy;1092 int phy_index = mpt3sas_phy->phy_id;1093 1094 INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);1095 phy = sas_phy_alloc(parent_dev, phy_index);1096 if (!phy) {1097 ioc_err(ioc, "failure at %s:%d/%s()!\n",1098 __FILE__, __LINE__, __func__);1099 return -1;1100 }1101 if ((_transport_set_identify(ioc, mpt3sas_phy->handle,1102 &mpt3sas_phy->identify))) {1103 ioc_err(ioc, "failure at %s:%d/%s()!\n",1104 __FILE__, __LINE__, __func__);1105 sas_phy_free(phy);1106 return -1;1107 }1108 phy->identify = mpt3sas_phy->identify;1109 mpt3sas_phy->attached_handle =1110 le16_to_cpu(expander_pg1.AttachedDevHandle);1111 if (mpt3sas_phy->attached_handle)1112 _transport_set_identify(ioc, mpt3sas_phy->attached_handle,1113 &mpt3sas_phy->remote_identify);1114 phy->identify.phy_identifier = mpt3sas_phy->phy_id;1115 phy->negotiated_linkrate = _transport_convert_phy_link_rate(1116 expander_pg1.NegotiatedLinkRate &1117 MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1118 phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(1119 expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);1120 phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(1121 expander_pg1.HwLinkRate >> 4);1122 phy->minimum_linkrate = _transport_convert_phy_link_rate(1123 expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1124 phy->maximum_linkrate = _transport_convert_phy_link_rate(1125 expander_pg1.ProgrammedLinkRate >> 4);1126 phy->hostdata = mpt3sas_phy->port;1127 1128 if ((sas_phy_add(phy))) {1129 ioc_err(ioc, "failure at %s:%d/%s()!\n",1130 __FILE__, __LINE__, __func__);1131 sas_phy_free(phy);1132 return -1;1133 }1134 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1135 dev_printk(KERN_INFO, &phy->dev,1136 "add: handle(0x%04x), sas_addr(0x%016llx)\n"1137 "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1138 mpt3sas_phy->handle, (unsigned long long)1139 mpt3sas_phy->identify.sas_address,1140 mpt3sas_phy->attached_handle,1141 (unsigned long long)1142 mpt3sas_phy->remote_identify.sas_address);1143 mpt3sas_phy->phy = phy;1144 return 0;1145}1146 1147/**1148 * mpt3sas_transport_update_links - refreshing phy link changes1149 * @ioc: per adapter object1150 * @sas_address: sas address of parent expander or sas host1151 * @handle: attached device handle1152 * @phy_number: phy number1153 * @link_rate: new link rate1154 * @port: hba port entry1155 *1156 * Return nothing.1157 */1158void1159mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc,1160 u64 sas_address, u16 handle, u8 phy_number, u8 link_rate,1161 struct hba_port *port)1162{1163 unsigned long flags;1164 struct _sas_node *sas_node;1165 struct _sas_phy *mpt3sas_phy;1166 struct hba_port *hba_port = NULL;1167 1168 if (ioc->shost_recovery || ioc->pci_error_recovery)1169 return;1170 1171 spin_lock_irqsave(&ioc->sas_node_lock, flags);1172 sas_node = _transport_sas_node_find_by_sas_address(ioc,1173 sas_address, port);1174 if (!sas_node) {1175 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1176 return;1177 }1178 1179 mpt3sas_phy = &sas_node->phy[phy_number];1180 mpt3sas_phy->attached_handle = handle;1181 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1182 if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {1183 _transport_set_identify(ioc, handle,1184 &mpt3sas_phy->remote_identify);1185 if ((sas_node->handle <= ioc->sas_hba.num_phys) &&1186 (ioc->multipath_on_hba)) {1187 list_for_each_entry(hba_port,1188 &ioc->port_table_list, list) {1189 if (hba_port->sas_address == sas_address &&1190 hba_port == port)1191 hba_port->phy_mask |=1192 (1 << mpt3sas_phy->phy_id);1193 }1194 }1195 mpt3sas_transport_add_phy_to_an_existing_port(ioc, sas_node,1196 mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address,1197 port);1198 } else1199 memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct1200 sas_identify));1201 1202 if (mpt3sas_phy->phy)1203 mpt3sas_phy->phy->negotiated_linkrate =1204 _transport_convert_phy_link_rate(link_rate);1205 1206 if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1207 dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,1208 "refresh: parent sas_addr(0x%016llx),\n"1209 "\tlink_rate(0x%02x), phy(%d)\n"1210 "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1211 (unsigned long long)sas_address,1212 link_rate, phy_number, handle, (unsigned long long)1213 mpt3sas_phy->remote_identify.sas_address);1214}1215 1216static inline void *1217phy_to_ioc(struct sas_phy *phy)1218{1219 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);1220 return shost_priv(shost);1221}1222 1223static inline void *1224rphy_to_ioc(struct sas_rphy *rphy)1225{1226 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);1227 return shost_priv(shost);1228}1229 1230/* report phy error log structure */1231struct phy_error_log_request {1232 u8 smp_frame_type; /* 0x40 */1233 u8 function; /* 0x11 */1234 u8 allocated_response_length;1235 u8 request_length; /* 02 */1236 u8 reserved_1[5];1237 u8 phy_identifier;1238 u8 reserved_2[2];1239};1240 1241/* report phy error log reply structure */1242struct phy_error_log_reply {1243 u8 smp_frame_type; /* 0x41 */1244 u8 function; /* 0x11 */1245 u8 function_result;1246 u8 response_length;1247 __be16 expander_change_count;1248 u8 reserved_1[3];1249 u8 phy_identifier;1250 u8 reserved_2[2];1251 __be32 invalid_dword;1252 __be32 running_disparity_error;1253 __be32 loss_of_dword_sync;1254 __be32 phy_reset_problem;1255};1256 1257/**1258 * _transport_get_expander_phy_error_log - return expander counters1259 * @ioc: per adapter object1260 * @phy: The sas phy object1261 *1262 * Return: 0 for success, non-zero for failure.1263 *1264 */1265static int1266_transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,1267 struct sas_phy *phy)1268{1269 Mpi2SmpPassthroughRequest_t *mpi_request;1270 Mpi2SmpPassthroughReply_t *mpi_reply;1271 struct phy_error_log_request *phy_error_log_request;1272 struct phy_error_log_reply *phy_error_log_reply;1273 int rc;1274 u16 smid;1275 void *psge;1276 u8 issue_reset = 0;1277 void *data_out = NULL;1278 dma_addr_t data_out_dma;1279 u32 sz;1280 1281 if (ioc->shost_recovery || ioc->pci_error_recovery) {1282 ioc_info(ioc, "%s: host reset in progress!\n", __func__);1283 return -EFAULT;1284 }1285 1286 mutex_lock(&ioc->transport_cmds.mutex);1287 1288 if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {1289 ioc_err(ioc, "%s: transport_cmds in use\n", __func__);1290 rc = -EAGAIN;1291 goto out;1292 }1293 ioc->transport_cmds.status = MPT3_CMD_PENDING;1294 1295 rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);1296 if (rc)1297 goto out;1298 1299 smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);1300 if (!smid) {1301 ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);1302 rc = -EAGAIN;1303 goto out;1304 }1305 1306 mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);1307 ioc->transport_cmds.smid = smid;1308 1309 sz = sizeof(struct phy_error_log_request) +1310 sizeof(struct phy_error_log_reply);1311 data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,1312 GFP_KERNEL);1313 if (!data_out) {1314 pr_err("failure at %s:%d/%s()!\n", __FILE__,1315 __LINE__, __func__);1316 rc = -ENOMEM;1317 mpt3sas_base_free_smid(ioc, smid);1318 goto out;1319 }1320 1321 rc = -EINVAL;1322 memset(data_out, 0, sz);1323 phy_error_log_request = data_out;1324 phy_error_log_request->smp_frame_type = 0x40;1325 phy_error_log_request->function = 0x11;1326 phy_error_log_request->request_length = 2;1327 phy_error_log_request->allocated_response_length = 0;1328 phy_error_log_request->phy_identifier = phy->number;1329 1330 memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));1331 mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;1332 mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy);1333 mpi_request->VF_ID = 0; /* TODO */1334 mpi_request->VP_ID = 0;1335 mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);1336 mpi_request->RequestDataLength =1337 cpu_to_le16(sizeof(struct phy_error_log_request));1338 psge = &mpi_request->SGL;1339 1340 ioc->build_sg(ioc, psge, data_out_dma,1341 sizeof(struct phy_error_log_request),1342 data_out_dma + sizeof(struct phy_error_log_request),1343 sizeof(struct phy_error_log_reply));1344 1345 dtransportprintk(ioc,1346 ioc_info(ioc, "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n",1347 (u64)phy->identify.sas_address,1348 phy->number));1349 init_completion(&ioc->transport_cmds.done);1350 ioc->put_smid_default(ioc, smid);1351 wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);1352 1353 if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {1354 ioc_err(ioc, "%s: timeout\n", __func__);1355 _debug_dump_mf(mpi_request,1356 sizeof(Mpi2SmpPassthroughRequest_t)/4);1357 if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))1358 issue_reset = 1;1359 goto issue_host_reset;1360 }1361 1362 dtransportprintk(ioc, ioc_info(ioc, "phy_error_log - complete\n"));1363 1364 if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {1365 1366 mpi_reply = ioc->transport_cmds.reply;1367 1368 dtransportprintk(ioc,1369 ioc_info(ioc, "phy_error_log - reply data transfer size(%d)\n",1370 le16_to_cpu(mpi_reply->ResponseDataLength)));1371 1372 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=1373 sizeof(struct phy_error_log_reply))1374 goto out;1375 1376 phy_error_log_reply = data_out +1377 sizeof(struct phy_error_log_request);1378 1379 dtransportprintk(ioc,1380 ioc_info(ioc, "phy_error_log - function_result(%d)\n",1381 phy_error_log_reply->function_result));1382 1383 phy->invalid_dword_count =1384 be32_to_cpu(phy_error_log_reply->invalid_dword);1385 phy->running_disparity_error_count =1386 be32_to_cpu(phy_error_log_reply->running_disparity_error);1387 phy->loss_of_dword_sync_count =1388 be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);1389 phy->phy_reset_problem_count =1390 be32_to_cpu(phy_error_log_reply->phy_reset_problem);1391 rc = 0;1392 } else1393 dtransportprintk(ioc,1394 ioc_info(ioc, "phy_error_log - no reply\n"));1395 1396 issue_host_reset:1397 if (issue_reset)1398 mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);1399 out:1400 ioc->transport_cmds.status = MPT3_CMD_NOT_USED;1401 if (data_out)1402 dma_free_coherent(&ioc->pdev->dev, sz, data_out, data_out_dma);1403 1404 mutex_unlock(&ioc->transport_cmds.mutex);1405 return rc;1406}1407 1408/**1409 * _transport_get_linkerrors - return phy counters for both hba and expanders1410 * @phy: The sas phy object1411 *1412 * Return: 0 for success, non-zero for failure.1413 *1414 */1415static int1416_transport_get_linkerrors(struct sas_phy *phy)1417{1418 struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1419 unsigned long flags;1420 Mpi2ConfigReply_t mpi_reply;1421 Mpi2SasPhyPage1_t phy_pg1;1422 struct hba_port *port = phy->hostdata;1423 int port_id = port->port_id;1424 1425 spin_lock_irqsave(&ioc->sas_node_lock, flags);1426 if (_transport_sas_node_find_by_sas_address(ioc,1427 phy->identify.sas_address,1428 mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1429 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1430 return -EINVAL;1431 }1432 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1433 1434 if (phy->identify.sas_address != ioc->sas_hba.sas_address)1435 return _transport_get_expander_phy_error_log(ioc, phy);1436 1437 /* get hba phy error logs */1438 if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,1439 phy->number))) {1440 ioc_err(ioc, "failure at %s:%d/%s()!\n",1441 __FILE__, __LINE__, __func__);1442 return -ENXIO;1443 }1444 1445 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)1446 ioc_info(ioc, "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n",1447 phy->number,1448 le16_to_cpu(mpi_reply.IOCStatus),1449 le32_to_cpu(mpi_reply.IOCLogInfo));1450 1451 phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);1452 phy->running_disparity_error_count =1453 le32_to_cpu(phy_pg1.RunningDisparityErrorCount);1454 phy->loss_of_dword_sync_count =1455 le32_to_cpu(phy_pg1.LossDwordSynchCount);1456 phy->phy_reset_problem_count =1457 le32_to_cpu(phy_pg1.PhyResetProblemCount);1458 return 0;1459}1460 1461/**1462 * _transport_get_enclosure_identifier -1463 * @rphy: The sas phy object1464 * @identifier: ?1465 *1466 * Obtain the enclosure logical id for an expander.1467 * Return: 0 for success, non-zero for failure.1468 */1469static int1470_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)1471{1472 struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy);1473 struct _sas_device *sas_device;1474 unsigned long flags;1475 int rc;1476 1477 spin_lock_irqsave(&ioc->sas_device_lock, flags);1478 sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);1479 if (sas_device) {1480 *identifier = sas_device->enclosure_logical_id;1481 rc = 0;1482 sas_device_put(sas_device);1483 } else {1484 *identifier = 0;1485 rc = -ENXIO;1486 }1487 1488 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);1489 return rc;1490}1491 1492/**1493 * _transport_get_bay_identifier -1494 * @rphy: The sas phy object1495 *1496 * Return: the slot id for a device that resides inside an enclosure.1497 */1498static int1499_transport_get_bay_identifier(struct sas_rphy *rphy)1500{1501 struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy);1502 struct _sas_device *sas_device;1503 unsigned long flags;1504 int rc;1505 1506 spin_lock_irqsave(&ioc->sas_device_lock, flags);1507 sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);1508 if (sas_device) {1509 rc = sas_device->slot;1510 sas_device_put(sas_device);1511 } else {1512 rc = -ENXIO;1513 }1514 spin_unlock_irqrestore(&ioc->sas_device_lock, flags);1515 return rc;1516}1517 1518/* phy control request structure */1519struct phy_control_request {1520 u8 smp_frame_type; /* 0x40 */1521 u8 function; /* 0x91 */1522 u8 allocated_response_length;1523 u8 request_length; /* 0x09 */1524 u16 expander_change_count;1525 u8 reserved_1[3];1526 u8 phy_identifier;1527 u8 phy_operation;1528 u8 reserved_2[13];1529 u64 attached_device_name;1530 u8 programmed_min_physical_link_rate;1531 u8 programmed_max_physical_link_rate;1532 u8 reserved_3[6];1533};1534 1535/* phy control reply structure */1536struct phy_control_reply {1537 u8 smp_frame_type; /* 0x41 */1538 u8 function; /* 0x11 */1539 u8 function_result;1540 u8 response_length;1541};1542 1543#define SMP_PHY_CONTROL_LINK_RESET (0x01)1544#define SMP_PHY_CONTROL_HARD_RESET (0x02)1545#define SMP_PHY_CONTROL_DISABLE (0x03)1546 1547/**1548 * _transport_expander_phy_control - expander phy control1549 * @ioc: per adapter object1550 * @phy: The sas phy object1551 * @phy_operation: ?1552 *1553 * Return: 0 for success, non-zero for failure.1554 *1555 */1556static int1557_transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,1558 struct sas_phy *phy, u8 phy_operation)1559{1560 Mpi2SmpPassthroughRequest_t *mpi_request;1561 Mpi2SmpPassthroughReply_t *mpi_reply;1562 struct phy_control_request *phy_control_request;1563 struct phy_control_reply *phy_control_reply;1564 int rc;1565 u16 smid;1566 void *psge;1567 u8 issue_reset = 0;1568 void *data_out = NULL;1569 dma_addr_t data_out_dma;1570 u32 sz;1571 1572 if (ioc->shost_recovery || ioc->pci_error_recovery) {1573 ioc_info(ioc, "%s: host reset in progress!\n", __func__);1574 return -EFAULT;1575 }1576 1577 mutex_lock(&ioc->transport_cmds.mutex);1578 1579 if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {1580 ioc_err(ioc, "%s: transport_cmds in use\n", __func__);1581 rc = -EAGAIN;1582 goto out;1583 }1584 ioc->transport_cmds.status = MPT3_CMD_PENDING;1585 1586 rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);1587 if (rc)1588 goto out;1589 1590 smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);1591 if (!smid) {1592 ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);1593 rc = -EAGAIN;1594 goto out;1595 }1596 1597 mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);1598 ioc->transport_cmds.smid = smid;1599 1600 sz = sizeof(struct phy_control_request) +1601 sizeof(struct phy_control_reply);1602 data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,1603 GFP_KERNEL);1604 if (!data_out) {1605 pr_err("failure at %s:%d/%s()!\n", __FILE__,1606 __LINE__, __func__);1607 rc = -ENOMEM;1608 mpt3sas_base_free_smid(ioc, smid);1609 goto out;1610 }1611 1612 rc = -EINVAL;1613 memset(data_out, 0, sz);1614 phy_control_request = data_out;1615 phy_control_request->smp_frame_type = 0x40;1616 phy_control_request->function = 0x91;1617 phy_control_request->request_length = 9;1618 phy_control_request->allocated_response_length = 0;1619 phy_control_request->phy_identifier = phy->number;1620 phy_control_request->phy_operation = phy_operation;1621 phy_control_request->programmed_min_physical_link_rate =1622 phy->minimum_linkrate << 4;1623 phy_control_request->programmed_max_physical_link_rate =1624 phy->maximum_linkrate << 4;1625 1626 memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));1627 mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;1628 mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy);1629 mpi_request->VF_ID = 0; /* TODO */1630 mpi_request->VP_ID = 0;1631 mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);1632 mpi_request->RequestDataLength =1633 cpu_to_le16(sizeof(struct phy_error_log_request));1634 psge = &mpi_request->SGL;1635 1636 ioc->build_sg(ioc, psge, data_out_dma,1637 sizeof(struct phy_control_request),1638 data_out_dma + sizeof(struct phy_control_request),1639 sizeof(struct phy_control_reply));1640 1641 dtransportprintk(ioc,1642 ioc_info(ioc, "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",1643 (u64)phy->identify.sas_address,1644 phy->number, phy_operation));1645 init_completion(&ioc->transport_cmds.done);1646 ioc->put_smid_default(ioc, smid);1647 wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);1648 1649 if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {1650 ioc_err(ioc, "%s: timeout\n", __func__);1651 _debug_dump_mf(mpi_request,1652 sizeof(Mpi2SmpPassthroughRequest_t)/4);1653 if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))1654 issue_reset = 1;1655 goto issue_host_reset;1656 }1657 1658 dtransportprintk(ioc, ioc_info(ioc, "phy_control - complete\n"));1659 1660 if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {1661 1662 mpi_reply = ioc->transport_cmds.reply;1663 1664 dtransportprintk(ioc,1665 ioc_info(ioc, "phy_control - reply data transfer size(%d)\n",1666 le16_to_cpu(mpi_reply->ResponseDataLength)));1667 1668 if (le16_to_cpu(mpi_reply->ResponseDataLength) !=1669 sizeof(struct phy_control_reply))1670 goto out;1671 1672 phy_control_reply = data_out +1673 sizeof(struct phy_control_request);1674 1675 dtransportprintk(ioc,1676 ioc_info(ioc, "phy_control - function_result(%d)\n",1677 phy_control_reply->function_result));1678 1679 rc = 0;1680 } else1681 dtransportprintk(ioc,1682 ioc_info(ioc, "phy_control - no reply\n"));1683 1684 issue_host_reset:1685 if (issue_reset)1686 mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);1687 out:1688 ioc->transport_cmds.status = MPT3_CMD_NOT_USED;1689 if (data_out)1690 dma_free_coherent(&ioc->pdev->dev, sz, data_out,1691 data_out_dma);1692 1693 mutex_unlock(&ioc->transport_cmds.mutex);1694 return rc;1695}1696 1697/**1698 * _transport_phy_reset -1699 * @phy: The sas phy object1700 * @hard_reset:1701 *1702 * Return: 0 for success, non-zero for failure.1703 */1704static int1705_transport_phy_reset(struct sas_phy *phy, int hard_reset)1706{1707 struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1708 Mpi2SasIoUnitControlReply_t mpi_reply;1709 Mpi2SasIoUnitControlRequest_t mpi_request;1710 struct hba_port *port = phy->hostdata;1711 int port_id = port->port_id;1712 unsigned long flags;1713 1714 spin_lock_irqsave(&ioc->sas_node_lock, flags);1715 if (_transport_sas_node_find_by_sas_address(ioc,1716 phy->identify.sas_address,1717 mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1718 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1719 return -EINVAL;1720 }1721 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1722 1723 /* handle expander phys */1724 if (phy->identify.sas_address != ioc->sas_hba.sas_address)1725 return _transport_expander_phy_control(ioc, phy,1726 (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :1727 SMP_PHY_CONTROL_LINK_RESET);1728 1729 /* handle hba phys */1730 memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));1731 mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;1732 mpi_request.Operation = hard_reset ?1733 MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;1734 mpi_request.PhyNum = phy->number;1735 1736 if ((mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {1737 ioc_err(ioc, "failure at %s:%d/%s()!\n",1738 __FILE__, __LINE__, __func__);1739 return -ENXIO;1740 }1741 1742 if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)1743 ioc_info(ioc, "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",1744 phy->number, le16_to_cpu(mpi_reply.IOCStatus),1745 le32_to_cpu(mpi_reply.IOCLogInfo));1746 1747 return 0;1748}1749 1750/**1751 * _transport_phy_enable - enable/disable phys1752 * @phy: The sas phy object1753 * @enable: enable phy when true1754 *1755 * Only support sas_host direct attached phys.1756 * Return: 0 for success, non-zero for failure.1757 */1758static int1759_transport_phy_enable(struct sas_phy *phy, int enable)1760{1761 struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1762 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;1763 Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;1764 Mpi2ConfigReply_t mpi_reply;1765 u16 ioc_status;1766 u16 sz;1767 int rc = 0;1768 unsigned long flags;1769 int i, discovery_active;1770 struct hba_port *port = phy->hostdata;1771 int port_id = port->port_id;1772 1773 spin_lock_irqsave(&ioc->sas_node_lock, flags);1774 if (_transport_sas_node_find_by_sas_address(ioc,1775 phy->identify.sas_address,1776 mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1777 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1778 return -EINVAL;1779 }1780 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1781 1782 /* handle expander phys */1783 if (phy->identify.sas_address != ioc->sas_hba.sas_address)1784 return _transport_expander_phy_control(ioc, phy,1785 (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :1786 SMP_PHY_CONTROL_DISABLE);1787 1788 /* handle hba phys */1789 1790 /* read sas_iounit page 0 */1791 sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys);1792 sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);1793 if (!sas_iounit_pg0) {1794 ioc_err(ioc, "failure at %s:%d/%s()!\n",1795 __FILE__, __LINE__, __func__);1796 rc = -ENOMEM;1797 goto out;1798 }1799 if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,1800 sas_iounit_pg0, sz))) {1801 ioc_err(ioc, "failure at %s:%d/%s()!\n",1802 __FILE__, __LINE__, __func__);1803 rc = -ENXIO;1804 goto out;1805 }1806 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1807 MPI2_IOCSTATUS_MASK;1808 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1809 ioc_err(ioc, "failure at %s:%d/%s()!\n",1810 __FILE__, __LINE__, __func__);1811 rc = -EIO;1812 goto out;1813 }1814 1815 /* unable to enable/disable phys when when discovery is active */1816 for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {1817 if (sas_iounit_pg0->PhyData[i].PortFlags &1818 MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {1819 ioc_err(ioc, "discovery is active on port = %d, phy = %d: unable to enable/disable phys, try again later!\n",1820 sas_iounit_pg0->PhyData[i].Port, i);1821 discovery_active = 1;1822 }1823 }1824 1825 if (discovery_active) {1826 rc = -EAGAIN;1827 goto out;1828 }1829 1830 /* read sas_iounit page 1 */1831 sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys);1832 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);1833 if (!sas_iounit_pg1) {1834 ioc_err(ioc, "failure at %s:%d/%s()!\n",1835 __FILE__, __LINE__, __func__);1836 rc = -ENOMEM;1837 goto out;1838 }1839 if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,1840 sas_iounit_pg1, sz))) {1841 ioc_err(ioc, "failure at %s:%d/%s()!\n",1842 __FILE__, __LINE__, __func__);1843 rc = -ENXIO;1844 goto out;1845 }1846 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1847 MPI2_IOCSTATUS_MASK;1848 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1849 ioc_err(ioc, "failure at %s:%d/%s()!\n",1850 __FILE__, __LINE__, __func__);1851 rc = -EIO;1852 goto out;1853 }1854 1855 /* copy Port/PortFlags/PhyFlags from page 0 */1856 for (i = 0; i < ioc->sas_hba.num_phys ; i++) {1857 sas_iounit_pg1->PhyData[i].Port =1858 sas_iounit_pg0->PhyData[i].Port;1859 sas_iounit_pg1->PhyData[i].PortFlags =1860 (sas_iounit_pg0->PhyData[i].PortFlags &1861 MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);1862 sas_iounit_pg1->PhyData[i].PhyFlags =1863 (sas_iounit_pg0->PhyData[i].PhyFlags &1864 (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +1865 MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));1866 }1867 1868 if (enable)1869 sas_iounit_pg1->PhyData[phy->number].PhyFlags1870 &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;1871 else1872 sas_iounit_pg1->PhyData[phy->number].PhyFlags1873 |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;1874 1875 mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);1876 1877 /* link reset */1878 if (enable)1879 _transport_phy_reset(phy, 0);1880 1881 out:1882 kfree(sas_iounit_pg1);1883 kfree(sas_iounit_pg0);1884 return rc;1885}1886 1887/**1888 * _transport_phy_speed - set phy min/max link rates1889 * @phy: The sas phy object1890 * @rates: rates defined in sas_phy_linkrates1891 *1892 * Only support sas_host direct attached phys.1893 *1894 * Return: 0 for success, non-zero for failure.1895 */1896static int1897_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)1898{1899 struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1900 Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;1901 Mpi2SasPhyPage0_t phy_pg0;1902 Mpi2ConfigReply_t mpi_reply;1903 u16 ioc_status;1904 u16 sz;1905 int i;1906 int rc = 0;1907 unsigned long flags;1908 struct hba_port *port = phy->hostdata;1909 int port_id = port->port_id;1910 1911 spin_lock_irqsave(&ioc->sas_node_lock, flags);1912 if (_transport_sas_node_find_by_sas_address(ioc,1913 phy->identify.sas_address,1914 mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1915 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1916 return -EINVAL;1917 }1918 spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1919 1920 if (!rates->minimum_linkrate)1921 rates->minimum_linkrate = phy->minimum_linkrate;1922 else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)1923 rates->minimum_linkrate = phy->minimum_linkrate_hw;1924 1925 if (!rates->maximum_linkrate)1926 rates->maximum_linkrate = phy->maximum_linkrate;1927 else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)1928 rates->maximum_linkrate = phy->maximum_linkrate_hw;1929 1930 /* handle expander phys */1931 if (phy->identify.sas_address != ioc->sas_hba.sas_address) {1932 phy->minimum_linkrate = rates->minimum_linkrate;1933 phy->maximum_linkrate = rates->maximum_linkrate;1934 return _transport_expander_phy_control(ioc, phy,1935 SMP_PHY_CONTROL_LINK_RESET);1936 }1937 1938 /* handle hba phys */1939 1940 /* sas_iounit page 1 */1941 sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys);1942 sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);1943 if (!sas_iounit_pg1) {1944 ioc_err(ioc, "failure at %s:%d/%s()!\n",1945 __FILE__, __LINE__, __func__);1946 rc = -ENOMEM;1947 goto out;1948 }1949 if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,1950 sas_iounit_pg1, sz))) {1951 ioc_err(ioc, "failure at %s:%d/%s()!\n",1952 __FILE__, __LINE__, __func__);1953 rc = -ENXIO;1954 goto out;1955 }1956 ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1957 MPI2_IOCSTATUS_MASK;1958 if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1959 ioc_err(ioc, "failure at %s:%d/%s()!\n",1960 __FILE__, __LINE__, __func__);1961 rc = -EIO;1962 goto out;1963 }1964 1965 for (i = 0; i < ioc->sas_hba.num_phys; i++) {1966 if (phy->number != i) {1967 sas_iounit_pg1->PhyData[i].MaxMinLinkRate =1968 (ioc->sas_hba.phy[i].phy->minimum_linkrate +1969 (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));1970 } else {1971 sas_iounit_pg1->PhyData[i].MaxMinLinkRate =1972 (rates->minimum_linkrate +1973 (rates->maximum_linkrate << 4));1974 }1975 }1976 1977 if (mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,1978 sz)) {1979 ioc_err(ioc, "failure at %s:%d/%s()!\n",1980 __FILE__, __LINE__, __func__);1981 rc = -ENXIO;1982 goto out;1983 }1984 1985 /* link reset */1986 _transport_phy_reset(phy, 0);1987 1988 /* read phy page 0, then update the rates in the sas transport phy */1989 if (!mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,1990 phy->number)) {1991 phy->minimum_linkrate = _transport_convert_phy_link_rate(1992 phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1993 phy->maximum_linkrate = _transport_convert_phy_link_rate(1994 phy_pg0.ProgrammedLinkRate >> 4);1995 phy->negotiated_linkrate = _transport_convert_phy_link_rate(1996 phy_pg0.NegotiatedLinkRate &1997 MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1998 }1999 2000 out:2001 kfree(sas_iounit_pg1);2002 return rc;2003}2004 2005static int2006_transport_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,2007 dma_addr_t *dma_addr, size_t *dma_len, void **p)2008{2009 /* Check if the request is split across multiple segments */2010 if (buf->sg_cnt > 1) {2011 *p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,2012 GFP_KERNEL);2013 if (!*p)2014 return -ENOMEM;2015 *dma_len = buf->payload_len;2016 } else {2017 if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))2018 return -ENOMEM;2019 *dma_addr = sg_dma_address(buf->sg_list);2020 *dma_len = sg_dma_len(buf->sg_list);2021 *p = NULL;2022 }2023 2024 return 0;2025}2026 2027static void2028_transport_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,2029 dma_addr_t dma_addr, void *p)2030{2031 if (p)2032 dma_free_coherent(dev, buf->payload_len, p, dma_addr);2033 else2034 dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);2035}2036 2037/**2038 * _transport_smp_handler - transport portal for smp passthru2039 * @job: ?2040 * @shost: shost object2041 * @rphy: sas transport rphy object2042 *2043 * This used primarily for smp_utils.2044 * Example:2045 * smp_rep_general /sys/class/bsg/expander-5:02046 */2047static void2048_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,2049 struct sas_rphy *rphy)2050{2051 struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);2052 Mpi2SmpPassthroughRequest_t *mpi_request;2053 Mpi2SmpPassthroughReply_t *mpi_reply;2054 int rc;2055 u16 smid;2056 void *psge;2057 dma_addr_t dma_addr_in;2058 dma_addr_t dma_addr_out;2059 void *addr_in = NULL;2060 void *addr_out = NULL;2061 size_t dma_len_in;2062 size_t dma_len_out;2063 unsigned int reslen = 0;2064 2065 if (ioc->shost_recovery || ioc->pci_error_recovery) {2066 ioc_info(ioc, "%s: host reset in progress!\n", __func__);2067 rc = -EFAULT;2068 goto job_done;2069 }2070 2071 rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);2072 if (rc)2073 goto job_done;2074 2075 if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {2076 ioc_err(ioc, "%s: transport_cmds in use\n",2077 __func__);2078 rc = -EAGAIN;2079 goto out;2080 }2081 ioc->transport_cmds.status = MPT3_CMD_PENDING;2082 2083 rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->request_payload,2084 &dma_addr_out, &dma_len_out, &addr_out);2085 if (rc)2086 goto out;2087 if (addr_out) {2088 sg_copy_to_buffer(job->request_payload.sg_list,2089 job->request_payload.sg_cnt, addr_out,2090 job->request_payload.payload_len);2091 }2092 2093 rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->reply_payload,2094 &dma_addr_in, &dma_len_in, &addr_in);2095 if (rc)2096 goto unmap_out;2097 2098 rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);2099 if (rc)2100 goto unmap_in;2101 2102 smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);2103 if (!smid) {2104 ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);2105 rc = -EAGAIN;2106 goto unmap_in;2107 }2108 2109 rc = 0;2110 mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);2111 ioc->transport_cmds.smid = smid;2112 2113 memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));2114 mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;2115 mpi_request->PhysicalPort = _transport_get_port_id_by_rphy(ioc, rphy);2116 mpi_request->SASAddress = (rphy) ?2117 cpu_to_le64(rphy->identify.sas_address) :2118 cpu_to_le64(ioc->sas_hba.sas_address);2119 mpi_request->RequestDataLength = cpu_to_le16(dma_len_out - 4);2120 psge = &mpi_request->SGL;2121 2122 ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in,2123 dma_len_in - 4);2124 2125 dtransportprintk(ioc,2126 ioc_info(ioc, "%s: sending smp request\n", __func__));2127 2128 init_completion(&ioc->transport_cmds.done);2129 ioc->put_smid_default(ioc, smid);2130 wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);2131 2132 if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {2133 ioc_err(ioc, "%s: timeout\n", __func__);2134 _debug_dump_mf(mpi_request,2135 sizeof(Mpi2SmpPassthroughRequest_t)/4);2136 if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) {2137 mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);2138 rc = -ETIMEDOUT;2139 goto unmap_in;2140 }2141 }2142 2143 dtransportprintk(ioc, ioc_info(ioc, "%s - complete\n", __func__));2144 2145 if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) {2146 dtransportprintk(ioc,2147 ioc_info(ioc, "%s: no reply\n", __func__));2148 rc = -ENXIO;2149 goto unmap_in;2150 }2151 2152 mpi_reply = ioc->transport_cmds.reply;2153 2154 dtransportprintk(ioc,2155 ioc_info(ioc, "%s: reply data transfer size(%d)\n",2156 __func__,2157 le16_to_cpu(mpi_reply->ResponseDataLength)));2158 2159 memcpy(job->reply, mpi_reply, sizeof(*mpi_reply));2160 job->reply_len = sizeof(*mpi_reply);2161 reslen = le16_to_cpu(mpi_reply->ResponseDataLength);2162 2163 if (addr_in) {2164 sg_copy_to_buffer(job->reply_payload.sg_list,2165 job->reply_payload.sg_cnt, addr_in,2166 job->reply_payload.payload_len);2167 }2168 2169 rc = 0;2170 unmap_in:2171 _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->reply_payload,2172 dma_addr_in, addr_in);2173 unmap_out:2174 _transport_unmap_smp_buffer(&ioc->pdev->dev, &job->request_payload,2175 dma_addr_out, addr_out);2176 out:2177 ioc->transport_cmds.status = MPT3_CMD_NOT_USED;2178 mutex_unlock(&ioc->transport_cmds.mutex);2179job_done:2180 bsg_job_done(job, rc, reslen);2181}2182 2183struct sas_function_template mpt3sas_transport_functions = {2184 .get_linkerrors = _transport_get_linkerrors,2185 .get_enclosure_identifier = _transport_get_enclosure_identifier,2186 .get_bay_identifier = _transport_get_bay_identifier,2187 .phy_reset = _transport_phy_reset,2188 .phy_enable = _transport_phy_enable,2189 .set_phy_speed = _transport_phy_speed,2190 .smp_handler = _transport_smp_handler,2191};2192 2193struct scsi_transport_template *mpt3sas_transport_template;2194