1 /* 2 * driver for Microsemi PQI-based storage controllers 3 * Copyright (c) 2016-2017 Microsemi Corporation 4 * Copyright (c) 2016 PMC-Sierra, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 13 * NON INFRINGEMENT. See the GNU General Public License for more details. 14 * 15 * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com 16 * 17 */ 18 19 #include <linux/kernel.h> 20 #include <linux/bsg-lib.h> 21 #include <scsi/scsi_host.h> 22 #include <scsi/scsi_cmnd.h> 23 #include <scsi/scsi_transport_sas.h> 24 #include <asm/unaligned.h> 25 #include "smartpqi.h" 26 27 static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port) 28 { 29 struct pqi_sas_phy *pqi_sas_phy; 30 struct sas_phy *phy; 31 32 pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL); 33 if (!pqi_sas_phy) 34 return NULL; 35 36 phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev, 37 pqi_sas_port->next_phy_index); 38 if (!phy) { 39 kfree(pqi_sas_phy); 40 return NULL; 41 } 42 43 pqi_sas_port->next_phy_index++; 44 pqi_sas_phy->phy = phy; 45 pqi_sas_phy->parent_port = pqi_sas_port; 46 47 return pqi_sas_phy; 48 } 49 50 static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy) 51 { 52 struct sas_phy *phy = pqi_sas_phy->phy; 53 54 sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy); 55 sas_phy_free(phy); 56 if (pqi_sas_phy->added_to_port) 57 list_del(&pqi_sas_phy->phy_list_entry); 58 kfree(pqi_sas_phy); 59 } 60 61 static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy) 62 { 63 int rc; 64 struct pqi_sas_port *pqi_sas_port; 65 struct sas_phy *phy; 66 struct sas_identify *identify; 67 68 pqi_sas_port = pqi_sas_phy->parent_port; 69 phy = pqi_sas_phy->phy; 70 71 identify = &phy->identify; 72 memset(identify, 0, sizeof(*identify)); 73 identify->sas_address = pqi_sas_port->sas_address; 74 identify->device_type = SAS_END_DEVICE; 75 identify->initiator_port_protocols = SAS_PROTOCOL_STP; 76 identify->target_port_protocols = SAS_PROTOCOL_STP; 77 phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 78 phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 79 phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; 80 phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; 81 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 82 83 rc = sas_phy_add(pqi_sas_phy->phy); 84 if (rc) 85 return rc; 86 87 sas_port_add_phy(pqi_sas_port->port, pqi_sas_phy->phy); 88 list_add_tail(&pqi_sas_phy->phy_list_entry, 89 &pqi_sas_port->phy_list_head); 90 pqi_sas_phy->added_to_port = true; 91 92 return 0; 93 } 94 95 static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port, 96 struct sas_rphy *rphy) 97 { 98 struct sas_identify *identify; 99 100 identify = &rphy->identify; 101 identify->sas_address = pqi_sas_port->sas_address; 102 103 if (pqi_sas_port->device && 104 pqi_sas_port->device->is_expander_smp_device) { 105 identify->initiator_port_protocols = SAS_PROTOCOL_SMP; 106 identify->target_port_protocols = SAS_PROTOCOL_SMP; 107 } else { 108 identify->initiator_port_protocols = SAS_PROTOCOL_STP; 109 identify->target_port_protocols = SAS_PROTOCOL_STP; 110 } 111 112 return sas_rphy_add(rphy); 113 } 114 115 static struct sas_rphy *pqi_sas_rphy_alloc(struct pqi_sas_port *pqi_sas_port) 116 { 117 if (pqi_sas_port->device && 118 pqi_sas_port->device->is_expander_smp_device) 119 return sas_expander_alloc(pqi_sas_port->port, 120 SAS_FANOUT_EXPANDER_DEVICE); 121 122 return sas_end_device_alloc(pqi_sas_port->port); 123 } 124 125 static struct pqi_sas_port *pqi_alloc_sas_port( 126 struct pqi_sas_node *pqi_sas_node, u64 sas_address, 127 struct pqi_scsi_dev *device) 128 { 129 int rc; 130 struct pqi_sas_port *pqi_sas_port; 131 struct sas_port *port; 132 133 pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL); 134 if (!pqi_sas_port) 135 return NULL; 136 137 INIT_LIST_HEAD(&pqi_sas_port->phy_list_head); 138 pqi_sas_port->parent_node = pqi_sas_node; 139 140 port = sas_port_alloc_num(pqi_sas_node->parent_dev); 141 if (!port) 142 goto free_pqi_port; 143 144 rc = sas_port_add(port); 145 if (rc) 146 goto free_sas_port; 147 148 pqi_sas_port->port = port; 149 pqi_sas_port->sas_address = sas_address; 150 pqi_sas_port->device = device; 151 list_add_tail(&pqi_sas_port->port_list_entry, 152 &pqi_sas_node->port_list_head); 153 154 return pqi_sas_port; 155 156 free_sas_port: 157 sas_port_free(port); 158 free_pqi_port: 159 kfree(pqi_sas_port); 160 161 return NULL; 162 } 163 164 static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port) 165 { 166 struct pqi_sas_phy *pqi_sas_phy; 167 struct pqi_sas_phy *next; 168 169 list_for_each_entry_safe(pqi_sas_phy, next, 170 &pqi_sas_port->phy_list_head, phy_list_entry) 171 pqi_free_sas_phy(pqi_sas_phy); 172 173 sas_port_delete(pqi_sas_port->port); 174 list_del(&pqi_sas_port->port_list_entry); 175 kfree(pqi_sas_port); 176 } 177 178 static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev) 179 { 180 struct pqi_sas_node *pqi_sas_node; 181 182 pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL); 183 if (pqi_sas_node) { 184 pqi_sas_node->parent_dev = parent_dev; 185 INIT_LIST_HEAD(&pqi_sas_node->port_list_head); 186 } 187 188 return pqi_sas_node; 189 } 190 191 static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node) 192 { 193 struct pqi_sas_port *pqi_sas_port; 194 struct pqi_sas_port *next; 195 196 if (!pqi_sas_node) 197 return; 198 199 list_for_each_entry_safe(pqi_sas_port, next, 200 &pqi_sas_node->port_list_head, port_list_entry) 201 pqi_free_sas_port(pqi_sas_port); 202 203 kfree(pqi_sas_node); 204 } 205 206 struct pqi_scsi_dev *pqi_find_device_by_sas_rphy( 207 struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy) 208 { 209 struct pqi_scsi_dev *device; 210 211 list_for_each_entry(device, &ctrl_info->scsi_device_list, 212 scsi_device_list_entry) { 213 if (!device->sas_port) 214 continue; 215 if (device->sas_port->rphy == rphy) 216 return device; 217 } 218 219 return NULL; 220 } 221 222 int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info) 223 { 224 int rc; 225 struct device *parent_dev; 226 struct pqi_sas_node *pqi_sas_node; 227 struct pqi_sas_port *pqi_sas_port; 228 struct pqi_sas_phy *pqi_sas_phy; 229 230 parent_dev = &shost->shost_dev; 231 232 pqi_sas_node = pqi_alloc_sas_node(parent_dev); 233 if (!pqi_sas_node) 234 return -ENOMEM; 235 236 pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, 237 ctrl_info->sas_address, NULL); 238 if (!pqi_sas_port) { 239 rc = -ENODEV; 240 goto free_sas_node; 241 } 242 243 pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port); 244 if (!pqi_sas_phy) { 245 rc = -ENODEV; 246 goto free_sas_port; 247 } 248 249 rc = pqi_sas_port_add_phy(pqi_sas_phy); 250 if (rc) 251 goto free_sas_phy; 252 253 ctrl_info->sas_host = pqi_sas_node; 254 255 return 0; 256 257 free_sas_phy: 258 pqi_free_sas_phy(pqi_sas_phy); 259 free_sas_port: 260 pqi_free_sas_port(pqi_sas_port); 261 free_sas_node: 262 pqi_free_sas_node(pqi_sas_node); 263 264 return rc; 265 } 266 267 void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info) 268 { 269 pqi_free_sas_node(ctrl_info->sas_host); 270 } 271 272 int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node, 273 struct pqi_scsi_dev *device) 274 { 275 int rc; 276 struct pqi_sas_port *pqi_sas_port; 277 struct sas_rphy *rphy; 278 279 pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, 280 device->sas_address, device); 281 if (!pqi_sas_port) 282 return -ENOMEM; 283 284 rphy = pqi_sas_rphy_alloc(pqi_sas_port); 285 if (!rphy) { 286 rc = -ENODEV; 287 goto free_sas_port; 288 } 289 290 pqi_sas_port->rphy = rphy; 291 device->sas_port = pqi_sas_port; 292 293 rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy); 294 if (rc) 295 goto free_sas_port; 296 297 return 0; 298 299 free_sas_port: 300 pqi_free_sas_port(pqi_sas_port); 301 device->sas_port = NULL; 302 303 return rc; 304 } 305 306 void pqi_remove_sas_device(struct pqi_scsi_dev *device) 307 { 308 if (device->sas_port) { 309 pqi_free_sas_port(device->sas_port); 310 device->sas_port = NULL; 311 } 312 } 313 314 static int pqi_sas_get_linkerrors(struct sas_phy *phy) 315 { 316 return 0; 317 } 318 319 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, 320 u64 *identifier) 321 { 322 return 0; 323 } 324 325 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy) 326 { 327 return -ENXIO; 328 } 329 330 static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset) 331 { 332 return 0; 333 } 334 335 static int pqi_sas_phy_enable(struct sas_phy *phy, int enable) 336 { 337 return 0; 338 } 339 340 static int pqi_sas_phy_setup(struct sas_phy *phy) 341 { 342 return 0; 343 } 344 345 static void pqi_sas_phy_release(struct sas_phy *phy) 346 { 347 } 348 349 static int pqi_sas_phy_speed(struct sas_phy *phy, 350 struct sas_phy_linkrates *rates) 351 { 352 return -EINVAL; 353 } 354 355 #define CSMI_IOCTL_TIMEOUT 60 356 #define SMP_CRC_FIELD_LENGTH 4 357 358 static struct bmic_csmi_smp_passthru_buffer * 359 pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy, 360 struct bsg_job *job) 361 { 362 struct bmic_csmi_smp_passthru_buffer *smp_buf; 363 struct bmic_csmi_ioctl_header *ioctl_header; 364 struct bmic_csmi_smp_passthru *parameters; 365 u32 req_size; 366 u32 resp_size; 367 368 smp_buf = kzalloc(sizeof(*smp_buf), GFP_KERNEL); 369 if (!smp_buf) 370 return NULL; 371 372 req_size = job->request_payload.payload_len; 373 resp_size = job->reply_payload.payload_len; 374 375 ioctl_header = &smp_buf->ioctl_header; 376 put_unaligned_le32(sizeof(smp_buf->ioctl_header), 377 &ioctl_header->header_length); 378 put_unaligned_le32(CSMI_IOCTL_TIMEOUT, &ioctl_header->timeout); 379 put_unaligned_le32(CSMI_CC_SAS_SMP_PASSTHRU, 380 &ioctl_header->control_code); 381 put_unaligned_le32(sizeof(smp_buf->parameters), &ioctl_header->length); 382 383 parameters = &smp_buf->parameters; 384 parameters->phy_identifier = rphy->identify.phy_identifier; 385 parameters->port_identifier = 0; 386 parameters->connection_rate = 0; 387 put_unaligned_be64(rphy->identify.sas_address, 388 ¶meters->destination_sas_address); 389 390 if (req_size > SMP_CRC_FIELD_LENGTH) 391 req_size -= SMP_CRC_FIELD_LENGTH; 392 393 put_unaligned_le32(req_size, ¶meters->request_length); 394 395 put_unaligned_le32(resp_size, ¶meters->response_length); 396 397 sg_copy_to_buffer(job->request_payload.sg_list, 398 job->reply_payload.sg_cnt, ¶meters->request, 399 req_size); 400 401 return smp_buf; 402 } 403 404 static unsigned int pqi_build_sas_smp_handler_reply( 405 struct bmic_csmi_smp_passthru_buffer *smp_buf, struct bsg_job *job, 406 struct pqi_raid_error_info *error_info) 407 { 408 sg_copy_from_buffer(job->reply_payload.sg_list, 409 job->reply_payload.sg_cnt, &smp_buf->parameters.response, 410 le32_to_cpu(smp_buf->parameters.response_length)); 411 412 job->reply_len = le16_to_cpu(error_info->sense_data_length); 413 memcpy(job->reply, error_info->data, 414 le16_to_cpu(error_info->sense_data_length)); 415 416 return job->reply_payload.payload_len - 417 get_unaligned_le32(&error_info->data_in_transferred); 418 } 419 420 void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, 421 struct sas_rphy *rphy) 422 { 423 int rc; 424 struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost); 425 struct bmic_csmi_smp_passthru_buffer *smp_buf; 426 struct pqi_raid_error_info error_info; 427 unsigned int reslen = 0; 428 429 pqi_ctrl_busy(ctrl_info); 430 431 if (job->reply_payload.payload_len == 0) { 432 rc = -ENOMEM; 433 goto out; 434 } 435 436 if (!rphy) { 437 rc = -EINVAL; 438 goto out; 439 } 440 441 if (rphy->identify.device_type != SAS_FANOUT_EXPANDER_DEVICE) { 442 rc = -EINVAL; 443 goto out; 444 } 445 446 if (job->request_payload.sg_cnt > 1 || job->reply_payload.sg_cnt > 1) { 447 rc = -EINVAL; 448 goto out; 449 } 450 451 if (pqi_ctrl_offline(ctrl_info)) { 452 rc = -ENXIO; 453 goto out; 454 } 455 456 if (pqi_ctrl_blocked(ctrl_info)) { 457 rc = -EBUSY; 458 goto out; 459 } 460 461 smp_buf = pqi_build_csmi_smp_passthru_buffer(rphy, job); 462 if (!smp_buf) { 463 rc = -ENOMEM; 464 goto out; 465 } 466 467 rc = pqi_csmi_smp_passthru(ctrl_info, smp_buf, sizeof(*smp_buf), 468 &error_info); 469 if (rc) 470 goto out; 471 472 reslen = pqi_build_sas_smp_handler_reply(smp_buf, job, &error_info); 473 out: 474 bsg_job_done(job, rc, reslen); 475 pqi_ctrl_unbusy(ctrl_info); 476 } 477 struct sas_function_template pqi_sas_transport_functions = { 478 .get_linkerrors = pqi_sas_get_linkerrors, 479 .get_enclosure_identifier = pqi_sas_get_enclosure_identifier, 480 .get_bay_identifier = pqi_sas_get_bay_identifier, 481 .phy_reset = pqi_sas_phy_reset, 482 .phy_enable = pqi_sas_phy_enable, 483 .phy_setup = pqi_sas_phy_setup, 484 .phy_release = pqi_sas_phy_release, 485 .set_phy_speed = pqi_sas_phy_speed, 486 .smp_handler = pqi_sas_smp_handler, 487 }; 488