forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-01-04 1543e317f1da31b75942316931e8f491a8920811
kernel/drivers/scsi/smartpqi/smartpqi_sas_transport.c
....@@ -1,25 +1,20 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * driver for Microsemi PQI-based storage controllers
3
- * Copyright (c) 2016-2017 Microsemi Corporation
4
+ * Copyright (c) 2019-2020 Microchip Technology Inc. and its subsidiaries
5
+ * Copyright (c) 2016-2018 Microsemi Corporation
46 * Copyright (c) 2016 PMC-Sierra, Inc.
57 *
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
8
+ * Questions/Comments/Bugfixes to storagedev@microchip.com
169 *
1710 */
1811
1912 #include <linux/kernel.h>
13
+#include <linux/bsg-lib.h>
2014 #include <scsi/scsi_host.h>
2115 #include <scsi/scsi_cmnd.h>
2216 #include <scsi/scsi_transport_sas.h>
17
+#include <asm/unaligned.h>
2318 #include "smartpqi.h"
2419
2520 static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port)
....@@ -97,14 +92,32 @@
9792
9893 identify = &rphy->identify;
9994 identify->sas_address = pqi_sas_port->sas_address;
100
- identify->initiator_port_protocols = SAS_PROTOCOL_STP;
101
- identify->target_port_protocols = SAS_PROTOCOL_STP;
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
+ }
102104
103105 return sas_rphy_add(rphy);
104106 }
105107
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
+
106118 static struct pqi_sas_port *pqi_alloc_sas_port(
107
- struct pqi_sas_node *pqi_sas_node, u64 sas_address)
119
+ struct pqi_sas_node *pqi_sas_node, u64 sas_address,
120
+ struct pqi_scsi_dev *device)
108121 {
109122 int rc;
110123 struct pqi_sas_port *pqi_sas_port;
....@@ -127,6 +140,7 @@
127140
128141 pqi_sas_port->port = port;
129142 pqi_sas_port->sas_address = sas_address;
143
+ pqi_sas_port->device = device;
130144 list_add_tail(&pqi_sas_port->port_list_entry,
131145 &pqi_sas_node->port_list_head);
132146
....@@ -146,7 +160,7 @@
146160 struct pqi_sas_phy *next;
147161
148162 list_for_each_entry_safe(pqi_sas_phy, next,
149
- &pqi_sas_port->phy_list_head, phy_list_entry)
163
+ &pqi_sas_port->phy_list_head, phy_list_entry)
150164 pqi_free_sas_phy(pqi_sas_phy);
151165
152166 sas_port_delete(pqi_sas_port->port);
....@@ -176,7 +190,7 @@
176190 return;
177191
178192 list_for_each_entry_safe(pqi_sas_port, next,
179
- &pqi_sas_node->port_list_head, port_list_entry)
193
+ &pqi_sas_node->port_list_head, port_list_entry)
180194 pqi_free_sas_port(pqi_sas_port);
181195
182196 kfree(pqi_sas_node);
....@@ -206,13 +220,14 @@
206220 struct pqi_sas_port *pqi_sas_port;
207221 struct pqi_sas_phy *pqi_sas_phy;
208222
209
- parent_dev = &shost->shost_gendev;
223
+ parent_dev = &shost->shost_dev;
210224
211225 pqi_sas_node = pqi_alloc_sas_node(parent_dev);
212226 if (!pqi_sas_node)
213227 return -ENOMEM;
214228
215
- pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, ctrl_info->sas_address);
229
+ pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node,
230
+ ctrl_info->sas_address, NULL);
216231 if (!pqi_sas_port) {
217232 rc = -ENODEV;
218233 goto free_sas_node;
....@@ -254,11 +269,12 @@
254269 struct pqi_sas_port *pqi_sas_port;
255270 struct sas_rphy *rphy;
256271
257
- pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, device->sas_address);
272
+ pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node,
273
+ device->sas_address, device);
258274 if (!pqi_sas_port)
259275 return -ENOMEM;
260276
261
- rphy = sas_end_device_alloc(pqi_sas_port->port);
277
+ rphy = pqi_sas_rphy_alloc(pqi_sas_port);
262278 if (!rphy) {
263279 rc = -ENODEV;
264280 goto free_sas_port;
....@@ -296,12 +312,107 @@
296312 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy,
297313 u64 *identifier)
298314 {
299
- return 0;
315
+ int rc;
316
+ unsigned long flags;
317
+ struct Scsi_Host *shost;
318
+ struct pqi_ctrl_info *ctrl_info;
319
+ struct pqi_scsi_dev *found_device;
320
+ struct pqi_scsi_dev *device;
321
+
322
+ if (!rphy)
323
+ return -ENODEV;
324
+
325
+ shost = rphy_to_shost(rphy);
326
+ ctrl_info = shost_to_hba(shost);
327
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
328
+ found_device = pqi_find_device_by_sas_rphy(ctrl_info, rphy);
329
+
330
+ if (!found_device) {
331
+ rc = -ENODEV;
332
+ goto out;
333
+ }
334
+
335
+ if (found_device->devtype == TYPE_ENCLOSURE) {
336
+ *identifier = get_unaligned_be64(&found_device->wwid);
337
+ rc = 0;
338
+ goto out;
339
+ }
340
+
341
+ if (found_device->box_index == 0xff ||
342
+ found_device->phys_box_on_bus == 0 ||
343
+ found_device->bay == 0xff) {
344
+ rc = -EINVAL;
345
+ goto out;
346
+ }
347
+
348
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
349
+ scsi_device_list_entry) {
350
+ if (device->devtype == TYPE_ENCLOSURE &&
351
+ device->box_index == found_device->box_index &&
352
+ device->phys_box_on_bus ==
353
+ found_device->phys_box_on_bus &&
354
+ memcmp(device->phys_connector,
355
+ found_device->phys_connector, 2) == 0) {
356
+ *identifier =
357
+ get_unaligned_be64(&device->wwid);
358
+ rc = 0;
359
+ goto out;
360
+ }
361
+ }
362
+
363
+ if (found_device->phy_connected_dev_type != SA_DEVICE_TYPE_CONTROLLER) {
364
+ rc = -EINVAL;
365
+ goto out;
366
+ }
367
+
368
+ list_for_each_entry(device, &ctrl_info->scsi_device_list,
369
+ scsi_device_list_entry) {
370
+ if (device->devtype == TYPE_ENCLOSURE &&
371
+ CISS_GET_DRIVE_NUMBER(device->scsi3addr) ==
372
+ PQI_VSEP_CISS_BTL) {
373
+ *identifier = get_unaligned_be64(&device->wwid);
374
+ rc = 0;
375
+ goto out;
376
+ }
377
+ }
378
+
379
+ rc = -EINVAL;
380
+out:
381
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
382
+
383
+ return rc;
300384 }
301385
302386 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy)
303387 {
304
- return -ENXIO;
388
+ int rc;
389
+ unsigned long flags;
390
+ struct pqi_ctrl_info *ctrl_info;
391
+ struct pqi_scsi_dev *device;
392
+ struct Scsi_Host *shost;
393
+
394
+ if (!rphy)
395
+ return -ENODEV;
396
+
397
+ shost = rphy_to_shost(rphy);
398
+ ctrl_info = shost_to_hba(shost);
399
+ spin_lock_irqsave(&ctrl_info->scsi_device_list_lock, flags);
400
+ device = pqi_find_device_by_sas_rphy(ctrl_info, rphy);
401
+
402
+ if (!device) {
403
+ rc = -ENODEV;
404
+ goto out;
405
+ }
406
+
407
+ if (device->bay == 0xff)
408
+ rc = -EINVAL;
409
+ else
410
+ rc = device->bay;
411
+
412
+out:
413
+ spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags);
414
+
415
+ return rc;
305416 }
306417
307418 static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset)
....@@ -329,6 +440,117 @@
329440 return -EINVAL;
330441 }
331442
443
+#define CSMI_IOCTL_TIMEOUT 60
444
+#define SMP_CRC_FIELD_LENGTH 4
445
+
446
+static struct bmic_csmi_smp_passthru_buffer *
447
+pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy,
448
+ struct bsg_job *job)
449
+{
450
+ struct bmic_csmi_smp_passthru_buffer *smp_buf;
451
+ struct bmic_csmi_ioctl_header *ioctl_header;
452
+ struct bmic_csmi_smp_passthru *parameters;
453
+ u32 req_size;
454
+ u32 resp_size;
455
+
456
+ smp_buf = kzalloc(sizeof(*smp_buf), GFP_KERNEL);
457
+ if (!smp_buf)
458
+ return NULL;
459
+
460
+ req_size = job->request_payload.payload_len;
461
+ resp_size = job->reply_payload.payload_len;
462
+
463
+ ioctl_header = &smp_buf->ioctl_header;
464
+ put_unaligned_le32(sizeof(smp_buf->ioctl_header),
465
+ &ioctl_header->header_length);
466
+ put_unaligned_le32(CSMI_IOCTL_TIMEOUT, &ioctl_header->timeout);
467
+ put_unaligned_le32(CSMI_CC_SAS_SMP_PASSTHRU,
468
+ &ioctl_header->control_code);
469
+ put_unaligned_le32(sizeof(smp_buf->parameters), &ioctl_header->length);
470
+
471
+ parameters = &smp_buf->parameters;
472
+ parameters->phy_identifier = rphy->identify.phy_identifier;
473
+ parameters->port_identifier = 0;
474
+ parameters->connection_rate = 0;
475
+ put_unaligned_be64(rphy->identify.sas_address,
476
+ &parameters->destination_sas_address);
477
+
478
+ if (req_size > SMP_CRC_FIELD_LENGTH)
479
+ req_size -= SMP_CRC_FIELD_LENGTH;
480
+
481
+ put_unaligned_le32(req_size, &parameters->request_length);
482
+ put_unaligned_le32(resp_size, &parameters->response_length);
483
+
484
+ sg_copy_to_buffer(job->request_payload.sg_list,
485
+ job->reply_payload.sg_cnt, &parameters->request,
486
+ req_size);
487
+
488
+ return smp_buf;
489
+}
490
+
491
+static unsigned int pqi_build_sas_smp_handler_reply(
492
+ struct bmic_csmi_smp_passthru_buffer *smp_buf, struct bsg_job *job,
493
+ struct pqi_raid_error_info *error_info)
494
+{
495
+ sg_copy_from_buffer(job->reply_payload.sg_list,
496
+ job->reply_payload.sg_cnt, &smp_buf->parameters.response,
497
+ le32_to_cpu(smp_buf->parameters.response_length));
498
+
499
+ job->reply_len = le16_to_cpu(error_info->sense_data_length);
500
+ memcpy(job->reply, error_info->data,
501
+ le16_to_cpu(error_info->sense_data_length));
502
+
503
+ return job->reply_payload.payload_len -
504
+ get_unaligned_le32(&error_info->data_in_transferred);
505
+}
506
+
507
+void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
508
+ struct sas_rphy *rphy)
509
+{
510
+ int rc;
511
+ struct pqi_ctrl_info *ctrl_info;
512
+ struct bmic_csmi_smp_passthru_buffer *smp_buf;
513
+ struct pqi_raid_error_info error_info;
514
+ unsigned int reslen = 0;
515
+
516
+ ctrl_info = shost_to_hba(shost);
517
+
518
+ if (job->reply_payload.payload_len == 0) {
519
+ rc = -ENOMEM;
520
+ goto out;
521
+ }
522
+
523
+ if (!rphy) {
524
+ rc = -EINVAL;
525
+ goto out;
526
+ }
527
+
528
+ if (rphy->identify.device_type != SAS_FANOUT_EXPANDER_DEVICE) {
529
+ rc = -EINVAL;
530
+ goto out;
531
+ }
532
+
533
+ if (job->request_payload.sg_cnt > 1 || job->reply_payload.sg_cnt > 1) {
534
+ rc = -EINVAL;
535
+ goto out;
536
+ }
537
+
538
+ smp_buf = pqi_build_csmi_smp_passthru_buffer(rphy, job);
539
+ if (!smp_buf) {
540
+ rc = -ENOMEM;
541
+ goto out;
542
+ }
543
+
544
+ rc = pqi_csmi_smp_passthru(ctrl_info, smp_buf, sizeof(*smp_buf),
545
+ &error_info);
546
+ if (rc)
547
+ goto out;
548
+
549
+ reslen = pqi_build_sas_smp_handler_reply(smp_buf, job, &error_info);
550
+out:
551
+ bsg_job_done(job, rc, reslen);
552
+ pqi_ctrl_unbusy(ctrl_info);
553
+}
332554 struct sas_function_template pqi_sas_transport_functions = {
333555 .get_linkerrors = pqi_sas_get_linkerrors,
334556 .get_enclosure_identifier = pqi_sas_get_enclosure_identifier,
....@@ -338,4 +560,5 @@
338560 .phy_setup = pqi_sas_phy_setup,
339561 .phy_release = pqi_sas_phy_release,
340562 .set_phy_speed = pqi_sas_phy_speed,
563
+ .smp_handler = pqi_sas_smp_handler,
341564 };