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