| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * FiberChannel transport specific attributes exported to sysfs. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. |
|---|
| 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; either version 2 of the License, or |
|---|
| 9 | | - * (at your option) any later version. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 14 | | - * GNU General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program; if not, write to the Free Software |
|---|
| 18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 19 | | - * |
|---|
| 20 | | - * ======== |
|---|
| 21 | | - * |
|---|
| 22 | 6 | * Copyright (C) 2004-2007 James Smart, Emulex Corporation |
|---|
| 23 | 7 | * Rewrite for host, target, device, and remote port attributes, |
|---|
| 24 | 8 | * statistics, and service functions... |
|---|
| 25 | 9 | * Add vports, etc |
|---|
| 26 | | - * |
|---|
| 27 | 10 | */ |
|---|
| 28 | 11 | #include <linux/module.h> |
|---|
| 29 | 12 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 147 | 130 | { FCH_EVT_PORT_OFFLINE, "port_offline" }, |
|---|
| 148 | 131 | { FCH_EVT_PORT_FABRIC, "port_fabric" }, |
|---|
| 149 | 132 | { FCH_EVT_LINK_UNKNOWN, "link_unknown" }, |
|---|
| 133 | + { FCH_EVT_LINK_FPIN, "link_FPIN" }, |
|---|
| 150 | 134 | { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" }, |
|---|
| 151 | 135 | }; |
|---|
| 152 | 136 | fc_enum_name_search(host_event_code, fc_host_event_code, |
|---|
| .. | .. |
|---|
| 269 | 253 | { FC_PORTSPEED_25GBIT, "25 Gbit" }, |
|---|
| 270 | 254 | { FC_PORTSPEED_64GBIT, "64 Gbit" }, |
|---|
| 271 | 255 | { FC_PORTSPEED_128GBIT, "128 Gbit" }, |
|---|
| 256 | + { FC_PORTSPEED_256GBIT, "256 Gbit" }, |
|---|
| 272 | 257 | { FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" }, |
|---|
| 273 | 258 | }; |
|---|
| 274 | 259 | fc_bitfield_name_search(port_speed, fc_port_speed_names) |
|---|
| .. | .. |
|---|
| 295 | 280 | { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, |
|---|
| 296 | 281 | { FC_PORT_ROLE_IP_PORT, "IP Port" }, |
|---|
| 297 | 282 | { FC_PORT_ROLE_FCP_DUMMY_INITIATOR, "FCP Dummy Initiator" }, |
|---|
| 283 | + { FC_PORT_ROLE_NVME_INITIATOR, "NVMe Initiator" }, |
|---|
| 284 | + { FC_PORT_ROLE_NVME_TARGET, "NVMe Target" }, |
|---|
| 285 | + { FC_PORT_ROLE_NVME_DISCOVERY, "NVMe Discovery" }, |
|---|
| 298 | 286 | }; |
|---|
| 299 | 287 | fc_bitfield_name_search(port_roles, fc_port_role_names) |
|---|
| 300 | 288 | |
|---|
| .. | .. |
|---|
| 523 | 511 | } |
|---|
| 524 | 512 | EXPORT_SYMBOL(fc_get_event_number); |
|---|
| 525 | 513 | |
|---|
| 526 | | - |
|---|
| 527 | 514 | /** |
|---|
| 528 | | - * fc_host_post_event - called to post an even on an fc_host. |
|---|
| 515 | + * fc_host_post_fc_event - routine to do the work of posting an event |
|---|
| 516 | + * on an fc_host. |
|---|
| 529 | 517 | * @shost: host the event occurred on |
|---|
| 530 | 518 | * @event_number: fc event number obtained from get_fc_event_number() |
|---|
| 531 | 519 | * @event_code: fc_host event being posted |
|---|
| 532 | | - * @event_data: 32bits of data for the event being posted |
|---|
| 520 | + * @data_len: amount, in bytes, of event data |
|---|
| 521 | + * @data_buf: pointer to event data |
|---|
| 522 | + * @vendor_id: value for Vendor id |
|---|
| 533 | 523 | * |
|---|
| 534 | 524 | * Notes: |
|---|
| 535 | 525 | * This routine assumes no locks are held on entry. |
|---|
| 536 | 526 | */ |
|---|
| 537 | 527 | void |
|---|
| 538 | | -fc_host_post_event(struct Scsi_Host *shost, u32 event_number, |
|---|
| 539 | | - enum fc_host_event_code event_code, u32 event_data) |
|---|
| 528 | +fc_host_post_fc_event(struct Scsi_Host *shost, u32 event_number, |
|---|
| 529 | + enum fc_host_event_code event_code, |
|---|
| 530 | + u32 data_len, char *data_buf, u64 vendor_id) |
|---|
| 540 | 531 | { |
|---|
| 541 | 532 | struct sk_buff *skb; |
|---|
| 542 | 533 | struct nlmsghdr *nlh; |
|---|
| .. | .. |
|---|
| 545 | 536 | u32 len; |
|---|
| 546 | 537 | int err; |
|---|
| 547 | 538 | |
|---|
| 539 | + if (!data_buf || data_len < 4) |
|---|
| 540 | + data_len = 0; |
|---|
| 541 | + |
|---|
| 548 | 542 | if (!scsi_nl_sock) { |
|---|
| 549 | 543 | err = -ENOENT; |
|---|
| 550 | 544 | goto send_fail; |
|---|
| 551 | 545 | } |
|---|
| 552 | 546 | |
|---|
| 553 | | - len = FC_NL_MSGALIGN(sizeof(*event)); |
|---|
| 547 | + len = FC_NL_MSGALIGN(sizeof(*event) + data_len); |
|---|
| 554 | 548 | |
|---|
| 555 | 549 | skb = nlmsg_new(len, GFP_KERNEL); |
|---|
| 556 | 550 | if (!skb) { |
|---|
| .. | .. |
|---|
| 568 | 562 | INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, |
|---|
| 569 | 563 | FC_NL_ASYNC_EVENT, len); |
|---|
| 570 | 564 | event->seconds = ktime_get_real_seconds(); |
|---|
| 571 | | - event->vendor_id = 0; |
|---|
| 565 | + event->vendor_id = vendor_id; |
|---|
| 572 | 566 | event->host_no = shost->host_no; |
|---|
| 573 | | - event->event_datalen = sizeof(u32); /* bytes */ |
|---|
| 567 | + event->event_datalen = data_len; /* bytes */ |
|---|
| 574 | 568 | event->event_num = event_number; |
|---|
| 575 | 569 | event->event_code = event_code; |
|---|
| 576 | | - event->event_data = event_data; |
|---|
| 570 | + if (data_len) |
|---|
| 571 | + memcpy(&event->event_data, data_buf, data_len); |
|---|
| 577 | 572 | |
|---|
| 578 | 573 | nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, |
|---|
| 579 | 574 | GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 586 | 581 | printk(KERN_WARNING |
|---|
| 587 | 582 | "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", |
|---|
| 588 | 583 | __func__, shost->host_no, |
|---|
| 589 | | - (name) ? name : "<unknown>", event_data, err); |
|---|
| 584 | + (name) ? name : "<unknown>", |
|---|
| 585 | + (data_len) ? *((u32 *)data_buf) : 0xFFFFFFFF, err); |
|---|
| 590 | 586 | return; |
|---|
| 587 | +} |
|---|
| 588 | +EXPORT_SYMBOL(fc_host_post_fc_event); |
|---|
| 589 | + |
|---|
| 590 | +/** |
|---|
| 591 | + * fc_host_post_event - called to post an even on an fc_host. |
|---|
| 592 | + * @shost: host the event occurred on |
|---|
| 593 | + * @event_number: fc event number obtained from get_fc_event_number() |
|---|
| 594 | + * @event_code: fc_host event being posted |
|---|
| 595 | + * @event_data: 32bits of data for the event being posted |
|---|
| 596 | + * |
|---|
| 597 | + * Notes: |
|---|
| 598 | + * This routine assumes no locks are held on entry. |
|---|
| 599 | + */ |
|---|
| 600 | +void |
|---|
| 601 | +fc_host_post_event(struct Scsi_Host *shost, u32 event_number, |
|---|
| 602 | + enum fc_host_event_code event_code, u32 event_data) |
|---|
| 603 | +{ |
|---|
| 604 | + fc_host_post_fc_event(shost, event_number, event_code, |
|---|
| 605 | + (u32)sizeof(u32), (char *)&event_data, 0); |
|---|
| 591 | 606 | } |
|---|
| 592 | 607 | EXPORT_SYMBOL(fc_host_post_event); |
|---|
| 593 | 608 | |
|---|
| 594 | 609 | |
|---|
| 595 | 610 | /** |
|---|
| 596 | | - * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host |
|---|
| 611 | + * fc_host_post_vendor_event - called to post a vendor unique event |
|---|
| 612 | + * on an fc_host |
|---|
| 597 | 613 | * @shost: host the event occurred on |
|---|
| 598 | 614 | * @event_number: fc event number obtained from get_fc_event_number() |
|---|
| 599 | 615 | * @data_len: amount, in bytes, of vendor unique data |
|---|
| .. | .. |
|---|
| 607 | 623 | fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, |
|---|
| 608 | 624 | u32 data_len, char * data_buf, u64 vendor_id) |
|---|
| 609 | 625 | { |
|---|
| 610 | | - struct sk_buff *skb; |
|---|
| 611 | | - struct nlmsghdr *nlh; |
|---|
| 612 | | - struct fc_nl_event *event; |
|---|
| 613 | | - u32 len; |
|---|
| 614 | | - int err; |
|---|
| 615 | | - |
|---|
| 616 | | - if (!scsi_nl_sock) { |
|---|
| 617 | | - err = -ENOENT; |
|---|
| 618 | | - goto send_vendor_fail; |
|---|
| 619 | | - } |
|---|
| 620 | | - |
|---|
| 621 | | - len = FC_NL_MSGALIGN(sizeof(*event) + data_len); |
|---|
| 622 | | - |
|---|
| 623 | | - skb = nlmsg_new(len, GFP_KERNEL); |
|---|
| 624 | | - if (!skb) { |
|---|
| 625 | | - err = -ENOBUFS; |
|---|
| 626 | | - goto send_vendor_fail; |
|---|
| 627 | | - } |
|---|
| 628 | | - |
|---|
| 629 | | - nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, len, 0); |
|---|
| 630 | | - if (!nlh) { |
|---|
| 631 | | - err = -ENOBUFS; |
|---|
| 632 | | - goto send_vendor_fail_skb; |
|---|
| 633 | | - } |
|---|
| 634 | | - event = nlmsg_data(nlh); |
|---|
| 635 | | - |
|---|
| 636 | | - INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, |
|---|
| 637 | | - FC_NL_ASYNC_EVENT, len); |
|---|
| 638 | | - event->seconds = ktime_get_real_seconds(); |
|---|
| 639 | | - event->vendor_id = vendor_id; |
|---|
| 640 | | - event->host_no = shost->host_no; |
|---|
| 641 | | - event->event_datalen = data_len; /* bytes */ |
|---|
| 642 | | - event->event_num = event_number; |
|---|
| 643 | | - event->event_code = FCH_EVT_VENDOR_UNIQUE; |
|---|
| 644 | | - memcpy(&event->event_data, data_buf, data_len); |
|---|
| 645 | | - |
|---|
| 646 | | - nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, |
|---|
| 647 | | - GFP_KERNEL); |
|---|
| 648 | | - return; |
|---|
| 649 | | - |
|---|
| 650 | | -send_vendor_fail_skb: |
|---|
| 651 | | - kfree_skb(skb); |
|---|
| 652 | | -send_vendor_fail: |
|---|
| 653 | | - printk(KERN_WARNING |
|---|
| 654 | | - "%s: Dropped Event : host %d vendor_unique - err %d\n", |
|---|
| 655 | | - __func__, shost->host_no, err); |
|---|
| 656 | | - return; |
|---|
| 626 | + fc_host_post_fc_event(shost, event_number, FCH_EVT_VENDOR_UNIQUE, |
|---|
| 627 | + data_len, data_buf, vendor_id); |
|---|
| 657 | 628 | } |
|---|
| 658 | 629 | EXPORT_SYMBOL(fc_host_post_vendor_event); |
|---|
| 659 | 630 | |
|---|
| 631 | +/** |
|---|
| 632 | + * fc_host_rcv_fpin - routine to process a received FPIN. |
|---|
| 633 | + * @shost: host the FPIN was received on |
|---|
| 634 | + * @fpin_len: length of FPIN payload, in bytes |
|---|
| 635 | + * @fpin_buf: pointer to FPIN payload |
|---|
| 636 | + * |
|---|
| 637 | + * Notes: |
|---|
| 638 | + * This routine assumes no locks are held on entry. |
|---|
| 639 | + */ |
|---|
| 640 | +void |
|---|
| 641 | +fc_host_fpin_rcv(struct Scsi_Host *shost, u32 fpin_len, char *fpin_buf) |
|---|
| 642 | +{ |
|---|
| 643 | + fc_host_post_fc_event(shost, fc_get_event_number(), |
|---|
| 644 | + FCH_EVT_LINK_FPIN, fpin_len, fpin_buf, 0); |
|---|
| 645 | +} |
|---|
| 646 | +EXPORT_SYMBOL(fc_host_fpin_rcv); |
|---|
| 660 | 647 | |
|---|
| 661 | 648 | |
|---|
| 662 | 649 | static __init int fc_transport_init(void) |
|---|
| .. | .. |
|---|
| 3592 | 3579 | |
|---|
| 3593 | 3580 | /* the blk_end_sync_io() doesn't check the error */ |
|---|
| 3594 | 3581 | if (inflight) |
|---|
| 3595 | | - __blk_complete_request(req); |
|---|
| 3582 | + blk_mq_end_request(req, BLK_STS_IOERR); |
|---|
| 3596 | 3583 | return BLK_EH_DONE; |
|---|
| 3597 | 3584 | } |
|---|
| 3598 | 3585 | |
|---|
| .. | .. |
|---|
| 3684 | 3671 | fc_bsg_goose_queue(struct fc_rport *rport) |
|---|
| 3685 | 3672 | { |
|---|
| 3686 | 3673 | struct request_queue *q = rport->rqst_q; |
|---|
| 3687 | | - unsigned long flags; |
|---|
| 3688 | 3674 | |
|---|
| 3689 | | - if (!q) |
|---|
| 3690 | | - return; |
|---|
| 3691 | | - |
|---|
| 3692 | | - spin_lock_irqsave(q->queue_lock, flags); |
|---|
| 3693 | | - blk_run_queue_async(q); |
|---|
| 3694 | | - spin_unlock_irqrestore(q->queue_lock, flags); |
|---|
| 3675 | + if (q) |
|---|
| 3676 | + blk_mq_run_hw_queues(q, true); |
|---|
| 3695 | 3677 | } |
|---|
| 3696 | 3678 | |
|---|
| 3697 | 3679 | /** |
|---|
| .. | .. |
|---|
| 3759 | 3741 | return fc_bsg_host_dispatch(shost, job); |
|---|
| 3760 | 3742 | } |
|---|
| 3761 | 3743 | |
|---|
| 3744 | +static blk_status_t fc_bsg_rport_prep(struct fc_rport *rport) |
|---|
| 3745 | +{ |
|---|
| 3746 | + if (rport->port_state == FC_PORTSTATE_BLOCKED && |
|---|
| 3747 | + !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) |
|---|
| 3748 | + return BLK_STS_RESOURCE; |
|---|
| 3749 | + |
|---|
| 3750 | + if (rport->port_state != FC_PORTSTATE_ONLINE) |
|---|
| 3751 | + return BLK_STS_IOERR; |
|---|
| 3752 | + |
|---|
| 3753 | + return BLK_STS_OK; |
|---|
| 3754 | +} |
|---|
| 3755 | + |
|---|
| 3756 | + |
|---|
| 3757 | +static int fc_bsg_dispatch_prep(struct bsg_job *job) |
|---|
| 3758 | +{ |
|---|
| 3759 | + struct fc_rport *rport = fc_bsg_to_rport(job); |
|---|
| 3760 | + blk_status_t ret; |
|---|
| 3761 | + |
|---|
| 3762 | + ret = fc_bsg_rport_prep(rport); |
|---|
| 3763 | + switch (ret) { |
|---|
| 3764 | + case BLK_STS_OK: |
|---|
| 3765 | + break; |
|---|
| 3766 | + case BLK_STS_RESOURCE: |
|---|
| 3767 | + return -EAGAIN; |
|---|
| 3768 | + default: |
|---|
| 3769 | + return -EIO; |
|---|
| 3770 | + } |
|---|
| 3771 | + |
|---|
| 3772 | + return fc_bsg_dispatch(job); |
|---|
| 3773 | +} |
|---|
| 3774 | + |
|---|
| 3762 | 3775 | /** |
|---|
| 3763 | 3776 | * fc_bsg_hostadd - Create and add the bsg hooks so we can receive requests |
|---|
| 3764 | 3777 | * @shost: shost for fc_host |
|---|
| .. | .. |
|---|
| 3780 | 3793 | snprintf(bsg_name, sizeof(bsg_name), |
|---|
| 3781 | 3794 | "fc_host%d", shost->host_no); |
|---|
| 3782 | 3795 | |
|---|
| 3783 | | - q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, i->f->dd_bsg_size); |
|---|
| 3796 | + q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, fc_bsg_job_timeout, |
|---|
| 3797 | + i->f->dd_bsg_size); |
|---|
| 3784 | 3798 | if (IS_ERR(q)) { |
|---|
| 3785 | 3799 | dev_err(dev, |
|---|
| 3786 | 3800 | "fc_host%d: bsg interface failed to initialize - setup queue\n", |
|---|
| .. | .. |
|---|
| 3788 | 3802 | return PTR_ERR(q); |
|---|
| 3789 | 3803 | } |
|---|
| 3790 | 3804 | __scsi_init_queue(shost, q); |
|---|
| 3791 | | - blk_queue_rq_timed_out(q, fc_bsg_job_timeout); |
|---|
| 3792 | 3805 | blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT); |
|---|
| 3793 | 3806 | fc_host->rqst_q = q; |
|---|
| 3794 | 3807 | return 0; |
|---|
| 3795 | | -} |
|---|
| 3796 | | - |
|---|
| 3797 | | -static int fc_bsg_rport_prep(struct request_queue *q, struct request *req) |
|---|
| 3798 | | -{ |
|---|
| 3799 | | - struct fc_rport *rport = dev_to_rport(q->queuedata); |
|---|
| 3800 | | - |
|---|
| 3801 | | - if (rport->port_state == FC_PORTSTATE_BLOCKED && |
|---|
| 3802 | | - !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) |
|---|
| 3803 | | - return BLKPREP_DEFER; |
|---|
| 3804 | | - |
|---|
| 3805 | | - if (rport->port_state != FC_PORTSTATE_ONLINE) |
|---|
| 3806 | | - return BLKPREP_KILL; |
|---|
| 3807 | | - |
|---|
| 3808 | | - return BLKPREP_OK; |
|---|
| 3809 | 3808 | } |
|---|
| 3810 | 3809 | |
|---|
| 3811 | 3810 | /** |
|---|
| .. | .. |
|---|
| 3825 | 3824 | if (!i->f->bsg_request) |
|---|
| 3826 | 3825 | return -ENOTSUPP; |
|---|
| 3827 | 3826 | |
|---|
| 3828 | | - q = bsg_setup_queue(dev, dev_name(dev), fc_bsg_dispatch, |
|---|
| 3829 | | - i->f->dd_bsg_size); |
|---|
| 3827 | + q = bsg_setup_queue(dev, dev_name(dev), fc_bsg_dispatch_prep, |
|---|
| 3828 | + fc_bsg_job_timeout, i->f->dd_bsg_size); |
|---|
| 3830 | 3829 | if (IS_ERR(q)) { |
|---|
| 3831 | 3830 | dev_err(dev, "failed to setup bsg queue\n"); |
|---|
| 3832 | 3831 | return PTR_ERR(q); |
|---|
| 3833 | 3832 | } |
|---|
| 3834 | 3833 | __scsi_init_queue(shost, q); |
|---|
| 3835 | | - blk_queue_prep_rq(q, fc_bsg_rport_prep); |
|---|
| 3836 | | - blk_queue_rq_timed_out(q, fc_bsg_job_timeout); |
|---|
| 3837 | 3834 | blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); |
|---|
| 3838 | 3835 | rport->rqst_q = q; |
|---|
| 3839 | 3836 | return 0; |
|---|
| .. | .. |
|---|
| 3852 | 3849 | static void |
|---|
| 3853 | 3850 | fc_bsg_remove(struct request_queue *q) |
|---|
| 3854 | 3851 | { |
|---|
| 3855 | | - if (q) { |
|---|
| 3856 | | - bsg_unregister_queue(q); |
|---|
| 3857 | | - blk_cleanup_queue(q); |
|---|
| 3858 | | - } |
|---|
| 3852 | + bsg_remove_queue(q); |
|---|
| 3859 | 3853 | } |
|---|
| 3860 | 3854 | |
|---|
| 3861 | 3855 | |
|---|