root/drivers/scsi/smartpqi/smartpqi_sas_transport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pqi_alloc_sas_phy
  2. pqi_free_sas_phy
  3. pqi_sas_port_add_phy
  4. pqi_sas_port_add_rphy
  5. pqi_sas_rphy_alloc
  6. pqi_alloc_sas_port
  7. pqi_free_sas_port
  8. pqi_alloc_sas_node
  9. pqi_free_sas_node
  10. pqi_find_device_by_sas_rphy
  11. pqi_add_sas_host
  12. pqi_delete_sas_host
  13. pqi_add_sas_device
  14. pqi_remove_sas_device
  15. pqi_sas_get_linkerrors
  16. pqi_sas_get_enclosure_identifier
  17. pqi_sas_get_bay_identifier
  18. pqi_sas_phy_reset
  19. pqi_sas_phy_enable
  20. pqi_sas_phy_setup
  21. pqi_sas_phy_release
  22. pqi_sas_phy_speed
  23. pqi_build_csmi_smp_passthru_buffer
  24. pqi_build_sas_smp_handler_reply
  25. pqi_sas_smp_handler

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  *    driver for Microsemi PQI-based storage controllers
   4  *    Copyright (c) 2019 Microchip Technology Inc. and its subsidiaries
   5  *    Copyright (c) 2016-2018 Microsemi Corporation
   6  *    Copyright (c) 2016 PMC-Sierra, Inc.
   7  *
   8  *    Questions/Comments/Bugfixes to storagedev@microchip.com
   9  *
  10  */
  11 
  12 #include <linux/kernel.h>
  13 #include <linux/bsg-lib.h>
  14 #include <scsi/scsi_host.h>
  15 #include <scsi/scsi_cmnd.h>
  16 #include <scsi/scsi_transport_sas.h>
  17 #include <asm/unaligned.h>
  18 #include "smartpqi.h"
  19 
  20 static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port)
  21 {
  22         struct pqi_sas_phy *pqi_sas_phy;
  23         struct sas_phy *phy;
  24 
  25         pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL);
  26         if (!pqi_sas_phy)
  27                 return NULL;
  28 
  29         phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev,
  30                 pqi_sas_port->next_phy_index);
  31         if (!phy) {
  32                 kfree(pqi_sas_phy);
  33                 return NULL;
  34         }
  35 
  36         pqi_sas_port->next_phy_index++;
  37         pqi_sas_phy->phy = phy;
  38         pqi_sas_phy->parent_port = pqi_sas_port;
  39 
  40         return pqi_sas_phy;
  41 }
  42 
  43 static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy)
  44 {
  45         struct sas_phy *phy = pqi_sas_phy->phy;
  46 
  47         sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy);
  48         if (pqi_sas_phy->added_to_port)
  49                 list_del(&pqi_sas_phy->phy_list_entry);
  50         sas_phy_delete(phy);
  51         kfree(pqi_sas_phy);
  52 }
  53 
  54 static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy)
  55 {
  56         int rc;
  57         struct pqi_sas_port *pqi_sas_port;
  58         struct sas_phy *phy;
  59         struct sas_identify *identify;
  60 
  61         pqi_sas_port = pqi_sas_phy->parent_port;
  62         phy = pqi_sas_phy->phy;
  63 
  64         identify = &phy->identify;
  65         memset(identify, 0, sizeof(*identify));
  66         identify->sas_address = pqi_sas_port->sas_address;
  67         identify->device_type = SAS_END_DEVICE;
  68         identify->initiator_port_protocols = SAS_PROTOCOL_STP;
  69         identify->target_port_protocols = SAS_PROTOCOL_STP;
  70         phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
  71         phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
  72         phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
  73         phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
  74         phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
  75 
  76         rc = sas_phy_add(pqi_sas_phy->phy);
  77         if (rc)
  78                 return rc;
  79 
  80         sas_port_add_phy(pqi_sas_port->port, pqi_sas_phy->phy);
  81         list_add_tail(&pqi_sas_phy->phy_list_entry,
  82                 &pqi_sas_port->phy_list_head);
  83         pqi_sas_phy->added_to_port = true;
  84 
  85         return 0;
  86 }
  87 
  88 static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port,
  89         struct sas_rphy *rphy)
  90 {
  91         struct sas_identify *identify;
  92 
  93         identify = &rphy->identify;
  94         identify->sas_address = pqi_sas_port->sas_address;
  95 
  96         if (pqi_sas_port->device &&
  97                 pqi_sas_port->device->is_expander_smp_device) {
  98                 identify->initiator_port_protocols = SAS_PROTOCOL_SMP;
  99                 identify->target_port_protocols = SAS_PROTOCOL_SMP;
 100         } else {
 101                 identify->initiator_port_protocols = SAS_PROTOCOL_STP;
 102                 identify->target_port_protocols = SAS_PROTOCOL_STP;
 103         }
 104 
 105         return sas_rphy_add(rphy);
 106 }
 107 
 108 static struct sas_rphy *pqi_sas_rphy_alloc(struct pqi_sas_port *pqi_sas_port)
 109 {
 110         if (pqi_sas_port->device &&
 111                 pqi_sas_port->device->is_expander_smp_device)
 112                 return sas_expander_alloc(pqi_sas_port->port,
 113                                 SAS_FANOUT_EXPANDER_DEVICE);
 114 
 115         return sas_end_device_alloc(pqi_sas_port->port);
 116 }
 117 
 118 static struct pqi_sas_port *pqi_alloc_sas_port(
 119         struct pqi_sas_node *pqi_sas_node, u64 sas_address,
 120         struct pqi_scsi_dev *device)
 121 {
 122         int rc;
 123         struct pqi_sas_port *pqi_sas_port;
 124         struct sas_port *port;
 125 
 126         pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL);
 127         if (!pqi_sas_port)
 128                 return NULL;
 129 
 130         INIT_LIST_HEAD(&pqi_sas_port->phy_list_head);
 131         pqi_sas_port->parent_node = pqi_sas_node;
 132 
 133         port = sas_port_alloc_num(pqi_sas_node->parent_dev);
 134         if (!port)
 135                 goto free_pqi_port;
 136 
 137         rc = sas_port_add(port);
 138         if (rc)
 139                 goto free_sas_port;
 140 
 141         pqi_sas_port->port = port;
 142         pqi_sas_port->sas_address = sas_address;
 143         pqi_sas_port->device = device;
 144         list_add_tail(&pqi_sas_port->port_list_entry,
 145                 &pqi_sas_node->port_list_head);
 146 
 147         return pqi_sas_port;
 148 
 149 free_sas_port:
 150         sas_port_free(port);
 151 free_pqi_port:
 152         kfree(pqi_sas_port);
 153 
 154         return NULL;
 155 }
 156 
 157 static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port)
 158 {
 159         struct pqi_sas_phy *pqi_sas_phy;
 160         struct pqi_sas_phy *next;
 161 
 162         list_for_each_entry_safe(pqi_sas_phy, next,
 163                 &pqi_sas_port->phy_list_head, phy_list_entry)
 164                 pqi_free_sas_phy(pqi_sas_phy);
 165 
 166         sas_port_delete(pqi_sas_port->port);
 167         list_del(&pqi_sas_port->port_list_entry);
 168         kfree(pqi_sas_port);
 169 }
 170 
 171 static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev)
 172 {
 173         struct pqi_sas_node *pqi_sas_node;
 174 
 175         pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL);
 176         if (pqi_sas_node) {
 177                 pqi_sas_node->parent_dev = parent_dev;
 178                 INIT_LIST_HEAD(&pqi_sas_node->port_list_head);
 179         }
 180 
 181         return pqi_sas_node;
 182 }
 183 
 184 static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node)
 185 {
 186         struct pqi_sas_port *pqi_sas_port;
 187         struct pqi_sas_port *next;
 188 
 189         if (!pqi_sas_node)
 190                 return;
 191 
 192         list_for_each_entry_safe(pqi_sas_port, next,
 193                 &pqi_sas_node->port_list_head, port_list_entry)
 194                 pqi_free_sas_port(pqi_sas_port);
 195 
 196         kfree(pqi_sas_node);
 197 }
 198 
 199 struct pqi_scsi_dev *pqi_find_device_by_sas_rphy(
 200         struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy)
 201 {
 202         struct pqi_scsi_dev *device;
 203 
 204         list_for_each_entry(device, &ctrl_info->scsi_device_list,
 205                 scsi_device_list_entry) {
 206                 if (!device->sas_port)
 207                         continue;
 208                 if (device->sas_port->rphy == rphy)
 209                         return device;
 210         }
 211 
 212         return NULL;
 213 }
 214 
 215 int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info)
 216 {
 217         int rc;
 218         struct device *parent_dev;
 219         struct pqi_sas_node *pqi_sas_node;
 220         struct pqi_sas_port *pqi_sas_port;
 221         struct pqi_sas_phy *pqi_sas_phy;
 222 
 223         parent_dev = &shost->shost_dev;
 224 
 225         pqi_sas_node = pqi_alloc_sas_node(parent_dev);
 226         if (!pqi_sas_node)
 227                 return -ENOMEM;
 228 
 229         pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node,
 230                 ctrl_info->sas_address, NULL);
 231         if (!pqi_sas_port) {
 232                 rc = -ENODEV;
 233                 goto free_sas_node;
 234         }
 235 
 236         pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port);
 237         if (!pqi_sas_phy) {
 238                 rc = -ENODEV;
 239                 goto free_sas_port;
 240         }
 241 
 242         rc = pqi_sas_port_add_phy(pqi_sas_phy);
 243         if (rc)
 244                 goto free_sas_phy;
 245 
 246         ctrl_info->sas_host = pqi_sas_node;
 247 
 248         return 0;
 249 
 250 free_sas_phy:
 251         pqi_free_sas_phy(pqi_sas_phy);
 252 free_sas_port:
 253         pqi_free_sas_port(pqi_sas_port);
 254 free_sas_node:
 255         pqi_free_sas_node(pqi_sas_node);
 256 
 257         return rc;
 258 }
 259 
 260 void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info)
 261 {
 262         pqi_free_sas_node(ctrl_info->sas_host);
 263 }
 264 
 265 int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node,
 266         struct pqi_scsi_dev *device)
 267 {
 268         int rc;
 269         struct pqi_sas_port *pqi_sas_port;
 270         struct sas_rphy *rphy;
 271 
 272         pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node,
 273                 device->sas_address, device);
 274         if (!pqi_sas_port)
 275                 return -ENOMEM;
 276 
 277         rphy = pqi_sas_rphy_alloc(pqi_sas_port);
 278         if (!rphy) {
 279                 rc = -ENODEV;
 280                 goto free_sas_port;
 281         }
 282 
 283         pqi_sas_port->rphy = rphy;
 284         device->sas_port = pqi_sas_port;
 285 
 286         rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy);
 287         if (rc)
 288                 goto free_sas_port;
 289 
 290         return 0;
 291 
 292 free_sas_port:
 293         pqi_free_sas_port(pqi_sas_port);
 294         device->sas_port = NULL;
 295 
 296         return rc;
 297 }
 298 
 299 void pqi_remove_sas_device(struct pqi_scsi_dev *device)
 300 {
 301         if (device->sas_port) {
 302                 pqi_free_sas_port(device->sas_port);
 303                 device->sas_port = NULL;
 304         }
 305 }
 306 
 307 static int pqi_sas_get_linkerrors(struct sas_phy *phy)
 308 {
 309         return 0;
 310 }
 311 
 312 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
 313         u64 *identifier)
 314 {
 315 
 316         int rc;
 317         unsigned long flags;
 318         struct Scsi_Host *shost;
 319         struct pqi_ctrl_info *ctrl_info;
 320         struct pqi_scsi_dev *found_device;
 321         struct pqi_scsi_dev *device;
 322 
 323         if (!rphy)
 324                 return -ENODEV;
 325 
 326         shost = rphy_to_shost(rphy);
 327         ctrl_info = shost_to_hba(shost);
 328         spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
 329         found_device = pqi_find_device_by_sas_rphy(ctrl_info, rphy);
 330 
 331         if (!found_device) {
 332                 rc = -ENODEV;
 333                 goto out;
 334         }
 335 
 336         if (found_device->devtype == TYPE_ENCLOSURE) {
 337                 *identifier = get_unaligned_be64(&found_device->wwid);
 338                 rc = 0;
 339                 goto out;
 340         }
 341 
 342         if (found_device->box_index == 0xff ||
 343                 found_device->phys_box_on_bus == 0 ||
 344                 found_device->bay == 0xff) {
 345                 rc = -EINVAL;
 346                 goto out;
 347         }
 348 
 349         list_for_each_entry(device, &ctrl_info->scsi_device_list,
 350                 scsi_device_list_entry) {
 351                 if (device->devtype == TYPE_ENCLOSURE &&
 352                         device->box_index == found_device->box_index &&
 353                         device->phys_box_on_bus ==
 354                                 found_device->phys_box_on_bus &&
 355                         memcmp(device->phys_connector,
 356                                 found_device->phys_connector, 2) == 0) {
 357                         *identifier =
 358                                 get_unaligned_be64(&device->wwid);
 359                         rc = 0;
 360                         goto out;
 361                 }
 362         }
 363 
 364         if (found_device->phy_connected_dev_type != SA_CONTROLLER_DEVICE) {
 365                 rc = -EINVAL;
 366                 goto out;
 367         }
 368 
 369         list_for_each_entry(device, &ctrl_info->scsi_device_list,
 370                 scsi_device_list_entry) {
 371                 if (device->devtype == TYPE_ENCLOSURE &&
 372                         CISS_GET_DRIVE_NUMBER(device->scsi3addr) ==
 373                                 PQI_VSEP_CISS_BTL) {
 374                         *identifier = get_unaligned_be64(&device->wwid);
 375                         rc = 0;
 376                         goto out;
 377                 }
 378         }
 379 
 380         rc = -EINVAL;
 381 out:
 382         spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
 383 
 384         return rc;
 385 
 386 }
 387 
 388 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
 389 {
 390 
 391         int rc;
 392         unsigned long flags;
 393         struct pqi_ctrl_info *ctrl_info;
 394         struct pqi_scsi_dev *device;
 395         struct Scsi_Host *shost;
 396 
 397         if (!rphy)
 398                 return -ENODEV;
 399 
 400         shost = rphy_to_shost(rphy);
 401         ctrl_info = shost_to_hba(shost);
 402         spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
 403         device = pqi_find_device_by_sas_rphy(ctrl_info, rphy);
 404 
 405         if (!device) {
 406                 rc = -ENODEV;
 407                 goto out;
 408         }
 409 
 410         if (device->bay == 0xff)
 411                 rc = -EINVAL;
 412         else
 413                 rc = device->bay;
 414 
 415 out:
 416         spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
 417 
 418         return rc;
 419 }
 420 
 421 static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset)
 422 {
 423         return 0;
 424 }
 425 
 426 static int pqi_sas_phy_enable(struct sas_phy *phy, int enable)
 427 {
 428         return 0;
 429 }
 430 
 431 static int pqi_sas_phy_setup(struct sas_phy *phy)
 432 {
 433         return 0;
 434 }
 435 
 436 static void pqi_sas_phy_release(struct sas_phy *phy)
 437 {
 438 }
 439 
 440 static int pqi_sas_phy_speed(struct sas_phy *phy,
 441         struct sas_phy_linkrates *rates)
 442 {
 443         return -EINVAL;
 444 }
 445 
 446 #define CSMI_IOCTL_TIMEOUT      60
 447 #define SMP_CRC_FIELD_LENGTH    4
 448 
 449 static struct bmic_csmi_smp_passthru_buffer *
 450 pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy,
 451         struct bsg_job *job)
 452 {
 453         struct bmic_csmi_smp_passthru_buffer *smp_buf;
 454         struct bmic_csmi_ioctl_header *ioctl_header;
 455         struct bmic_csmi_smp_passthru *parameters;
 456         u32 req_size;
 457         u32 resp_size;
 458 
 459         smp_buf = kzalloc(sizeof(*smp_buf), GFP_KERNEL);
 460         if (!smp_buf)
 461                 return NULL;
 462 
 463         req_size = job->request_payload.payload_len;
 464         resp_size = job->reply_payload.payload_len;
 465 
 466         ioctl_header = &smp_buf->ioctl_header;
 467         put_unaligned_le32(sizeof(smp_buf->ioctl_header),
 468                 &ioctl_header->header_length);
 469         put_unaligned_le32(CSMI_IOCTL_TIMEOUT, &ioctl_header->timeout);
 470         put_unaligned_le32(CSMI_CC_SAS_SMP_PASSTHRU,
 471                 &ioctl_header->control_code);
 472         put_unaligned_le32(sizeof(smp_buf->parameters), &ioctl_header->length);
 473 
 474         parameters = &smp_buf->parameters;
 475         parameters->phy_identifier = rphy->identify.phy_identifier;
 476         parameters->port_identifier = 0;
 477         parameters->connection_rate = 0;
 478         put_unaligned_be64(rphy->identify.sas_address,
 479                 &parameters->destination_sas_address);
 480 
 481         if (req_size > SMP_CRC_FIELD_LENGTH)
 482                 req_size -= SMP_CRC_FIELD_LENGTH;
 483 
 484         put_unaligned_le32(req_size, &parameters->request_length);
 485 
 486         put_unaligned_le32(resp_size, &parameters->response_length);
 487 
 488         sg_copy_to_buffer(job->request_payload.sg_list,
 489                 job->reply_payload.sg_cnt, &parameters->request,
 490                 req_size);
 491 
 492         return smp_buf;
 493 }
 494 
 495 static unsigned int pqi_build_sas_smp_handler_reply(
 496         struct bmic_csmi_smp_passthru_buffer *smp_buf, struct bsg_job *job,
 497         struct pqi_raid_error_info *error_info)
 498 {
 499         sg_copy_from_buffer(job->reply_payload.sg_list,
 500                 job->reply_payload.sg_cnt, &smp_buf->parameters.response,
 501                 le32_to_cpu(smp_buf->parameters.response_length));
 502 
 503         job->reply_len = le16_to_cpu(error_info->sense_data_length);
 504         memcpy(job->reply, error_info->data,
 505                         le16_to_cpu(error_info->sense_data_length));
 506 
 507         return job->reply_payload.payload_len -
 508                 get_unaligned_le32(&error_info->data_in_transferred);
 509 }
 510 
 511 void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
 512         struct sas_rphy *rphy)
 513 {
 514         int rc;
 515         struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost);
 516         struct bmic_csmi_smp_passthru_buffer *smp_buf;
 517         struct pqi_raid_error_info error_info;
 518         unsigned int reslen = 0;
 519 
 520         pqi_ctrl_busy(ctrl_info);
 521 
 522         if (job->reply_payload.payload_len == 0) {
 523                 rc = -ENOMEM;
 524                 goto out;
 525         }
 526 
 527         if (!rphy) {
 528                 rc = -EINVAL;
 529                 goto out;
 530         }
 531 
 532         if (rphy->identify.device_type != SAS_FANOUT_EXPANDER_DEVICE) {
 533                 rc = -EINVAL;
 534                 goto out;
 535         }
 536 
 537         if (job->request_payload.sg_cnt > 1 || job->reply_payload.sg_cnt > 1) {
 538                 rc = -EINVAL;
 539                 goto out;
 540         }
 541 
 542         if (pqi_ctrl_offline(ctrl_info)) {
 543                 rc = -ENXIO;
 544                 goto out;
 545         }
 546 
 547         if (pqi_ctrl_blocked(ctrl_info)) {
 548                 rc = -EBUSY;
 549                 goto out;
 550         }
 551 
 552         smp_buf = pqi_build_csmi_smp_passthru_buffer(rphy, job);
 553         if (!smp_buf) {
 554                 rc = -ENOMEM;
 555                 goto out;
 556         }
 557 
 558         rc = pqi_csmi_smp_passthru(ctrl_info, smp_buf, sizeof(*smp_buf),
 559                 &error_info);
 560         if (rc)
 561                 goto out;
 562 
 563         reslen = pqi_build_sas_smp_handler_reply(smp_buf, job, &error_info);
 564 out:
 565         bsg_job_done(job, rc, reslen);
 566         pqi_ctrl_unbusy(ctrl_info);
 567 }
 568 struct sas_function_template pqi_sas_transport_functions = {
 569         .get_linkerrors = pqi_sas_get_linkerrors,
 570         .get_enclosure_identifier = pqi_sas_get_enclosure_identifier,
 571         .get_bay_identifier = pqi_sas_get_bay_identifier,
 572         .phy_reset = pqi_sas_phy_reset,
 573         .phy_enable = pqi_sas_phy_enable,
 574         .phy_setup = pqi_sas_phy_setup,
 575         .phy_release = pqi_sas_phy_release,
 576         .set_phy_speed = pqi_sas_phy_speed,
 577         .smp_handler = pqi_sas_smp_handler,
 578 };

/* [<][>][^][v][top][bottom][index][help] */