diff options
Diffstat (limited to 'drivers/scsi')
43 files changed, 8086 insertions, 1553 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 81ccbd7f9e34..26be540d1dd3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -888,6 +888,25 @@ config SCSI_IBMVSCSIS | |||
888 | To compile this driver as a module, choose M here: the | 888 | To compile this driver as a module, choose M here: the |
889 | module will be called ibmvstgt. | 889 | module will be called ibmvstgt. |
890 | 890 | ||
891 | config SCSI_IBMVFC | ||
892 | tristate "IBM Virtual FC support" | ||
893 | depends on PPC_PSERIES && SCSI | ||
894 | select SCSI_FC_ATTRS | ||
895 | help | ||
896 | This is the IBM POWER Virtual FC Client | ||
897 | |||
898 | To compile this driver as a module, choose M here: the | ||
899 | module will be called ibmvfc. | ||
900 | |||
901 | config SCSI_IBMVFC_TRACE | ||
902 | bool "enable driver internal trace" | ||
903 | depends on SCSI_IBMVFC | ||
904 | default y | ||
905 | help | ||
906 | If you say Y here, the driver will trace all commands issued | ||
907 | to the adapter. Performance impact is minimal. Trace can be | ||
908 | dumped using /sys/class/scsi_host/hostXX/trace. | ||
909 | |||
891 | config SCSI_INITIO | 910 | config SCSI_INITIO |
892 | tristate "Initio 9100U(W) support" | 911 | tristate "Initio 9100U(W) support" |
893 | depends on PCI && SCSI | 912 | depends on PCI && SCSI |
@@ -1738,10 +1757,12 @@ config SCSI_SUNESP | |||
1738 | select SCSI_SPI_ATTRS | 1757 | select SCSI_SPI_ATTRS |
1739 | help | 1758 | help |
1740 | This is the driver for the Sun ESP SCSI host adapter. The ESP | 1759 | This is the driver for the Sun ESP SCSI host adapter. The ESP |
1741 | chipset is present in most SPARC SBUS-based computers. | 1760 | chipset is present in most SPARC SBUS-based computers and |
1761 | supports the Emulex family of ESP SCSI chips (esp100, esp100A, | ||
1762 | esp236, fas101, fas236) as well as the Qlogic fas366 SCSI chip. | ||
1742 | 1763 | ||
1743 | To compile this driver as a module, choose M here: the | 1764 | To compile this driver as a module, choose M here: the |
1744 | module will be called esp. | 1765 | module will be called sun_esp. |
1745 | 1766 | ||
1746 | config ZFCP | 1767 | config ZFCP |
1747 | tristate "FCP host bus adapter driver for IBM eServer zSeries" | 1768 | tristate "FCP host bus adapter driver for IBM eServer zSeries" |
@@ -1771,4 +1792,6 @@ endif # SCSI_LOWLEVEL | |||
1771 | 1792 | ||
1772 | source "drivers/scsi/pcmcia/Kconfig" | 1793 | source "drivers/scsi/pcmcia/Kconfig" |
1773 | 1794 | ||
1795 | source "drivers/scsi/device_handler/Kconfig" | ||
1796 | |||
1774 | endmenu | 1797 | endmenu |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 6c775e350c98..a8149677de23 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -34,6 +34,7 @@ obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o | |||
34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o | 34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o |
35 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ | 35 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ |
36 | obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o | 36 | obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o |
37 | obj-$(CONFIG_SCSI_DH) += device_handler/ | ||
37 | 38 | ||
38 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o | 39 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o |
39 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o | 40 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o |
@@ -118,6 +119,7 @@ obj-$(CONFIG_SCSI_IPR) += ipr.o | |||
118 | obj-$(CONFIG_SCSI_SRP) += libsrp.o | 119 | obj-$(CONFIG_SCSI_SRP) += libsrp.o |
119 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ | 120 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ |
120 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ | 121 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ |
122 | obj-$(CONFIG_SCSI_IBMVFC) += ibmvscsi/ | ||
121 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o | 123 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o |
122 | obj-$(CONFIG_SCSI_STEX) += stex.o | 124 | obj-$(CONFIG_SCSI_STEX) += stex.o |
123 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o | 125 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o |
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 5fd83deab36c..a7355260cfcf 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/kthread.h> | 41 | #include <linux/kthread.h> |
42 | #include <linux/semaphore.h> | 42 | #include <linux/semaphore.h> |
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <scsi/scsi_host.h> | ||
44 | 45 | ||
45 | #include "aacraid.h" | 46 | #include "aacraid.h" |
46 | 47 | ||
@@ -581,6 +582,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
581 | for (i = 0; i < upsg->count; i++) { | 582 | for (i = 0; i < upsg->count; i++) { |
582 | u64 addr; | 583 | u64 addr; |
583 | void* p; | 584 | void* p; |
585 | if (upsg->sg[i].count > | ||
586 | (dev->adapter_info.options & | ||
587 | AAC_OPT_NEW_COMM) ? | ||
588 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
589 | 65536) { | ||
590 | rcode = -EINVAL; | ||
591 | goto cleanup; | ||
592 | } | ||
584 | /* Does this really need to be GFP_DMA? */ | 593 | /* Does this really need to be GFP_DMA? */ |
585 | p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 594 | p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
586 | if(!p) { | 595 | if(!p) { |
@@ -625,6 +634,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
625 | for (i = 0; i < usg->count; i++) { | 634 | for (i = 0; i < usg->count; i++) { |
626 | u64 addr; | 635 | u64 addr; |
627 | void* p; | 636 | void* p; |
637 | if (usg->sg[i].count > | ||
638 | (dev->adapter_info.options & | ||
639 | AAC_OPT_NEW_COMM) ? | ||
640 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
641 | 65536) { | ||
642 | rcode = -EINVAL; | ||
643 | goto cleanup; | ||
644 | } | ||
628 | /* Does this really need to be GFP_DMA? */ | 645 | /* Does this really need to be GFP_DMA? */ |
629 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 646 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
630 | if(!p) { | 647 | if(!p) { |
@@ -667,6 +684,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
667 | for (i = 0; i < upsg->count; i++) { | 684 | for (i = 0; i < upsg->count; i++) { |
668 | uintptr_t addr; | 685 | uintptr_t addr; |
669 | void* p; | 686 | void* p; |
687 | if (usg->sg[i].count > | ||
688 | (dev->adapter_info.options & | ||
689 | AAC_OPT_NEW_COMM) ? | ||
690 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
691 | 65536) { | ||
692 | rcode = -EINVAL; | ||
693 | goto cleanup; | ||
694 | } | ||
670 | /* Does this really need to be GFP_DMA? */ | 695 | /* Does this really need to be GFP_DMA? */ |
671 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); | 696 | p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); |
672 | if(!p) { | 697 | if(!p) { |
@@ -698,6 +723,14 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) | |||
698 | for (i = 0; i < upsg->count; i++) { | 723 | for (i = 0; i < upsg->count; i++) { |
699 | dma_addr_t addr; | 724 | dma_addr_t addr; |
700 | void* p; | 725 | void* p; |
726 | if (upsg->sg[i].count > | ||
727 | (dev->adapter_info.options & | ||
728 | AAC_OPT_NEW_COMM) ? | ||
729 | (dev->scsi_host_ptr->max_sectors << 9) : | ||
730 | 65536) { | ||
731 | rcode = -EINVAL; | ||
732 | goto cleanup; | ||
733 | } | ||
701 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); | 734 | p = kmalloc(upsg->sg[i].count, GFP_KERNEL); |
702 | if (!p) { | 735 | if (!p) { |
703 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", | 736 | dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", |
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 68c140e82673..9aa301c1ed07 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c | |||
@@ -865,7 +865,7 @@ static ssize_t aac_show_bios_version(struct device *device, | |||
865 | return len; | 865 | return len; |
866 | } | 866 | } |
867 | 867 | ||
868 | ssize_t aac_show_serial_number(struct device *device, | 868 | static ssize_t aac_show_serial_number(struct device *device, |
869 | struct device_attribute *attr, char *buf) | 869 | struct device_attribute *attr, char *buf) |
870 | { | 870 | { |
871 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; | 871 | struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; |
diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig new file mode 100644 index 000000000000..2adc0f666b68 --- /dev/null +++ b/drivers/scsi/device_handler/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # SCSI Device Handler configuration | ||
3 | # | ||
4 | |||
5 | menuconfig SCSI_DH | ||
6 | tristate "SCSI Device Handlers" | ||
7 | depends on SCSI | ||
8 | default n | ||
9 | help | ||
10 | SCSI Device Handlers provide device specific support for | ||
11 | devices utilized in multipath configurations. Say Y here to | ||
12 | select support for specific hardware. | ||
13 | |||
14 | config SCSI_DH_RDAC | ||
15 | tristate "LSI RDAC Device Handler" | ||
16 | depends on SCSI_DH | ||
17 | help | ||
18 | If you have a LSI RDAC select y. Otherwise, say N. | ||
19 | |||
20 | config SCSI_DH_HP_SW | ||
21 | tristate "HP/COMPAQ MSA Device Handler" | ||
22 | depends on SCSI_DH | ||
23 | help | ||
24 | If you have a HP/COMPAQ MSA device that requires START_STOP to | ||
25 | be sent to start it and cannot upgrade the firmware then select y. | ||
26 | Otherwise, say N. | ||
27 | |||
28 | config SCSI_DH_EMC | ||
29 | tristate "EMC CLARiiON Device Handler" | ||
30 | depends on SCSI_DH | ||
31 | help | ||
32 | If you have a EMC CLARiiON select y. Otherwise, say N. | ||
diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile new file mode 100644 index 000000000000..35272e93b1c8 --- /dev/null +++ b/drivers/scsi/device_handler/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # SCSI Device Handler | ||
3 | # | ||
4 | obj-$(CONFIG_SCSI_DH) += scsi_dh.o | ||
5 | obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o | ||
6 | obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o | ||
7 | obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o | ||
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c new file mode 100644 index 000000000000..ab6c21cd9689 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * SCSI device handler infrastruture. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * Copyright IBM Corporation, 2007 | ||
19 | * Authors: | ||
20 | * Chandra Seetharaman <sekharan@us.ibm.com> | ||
21 | * Mike Anderson <andmike@linux.vnet.ibm.com> | ||
22 | */ | ||
23 | |||
24 | #include <scsi/scsi_dh.h> | ||
25 | #include "../scsi_priv.h" | ||
26 | |||
27 | static DEFINE_SPINLOCK(list_lock); | ||
28 | static LIST_HEAD(scsi_dh_list); | ||
29 | |||
30 | static struct scsi_device_handler *get_device_handler(const char *name) | ||
31 | { | ||
32 | struct scsi_device_handler *tmp, *found = NULL; | ||
33 | |||
34 | spin_lock(&list_lock); | ||
35 | list_for_each_entry(tmp, &scsi_dh_list, list) { | ||
36 | if (!strcmp(tmp->name, name)) { | ||
37 | found = tmp; | ||
38 | break; | ||
39 | } | ||
40 | } | ||
41 | spin_unlock(&list_lock); | ||
42 | return found; | ||
43 | } | ||
44 | |||
45 | static int scsi_dh_notifier_add(struct device *dev, void *data) | ||
46 | { | ||
47 | struct scsi_device_handler *scsi_dh = data; | ||
48 | |||
49 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * scsi_register_device_handler - register a device handler personality | ||
55 | * module. | ||
56 | * @scsi_dh - device handler to be registered. | ||
57 | * | ||
58 | * Returns 0 on success, -EBUSY if handler already registered. | ||
59 | */ | ||
60 | int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) | ||
61 | { | ||
62 | int ret = -EBUSY; | ||
63 | struct scsi_device_handler *tmp; | ||
64 | |||
65 | tmp = get_device_handler(scsi_dh->name); | ||
66 | if (tmp) | ||
67 | goto done; | ||
68 | |||
69 | ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
70 | |||
71 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); | ||
72 | spin_lock(&list_lock); | ||
73 | list_add(&scsi_dh->list, &scsi_dh_list); | ||
74 | spin_unlock(&list_lock); | ||
75 | |||
76 | done: | ||
77 | return ret; | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(scsi_register_device_handler); | ||
80 | |||
81 | static int scsi_dh_notifier_remove(struct device *dev, void *data) | ||
82 | { | ||
83 | struct scsi_device_handler *scsi_dh = data; | ||
84 | |||
85 | scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev); | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | * scsi_unregister_device_handler - register a device handler personality | ||
91 | * module. | ||
92 | * @scsi_dh - device handler to be unregistered. | ||
93 | * | ||
94 | * Returns 0 on success, -ENODEV if handler not registered. | ||
95 | */ | ||
96 | int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) | ||
97 | { | ||
98 | int ret = -ENODEV; | ||
99 | struct scsi_device_handler *tmp; | ||
100 | |||
101 | tmp = get_device_handler(scsi_dh->name); | ||
102 | if (!tmp) | ||
103 | goto done; | ||
104 | |||
105 | ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb); | ||
106 | |||
107 | bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, | ||
108 | scsi_dh_notifier_remove); | ||
109 | spin_lock(&list_lock); | ||
110 | list_del(&scsi_dh->list); | ||
111 | spin_unlock(&list_lock); | ||
112 | |||
113 | done: | ||
114 | return ret; | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); | ||
117 | |||
118 | /* | ||
119 | * scsi_dh_activate - activate the path associated with the scsi_device | ||
120 | * corresponding to the given request queue. | ||
121 | * @q - Request queue that is associated with the scsi_device to be | ||
122 | * activated. | ||
123 | */ | ||
124 | int scsi_dh_activate(struct request_queue *q) | ||
125 | { | ||
126 | int err = 0; | ||
127 | unsigned long flags; | ||
128 | struct scsi_device *sdev; | ||
129 | struct scsi_device_handler *scsi_dh = NULL; | ||
130 | |||
131 | spin_lock_irqsave(q->queue_lock, flags); | ||
132 | sdev = q->queuedata; | ||
133 | if (sdev && sdev->scsi_dh_data) | ||
134 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | ||
135 | if (!scsi_dh || !get_device(&sdev->sdev_gendev)) | ||
136 | err = SCSI_DH_NOSYS; | ||
137 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
138 | |||
139 | if (err) | ||
140 | return err; | ||
141 | |||
142 | if (scsi_dh->activate) | ||
143 | err = scsi_dh->activate(sdev); | ||
144 | put_device(&sdev->sdev_gendev); | ||
145 | return err; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(scsi_dh_activate); | ||
148 | |||
149 | /* | ||
150 | * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for | ||
151 | * the given name. FALSE(0) otherwise. | ||
152 | * @name - name of the device handler. | ||
153 | */ | ||
154 | int scsi_dh_handler_exist(const char *name) | ||
155 | { | ||
156 | return (get_device_handler(name) != NULL); | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | ||
159 | |||
160 | MODULE_DESCRIPTION("SCSI device handler"); | ||
161 | MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>"); | ||
162 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c new file mode 100644 index 000000000000..ed53f14007a2 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_emc.c | |||
@@ -0,0 +1,499 @@ | |||
1 | /* | ||
2 | * Target driver for EMC CLARiiON AX/CX-series hardware. | ||
3 | * Based on code from Lars Marowsky-Bree <lmb@suse.de> | ||
4 | * and Ed Goggin <egoggin@emc.com>. | ||
5 | * | ||
6 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | ||
7 | * Copyright (C) 2006 Mike Christie | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; see the file COPYING. If not, write to | ||
21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | #include <scsi/scsi.h> | ||
24 | #include <scsi/scsi_eh.h> | ||
25 | #include <scsi/scsi_dh.h> | ||
26 | #include <scsi/scsi_device.h> | ||
27 | |||
28 | #define CLARIION_NAME "emc_clariion" | ||
29 | |||
30 | #define CLARIION_TRESPASS_PAGE 0x22 | ||
31 | #define CLARIION_BUFFER_SIZE 0x80 | ||
32 | #define CLARIION_TIMEOUT (60 * HZ) | ||
33 | #define CLARIION_RETRIES 3 | ||
34 | #define CLARIION_UNBOUND_LU -1 | ||
35 | |||
36 | static unsigned char long_trespass[] = { | ||
37 | 0, 0, 0, 0, | ||
38 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
39 | 0x09, /* Page length - 2 */ | ||
40 | 0x81, /* Trespass code + Honor reservation bit */ | ||
41 | 0xff, 0xff, /* Trespass target */ | ||
42 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
43 | }; | ||
44 | |||
45 | static unsigned char long_trespass_hr[] = { | ||
46 | 0, 0, 0, 0, | ||
47 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
48 | 0x09, /* Page length - 2 */ | ||
49 | 0x01, /* Trespass code + Honor reservation bit */ | ||
50 | 0xff, 0xff, /* Trespass target */ | ||
51 | 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ | ||
52 | }; | ||
53 | |||
54 | static unsigned char short_trespass[] = { | ||
55 | 0, 0, 0, 0, | ||
56 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
57 | 0x02, /* Page length - 2 */ | ||
58 | 0x81, /* Trespass code + Honor reservation bit */ | ||
59 | 0xff, /* Trespass target */ | ||
60 | }; | ||
61 | |||
62 | static unsigned char short_trespass_hr[] = { | ||
63 | 0, 0, 0, 0, | ||
64 | CLARIION_TRESPASS_PAGE, /* Page code */ | ||
65 | 0x02, /* Page length - 2 */ | ||
66 | 0x01, /* Trespass code + Honor reservation bit */ | ||
67 | 0xff, /* Trespass target */ | ||
68 | }; | ||
69 | |||
70 | struct clariion_dh_data { | ||
71 | /* | ||
72 | * Use short trespass command (FC-series) or the long version | ||
73 | * (default for AX/CX CLARiiON arrays). | ||
74 | */ | ||
75 | unsigned short_trespass; | ||
76 | /* | ||
77 | * Whether or not (default) to honor SCSI reservations when | ||
78 | * initiating a switch-over. | ||
79 | */ | ||
80 | unsigned hr; | ||
81 | /* I/O buffer for both MODE_SELECT and INQUIRY commands. */ | ||
82 | char buffer[CLARIION_BUFFER_SIZE]; | ||
83 | /* | ||
84 | * SCSI sense buffer for commands -- assumes serial issuance | ||
85 | * and completion sequence of all commands for same multipath. | ||
86 | */ | ||
87 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
88 | /* which SP (A=0,B=1,UNBOUND=-1) is dflt SP for path's mapped dev */ | ||
89 | int default_sp; | ||
90 | /* which SP (A=0,B=1,UNBOUND=-1) is active for path's mapped dev */ | ||
91 | int current_sp; | ||
92 | }; | ||
93 | |||
94 | static inline struct clariion_dh_data | ||
95 | *get_clariion_data(struct scsi_device *sdev) | ||
96 | { | ||
97 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
98 | BUG_ON(scsi_dh_data == NULL); | ||
99 | return ((struct clariion_dh_data *) scsi_dh_data->buf); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Parse MODE_SELECT cmd reply. | ||
104 | */ | ||
105 | static int trespass_endio(struct scsi_device *sdev, int result) | ||
106 | { | ||
107 | int err = SCSI_DH_OK; | ||
108 | struct scsi_sense_hdr sshdr; | ||
109 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
110 | char *sense = csdev->sense; | ||
111 | |||
112 | if (status_byte(result) == CHECK_CONDITION && | ||
113 | scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { | ||
114 | sdev_printk(KERN_ERR, sdev, "Found valid sense data 0x%2x, " | ||
115 | "0x%2x, 0x%2x while sending CLARiiON trespass " | ||
116 | "command.\n", sshdr.sense_key, sshdr.asc, | ||
117 | sshdr.ascq); | ||
118 | |||
119 | if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && | ||
120 | (sshdr.ascq == 0x00)) { | ||
121 | /* | ||
122 | * Array based copy in progress -- do not send | ||
123 | * mode_select or copy will be aborted mid-stream. | ||
124 | */ | ||
125 | sdev_printk(KERN_INFO, sdev, "Array Based Copy in " | ||
126 | "progress while sending CLARiiON trespass " | ||
127 | "command.\n"); | ||
128 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
129 | } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && | ||
130 | (sshdr.ascq == 0x03)) { | ||
131 | /* | ||
132 | * LUN Not Ready - Manual Intervention Required | ||
133 | * indicates in-progress ucode upgrade (NDU). | ||
134 | */ | ||
135 | sdev_printk(KERN_INFO, sdev, "Detected in-progress " | ||
136 | "ucode upgrade NDU operation while sending " | ||
137 | "CLARiiON trespass command.\n"); | ||
138 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
139 | } else | ||
140 | err = SCSI_DH_DEV_FAILED; | ||
141 | } else if (result) { | ||
142 | sdev_printk(KERN_ERR, sdev, "Error 0x%x while sending " | ||
143 | "CLARiiON trespass command.\n", result); | ||
144 | err = SCSI_DH_IO; | ||
145 | } | ||
146 | |||
147 | return err; | ||
148 | } | ||
149 | |||
150 | static int parse_sp_info_reply(struct scsi_device *sdev, int result, | ||
151 | int *default_sp, int *current_sp, int *new_current_sp) | ||
152 | { | ||
153 | int err = SCSI_DH_OK; | ||
154 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
155 | |||
156 | if (result == 0) { | ||
157 | /* check for in-progress ucode upgrade (NDU) */ | ||
158 | if (csdev->buffer[48] != 0) { | ||
159 | sdev_printk(KERN_NOTICE, sdev, "Detected in-progress " | ||
160 | "ucode upgrade NDU operation while finding " | ||
161 | "current active SP."); | ||
162 | err = SCSI_DH_DEV_TEMP_BUSY; | ||
163 | } else { | ||
164 | *default_sp = csdev->buffer[5]; | ||
165 | |||
166 | if (csdev->buffer[4] == 2) | ||
167 | /* SP for path is current */ | ||
168 | *current_sp = csdev->buffer[8]; | ||
169 | else { | ||
170 | if (csdev->buffer[4] == 1) | ||
171 | /* SP for this path is NOT current */ | ||
172 | if (csdev->buffer[8] == 0) | ||
173 | *current_sp = 1; | ||
174 | else | ||
175 | *current_sp = 0; | ||
176 | else | ||
177 | /* unbound LU or LUNZ */ | ||
178 | *current_sp = CLARIION_UNBOUND_LU; | ||
179 | } | ||
180 | *new_current_sp = csdev->buffer[8]; | ||
181 | } | ||
182 | } else { | ||
183 | struct scsi_sense_hdr sshdr; | ||
184 | |||
185 | err = SCSI_DH_IO; | ||
186 | |||
187 | if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, | ||
188 | &sshdr)) | ||
189 | sdev_printk(KERN_ERR, sdev, "Found valid sense data " | ||
190 | "0x%2x, 0x%2x, 0x%2x while finding current " | ||
191 | "active SP.", sshdr.sense_key, sshdr.asc, | ||
192 | sshdr.ascq); | ||
193 | else | ||
194 | sdev_printk(KERN_ERR, sdev, "Error 0x%x finding " | ||
195 | "current active SP.", result); | ||
196 | } | ||
197 | |||
198 | return err; | ||
199 | } | ||
200 | |||
201 | static int sp_info_endio(struct scsi_device *sdev, int result, | ||
202 | int mode_select_sent, int *done) | ||
203 | { | ||
204 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
205 | int err_flags, default_sp, current_sp, new_current_sp; | ||
206 | |||
207 | err_flags = parse_sp_info_reply(sdev, result, &default_sp, | ||
208 | ¤t_sp, &new_current_sp); | ||
209 | |||
210 | if (err_flags != SCSI_DH_OK) | ||
211 | goto done; | ||
212 | |||
213 | if (mode_select_sent) { | ||
214 | csdev->default_sp = default_sp; | ||
215 | csdev->current_sp = current_sp; | ||
216 | } else { | ||
217 | /* | ||
218 | * Issue the actual module_selec request IFF either | ||
219 | * (1) we do not know the identity of the current SP OR | ||
220 | * (2) what we think we know is actually correct. | ||
221 | */ | ||
222 | if ((current_sp != CLARIION_UNBOUND_LU) && | ||
223 | (new_current_sp != current_sp)) { | ||
224 | |||
225 | csdev->default_sp = default_sp; | ||
226 | csdev->current_sp = current_sp; | ||
227 | |||
228 | sdev_printk(KERN_INFO, sdev, "Ignoring path group " | ||
229 | "switch-over command for CLARiiON SP%s since " | ||
230 | " mapped device is already initialized.", | ||
231 | current_sp ? "B" : "A"); | ||
232 | if (done) | ||
233 | *done = 1; /* as good as doing it */ | ||
234 | } | ||
235 | } | ||
236 | done: | ||
237 | return err_flags; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * Get block request for REQ_BLOCK_PC command issued to path. Currently | ||
242 | * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. | ||
243 | * | ||
244 | * Uses data and sense buffers in hardware handler context structure and | ||
245 | * assumes serial servicing of commands, both issuance and completion. | ||
246 | */ | ||
247 | static struct request *get_req(struct scsi_device *sdev, int cmd) | ||
248 | { | ||
249 | struct clariion_dh_data *csdev = get_clariion_data(sdev); | ||
250 | struct request *rq; | ||
251 | unsigned char *page22; | ||
252 | int len = 0; | ||
253 | |||
254 | rq = blk_get_request(sdev->request_queue, | ||
255 | (cmd == MODE_SELECT) ? WRITE : READ, GFP_ATOMIC); | ||
256 | if (!rq) { | ||
257 | sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); | ||
258 | return NULL; | ||
259 | } | ||
260 | |||
261 | memset(&rq->cmd, 0, BLK_MAX_CDB); | ||
262 | rq->cmd[0] = cmd; | ||
263 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
264 | |||
265 | switch (cmd) { | ||
266 | case MODE_SELECT: | ||
267 | if (csdev->short_trespass) { | ||
268 | page22 = csdev->hr ? short_trespass_hr : short_trespass; | ||
269 | len = sizeof(short_trespass); | ||
270 | } else { | ||
271 | page22 = csdev->hr ? long_trespass_hr : long_trespass; | ||
272 | len = sizeof(long_trespass); | ||
273 | } | ||
274 | /* | ||
275 | * Can't DMA from kernel BSS -- must copy selected trespass | ||
276 | * command mode page contents to context buffer which is | ||
277 | * allocated by kmalloc. | ||
278 | */ | ||
279 | BUG_ON((len > CLARIION_BUFFER_SIZE)); | ||
280 | memcpy(csdev->buffer, page22, len); | ||
281 | rq->cmd_flags |= REQ_RW; | ||
282 | rq->cmd[1] = 0x10; | ||
283 | break; | ||
284 | case INQUIRY: | ||
285 | rq->cmd[1] = 0x1; | ||
286 | rq->cmd[2] = 0xC0; | ||
287 | len = CLARIION_BUFFER_SIZE; | ||
288 | memset(csdev->buffer, 0, CLARIION_BUFFER_SIZE); | ||
289 | break; | ||
290 | default: | ||
291 | BUG_ON(1); | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | rq->cmd[4] = len; | ||
296 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
297 | rq->cmd_flags |= REQ_FAILFAST; | ||
298 | rq->timeout = CLARIION_TIMEOUT; | ||
299 | rq->retries = CLARIION_RETRIES; | ||
300 | |||
301 | rq->sense = csdev->sense; | ||
302 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
303 | rq->sense_len = 0; | ||
304 | |||
305 | if (blk_rq_map_kern(sdev->request_queue, rq, csdev->buffer, | ||
306 | len, GFP_ATOMIC)) { | ||
307 | __blk_put_request(rq->q, rq); | ||
308 | return NULL; | ||
309 | } | ||
310 | |||
311 | return rq; | ||
312 | } | ||
313 | |||
314 | static int send_cmd(struct scsi_device *sdev, int cmd) | ||
315 | { | ||
316 | struct request *rq = get_req(sdev, cmd); | ||
317 | |||
318 | if (!rq) | ||
319 | return SCSI_DH_RES_TEMP_UNAVAIL; | ||
320 | |||
321 | return blk_execute_rq(sdev->request_queue, NULL, rq, 1); | ||
322 | } | ||
323 | |||
324 | static int clariion_activate(struct scsi_device *sdev) | ||
325 | { | ||
326 | int result, done = 0; | ||
327 | |||
328 | result = send_cmd(sdev, INQUIRY); | ||
329 | result = sp_info_endio(sdev, result, 0, &done); | ||
330 | if (result || done) | ||
331 | goto done; | ||
332 | |||
333 | result = send_cmd(sdev, MODE_SELECT); | ||
334 | result = trespass_endio(sdev, result); | ||
335 | if (result) | ||
336 | goto done; | ||
337 | |||
338 | result = send_cmd(sdev, INQUIRY); | ||
339 | result = sp_info_endio(sdev, result, 1, NULL); | ||
340 | done: | ||
341 | return result; | ||
342 | } | ||
343 | |||
344 | static int clariion_check_sense(struct scsi_device *sdev, | ||
345 | struct scsi_sense_hdr *sense_hdr) | ||
346 | { | ||
347 | switch (sense_hdr->sense_key) { | ||
348 | case NOT_READY: | ||
349 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03) | ||
350 | /* | ||
351 | * LUN Not Ready - Manual Intervention Required | ||
352 | * indicates this is a passive path. | ||
353 | * | ||
354 | * FIXME: However, if this is seen and EVPD C0 | ||
355 | * indicates that this is due to a NDU in | ||
356 | * progress, we should set FAIL_PATH too. | ||
357 | * This indicates we might have to do a SCSI | ||
358 | * inquiry in the end_io path. Ugh. | ||
359 | * | ||
360 | * Can return FAILED only when we want the error | ||
361 | * recovery process to kick in. | ||
362 | */ | ||
363 | return SUCCESS; | ||
364 | break; | ||
365 | case ILLEGAL_REQUEST: | ||
366 | if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01) | ||
367 | /* | ||
368 | * An array based copy is in progress. Do not | ||
369 | * fail the path, do not bypass to another PG, | ||
370 | * do not retry. Fail the IO immediately. | ||
371 | * (Actually this is the same conclusion as in | ||
372 | * the default handler, but lets make sure.) | ||
373 | * | ||
374 | * Can return FAILED only when we want the error | ||
375 | * recovery process to kick in. | ||
376 | */ | ||
377 | return SUCCESS; | ||
378 | break; | ||
379 | case UNIT_ATTENTION: | ||
380 | if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) | ||
381 | /* | ||
382 | * Unit Attention Code. This is the first IO | ||
383 | * to the new path, so just retry. | ||
384 | */ | ||
385 | return NEEDS_RETRY; | ||
386 | break; | ||
387 | } | ||
388 | |||
389 | /* success just means we do not care what scsi-ml does */ | ||
390 | return SUCCESS; | ||
391 | } | ||
392 | |||
393 | static const struct { | ||
394 | char *vendor; | ||
395 | char *model; | ||
396 | } clariion_dev_list[] = { | ||
397 | {"DGC", "RAID"}, | ||
398 | {"DGC", "DISK"}, | ||
399 | {NULL, NULL}, | ||
400 | }; | ||
401 | |||
402 | static int clariion_bus_notify(struct notifier_block *, unsigned long, void *); | ||
403 | |||
404 | static struct scsi_device_handler clariion_dh = { | ||
405 | .name = CLARIION_NAME, | ||
406 | .module = THIS_MODULE, | ||
407 | .nb.notifier_call = clariion_bus_notify, | ||
408 | .check_sense = clariion_check_sense, | ||
409 | .activate = clariion_activate, | ||
410 | }; | ||
411 | |||
412 | /* | ||
413 | * TODO: need some interface so we can set trespass values | ||
414 | */ | ||
415 | static int clariion_bus_notify(struct notifier_block *nb, | ||
416 | unsigned long action, void *data) | ||
417 | { | ||
418 | struct device *dev = data; | ||
419 | struct scsi_device *sdev = to_scsi_device(dev); | ||
420 | struct scsi_dh_data *scsi_dh_data; | ||
421 | struct clariion_dh_data *h; | ||
422 | int i, found = 0; | ||
423 | unsigned long flags; | ||
424 | |||
425 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
426 | for (i = 0; clariion_dev_list[i].vendor; i++) { | ||
427 | if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, | ||
428 | strlen(clariion_dev_list[i].vendor)) && | ||
429 | !strncmp(sdev->model, clariion_dev_list[i].model, | ||
430 | strlen(clariion_dev_list[i].model))) { | ||
431 | found = 1; | ||
432 | break; | ||
433 | } | ||
434 | } | ||
435 | if (!found) | ||
436 | goto out; | ||
437 | |||
438 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
439 | + sizeof(*h) , GFP_KERNEL); | ||
440 | if (!scsi_dh_data) { | ||
441 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
442 | CLARIION_NAME); | ||
443 | goto out; | ||
444 | } | ||
445 | |||
446 | scsi_dh_data->scsi_dh = &clariion_dh; | ||
447 | h = (struct clariion_dh_data *) scsi_dh_data->buf; | ||
448 | h->default_sp = CLARIION_UNBOUND_LU; | ||
449 | h->current_sp = CLARIION_UNBOUND_LU; | ||
450 | |||
451 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
452 | sdev->scsi_dh_data = scsi_dh_data; | ||
453 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
454 | |||
455 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME); | ||
456 | try_module_get(THIS_MODULE); | ||
457 | |||
458 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
459 | if (sdev->scsi_dh_data == NULL || | ||
460 | sdev->scsi_dh_data->scsi_dh != &clariion_dh) | ||
461 | goto out; | ||
462 | |||
463 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
464 | scsi_dh_data = sdev->scsi_dh_data; | ||
465 | sdev->scsi_dh_data = NULL; | ||
466 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
467 | |||
468 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", | ||
469 | CLARIION_NAME); | ||
470 | |||
471 | kfree(scsi_dh_data); | ||
472 | module_put(THIS_MODULE); | ||
473 | } | ||
474 | |||
475 | out: | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int __init clariion_init(void) | ||
480 | { | ||
481 | int r; | ||
482 | |||
483 | r = scsi_register_device_handler(&clariion_dh); | ||
484 | if (r != 0) | ||
485 | printk(KERN_ERR "Failed to register scsi device handler."); | ||
486 | return r; | ||
487 | } | ||
488 | |||
489 | static void __exit clariion_exit(void) | ||
490 | { | ||
491 | scsi_unregister_device_handler(&clariion_dh); | ||
492 | } | ||
493 | |||
494 | module_init(clariion_init); | ||
495 | module_exit(clariion_exit); | ||
496 | |||
497 | MODULE_DESCRIPTION("EMC CX/AX/FC-family driver"); | ||
498 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>"); | ||
499 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c new file mode 100644 index 000000000000..12ceab7b3662 --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be | ||
3 | * upgraded. | ||
4 | * | ||
5 | * Copyright (C) 2006 Red Hat, Inc. All rights reserved. | ||
6 | * Copyright (C) 2006 Mike Christie | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <scsi/scsi.h> | ||
24 | #include <scsi/scsi_dbg.h> | ||
25 | #include <scsi/scsi_eh.h> | ||
26 | #include <scsi/scsi_dh.h> | ||
27 | |||
28 | #define HP_SW_NAME "hp_sw" | ||
29 | |||
30 | #define HP_SW_TIMEOUT (60 * HZ) | ||
31 | #define HP_SW_RETRIES 3 | ||
32 | |||
33 | struct hp_sw_dh_data { | ||
34 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
35 | int retries; | ||
36 | }; | ||
37 | |||
38 | static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) | ||
39 | { | ||
40 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
41 | BUG_ON(scsi_dh_data == NULL); | ||
42 | return ((struct hp_sw_dh_data *) scsi_dh_data->buf); | ||
43 | } | ||
44 | |||
45 | static int hp_sw_done(struct scsi_device *sdev) | ||
46 | { | ||
47 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
48 | struct scsi_sense_hdr sshdr; | ||
49 | int rc; | ||
50 | |||
51 | sdev_printk(KERN_INFO, sdev, "hp_sw_done\n"); | ||
52 | |||
53 | rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr); | ||
54 | if (!rc) | ||
55 | goto done; | ||
56 | switch (sshdr.sense_key) { | ||
57 | case NOT_READY: | ||
58 | if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { | ||
59 | rc = SCSI_DH_RETRY; | ||
60 | h->retries++; | ||
61 | break; | ||
62 | } | ||
63 | /* fall through */ | ||
64 | default: | ||
65 | h->retries++; | ||
66 | rc = SCSI_DH_IMM_RETRY; | ||
67 | } | ||
68 | |||
69 | done: | ||
70 | if (rc == SCSI_DH_OK || rc == SCSI_DH_IO) | ||
71 | h->retries = 0; | ||
72 | else if (h->retries > HP_SW_RETRIES) { | ||
73 | h->retries = 0; | ||
74 | rc = SCSI_DH_IO; | ||
75 | } | ||
76 | return rc; | ||
77 | } | ||
78 | |||
79 | static int hp_sw_activate(struct scsi_device *sdev) | ||
80 | { | ||
81 | struct hp_sw_dh_data *h = get_hp_sw_data(sdev); | ||
82 | struct request *req; | ||
83 | int ret = SCSI_DH_RES_TEMP_UNAVAIL; | ||
84 | |||
85 | req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC); | ||
86 | if (!req) | ||
87 | goto done; | ||
88 | |||
89 | sdev_printk(KERN_INFO, sdev, "sending START_STOP."); | ||
90 | |||
91 | req->cmd_type = REQ_TYPE_BLOCK_PC; | ||
92 | req->cmd_flags |= REQ_FAILFAST; | ||
93 | req->cmd_len = COMMAND_SIZE(START_STOP); | ||
94 | memset(req->cmd, 0, MAX_COMMAND_SIZE); | ||
95 | req->cmd[0] = START_STOP; | ||
96 | req->cmd[4] = 1; /* Start spin cycle */ | ||
97 | req->timeout = HP_SW_TIMEOUT; | ||
98 | req->sense = h->sense; | ||
99 | memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
100 | req->sense_len = 0; | ||
101 | |||
102 | ret = blk_execute_rq(req->q, NULL, req, 1); | ||
103 | if (!ret) /* SUCCESS */ | ||
104 | ret = hp_sw_done(sdev); | ||
105 | else | ||
106 | ret = SCSI_DH_IO; | ||
107 | done: | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static const struct { | ||
112 | char *vendor; | ||
113 | char *model; | ||
114 | } hp_sw_dh_data_list[] = { | ||
115 | {"COMPAQ", "MSA"}, | ||
116 | {"HP", "HSV"}, | ||
117 | {"DEC", "HSG80"}, | ||
118 | {NULL, NULL}, | ||
119 | }; | ||
120 | |||
121 | static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *); | ||
122 | |||
123 | static struct scsi_device_handler hp_sw_dh = { | ||
124 | .name = HP_SW_NAME, | ||
125 | .module = THIS_MODULE, | ||
126 | .nb.notifier_call = hp_sw_bus_notify, | ||
127 | .activate = hp_sw_activate, | ||
128 | }; | ||
129 | |||
130 | static int hp_sw_bus_notify(struct notifier_block *nb, | ||
131 | unsigned long action, void *data) | ||
132 | { | ||
133 | struct device *dev = data; | ||
134 | struct scsi_device *sdev = to_scsi_device(dev); | ||
135 | struct scsi_dh_data *scsi_dh_data; | ||
136 | int i, found = 0; | ||
137 | unsigned long flags; | ||
138 | |||
139 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
140 | for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { | ||
141 | if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, | ||
142 | strlen(hp_sw_dh_data_list[i].vendor)) && | ||
143 | !strncmp(sdev->model, hp_sw_dh_data_list[i].model, | ||
144 | strlen(hp_sw_dh_data_list[i].model))) { | ||
145 | found = 1; | ||
146 | break; | ||
147 | } | ||
148 | } | ||
149 | if (!found) | ||
150 | goto out; | ||
151 | |||
152 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
153 | + sizeof(struct hp_sw_dh_data) , GFP_KERNEL); | ||
154 | if (!scsi_dh_data) { | ||
155 | sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n", | ||
156 | HP_SW_NAME); | ||
157 | goto out; | ||
158 | } | ||
159 | |||
160 | scsi_dh_data->scsi_dh = &hp_sw_dh; | ||
161 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
162 | sdev->scsi_dh_data = scsi_dh_data; | ||
163 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
164 | try_module_get(THIS_MODULE); | ||
165 | |||
166 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME); | ||
167 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
168 | if (sdev->scsi_dh_data == NULL || | ||
169 | sdev->scsi_dh_data->scsi_dh != &hp_sw_dh) | ||
170 | goto out; | ||
171 | |||
172 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
173 | scsi_dh_data = sdev->scsi_dh_data; | ||
174 | sdev->scsi_dh_data = NULL; | ||
175 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
176 | module_put(THIS_MODULE); | ||
177 | |||
178 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME); | ||
179 | |||
180 | kfree(scsi_dh_data); | ||
181 | } | ||
182 | |||
183 | out: | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int __init hp_sw_init(void) | ||
188 | { | ||
189 | return scsi_register_device_handler(&hp_sw_dh); | ||
190 | } | ||
191 | |||
192 | static void __exit hp_sw_exit(void) | ||
193 | { | ||
194 | scsi_unregister_device_handler(&hp_sw_dh); | ||
195 | } | ||
196 | |||
197 | module_init(hp_sw_init); | ||
198 | module_exit(hp_sw_exit); | ||
199 | |||
200 | MODULE_DESCRIPTION("HP MSA 1000"); | ||
201 | MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); | ||
202 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c new file mode 100644 index 000000000000..6fff077a888d --- /dev/null +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c | |||
@@ -0,0 +1,691 @@ | |||
1 | /* | ||
2 | * Engenio/LSI RDAC SCSI Device Handler | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Christie. All rights reserved. | ||
5 | * Copyright (C) Chandra Seetharaman, IBM Corp. 2007 | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
20 | * | ||
21 | */ | ||
22 | #include <scsi/scsi.h> | ||
23 | #include <scsi/scsi_eh.h> | ||
24 | #include <scsi/scsi_dh.h> | ||
25 | |||
26 | #define RDAC_NAME "rdac" | ||
27 | |||
28 | /* | ||
29 | * LSI mode page stuff | ||
30 | * | ||
31 | * These struct definitions and the forming of the | ||
32 | * mode page were taken from the LSI RDAC 2.4 GPL'd | ||
33 | * driver, and then converted to Linux conventions. | ||
34 | */ | ||
35 | #define RDAC_QUIESCENCE_TIME 20; | ||
36 | /* | ||
37 | * Page Codes | ||
38 | */ | ||
39 | #define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c | ||
40 | |||
41 | /* | ||
42 | * Controller modes definitions | ||
43 | */ | ||
44 | #define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02 | ||
45 | |||
46 | /* | ||
47 | * RDAC Options field | ||
48 | */ | ||
49 | #define RDAC_FORCED_QUIESENCE 0x02 | ||
50 | |||
51 | #define RDAC_TIMEOUT (60 * HZ) | ||
52 | #define RDAC_RETRIES 3 | ||
53 | |||
54 | struct rdac_mode_6_hdr { | ||
55 | u8 data_len; | ||
56 | u8 medium_type; | ||
57 | u8 device_params; | ||
58 | u8 block_desc_len; | ||
59 | }; | ||
60 | |||
61 | struct rdac_mode_10_hdr { | ||
62 | u16 data_len; | ||
63 | u8 medium_type; | ||
64 | u8 device_params; | ||
65 | u16 reserved; | ||
66 | u16 block_desc_len; | ||
67 | }; | ||
68 | |||
69 | struct rdac_mode_common { | ||
70 | u8 controller_serial[16]; | ||
71 | u8 alt_controller_serial[16]; | ||
72 | u8 rdac_mode[2]; | ||
73 | u8 alt_rdac_mode[2]; | ||
74 | u8 quiescence_timeout; | ||
75 | u8 rdac_options; | ||
76 | }; | ||
77 | |||
78 | struct rdac_pg_legacy { | ||
79 | struct rdac_mode_6_hdr hdr; | ||
80 | u8 page_code; | ||
81 | u8 page_len; | ||
82 | struct rdac_mode_common common; | ||
83 | #define MODE6_MAX_LUN 32 | ||
84 | u8 lun_table[MODE6_MAX_LUN]; | ||
85 | u8 reserved2[32]; | ||
86 | u8 reserved3; | ||
87 | u8 reserved4; | ||
88 | }; | ||
89 | |||
90 | struct rdac_pg_expanded { | ||
91 | struct rdac_mode_10_hdr hdr; | ||
92 | u8 page_code; | ||
93 | u8 subpage_code; | ||
94 | u8 page_len[2]; | ||
95 | struct rdac_mode_common common; | ||
96 | u8 lun_table[256]; | ||
97 | u8 reserved3; | ||
98 | u8 reserved4; | ||
99 | }; | ||
100 | |||
101 | struct c9_inquiry { | ||
102 | u8 peripheral_info; | ||
103 | u8 page_code; /* 0xC9 */ | ||
104 | u8 reserved1; | ||
105 | u8 page_len; | ||
106 | u8 page_id[4]; /* "vace" */ | ||
107 | u8 avte_cvp; | ||
108 | u8 path_prio; | ||
109 | u8 reserved2[38]; | ||
110 | }; | ||
111 | |||
112 | #define SUBSYS_ID_LEN 16 | ||
113 | #define SLOT_ID_LEN 2 | ||
114 | |||
115 | struct c4_inquiry { | ||
116 | u8 peripheral_info; | ||
117 | u8 page_code; /* 0xC4 */ | ||
118 | u8 reserved1; | ||
119 | u8 page_len; | ||
120 | u8 page_id[4]; /* "subs" */ | ||
121 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
122 | u8 revision[4]; | ||
123 | u8 slot_id[SLOT_ID_LEN]; | ||
124 | u8 reserved[2]; | ||
125 | }; | ||
126 | |||
127 | struct rdac_controller { | ||
128 | u8 subsys_id[SUBSYS_ID_LEN]; | ||
129 | u8 slot_id[SLOT_ID_LEN]; | ||
130 | int use_ms10; | ||
131 | struct kref kref; | ||
132 | struct list_head node; /* list of all controllers */ | ||
133 | union { | ||
134 | struct rdac_pg_legacy legacy; | ||
135 | struct rdac_pg_expanded expanded; | ||
136 | } mode_select; | ||
137 | }; | ||
138 | struct c8_inquiry { | ||
139 | u8 peripheral_info; | ||
140 | u8 page_code; /* 0xC8 */ | ||
141 | u8 reserved1; | ||
142 | u8 page_len; | ||
143 | u8 page_id[4]; /* "edid" */ | ||
144 | u8 reserved2[3]; | ||
145 | u8 vol_uniq_id_len; | ||
146 | u8 vol_uniq_id[16]; | ||
147 | u8 vol_user_label_len; | ||
148 | u8 vol_user_label[60]; | ||
149 | u8 array_uniq_id_len; | ||
150 | u8 array_unique_id[16]; | ||
151 | u8 array_user_label_len; | ||
152 | u8 array_user_label[60]; | ||
153 | u8 lun[8]; | ||
154 | }; | ||
155 | |||
156 | struct c2_inquiry { | ||
157 | u8 peripheral_info; | ||
158 | u8 page_code; /* 0xC2 */ | ||
159 | u8 reserved1; | ||
160 | u8 page_len; | ||
161 | u8 page_id[4]; /* "swr4" */ | ||
162 | u8 sw_version[3]; | ||
163 | u8 sw_date[3]; | ||
164 | u8 features_enabled; | ||
165 | u8 max_lun_supported; | ||
166 | u8 partitions[239]; /* Total allocation length should be 0xFF */ | ||
167 | }; | ||
168 | |||
169 | struct rdac_dh_data { | ||
170 | struct rdac_controller *ctlr; | ||
171 | #define UNINITIALIZED_LUN (1 << 8) | ||
172 | unsigned lun; | ||
173 | #define RDAC_STATE_ACTIVE 0 | ||
174 | #define RDAC_STATE_PASSIVE 1 | ||
175 | unsigned char state; | ||
176 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
177 | union { | ||
178 | struct c2_inquiry c2; | ||
179 | struct c4_inquiry c4; | ||
180 | struct c8_inquiry c8; | ||
181 | struct c9_inquiry c9; | ||
182 | } inq; | ||
183 | }; | ||
184 | |||
185 | static LIST_HEAD(ctlr_list); | ||
186 | static DEFINE_SPINLOCK(list_lock); | ||
187 | |||
188 | static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) | ||
189 | { | ||
190 | struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; | ||
191 | BUG_ON(scsi_dh_data == NULL); | ||
192 | return ((struct rdac_dh_data *) scsi_dh_data->buf); | ||
193 | } | ||
194 | |||
195 | static struct request *get_rdac_req(struct scsi_device *sdev, | ||
196 | void *buffer, unsigned buflen, int rw) | ||
197 | { | ||
198 | struct request *rq; | ||
199 | struct request_queue *q = sdev->request_queue; | ||
200 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
201 | |||
202 | rq = blk_get_request(q, rw, GFP_KERNEL); | ||
203 | |||
204 | if (!rq) { | ||
205 | sdev_printk(KERN_INFO, sdev, | ||
206 | "get_rdac_req: blk_get_request failed.\n"); | ||
207 | return NULL; | ||
208 | } | ||
209 | |||
210 | if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) { | ||
211 | blk_put_request(rq); | ||
212 | sdev_printk(KERN_INFO, sdev, | ||
213 | "get_rdac_req: blk_rq_map_kern failed.\n"); | ||
214 | return NULL; | ||
215 | } | ||
216 | |||
217 | memset(&rq->cmd, 0, BLK_MAX_CDB); | ||
218 | rq->sense = h->sense; | ||
219 | memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
220 | rq->sense_len = 0; | ||
221 | |||
222 | rq->cmd_type = REQ_TYPE_BLOCK_PC; | ||
223 | rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; | ||
224 | rq->retries = RDAC_RETRIES; | ||
225 | rq->timeout = RDAC_TIMEOUT; | ||
226 | |||
227 | return rq; | ||
228 | } | ||
229 | |||
230 | static struct request *rdac_failover_get(struct scsi_device *sdev) | ||
231 | { | ||
232 | struct request *rq; | ||
233 | struct rdac_mode_common *common; | ||
234 | unsigned data_size; | ||
235 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
236 | |||
237 | if (h->ctlr->use_ms10) { | ||
238 | struct rdac_pg_expanded *rdac_pg; | ||
239 | |||
240 | data_size = sizeof(struct rdac_pg_expanded); | ||
241 | rdac_pg = &h->ctlr->mode_select.expanded; | ||
242 | memset(rdac_pg, 0, data_size); | ||
243 | common = &rdac_pg->common; | ||
244 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40; | ||
245 | rdac_pg->subpage_code = 0x1; | ||
246 | rdac_pg->page_len[0] = 0x01; | ||
247 | rdac_pg->page_len[1] = 0x28; | ||
248 | rdac_pg->lun_table[h->lun] = 0x81; | ||
249 | } else { | ||
250 | struct rdac_pg_legacy *rdac_pg; | ||
251 | |||
252 | data_size = sizeof(struct rdac_pg_legacy); | ||
253 | rdac_pg = &h->ctlr->mode_select.legacy; | ||
254 | memset(rdac_pg, 0, data_size); | ||
255 | common = &rdac_pg->common; | ||
256 | rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; | ||
257 | rdac_pg->page_len = 0x68; | ||
258 | rdac_pg->lun_table[h->lun] = 0x81; | ||
259 | } | ||
260 | common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; | ||
261 | common->quiescence_timeout = RDAC_QUIESCENCE_TIME; | ||
262 | common->rdac_options = RDAC_FORCED_QUIESENCE; | ||
263 | |||
264 | /* get request for block layer packet command */ | ||
265 | rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE); | ||
266 | if (!rq) | ||
267 | return NULL; | ||
268 | |||
269 | /* Prepare the command. */ | ||
270 | if (h->ctlr->use_ms10) { | ||
271 | rq->cmd[0] = MODE_SELECT_10; | ||
272 | rq->cmd[7] = data_size >> 8; | ||
273 | rq->cmd[8] = data_size & 0xff; | ||
274 | } else { | ||
275 | rq->cmd[0] = MODE_SELECT; | ||
276 | rq->cmd[4] = data_size; | ||
277 | } | ||
278 | rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); | ||
279 | |||
280 | return rq; | ||
281 | } | ||
282 | |||
283 | static void release_controller(struct kref *kref) | ||
284 | { | ||
285 | struct rdac_controller *ctlr; | ||
286 | ctlr = container_of(kref, struct rdac_controller, kref); | ||
287 | |||
288 | spin_lock(&list_lock); | ||
289 | list_del(&ctlr->node); | ||
290 | spin_unlock(&list_lock); | ||
291 | kfree(ctlr); | ||
292 | } | ||
293 | |||
294 | static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id) | ||
295 | { | ||
296 | struct rdac_controller *ctlr, *tmp; | ||
297 | |||
298 | spin_lock(&list_lock); | ||
299 | |||
300 | list_for_each_entry(tmp, &ctlr_list, node) { | ||
301 | if ((memcmp(tmp->subsys_id, subsys_id, SUBSYS_ID_LEN) == 0) && | ||
302 | (memcmp(tmp->slot_id, slot_id, SLOT_ID_LEN) == 0)) { | ||
303 | kref_get(&tmp->kref); | ||
304 | spin_unlock(&list_lock); | ||
305 | return tmp; | ||
306 | } | ||
307 | } | ||
308 | ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); | ||
309 | if (!ctlr) | ||
310 | goto done; | ||
311 | |||
312 | /* initialize fields of controller */ | ||
313 | memcpy(ctlr->subsys_id, subsys_id, SUBSYS_ID_LEN); | ||
314 | memcpy(ctlr->slot_id, slot_id, SLOT_ID_LEN); | ||
315 | kref_init(&ctlr->kref); | ||
316 | ctlr->use_ms10 = -1; | ||
317 | list_add(&ctlr->node, &ctlr_list); | ||
318 | done: | ||
319 | spin_unlock(&list_lock); | ||
320 | return ctlr; | ||
321 | } | ||
322 | |||
323 | static int submit_inquiry(struct scsi_device *sdev, int page_code, | ||
324 | unsigned int len) | ||
325 | { | ||
326 | struct request *rq; | ||
327 | struct request_queue *q = sdev->request_queue; | ||
328 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
329 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
330 | |||
331 | rq = get_rdac_req(sdev, &h->inq, len, READ); | ||
332 | if (!rq) | ||
333 | goto done; | ||
334 | |||
335 | /* Prepare the command. */ | ||
336 | rq->cmd[0] = INQUIRY; | ||
337 | rq->cmd[1] = 1; | ||
338 | rq->cmd[2] = page_code; | ||
339 | rq->cmd[4] = len; | ||
340 | rq->cmd_len = COMMAND_SIZE(INQUIRY); | ||
341 | err = blk_execute_rq(q, NULL, rq, 1); | ||
342 | if (err == -EIO) | ||
343 | err = SCSI_DH_IO; | ||
344 | done: | ||
345 | return err; | ||
346 | } | ||
347 | |||
348 | static int get_lun(struct scsi_device *sdev) | ||
349 | { | ||
350 | int err; | ||
351 | struct c8_inquiry *inqp; | ||
352 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
353 | |||
354 | err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry)); | ||
355 | if (err == SCSI_DH_OK) { | ||
356 | inqp = &h->inq.c8; | ||
357 | h->lun = inqp->lun[7]; /* currently it uses only one byte */ | ||
358 | } | ||
359 | return err; | ||
360 | } | ||
361 | |||
362 | #define RDAC_OWNED 0 | ||
363 | #define RDAC_UNOWNED 1 | ||
364 | #define RDAC_FAILED 2 | ||
365 | static int check_ownership(struct scsi_device *sdev) | ||
366 | { | ||
367 | int err; | ||
368 | struct c9_inquiry *inqp; | ||
369 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
370 | |||
371 | err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry)); | ||
372 | if (err == SCSI_DH_OK) { | ||
373 | err = RDAC_UNOWNED; | ||
374 | inqp = &h->inq.c9; | ||
375 | /* | ||
376 | * If in AVT mode or if the path already owns the LUN, | ||
377 | * return RDAC_OWNED; | ||
378 | */ | ||
379 | if (((inqp->avte_cvp >> 7) == 0x1) || | ||
380 | ((inqp->avte_cvp & 0x1) != 0)) | ||
381 | err = RDAC_OWNED; | ||
382 | } else | ||
383 | err = RDAC_FAILED; | ||
384 | return err; | ||
385 | } | ||
386 | |||
387 | static int initialize_controller(struct scsi_device *sdev) | ||
388 | { | ||
389 | int err; | ||
390 | struct c4_inquiry *inqp; | ||
391 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
392 | |||
393 | err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry)); | ||
394 | if (err == SCSI_DH_OK) { | ||
395 | inqp = &h->inq.c4; | ||
396 | h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id); | ||
397 | if (!h->ctlr) | ||
398 | err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
399 | } | ||
400 | return err; | ||
401 | } | ||
402 | |||
403 | static int set_mode_select(struct scsi_device *sdev) | ||
404 | { | ||
405 | int err; | ||
406 | struct c2_inquiry *inqp; | ||
407 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
408 | |||
409 | err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry)); | ||
410 | if (err == SCSI_DH_OK) { | ||
411 | inqp = &h->inq.c2; | ||
412 | /* | ||
413 | * If more than MODE6_MAX_LUN luns are supported, use | ||
414 | * mode select 10 | ||
415 | */ | ||
416 | if (inqp->max_lun_supported >= MODE6_MAX_LUN) | ||
417 | h->ctlr->use_ms10 = 1; | ||
418 | else | ||
419 | h->ctlr->use_ms10 = 0; | ||
420 | } | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | static int mode_select_handle_sense(struct scsi_device *sdev) | ||
425 | { | ||
426 | struct scsi_sense_hdr sense_hdr; | ||
427 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
428 | int sense, err = SCSI_DH_IO, ret; | ||
429 | |||
430 | ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr); | ||
431 | if (!ret) | ||
432 | goto done; | ||
433 | |||
434 | err = SCSI_DH_OK; | ||
435 | sense = (sense_hdr.sense_key << 16) | (sense_hdr.asc << 8) | | ||
436 | sense_hdr.ascq; | ||
437 | /* If it is retryable failure, submit the c9 inquiry again */ | ||
438 | if (sense == 0x59136 || sense == 0x68b02 || sense == 0xb8b02 || | ||
439 | sense == 0x62900) { | ||
440 | /* 0x59136 - Command lock contention | ||
441 | * 0x[6b]8b02 - Quiesense in progress or achieved | ||
442 | * 0x62900 - Power On, Reset, or Bus Device Reset | ||
443 | */ | ||
444 | err = SCSI_DH_RETRY; | ||
445 | } | ||
446 | |||
447 | if (sense) | ||
448 | sdev_printk(KERN_INFO, sdev, | ||
449 | "MODE_SELECT failed with sense 0x%x.\n", sense); | ||
450 | done: | ||
451 | return err; | ||
452 | } | ||
453 | |||
454 | static int send_mode_select(struct scsi_device *sdev) | ||
455 | { | ||
456 | struct request *rq; | ||
457 | struct request_queue *q = sdev->request_queue; | ||
458 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
459 | int err = SCSI_DH_RES_TEMP_UNAVAIL; | ||
460 | |||
461 | rq = rdac_failover_get(sdev); | ||
462 | if (!rq) | ||
463 | goto done; | ||
464 | |||
465 | sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n"); | ||
466 | |||
467 | err = blk_execute_rq(q, NULL, rq, 1); | ||
468 | if (err != SCSI_DH_OK) | ||
469 | err = mode_select_handle_sense(sdev); | ||
470 | if (err == SCSI_DH_OK) | ||
471 | h->state = RDAC_STATE_ACTIVE; | ||
472 | done: | ||
473 | return err; | ||
474 | } | ||
475 | |||
476 | static int rdac_activate(struct scsi_device *sdev) | ||
477 | { | ||
478 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
479 | int err = SCSI_DH_OK; | ||
480 | |||
481 | if (h->lun == UNINITIALIZED_LUN) { | ||
482 | err = get_lun(sdev); | ||
483 | if (err != SCSI_DH_OK) | ||
484 | goto done; | ||
485 | } | ||
486 | |||
487 | err = check_ownership(sdev); | ||
488 | switch (err) { | ||
489 | case RDAC_UNOWNED: | ||
490 | break; | ||
491 | case RDAC_OWNED: | ||
492 | err = SCSI_DH_OK; | ||
493 | goto done; | ||
494 | case RDAC_FAILED: | ||
495 | default: | ||
496 | err = SCSI_DH_IO; | ||
497 | goto done; | ||
498 | } | ||
499 | |||
500 | if (!h->ctlr) { | ||
501 | err = initialize_controller(sdev); | ||
502 | if (err != SCSI_DH_OK) | ||
503 | goto done; | ||
504 | } | ||
505 | |||
506 | if (h->ctlr->use_ms10 == -1) { | ||
507 | err = set_mode_select(sdev); | ||
508 | if (err != SCSI_DH_OK) | ||
509 | goto done; | ||
510 | } | ||
511 | |||
512 | err = send_mode_select(sdev); | ||
513 | done: | ||
514 | return err; | ||
515 | } | ||
516 | |||
517 | static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) | ||
518 | { | ||
519 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
520 | int ret = BLKPREP_OK; | ||
521 | |||
522 | if (h->state != RDAC_STATE_ACTIVE) { | ||
523 | ret = BLKPREP_KILL; | ||
524 | req->cmd_flags |= REQ_QUIET; | ||
525 | } | ||
526 | return ret; | ||
527 | |||
528 | } | ||
529 | |||
530 | static int rdac_check_sense(struct scsi_device *sdev, | ||
531 | struct scsi_sense_hdr *sense_hdr) | ||
532 | { | ||
533 | struct rdac_dh_data *h = get_rdac_data(sdev); | ||
534 | switch (sense_hdr->sense_key) { | ||
535 | case NOT_READY: | ||
536 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81) | ||
537 | /* LUN Not Ready - Storage firmware incompatible | ||
538 | * Manual code synchonisation required. | ||
539 | * | ||
540 | * Nothing we can do here. Try to bypass the path. | ||
541 | */ | ||
542 | return SUCCESS; | ||
543 | if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0xA1) | ||
544 | /* LUN Not Ready - Quiescense in progress | ||
545 | * | ||
546 | * Just retry and wait. | ||
547 | */ | ||
548 | return NEEDS_RETRY; | ||
549 | break; | ||
550 | case ILLEGAL_REQUEST: | ||
551 | if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) { | ||
552 | /* Invalid Request - Current Logical Unit Ownership. | ||
553 | * Controller is not the current owner of the LUN, | ||
554 | * Fail the path, so that the other path be used. | ||
555 | */ | ||
556 | h->state = RDAC_STATE_PASSIVE; | ||
557 | return SUCCESS; | ||
558 | } | ||
559 | break; | ||
560 | case UNIT_ATTENTION: | ||
561 | if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) | ||
562 | /* | ||
563 | * Power On, Reset, or Bus Device Reset, just retry. | ||
564 | */ | ||
565 | return NEEDS_RETRY; | ||
566 | break; | ||
567 | } | ||
568 | /* success just means we do not care what scsi-ml does */ | ||
569 | return SCSI_RETURN_NOT_HANDLED; | ||
570 | } | ||
571 | |||
572 | static const struct { | ||
573 | char *vendor; | ||
574 | char *model; | ||
575 | } rdac_dev_list[] = { | ||
576 | {"IBM", "1722"}, | ||
577 | {"IBM", "1724"}, | ||
578 | {"IBM", "1726"}, | ||
579 | {"IBM", "1742"}, | ||
580 | {"IBM", "1814"}, | ||
581 | {"IBM", "1815"}, | ||
582 | {"IBM", "1818"}, | ||
583 | {"IBM", "3526"}, | ||
584 | {"SGI", "TP9400"}, | ||
585 | {"SGI", "TP9500"}, | ||
586 | {"SGI", "IS"}, | ||
587 | {"STK", "OPENstorage D280"}, | ||
588 | {"SUN", "CSM200_R"}, | ||
589 | {"SUN", "LCSM100_F"}, | ||
590 | {NULL, NULL}, | ||
591 | }; | ||
592 | |||
593 | static int rdac_bus_notify(struct notifier_block *, unsigned long, void *); | ||
594 | |||
595 | static struct scsi_device_handler rdac_dh = { | ||
596 | .name = RDAC_NAME, | ||
597 | .module = THIS_MODULE, | ||
598 | .nb.notifier_call = rdac_bus_notify, | ||
599 | .prep_fn = rdac_prep_fn, | ||
600 | .check_sense = rdac_check_sense, | ||
601 | .activate = rdac_activate, | ||
602 | }; | ||
603 | |||
604 | /* | ||
605 | * TODO: need some interface so we can set trespass values | ||
606 | */ | ||
607 | static int rdac_bus_notify(struct notifier_block *nb, | ||
608 | unsigned long action, void *data) | ||
609 | { | ||
610 | struct device *dev = data; | ||
611 | struct scsi_device *sdev = to_scsi_device(dev); | ||
612 | struct scsi_dh_data *scsi_dh_data; | ||
613 | struct rdac_dh_data *h; | ||
614 | int i, found = 0; | ||
615 | unsigned long flags; | ||
616 | |||
617 | if (action == BUS_NOTIFY_ADD_DEVICE) { | ||
618 | for (i = 0; rdac_dev_list[i].vendor; i++) { | ||
619 | if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, | ||
620 | strlen(rdac_dev_list[i].vendor)) && | ||
621 | !strncmp(sdev->model, rdac_dev_list[i].model, | ||
622 | strlen(rdac_dev_list[i].model))) { | ||
623 | found = 1; | ||
624 | break; | ||
625 | } | ||
626 | } | ||
627 | if (!found) | ||
628 | goto out; | ||
629 | |||
630 | scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *) | ||
631 | + sizeof(*h) , GFP_KERNEL); | ||
632 | if (!scsi_dh_data) { | ||
633 | sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n", | ||
634 | RDAC_NAME); | ||
635 | goto out; | ||
636 | } | ||
637 | |||
638 | scsi_dh_data->scsi_dh = &rdac_dh; | ||
639 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
640 | h->lun = UNINITIALIZED_LUN; | ||
641 | h->state = RDAC_STATE_ACTIVE; | ||
642 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
643 | sdev->scsi_dh_data = scsi_dh_data; | ||
644 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
645 | try_module_get(THIS_MODULE); | ||
646 | |||
647 | sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME); | ||
648 | |||
649 | } else if (action == BUS_NOTIFY_DEL_DEVICE) { | ||
650 | if (sdev->scsi_dh_data == NULL || | ||
651 | sdev->scsi_dh_data->scsi_dh != &rdac_dh) | ||
652 | goto out; | ||
653 | |||
654 | spin_lock_irqsave(sdev->request_queue->queue_lock, flags); | ||
655 | scsi_dh_data = sdev->scsi_dh_data; | ||
656 | sdev->scsi_dh_data = NULL; | ||
657 | spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); | ||
658 | |||
659 | h = (struct rdac_dh_data *) scsi_dh_data->buf; | ||
660 | if (h->ctlr) | ||
661 | kref_put(&h->ctlr->kref, release_controller); | ||
662 | kfree(scsi_dh_data); | ||
663 | module_put(THIS_MODULE); | ||
664 | sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME); | ||
665 | } | ||
666 | |||
667 | out: | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static int __init rdac_init(void) | ||
672 | { | ||
673 | int r; | ||
674 | |||
675 | r = scsi_register_device_handler(&rdac_dh); | ||
676 | if (r != 0) | ||
677 | printk(KERN_ERR "Failed to register scsi device handler."); | ||
678 | return r; | ||
679 | } | ||
680 | |||
681 | static void __exit rdac_exit(void) | ||
682 | { | ||
683 | scsi_unregister_device_handler(&rdac_dh); | ||
684 | } | ||
685 | |||
686 | module_init(rdac_init); | ||
687 | module_exit(rdac_exit); | ||
688 | |||
689 | MODULE_DESCRIPTION("Multipath LSI/Engenio RDAC driver"); | ||
690 | MODULE_AUTHOR("Mike Christie, Chandra Seetharaman"); | ||
691 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c index 59fbef08d690..62a4618530d0 100644 --- a/drivers/scsi/esp_scsi.c +++ b/drivers/scsi/esp_scsi.c | |||
@@ -219,19 +219,10 @@ static void esp_reset_esp(struct esp *esp) | |||
219 | /* Now reset the ESP chip */ | 219 | /* Now reset the ESP chip */ |
220 | scsi_esp_cmd(esp, ESP_CMD_RC); | 220 | scsi_esp_cmd(esp, ESP_CMD_RC); |
221 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); | 221 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); |
222 | if (esp->rev == FAST) | ||
223 | esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2); | ||
222 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); | 224 | scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); |
223 | 225 | ||
224 | /* Reload the configuration registers */ | ||
225 | esp_write8(esp->cfact, ESP_CFACT); | ||
226 | |||
227 | esp->prev_stp = 0; | ||
228 | esp_write8(esp->prev_stp, ESP_STP); | ||
229 | |||
230 | esp->prev_soff = 0; | ||
231 | esp_write8(esp->prev_soff, ESP_SOFF); | ||
232 | |||
233 | esp_write8(esp->neg_defp, ESP_TIMEO); | ||
234 | |||
235 | /* This is the only point at which it is reliable to read | 226 | /* This is the only point at which it is reliable to read |
236 | * the ID-code for a fast ESP chip variants. | 227 | * the ID-code for a fast ESP chip variants. |
237 | */ | 228 | */ |
@@ -316,6 +307,17 @@ static void esp_reset_esp(struct esp *esp) | |||
316 | break; | 307 | break; |
317 | } | 308 | } |
318 | 309 | ||
310 | /* Reload the configuration registers */ | ||
311 | esp_write8(esp->cfact, ESP_CFACT); | ||
312 | |||
313 | esp->prev_stp = 0; | ||
314 | esp_write8(esp->prev_stp, ESP_STP); | ||
315 | |||
316 | esp->prev_soff = 0; | ||
317 | esp_write8(esp->prev_soff, ESP_SOFF); | ||
318 | |||
319 | esp_write8(esp->neg_defp, ESP_TIMEO); | ||
320 | |||
319 | /* Eat any bitrot in the chip */ | 321 | /* Eat any bitrot in the chip */ |
320 | esp_read8(ESP_INTRPT); | 322 | esp_read8(ESP_INTRPT); |
321 | udelay(100); | 323 | udelay(100); |
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index c6457bfc8a49..35cd892dce04 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c | |||
@@ -290,7 +290,7 @@ static void scsi_host_dev_release(struct device *dev) | |||
290 | kfree(shost); | 290 | kfree(shost); |
291 | } | 291 | } |
292 | 292 | ||
293 | struct device_type scsi_host_type = { | 293 | static struct device_type scsi_host_type = { |
294 | .name = "scsi_host", | 294 | .name = "scsi_host", |
295 | .release = scsi_host_dev_release, | 295 | .release = scsi_host_dev_release, |
296 | }; | 296 | }; |
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 6ac0633d5452..a423d9633625 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile | |||
@@ -5,3 +5,4 @@ ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o | |||
5 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o | 5 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o |
6 | 6 | ||
7 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o | 7 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o |
8 | obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o | ||
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c new file mode 100644 index 000000000000..eb702b96d57c --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc.c | |||
@@ -0,0 +1,3910 @@ | |||
1 | /* | ||
2 | * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter | ||
3 | * | ||
4 | * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation | ||
5 | * | ||
6 | * Copyright (C) IBM Corporation, 2008 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/dmapool.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/of.h> | ||
32 | #include <linux/stringify.h> | ||
33 | #include <asm/firmware.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/vio.h> | ||
36 | #include <scsi/scsi.h> | ||
37 | #include <scsi/scsi_cmnd.h> | ||
38 | #include <scsi/scsi_host.h> | ||
39 | #include <scsi/scsi_device.h> | ||
40 | #include <scsi/scsi_tcq.h> | ||
41 | #include <scsi/scsi_transport_fc.h> | ||
42 | #include "ibmvfc.h" | ||
43 | |||
44 | static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT; | ||
45 | static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; | ||
46 | static unsigned int max_lun = IBMVFC_MAX_LUN; | ||
47 | static unsigned int max_targets = IBMVFC_MAX_TARGETS; | ||
48 | static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; | ||
49 | static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; | ||
50 | static unsigned int dev_loss_tmo = IBMVFC_DEV_LOSS_TMO; | ||
51 | static unsigned int ibmvfc_debug = IBMVFC_DEBUG; | ||
52 | static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; | ||
53 | static LIST_HEAD(ibmvfc_head); | ||
54 | static DEFINE_SPINLOCK(ibmvfc_driver_lock); | ||
55 | static struct scsi_transport_template *ibmvfc_transport_template; | ||
56 | |||
57 | MODULE_DESCRIPTION("IBM Virtual Fibre Channel Driver"); | ||
58 | MODULE_AUTHOR("Brian King <brking@linux.vnet.ibm.com>"); | ||
59 | MODULE_LICENSE("GPL"); | ||
60 | MODULE_VERSION(IBMVFC_DRIVER_VERSION); | ||
61 | |||
62 | module_param_named(init_timeout, init_timeout, uint, S_IRUGO | S_IWUSR); | ||
63 | MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds. " | ||
64 | "[Default=" __stringify(IBMVFC_INIT_TIMEOUT) "]"); | ||
65 | module_param_named(default_timeout, default_timeout, uint, S_IRUGO | S_IWUSR); | ||
66 | MODULE_PARM_DESC(default_timeout, | ||
67 | "Default timeout in seconds for initialization and EH commands. " | ||
68 | "[Default=" __stringify(IBMVFC_DEFAULT_TIMEOUT) "]"); | ||
69 | module_param_named(max_requests, max_requests, uint, S_IRUGO); | ||
70 | MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. " | ||
71 | "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]"); | ||
72 | module_param_named(max_lun, max_lun, uint, S_IRUGO); | ||
73 | MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " | ||
74 | "[Default=" __stringify(IBMVFC_MAX_LUN) "]"); | ||
75 | module_param_named(max_targets, max_targets, uint, S_IRUGO); | ||
76 | MODULE_PARM_DESC(max_targets, "Maximum allowed targets. " | ||
77 | "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]"); | ||
78 | module_param_named(disc_threads, disc_threads, uint, S_IRUGO | S_IWUSR); | ||
79 | MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " | ||
80 | "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]"); | ||
81 | module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); | ||
82 | MODULE_PARM_DESC(debug, "Enable driver debug information. " | ||
83 | "[Default=" __stringify(IBMVFC_DEBUG) "]"); | ||
84 | module_param_named(dev_loss_tmo, dev_loss_tmo, uint, S_IRUGO | S_IWUSR); | ||
85 | MODULE_PARM_DESC(dev_loss_tmo, "Maximum number of seconds that the FC " | ||
86 | "transport should insulate the loss of a remote port. Once this " | ||
87 | "value is exceeded, the scsi target is removed. " | ||
88 | "[Default=" __stringify(IBMVFC_DEV_LOSS_TMO) "]"); | ||
89 | module_param_named(log_level, log_level, uint, 0); | ||
90 | MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. " | ||
91 | "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]"); | ||
92 | |||
93 | static const struct { | ||
94 | u16 status; | ||
95 | u16 error; | ||
96 | u8 result; | ||
97 | u8 retry; | ||
98 | int log; | ||
99 | char *name; | ||
100 | } cmd_status [] = { | ||
101 | { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, | ||
102 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, | ||
103 | { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, | ||
104 | { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" }, | ||
105 | { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, | ||
106 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, | ||
107 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, | ||
108 | { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_REGISTER, DID_ERROR, 1, 1, "unable to register" }, | ||
109 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_BUSY, DID_BUS_BUSY, 1, 0, "transport busy" }, | ||
110 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" }, | ||
111 | { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" }, | ||
112 | { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, | ||
113 | { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 0, 0, "link halted" }, | ||
114 | { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" }, | ||
115 | |||
116 | { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, | ||
117 | { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, | ||
118 | { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" }, | ||
119 | { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" }, | ||
120 | { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, | ||
121 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, | ||
122 | { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, | ||
123 | { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, | ||
124 | { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, | ||
125 | |||
126 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, | ||
127 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_VERSION, DID_ERROR, 0, 1, "invalid version level" }, | ||
128 | { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_ERROR, DID_ERROR, 1, 1, "logical error" }, | ||
129 | { IBMVFC_FC_FAILURE, IBMVFC_INVALID_CT_IU_SIZE, DID_ERROR, 0, 1, "invalid CT_IU size" }, | ||
130 | { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_BUSY, DID_REQUEUE, 1, 0, "logical busy" }, | ||
131 | { IBMVFC_FC_FAILURE, IBMVFC_PROTOCOL_ERROR, DID_ERROR, 1, 1, "protocol error" }, | ||
132 | { IBMVFC_FC_FAILURE, IBMVFC_UNABLE_TO_PERFORM_REQ, DID_ERROR, 1, 1, "unable to perform request" }, | ||
133 | { IBMVFC_FC_FAILURE, IBMVFC_CMD_NOT_SUPPORTED, DID_ERROR, 0, 0, "command not supported" }, | ||
134 | { IBMVFC_FC_FAILURE, IBMVFC_SERVER_NOT_AVAIL, DID_ERROR, 0, 1, "server not available" }, | ||
135 | { IBMVFC_FC_FAILURE, IBMVFC_CMD_IN_PROGRESS, DID_ERROR, 0, 1, "command already in progress" }, | ||
136 | { IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" }, | ||
137 | |||
138 | { IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" }, | ||
139 | }; | ||
140 | |||
141 | static void ibmvfc_npiv_login(struct ibmvfc_host *); | ||
142 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); | ||
143 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); | ||
144 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *); | ||
145 | |||
146 | static const char *unknown_error = "unknown error"; | ||
147 | |||
148 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
149 | /** | ||
150 | * ibmvfc_trc_start - Log a start trace entry | ||
151 | * @evt: ibmvfc event struct | ||
152 | * | ||
153 | **/ | ||
154 | static void ibmvfc_trc_start(struct ibmvfc_event *evt) | ||
155 | { | ||
156 | struct ibmvfc_host *vhost = evt->vhost; | ||
157 | struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; | ||
158 | struct ibmvfc_mad_common *mad = &evt->iu.mad_common; | ||
159 | struct ibmvfc_trace_entry *entry; | ||
160 | |||
161 | entry = &vhost->trace[vhost->trace_index++]; | ||
162 | entry->evt = evt; | ||
163 | entry->time = jiffies; | ||
164 | entry->fmt = evt->crq.format; | ||
165 | entry->type = IBMVFC_TRC_START; | ||
166 | |||
167 | switch (entry->fmt) { | ||
168 | case IBMVFC_CMD_FORMAT: | ||
169 | entry->op_code = vfc_cmd->iu.cdb[0]; | ||
170 | entry->scsi_id = vfc_cmd->tgt_scsi_id; | ||
171 | entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); | ||
172 | entry->tmf_flags = vfc_cmd->iu.tmf_flags; | ||
173 | entry->u.start.xfer_len = vfc_cmd->iu.xfer_len; | ||
174 | break; | ||
175 | case IBMVFC_MAD_FORMAT: | ||
176 | entry->op_code = mad->opcode; | ||
177 | break; | ||
178 | default: | ||
179 | break; | ||
180 | }; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * ibmvfc_trc_end - Log an end trace entry | ||
185 | * @evt: ibmvfc event struct | ||
186 | * | ||
187 | **/ | ||
188 | static void ibmvfc_trc_end(struct ibmvfc_event *evt) | ||
189 | { | ||
190 | struct ibmvfc_host *vhost = evt->vhost; | ||
191 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
192 | struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common; | ||
193 | struct ibmvfc_trace_entry *entry = &vhost->trace[vhost->trace_index++]; | ||
194 | |||
195 | entry->evt = evt; | ||
196 | entry->time = jiffies; | ||
197 | entry->fmt = evt->crq.format; | ||
198 | entry->type = IBMVFC_TRC_END; | ||
199 | |||
200 | switch (entry->fmt) { | ||
201 | case IBMVFC_CMD_FORMAT: | ||
202 | entry->op_code = vfc_cmd->iu.cdb[0]; | ||
203 | entry->scsi_id = vfc_cmd->tgt_scsi_id; | ||
204 | entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); | ||
205 | entry->tmf_flags = vfc_cmd->iu.tmf_flags; | ||
206 | entry->u.end.status = vfc_cmd->status; | ||
207 | entry->u.end.error = vfc_cmd->error; | ||
208 | entry->u.end.fcp_rsp_flags = vfc_cmd->rsp.flags; | ||
209 | entry->u.end.rsp_code = vfc_cmd->rsp.data.info.rsp_code; | ||
210 | entry->u.end.scsi_status = vfc_cmd->rsp.scsi_status; | ||
211 | break; | ||
212 | case IBMVFC_MAD_FORMAT: | ||
213 | entry->op_code = mad->opcode; | ||
214 | entry->u.end.status = mad->status; | ||
215 | break; | ||
216 | default: | ||
217 | break; | ||
218 | |||
219 | }; | ||
220 | } | ||
221 | |||
222 | #else | ||
223 | #define ibmvfc_trc_start(evt) do { } while (0) | ||
224 | #define ibmvfc_trc_end(evt) do { } while (0) | ||
225 | #endif | ||
226 | |||
227 | /** | ||
228 | * ibmvfc_get_err_index - Find the index into cmd_status for the fcp response | ||
229 | * @status: status / error class | ||
230 | * @error: error | ||
231 | * | ||
232 | * Return value: | ||
233 | * index into cmd_status / -EINVAL on failure | ||
234 | **/ | ||
235 | static int ibmvfc_get_err_index(u16 status, u16 error) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | for (i = 0; i < ARRAY_SIZE(cmd_status); i++) | ||
240 | if ((cmd_status[i].status & status) == cmd_status[i].status && | ||
241 | cmd_status[i].error == error) | ||
242 | return i; | ||
243 | |||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * ibmvfc_get_cmd_error - Find the error description for the fcp response | ||
249 | * @status: status / error class | ||
250 | * @error: error | ||
251 | * | ||
252 | * Return value: | ||
253 | * error description string | ||
254 | **/ | ||
255 | static const char *ibmvfc_get_cmd_error(u16 status, u16 error) | ||
256 | { | ||
257 | int rc = ibmvfc_get_err_index(status, error); | ||
258 | if (rc >= 0) | ||
259 | return cmd_status[rc].name; | ||
260 | return unknown_error; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * ibmvfc_get_err_result - Find the scsi status to return for the fcp response | ||
265 | * @vfc_cmd: ibmvfc command struct | ||
266 | * | ||
267 | * Return value: | ||
268 | * SCSI result value to return for completed command | ||
269 | **/ | ||
270 | static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) | ||
271 | { | ||
272 | int err; | ||
273 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
274 | int fc_rsp_len = rsp->fcp_rsp_len; | ||
275 | |||
276 | if ((rsp->flags & FCP_RSP_LEN_VALID) && | ||
277 | ((!fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || | ||
278 | rsp->data.info.rsp_code)) | ||
279 | return DID_ERROR << 16; | ||
280 | |||
281 | if (!vfc_cmd->status) { | ||
282 | if (rsp->flags & FCP_RESID_OVER) | ||
283 | return rsp->scsi_status | (DID_ERROR << 16); | ||
284 | else | ||
285 | return rsp->scsi_status | (DID_OK << 16); | ||
286 | } | ||
287 | |||
288 | err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | ||
289 | if (err >= 0) | ||
290 | return rsp->scsi_status | (cmd_status[err].result << 16); | ||
291 | return rsp->scsi_status | (DID_ERROR << 16); | ||
292 | } | ||
293 | |||
294 | /** | ||
295 | * ibmvfc_retry_cmd - Determine if error status is retryable | ||
296 | * @status: status / error class | ||
297 | * @error: error | ||
298 | * | ||
299 | * Return value: | ||
300 | * 1 if error should be retried / 0 if it should not | ||
301 | **/ | ||
302 | static int ibmvfc_retry_cmd(u16 status, u16 error) | ||
303 | { | ||
304 | int rc = ibmvfc_get_err_index(status, error); | ||
305 | |||
306 | if (rc >= 0) | ||
307 | return cmd_status[rc].retry; | ||
308 | return 1; | ||
309 | } | ||
310 | |||
311 | static const char *unknown_fc_explain = "unknown fc explain"; | ||
312 | |||
313 | static const struct { | ||
314 | u16 fc_explain; | ||
315 | char *name; | ||
316 | } ls_explain [] = { | ||
317 | { 0x00, "no additional explanation" }, | ||
318 | { 0x01, "service parameter error - options" }, | ||
319 | { 0x03, "service parameter error - initiator control" }, | ||
320 | { 0x05, "service parameter error - recipient control" }, | ||
321 | { 0x07, "service parameter error - received data field size" }, | ||
322 | { 0x09, "service parameter error - concurrent seq" }, | ||
323 | { 0x0B, "service parameter error - credit" }, | ||
324 | { 0x0D, "invalid N_Port/F_Port_Name" }, | ||
325 | { 0x0E, "invalid node/Fabric Name" }, | ||
326 | { 0x0F, "invalid common service parameters" }, | ||
327 | { 0x11, "invalid association header" }, | ||
328 | { 0x13, "association header required" }, | ||
329 | { 0x15, "invalid originator S_ID" }, | ||
330 | { 0x17, "invalid OX_ID-RX-ID combination" }, | ||
331 | { 0x19, "command (request) already in progress" }, | ||
332 | { 0x1E, "N_Port Login requested" }, | ||
333 | { 0x1F, "Invalid N_Port_ID" }, | ||
334 | }; | ||
335 | |||
336 | static const struct { | ||
337 | u16 fc_explain; | ||
338 | char *name; | ||
339 | } gs_explain [] = { | ||
340 | { 0x00, "no additional explanation" }, | ||
341 | { 0x01, "port identifier not registered" }, | ||
342 | { 0x02, "port name not registered" }, | ||
343 | { 0x03, "node name not registered" }, | ||
344 | { 0x04, "class of service not registered" }, | ||
345 | { 0x06, "initial process associator not registered" }, | ||
346 | { 0x07, "FC-4 TYPEs not registered" }, | ||
347 | { 0x08, "symbolic port name not registered" }, | ||
348 | { 0x09, "symbolic node name not registered" }, | ||
349 | { 0x0A, "port type not registered" }, | ||
350 | { 0xF0, "authorization exception" }, | ||
351 | { 0xF1, "authentication exception" }, | ||
352 | { 0xF2, "data base full" }, | ||
353 | { 0xF3, "data base empty" }, | ||
354 | { 0xF4, "processing request" }, | ||
355 | { 0xF5, "unable to verify connection" }, | ||
356 | { 0xF6, "devices not in a common zone" }, | ||
357 | }; | ||
358 | |||
359 | /** | ||
360 | * ibmvfc_get_ls_explain - Return the FC Explain description text | ||
361 | * @status: FC Explain status | ||
362 | * | ||
363 | * Returns: | ||
364 | * error string | ||
365 | **/ | ||
366 | static const char *ibmvfc_get_ls_explain(u16 status) | ||
367 | { | ||
368 | int i; | ||
369 | |||
370 | for (i = 0; i < ARRAY_SIZE(ls_explain); i++) | ||
371 | if (ls_explain[i].fc_explain == status) | ||
372 | return ls_explain[i].name; | ||
373 | |||
374 | return unknown_fc_explain; | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * ibmvfc_get_gs_explain - Return the FC Explain description text | ||
379 | * @status: FC Explain status | ||
380 | * | ||
381 | * Returns: | ||
382 | * error string | ||
383 | **/ | ||
384 | static const char *ibmvfc_get_gs_explain(u16 status) | ||
385 | { | ||
386 | int i; | ||
387 | |||
388 | for (i = 0; i < ARRAY_SIZE(gs_explain); i++) | ||
389 | if (gs_explain[i].fc_explain == status) | ||
390 | return gs_explain[i].name; | ||
391 | |||
392 | return unknown_fc_explain; | ||
393 | } | ||
394 | |||
395 | static const struct { | ||
396 | enum ibmvfc_fc_type fc_type; | ||
397 | char *name; | ||
398 | } fc_type [] = { | ||
399 | { IBMVFC_FABRIC_REJECT, "fabric reject" }, | ||
400 | { IBMVFC_PORT_REJECT, "port reject" }, | ||
401 | { IBMVFC_LS_REJECT, "ELS reject" }, | ||
402 | { IBMVFC_FABRIC_BUSY, "fabric busy" }, | ||
403 | { IBMVFC_PORT_BUSY, "port busy" }, | ||
404 | { IBMVFC_BASIC_REJECT, "basic reject" }, | ||
405 | }; | ||
406 | |||
407 | static const char *unknown_fc_type = "unknown fc type"; | ||
408 | |||
409 | /** | ||
410 | * ibmvfc_get_fc_type - Return the FC Type description text | ||
411 | * @status: FC Type error status | ||
412 | * | ||
413 | * Returns: | ||
414 | * error string | ||
415 | **/ | ||
416 | static const char *ibmvfc_get_fc_type(u16 status) | ||
417 | { | ||
418 | int i; | ||
419 | |||
420 | for (i = 0; i < ARRAY_SIZE(fc_type); i++) | ||
421 | if (fc_type[i].fc_type == status) | ||
422 | return fc_type[i].name; | ||
423 | |||
424 | return unknown_fc_type; | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * ibmvfc_set_tgt_action - Set the next init action for the target | ||
429 | * @tgt: ibmvfc target struct | ||
430 | * @action: action to perform | ||
431 | * | ||
432 | **/ | ||
433 | static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, | ||
434 | enum ibmvfc_target_action action) | ||
435 | { | ||
436 | switch (tgt->action) { | ||
437 | case IBMVFC_TGT_ACTION_DEL_RPORT: | ||
438 | break; | ||
439 | default: | ||
440 | tgt->action = action; | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | /** | ||
446 | * ibmvfc_set_host_state - Set the state for the host | ||
447 | * @vhost: ibmvfc host struct | ||
448 | * @state: state to set host to | ||
449 | * | ||
450 | * Returns: | ||
451 | * 0 if state changed / non-zero if not changed | ||
452 | **/ | ||
453 | static int ibmvfc_set_host_state(struct ibmvfc_host *vhost, | ||
454 | enum ibmvfc_host_state state) | ||
455 | { | ||
456 | int rc = 0; | ||
457 | |||
458 | switch (vhost->state) { | ||
459 | case IBMVFC_HOST_OFFLINE: | ||
460 | rc = -EINVAL; | ||
461 | break; | ||
462 | default: | ||
463 | vhost->state = state; | ||
464 | break; | ||
465 | }; | ||
466 | |||
467 | return rc; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * ibmvfc_set_host_action - Set the next init action for the host | ||
472 | * @vhost: ibmvfc host struct | ||
473 | * @action: action to perform | ||
474 | * | ||
475 | **/ | ||
476 | static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, | ||
477 | enum ibmvfc_host_action action) | ||
478 | { | ||
479 | switch (action) { | ||
480 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
481 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) | ||
482 | vhost->action = action; | ||
483 | break; | ||
484 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
485 | if (vhost->action == IBMVFC_HOST_ACTION_INIT) | ||
486 | vhost->action = action; | ||
487 | break; | ||
488 | case IBMVFC_HOST_ACTION_QUERY: | ||
489 | switch (vhost->action) { | ||
490 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
491 | case IBMVFC_HOST_ACTION_NONE: | ||
492 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
493 | vhost->action = action; | ||
494 | break; | ||
495 | default: | ||
496 | break; | ||
497 | }; | ||
498 | break; | ||
499 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
500 | if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) | ||
501 | vhost->action = action; | ||
502 | break; | ||
503 | case IBMVFC_HOST_ACTION_INIT: | ||
504 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
505 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
506 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
507 | case IBMVFC_HOST_ACTION_NONE: | ||
508 | default: | ||
509 | vhost->action = action; | ||
510 | break; | ||
511 | }; | ||
512 | } | ||
513 | |||
514 | /** | ||
515 | * ibmvfc_reinit_host - Re-start host initialization (no NPIV Login) | ||
516 | * @vhost: ibmvfc host struct | ||
517 | * | ||
518 | * Return value: | ||
519 | * nothing | ||
520 | **/ | ||
521 | static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) | ||
522 | { | ||
523 | if (vhost->action == IBMVFC_HOST_ACTION_NONE) { | ||
524 | scsi_block_requests(vhost->host); | ||
525 | ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING); | ||
526 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
527 | } else | ||
528 | vhost->reinit = 1; | ||
529 | |||
530 | wake_up(&vhost->work_wait_q); | ||
531 | } | ||
532 | |||
533 | /** | ||
534 | * ibmvfc_link_down - Handle a link down event from the adapter | ||
535 | * @vhost: ibmvfc host struct | ||
536 | * @state: ibmvfc host state to enter | ||
537 | * | ||
538 | **/ | ||
539 | static void ibmvfc_link_down(struct ibmvfc_host *vhost, | ||
540 | enum ibmvfc_host_state state) | ||
541 | { | ||
542 | struct ibmvfc_target *tgt; | ||
543 | |||
544 | ENTER; | ||
545 | scsi_block_requests(vhost->host); | ||
546 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
547 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
548 | ibmvfc_set_host_state(vhost, state); | ||
549 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | ||
550 | vhost->events_to_log |= IBMVFC_AE_LINKDOWN; | ||
551 | wake_up(&vhost->work_wait_q); | ||
552 | LEAVE; | ||
553 | } | ||
554 | |||
555 | /** | ||
556 | * ibmvfc_init_host - Start host initialization | ||
557 | * @vhost: ibmvfc host struct | ||
558 | * | ||
559 | * Return value: | ||
560 | * nothing | ||
561 | **/ | ||
562 | static void ibmvfc_init_host(struct ibmvfc_host *vhost) | ||
563 | { | ||
564 | struct ibmvfc_target *tgt; | ||
565 | |||
566 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | ||
567 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
568 | dev_err(vhost->dev, | ||
569 | "Host initialization retries exceeded. Taking adapter offline\n"); | ||
570 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | ||
571 | return; | ||
572 | } | ||
573 | } | ||
574 | |||
575 | if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { | ||
576 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
577 | tgt->need_login = 1; | ||
578 | scsi_block_requests(vhost->host); | ||
579 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
580 | vhost->job_step = ibmvfc_npiv_login; | ||
581 | wake_up(&vhost->work_wait_q); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * ibmvfc_send_crq - Send a CRQ | ||
587 | * @vhost: ibmvfc host struct | ||
588 | * @word1: the first 64 bits of the data | ||
589 | * @word2: the second 64 bits of the data | ||
590 | * | ||
591 | * Return value: | ||
592 | * 0 on success / other on failure | ||
593 | **/ | ||
594 | static int ibmvfc_send_crq(struct ibmvfc_host *vhost, u64 word1, u64 word2) | ||
595 | { | ||
596 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
597 | return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); | ||
598 | } | ||
599 | |||
600 | /** | ||
601 | * ibmvfc_send_crq_init - Send a CRQ init message | ||
602 | * @vhost: ibmvfc host struct | ||
603 | * | ||
604 | * Return value: | ||
605 | * 0 on success / other on failure | ||
606 | **/ | ||
607 | static int ibmvfc_send_crq_init(struct ibmvfc_host *vhost) | ||
608 | { | ||
609 | ibmvfc_dbg(vhost, "Sending CRQ init\n"); | ||
610 | return ibmvfc_send_crq(vhost, 0xC001000000000000LL, 0); | ||
611 | } | ||
612 | |||
613 | /** | ||
614 | * ibmvfc_send_crq_init_complete - Send a CRQ init complete message | ||
615 | * @vhost: ibmvfc host struct | ||
616 | * | ||
617 | * Return value: | ||
618 | * 0 on success / other on failure | ||
619 | **/ | ||
620 | static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) | ||
621 | { | ||
622 | ibmvfc_dbg(vhost, "Sending CRQ init complete\n"); | ||
623 | return ibmvfc_send_crq(vhost, 0xC002000000000000LL, 0); | ||
624 | } | ||
625 | |||
626 | /** | ||
627 | * ibmvfc_release_crq_queue - Deallocates data and unregisters CRQ | ||
628 | * @vhost: ibmvfc host struct | ||
629 | * | ||
630 | * Frees irq, deallocates a page for messages, unmaps dma, and unregisters | ||
631 | * the crq with the hypervisor. | ||
632 | **/ | ||
633 | static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) | ||
634 | { | ||
635 | long rc; | ||
636 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
637 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
638 | |||
639 | ibmvfc_dbg(vhost, "Releasing CRQ\n"); | ||
640 | free_irq(vdev->irq, vhost); | ||
641 | do { | ||
642 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
643 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
644 | |||
645 | vhost->state = IBMVFC_NO_CRQ; | ||
646 | dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
647 | free_page((unsigned long)crq->msgs); | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * ibmvfc_reenable_crq_queue - reenables the CRQ | ||
652 | * @vhost: ibmvfc host struct | ||
653 | * | ||
654 | * Return value: | ||
655 | * 0 on success / other on failure | ||
656 | **/ | ||
657 | static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) | ||
658 | { | ||
659 | int rc; | ||
660 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
661 | |||
662 | /* Re-enable the CRQ */ | ||
663 | do { | ||
664 | rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); | ||
665 | } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
666 | |||
667 | if (rc) | ||
668 | dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc); | ||
669 | |||
670 | return rc; | ||
671 | } | ||
672 | |||
673 | /** | ||
674 | * ibmvfc_reset_crq - resets a crq after a failure | ||
675 | * @vhost: ibmvfc host struct | ||
676 | * | ||
677 | * Return value: | ||
678 | * 0 on success / other on failure | ||
679 | **/ | ||
680 | static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) | ||
681 | { | ||
682 | int rc; | ||
683 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
684 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
685 | |||
686 | /* Close the CRQ */ | ||
687 | do { | ||
688 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
689 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
690 | |||
691 | vhost->state = IBMVFC_NO_CRQ; | ||
692 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
693 | |||
694 | /* Clean out the queue */ | ||
695 | memset(crq->msgs, 0, PAGE_SIZE); | ||
696 | crq->cur = 0; | ||
697 | |||
698 | /* And re-open it again */ | ||
699 | rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, | ||
700 | crq->msg_token, PAGE_SIZE); | ||
701 | |||
702 | if (rc == H_CLOSED) | ||
703 | /* Adapter is good, but other end is not ready */ | ||
704 | dev_warn(vhost->dev, "Partner adapter not ready\n"); | ||
705 | else if (rc != 0) | ||
706 | dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); | ||
707 | |||
708 | return rc; | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * ibmvfc_valid_event - Determines if event is valid. | ||
713 | * @pool: event_pool that contains the event | ||
714 | * @evt: ibmvfc event to be checked for validity | ||
715 | * | ||
716 | * Return value: | ||
717 | * 1 if event is valid / 0 if event is not valid | ||
718 | **/ | ||
719 | static int ibmvfc_valid_event(struct ibmvfc_event_pool *pool, | ||
720 | struct ibmvfc_event *evt) | ||
721 | { | ||
722 | int index = evt - pool->events; | ||
723 | if (index < 0 || index >= pool->size) /* outside of bounds */ | ||
724 | return 0; | ||
725 | if (evt != pool->events + index) /* unaligned */ | ||
726 | return 0; | ||
727 | return 1; | ||
728 | } | ||
729 | |||
730 | /** | ||
731 | * ibmvfc_free_event - Free the specified event | ||
732 | * @evt: ibmvfc_event to be freed | ||
733 | * | ||
734 | **/ | ||
735 | static void ibmvfc_free_event(struct ibmvfc_event *evt) | ||
736 | { | ||
737 | struct ibmvfc_host *vhost = evt->vhost; | ||
738 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
739 | |||
740 | BUG_ON(!ibmvfc_valid_event(pool, evt)); | ||
741 | BUG_ON(atomic_inc_return(&evt->free) != 1); | ||
742 | list_add_tail(&evt->queue, &vhost->free); | ||
743 | } | ||
744 | |||
745 | /** | ||
746 | * ibmvfc_scsi_eh_done - EH done function for queuecommand commands | ||
747 | * @evt: ibmvfc event struct | ||
748 | * | ||
749 | * This function does not setup any error status, that must be done | ||
750 | * before this function gets called. | ||
751 | **/ | ||
752 | static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) | ||
753 | { | ||
754 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
755 | |||
756 | if (cmnd) { | ||
757 | scsi_dma_unmap(cmnd); | ||
758 | cmnd->scsi_done(cmnd); | ||
759 | } | ||
760 | |||
761 | ibmvfc_free_event(evt); | ||
762 | } | ||
763 | |||
764 | /** | ||
765 | * ibmvfc_fail_request - Fail request with specified error code | ||
766 | * @evt: ibmvfc event struct | ||
767 | * @error_code: error code to fail request with | ||
768 | * | ||
769 | * Return value: | ||
770 | * none | ||
771 | **/ | ||
772 | static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code) | ||
773 | { | ||
774 | if (evt->cmnd) { | ||
775 | evt->cmnd->result = (error_code << 16); | ||
776 | evt->done = ibmvfc_scsi_eh_done; | ||
777 | } else | ||
778 | evt->xfer_iu->mad_common.status = IBMVFC_MAD_DRIVER_FAILED; | ||
779 | |||
780 | list_del(&evt->queue); | ||
781 | del_timer(&evt->timer); | ||
782 | ibmvfc_trc_end(evt); | ||
783 | evt->done(evt); | ||
784 | } | ||
785 | |||
786 | /** | ||
787 | * ibmvfc_purge_requests - Our virtual adapter just shut down. Purge any sent requests | ||
788 | * @vhost: ibmvfc host struct | ||
789 | * @error_code: error code to fail requests with | ||
790 | * | ||
791 | * Return value: | ||
792 | * none | ||
793 | **/ | ||
794 | static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) | ||
795 | { | ||
796 | struct ibmvfc_event *evt, *pos; | ||
797 | |||
798 | ibmvfc_dbg(vhost, "Purging all requests\n"); | ||
799 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) | ||
800 | ibmvfc_fail_request(evt, error_code); | ||
801 | } | ||
802 | |||
803 | /** | ||
804 | * __ibmvfc_reset_host - Reset the connection to the server (no locking) | ||
805 | * @vhost: struct ibmvfc host to reset | ||
806 | **/ | ||
807 | static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) | ||
808 | { | ||
809 | int rc; | ||
810 | |||
811 | scsi_block_requests(vhost->host); | ||
812 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
813 | if ((rc = ibmvfc_reset_crq(vhost)) || | ||
814 | (rc = ibmvfc_send_crq_init(vhost)) || | ||
815 | (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { | ||
816 | dev_err(vhost->dev, "Error after reset rc=%d\n", rc); | ||
817 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
818 | } else | ||
819 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * ibmvfc_reset_host - Reset the connection to the server | ||
824 | * @vhost: struct ibmvfc host to reset | ||
825 | **/ | ||
826 | static void ibmvfc_reset_host(struct ibmvfc_host *vhost) | ||
827 | { | ||
828 | unsigned long flags; | ||
829 | |||
830 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
831 | __ibmvfc_reset_host(vhost); | ||
832 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
833 | } | ||
834 | |||
835 | /** | ||
836 | * ibmvfc_retry_host_init - Retry host initialization if allowed | ||
837 | * @vhost: ibmvfc host struct | ||
838 | * | ||
839 | **/ | ||
840 | static void ibmvfc_retry_host_init(struct ibmvfc_host *vhost) | ||
841 | { | ||
842 | if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { | ||
843 | if (++vhost->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
844 | dev_err(vhost->dev, | ||
845 | "Host initialization retries exceeded. Taking adapter offline\n"); | ||
846 | ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); | ||
847 | } else if (vhost->init_retries == IBMVFC_MAX_INIT_RETRIES) | ||
848 | __ibmvfc_reset_host(vhost); | ||
849 | else | ||
850 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
851 | } | ||
852 | |||
853 | wake_up(&vhost->work_wait_q); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * __ibmvfc_find_target - Find the specified scsi_target (no locking) | ||
858 | * @starget: scsi target struct | ||
859 | * | ||
860 | * Return value: | ||
861 | * ibmvfc_target struct / NULL if not found | ||
862 | **/ | ||
863 | static struct ibmvfc_target *__ibmvfc_find_target(struct scsi_target *starget) | ||
864 | { | ||
865 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
866 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
867 | struct ibmvfc_target *tgt; | ||
868 | |||
869 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
870 | if (tgt->target_id == starget->id) | ||
871 | return tgt; | ||
872 | return NULL; | ||
873 | } | ||
874 | |||
875 | /** | ||
876 | * ibmvfc_find_target - Find the specified scsi_target | ||
877 | * @starget: scsi target struct | ||
878 | * | ||
879 | * Return value: | ||
880 | * ibmvfc_target struct / NULL if not found | ||
881 | **/ | ||
882 | static struct ibmvfc_target *ibmvfc_find_target(struct scsi_target *starget) | ||
883 | { | ||
884 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
885 | struct ibmvfc_target *tgt; | ||
886 | unsigned long flags; | ||
887 | |||
888 | spin_lock_irqsave(shost->host_lock, flags); | ||
889 | tgt = __ibmvfc_find_target(starget); | ||
890 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
891 | return tgt; | ||
892 | } | ||
893 | |||
894 | /** | ||
895 | * ibmvfc_get_host_speed - Get host port speed | ||
896 | * @shost: scsi host struct | ||
897 | * | ||
898 | * Return value: | ||
899 | * none | ||
900 | **/ | ||
901 | static void ibmvfc_get_host_speed(struct Scsi_Host *shost) | ||
902 | { | ||
903 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
904 | unsigned long flags; | ||
905 | |||
906 | spin_lock_irqsave(shost->host_lock, flags); | ||
907 | if (vhost->state == IBMVFC_ACTIVE) { | ||
908 | switch (vhost->login_buf->resp.link_speed / 100) { | ||
909 | case 1: | ||
910 | fc_host_speed(shost) = FC_PORTSPEED_1GBIT; | ||
911 | break; | ||
912 | case 2: | ||
913 | fc_host_speed(shost) = FC_PORTSPEED_2GBIT; | ||
914 | break; | ||
915 | case 4: | ||
916 | fc_host_speed(shost) = FC_PORTSPEED_4GBIT; | ||
917 | break; | ||
918 | case 8: | ||
919 | fc_host_speed(shost) = FC_PORTSPEED_8GBIT; | ||
920 | break; | ||
921 | case 10: | ||
922 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; | ||
923 | break; | ||
924 | case 16: | ||
925 | fc_host_speed(shost) = FC_PORTSPEED_16GBIT; | ||
926 | break; | ||
927 | default: | ||
928 | ibmvfc_log(vhost, 3, "Unknown port speed: %ld Gbit\n", | ||
929 | vhost->login_buf->resp.link_speed / 100); | ||
930 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
931 | break; | ||
932 | } | ||
933 | } else | ||
934 | fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; | ||
935 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
936 | } | ||
937 | |||
938 | /** | ||
939 | * ibmvfc_get_host_port_state - Get host port state | ||
940 | * @shost: scsi host struct | ||
941 | * | ||
942 | * Return value: | ||
943 | * none | ||
944 | **/ | ||
945 | static void ibmvfc_get_host_port_state(struct Scsi_Host *shost) | ||
946 | { | ||
947 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
948 | unsigned long flags; | ||
949 | |||
950 | spin_lock_irqsave(shost->host_lock, flags); | ||
951 | switch (vhost->state) { | ||
952 | case IBMVFC_INITIALIZING: | ||
953 | case IBMVFC_ACTIVE: | ||
954 | fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; | ||
955 | break; | ||
956 | case IBMVFC_LINK_DOWN: | ||
957 | fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; | ||
958 | break; | ||
959 | case IBMVFC_LINK_DEAD: | ||
960 | case IBMVFC_HOST_OFFLINE: | ||
961 | fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; | ||
962 | break; | ||
963 | case IBMVFC_HALTED: | ||
964 | fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; | ||
965 | break; | ||
966 | default: | ||
967 | ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); | ||
968 | fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; | ||
969 | break; | ||
970 | } | ||
971 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
972 | } | ||
973 | |||
974 | /** | ||
975 | * ibmvfc_set_rport_dev_loss_tmo - Set rport's device loss timeout | ||
976 | * @rport: rport struct | ||
977 | * @timeout: timeout value | ||
978 | * | ||
979 | * Return value: | ||
980 | * none | ||
981 | **/ | ||
982 | static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) | ||
983 | { | ||
984 | if (timeout) | ||
985 | rport->dev_loss_tmo = timeout; | ||
986 | else | ||
987 | rport->dev_loss_tmo = 1; | ||
988 | } | ||
989 | |||
990 | /** | ||
991 | * ibmvfc_get_starget_node_name - Get SCSI target's node name | ||
992 | * @starget: scsi target struct | ||
993 | * | ||
994 | * Return value: | ||
995 | * none | ||
996 | **/ | ||
997 | static void ibmvfc_get_starget_node_name(struct scsi_target *starget) | ||
998 | { | ||
999 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1000 | fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; | ||
1001 | } | ||
1002 | |||
1003 | /** | ||
1004 | * ibmvfc_get_starget_port_name - Get SCSI target's port name | ||
1005 | * @starget: scsi target struct | ||
1006 | * | ||
1007 | * Return value: | ||
1008 | * none | ||
1009 | **/ | ||
1010 | static void ibmvfc_get_starget_port_name(struct scsi_target *starget) | ||
1011 | { | ||
1012 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1013 | fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; | ||
1014 | } | ||
1015 | |||
1016 | /** | ||
1017 | * ibmvfc_get_starget_port_id - Get SCSI target's port ID | ||
1018 | * @starget: scsi target struct | ||
1019 | * | ||
1020 | * Return value: | ||
1021 | * none | ||
1022 | **/ | ||
1023 | static void ibmvfc_get_starget_port_id(struct scsi_target *starget) | ||
1024 | { | ||
1025 | struct ibmvfc_target *tgt = ibmvfc_find_target(starget); | ||
1026 | fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; | ||
1027 | } | ||
1028 | |||
1029 | /** | ||
1030 | * ibmvfc_wait_while_resetting - Wait while the host resets | ||
1031 | * @vhost: ibmvfc host struct | ||
1032 | * | ||
1033 | * Return value: | ||
1034 | * 0 on success / other on failure | ||
1035 | **/ | ||
1036 | static int ibmvfc_wait_while_resetting(struct ibmvfc_host *vhost) | ||
1037 | { | ||
1038 | long timeout = wait_event_timeout(vhost->init_wait_q, | ||
1039 | (vhost->state == IBMVFC_ACTIVE || | ||
1040 | vhost->state == IBMVFC_HOST_OFFLINE || | ||
1041 | vhost->state == IBMVFC_LINK_DEAD), | ||
1042 | (init_timeout * HZ)); | ||
1043 | |||
1044 | return timeout ? 0 : -EIO; | ||
1045 | } | ||
1046 | |||
1047 | /** | ||
1048 | * ibmvfc_issue_fc_host_lip - Re-initiate link initialization | ||
1049 | * @shost: scsi host struct | ||
1050 | * | ||
1051 | * Return value: | ||
1052 | * 0 on success / other on failure | ||
1053 | **/ | ||
1054 | static int ibmvfc_issue_fc_host_lip(struct Scsi_Host *shost) | ||
1055 | { | ||
1056 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
1057 | |||
1058 | dev_err(vhost->dev, "Initiating host LIP. Resetting connection\n"); | ||
1059 | ibmvfc_reset_host(vhost); | ||
1060 | return ibmvfc_wait_while_resetting(vhost); | ||
1061 | } | ||
1062 | |||
1063 | /** | ||
1064 | * ibmvfc_gather_partition_info - Gather info about the LPAR | ||
1065 | * | ||
1066 | * Return value: | ||
1067 | * none | ||
1068 | **/ | ||
1069 | static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) | ||
1070 | { | ||
1071 | struct device_node *rootdn; | ||
1072 | const char *name; | ||
1073 | const unsigned int *num; | ||
1074 | |||
1075 | rootdn = of_find_node_by_path("/"); | ||
1076 | if (!rootdn) | ||
1077 | return; | ||
1078 | |||
1079 | name = of_get_property(rootdn, "ibm,partition-name", NULL); | ||
1080 | if (name) | ||
1081 | strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); | ||
1082 | num = of_get_property(rootdn, "ibm,partition-no", NULL); | ||
1083 | if (num) | ||
1084 | vhost->partition_number = *num; | ||
1085 | of_node_put(rootdn); | ||
1086 | } | ||
1087 | |||
1088 | /** | ||
1089 | * ibmvfc_set_login_info - Setup info for NPIV login | ||
1090 | * @vhost: ibmvfc host struct | ||
1091 | * | ||
1092 | * Return value: | ||
1093 | * none | ||
1094 | **/ | ||
1095 | static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) | ||
1096 | { | ||
1097 | struct ibmvfc_npiv_login *login_info = &vhost->login_info; | ||
1098 | struct device_node *of_node = vhost->dev->archdata.of_node; | ||
1099 | const char *location; | ||
1100 | |||
1101 | memset(login_info, 0, sizeof(*login_info)); | ||
1102 | |||
1103 | login_info->ostype = IBMVFC_OS_LINUX; | ||
1104 | login_info->max_dma_len = IBMVFC_MAX_SECTORS << 9; | ||
1105 | login_info->max_payload = sizeof(struct ibmvfc_fcp_cmd_iu); | ||
1106 | login_info->max_response = sizeof(struct ibmvfc_fcp_rsp); | ||
1107 | login_info->partition_num = vhost->partition_number; | ||
1108 | login_info->vfc_frame_version = 1; | ||
1109 | login_info->fcp_version = 3; | ||
1110 | if (vhost->client_migrated) | ||
1111 | login_info->flags = IBMVFC_CLIENT_MIGRATED; | ||
1112 | |||
1113 | login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; | ||
1114 | login_info->capabilities = IBMVFC_CAN_MIGRATE; | ||
1115 | login_info->async.va = vhost->async_crq.msg_token; | ||
1116 | login_info->async.len = vhost->async_crq.size; | ||
1117 | strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); | ||
1118 | strncpy(login_info->device_name, | ||
1119 | vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); | ||
1120 | |||
1121 | location = of_get_property(of_node, "ibm,loc-code", NULL); | ||
1122 | location = location ? location : vhost->dev->bus_id; | ||
1123 | strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); | ||
1124 | } | ||
1125 | |||
1126 | /** | ||
1127 | * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host | ||
1128 | * @vhost: ibmvfc host who owns the event pool | ||
1129 | * | ||
1130 | * Returns zero on success. | ||
1131 | **/ | ||
1132 | static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost) | ||
1133 | { | ||
1134 | int i; | ||
1135 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
1136 | |||
1137 | ENTER; | ||
1138 | pool->size = max_requests + IBMVFC_NUM_INTERNAL_REQ; | ||
1139 | pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); | ||
1140 | if (!pool->events) | ||
1141 | return -ENOMEM; | ||
1142 | |||
1143 | pool->iu_storage = dma_alloc_coherent(vhost->dev, | ||
1144 | pool->size * sizeof(*pool->iu_storage), | ||
1145 | &pool->iu_token, 0); | ||
1146 | |||
1147 | if (!pool->iu_storage) { | ||
1148 | kfree(pool->events); | ||
1149 | return -ENOMEM; | ||
1150 | } | ||
1151 | |||
1152 | for (i = 0; i < pool->size; ++i) { | ||
1153 | struct ibmvfc_event *evt = &pool->events[i]; | ||
1154 | atomic_set(&evt->free, 1); | ||
1155 | evt->crq.valid = 0x80; | ||
1156 | evt->crq.ioba = pool->iu_token + (sizeof(*evt->xfer_iu) * i); | ||
1157 | evt->xfer_iu = pool->iu_storage + i; | ||
1158 | evt->vhost = vhost; | ||
1159 | evt->ext_list = NULL; | ||
1160 | list_add_tail(&evt->queue, &vhost->free); | ||
1161 | } | ||
1162 | |||
1163 | LEAVE; | ||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | /** | ||
1168 | * ibmvfc_free_event_pool - Frees memory of the event pool of a host | ||
1169 | * @vhost: ibmvfc host who owns the event pool | ||
1170 | * | ||
1171 | **/ | ||
1172 | static void ibmvfc_free_event_pool(struct ibmvfc_host *vhost) | ||
1173 | { | ||
1174 | int i; | ||
1175 | struct ibmvfc_event_pool *pool = &vhost->pool; | ||
1176 | |||
1177 | ENTER; | ||
1178 | for (i = 0; i < pool->size; ++i) { | ||
1179 | list_del(&pool->events[i].queue); | ||
1180 | BUG_ON(atomic_read(&pool->events[i].free) != 1); | ||
1181 | if (pool->events[i].ext_list) | ||
1182 | dma_pool_free(vhost->sg_pool, | ||
1183 | pool->events[i].ext_list, | ||
1184 | pool->events[i].ext_list_token); | ||
1185 | } | ||
1186 | |||
1187 | kfree(pool->events); | ||
1188 | dma_free_coherent(vhost->dev, | ||
1189 | pool->size * sizeof(*pool->iu_storage), | ||
1190 | pool->iu_storage, pool->iu_token); | ||
1191 | LEAVE; | ||
1192 | } | ||
1193 | |||
1194 | /** | ||
1195 | * ibmvfc_get_event - Gets the next free event in pool | ||
1196 | * @vhost: ibmvfc host struct | ||
1197 | * | ||
1198 | * Returns a free event from the pool. | ||
1199 | **/ | ||
1200 | static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_host *vhost) | ||
1201 | { | ||
1202 | struct ibmvfc_event *evt; | ||
1203 | |||
1204 | BUG_ON(list_empty(&vhost->free)); | ||
1205 | evt = list_entry(vhost->free.next, struct ibmvfc_event, queue); | ||
1206 | atomic_set(&evt->free, 0); | ||
1207 | list_del(&evt->queue); | ||
1208 | return evt; | ||
1209 | } | ||
1210 | |||
1211 | /** | ||
1212 | * ibmvfc_init_event - Initialize fields in an event struct that are always | ||
1213 | * required. | ||
1214 | * @evt: The event | ||
1215 | * @done: Routine to call when the event is responded to | ||
1216 | * @format: SRP or MAD format | ||
1217 | **/ | ||
1218 | static void ibmvfc_init_event(struct ibmvfc_event *evt, | ||
1219 | void (*done) (struct ibmvfc_event *), u8 format) | ||
1220 | { | ||
1221 | evt->cmnd = NULL; | ||
1222 | evt->sync_iu = NULL; | ||
1223 | evt->crq.format = format; | ||
1224 | evt->done = done; | ||
1225 | } | ||
1226 | |||
1227 | /** | ||
1228 | * ibmvfc_map_sg_list - Initialize scatterlist | ||
1229 | * @scmd: scsi command struct | ||
1230 | * @nseg: number of scatterlist segments | ||
1231 | * @md: memory descriptor list to initialize | ||
1232 | **/ | ||
1233 | static void ibmvfc_map_sg_list(struct scsi_cmnd *scmd, int nseg, | ||
1234 | struct srp_direct_buf *md) | ||
1235 | { | ||
1236 | int i; | ||
1237 | struct scatterlist *sg; | ||
1238 | |||
1239 | scsi_for_each_sg(scmd, sg, nseg, i) { | ||
1240 | md[i].va = sg_dma_address(sg); | ||
1241 | md[i].len = sg_dma_len(sg); | ||
1242 | md[i].key = 0; | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | /** | ||
1247 | * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes decriptor fields | ||
1248 | * @scmd: Scsi_Cmnd with the scatterlist | ||
1249 | * @evt: ibmvfc event struct | ||
1250 | * @vfc_cmd: vfc_cmd that contains the memory descriptor | ||
1251 | * @dev: device for which to map dma memory | ||
1252 | * | ||
1253 | * Returns: | ||
1254 | * 0 on success / non-zero on failure | ||
1255 | **/ | ||
1256 | static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, | ||
1257 | struct ibmvfc_event *evt, | ||
1258 | struct ibmvfc_cmd *vfc_cmd, struct device *dev) | ||
1259 | { | ||
1260 | |||
1261 | int sg_mapped; | ||
1262 | struct srp_direct_buf *data = &vfc_cmd->ioba; | ||
1263 | struct ibmvfc_host *vhost = dev_get_drvdata(dev); | ||
1264 | |||
1265 | sg_mapped = scsi_dma_map(scmd); | ||
1266 | if (!sg_mapped) { | ||
1267 | vfc_cmd->flags |= IBMVFC_NO_MEM_DESC; | ||
1268 | return 0; | ||
1269 | } else if (unlikely(sg_mapped < 0)) { | ||
1270 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1271 | scmd_printk(KERN_ERR, scmd, "Failed to map DMA buffer for command\n"); | ||
1272 | return sg_mapped; | ||
1273 | } | ||
1274 | |||
1275 | if (scmd->sc_data_direction == DMA_TO_DEVICE) { | ||
1276 | vfc_cmd->flags |= IBMVFC_WRITE; | ||
1277 | vfc_cmd->iu.add_cdb_len |= IBMVFC_WRDATA; | ||
1278 | } else { | ||
1279 | vfc_cmd->flags |= IBMVFC_READ; | ||
1280 | vfc_cmd->iu.add_cdb_len |= IBMVFC_RDDATA; | ||
1281 | } | ||
1282 | |||
1283 | if (sg_mapped == 1) { | ||
1284 | ibmvfc_map_sg_list(scmd, sg_mapped, data); | ||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | vfc_cmd->flags |= IBMVFC_SCATTERLIST; | ||
1289 | |||
1290 | if (!evt->ext_list) { | ||
1291 | evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC, | ||
1292 | &evt->ext_list_token); | ||
1293 | |||
1294 | if (!evt->ext_list) { | ||
1295 | scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); | ||
1296 | return -ENOMEM; | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | ibmvfc_map_sg_list(scmd, sg_mapped, evt->ext_list); | ||
1301 | |||
1302 | data->va = evt->ext_list_token; | ||
1303 | data->len = sg_mapped * sizeof(struct srp_direct_buf); | ||
1304 | data->key = 0; | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | /** | ||
1309 | * ibmvfc_timeout - Internal command timeout handler | ||
1310 | * @evt: struct ibmvfc_event that timed out | ||
1311 | * | ||
1312 | * Called when an internally generated command times out | ||
1313 | **/ | ||
1314 | static void ibmvfc_timeout(struct ibmvfc_event *evt) | ||
1315 | { | ||
1316 | struct ibmvfc_host *vhost = evt->vhost; | ||
1317 | dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); | ||
1318 | ibmvfc_reset_host(vhost); | ||
1319 | } | ||
1320 | |||
1321 | /** | ||
1322 | * ibmvfc_send_event - Transforms event to u64 array and calls send_crq() | ||
1323 | * @evt: event to be sent | ||
1324 | * @vhost: ibmvfc host struct | ||
1325 | * @timeout: timeout in seconds - 0 means do not time command | ||
1326 | * | ||
1327 | * Returns the value returned from ibmvfc_send_crq(). (Zero for success) | ||
1328 | **/ | ||
1329 | static int ibmvfc_send_event(struct ibmvfc_event *evt, | ||
1330 | struct ibmvfc_host *vhost, unsigned long timeout) | ||
1331 | { | ||
1332 | u64 *crq_as_u64 = (u64 *) &evt->crq; | ||
1333 | int rc; | ||
1334 | |||
1335 | /* Copy the IU into the transfer area */ | ||
1336 | *evt->xfer_iu = evt->iu; | ||
1337 | if (evt->crq.format == IBMVFC_CMD_FORMAT) | ||
1338 | evt->xfer_iu->cmd.tag = (u64)evt; | ||
1339 | else if (evt->crq.format == IBMVFC_MAD_FORMAT) | ||
1340 | evt->xfer_iu->mad_common.tag = (u64)evt; | ||
1341 | else | ||
1342 | BUG(); | ||
1343 | |||
1344 | list_add_tail(&evt->queue, &vhost->sent); | ||
1345 | init_timer(&evt->timer); | ||
1346 | |||
1347 | if (timeout) { | ||
1348 | evt->timer.data = (unsigned long) evt; | ||
1349 | evt->timer.expires = jiffies + (timeout * HZ); | ||
1350 | evt->timer.function = (void (*)(unsigned long))ibmvfc_timeout; | ||
1351 | add_timer(&evt->timer); | ||
1352 | } | ||
1353 | |||
1354 | if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { | ||
1355 | list_del(&evt->queue); | ||
1356 | del_timer(&evt->timer); | ||
1357 | |||
1358 | /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. | ||
1359 | * Firmware will send a CRQ with a transport event (0xFF) to | ||
1360 | * tell this client what has happened to the transport. This | ||
1361 | * will be handled in ibmvfc_handle_crq() | ||
1362 | */ | ||
1363 | if (rc == H_CLOSED) { | ||
1364 | if (printk_ratelimit()) | ||
1365 | dev_warn(vhost->dev, "Send warning. Receive queue closed, will retry.\n"); | ||
1366 | if (evt->cmnd) | ||
1367 | scsi_dma_unmap(evt->cmnd); | ||
1368 | ibmvfc_free_event(evt); | ||
1369 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1370 | } | ||
1371 | |||
1372 | dev_err(vhost->dev, "Send error (rc=%d)\n", rc); | ||
1373 | if (evt->cmnd) { | ||
1374 | evt->cmnd->result = DID_ERROR << 16; | ||
1375 | evt->done = ibmvfc_scsi_eh_done; | ||
1376 | } else | ||
1377 | evt->xfer_iu->mad_common.status = IBMVFC_MAD_CRQ_ERROR; | ||
1378 | |||
1379 | evt->done(evt); | ||
1380 | } else | ||
1381 | ibmvfc_trc_start(evt); | ||
1382 | |||
1383 | return 0; | ||
1384 | } | ||
1385 | |||
1386 | /** | ||
1387 | * ibmvfc_log_error - Log an error for the failed command if appropriate | ||
1388 | * @evt: ibmvfc event to log | ||
1389 | * | ||
1390 | **/ | ||
1391 | static void ibmvfc_log_error(struct ibmvfc_event *evt) | ||
1392 | { | ||
1393 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
1394 | struct ibmvfc_host *vhost = evt->vhost; | ||
1395 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
1396 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
1397 | const char *err = unknown_error; | ||
1398 | int index = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); | ||
1399 | int logerr = 0; | ||
1400 | int rsp_code = 0; | ||
1401 | |||
1402 | if (index >= 0) { | ||
1403 | logerr = cmd_status[index].log; | ||
1404 | err = cmd_status[index].name; | ||
1405 | } | ||
1406 | |||
1407 | if (!logerr && (vhost->log_level <= IBMVFC_DEFAULT_LOG_LEVEL)) | ||
1408 | return; | ||
1409 | |||
1410 | if (rsp->flags & FCP_RSP_LEN_VALID) | ||
1411 | rsp_code = rsp->data.info.rsp_code; | ||
1412 | |||
1413 | scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) " | ||
1414 | "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n", | ||
1415 | cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error, | ||
1416 | rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); | ||
1417 | } | ||
1418 | |||
1419 | /** | ||
1420 | * ibmvfc_scsi_done - Handle responses from commands | ||
1421 | * @evt: ibmvfc event to be handled | ||
1422 | * | ||
1423 | * Used as a callback when sending scsi cmds. | ||
1424 | **/ | ||
1425 | static void ibmvfc_scsi_done(struct ibmvfc_event *evt) | ||
1426 | { | ||
1427 | struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; | ||
1428 | struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; | ||
1429 | struct scsi_cmnd *cmnd = evt->cmnd; | ||
1430 | int rsp_len = 0; | ||
1431 | int sense_len = rsp->fcp_sense_len; | ||
1432 | |||
1433 | if (cmnd) { | ||
1434 | if (vfc_cmd->response_flags & IBMVFC_ADAPTER_RESID_VALID) | ||
1435 | scsi_set_resid(cmnd, vfc_cmd->adapter_resid); | ||
1436 | else if (rsp->flags & FCP_RESID_UNDER) | ||
1437 | scsi_set_resid(cmnd, rsp->fcp_resid); | ||
1438 | else | ||
1439 | scsi_set_resid(cmnd, 0); | ||
1440 | |||
1441 | if (vfc_cmd->status) { | ||
1442 | cmnd->result = ibmvfc_get_err_result(vfc_cmd); | ||
1443 | |||
1444 | if (rsp->flags & FCP_RSP_LEN_VALID) | ||
1445 | rsp_len = rsp->fcp_rsp_len; | ||
1446 | if ((sense_len + rsp_len) > SCSI_SENSE_BUFFERSIZE) | ||
1447 | sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; | ||
1448 | if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len) | ||
1449 | memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); | ||
1450 | |||
1451 | ibmvfc_log_error(evt); | ||
1452 | } | ||
1453 | |||
1454 | if (!cmnd->result && | ||
1455 | (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow)) | ||
1456 | cmnd->result = (DID_ERROR << 16); | ||
1457 | |||
1458 | scsi_dma_unmap(cmnd); | ||
1459 | cmnd->scsi_done(cmnd); | ||
1460 | } | ||
1461 | |||
1462 | ibmvfc_free_event(evt); | ||
1463 | } | ||
1464 | |||
1465 | /** | ||
1466 | * ibmvfc_host_chkready - Check if the host can accept commands | ||
1467 | * @vhost: struct ibmvfc host | ||
1468 | * | ||
1469 | * Returns: | ||
1470 | * 1 if host can accept command / 0 if not | ||
1471 | **/ | ||
1472 | static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost) | ||
1473 | { | ||
1474 | int result = 0; | ||
1475 | |||
1476 | switch (vhost->state) { | ||
1477 | case IBMVFC_LINK_DEAD: | ||
1478 | case IBMVFC_HOST_OFFLINE: | ||
1479 | result = DID_NO_CONNECT << 16; | ||
1480 | break; | ||
1481 | case IBMVFC_NO_CRQ: | ||
1482 | case IBMVFC_INITIALIZING: | ||
1483 | case IBMVFC_HALTED: | ||
1484 | case IBMVFC_LINK_DOWN: | ||
1485 | result = DID_REQUEUE << 16; | ||
1486 | break; | ||
1487 | case IBMVFC_ACTIVE: | ||
1488 | result = 0; | ||
1489 | break; | ||
1490 | }; | ||
1491 | |||
1492 | return result; | ||
1493 | } | ||
1494 | |||
1495 | /** | ||
1496 | * ibmvfc_queuecommand - The queuecommand function of the scsi template | ||
1497 | * @cmnd: struct scsi_cmnd to be executed | ||
1498 | * @done: Callback function to be called when cmnd is completed | ||
1499 | * | ||
1500 | * Returns: | ||
1501 | * 0 on success / other on failure | ||
1502 | **/ | ||
1503 | static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd, | ||
1504 | void (*done) (struct scsi_cmnd *)) | ||
1505 | { | ||
1506 | struct ibmvfc_host *vhost = shost_priv(cmnd->device->host); | ||
1507 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | ||
1508 | struct ibmvfc_cmd *vfc_cmd; | ||
1509 | struct ibmvfc_event *evt; | ||
1510 | u8 tag[2]; | ||
1511 | int rc; | ||
1512 | |||
1513 | if (unlikely((rc = fc_remote_port_chkready(rport))) || | ||
1514 | unlikely((rc = ibmvfc_host_chkready(vhost)))) { | ||
1515 | cmnd->result = rc; | ||
1516 | done(cmnd); | ||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | cmnd->result = (DID_OK << 16); | ||
1521 | evt = ibmvfc_get_event(vhost); | ||
1522 | ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); | ||
1523 | evt->cmnd = cmnd; | ||
1524 | cmnd->scsi_done = done; | ||
1525 | vfc_cmd = &evt->iu.cmd; | ||
1526 | memset(vfc_cmd, 0, sizeof(*vfc_cmd)); | ||
1527 | vfc_cmd->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1528 | vfc_cmd->resp.len = sizeof(vfc_cmd->rsp); | ||
1529 | vfc_cmd->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1530 | vfc_cmd->payload_len = sizeof(vfc_cmd->iu); | ||
1531 | vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); | ||
1532 | vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; | ||
1533 | vfc_cmd->tgt_scsi_id = rport->port_id; | ||
1534 | if ((rport->supported_classes & FC_COS_CLASS3) && | ||
1535 | (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3)) | ||
1536 | vfc_cmd->flags = IBMVFC_CLASS_3_ERR; | ||
1537 | vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); | ||
1538 | int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); | ||
1539 | memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); | ||
1540 | |||
1541 | if (scsi_populate_tag_msg(cmnd, tag)) { | ||
1542 | vfc_cmd->task_tag = tag[1]; | ||
1543 | switch (tag[0]) { | ||
1544 | case MSG_SIMPLE_TAG: | ||
1545 | vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK; | ||
1546 | break; | ||
1547 | case MSG_HEAD_TAG: | ||
1548 | vfc_cmd->iu.pri_task_attr = IBMVFC_HEAD_OF_QUEUE; | ||
1549 | break; | ||
1550 | case MSG_ORDERED_TAG: | ||
1551 | vfc_cmd->iu.pri_task_attr = IBMVFC_ORDERED_TASK; | ||
1552 | break; | ||
1553 | }; | ||
1554 | } | ||
1555 | |||
1556 | if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev)))) | ||
1557 | return ibmvfc_send_event(evt, vhost, 0); | ||
1558 | |||
1559 | ibmvfc_free_event(evt); | ||
1560 | if (rc == -ENOMEM) | ||
1561 | return SCSI_MLQUEUE_HOST_BUSY; | ||
1562 | |||
1563 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1564 | scmd_printk(KERN_ERR, cmnd, | ||
1565 | "Failed to map DMA buffer for command. rc=%d\n", rc); | ||
1566 | |||
1567 | cmnd->result = DID_ERROR << 16; | ||
1568 | done(cmnd); | ||
1569 | return 0; | ||
1570 | } | ||
1571 | |||
1572 | /** | ||
1573 | * ibmvfc_sync_completion - Signal that a synchronous command has completed | ||
1574 | * @evt: ibmvfc event struct | ||
1575 | * | ||
1576 | **/ | ||
1577 | static void ibmvfc_sync_completion(struct ibmvfc_event *evt) | ||
1578 | { | ||
1579 | /* copy the response back */ | ||
1580 | if (evt->sync_iu) | ||
1581 | *evt->sync_iu = *evt->xfer_iu; | ||
1582 | |||
1583 | complete(&evt->comp); | ||
1584 | } | ||
1585 | |||
1586 | /** | ||
1587 | * ibmvfc_reset_device - Reset the device with the specified reset type | ||
1588 | * @sdev: scsi device to reset | ||
1589 | * @type: reset type | ||
1590 | * @desc: reset type description for log messages | ||
1591 | * | ||
1592 | * Returns: | ||
1593 | * 0 on success / other on failure | ||
1594 | **/ | ||
1595 | static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) | ||
1596 | { | ||
1597 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1598 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1599 | struct ibmvfc_cmd *tmf; | ||
1600 | struct ibmvfc_event *evt; | ||
1601 | union ibmvfc_iu rsp_iu; | ||
1602 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | ||
1603 | int rsp_rc = -EBUSY; | ||
1604 | unsigned long flags; | ||
1605 | int rsp_code = 0; | ||
1606 | |||
1607 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1608 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1609 | evt = ibmvfc_get_event(vhost); | ||
1610 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); | ||
1611 | |||
1612 | tmf = &evt->iu.cmd; | ||
1613 | memset(tmf, 0, sizeof(*tmf)); | ||
1614 | tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1615 | tmf->resp.len = sizeof(tmf->rsp); | ||
1616 | tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1617 | tmf->payload_len = sizeof(tmf->iu); | ||
1618 | tmf->resp_len = sizeof(tmf->rsp); | ||
1619 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1620 | tmf->tgt_scsi_id = rport->port_id; | ||
1621 | int_to_scsilun(sdev->lun, &tmf->iu.lun); | ||
1622 | tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); | ||
1623 | tmf->iu.tmf_flags = type; | ||
1624 | evt->sync_iu = &rsp_iu; | ||
1625 | |||
1626 | init_completion(&evt->comp); | ||
1627 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1628 | } | ||
1629 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1630 | |||
1631 | if (rsp_rc != 0) { | ||
1632 | sdev_printk(KERN_ERR, sdev, "Failed to send %s reset event. rc=%d\n", | ||
1633 | desc, rsp_rc); | ||
1634 | return -EIO; | ||
1635 | } | ||
1636 | |||
1637 | sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc); | ||
1638 | wait_for_completion(&evt->comp); | ||
1639 | |||
1640 | if (rsp_iu.cmd.status) { | ||
1641 | if (fc_rsp->flags & FCP_RSP_LEN_VALID) | ||
1642 | rsp_code = fc_rsp->data.info.rsp_code; | ||
1643 | |||
1644 | sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) " | ||
1645 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", | ||
1646 | desc, ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), | ||
1647 | rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, | ||
1648 | fc_rsp->scsi_status); | ||
1649 | rsp_rc = -EIO; | ||
1650 | } else | ||
1651 | sdev_printk(KERN_INFO, sdev, "%s reset successful\n", desc); | ||
1652 | |||
1653 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1654 | ibmvfc_free_event(evt); | ||
1655 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1656 | return rsp_rc; | ||
1657 | } | ||
1658 | |||
1659 | /** | ||
1660 | * ibmvfc_abort_task_set - Abort outstanding commands to the device | ||
1661 | * @sdev: scsi device to abort commands | ||
1662 | * | ||
1663 | * This sends an Abort Task Set to the VIOS for the specified device. This does | ||
1664 | * NOT send any cancel to the VIOS. That must be done separately. | ||
1665 | * | ||
1666 | * Returns: | ||
1667 | * 0 on success / other on failure | ||
1668 | **/ | ||
1669 | static int ibmvfc_abort_task_set(struct scsi_device *sdev) | ||
1670 | { | ||
1671 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1672 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1673 | struct ibmvfc_cmd *tmf; | ||
1674 | struct ibmvfc_event *evt, *found_evt; | ||
1675 | union ibmvfc_iu rsp_iu; | ||
1676 | struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; | ||
1677 | int rsp_rc = -EBUSY; | ||
1678 | unsigned long flags; | ||
1679 | int rsp_code = 0; | ||
1680 | |||
1681 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1682 | found_evt = NULL; | ||
1683 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1684 | if (evt->cmnd && evt->cmnd->device == sdev) { | ||
1685 | found_evt = evt; | ||
1686 | break; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if (!found_evt) { | ||
1691 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1692 | sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); | ||
1693 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1694 | return 0; | ||
1695 | } | ||
1696 | |||
1697 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1698 | evt = ibmvfc_get_event(vhost); | ||
1699 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); | ||
1700 | |||
1701 | tmf = &evt->iu.cmd; | ||
1702 | memset(tmf, 0, sizeof(*tmf)); | ||
1703 | tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); | ||
1704 | tmf->resp.len = sizeof(tmf->rsp); | ||
1705 | tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; | ||
1706 | tmf->payload_len = sizeof(tmf->iu); | ||
1707 | tmf->resp_len = sizeof(tmf->rsp); | ||
1708 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1709 | tmf->tgt_scsi_id = rport->port_id; | ||
1710 | int_to_scsilun(sdev->lun, &tmf->iu.lun); | ||
1711 | tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); | ||
1712 | tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; | ||
1713 | evt->sync_iu = &rsp_iu; | ||
1714 | |||
1715 | init_completion(&evt->comp); | ||
1716 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1717 | } | ||
1718 | |||
1719 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1720 | |||
1721 | if (rsp_rc != 0) { | ||
1722 | sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); | ||
1723 | return -EIO; | ||
1724 | } | ||
1725 | |||
1726 | sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); | ||
1727 | wait_for_completion(&evt->comp); | ||
1728 | |||
1729 | if (rsp_iu.cmd.status) { | ||
1730 | if (fc_rsp->flags & FCP_RSP_LEN_VALID) | ||
1731 | rsp_code = fc_rsp->data.info.rsp_code; | ||
1732 | |||
1733 | sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " | ||
1734 | "flags: %x fcp_rsp: %x, scsi_status: %x\n", | ||
1735 | ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), | ||
1736 | rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, | ||
1737 | fc_rsp->scsi_status); | ||
1738 | rsp_rc = -EIO; | ||
1739 | } else | ||
1740 | sdev_printk(KERN_INFO, sdev, "Abort successful\n"); | ||
1741 | |||
1742 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1743 | ibmvfc_free_event(evt); | ||
1744 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1745 | return rsp_rc; | ||
1746 | } | ||
1747 | |||
1748 | /** | ||
1749 | * ibmvfc_cancel_all - Cancel all outstanding commands to the device | ||
1750 | * @sdev: scsi device to cancel commands | ||
1751 | * @type: type of error recovery being performed | ||
1752 | * | ||
1753 | * This sends a cancel to the VIOS for the specified device. This does | ||
1754 | * NOT send any abort to the actual device. That must be done separately. | ||
1755 | * | ||
1756 | * Returns: | ||
1757 | * 0 on success / other on failure | ||
1758 | **/ | ||
1759 | static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) | ||
1760 | { | ||
1761 | struct ibmvfc_host *vhost = shost_priv(sdev->host); | ||
1762 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
1763 | struct ibmvfc_tmf *tmf; | ||
1764 | struct ibmvfc_event *evt, *found_evt; | ||
1765 | union ibmvfc_iu rsp; | ||
1766 | int rsp_rc = -EBUSY; | ||
1767 | unsigned long flags; | ||
1768 | u16 status; | ||
1769 | |||
1770 | ENTER; | ||
1771 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1772 | found_evt = NULL; | ||
1773 | list_for_each_entry(evt, &vhost->sent, queue) { | ||
1774 | if (evt->cmnd && evt->cmnd->device == sdev) { | ||
1775 | found_evt = evt; | ||
1776 | break; | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | if (!found_evt) { | ||
1781 | if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) | ||
1782 | sdev_printk(KERN_INFO, sdev, "No events found to cancel\n"); | ||
1783 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | if (vhost->state == IBMVFC_ACTIVE) { | ||
1788 | evt = ibmvfc_get_event(vhost); | ||
1789 | ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); | ||
1790 | |||
1791 | tmf = &evt->iu.tmf; | ||
1792 | memset(tmf, 0, sizeof(*tmf)); | ||
1793 | tmf->common.version = 1; | ||
1794 | tmf->common.opcode = IBMVFC_TMF_MAD; | ||
1795 | tmf->common.length = sizeof(*tmf); | ||
1796 | tmf->scsi_id = rport->port_id; | ||
1797 | int_to_scsilun(sdev->lun, &tmf->lun); | ||
1798 | tmf->flags = (type | IBMVFC_TMF_LUA_VALID); | ||
1799 | tmf->cancel_key = (unsigned long)sdev->hostdata; | ||
1800 | tmf->my_cancel_key = (IBMVFC_TMF_CANCEL_KEY | (unsigned long)sdev->hostdata); | ||
1801 | |||
1802 | evt->sync_iu = &rsp; | ||
1803 | init_completion(&evt->comp); | ||
1804 | rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); | ||
1805 | } | ||
1806 | |||
1807 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1808 | |||
1809 | if (rsp_rc != 0) { | ||
1810 | sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc); | ||
1811 | return -EIO; | ||
1812 | } | ||
1813 | |||
1814 | sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n"); | ||
1815 | |||
1816 | wait_for_completion(&evt->comp); | ||
1817 | status = rsp.mad_common.status; | ||
1818 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1819 | ibmvfc_free_event(evt); | ||
1820 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1821 | |||
1822 | if (status != IBMVFC_MAD_SUCCESS) { | ||
1823 | sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status); | ||
1824 | return -EIO; | ||
1825 | } | ||
1826 | |||
1827 | sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n"); | ||
1828 | return 0; | ||
1829 | } | ||
1830 | |||
1831 | /** | ||
1832 | * ibmvfc_eh_abort_handler - Abort a command | ||
1833 | * @cmd: scsi command to abort | ||
1834 | * | ||
1835 | * Returns: | ||
1836 | * SUCCESS / FAILED | ||
1837 | **/ | ||
1838 | static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) | ||
1839 | { | ||
1840 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1841 | struct ibmvfc_event *evt, *pos; | ||
1842 | int cancel_rc, abort_rc; | ||
1843 | unsigned long flags; | ||
1844 | |||
1845 | ENTER; | ||
1846 | ibmvfc_wait_while_resetting(vhost); | ||
1847 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_ABORT_TASK_SET); | ||
1848 | abort_rc = ibmvfc_abort_task_set(cmd->device); | ||
1849 | |||
1850 | if (!cancel_rc && !abort_rc) { | ||
1851 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1852 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1853 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1854 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1855 | } | ||
1856 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1857 | LEAVE; | ||
1858 | return SUCCESS; | ||
1859 | } | ||
1860 | |||
1861 | LEAVE; | ||
1862 | return FAILED; | ||
1863 | } | ||
1864 | |||
1865 | /** | ||
1866 | * ibmvfc_eh_device_reset_handler - Reset a single LUN | ||
1867 | * @cmd: scsi command struct | ||
1868 | * | ||
1869 | * Returns: | ||
1870 | * SUCCESS / FAILED | ||
1871 | **/ | ||
1872 | static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) | ||
1873 | { | ||
1874 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1875 | struct ibmvfc_event *evt, *pos; | ||
1876 | int cancel_rc, reset_rc; | ||
1877 | unsigned long flags; | ||
1878 | |||
1879 | ENTER; | ||
1880 | ibmvfc_wait_while_resetting(vhost); | ||
1881 | cancel_rc = ibmvfc_cancel_all(cmd->device, IBMVFC_TMF_LUN_RESET); | ||
1882 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_LUN_RESET, "LUN"); | ||
1883 | |||
1884 | if (!cancel_rc && !reset_rc) { | ||
1885 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1886 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1887 | if (evt->cmnd && evt->cmnd->device == cmd->device) | ||
1888 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1889 | } | ||
1890 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1891 | LEAVE; | ||
1892 | return SUCCESS; | ||
1893 | } | ||
1894 | |||
1895 | LEAVE; | ||
1896 | return FAILED; | ||
1897 | } | ||
1898 | |||
1899 | /** | ||
1900 | * ibmvfc_dev_cancel_all - Device iterated cancel all function | ||
1901 | * @sdev: scsi device struct | ||
1902 | * @data: return code | ||
1903 | * | ||
1904 | **/ | ||
1905 | static void ibmvfc_dev_cancel_all(struct scsi_device *sdev, void *data) | ||
1906 | { | ||
1907 | unsigned long *rc = data; | ||
1908 | *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); | ||
1909 | } | ||
1910 | |||
1911 | /** | ||
1912 | * ibmvfc_dev_abort_all - Device iterated abort task set function | ||
1913 | * @sdev: scsi device struct | ||
1914 | * @data: return code | ||
1915 | * | ||
1916 | **/ | ||
1917 | static void ibmvfc_dev_abort_all(struct scsi_device *sdev, void *data) | ||
1918 | { | ||
1919 | unsigned long *rc = data; | ||
1920 | *rc |= ibmvfc_abort_task_set(sdev); | ||
1921 | } | ||
1922 | |||
1923 | /** | ||
1924 | * ibmvfc_eh_target_reset_handler - Reset the target | ||
1925 | * @cmd: scsi command struct | ||
1926 | * | ||
1927 | * Returns: | ||
1928 | * SUCCESS / FAILED | ||
1929 | **/ | ||
1930 | static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) | ||
1931 | { | ||
1932 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1933 | struct scsi_target *starget = scsi_target(cmd->device); | ||
1934 | struct ibmvfc_event *evt, *pos; | ||
1935 | int reset_rc; | ||
1936 | unsigned long cancel_rc = 0; | ||
1937 | unsigned long flags; | ||
1938 | |||
1939 | ENTER; | ||
1940 | ibmvfc_wait_while_resetting(vhost); | ||
1941 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | ||
1942 | reset_rc = ibmvfc_reset_device(cmd->device, IBMVFC_TARGET_RESET, "target"); | ||
1943 | |||
1944 | if (!cancel_rc && !reset_rc) { | ||
1945 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
1946 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1947 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | ||
1948 | ibmvfc_fail_request(evt, DID_ABORT); | ||
1949 | } | ||
1950 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
1951 | LEAVE; | ||
1952 | return SUCCESS; | ||
1953 | } | ||
1954 | |||
1955 | LEAVE; | ||
1956 | return FAILED; | ||
1957 | } | ||
1958 | |||
1959 | /** | ||
1960 | * ibmvfc_eh_host_reset_handler - Reset the connection to the server | ||
1961 | * @cmd: struct scsi_cmnd having problems | ||
1962 | * | ||
1963 | **/ | ||
1964 | static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) | ||
1965 | { | ||
1966 | int rc; | ||
1967 | struct ibmvfc_host *vhost = shost_priv(cmd->device->host); | ||
1968 | |||
1969 | dev_err(vhost->dev, "Resetting connection due to error recovery\n"); | ||
1970 | rc = ibmvfc_issue_fc_host_lip(vhost->host); | ||
1971 | return rc ? FAILED : SUCCESS; | ||
1972 | } | ||
1973 | |||
1974 | /** | ||
1975 | * ibmvfc_terminate_rport_io - Terminate all pending I/O to the rport. | ||
1976 | * @rport: rport struct | ||
1977 | * | ||
1978 | * Return value: | ||
1979 | * none | ||
1980 | **/ | ||
1981 | static void ibmvfc_terminate_rport_io(struct fc_rport *rport) | ||
1982 | { | ||
1983 | struct scsi_target *starget = to_scsi_target(&rport->dev); | ||
1984 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
1985 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
1986 | struct ibmvfc_event *evt, *pos; | ||
1987 | unsigned long cancel_rc = 0; | ||
1988 | unsigned long abort_rc = 0; | ||
1989 | unsigned long flags; | ||
1990 | |||
1991 | ENTER; | ||
1992 | starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all); | ||
1993 | starget_for_each_device(starget, &abort_rc, ibmvfc_dev_abort_all); | ||
1994 | |||
1995 | if (!cancel_rc && !abort_rc) { | ||
1996 | spin_lock_irqsave(shost->host_lock, flags); | ||
1997 | list_for_each_entry_safe(evt, pos, &vhost->sent, queue) { | ||
1998 | if (evt->cmnd && scsi_target(evt->cmnd->device) == starget) | ||
1999 | ibmvfc_fail_request(evt, DID_ABORT); | ||
2000 | } | ||
2001 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2002 | } else | ||
2003 | ibmvfc_issue_fc_host_lip(shost); | ||
2004 | |||
2005 | scsi_target_unblock(&rport->dev); | ||
2006 | LEAVE; | ||
2007 | } | ||
2008 | |||
2009 | static const struct { | ||
2010 | enum ibmvfc_async_event ae; | ||
2011 | const char *desc; | ||
2012 | } ae_desc [] = { | ||
2013 | { IBMVFC_AE_ELS_PLOGI, "PLOGI" }, | ||
2014 | { IBMVFC_AE_ELS_LOGO, "LOGO" }, | ||
2015 | { IBMVFC_AE_ELS_PRLO, "PRLO" }, | ||
2016 | { IBMVFC_AE_SCN_NPORT, "N-Port SCN" }, | ||
2017 | { IBMVFC_AE_SCN_GROUP, "Group SCN" }, | ||
2018 | { IBMVFC_AE_SCN_DOMAIN, "Domain SCN" }, | ||
2019 | { IBMVFC_AE_SCN_FABRIC, "Fabric SCN" }, | ||
2020 | { IBMVFC_AE_LINK_UP, "Link Up" }, | ||
2021 | { IBMVFC_AE_LINK_DOWN, "Link Down" }, | ||
2022 | { IBMVFC_AE_LINK_DEAD, "Link Dead" }, | ||
2023 | { IBMVFC_AE_HALT, "Halt" }, | ||
2024 | { IBMVFC_AE_RESUME, "Resume" }, | ||
2025 | { IBMVFC_AE_ADAPTER_FAILED, "Adapter Failed" }, | ||
2026 | }; | ||
2027 | |||
2028 | static const char *unknown_ae = "Unknown async"; | ||
2029 | |||
2030 | /** | ||
2031 | * ibmvfc_get_ae_desc - Get text description for async event | ||
2032 | * @ae: async event | ||
2033 | * | ||
2034 | **/ | ||
2035 | static const char *ibmvfc_get_ae_desc(u64 ae) | ||
2036 | { | ||
2037 | int i; | ||
2038 | |||
2039 | for (i = 0; i < ARRAY_SIZE(ae_desc); i++) | ||
2040 | if (ae_desc[i].ae == ae) | ||
2041 | return ae_desc[i].desc; | ||
2042 | |||
2043 | return unknown_ae; | ||
2044 | } | ||
2045 | |||
2046 | /** | ||
2047 | * ibmvfc_handle_async - Handle an async event from the adapter | ||
2048 | * @crq: crq to process | ||
2049 | * @vhost: ibmvfc host struct | ||
2050 | * | ||
2051 | **/ | ||
2052 | static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, | ||
2053 | struct ibmvfc_host *vhost) | ||
2054 | { | ||
2055 | const char *desc = ibmvfc_get_ae_desc(crq->event); | ||
2056 | |||
2057 | ibmvfc_log(vhost, 2, "%s event received\n", desc); | ||
2058 | |||
2059 | switch (crq->event) { | ||
2060 | case IBMVFC_AE_LINK_UP: | ||
2061 | case IBMVFC_AE_RESUME: | ||
2062 | vhost->events_to_log |= IBMVFC_AE_LINKUP; | ||
2063 | ibmvfc_init_host(vhost); | ||
2064 | break; | ||
2065 | case IBMVFC_AE_SCN_FABRIC: | ||
2066 | vhost->events_to_log |= IBMVFC_AE_RSCN; | ||
2067 | ibmvfc_init_host(vhost); | ||
2068 | break; | ||
2069 | case IBMVFC_AE_SCN_NPORT: | ||
2070 | case IBMVFC_AE_SCN_GROUP: | ||
2071 | case IBMVFC_AE_SCN_DOMAIN: | ||
2072 | vhost->events_to_log |= IBMVFC_AE_RSCN; | ||
2073 | case IBMVFC_AE_ELS_LOGO: | ||
2074 | case IBMVFC_AE_ELS_PRLO: | ||
2075 | case IBMVFC_AE_ELS_PLOGI: | ||
2076 | ibmvfc_reinit_host(vhost); | ||
2077 | break; | ||
2078 | case IBMVFC_AE_LINK_DOWN: | ||
2079 | case IBMVFC_AE_ADAPTER_FAILED: | ||
2080 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2081 | break; | ||
2082 | case IBMVFC_AE_LINK_DEAD: | ||
2083 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2084 | break; | ||
2085 | case IBMVFC_AE_HALT: | ||
2086 | ibmvfc_link_down(vhost, IBMVFC_HALTED); | ||
2087 | break; | ||
2088 | default: | ||
2089 | dev_err(vhost->dev, "Unknown async event received: %ld\n", crq->event); | ||
2090 | break; | ||
2091 | }; | ||
2092 | } | ||
2093 | |||
2094 | /** | ||
2095 | * ibmvfc_handle_crq - Handles and frees received events in the CRQ | ||
2096 | * @crq: Command/Response queue | ||
2097 | * @vhost: ibmvfc host struct | ||
2098 | * | ||
2099 | **/ | ||
2100 | static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) | ||
2101 | { | ||
2102 | long rc; | ||
2103 | struct ibmvfc_event *evt = (struct ibmvfc_event *)crq->ioba; | ||
2104 | |||
2105 | switch (crq->valid) { | ||
2106 | case IBMVFC_CRQ_INIT_RSP: | ||
2107 | switch (crq->format) { | ||
2108 | case IBMVFC_CRQ_INIT: | ||
2109 | dev_info(vhost->dev, "Partner initialized\n"); | ||
2110 | /* Send back a response */ | ||
2111 | rc = ibmvfc_send_crq_init_complete(vhost); | ||
2112 | if (rc == 0) | ||
2113 | ibmvfc_init_host(vhost); | ||
2114 | else | ||
2115 | dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc); | ||
2116 | break; | ||
2117 | case IBMVFC_CRQ_INIT_COMPLETE: | ||
2118 | dev_info(vhost->dev, "Partner initialization complete\n"); | ||
2119 | ibmvfc_init_host(vhost); | ||
2120 | break; | ||
2121 | default: | ||
2122 | dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format); | ||
2123 | } | ||
2124 | return; | ||
2125 | case IBMVFC_CRQ_XPORT_EVENT: | ||
2126 | vhost->state = IBMVFC_NO_CRQ; | ||
2127 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
2128 | if (crq->format == IBMVFC_PARTITION_MIGRATED) { | ||
2129 | /* We need to re-setup the interpartition connection */ | ||
2130 | dev_info(vhost->dev, "Re-enabling adapter\n"); | ||
2131 | vhost->client_migrated = 1; | ||
2132 | ibmvfc_purge_requests(vhost, DID_REQUEUE); | ||
2133 | if ((rc = ibmvfc_reenable_crq_queue(vhost)) || | ||
2134 | (rc = ibmvfc_send_crq_init(vhost))) { | ||
2135 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2136 | dev_err(vhost->dev, "Error after enable (rc=%ld)\n", rc); | ||
2137 | } else | ||
2138 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2139 | } else { | ||
2140 | dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); | ||
2141 | |||
2142 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
2143 | if ((rc = ibmvfc_reset_crq(vhost)) || | ||
2144 | (rc = ibmvfc_send_crq_init(vhost))) { | ||
2145 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
2146 | dev_err(vhost->dev, "Error after reset (rc=%ld)\n", rc); | ||
2147 | } else | ||
2148 | ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); | ||
2149 | } | ||
2150 | return; | ||
2151 | case IBMVFC_CRQ_CMD_RSP: | ||
2152 | break; | ||
2153 | default: | ||
2154 | dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid); | ||
2155 | return; | ||
2156 | } | ||
2157 | |||
2158 | if (crq->format == IBMVFC_ASYNC_EVENT) | ||
2159 | return; | ||
2160 | |||
2161 | /* The only kind of payload CRQs we should get are responses to | ||
2162 | * things we send. Make sure this response is to something we | ||
2163 | * actually sent | ||
2164 | */ | ||
2165 | if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) { | ||
2166 | dev_err(vhost->dev, "Returned correlation_token 0x%08lx is invalid!\n", | ||
2167 | crq->ioba); | ||
2168 | return; | ||
2169 | } | ||
2170 | |||
2171 | if (unlikely(atomic_read(&evt->free))) { | ||
2172 | dev_err(vhost->dev, "Received duplicate correlation_token 0x%08lx!\n", | ||
2173 | crq->ioba); | ||
2174 | return; | ||
2175 | } | ||
2176 | |||
2177 | del_timer(&evt->timer); | ||
2178 | list_del(&evt->queue); | ||
2179 | ibmvfc_trc_end(evt); | ||
2180 | evt->done(evt); | ||
2181 | } | ||
2182 | |||
2183 | /** | ||
2184 | * ibmvfc_scan_finished - Check if the device scan is done. | ||
2185 | * @shost: scsi host struct | ||
2186 | * @time: current elapsed time | ||
2187 | * | ||
2188 | * Returns: | ||
2189 | * 0 if scan is not done / 1 if scan is done | ||
2190 | **/ | ||
2191 | static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time) | ||
2192 | { | ||
2193 | unsigned long flags; | ||
2194 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2195 | int done = 0; | ||
2196 | |||
2197 | spin_lock_irqsave(shost->host_lock, flags); | ||
2198 | if (time >= (init_timeout * HZ)) { | ||
2199 | dev_info(vhost->dev, "Scan taking longer than %d seconds, " | ||
2200 | "continuing initialization\n", init_timeout); | ||
2201 | done = 1; | ||
2202 | } | ||
2203 | |||
2204 | if (vhost->state != IBMVFC_NO_CRQ && vhost->action == IBMVFC_HOST_ACTION_NONE) | ||
2205 | done = 1; | ||
2206 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2207 | return done; | ||
2208 | } | ||
2209 | |||
2210 | /** | ||
2211 | * ibmvfc_slave_alloc - Setup the device's task set value | ||
2212 | * @sdev: struct scsi_device device to configure | ||
2213 | * | ||
2214 | * Set the device's task set value so that error handling works as | ||
2215 | * expected. | ||
2216 | * | ||
2217 | * Returns: | ||
2218 | * 0 on success / -ENXIO if device does not exist | ||
2219 | **/ | ||
2220 | static int ibmvfc_slave_alloc(struct scsi_device *sdev) | ||
2221 | { | ||
2222 | struct Scsi_Host *shost = sdev->host; | ||
2223 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
2224 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2225 | unsigned long flags = 0; | ||
2226 | |||
2227 | if (!rport || fc_remote_port_chkready(rport)) | ||
2228 | return -ENXIO; | ||
2229 | |||
2230 | spin_lock_irqsave(shost->host_lock, flags); | ||
2231 | sdev->hostdata = (void *)(unsigned long)vhost->task_set++; | ||
2232 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2233 | return 0; | ||
2234 | } | ||
2235 | |||
2236 | /** | ||
2237 | * ibmvfc_slave_configure - Configure the device | ||
2238 | * @sdev: struct scsi_device device to configure | ||
2239 | * | ||
2240 | * Enable allow_restart for a device if it is a disk. Adjust the | ||
2241 | * queue_depth here also. | ||
2242 | * | ||
2243 | * Returns: | ||
2244 | * 0 | ||
2245 | **/ | ||
2246 | static int ibmvfc_slave_configure(struct scsi_device *sdev) | ||
2247 | { | ||
2248 | struct Scsi_Host *shost = sdev->host; | ||
2249 | struct fc_rport *rport = starget_to_rport(sdev->sdev_target); | ||
2250 | unsigned long flags = 0; | ||
2251 | |||
2252 | spin_lock_irqsave(shost->host_lock, flags); | ||
2253 | if (sdev->type == TYPE_DISK) | ||
2254 | sdev->allow_restart = 1; | ||
2255 | |||
2256 | if (sdev->tagged_supported) { | ||
2257 | scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); | ||
2258 | scsi_activate_tcq(sdev, sdev->queue_depth); | ||
2259 | } else | ||
2260 | scsi_deactivate_tcq(sdev, sdev->queue_depth); | ||
2261 | |||
2262 | rport->dev_loss_tmo = dev_loss_tmo; | ||
2263 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2264 | return 0; | ||
2265 | } | ||
2266 | |||
2267 | /** | ||
2268 | * ibmvfc_change_queue_depth - Change the device's queue depth | ||
2269 | * @sdev: scsi device struct | ||
2270 | * @qdepth: depth to set | ||
2271 | * | ||
2272 | * Return value: | ||
2273 | * actual depth set | ||
2274 | **/ | ||
2275 | static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth) | ||
2276 | { | ||
2277 | if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) | ||
2278 | qdepth = IBMVFC_MAX_CMDS_PER_LUN; | ||
2279 | |||
2280 | scsi_adjust_queue_depth(sdev, 0, qdepth); | ||
2281 | return sdev->queue_depth; | ||
2282 | } | ||
2283 | |||
2284 | /** | ||
2285 | * ibmvfc_change_queue_type - Change the device's queue type | ||
2286 | * @sdev: scsi device struct | ||
2287 | * @tag_type: type of tags to use | ||
2288 | * | ||
2289 | * Return value: | ||
2290 | * actual queue type set | ||
2291 | **/ | ||
2292 | static int ibmvfc_change_queue_type(struct scsi_device *sdev, int tag_type) | ||
2293 | { | ||
2294 | if (sdev->tagged_supported) { | ||
2295 | scsi_set_tag_type(sdev, tag_type); | ||
2296 | |||
2297 | if (tag_type) | ||
2298 | scsi_activate_tcq(sdev, sdev->queue_depth); | ||
2299 | else | ||
2300 | scsi_deactivate_tcq(sdev, sdev->queue_depth); | ||
2301 | } else | ||
2302 | tag_type = 0; | ||
2303 | |||
2304 | return tag_type; | ||
2305 | } | ||
2306 | |||
2307 | static ssize_t ibmvfc_show_host_partition_name(struct device *dev, | ||
2308 | struct device_attribute *attr, char *buf) | ||
2309 | { | ||
2310 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2311 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2312 | |||
2313 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2314 | vhost->login_buf->resp.partition_name); | ||
2315 | } | ||
2316 | |||
2317 | static struct device_attribute ibmvfc_host_partition_name = { | ||
2318 | .attr = { | ||
2319 | .name = "partition_name", | ||
2320 | .mode = S_IRUGO, | ||
2321 | }, | ||
2322 | .show = ibmvfc_show_host_partition_name, | ||
2323 | }; | ||
2324 | |||
2325 | static ssize_t ibmvfc_show_host_device_name(struct device *dev, | ||
2326 | struct device_attribute *attr, char *buf) | ||
2327 | { | ||
2328 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2329 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2330 | |||
2331 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2332 | vhost->login_buf->resp.device_name); | ||
2333 | } | ||
2334 | |||
2335 | static struct device_attribute ibmvfc_host_device_name = { | ||
2336 | .attr = { | ||
2337 | .name = "device_name", | ||
2338 | .mode = S_IRUGO, | ||
2339 | }, | ||
2340 | .show = ibmvfc_show_host_device_name, | ||
2341 | }; | ||
2342 | |||
2343 | static ssize_t ibmvfc_show_host_loc_code(struct device *dev, | ||
2344 | struct device_attribute *attr, char *buf) | ||
2345 | { | ||
2346 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2347 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2348 | |||
2349 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2350 | vhost->login_buf->resp.port_loc_code); | ||
2351 | } | ||
2352 | |||
2353 | static struct device_attribute ibmvfc_host_loc_code = { | ||
2354 | .attr = { | ||
2355 | .name = "port_loc_code", | ||
2356 | .mode = S_IRUGO, | ||
2357 | }, | ||
2358 | .show = ibmvfc_show_host_loc_code, | ||
2359 | }; | ||
2360 | |||
2361 | static ssize_t ibmvfc_show_host_drc_name(struct device *dev, | ||
2362 | struct device_attribute *attr, char *buf) | ||
2363 | { | ||
2364 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2365 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2366 | |||
2367 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
2368 | vhost->login_buf->resp.drc_name); | ||
2369 | } | ||
2370 | |||
2371 | static struct device_attribute ibmvfc_host_drc_name = { | ||
2372 | .attr = { | ||
2373 | .name = "drc_name", | ||
2374 | .mode = S_IRUGO, | ||
2375 | }, | ||
2376 | .show = ibmvfc_show_host_drc_name, | ||
2377 | }; | ||
2378 | |||
2379 | static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, | ||
2380 | struct device_attribute *attr, char *buf) | ||
2381 | { | ||
2382 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2383 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2384 | return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); | ||
2385 | } | ||
2386 | |||
2387 | static struct device_attribute ibmvfc_host_npiv_version = { | ||
2388 | .attr = { | ||
2389 | .name = "npiv_version", | ||
2390 | .mode = S_IRUGO, | ||
2391 | }, | ||
2392 | .show = ibmvfc_show_host_npiv_version, | ||
2393 | }; | ||
2394 | |||
2395 | /** | ||
2396 | * ibmvfc_show_log_level - Show the adapter's error logging level | ||
2397 | * @dev: class device struct | ||
2398 | * @buf: buffer | ||
2399 | * | ||
2400 | * Return value: | ||
2401 | * number of bytes printed to buffer | ||
2402 | **/ | ||
2403 | static ssize_t ibmvfc_show_log_level(struct device *dev, | ||
2404 | struct device_attribute *attr, char *buf) | ||
2405 | { | ||
2406 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2407 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2408 | unsigned long flags = 0; | ||
2409 | int len; | ||
2410 | |||
2411 | spin_lock_irqsave(shost->host_lock, flags); | ||
2412 | len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->log_level); | ||
2413 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2414 | return len; | ||
2415 | } | ||
2416 | |||
2417 | /** | ||
2418 | * ibmvfc_store_log_level - Change the adapter's error logging level | ||
2419 | * @dev: class device struct | ||
2420 | * @buf: buffer | ||
2421 | * | ||
2422 | * Return value: | ||
2423 | * number of bytes printed to buffer | ||
2424 | **/ | ||
2425 | static ssize_t ibmvfc_store_log_level(struct device *dev, | ||
2426 | struct device_attribute *attr, | ||
2427 | const char *buf, size_t count) | ||
2428 | { | ||
2429 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2430 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2431 | unsigned long flags = 0; | ||
2432 | |||
2433 | spin_lock_irqsave(shost->host_lock, flags); | ||
2434 | vhost->log_level = simple_strtoul(buf, NULL, 10); | ||
2435 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2436 | return strlen(buf); | ||
2437 | } | ||
2438 | |||
2439 | static struct device_attribute ibmvfc_log_level_attr = { | ||
2440 | .attr = { | ||
2441 | .name = "log_level", | ||
2442 | .mode = S_IRUGO | S_IWUSR, | ||
2443 | }, | ||
2444 | .show = ibmvfc_show_log_level, | ||
2445 | .store = ibmvfc_store_log_level | ||
2446 | }; | ||
2447 | |||
2448 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
2449 | /** | ||
2450 | * ibmvfc_read_trace - Dump the adapter trace | ||
2451 | * @kobj: kobject struct | ||
2452 | * @bin_attr: bin_attribute struct | ||
2453 | * @buf: buffer | ||
2454 | * @off: offset | ||
2455 | * @count: buffer size | ||
2456 | * | ||
2457 | * Return value: | ||
2458 | * number of bytes printed to buffer | ||
2459 | **/ | ||
2460 | static ssize_t ibmvfc_read_trace(struct kobject *kobj, | ||
2461 | struct bin_attribute *bin_attr, | ||
2462 | char *buf, loff_t off, size_t count) | ||
2463 | { | ||
2464 | struct device *dev = container_of(kobj, struct device, kobj); | ||
2465 | struct Scsi_Host *shost = class_to_shost(dev); | ||
2466 | struct ibmvfc_host *vhost = shost_priv(shost); | ||
2467 | unsigned long flags = 0; | ||
2468 | int size = IBMVFC_TRACE_SIZE; | ||
2469 | char *src = (char *)vhost->trace; | ||
2470 | |||
2471 | if (off > size) | ||
2472 | return 0; | ||
2473 | if (off + count > size) { | ||
2474 | size -= off; | ||
2475 | count = size; | ||
2476 | } | ||
2477 | |||
2478 | spin_lock_irqsave(shost->host_lock, flags); | ||
2479 | memcpy(buf, &src[off], count); | ||
2480 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
2481 | return count; | ||
2482 | } | ||
2483 | |||
2484 | static struct bin_attribute ibmvfc_trace_attr = { | ||
2485 | .attr = { | ||
2486 | .name = "trace", | ||
2487 | .mode = S_IRUGO, | ||
2488 | }, | ||
2489 | .size = 0, | ||
2490 | .read = ibmvfc_read_trace, | ||
2491 | }; | ||
2492 | #endif | ||
2493 | |||
2494 | static struct device_attribute *ibmvfc_attrs[] = { | ||
2495 | &ibmvfc_host_partition_name, | ||
2496 | &ibmvfc_host_device_name, | ||
2497 | &ibmvfc_host_loc_code, | ||
2498 | &ibmvfc_host_drc_name, | ||
2499 | &ibmvfc_host_npiv_version, | ||
2500 | &ibmvfc_log_level_attr, | ||
2501 | NULL | ||
2502 | }; | ||
2503 | |||
2504 | static struct scsi_host_template driver_template = { | ||
2505 | .module = THIS_MODULE, | ||
2506 | .name = "IBM POWER Virtual FC Adapter", | ||
2507 | .proc_name = IBMVFC_NAME, | ||
2508 | .queuecommand = ibmvfc_queuecommand, | ||
2509 | .eh_abort_handler = ibmvfc_eh_abort_handler, | ||
2510 | .eh_device_reset_handler = ibmvfc_eh_device_reset_handler, | ||
2511 | .eh_target_reset_handler = ibmvfc_eh_target_reset_handler, | ||
2512 | .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, | ||
2513 | .slave_alloc = ibmvfc_slave_alloc, | ||
2514 | .slave_configure = ibmvfc_slave_configure, | ||
2515 | .scan_finished = ibmvfc_scan_finished, | ||
2516 | .change_queue_depth = ibmvfc_change_queue_depth, | ||
2517 | .change_queue_type = ibmvfc_change_queue_type, | ||
2518 | .cmd_per_lun = 16, | ||
2519 | .can_queue = IBMVFC_MAX_REQUESTS_DEFAULT, | ||
2520 | .this_id = -1, | ||
2521 | .sg_tablesize = SG_ALL, | ||
2522 | .max_sectors = IBMVFC_MAX_SECTORS, | ||
2523 | .use_clustering = ENABLE_CLUSTERING, | ||
2524 | .shost_attrs = ibmvfc_attrs, | ||
2525 | }; | ||
2526 | |||
2527 | /** | ||
2528 | * ibmvfc_next_async_crq - Returns the next entry in async queue | ||
2529 | * @vhost: ibmvfc host struct | ||
2530 | * | ||
2531 | * Returns: | ||
2532 | * Pointer to next entry in queue / NULL if empty | ||
2533 | **/ | ||
2534 | static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost) | ||
2535 | { | ||
2536 | struct ibmvfc_async_crq_queue *async_crq = &vhost->async_crq; | ||
2537 | struct ibmvfc_async_crq *crq; | ||
2538 | |||
2539 | crq = &async_crq->msgs[async_crq->cur]; | ||
2540 | if (crq->valid & 0x80) { | ||
2541 | if (++async_crq->cur == async_crq->size) | ||
2542 | async_crq->cur = 0; | ||
2543 | } else | ||
2544 | crq = NULL; | ||
2545 | |||
2546 | return crq; | ||
2547 | } | ||
2548 | |||
2549 | /** | ||
2550 | * ibmvfc_next_crq - Returns the next entry in message queue | ||
2551 | * @vhost: ibmvfc host struct | ||
2552 | * | ||
2553 | * Returns: | ||
2554 | * Pointer to next entry in queue / NULL if empty | ||
2555 | **/ | ||
2556 | static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost) | ||
2557 | { | ||
2558 | struct ibmvfc_crq_queue *queue = &vhost->crq; | ||
2559 | struct ibmvfc_crq *crq; | ||
2560 | |||
2561 | crq = &queue->msgs[queue->cur]; | ||
2562 | if (crq->valid & 0x80) { | ||
2563 | if (++queue->cur == queue->size) | ||
2564 | queue->cur = 0; | ||
2565 | } else | ||
2566 | crq = NULL; | ||
2567 | |||
2568 | return crq; | ||
2569 | } | ||
2570 | |||
2571 | /** | ||
2572 | * ibmvfc_interrupt - Interrupt handler | ||
2573 | * @irq: number of irq to handle, not used | ||
2574 | * @dev_instance: ibmvfc_host that received interrupt | ||
2575 | * | ||
2576 | * Returns: | ||
2577 | * IRQ_HANDLED | ||
2578 | **/ | ||
2579 | static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) | ||
2580 | { | ||
2581 | struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; | ||
2582 | struct vio_dev *vdev = to_vio_dev(vhost->dev); | ||
2583 | struct ibmvfc_crq *crq; | ||
2584 | struct ibmvfc_async_crq *async; | ||
2585 | unsigned long flags; | ||
2586 | int done = 0; | ||
2587 | |||
2588 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
2589 | vio_disable_interrupts(to_vio_dev(vhost->dev)); | ||
2590 | while (!done) { | ||
2591 | /* Pull all the valid messages off the CRQ */ | ||
2592 | while ((crq = ibmvfc_next_crq(vhost)) != NULL) { | ||
2593 | ibmvfc_handle_crq(crq, vhost); | ||
2594 | crq->valid = 0; | ||
2595 | } | ||
2596 | |||
2597 | /* Pull all the valid messages off the async CRQ */ | ||
2598 | while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | ||
2599 | ibmvfc_handle_async(async, vhost); | ||
2600 | async->valid = 0; | ||
2601 | } | ||
2602 | |||
2603 | vio_enable_interrupts(vdev); | ||
2604 | if ((crq = ibmvfc_next_crq(vhost)) != NULL) { | ||
2605 | vio_disable_interrupts(vdev); | ||
2606 | ibmvfc_handle_crq(crq, vhost); | ||
2607 | crq->valid = 0; | ||
2608 | } else if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { | ||
2609 | vio_disable_interrupts(vdev); | ||
2610 | ibmvfc_handle_async(async, vhost); | ||
2611 | crq->valid = 0; | ||
2612 | } else | ||
2613 | done = 1; | ||
2614 | } | ||
2615 | |||
2616 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
2617 | return IRQ_HANDLED; | ||
2618 | } | ||
2619 | |||
2620 | /** | ||
2621 | * ibmvfc_init_tgt - Set the next init job step for the target | ||
2622 | * @tgt: ibmvfc target struct | ||
2623 | * @job_step: job step to perform | ||
2624 | * | ||
2625 | **/ | ||
2626 | static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, | ||
2627 | void (*job_step) (struct ibmvfc_target *)) | ||
2628 | { | ||
2629 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); | ||
2630 | tgt->job_step = job_step; | ||
2631 | wake_up(&tgt->vhost->work_wait_q); | ||
2632 | } | ||
2633 | |||
2634 | /** | ||
2635 | * ibmvfc_retry_tgt_init - Attempt to retry a step in target initialization | ||
2636 | * @tgt: ibmvfc target struct | ||
2637 | * @job_step: initialization job step | ||
2638 | * | ||
2639 | **/ | ||
2640 | static void ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, | ||
2641 | void (*job_step) (struct ibmvfc_target *)) | ||
2642 | { | ||
2643 | if (++tgt->init_retries > IBMVFC_MAX_INIT_RETRIES) { | ||
2644 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2645 | wake_up(&tgt->vhost->work_wait_q); | ||
2646 | } else | ||
2647 | ibmvfc_init_tgt(tgt, job_step); | ||
2648 | } | ||
2649 | |||
2650 | /** | ||
2651 | * ibmvfc_release_tgt - Free memory allocated for a target | ||
2652 | * @kref: kref struct | ||
2653 | * | ||
2654 | **/ | ||
2655 | static void ibmvfc_release_tgt(struct kref *kref) | ||
2656 | { | ||
2657 | struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); | ||
2658 | kfree(tgt); | ||
2659 | } | ||
2660 | |||
2661 | /** | ||
2662 | * ibmvfc_tgt_prli_done - Completion handler for Process Login | ||
2663 | * @evt: ibmvfc event struct | ||
2664 | * | ||
2665 | **/ | ||
2666 | static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) | ||
2667 | { | ||
2668 | struct ibmvfc_target *tgt = evt->tgt; | ||
2669 | struct ibmvfc_host *vhost = evt->vhost; | ||
2670 | struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; | ||
2671 | u32 status = rsp->common.status; | ||
2672 | |||
2673 | vhost->discovery_threads--; | ||
2674 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2675 | switch (status) { | ||
2676 | case IBMVFC_MAD_SUCCESS: | ||
2677 | tgt_dbg(tgt, "Process Login succeeded\n"); | ||
2678 | tgt->need_login = 0; | ||
2679 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_ADD_RPORT); | ||
2680 | break; | ||
2681 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2682 | break; | ||
2683 | case IBMVFC_MAD_CRQ_ERROR: | ||
2684 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | ||
2685 | break; | ||
2686 | case IBMVFC_MAD_FAILED: | ||
2687 | default: | ||
2688 | tgt_err(tgt, "Process Login failed: %s (%x:%x) rc=0x%02X\n", | ||
2689 | ibmvfc_get_cmd_error(rsp->status, rsp->error), | ||
2690 | rsp->status, rsp->error, status); | ||
2691 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2692 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); | ||
2693 | break; | ||
2694 | }; | ||
2695 | |||
2696 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2697 | ibmvfc_free_event(evt); | ||
2698 | wake_up(&vhost->work_wait_q); | ||
2699 | } | ||
2700 | |||
2701 | /** | ||
2702 | * ibmvfc_tgt_send_prli - Send a process login | ||
2703 | * @tgt: ibmvfc target struct | ||
2704 | * | ||
2705 | **/ | ||
2706 | static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) | ||
2707 | { | ||
2708 | struct ibmvfc_process_login *prli; | ||
2709 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2710 | struct ibmvfc_event *evt; | ||
2711 | |||
2712 | if (vhost->discovery_threads >= disc_threads) | ||
2713 | return; | ||
2714 | |||
2715 | kref_get(&tgt->kref); | ||
2716 | evt = ibmvfc_get_event(vhost); | ||
2717 | vhost->discovery_threads++; | ||
2718 | ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT); | ||
2719 | evt->tgt = tgt; | ||
2720 | prli = &evt->iu.prli; | ||
2721 | memset(prli, 0, sizeof(*prli)); | ||
2722 | prli->common.version = 1; | ||
2723 | prli->common.opcode = IBMVFC_PROCESS_LOGIN; | ||
2724 | prli->common.length = sizeof(*prli); | ||
2725 | prli->scsi_id = tgt->scsi_id; | ||
2726 | |||
2727 | prli->parms.type = IBMVFC_SCSI_FCP_TYPE; | ||
2728 | prli->parms.flags = IBMVFC_PRLI_EST_IMG_PAIR; | ||
2729 | prli->parms.service_parms = IBMVFC_PRLI_INITIATOR_FUNC; | ||
2730 | |||
2731 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2732 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2733 | vhost->discovery_threads--; | ||
2734 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2735 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2736 | } else | ||
2737 | tgt_dbg(tgt, "Sent process login\n"); | ||
2738 | } | ||
2739 | |||
2740 | /** | ||
2741 | * ibmvfc_tgt_plogi_done - Completion handler for Port Login | ||
2742 | * @evt: ibmvfc event struct | ||
2743 | * | ||
2744 | **/ | ||
2745 | static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) | ||
2746 | { | ||
2747 | struct ibmvfc_target *tgt = evt->tgt; | ||
2748 | struct ibmvfc_host *vhost = evt->vhost; | ||
2749 | struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi; | ||
2750 | u32 status = rsp->common.status; | ||
2751 | |||
2752 | vhost->discovery_threads--; | ||
2753 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2754 | switch (status) { | ||
2755 | case IBMVFC_MAD_SUCCESS: | ||
2756 | tgt_dbg(tgt, "Port Login succeeded\n"); | ||
2757 | if (tgt->ids.port_name && | ||
2758 | tgt->ids.port_name != wwn_to_u64(rsp->service_parms.port_name)) { | ||
2759 | vhost->reinit = 1; | ||
2760 | tgt_dbg(tgt, "Port re-init required\n"); | ||
2761 | break; | ||
2762 | } | ||
2763 | tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); | ||
2764 | tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); | ||
2765 | tgt->ids.port_id = tgt->scsi_id; | ||
2766 | tgt->ids.roles = FC_PORT_ROLE_FCP_TARGET; | ||
2767 | memcpy(&tgt->service_parms, &rsp->service_parms, | ||
2768 | sizeof(tgt->service_parms)); | ||
2769 | memcpy(&tgt->service_parms_change, &rsp->service_parms_change, | ||
2770 | sizeof(tgt->service_parms_change)); | ||
2771 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli); | ||
2772 | break; | ||
2773 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2774 | break; | ||
2775 | case IBMVFC_MAD_CRQ_ERROR: | ||
2776 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | ||
2777 | break; | ||
2778 | case IBMVFC_MAD_FAILED: | ||
2779 | default: | ||
2780 | tgt_err(tgt, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
2781 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, | ||
2782 | ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, | ||
2783 | ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); | ||
2784 | |||
2785 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2786 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); | ||
2787 | break; | ||
2788 | }; | ||
2789 | |||
2790 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2791 | ibmvfc_free_event(evt); | ||
2792 | wake_up(&vhost->work_wait_q); | ||
2793 | } | ||
2794 | |||
2795 | /** | ||
2796 | * ibmvfc_tgt_send_plogi - Send PLOGI to the specified target | ||
2797 | * @tgt: ibmvfc target struct | ||
2798 | * | ||
2799 | **/ | ||
2800 | static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) | ||
2801 | { | ||
2802 | struct ibmvfc_port_login *plogi; | ||
2803 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2804 | struct ibmvfc_event *evt; | ||
2805 | |||
2806 | if (vhost->discovery_threads >= disc_threads) | ||
2807 | return; | ||
2808 | |||
2809 | kref_get(&tgt->kref); | ||
2810 | evt = ibmvfc_get_event(vhost); | ||
2811 | vhost->discovery_threads++; | ||
2812 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2813 | ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT); | ||
2814 | evt->tgt = tgt; | ||
2815 | plogi = &evt->iu.plogi; | ||
2816 | memset(plogi, 0, sizeof(*plogi)); | ||
2817 | plogi->common.version = 1; | ||
2818 | plogi->common.opcode = IBMVFC_PORT_LOGIN; | ||
2819 | plogi->common.length = sizeof(*plogi); | ||
2820 | plogi->scsi_id = tgt->scsi_id; | ||
2821 | |||
2822 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2823 | vhost->discovery_threads--; | ||
2824 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2825 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2826 | } else | ||
2827 | tgt_dbg(tgt, "Sent port login\n"); | ||
2828 | } | ||
2829 | |||
2830 | /** | ||
2831 | * ibmvfc_tgt_implicit_logout_done - Completion handler for Implicit Logout MAD | ||
2832 | * @evt: ibmvfc event struct | ||
2833 | * | ||
2834 | **/ | ||
2835 | static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) | ||
2836 | { | ||
2837 | struct ibmvfc_target *tgt = evt->tgt; | ||
2838 | struct ibmvfc_host *vhost = evt->vhost; | ||
2839 | struct ibmvfc_implicit_logout *rsp = &evt->xfer_iu->implicit_logout; | ||
2840 | u32 status = rsp->common.status; | ||
2841 | |||
2842 | vhost->discovery_threads--; | ||
2843 | ibmvfc_free_event(evt); | ||
2844 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2845 | |||
2846 | switch (status) { | ||
2847 | case IBMVFC_MAD_SUCCESS: | ||
2848 | tgt_dbg(tgt, "Implicit Logout succeeded\n"); | ||
2849 | break; | ||
2850 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2851 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2852 | wake_up(&vhost->work_wait_q); | ||
2853 | return; | ||
2854 | case IBMVFC_MAD_FAILED: | ||
2855 | default: | ||
2856 | tgt_err(tgt, "Implicit Logout failed: rc=0x%02X\n", status); | ||
2857 | break; | ||
2858 | }; | ||
2859 | |||
2860 | if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) | ||
2861 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); | ||
2862 | else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && | ||
2863 | tgt->scsi_id != tgt->new_scsi_id) | ||
2864 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2865 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2866 | wake_up(&vhost->work_wait_q); | ||
2867 | } | ||
2868 | |||
2869 | /** | ||
2870 | * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target | ||
2871 | * @tgt: ibmvfc target struct | ||
2872 | * | ||
2873 | **/ | ||
2874 | static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) | ||
2875 | { | ||
2876 | struct ibmvfc_implicit_logout *mad; | ||
2877 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2878 | struct ibmvfc_event *evt; | ||
2879 | |||
2880 | if (vhost->discovery_threads >= disc_threads) | ||
2881 | return; | ||
2882 | |||
2883 | kref_get(&tgt->kref); | ||
2884 | evt = ibmvfc_get_event(vhost); | ||
2885 | vhost->discovery_threads++; | ||
2886 | ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); | ||
2887 | evt->tgt = tgt; | ||
2888 | mad = &evt->iu.implicit_logout; | ||
2889 | memset(mad, 0, sizeof(*mad)); | ||
2890 | mad->common.version = 1; | ||
2891 | mad->common.opcode = IBMVFC_IMPLICIT_LOGOUT; | ||
2892 | mad->common.length = sizeof(*mad); | ||
2893 | mad->old_scsi_id = tgt->scsi_id; | ||
2894 | |||
2895 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2896 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2897 | vhost->discovery_threads--; | ||
2898 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2899 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2900 | } else | ||
2901 | tgt_dbg(tgt, "Sent Implicit Logout\n"); | ||
2902 | } | ||
2903 | |||
2904 | /** | ||
2905 | * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD | ||
2906 | * @evt: ibmvfc event struct | ||
2907 | * | ||
2908 | **/ | ||
2909 | static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) | ||
2910 | { | ||
2911 | struct ibmvfc_target *tgt = evt->tgt; | ||
2912 | struct ibmvfc_host *vhost = evt->vhost; | ||
2913 | struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt; | ||
2914 | u32 status = rsp->common.status; | ||
2915 | |||
2916 | vhost->discovery_threads--; | ||
2917 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2918 | switch (status) { | ||
2919 | case IBMVFC_MAD_SUCCESS: | ||
2920 | tgt_dbg(tgt, "Query Target succeeded\n"); | ||
2921 | tgt->new_scsi_id = rsp->scsi_id; | ||
2922 | if (rsp->scsi_id != tgt->scsi_id) | ||
2923 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
2924 | break; | ||
2925 | case IBMVFC_MAD_DRIVER_FAILED: | ||
2926 | break; | ||
2927 | case IBMVFC_MAD_CRQ_ERROR: | ||
2928 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | ||
2929 | break; | ||
2930 | case IBMVFC_MAD_FAILED: | ||
2931 | default: | ||
2932 | tgt_err(tgt, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", | ||
2933 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, | ||
2934 | ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, | ||
2935 | ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); | ||
2936 | |||
2937 | if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && | ||
2938 | rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ && | ||
2939 | rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG) | ||
2940 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); | ||
2941 | else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
2942 | ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); | ||
2943 | break; | ||
2944 | }; | ||
2945 | |||
2946 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2947 | ibmvfc_free_event(evt); | ||
2948 | wake_up(&vhost->work_wait_q); | ||
2949 | } | ||
2950 | |||
2951 | /** | ||
2952 | * ibmvfc_tgt_query_target - Initiate a Query Target for specified target | ||
2953 | * @tgt: ibmvfc target struct | ||
2954 | * | ||
2955 | **/ | ||
2956 | static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt) | ||
2957 | { | ||
2958 | struct ibmvfc_query_tgt *query_tgt; | ||
2959 | struct ibmvfc_host *vhost = tgt->vhost; | ||
2960 | struct ibmvfc_event *evt; | ||
2961 | |||
2962 | if (vhost->discovery_threads >= disc_threads) | ||
2963 | return; | ||
2964 | |||
2965 | kref_get(&tgt->kref); | ||
2966 | evt = ibmvfc_get_event(vhost); | ||
2967 | vhost->discovery_threads++; | ||
2968 | evt->tgt = tgt; | ||
2969 | ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT); | ||
2970 | query_tgt = &evt->iu.query_tgt; | ||
2971 | memset(query_tgt, 0, sizeof(*query_tgt)); | ||
2972 | query_tgt->common.version = 1; | ||
2973 | query_tgt->common.opcode = IBMVFC_QUERY_TARGET; | ||
2974 | query_tgt->common.length = sizeof(*query_tgt); | ||
2975 | query_tgt->wwpn = tgt->ids.port_name; | ||
2976 | |||
2977 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); | ||
2978 | if (ibmvfc_send_event(evt, vhost, default_timeout)) { | ||
2979 | vhost->discovery_threads--; | ||
2980 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
2981 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
2982 | } else | ||
2983 | tgt_dbg(tgt, "Sent Query Target\n"); | ||
2984 | } | ||
2985 | |||
2986 | /** | ||
2987 | * ibmvfc_alloc_target - Allocate and initialize an ibmvfc target | ||
2988 | * @vhost: ibmvfc host struct | ||
2989 | * @scsi_id: SCSI ID to allocate target for | ||
2990 | * | ||
2991 | * Returns: | ||
2992 | * 0 on success / other on failure | ||
2993 | **/ | ||
2994 | static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) | ||
2995 | { | ||
2996 | struct ibmvfc_target *tgt; | ||
2997 | unsigned long flags; | ||
2998 | |||
2999 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3000 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3001 | if (tgt->scsi_id == scsi_id) { | ||
3002 | if (tgt->need_login) | ||
3003 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
3004 | goto unlock_out; | ||
3005 | } | ||
3006 | } | ||
3007 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3008 | |||
3009 | tgt = mempool_alloc(vhost->tgt_pool, GFP_KERNEL); | ||
3010 | if (!tgt) { | ||
3011 | dev_err(vhost->dev, "Target allocation failure for scsi id %08lx\n", | ||
3012 | scsi_id); | ||
3013 | return -ENOMEM; | ||
3014 | } | ||
3015 | |||
3016 | tgt->scsi_id = scsi_id; | ||
3017 | tgt->new_scsi_id = scsi_id; | ||
3018 | tgt->vhost = vhost; | ||
3019 | tgt->need_login = 1; | ||
3020 | kref_init(&tgt->kref); | ||
3021 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); | ||
3022 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3023 | list_add_tail(&tgt->queue, &vhost->targets); | ||
3024 | |||
3025 | unlock_out: | ||
3026 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3027 | return 0; | ||
3028 | } | ||
3029 | |||
3030 | /** | ||
3031 | * ibmvfc_alloc_targets - Allocate and initialize ibmvfc targets | ||
3032 | * @vhost: ibmvfc host struct | ||
3033 | * | ||
3034 | * Returns: | ||
3035 | * 0 on success / other on failure | ||
3036 | **/ | ||
3037 | static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost) | ||
3038 | { | ||
3039 | int i, rc; | ||
3040 | |||
3041 | for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) | ||
3042 | rc = ibmvfc_alloc_target(vhost, | ||
3043 | vhost->disc_buf->scsi_id[i] & IBMVFC_DISC_TGT_SCSI_ID_MASK); | ||
3044 | |||
3045 | return rc; | ||
3046 | } | ||
3047 | |||
3048 | /** | ||
3049 | * ibmvfc_discover_targets_done - Completion handler for discover targets MAD | ||
3050 | * @evt: ibmvfc event struct | ||
3051 | * | ||
3052 | **/ | ||
3053 | static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) | ||
3054 | { | ||
3055 | struct ibmvfc_host *vhost = evt->vhost; | ||
3056 | struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets; | ||
3057 | u32 mad_status = rsp->common.status; | ||
3058 | |||
3059 | switch (mad_status) { | ||
3060 | case IBMVFC_MAD_SUCCESS: | ||
3061 | ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); | ||
3062 | vhost->num_targets = rsp->num_written; | ||
3063 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); | ||
3064 | break; | ||
3065 | case IBMVFC_MAD_FAILED: | ||
3066 | dev_err(vhost->dev, "Discover Targets failed: %s (%x:%x)\n", | ||
3067 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); | ||
3068 | ibmvfc_retry_host_init(vhost); | ||
3069 | break; | ||
3070 | case IBMVFC_MAD_DRIVER_FAILED: | ||
3071 | break; | ||
3072 | default: | ||
3073 | dev_err(vhost->dev, "Invalid Discover Targets response: 0x%x\n", mad_status); | ||
3074 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3075 | break; | ||
3076 | } | ||
3077 | |||
3078 | ibmvfc_free_event(evt); | ||
3079 | wake_up(&vhost->work_wait_q); | ||
3080 | } | ||
3081 | |||
3082 | /** | ||
3083 | * ibmvfc_discover_targets - Send Discover Targets MAD | ||
3084 | * @vhost: ibmvfc host struct | ||
3085 | * | ||
3086 | **/ | ||
3087 | static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) | ||
3088 | { | ||
3089 | struct ibmvfc_discover_targets *mad; | ||
3090 | struct ibmvfc_event *evt = ibmvfc_get_event(vhost); | ||
3091 | |||
3092 | ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT); | ||
3093 | mad = &evt->iu.discover_targets; | ||
3094 | memset(mad, 0, sizeof(*mad)); | ||
3095 | mad->common.version = 1; | ||
3096 | mad->common.opcode = IBMVFC_DISC_TARGETS; | ||
3097 | mad->common.length = sizeof(*mad); | ||
3098 | mad->bufflen = vhost->disc_buf_sz; | ||
3099 | mad->buffer.va = vhost->disc_buf_dma; | ||
3100 | mad->buffer.len = vhost->disc_buf_sz; | ||
3101 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); | ||
3102 | |||
3103 | if (!ibmvfc_send_event(evt, vhost, default_timeout)) | ||
3104 | ibmvfc_dbg(vhost, "Sent discover targets\n"); | ||
3105 | else | ||
3106 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3107 | } | ||
3108 | |||
3109 | /** | ||
3110 | * ibmvfc_npiv_login_done - Completion handler for NPIV Login | ||
3111 | * @evt: ibmvfc event struct | ||
3112 | * | ||
3113 | **/ | ||
3114 | static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) | ||
3115 | { | ||
3116 | struct ibmvfc_host *vhost = evt->vhost; | ||
3117 | u32 mad_status = evt->xfer_iu->npiv_login.common.status; | ||
3118 | struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp; | ||
3119 | unsigned int npiv_max_sectors; | ||
3120 | |||
3121 | switch (mad_status) { | ||
3122 | case IBMVFC_MAD_SUCCESS: | ||
3123 | ibmvfc_free_event(evt); | ||
3124 | break; | ||
3125 | case IBMVFC_MAD_FAILED: | ||
3126 | dev_err(vhost->dev, "NPIV Login failed: %s (%x:%x)\n", | ||
3127 | ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); | ||
3128 | if (ibmvfc_retry_cmd(rsp->status, rsp->error)) | ||
3129 | ibmvfc_retry_host_init(vhost); | ||
3130 | else | ||
3131 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3132 | ibmvfc_free_event(evt); | ||
3133 | return; | ||
3134 | case IBMVFC_MAD_CRQ_ERROR: | ||
3135 | ibmvfc_retry_host_init(vhost); | ||
3136 | case IBMVFC_MAD_DRIVER_FAILED: | ||
3137 | ibmvfc_free_event(evt); | ||
3138 | return; | ||
3139 | default: | ||
3140 | dev_err(vhost->dev, "Invalid NPIV Login response: 0x%x\n", mad_status); | ||
3141 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3142 | ibmvfc_free_event(evt); | ||
3143 | return; | ||
3144 | } | ||
3145 | |||
3146 | vhost->client_migrated = 0; | ||
3147 | |||
3148 | if (!(rsp->flags & IBMVFC_NATIVE_FC)) { | ||
3149 | dev_err(vhost->dev, "Virtual adapter does not support FC. %x\n", | ||
3150 | rsp->flags); | ||
3151 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3152 | wake_up(&vhost->work_wait_q); | ||
3153 | return; | ||
3154 | } | ||
3155 | |||
3156 | if (rsp->max_cmds <= IBMVFC_NUM_INTERNAL_REQ) { | ||
3157 | dev_err(vhost->dev, "Virtual adapter supported queue depth too small: %d\n", | ||
3158 | rsp->max_cmds); | ||
3159 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3160 | wake_up(&vhost->work_wait_q); | ||
3161 | return; | ||
3162 | } | ||
3163 | |||
3164 | npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); | ||
3165 | dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", | ||
3166 | rsp->partition_name, rsp->device_name, rsp->port_loc_code, | ||
3167 | rsp->drc_name, npiv_max_sectors); | ||
3168 | |||
3169 | fc_host_fabric_name(vhost->host) = rsp->node_name; | ||
3170 | fc_host_node_name(vhost->host) = rsp->node_name; | ||
3171 | fc_host_port_name(vhost->host) = rsp->port_name; | ||
3172 | fc_host_port_id(vhost->host) = rsp->scsi_id; | ||
3173 | fc_host_port_type(vhost->host) = FC_PORTTYPE_NPIV; | ||
3174 | fc_host_supported_classes(vhost->host) = 0; | ||
3175 | if (rsp->service_parms.class1_parms[0] & 0x80000000) | ||
3176 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS1; | ||
3177 | if (rsp->service_parms.class2_parms[0] & 0x80000000) | ||
3178 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS2; | ||
3179 | if (rsp->service_parms.class3_parms[0] & 0x80000000) | ||
3180 | fc_host_supported_classes(vhost->host) |= FC_COS_CLASS3; | ||
3181 | fc_host_maxframe_size(vhost->host) = | ||
3182 | rsp->service_parms.common.bb_rcv_sz & 0x0fff; | ||
3183 | |||
3184 | vhost->host->can_queue = rsp->max_cmds - IBMVFC_NUM_INTERNAL_REQ; | ||
3185 | vhost->host->max_sectors = npiv_max_sectors; | ||
3186 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
3187 | wake_up(&vhost->work_wait_q); | ||
3188 | } | ||
3189 | |||
3190 | /** | ||
3191 | * ibmvfc_npiv_login - Sends NPIV login | ||
3192 | * @vhost: ibmvfc host struct | ||
3193 | * | ||
3194 | **/ | ||
3195 | static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) | ||
3196 | { | ||
3197 | struct ibmvfc_npiv_login_mad *mad; | ||
3198 | struct ibmvfc_event *evt = ibmvfc_get_event(vhost); | ||
3199 | |||
3200 | ibmvfc_gather_partition_info(vhost); | ||
3201 | ibmvfc_set_login_info(vhost); | ||
3202 | ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT); | ||
3203 | |||
3204 | memcpy(vhost->login_buf, &vhost->login_info, sizeof(vhost->login_info)); | ||
3205 | mad = &evt->iu.npiv_login; | ||
3206 | memset(mad, 0, sizeof(struct ibmvfc_npiv_login_mad)); | ||
3207 | mad->common.version = 1; | ||
3208 | mad->common.opcode = IBMVFC_NPIV_LOGIN; | ||
3209 | mad->common.length = sizeof(struct ibmvfc_npiv_login_mad); | ||
3210 | mad->buffer.va = vhost->login_buf_dma; | ||
3211 | mad->buffer.len = sizeof(*vhost->login_buf); | ||
3212 | |||
3213 | memset(vhost->async_crq.msgs, 0, PAGE_SIZE); | ||
3214 | vhost->async_crq.cur = 0; | ||
3215 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); | ||
3216 | |||
3217 | if (!ibmvfc_send_event(evt, vhost, default_timeout)) | ||
3218 | ibmvfc_dbg(vhost, "Sent NPIV login\n"); | ||
3219 | else | ||
3220 | ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); | ||
3221 | }; | ||
3222 | |||
3223 | /** | ||
3224 | * ibmvfc_dev_init_to_do - Is there target initialization work to do? | ||
3225 | * @vhost: ibmvfc host struct | ||
3226 | * | ||
3227 | * Returns: | ||
3228 | * 1 if work to do / 0 if not | ||
3229 | **/ | ||
3230 | static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) | ||
3231 | { | ||
3232 | struct ibmvfc_target *tgt; | ||
3233 | |||
3234 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3235 | if (tgt->action == IBMVFC_TGT_ACTION_INIT || | ||
3236 | tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) | ||
3237 | return 1; | ||
3238 | } | ||
3239 | |||
3240 | return 0; | ||
3241 | } | ||
3242 | |||
3243 | /** | ||
3244 | * __ibmvfc_work_to_do - Is there task level work to do? (no locking) | ||
3245 | * @vhost: ibmvfc host struct | ||
3246 | * | ||
3247 | * Returns: | ||
3248 | * 1 if work to do / 0 if not | ||
3249 | **/ | ||
3250 | static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) | ||
3251 | { | ||
3252 | struct ibmvfc_target *tgt; | ||
3253 | |||
3254 | if (kthread_should_stop()) | ||
3255 | return 1; | ||
3256 | switch (vhost->action) { | ||
3257 | case IBMVFC_HOST_ACTION_NONE: | ||
3258 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
3259 | return 0; | ||
3260 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
3261 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
3262 | if (vhost->discovery_threads == disc_threads) | ||
3263 | return 0; | ||
3264 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3265 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) | ||
3266 | return 1; | ||
3267 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3268 | if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) | ||
3269 | return 0; | ||
3270 | return 1; | ||
3271 | case IBMVFC_HOST_ACTION_INIT: | ||
3272 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
3273 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
3274 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
3275 | case IBMVFC_HOST_ACTION_QUERY: | ||
3276 | default: | ||
3277 | break; | ||
3278 | }; | ||
3279 | |||
3280 | return 1; | ||
3281 | } | ||
3282 | |||
3283 | /** | ||
3284 | * ibmvfc_work_to_do - Is there task level work to do? | ||
3285 | * @vhost: ibmvfc host struct | ||
3286 | * | ||
3287 | * Returns: | ||
3288 | * 1 if work to do / 0 if not | ||
3289 | **/ | ||
3290 | static int ibmvfc_work_to_do(struct ibmvfc_host *vhost) | ||
3291 | { | ||
3292 | unsigned long flags; | ||
3293 | int rc; | ||
3294 | |||
3295 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3296 | rc = __ibmvfc_work_to_do(vhost); | ||
3297 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3298 | return rc; | ||
3299 | } | ||
3300 | |||
3301 | /** | ||
3302 | * ibmvfc_log_ae - Log async events if necessary | ||
3303 | * @vhost: ibmvfc host struct | ||
3304 | * @events: events to log | ||
3305 | * | ||
3306 | **/ | ||
3307 | static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) | ||
3308 | { | ||
3309 | if (events & IBMVFC_AE_RSCN) | ||
3310 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_RSCN, 0); | ||
3311 | if ((events & IBMVFC_AE_LINKDOWN) && | ||
3312 | vhost->state >= IBMVFC_HALTED) | ||
3313 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); | ||
3314 | if ((events & IBMVFC_AE_LINKUP) && | ||
3315 | vhost->state == IBMVFC_INITIALIZING) | ||
3316 | fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKUP, 0); | ||
3317 | } | ||
3318 | |||
3319 | /** | ||
3320 | * ibmvfc_tgt_add_rport - Tell the FC transport about a new remote port | ||
3321 | * @tgt: ibmvfc target struct | ||
3322 | * | ||
3323 | **/ | ||
3324 | static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) | ||
3325 | { | ||
3326 | struct ibmvfc_host *vhost = tgt->vhost; | ||
3327 | struct fc_rport *rport; | ||
3328 | unsigned long flags; | ||
3329 | |||
3330 | tgt_dbg(tgt, "Adding rport\n"); | ||
3331 | rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); | ||
3332 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3333 | tgt->rport = rport; | ||
3334 | ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); | ||
3335 | if (rport) { | ||
3336 | tgt_dbg(tgt, "rport add succeeded\n"); | ||
3337 | rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; | ||
3338 | rport->supported_classes = 0; | ||
3339 | if (tgt->service_parms.class1_parms[0] & 0x80000000) | ||
3340 | rport->supported_classes |= FC_COS_CLASS1; | ||
3341 | if (tgt->service_parms.class2_parms[0] & 0x80000000) | ||
3342 | rport->supported_classes |= FC_COS_CLASS2; | ||
3343 | if (tgt->service_parms.class3_parms[0] & 0x80000000) | ||
3344 | rport->supported_classes |= FC_COS_CLASS3; | ||
3345 | } else | ||
3346 | tgt_dbg(tgt, "rport add failed\n"); | ||
3347 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3348 | } | ||
3349 | |||
3350 | /** | ||
3351 | * ibmvfc_do_work - Do task level work | ||
3352 | * @vhost: ibmvfc host struct | ||
3353 | * | ||
3354 | **/ | ||
3355 | static void ibmvfc_do_work(struct ibmvfc_host *vhost) | ||
3356 | { | ||
3357 | struct ibmvfc_target *tgt; | ||
3358 | unsigned long flags; | ||
3359 | struct fc_rport *rport; | ||
3360 | |||
3361 | ibmvfc_log_ae(vhost, vhost->events_to_log); | ||
3362 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3363 | vhost->events_to_log = 0; | ||
3364 | switch (vhost->action) { | ||
3365 | case IBMVFC_HOST_ACTION_NONE: | ||
3366 | case IBMVFC_HOST_ACTION_INIT_WAIT: | ||
3367 | break; | ||
3368 | case IBMVFC_HOST_ACTION_INIT: | ||
3369 | BUG_ON(vhost->state != IBMVFC_INITIALIZING); | ||
3370 | vhost->job_step(vhost); | ||
3371 | break; | ||
3372 | case IBMVFC_HOST_ACTION_QUERY: | ||
3373 | list_for_each_entry(tgt, &vhost->targets, queue) | ||
3374 | ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target); | ||
3375 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY_TGTS); | ||
3376 | break; | ||
3377 | case IBMVFC_HOST_ACTION_QUERY_TGTS: | ||
3378 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3379 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) { | ||
3380 | tgt->job_step(tgt); | ||
3381 | break; | ||
3382 | } | ||
3383 | } | ||
3384 | |||
3385 | if (!ibmvfc_dev_init_to_do(vhost)) | ||
3386 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); | ||
3387 | break; | ||
3388 | case IBMVFC_HOST_ACTION_TGT_DEL: | ||
3389 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3390 | if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | ||
3391 | tgt_dbg(tgt, "Deleting rport\n"); | ||
3392 | rport = tgt->rport; | ||
3393 | tgt->rport = NULL; | ||
3394 | list_del(&tgt->queue); | ||
3395 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3396 | if (rport) | ||
3397 | fc_remote_port_delete(rport); | ||
3398 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3399 | return; | ||
3400 | } | ||
3401 | } | ||
3402 | |||
3403 | if (vhost->state == IBMVFC_INITIALIZING) { | ||
3404 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); | ||
3405 | vhost->job_step = ibmvfc_discover_targets; | ||
3406 | } else { | ||
3407 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
3408 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3409 | scsi_unblock_requests(vhost->host); | ||
3410 | wake_up(&vhost->init_wait_q); | ||
3411 | return; | ||
3412 | } | ||
3413 | break; | ||
3414 | case IBMVFC_HOST_ACTION_ALLOC_TGTS: | ||
3415 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_INIT); | ||
3416 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3417 | ibmvfc_alloc_targets(vhost); | ||
3418 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3419 | break; | ||
3420 | case IBMVFC_HOST_ACTION_TGT_INIT: | ||
3421 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3422 | if (tgt->action == IBMVFC_TGT_ACTION_INIT) { | ||
3423 | tgt->job_step(tgt); | ||
3424 | break; | ||
3425 | } | ||
3426 | } | ||
3427 | |||
3428 | if (!ibmvfc_dev_init_to_do(vhost)) { | ||
3429 | ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); | ||
3430 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_ADD); | ||
3431 | vhost->init_retries = 0; | ||
3432 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3433 | scsi_unblock_requests(vhost->host); | ||
3434 | return; | ||
3435 | } | ||
3436 | break; | ||
3437 | case IBMVFC_HOST_ACTION_TGT_ADD: | ||
3438 | list_for_each_entry(tgt, &vhost->targets, queue) { | ||
3439 | if (tgt->action == IBMVFC_TGT_ACTION_ADD_RPORT) { | ||
3440 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3441 | ibmvfc_tgt_add_rport(tgt); | ||
3442 | return; | ||
3443 | } else if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { | ||
3444 | tgt_dbg(tgt, "Deleting rport\n"); | ||
3445 | rport = tgt->rport; | ||
3446 | tgt->rport = NULL; | ||
3447 | list_del(&tgt->queue); | ||
3448 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3449 | if (rport) | ||
3450 | fc_remote_port_delete(rport); | ||
3451 | kref_put(&tgt->kref, ibmvfc_release_tgt); | ||
3452 | return; | ||
3453 | } | ||
3454 | } | ||
3455 | |||
3456 | if (vhost->reinit) { | ||
3457 | vhost->reinit = 0; | ||
3458 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); | ||
3459 | } else { | ||
3460 | ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); | ||
3461 | wake_up(&vhost->init_wait_q); | ||
3462 | } | ||
3463 | break; | ||
3464 | default: | ||
3465 | break; | ||
3466 | }; | ||
3467 | |||
3468 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3469 | } | ||
3470 | |||
3471 | /** | ||
3472 | * ibmvfc_work - Do task level work | ||
3473 | * @data: ibmvfc host struct | ||
3474 | * | ||
3475 | * Returns: | ||
3476 | * zero | ||
3477 | **/ | ||
3478 | static int ibmvfc_work(void *data) | ||
3479 | { | ||
3480 | struct ibmvfc_host *vhost = data; | ||
3481 | int rc; | ||
3482 | |||
3483 | set_user_nice(current, -20); | ||
3484 | |||
3485 | while (1) { | ||
3486 | rc = wait_event_interruptible(vhost->work_wait_q, | ||
3487 | ibmvfc_work_to_do(vhost)); | ||
3488 | |||
3489 | BUG_ON(rc); | ||
3490 | |||
3491 | if (kthread_should_stop()) | ||
3492 | break; | ||
3493 | |||
3494 | ibmvfc_do_work(vhost); | ||
3495 | } | ||
3496 | |||
3497 | ibmvfc_dbg(vhost, "ibmvfc kthread exiting...\n"); | ||
3498 | return 0; | ||
3499 | } | ||
3500 | |||
3501 | /** | ||
3502 | * ibmvfc_init_crq - Initializes and registers CRQ with hypervisor | ||
3503 | * @vhost: ibmvfc host struct | ||
3504 | * | ||
3505 | * Allocates a page for messages, maps it for dma, and registers | ||
3506 | * the crq with the hypervisor. | ||
3507 | * | ||
3508 | * Return value: | ||
3509 | * zero on success / other on failure | ||
3510 | **/ | ||
3511 | static int ibmvfc_init_crq(struct ibmvfc_host *vhost) | ||
3512 | { | ||
3513 | int rc, retrc = -ENOMEM; | ||
3514 | struct device *dev = vhost->dev; | ||
3515 | struct vio_dev *vdev = to_vio_dev(dev); | ||
3516 | struct ibmvfc_crq_queue *crq = &vhost->crq; | ||
3517 | |||
3518 | ENTER; | ||
3519 | crq->msgs = (struct ibmvfc_crq *)get_zeroed_page(GFP_KERNEL); | ||
3520 | |||
3521 | if (!crq->msgs) | ||
3522 | return -ENOMEM; | ||
3523 | |||
3524 | crq->size = PAGE_SIZE / sizeof(*crq->msgs); | ||
3525 | crq->msg_token = dma_map_single(dev, crq->msgs, | ||
3526 | PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
3527 | |||
3528 | if (dma_mapping_error(crq->msg_token)) | ||
3529 | goto map_failed; | ||
3530 | |||
3531 | retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, | ||
3532 | crq->msg_token, PAGE_SIZE); | ||
3533 | |||
3534 | if (rc == H_RESOURCE) | ||
3535 | /* maybe kexecing and resource is busy. try a reset */ | ||
3536 | retrc = rc = ibmvfc_reset_crq(vhost); | ||
3537 | |||
3538 | if (rc == H_CLOSED) | ||
3539 | dev_warn(dev, "Partner adapter not ready\n"); | ||
3540 | else if (rc) { | ||
3541 | dev_warn(dev, "Error %d opening adapter\n", rc); | ||
3542 | goto reg_crq_failed; | ||
3543 | } | ||
3544 | |||
3545 | retrc = 0; | ||
3546 | |||
3547 | if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { | ||
3548 | dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); | ||
3549 | goto req_irq_failed; | ||
3550 | } | ||
3551 | |||
3552 | if ((rc = vio_enable_interrupts(vdev))) { | ||
3553 | dev_err(dev, "Error %d enabling interrupts\n", rc); | ||
3554 | goto req_irq_failed; | ||
3555 | } | ||
3556 | |||
3557 | crq->cur = 0; | ||
3558 | LEAVE; | ||
3559 | return retrc; | ||
3560 | |||
3561 | req_irq_failed: | ||
3562 | do { | ||
3563 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
3564 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
3565 | reg_crq_failed: | ||
3566 | dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); | ||
3567 | map_failed: | ||
3568 | free_page((unsigned long)crq->msgs); | ||
3569 | return retrc; | ||
3570 | } | ||
3571 | |||
3572 | /** | ||
3573 | * ibmvfc_free_mem - Free memory for vhost | ||
3574 | * @vhost: ibmvfc host struct | ||
3575 | * | ||
3576 | * Return value: | ||
3577 | * none | ||
3578 | **/ | ||
3579 | static void ibmvfc_free_mem(struct ibmvfc_host *vhost) | ||
3580 | { | ||
3581 | struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; | ||
3582 | |||
3583 | ENTER; | ||
3584 | mempool_destroy(vhost->tgt_pool); | ||
3585 | kfree(vhost->trace); | ||
3586 | dma_free_coherent(vhost->dev, vhost->disc_buf_sz, vhost->disc_buf, | ||
3587 | vhost->disc_buf_dma); | ||
3588 | dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf), | ||
3589 | vhost->login_buf, vhost->login_buf_dma); | ||
3590 | dma_pool_destroy(vhost->sg_pool); | ||
3591 | dma_unmap_single(vhost->dev, async_q->msg_token, | ||
3592 | async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); | ||
3593 | free_page((unsigned long)async_q->msgs); | ||
3594 | LEAVE; | ||
3595 | } | ||
3596 | |||
3597 | /** | ||
3598 | * ibmvfc_alloc_mem - Allocate memory for vhost | ||
3599 | * @vhost: ibmvfc host struct | ||
3600 | * | ||
3601 | * Return value: | ||
3602 | * 0 on success / non-zero on failure | ||
3603 | **/ | ||
3604 | static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) | ||
3605 | { | ||
3606 | struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; | ||
3607 | struct device *dev = vhost->dev; | ||
3608 | |||
3609 | ENTER; | ||
3610 | async_q->msgs = (struct ibmvfc_async_crq *)get_zeroed_page(GFP_KERNEL); | ||
3611 | if (!async_q->msgs) { | ||
3612 | dev_err(dev, "Couldn't allocate async queue.\n"); | ||
3613 | goto nomem; | ||
3614 | } | ||
3615 | |||
3616 | async_q->size = PAGE_SIZE / sizeof(struct ibmvfc_async_crq); | ||
3617 | async_q->msg_token = dma_map_single(dev, async_q->msgs, | ||
3618 | async_q->size * sizeof(*async_q->msgs), | ||
3619 | DMA_BIDIRECTIONAL); | ||
3620 | |||
3621 | if (dma_mapping_error(async_q->msg_token)) { | ||
3622 | dev_err(dev, "Failed to map async queue\n"); | ||
3623 | goto free_async_crq; | ||
3624 | } | ||
3625 | |||
3626 | vhost->sg_pool = dma_pool_create(IBMVFC_NAME, dev, | ||
3627 | SG_ALL * sizeof(struct srp_direct_buf), | ||
3628 | sizeof(struct srp_direct_buf), 0); | ||
3629 | |||
3630 | if (!vhost->sg_pool) { | ||
3631 | dev_err(dev, "Failed to allocate sg pool\n"); | ||
3632 | goto unmap_async_crq; | ||
3633 | } | ||
3634 | |||
3635 | vhost->login_buf = dma_alloc_coherent(dev, sizeof(*vhost->login_buf), | ||
3636 | &vhost->login_buf_dma, GFP_KERNEL); | ||
3637 | |||
3638 | if (!vhost->login_buf) { | ||
3639 | dev_err(dev, "Couldn't allocate NPIV login buffer\n"); | ||
3640 | goto free_sg_pool; | ||
3641 | } | ||
3642 | |||
3643 | vhost->disc_buf_sz = sizeof(vhost->disc_buf->scsi_id[0]) * max_targets; | ||
3644 | vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz, | ||
3645 | &vhost->disc_buf_dma, GFP_KERNEL); | ||
3646 | |||
3647 | if (!vhost->disc_buf) { | ||
3648 | dev_err(dev, "Couldn't allocate Discover Targets buffer\n"); | ||
3649 | goto free_login_buffer; | ||
3650 | } | ||
3651 | |||
3652 | vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, | ||
3653 | sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); | ||
3654 | |||
3655 | if (!vhost->trace) | ||
3656 | goto free_disc_buffer; | ||
3657 | |||
3658 | vhost->tgt_pool = mempool_create_kzalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, | ||
3659 | sizeof(struct ibmvfc_target)); | ||
3660 | |||
3661 | if (!vhost->tgt_pool) { | ||
3662 | dev_err(dev, "Couldn't allocate target memory pool\n"); | ||
3663 | goto free_trace; | ||
3664 | } | ||
3665 | |||
3666 | LEAVE; | ||
3667 | return 0; | ||
3668 | |||
3669 | free_trace: | ||
3670 | kfree(vhost->trace); | ||
3671 | free_disc_buffer: | ||
3672 | dma_free_coherent(dev, vhost->disc_buf_sz, vhost->disc_buf, | ||
3673 | vhost->disc_buf_dma); | ||
3674 | free_login_buffer: | ||
3675 | dma_free_coherent(dev, sizeof(*vhost->login_buf), | ||
3676 | vhost->login_buf, vhost->login_buf_dma); | ||
3677 | free_sg_pool: | ||
3678 | dma_pool_destroy(vhost->sg_pool); | ||
3679 | unmap_async_crq: | ||
3680 | dma_unmap_single(dev, async_q->msg_token, | ||
3681 | async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); | ||
3682 | free_async_crq: | ||
3683 | free_page((unsigned long)async_q->msgs); | ||
3684 | nomem: | ||
3685 | LEAVE; | ||
3686 | return -ENOMEM; | ||
3687 | } | ||
3688 | |||
3689 | /** | ||
3690 | * ibmvfc_probe - Adapter hot plug add entry point | ||
3691 | * @vdev: vio device struct | ||
3692 | * @id: vio device id struct | ||
3693 | * | ||
3694 | * Return value: | ||
3695 | * 0 on success / non-zero on failure | ||
3696 | **/ | ||
3697 | static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
3698 | { | ||
3699 | struct ibmvfc_host *vhost; | ||
3700 | struct Scsi_Host *shost; | ||
3701 | struct device *dev = &vdev->dev; | ||
3702 | int rc = -ENOMEM; | ||
3703 | |||
3704 | ENTER; | ||
3705 | shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); | ||
3706 | if (!shost) { | ||
3707 | dev_err(dev, "Couldn't allocate host data\n"); | ||
3708 | goto out; | ||
3709 | } | ||
3710 | |||
3711 | shost->transportt = ibmvfc_transport_template; | ||
3712 | shost->can_queue = max_requests; | ||
3713 | shost->max_lun = max_lun; | ||
3714 | shost->max_id = max_targets; | ||
3715 | shost->max_sectors = IBMVFC_MAX_SECTORS; | ||
3716 | shost->max_cmd_len = IBMVFC_MAX_CDB_LEN; | ||
3717 | shost->unique_id = shost->host_no; | ||
3718 | |||
3719 | vhost = shost_priv(shost); | ||
3720 | INIT_LIST_HEAD(&vhost->sent); | ||
3721 | INIT_LIST_HEAD(&vhost->free); | ||
3722 | INIT_LIST_HEAD(&vhost->targets); | ||
3723 | sprintf(vhost->name, IBMVFC_NAME); | ||
3724 | vhost->host = shost; | ||
3725 | vhost->dev = dev; | ||
3726 | vhost->partition_number = -1; | ||
3727 | vhost->log_level = log_level; | ||
3728 | strcpy(vhost->partition_name, "UNKNOWN"); | ||
3729 | init_waitqueue_head(&vhost->work_wait_q); | ||
3730 | init_waitqueue_head(&vhost->init_wait_q); | ||
3731 | |||
3732 | if ((rc = ibmvfc_alloc_mem(vhost))) | ||
3733 | goto free_scsi_host; | ||
3734 | |||
3735 | vhost->work_thread = kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NAME, | ||
3736 | shost->host_no); | ||
3737 | |||
3738 | if (IS_ERR(vhost->work_thread)) { | ||
3739 | dev_err(dev, "Couldn't create kernel thread: %ld\n", | ||
3740 | PTR_ERR(vhost->work_thread)); | ||
3741 | goto free_host_mem; | ||
3742 | } | ||
3743 | |||
3744 | if ((rc = ibmvfc_init_crq(vhost))) { | ||
3745 | dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); | ||
3746 | goto kill_kthread; | ||
3747 | } | ||
3748 | |||
3749 | if ((rc = ibmvfc_init_event_pool(vhost))) { | ||
3750 | dev_err(dev, "Couldn't initialize event pool. rc=%d\n", rc); | ||
3751 | goto release_crq; | ||
3752 | } | ||
3753 | |||
3754 | if ((rc = scsi_add_host(shost, dev))) | ||
3755 | goto release_event_pool; | ||
3756 | |||
3757 | if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj, | ||
3758 | &ibmvfc_trace_attr))) { | ||
3759 | dev_err(dev, "Failed to create trace file. rc=%d\n", rc); | ||
3760 | goto remove_shost; | ||
3761 | } | ||
3762 | |||
3763 | dev_set_drvdata(dev, vhost); | ||
3764 | spin_lock(&ibmvfc_driver_lock); | ||
3765 | list_add_tail(&vhost->queue, &ibmvfc_head); | ||
3766 | spin_unlock(&ibmvfc_driver_lock); | ||
3767 | |||
3768 | ibmvfc_send_crq_init(vhost); | ||
3769 | scsi_scan_host(shost); | ||
3770 | return 0; | ||
3771 | |||
3772 | remove_shost: | ||
3773 | scsi_remove_host(shost); | ||
3774 | release_event_pool: | ||
3775 | ibmvfc_free_event_pool(vhost); | ||
3776 | release_crq: | ||
3777 | ibmvfc_release_crq_queue(vhost); | ||
3778 | kill_kthread: | ||
3779 | kthread_stop(vhost->work_thread); | ||
3780 | free_host_mem: | ||
3781 | ibmvfc_free_mem(vhost); | ||
3782 | free_scsi_host: | ||
3783 | scsi_host_put(shost); | ||
3784 | out: | ||
3785 | LEAVE; | ||
3786 | return rc; | ||
3787 | } | ||
3788 | |||
3789 | /** | ||
3790 | * ibmvfc_remove - Adapter hot plug remove entry point | ||
3791 | * @vdev: vio device struct | ||
3792 | * | ||
3793 | * Return value: | ||
3794 | * 0 | ||
3795 | **/ | ||
3796 | static int ibmvfc_remove(struct vio_dev *vdev) | ||
3797 | { | ||
3798 | struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev); | ||
3799 | unsigned long flags; | ||
3800 | |||
3801 | ENTER; | ||
3802 | ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); | ||
3803 | kthread_stop(vhost->work_thread); | ||
3804 | fc_remove_host(vhost->host); | ||
3805 | scsi_remove_host(vhost->host); | ||
3806 | ibmvfc_release_crq_queue(vhost); | ||
3807 | |||
3808 | spin_lock_irqsave(vhost->host->host_lock, flags); | ||
3809 | ibmvfc_purge_requests(vhost, DID_ERROR); | ||
3810 | ibmvfc_free_event_pool(vhost); | ||
3811 | spin_unlock_irqrestore(vhost->host->host_lock, flags); | ||
3812 | |||
3813 | ibmvfc_free_mem(vhost); | ||
3814 | spin_lock(&ibmvfc_driver_lock); | ||
3815 | list_del(&vhost->queue); | ||
3816 | spin_unlock(&ibmvfc_driver_lock); | ||
3817 | scsi_host_put(vhost->host); | ||
3818 | LEAVE; | ||
3819 | return 0; | ||
3820 | } | ||
3821 | |||
3822 | static struct vio_device_id ibmvfc_device_table[] __devinitdata = { | ||
3823 | {"fcp", "IBM,vfc-client"}, | ||
3824 | { "", "" } | ||
3825 | }; | ||
3826 | MODULE_DEVICE_TABLE(vio, ibmvfc_device_table); | ||
3827 | |||
3828 | static struct vio_driver ibmvfc_driver = { | ||
3829 | .id_table = ibmvfc_device_table, | ||
3830 | .probe = ibmvfc_probe, | ||
3831 | .remove = ibmvfc_remove, | ||
3832 | .driver = { | ||
3833 | .name = IBMVFC_NAME, | ||
3834 | .owner = THIS_MODULE, | ||
3835 | } | ||
3836 | }; | ||
3837 | |||
3838 | static struct fc_function_template ibmvfc_transport_functions = { | ||
3839 | .show_host_fabric_name = 1, | ||
3840 | .show_host_node_name = 1, | ||
3841 | .show_host_port_name = 1, | ||
3842 | .show_host_supported_classes = 1, | ||
3843 | .show_host_port_type = 1, | ||
3844 | .show_host_port_id = 1, | ||
3845 | |||
3846 | .get_host_port_state = ibmvfc_get_host_port_state, | ||
3847 | .show_host_port_state = 1, | ||
3848 | |||
3849 | .get_host_speed = ibmvfc_get_host_speed, | ||
3850 | .show_host_speed = 1, | ||
3851 | |||
3852 | .issue_fc_host_lip = ibmvfc_issue_fc_host_lip, | ||
3853 | .terminate_rport_io = ibmvfc_terminate_rport_io, | ||
3854 | |||
3855 | .show_rport_maxframe_size = 1, | ||
3856 | .show_rport_supported_classes = 1, | ||
3857 | |||
3858 | .set_rport_dev_loss_tmo = ibmvfc_set_rport_dev_loss_tmo, | ||
3859 | .show_rport_dev_loss_tmo = 1, | ||
3860 | |||
3861 | .get_starget_node_name = ibmvfc_get_starget_node_name, | ||
3862 | .show_starget_node_name = 1, | ||
3863 | |||
3864 | .get_starget_port_name = ibmvfc_get_starget_port_name, | ||
3865 | .show_starget_port_name = 1, | ||
3866 | |||
3867 | .get_starget_port_id = ibmvfc_get_starget_port_id, | ||
3868 | .show_starget_port_id = 1, | ||
3869 | }; | ||
3870 | |||
3871 | /** | ||
3872 | * ibmvfc_module_init - Initialize the ibmvfc module | ||
3873 | * | ||
3874 | * Return value: | ||
3875 | * 0 on success / other on failure | ||
3876 | **/ | ||
3877 | static int __init ibmvfc_module_init(void) | ||
3878 | { | ||
3879 | int rc; | ||
3880 | |||
3881 | if (!firmware_has_feature(FW_FEATURE_VIO)) | ||
3882 | return -ENODEV; | ||
3883 | |||
3884 | printk(KERN_INFO IBMVFC_NAME": IBM Virtual Fibre Channel Driver version: %s %s\n", | ||
3885 | IBMVFC_DRIVER_VERSION, IBMVFC_DRIVER_DATE); | ||
3886 | |||
3887 | ibmvfc_transport_template = fc_attach_transport(&ibmvfc_transport_functions); | ||
3888 | if (!ibmvfc_transport_template) | ||
3889 | return -ENOMEM; | ||
3890 | |||
3891 | rc = vio_register_driver(&ibmvfc_driver); | ||
3892 | if (rc) | ||
3893 | fc_release_transport(ibmvfc_transport_template); | ||
3894 | return rc; | ||
3895 | } | ||
3896 | |||
3897 | /** | ||
3898 | * ibmvfc_module_exit - Teardown the ibmvfc module | ||
3899 | * | ||
3900 | * Return value: | ||
3901 | * nothing | ||
3902 | **/ | ||
3903 | static void __exit ibmvfc_module_exit(void) | ||
3904 | { | ||
3905 | vio_unregister_driver(&ibmvfc_driver); | ||
3906 | fc_release_transport(ibmvfc_transport_template); | ||
3907 | } | ||
3908 | |||
3909 | module_init(ibmvfc_module_init); | ||
3910 | module_exit(ibmvfc_module_exit); | ||
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h new file mode 100644 index 000000000000..057f3c01ed61 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc.h | |||
@@ -0,0 +1,682 @@ | |||
1 | /* | ||
2 | * ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter | ||
3 | * | ||
4 | * Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation | ||
5 | * | ||
6 | * Copyright (C) IBM Corporation, 2008 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #ifndef _IBMVFC_H | ||
25 | #define _IBMVFC_H | ||
26 | |||
27 | #include <linux/list.h> | ||
28 | #include <linux/types.h> | ||
29 | #include "viosrp.h" | ||
30 | |||
31 | #define IBMVFC_NAME "ibmvfc" | ||
32 | #define IBMVFC_DRIVER_VERSION "1.0.0" | ||
33 | #define IBMVFC_DRIVER_DATE "(July 1, 2008)" | ||
34 | |||
35 | #define IBMVFC_DEFAULT_TIMEOUT 15 | ||
36 | #define IBMVFC_INIT_TIMEOUT 30 | ||
37 | #define IBMVFC_MAX_REQUESTS_DEFAULT 100 | ||
38 | |||
39 | #define IBMVFC_DEBUG 0 | ||
40 | #define IBMVFC_MAX_TARGETS 1024 | ||
41 | #define IBMVFC_MAX_LUN 0xffffffff | ||
42 | #define IBMVFC_MAX_SECTORS 0xffffu | ||
43 | #define IBMVFC_MAX_DISC_THREADS 4 | ||
44 | #define IBMVFC_TGT_MEMPOOL_SZ 64 | ||
45 | #define IBMVFC_MAX_CMDS_PER_LUN 64 | ||
46 | #define IBMVFC_MAX_INIT_RETRIES 3 | ||
47 | #define IBMVFC_DEV_LOSS_TMO (5 * 60) | ||
48 | #define IBMVFC_DEFAULT_LOG_LEVEL 2 | ||
49 | #define IBMVFC_MAX_CDB_LEN 16 | ||
50 | |||
51 | /* | ||
52 | * Ensure we have resources for ERP and initialization: | ||
53 | * 1 for ERP | ||
54 | * 1 for initialization | ||
55 | * 1 for each discovery thread | ||
56 | */ | ||
57 | #define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + disc_threads) | ||
58 | |||
59 | #define IBMVFC_MAD_SUCCESS 0x00 | ||
60 | #define IBMVFC_MAD_NOT_SUPPORTED 0xF1 | ||
61 | #define IBMVFC_MAD_FAILED 0xF7 | ||
62 | #define IBMVFC_MAD_DRIVER_FAILED 0xEE | ||
63 | #define IBMVFC_MAD_CRQ_ERROR 0xEF | ||
64 | |||
65 | enum ibmvfc_crq_valid { | ||
66 | IBMVFC_CRQ_CMD_RSP = 0x80, | ||
67 | IBMVFC_CRQ_INIT_RSP = 0xC0, | ||
68 | IBMVFC_CRQ_XPORT_EVENT = 0xFF, | ||
69 | }; | ||
70 | |||
71 | enum ibmvfc_crq_format { | ||
72 | IBMVFC_CRQ_INIT = 0x01, | ||
73 | IBMVFC_CRQ_INIT_COMPLETE = 0x02, | ||
74 | IBMVFC_PARTITION_MIGRATED = 0x06, | ||
75 | }; | ||
76 | |||
77 | enum ibmvfc_cmd_status_flags { | ||
78 | IBMVFC_FABRIC_MAPPED = 0x0001, | ||
79 | IBMVFC_VIOS_FAILURE = 0x0002, | ||
80 | IBMVFC_FC_FAILURE = 0x0004, | ||
81 | IBMVFC_FC_SCSI_ERROR = 0x0008, | ||
82 | IBMVFC_HW_EVENT_LOGGED = 0x0010, | ||
83 | IBMVFC_VIOS_LOGGED = 0x0020, | ||
84 | }; | ||
85 | |||
86 | enum ibmvfc_fabric_mapped_errors { | ||
87 | IBMVFC_UNABLE_TO_ESTABLISH = 0x0001, | ||
88 | IBMVFC_XPORT_FAULT = 0x0002, | ||
89 | IBMVFC_CMD_TIMEOUT = 0x0003, | ||
90 | IBMVFC_ENETDOWN = 0x0004, | ||
91 | IBMVFC_HW_FAILURE = 0x0005, | ||
92 | IBMVFC_LINK_DOWN_ERR = 0x0006, | ||
93 | IBMVFC_LINK_DEAD_ERR = 0x0007, | ||
94 | IBMVFC_UNABLE_TO_REGISTER = 0x0008, | ||
95 | IBMVFC_XPORT_BUSY = 0x000A, | ||
96 | IBMVFC_XPORT_DEAD = 0x000B, | ||
97 | IBMVFC_CONFIG_ERROR = 0x000C, | ||
98 | IBMVFC_NAME_SERVER_FAIL = 0x000D, | ||
99 | IBMVFC_LINK_HALTED = 0x000E, | ||
100 | IBMVFC_XPORT_GENERAL = 0x8000, | ||
101 | }; | ||
102 | |||
103 | enum ibmvfc_vios_errors { | ||
104 | IBMVFC_CRQ_FAILURE = 0x0001, | ||
105 | IBMVFC_SW_FAILURE = 0x0002, | ||
106 | IBMVFC_INVALID_PARAMETER = 0x0003, | ||
107 | IBMVFC_MISSING_PARAMETER = 0x0004, | ||
108 | IBMVFC_HOST_IO_BUS = 0x0005, | ||
109 | IBMVFC_TRANS_CANCELLED = 0x0006, | ||
110 | IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, | ||
111 | IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, | ||
112 | IBMVFC_COMMAND_FAILED = 0x8000, | ||
113 | }; | ||
114 | |||
115 | enum ibmvfc_mad_types { | ||
116 | IBMVFC_NPIV_LOGIN = 0x0001, | ||
117 | IBMVFC_DISC_TARGETS = 0x0002, | ||
118 | IBMVFC_PORT_LOGIN = 0x0004, | ||
119 | IBMVFC_PROCESS_LOGIN = 0x0008, | ||
120 | IBMVFC_QUERY_TARGET = 0x0010, | ||
121 | IBMVFC_IMPLICIT_LOGOUT = 0x0040, | ||
122 | IBMVFC_TMF_MAD = 0x0100, | ||
123 | }; | ||
124 | |||
125 | struct ibmvfc_mad_common { | ||
126 | u32 version; | ||
127 | u32 reserved; | ||
128 | u32 opcode; | ||
129 | u16 status; | ||
130 | u16 length; | ||
131 | u64 tag; | ||
132 | }__attribute__((packed, aligned (8))); | ||
133 | |||
134 | struct ibmvfc_npiv_login_mad { | ||
135 | struct ibmvfc_mad_common common; | ||
136 | struct srp_direct_buf buffer; | ||
137 | }__attribute__((packed, aligned (8))); | ||
138 | |||
139 | #define IBMVFC_MAX_NAME 256 | ||
140 | |||
141 | struct ibmvfc_npiv_login { | ||
142 | u32 ostype; | ||
143 | #define IBMVFC_OS_LINUX 0x02 | ||
144 | u32 pad; | ||
145 | u64 max_dma_len; | ||
146 | u32 max_payload; | ||
147 | u32 max_response; | ||
148 | u32 partition_num; | ||
149 | u32 vfc_frame_version; | ||
150 | u16 fcp_version; | ||
151 | u16 flags; | ||
152 | #define IBMVFC_CLIENT_MIGRATED 0x01 | ||
153 | #define IBMVFC_FLUSH_ON_HALT 0x02 | ||
154 | u32 max_cmds; | ||
155 | u64 capabilities; | ||
156 | #define IBMVFC_CAN_MIGRATE 0x01 | ||
157 | u64 node_name; | ||
158 | struct srp_direct_buf async; | ||
159 | u8 partition_name[IBMVFC_MAX_NAME]; | ||
160 | u8 device_name[IBMVFC_MAX_NAME]; | ||
161 | u8 drc_name[IBMVFC_MAX_NAME]; | ||
162 | u64 reserved2[2]; | ||
163 | }__attribute__((packed, aligned (8))); | ||
164 | |||
165 | struct ibmvfc_common_svc_parms { | ||
166 | u16 fcph_version; | ||
167 | u16 b2b_credit; | ||
168 | u16 features; | ||
169 | u16 bb_rcv_sz; /* upper nibble is BB_SC_N */ | ||
170 | u32 ratov; | ||
171 | u32 edtov; | ||
172 | }__attribute__((packed, aligned (4))); | ||
173 | |||
174 | struct ibmvfc_service_parms { | ||
175 | struct ibmvfc_common_svc_parms common; | ||
176 | u8 port_name[8]; | ||
177 | u8 node_name[8]; | ||
178 | u32 class1_parms[4]; | ||
179 | u32 class2_parms[4]; | ||
180 | u32 class3_parms[4]; | ||
181 | u32 obsolete[4]; | ||
182 | u32 vendor_version[4]; | ||
183 | u32 services_avail[2]; | ||
184 | u32 ext_len; | ||
185 | u32 reserved[30]; | ||
186 | u32 clk_sync_qos[2]; | ||
187 | }__attribute__((packed, aligned (4))); | ||
188 | |||
189 | struct ibmvfc_npiv_login_resp { | ||
190 | u32 version; | ||
191 | u16 status; | ||
192 | u16 error; | ||
193 | u32 flags; | ||
194 | #define IBMVFC_NATIVE_FC 0x01 | ||
195 | #define IBMVFC_CAN_FLUSH_ON_HALT 0x08 | ||
196 | u32 reserved; | ||
197 | u64 capabilites; | ||
198 | u32 max_cmds; | ||
199 | u32 scsi_id_sz; | ||
200 | u64 max_dma_len; | ||
201 | u64 scsi_id; | ||
202 | u64 port_name; | ||
203 | u64 node_name; | ||
204 | u64 link_speed; | ||
205 | u8 partition_name[IBMVFC_MAX_NAME]; | ||
206 | u8 device_name[IBMVFC_MAX_NAME]; | ||
207 | u8 port_loc_code[IBMVFC_MAX_NAME]; | ||
208 | u8 drc_name[IBMVFC_MAX_NAME]; | ||
209 | struct ibmvfc_service_parms service_parms; | ||
210 | u64 reserved2; | ||
211 | }__attribute__((packed, aligned (8))); | ||
212 | |||
213 | union ibmvfc_npiv_login_data { | ||
214 | struct ibmvfc_npiv_login login; | ||
215 | struct ibmvfc_npiv_login_resp resp; | ||
216 | }__attribute__((packed, aligned (8))); | ||
217 | |||
218 | struct ibmvfc_discover_targets_buf { | ||
219 | u32 scsi_id[1]; | ||
220 | #define IBMVFC_DISC_TGT_SCSI_ID_MASK 0x00ffffff | ||
221 | }; | ||
222 | |||
223 | struct ibmvfc_discover_targets { | ||
224 | struct ibmvfc_mad_common common; | ||
225 | struct srp_direct_buf buffer; | ||
226 | u32 flags; | ||
227 | u16 status; | ||
228 | u16 error; | ||
229 | u32 bufflen; | ||
230 | u32 num_avail; | ||
231 | u32 num_written; | ||
232 | u64 reserved[2]; | ||
233 | }__attribute__((packed, aligned (8))); | ||
234 | |||
235 | enum ibmvfc_fc_reason { | ||
236 | IBMVFC_INVALID_ELS_CMD_CODE = 0x01, | ||
237 | IBMVFC_INVALID_VERSION = 0x02, | ||
238 | IBMVFC_LOGICAL_ERROR = 0x03, | ||
239 | IBMVFC_INVALID_CT_IU_SIZE = 0x04, | ||
240 | IBMVFC_LOGICAL_BUSY = 0x05, | ||
241 | IBMVFC_PROTOCOL_ERROR = 0x07, | ||
242 | IBMVFC_UNABLE_TO_PERFORM_REQ = 0x09, | ||
243 | IBMVFC_CMD_NOT_SUPPORTED = 0x0B, | ||
244 | IBMVFC_SERVER_NOT_AVAIL = 0x0D, | ||
245 | IBMVFC_CMD_IN_PROGRESS = 0x0E, | ||
246 | IBMVFC_VENDOR_SPECIFIC = 0xFF, | ||
247 | }; | ||
248 | |||
249 | enum ibmvfc_fc_type { | ||
250 | IBMVFC_FABRIC_REJECT = 0x01, | ||
251 | IBMVFC_PORT_REJECT = 0x02, | ||
252 | IBMVFC_LS_REJECT = 0x03, | ||
253 | IBMVFC_FABRIC_BUSY = 0x04, | ||
254 | IBMVFC_PORT_BUSY = 0x05, | ||
255 | IBMVFC_BASIC_REJECT = 0x06, | ||
256 | }; | ||
257 | |||
258 | enum ibmvfc_gs_explain { | ||
259 | IBMVFC_PORT_NAME_NOT_REG = 0x02, | ||
260 | }; | ||
261 | |||
262 | struct ibmvfc_port_login { | ||
263 | struct ibmvfc_mad_common common; | ||
264 | u64 scsi_id; | ||
265 | u16 reserved; | ||
266 | u16 fc_service_class; | ||
267 | u32 blksz; | ||
268 | u32 hdr_per_blk; | ||
269 | u16 status; | ||
270 | u16 error; /* also fc_reason */ | ||
271 | u16 fc_explain; | ||
272 | u16 fc_type; | ||
273 | u32 reserved2; | ||
274 | struct ibmvfc_service_parms service_parms; | ||
275 | struct ibmvfc_service_parms service_parms_change; | ||
276 | u64 reserved3[2]; | ||
277 | }__attribute__((packed, aligned (8))); | ||
278 | |||
279 | struct ibmvfc_prli_svc_parms { | ||
280 | u8 type; | ||
281 | #define IBMVFC_SCSI_FCP_TYPE 0x08 | ||
282 | u8 type_ext; | ||
283 | u16 flags; | ||
284 | #define IBMVFC_PRLI_ORIG_PA_VALID 0x8000 | ||
285 | #define IBMVFC_PRLI_RESP_PA_VALID 0x4000 | ||
286 | #define IBMVFC_PRLI_EST_IMG_PAIR 0x2000 | ||
287 | u32 orig_pa; | ||
288 | u32 resp_pa; | ||
289 | u32 service_parms; | ||
290 | #define IBMVFC_PRLI_TASK_RETRY 0x00000200 | ||
291 | #define IBMVFC_PRLI_RETRY 0x00000100 | ||
292 | #define IBMVFC_PRLI_DATA_OVERLAY 0x00000040 | ||
293 | #define IBMVFC_PRLI_INITIATOR_FUNC 0x00000020 | ||
294 | #define IBMVFC_PRLI_TARGET_FUNC 0x00000010 | ||
295 | #define IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED 0x00000002 | ||
296 | #define IBMVFC_PRLI_WR_FCP_XFER_RDY_DISABLED 0x00000001 | ||
297 | }__attribute__((packed, aligned (4))); | ||
298 | |||
299 | struct ibmvfc_process_login { | ||
300 | struct ibmvfc_mad_common common; | ||
301 | u64 scsi_id; | ||
302 | struct ibmvfc_prli_svc_parms parms; | ||
303 | u8 reserved[48]; | ||
304 | u16 status; | ||
305 | u16 error; /* also fc_reason */ | ||
306 | u32 reserved2; | ||
307 | u64 reserved3[2]; | ||
308 | }__attribute__((packed, aligned (8))); | ||
309 | |||
310 | struct ibmvfc_query_tgt { | ||
311 | struct ibmvfc_mad_common common; | ||
312 | u64 wwpn; | ||
313 | u64 scsi_id; | ||
314 | u16 status; | ||
315 | u16 error; | ||
316 | u16 fc_explain; | ||
317 | u16 fc_type; | ||
318 | u64 reserved[2]; | ||
319 | }__attribute__((packed, aligned (8))); | ||
320 | |||
321 | struct ibmvfc_implicit_logout { | ||
322 | struct ibmvfc_mad_common common; | ||
323 | u64 old_scsi_id; | ||
324 | u64 reserved[2]; | ||
325 | }__attribute__((packed, aligned (8))); | ||
326 | |||
327 | struct ibmvfc_tmf { | ||
328 | struct ibmvfc_mad_common common; | ||
329 | u64 scsi_id; | ||
330 | struct scsi_lun lun; | ||
331 | u32 flags; | ||
332 | #define IBMVFC_TMF_ABORT_TASK 0x02 | ||
333 | #define IBMVFC_TMF_ABORT_TASK_SET 0x04 | ||
334 | #define IBMVFC_TMF_LUN_RESET 0x10 | ||
335 | #define IBMVFC_TMF_TGT_RESET 0x20 | ||
336 | #define IBMVFC_TMF_LUA_VALID 0x40 | ||
337 | u32 cancel_key; | ||
338 | u32 my_cancel_key; | ||
339 | #define IBMVFC_TMF_CANCEL_KEY 0x80000000 | ||
340 | u32 pad; | ||
341 | u64 reserved[2]; | ||
342 | }__attribute__((packed, aligned (8))); | ||
343 | |||
344 | enum ibmvfc_fcp_rsp_info_codes { | ||
345 | RSP_NO_FAILURE = 0x00, | ||
346 | RSP_TMF_REJECTED = 0x04, | ||
347 | RSP_TMF_FAILED = 0x05, | ||
348 | RSP_TMF_INVALID_LUN = 0x09, | ||
349 | }; | ||
350 | |||
351 | struct ibmvfc_fcp_rsp_info { | ||
352 | u16 reserved; | ||
353 | u8 rsp_code; | ||
354 | u8 reserved2[4]; | ||
355 | }__attribute__((packed, aligned (2))); | ||
356 | |||
357 | enum ibmvfc_fcp_rsp_flags { | ||
358 | FCP_BIDI_RSP = 0x80, | ||
359 | FCP_BIDI_READ_RESID_UNDER = 0x40, | ||
360 | FCP_BIDI_READ_RESID_OVER = 0x20, | ||
361 | FCP_CONF_REQ = 0x10, | ||
362 | FCP_RESID_UNDER = 0x08, | ||
363 | FCP_RESID_OVER = 0x04, | ||
364 | FCP_SNS_LEN_VALID = 0x02, | ||
365 | FCP_RSP_LEN_VALID = 0x01, | ||
366 | }; | ||
367 | |||
368 | union ibmvfc_fcp_rsp_data { | ||
369 | struct ibmvfc_fcp_rsp_info info; | ||
370 | u8 sense[SCSI_SENSE_BUFFERSIZE + sizeof(struct ibmvfc_fcp_rsp_info)]; | ||
371 | }__attribute__((packed, aligned (8))); | ||
372 | |||
373 | struct ibmvfc_fcp_rsp { | ||
374 | u64 reserved; | ||
375 | u16 retry_delay_timer; | ||
376 | u8 flags; | ||
377 | u8 scsi_status; | ||
378 | u32 fcp_resid; | ||
379 | u32 fcp_sense_len; | ||
380 | u32 fcp_rsp_len; | ||
381 | union ibmvfc_fcp_rsp_data data; | ||
382 | }__attribute__((packed, aligned (8))); | ||
383 | |||
384 | enum ibmvfc_cmd_flags { | ||
385 | IBMVFC_SCATTERLIST = 0x0001, | ||
386 | IBMVFC_NO_MEM_DESC = 0x0002, | ||
387 | IBMVFC_READ = 0x0004, | ||
388 | IBMVFC_WRITE = 0x0008, | ||
389 | IBMVFC_TMF = 0x0080, | ||
390 | IBMVFC_CLASS_3_ERR = 0x0100, | ||
391 | }; | ||
392 | |||
393 | enum ibmvfc_fc_task_attr { | ||
394 | IBMVFC_SIMPLE_TASK = 0x00, | ||
395 | IBMVFC_HEAD_OF_QUEUE = 0x01, | ||
396 | IBMVFC_ORDERED_TASK = 0x02, | ||
397 | IBMVFC_ACA_TASK = 0x04, | ||
398 | }; | ||
399 | |||
400 | enum ibmvfc_fc_tmf_flags { | ||
401 | IBMVFC_ABORT_TASK_SET = 0x02, | ||
402 | IBMVFC_LUN_RESET = 0x10, | ||
403 | IBMVFC_TARGET_RESET = 0x20, | ||
404 | }; | ||
405 | |||
406 | struct ibmvfc_fcp_cmd_iu { | ||
407 | struct scsi_lun lun; | ||
408 | u8 crn; | ||
409 | u8 pri_task_attr; | ||
410 | u8 tmf_flags; | ||
411 | u8 add_cdb_len; | ||
412 | #define IBMVFC_RDDATA 0x02 | ||
413 | #define IBMVFC_WRDATA 0x01 | ||
414 | u8 cdb[IBMVFC_MAX_CDB_LEN]; | ||
415 | u32 xfer_len; | ||
416 | }__attribute__((packed, aligned (4))); | ||
417 | |||
418 | struct ibmvfc_cmd { | ||
419 | u64 task_tag; | ||
420 | u32 frame_type; | ||
421 | u32 payload_len; | ||
422 | u32 resp_len; | ||
423 | u32 adapter_resid; | ||
424 | u16 status; | ||
425 | u16 error; | ||
426 | u16 flags; | ||
427 | u16 response_flags; | ||
428 | #define IBMVFC_ADAPTER_RESID_VALID 0x01 | ||
429 | u32 cancel_key; | ||
430 | u32 exchange_id; | ||
431 | struct srp_direct_buf ext_func; | ||
432 | struct srp_direct_buf ioba; | ||
433 | struct srp_direct_buf resp; | ||
434 | u64 correlation; | ||
435 | u64 tgt_scsi_id; | ||
436 | u64 tag; | ||
437 | u64 reserved3[2]; | ||
438 | struct ibmvfc_fcp_cmd_iu iu; | ||
439 | struct ibmvfc_fcp_rsp rsp; | ||
440 | }__attribute__((packed, aligned (8))); | ||
441 | |||
442 | struct ibmvfc_trace_start_entry { | ||
443 | u32 xfer_len; | ||
444 | }__attribute__((packed)); | ||
445 | |||
446 | struct ibmvfc_trace_end_entry { | ||
447 | u16 status; | ||
448 | u16 error; | ||
449 | u8 fcp_rsp_flags; | ||
450 | u8 rsp_code; | ||
451 | u8 scsi_status; | ||
452 | u8 reserved; | ||
453 | }__attribute__((packed)); | ||
454 | |||
455 | struct ibmvfc_trace_entry { | ||
456 | struct ibmvfc_event *evt; | ||
457 | u32 time; | ||
458 | u32 scsi_id; | ||
459 | u32 lun; | ||
460 | u8 fmt; | ||
461 | u8 op_code; | ||
462 | u8 tmf_flags; | ||
463 | u8 type; | ||
464 | #define IBMVFC_TRC_START 0x00 | ||
465 | #define IBMVFC_TRC_END 0xff | ||
466 | union { | ||
467 | struct ibmvfc_trace_start_entry start; | ||
468 | struct ibmvfc_trace_end_entry end; | ||
469 | } u; | ||
470 | }__attribute__((packed, aligned (8))); | ||
471 | |||
472 | enum ibmvfc_crq_formats { | ||
473 | IBMVFC_CMD_FORMAT = 0x01, | ||
474 | IBMVFC_ASYNC_EVENT = 0x02, | ||
475 | IBMVFC_MAD_FORMAT = 0x04, | ||
476 | }; | ||
477 | |||
478 | enum ibmvfc_async_event { | ||
479 | IBMVFC_AE_ELS_PLOGI = 0x0001, | ||
480 | IBMVFC_AE_ELS_LOGO = 0x0002, | ||
481 | IBMVFC_AE_ELS_PRLO = 0x0004, | ||
482 | IBMVFC_AE_SCN_NPORT = 0x0008, | ||
483 | IBMVFC_AE_SCN_GROUP = 0x0010, | ||
484 | IBMVFC_AE_SCN_DOMAIN = 0x0020, | ||
485 | IBMVFC_AE_SCN_FABRIC = 0x0040, | ||
486 | IBMVFC_AE_LINK_UP = 0x0080, | ||
487 | IBMVFC_AE_LINK_DOWN = 0x0100, | ||
488 | IBMVFC_AE_LINK_DEAD = 0x0200, | ||
489 | IBMVFC_AE_HALT = 0x0400, | ||
490 | IBMVFC_AE_RESUME = 0x0800, | ||
491 | IBMVFC_AE_ADAPTER_FAILED = 0x1000, | ||
492 | }; | ||
493 | |||
494 | struct ibmvfc_crq { | ||
495 | u8 valid; | ||
496 | u8 format; | ||
497 | u8 reserved[6]; | ||
498 | u64 ioba; | ||
499 | }__attribute__((packed, aligned (8))); | ||
500 | |||
501 | struct ibmvfc_crq_queue { | ||
502 | struct ibmvfc_crq *msgs; | ||
503 | int size, cur; | ||
504 | dma_addr_t msg_token; | ||
505 | }; | ||
506 | |||
507 | struct ibmvfc_async_crq { | ||
508 | u8 valid; | ||
509 | u8 pad[3]; | ||
510 | u32 pad2; | ||
511 | u64 event; | ||
512 | u64 scsi_id; | ||
513 | u64 wwpn; | ||
514 | u64 node_name; | ||
515 | u64 reserved; | ||
516 | }__attribute__((packed, aligned (8))); | ||
517 | |||
518 | struct ibmvfc_async_crq_queue { | ||
519 | struct ibmvfc_async_crq *msgs; | ||
520 | int size, cur; | ||
521 | dma_addr_t msg_token; | ||
522 | }; | ||
523 | |||
524 | union ibmvfc_iu { | ||
525 | struct ibmvfc_mad_common mad_common; | ||
526 | struct ibmvfc_npiv_login_mad npiv_login; | ||
527 | struct ibmvfc_discover_targets discover_targets; | ||
528 | struct ibmvfc_port_login plogi; | ||
529 | struct ibmvfc_process_login prli; | ||
530 | struct ibmvfc_query_tgt query_tgt; | ||
531 | struct ibmvfc_implicit_logout implicit_logout; | ||
532 | struct ibmvfc_tmf tmf; | ||
533 | struct ibmvfc_cmd cmd; | ||
534 | }__attribute__((packed, aligned (8))); | ||
535 | |||
536 | enum ibmvfc_target_action { | ||
537 | IBMVFC_TGT_ACTION_NONE = 0, | ||
538 | IBMVFC_TGT_ACTION_INIT, | ||
539 | IBMVFC_TGT_ACTION_INIT_WAIT, | ||
540 | IBMVFC_TGT_ACTION_ADD_RPORT, | ||
541 | IBMVFC_TGT_ACTION_DEL_RPORT, | ||
542 | }; | ||
543 | |||
544 | struct ibmvfc_target { | ||
545 | struct list_head queue; | ||
546 | struct ibmvfc_host *vhost; | ||
547 | u64 scsi_id; | ||
548 | u64 new_scsi_id; | ||
549 | struct fc_rport *rport; | ||
550 | int target_id; | ||
551 | enum ibmvfc_target_action action; | ||
552 | int need_login; | ||
553 | int init_retries; | ||
554 | struct ibmvfc_service_parms service_parms; | ||
555 | struct ibmvfc_service_parms service_parms_change; | ||
556 | struct fc_rport_identifiers ids; | ||
557 | void (*job_step) (struct ibmvfc_target *); | ||
558 | struct kref kref; | ||
559 | }; | ||
560 | |||
561 | /* a unit of work for the hosting partition */ | ||
562 | struct ibmvfc_event { | ||
563 | struct list_head queue; | ||
564 | struct ibmvfc_host *vhost; | ||
565 | struct ibmvfc_target *tgt; | ||
566 | struct scsi_cmnd *cmnd; | ||
567 | atomic_t free; | ||
568 | union ibmvfc_iu *xfer_iu; | ||
569 | void (*done) (struct ibmvfc_event *); | ||
570 | struct ibmvfc_crq crq; | ||
571 | union ibmvfc_iu iu; | ||
572 | union ibmvfc_iu *sync_iu; | ||
573 | struct srp_direct_buf *ext_list; | ||
574 | dma_addr_t ext_list_token; | ||
575 | struct completion comp; | ||
576 | struct timer_list timer; | ||
577 | }; | ||
578 | |||
579 | /* a pool of event structs for use */ | ||
580 | struct ibmvfc_event_pool { | ||
581 | struct ibmvfc_event *events; | ||
582 | u32 size; | ||
583 | union ibmvfc_iu *iu_storage; | ||
584 | dma_addr_t iu_token; | ||
585 | }; | ||
586 | |||
587 | enum ibmvfc_host_action { | ||
588 | IBMVFC_HOST_ACTION_NONE = 0, | ||
589 | IBMVFC_HOST_ACTION_INIT, | ||
590 | IBMVFC_HOST_ACTION_INIT_WAIT, | ||
591 | IBMVFC_HOST_ACTION_QUERY, | ||
592 | IBMVFC_HOST_ACTION_QUERY_TGTS, | ||
593 | IBMVFC_HOST_ACTION_TGT_DEL, | ||
594 | IBMVFC_HOST_ACTION_ALLOC_TGTS, | ||
595 | IBMVFC_HOST_ACTION_TGT_INIT, | ||
596 | IBMVFC_HOST_ACTION_TGT_ADD, | ||
597 | }; | ||
598 | |||
599 | enum ibmvfc_host_state { | ||
600 | IBMVFC_NO_CRQ = 0, | ||
601 | IBMVFC_INITIALIZING, | ||
602 | IBMVFC_ACTIVE, | ||
603 | IBMVFC_HALTED, | ||
604 | IBMVFC_LINK_DOWN, | ||
605 | IBMVFC_LINK_DEAD, | ||
606 | IBMVFC_HOST_OFFLINE, | ||
607 | }; | ||
608 | |||
609 | struct ibmvfc_host { | ||
610 | char name[8]; | ||
611 | struct list_head queue; | ||
612 | struct Scsi_Host *host; | ||
613 | enum ibmvfc_host_state state; | ||
614 | enum ibmvfc_host_action action; | ||
615 | #define IBMVFC_NUM_TRACE_INDEX_BITS 8 | ||
616 | #define IBMVFC_NUM_TRACE_ENTRIES (1 << IBMVFC_NUM_TRACE_INDEX_BITS) | ||
617 | #define IBMVFC_TRACE_SIZE (sizeof(struct ibmvfc_trace_entry) * IBMVFC_NUM_TRACE_ENTRIES) | ||
618 | struct ibmvfc_trace_entry *trace; | ||
619 | u32 trace_index:IBMVFC_NUM_TRACE_INDEX_BITS; | ||
620 | int num_targets; | ||
621 | struct list_head targets; | ||
622 | struct list_head sent; | ||
623 | struct list_head free; | ||
624 | struct device *dev; | ||
625 | struct ibmvfc_event_pool pool; | ||
626 | struct dma_pool *sg_pool; | ||
627 | mempool_t *tgt_pool; | ||
628 | struct ibmvfc_crq_queue crq; | ||
629 | struct ibmvfc_async_crq_queue async_crq; | ||
630 | struct ibmvfc_npiv_login login_info; | ||
631 | union ibmvfc_npiv_login_data *login_buf; | ||
632 | dma_addr_t login_buf_dma; | ||
633 | int disc_buf_sz; | ||
634 | int log_level; | ||
635 | struct ibmvfc_discover_targets_buf *disc_buf; | ||
636 | int task_set; | ||
637 | int init_retries; | ||
638 | int discovery_threads; | ||
639 | int client_migrated; | ||
640 | int reinit; | ||
641 | int events_to_log; | ||
642 | #define IBMVFC_AE_LINKUP 0x0001 | ||
643 | #define IBMVFC_AE_LINKDOWN 0x0002 | ||
644 | #define IBMVFC_AE_RSCN 0x0004 | ||
645 | dma_addr_t disc_buf_dma; | ||
646 | unsigned int partition_number; | ||
647 | char partition_name[97]; | ||
648 | void (*job_step) (struct ibmvfc_host *); | ||
649 | struct task_struct *work_thread; | ||
650 | wait_queue_head_t init_wait_q; | ||
651 | wait_queue_head_t work_wait_q; | ||
652 | }; | ||
653 | |||
654 | #define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0) | ||
655 | |||
656 | #define tgt_dbg(t, fmt, ...) \ | ||
657 | DBG_CMD(dev_info((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) | ||
658 | |||
659 | #define tgt_err(t, fmt, ...) \ | ||
660 | dev_err((t)->vhost->dev, "%lX: " fmt, (t)->scsi_id, ##__VA_ARGS__) | ||
661 | |||
662 | #define ibmvfc_dbg(vhost, ...) \ | ||
663 | DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__)) | ||
664 | |||
665 | #define ibmvfc_log(vhost, level, ...) \ | ||
666 | do { \ | ||
667 | if (level >= (vhost)->log_level) \ | ||
668 | dev_err((vhost)->dev, ##__VA_ARGS__); \ | ||
669 | } while (0) | ||
670 | |||
671 | #define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __FUNCTION__)) | ||
672 | #define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __FUNCTION__)) | ||
673 | |||
674 | #ifdef CONFIG_SCSI_IBMVFC_TRACE | ||
675 | #define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) | ||
676 | #define ibmvfc_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) | ||
677 | #else | ||
678 | #define ibmvfc_create_trace_file(kobj, attr) 0 | ||
679 | #define ibmvfc_remove_trace_file(kobj, attr) do { } while (0) | ||
680 | #endif | ||
681 | |||
682 | #endif | ||
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 72b9b2a0eba3..2a2f0094570f 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -64,6 +64,10 @@ MODULE_LICENSE("GPL"); | |||
64 | #define BUG_ON(expr) | 64 | #define BUG_ON(expr) |
65 | #endif | 65 | #endif |
66 | 66 | ||
67 | static struct scsi_transport_template *iscsi_tcp_scsi_transport; | ||
68 | static struct scsi_host_template iscsi_sht; | ||
69 | static struct iscsi_transport iscsi_tcp_transport; | ||
70 | |||
67 | static unsigned int iscsi_max_lun = 512; | 71 | static unsigned int iscsi_max_lun = 512; |
68 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); | 72 | module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); |
69 | 73 | ||
@@ -494,39 +498,43 @@ iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) | |||
494 | * must be called with session lock | 498 | * must be called with session lock |
495 | */ | 499 | */ |
496 | static void | 500 | static void |
497 | iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 501 | iscsi_tcp_cleanup_task(struct iscsi_conn *conn, struct iscsi_task *task) |
498 | { | 502 | { |
499 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 503 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
500 | struct iscsi_r2t_info *r2t; | 504 | struct iscsi_r2t_info *r2t; |
501 | 505 | ||
502 | /* flush ctask's r2t queues */ | 506 | /* nothing to do for mgmt tasks */ |
503 | while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) { | 507 | if (!task->sc) |
504 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 508 | return; |
509 | |||
510 | /* flush task's r2t queues */ | ||
511 | while (__kfifo_get(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) { | ||
512 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, | ||
505 | sizeof(void*)); | 513 | sizeof(void*)); |
506 | debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n"); | 514 | debug_scsi("iscsi_tcp_cleanup_task pending r2t dropped\n"); |
507 | } | 515 | } |
508 | 516 | ||
509 | r2t = tcp_ctask->r2t; | 517 | r2t = tcp_task->r2t; |
510 | if (r2t != NULL) { | 518 | if (r2t != NULL) { |
511 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 519 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
512 | sizeof(void*)); | 520 | sizeof(void*)); |
513 | tcp_ctask->r2t = NULL; | 521 | tcp_task->r2t = NULL; |
514 | } | 522 | } |
515 | } | 523 | } |
516 | 524 | ||
517 | /** | 525 | /** |
518 | * iscsi_data_rsp - SCSI Data-In Response processing | 526 | * iscsi_data_rsp - SCSI Data-In Response processing |
519 | * @conn: iscsi connection | 527 | * @conn: iscsi connection |
520 | * @ctask: scsi command task | 528 | * @task: scsi command task |
521 | **/ | 529 | **/ |
522 | static int | 530 | static int |
523 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 531 | iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_task *task) |
524 | { | 532 | { |
525 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 533 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
526 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 534 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
527 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; | 535 | struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; |
528 | struct iscsi_session *session = conn->session; | 536 | struct iscsi_session *session = conn->session; |
529 | struct scsi_cmnd *sc = ctask->sc; | 537 | struct scsi_cmnd *sc = task->sc; |
530 | int datasn = be32_to_cpu(rhdr->datasn); | 538 | int datasn = be32_to_cpu(rhdr->datasn); |
531 | unsigned total_in_length = scsi_in(sc)->length; | 539 | unsigned total_in_length = scsi_in(sc)->length; |
532 | 540 | ||
@@ -534,18 +542,18 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
534 | if (tcp_conn->in.datalen == 0) | 542 | if (tcp_conn->in.datalen == 0) |
535 | return 0; | 543 | return 0; |
536 | 544 | ||
537 | if (tcp_ctask->exp_datasn != datasn) { | 545 | if (tcp_task->exp_datasn != datasn) { |
538 | debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->datasn(%d)\n", | 546 | debug_tcp("%s: task->exp_datasn(%d) != rhdr->datasn(%d)\n", |
539 | __FUNCTION__, tcp_ctask->exp_datasn, datasn); | 547 | __func__, tcp_task->exp_datasn, datasn); |
540 | return ISCSI_ERR_DATASN; | 548 | return ISCSI_ERR_DATASN; |
541 | } | 549 | } |
542 | 550 | ||
543 | tcp_ctask->exp_datasn++; | 551 | tcp_task->exp_datasn++; |
544 | 552 | ||
545 | tcp_ctask->data_offset = be32_to_cpu(rhdr->offset); | 553 | tcp_task->data_offset = be32_to_cpu(rhdr->offset); |
546 | if (tcp_ctask->data_offset + tcp_conn->in.datalen > total_in_length) { | 554 | if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) { |
547 | debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", | 555 | debug_tcp("%s: data_offset(%d) + data_len(%d) > total_length_in(%d)\n", |
548 | __FUNCTION__, tcp_ctask->data_offset, | 556 | __func__, tcp_task->data_offset, |
549 | tcp_conn->in.datalen, total_in_length); | 557 | tcp_conn->in.datalen, total_in_length); |
550 | return ISCSI_ERR_DATA_OFFSET; | 558 | return ISCSI_ERR_DATA_OFFSET; |
551 | } | 559 | } |
@@ -574,7 +582,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
574 | /** | 582 | /** |
575 | * iscsi_solicit_data_init - initialize first Data-Out | 583 | * iscsi_solicit_data_init - initialize first Data-Out |
576 | * @conn: iscsi connection | 584 | * @conn: iscsi connection |
577 | * @ctask: scsi command task | 585 | * @task: scsi command task |
578 | * @r2t: R2T info | 586 | * @r2t: R2T info |
579 | * | 587 | * |
580 | * Notes: | 588 | * Notes: |
@@ -584,7 +592,7 @@ iscsi_data_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
584 | * This function is called with connection lock taken. | 592 | * This function is called with connection lock taken. |
585 | **/ | 593 | **/ |
586 | static void | 594 | static void |
587 | iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 595 | iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_task *task, |
588 | struct iscsi_r2t_info *r2t) | 596 | struct iscsi_r2t_info *r2t) |
589 | { | 597 | { |
590 | struct iscsi_data *hdr; | 598 | struct iscsi_data *hdr; |
@@ -595,8 +603,8 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
595 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); | 603 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); |
596 | r2t->solicit_datasn++; | 604 | r2t->solicit_datasn++; |
597 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 605 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
598 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 606 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
599 | hdr->itt = ctask->hdr->itt; | 607 | hdr->itt = task->hdr->itt; |
600 | hdr->exp_statsn = r2t->exp_statsn; | 608 | hdr->exp_statsn = r2t->exp_statsn; |
601 | hdr->offset = cpu_to_be32(r2t->data_offset); | 609 | hdr->offset = cpu_to_be32(r2t->data_offset); |
602 | if (r2t->data_length > conn->max_xmit_dlength) { | 610 | if (r2t->data_length > conn->max_xmit_dlength) { |
@@ -616,14 +624,14 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
616 | /** | 624 | /** |
617 | * iscsi_r2t_rsp - iSCSI R2T Response processing | 625 | * iscsi_r2t_rsp - iSCSI R2T Response processing |
618 | * @conn: iscsi connection | 626 | * @conn: iscsi connection |
619 | * @ctask: scsi command task | 627 | * @task: scsi command task |
620 | **/ | 628 | **/ |
621 | static int | 629 | static int |
622 | iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 630 | iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) |
623 | { | 631 | { |
624 | struct iscsi_r2t_info *r2t; | 632 | struct iscsi_r2t_info *r2t; |
625 | struct iscsi_session *session = conn->session; | 633 | struct iscsi_session *session = conn->session; |
626 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 634 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
627 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 635 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
628 | struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; | 636 | struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; |
629 | int r2tsn = be32_to_cpu(rhdr->r2tsn); | 637 | int r2tsn = be32_to_cpu(rhdr->r2tsn); |
@@ -636,23 +644,23 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
636 | return ISCSI_ERR_DATALEN; | 644 | return ISCSI_ERR_DATALEN; |
637 | } | 645 | } |
638 | 646 | ||
639 | if (tcp_ctask->exp_datasn != r2tsn){ | 647 | if (tcp_task->exp_datasn != r2tsn){ |
640 | debug_tcp("%s: ctask->exp_datasn(%d) != rhdr->r2tsn(%d)\n", | 648 | debug_tcp("%s: task->exp_datasn(%d) != rhdr->r2tsn(%d)\n", |
641 | __FUNCTION__, tcp_ctask->exp_datasn, r2tsn); | 649 | __func__, tcp_task->exp_datasn, r2tsn); |
642 | return ISCSI_ERR_R2TSN; | 650 | return ISCSI_ERR_R2TSN; |
643 | } | 651 | } |
644 | 652 | ||
645 | /* fill-in new R2T associated with the task */ | 653 | /* fill-in new R2T associated with the task */ |
646 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); | 654 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
647 | 655 | ||
648 | if (!ctask->sc || session->state != ISCSI_STATE_LOGGED_IN) { | 656 | if (!task->sc || session->state != ISCSI_STATE_LOGGED_IN) { |
649 | iscsi_conn_printk(KERN_INFO, conn, | 657 | iscsi_conn_printk(KERN_INFO, conn, |
650 | "dropping R2T itt %d in recovery.\n", | 658 | "dropping R2T itt %d in recovery.\n", |
651 | ctask->itt); | 659 | task->itt); |
652 | return 0; | 660 | return 0; |
653 | } | 661 | } |
654 | 662 | ||
655 | rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*)); | 663 | rc = __kfifo_get(tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); |
656 | BUG_ON(!rc); | 664 | BUG_ON(!rc); |
657 | 665 | ||
658 | r2t->exp_statsn = rhdr->statsn; | 666 | r2t->exp_statsn = rhdr->statsn; |
@@ -660,7 +668,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
660 | if (r2t->data_length == 0) { | 668 | if (r2t->data_length == 0) { |
661 | iscsi_conn_printk(KERN_ERR, conn, | 669 | iscsi_conn_printk(KERN_ERR, conn, |
662 | "invalid R2T with zero data len\n"); | 670 | "invalid R2T with zero data len\n"); |
663 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 671 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
664 | sizeof(void*)); | 672 | sizeof(void*)); |
665 | return ISCSI_ERR_DATALEN; | 673 | return ISCSI_ERR_DATALEN; |
666 | } | 674 | } |
@@ -671,12 +679,12 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
671 | r2t->data_length, session->max_burst); | 679 | r2t->data_length, session->max_burst); |
672 | 680 | ||
673 | r2t->data_offset = be32_to_cpu(rhdr->data_offset); | 681 | r2t->data_offset = be32_to_cpu(rhdr->data_offset); |
674 | if (r2t->data_offset + r2t->data_length > scsi_out(ctask->sc)->length) { | 682 | if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { |
675 | iscsi_conn_printk(KERN_ERR, conn, | 683 | iscsi_conn_printk(KERN_ERR, conn, |
676 | "invalid R2T with data len %u at offset %u " | 684 | "invalid R2T with data len %u at offset %u " |
677 | "and total length %d\n", r2t->data_length, | 685 | "and total length %d\n", r2t->data_length, |
678 | r2t->data_offset, scsi_out(ctask->sc)->length); | 686 | r2t->data_offset, scsi_out(task->sc)->length); |
679 | __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, | 687 | __kfifo_put(tcp_task->r2tpool.queue, (void*)&r2t, |
680 | sizeof(void*)); | 688 | sizeof(void*)); |
681 | return ISCSI_ERR_DATALEN; | 689 | return ISCSI_ERR_DATALEN; |
682 | } | 690 | } |
@@ -684,13 +692,13 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | |||
684 | r2t->ttt = rhdr->ttt; /* no flip */ | 692 | r2t->ttt = rhdr->ttt; /* no flip */ |
685 | r2t->solicit_datasn = 0; | 693 | r2t->solicit_datasn = 0; |
686 | 694 | ||
687 | iscsi_solicit_data_init(conn, ctask, r2t); | 695 | iscsi_solicit_data_init(conn, task, r2t); |
688 | 696 | ||
689 | tcp_ctask->exp_datasn = r2tsn + 1; | 697 | tcp_task->exp_datasn = r2tsn + 1; |
690 | __kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)); | 698 | __kfifo_put(tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); |
691 | conn->r2t_pdus_cnt++; | 699 | conn->r2t_pdus_cnt++; |
692 | 700 | ||
693 | iscsi_requeue_ctask(ctask); | 701 | iscsi_requeue_task(task); |
694 | return 0; | 702 | return 0; |
695 | } | 703 | } |
696 | 704 | ||
@@ -733,10 +741,8 @@ static int | |||
733 | iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 741 | iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
734 | { | 742 | { |
735 | int rc = 0, opcode, ahslen; | 743 | int rc = 0, opcode, ahslen; |
736 | struct iscsi_session *session = conn->session; | ||
737 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 744 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
738 | struct iscsi_cmd_task *ctask; | 745 | struct iscsi_task *task; |
739 | uint32_t itt; | ||
740 | 746 | ||
741 | /* verify PDU length */ | 747 | /* verify PDU length */ |
742 | tcp_conn->in.datalen = ntoh24(hdr->dlength); | 748 | tcp_conn->in.datalen = ntoh24(hdr->dlength); |
@@ -754,7 +760,7 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
754 | 760 | ||
755 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; | 761 | opcode = hdr->opcode & ISCSI_OPCODE_MASK; |
756 | /* verify itt (itt encoding: age+cid+itt) */ | 762 | /* verify itt (itt encoding: age+cid+itt) */ |
757 | rc = iscsi_verify_itt(conn, hdr, &itt); | 763 | rc = iscsi_verify_itt(conn, hdr->itt); |
758 | if (rc) | 764 | if (rc) |
759 | return rc; | 765 | return rc; |
760 | 766 | ||
@@ -763,16 +769,21 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
763 | 769 | ||
764 | switch(opcode) { | 770 | switch(opcode) { |
765 | case ISCSI_OP_SCSI_DATA_IN: | 771 | case ISCSI_OP_SCSI_DATA_IN: |
766 | ctask = session->cmds[itt]; | ||
767 | spin_lock(&conn->session->lock); | 772 | spin_lock(&conn->session->lock); |
768 | rc = iscsi_data_rsp(conn, ctask); | 773 | task = iscsi_itt_to_ctask(conn, hdr->itt); |
769 | spin_unlock(&conn->session->lock); | 774 | if (!task) |
770 | if (rc) | 775 | rc = ISCSI_ERR_BAD_ITT; |
771 | return rc; | 776 | else |
777 | rc = iscsi_data_rsp(conn, task); | ||
778 | if (rc) { | ||
779 | spin_unlock(&conn->session->lock); | ||
780 | break; | ||
781 | } | ||
782 | |||
772 | if (tcp_conn->in.datalen) { | 783 | if (tcp_conn->in.datalen) { |
773 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 784 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
774 | struct hash_desc *rx_hash = NULL; | 785 | struct hash_desc *rx_hash = NULL; |
775 | struct scsi_data_buffer *sdb = scsi_in(ctask->sc); | 786 | struct scsi_data_buffer *sdb = scsi_in(task->sc); |
776 | 787 | ||
777 | /* | 788 | /* |
778 | * Setup copy of Data-In into the Scsi_Cmnd | 789 | * Setup copy of Data-In into the Scsi_Cmnd |
@@ -787,17 +798,21 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
787 | 798 | ||
788 | debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " | 799 | debug_tcp("iscsi_tcp_begin_data_in(%p, offset=%d, " |
789 | "datalen=%d)\n", tcp_conn, | 800 | "datalen=%d)\n", tcp_conn, |
790 | tcp_ctask->data_offset, | 801 | tcp_task->data_offset, |
791 | tcp_conn->in.datalen); | 802 | tcp_conn->in.datalen); |
792 | return iscsi_segment_seek_sg(&tcp_conn->in.segment, | 803 | rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, |
793 | sdb->table.sgl, | 804 | sdb->table.sgl, |
794 | sdb->table.nents, | 805 | sdb->table.nents, |
795 | tcp_ctask->data_offset, | 806 | tcp_task->data_offset, |
796 | tcp_conn->in.datalen, | 807 | tcp_conn->in.datalen, |
797 | iscsi_tcp_process_data_in, | 808 | iscsi_tcp_process_data_in, |
798 | rx_hash); | 809 | rx_hash); |
810 | spin_unlock(&conn->session->lock); | ||
811 | return rc; | ||
799 | } | 812 | } |
800 | /* fall through */ | 813 | rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); |
814 | spin_unlock(&conn->session->lock); | ||
815 | break; | ||
801 | case ISCSI_OP_SCSI_CMD_RSP: | 816 | case ISCSI_OP_SCSI_CMD_RSP: |
802 | if (tcp_conn->in.datalen) { | 817 | if (tcp_conn->in.datalen) { |
803 | iscsi_tcp_data_recv_prep(tcp_conn); | 818 | iscsi_tcp_data_recv_prep(tcp_conn); |
@@ -806,15 +821,17 @@ iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
806 | rc = iscsi_complete_pdu(conn, hdr, NULL, 0); | 821 | rc = iscsi_complete_pdu(conn, hdr, NULL, 0); |
807 | break; | 822 | break; |
808 | case ISCSI_OP_R2T: | 823 | case ISCSI_OP_R2T: |
809 | ctask = session->cmds[itt]; | 824 | spin_lock(&conn->session->lock); |
810 | if (ahslen) | 825 | task = iscsi_itt_to_ctask(conn, hdr->itt); |
826 | if (!task) | ||
827 | rc = ISCSI_ERR_BAD_ITT; | ||
828 | else if (ahslen) | ||
811 | rc = ISCSI_ERR_AHSLEN; | 829 | rc = ISCSI_ERR_AHSLEN; |
812 | else if (ctask->sc->sc_data_direction == DMA_TO_DEVICE) { | 830 | else if (task->sc->sc_data_direction == DMA_TO_DEVICE) |
813 | spin_lock(&session->lock); | 831 | rc = iscsi_r2t_rsp(conn, task); |
814 | rc = iscsi_r2t_rsp(conn, ctask); | 832 | else |
815 | spin_unlock(&session->lock); | ||
816 | } else | ||
817 | rc = ISCSI_ERR_PROTO; | 833 | rc = ISCSI_ERR_PROTO; |
834 | spin_unlock(&conn->session->lock); | ||
818 | break; | 835 | break; |
819 | case ISCSI_OP_LOGIN_RSP: | 836 | case ISCSI_OP_LOGIN_RSP: |
820 | case ISCSI_OP_TEXT_RSP: | 837 | case ISCSI_OP_TEXT_RSP: |
@@ -1176,7 +1193,7 @@ iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) | |||
1176 | { | 1193 | { |
1177 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1194 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1178 | 1195 | ||
1179 | debug_tcp("%s(%p%s)\n", __FUNCTION__, tcp_conn, | 1196 | debug_tcp("%s(%p%s)\n", __func__, tcp_conn, |
1180 | conn->hdrdgst_en? ", digest enabled" : ""); | 1197 | conn->hdrdgst_en? ", digest enabled" : ""); |
1181 | 1198 | ||
1182 | /* Clear the data segment - needs to be filled in by the | 1199 | /* Clear the data segment - needs to be filled in by the |
@@ -1185,7 +1202,7 @@ iscsi_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, size_t hdrlen) | |||
1185 | 1202 | ||
1186 | /* If header digest is enabled, compute the CRC and | 1203 | /* If header digest is enabled, compute the CRC and |
1187 | * place the digest into the same buffer. We make | 1204 | * place the digest into the same buffer. We make |
1188 | * sure that both iscsi_tcp_ctask and mtask have | 1205 | * sure that both iscsi_tcp_task and mtask have |
1189 | * sufficient room. | 1206 | * sufficient room. |
1190 | */ | 1207 | */ |
1191 | if (conn->hdrdgst_en) { | 1208 | if (conn->hdrdgst_en) { |
@@ -1217,7 +1234,7 @@ iscsi_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, | |||
1217 | struct hash_desc *tx_hash = NULL; | 1234 | struct hash_desc *tx_hash = NULL; |
1218 | unsigned int hdr_spec_len; | 1235 | unsigned int hdr_spec_len; |
1219 | 1236 | ||
1220 | debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __FUNCTION__, | 1237 | debug_tcp("%s(%p, offset=%d, datalen=%d%s)\n", __func__, |
1221 | tcp_conn, offset, len, | 1238 | tcp_conn, offset, len, |
1222 | conn->datadgst_en? ", digest enabled" : ""); | 1239 | conn->datadgst_en? ", digest enabled" : ""); |
1223 | 1240 | ||
@@ -1242,7 +1259,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1242 | struct hash_desc *tx_hash = NULL; | 1259 | struct hash_desc *tx_hash = NULL; |
1243 | unsigned int hdr_spec_len; | 1260 | unsigned int hdr_spec_len; |
1244 | 1261 | ||
1245 | debug_tcp("%s(%p, datalen=%d%s)\n", __FUNCTION__, tcp_conn, len, | 1262 | debug_tcp("%s(%p, datalen=%d%s)\n", __func__, tcp_conn, len, |
1246 | conn->datadgst_en? ", digest enabled" : ""); | 1263 | conn->datadgst_en? ", digest enabled" : ""); |
1247 | 1264 | ||
1248 | /* Make sure the datalen matches what the caller | 1265 | /* Make sure the datalen matches what the caller |
@@ -1260,7 +1277,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1260 | /** | 1277 | /** |
1261 | * iscsi_solicit_data_cont - initialize next Data-Out | 1278 | * iscsi_solicit_data_cont - initialize next Data-Out |
1262 | * @conn: iscsi connection | 1279 | * @conn: iscsi connection |
1263 | * @ctask: scsi command task | 1280 | * @task: scsi command task |
1264 | * @r2t: R2T info | 1281 | * @r2t: R2T info |
1265 | * @left: bytes left to transfer | 1282 | * @left: bytes left to transfer |
1266 | * | 1283 | * |
@@ -1271,7 +1288,7 @@ iscsi_tcp_send_linear_data_prepare(struct iscsi_conn *conn, void *data, | |||
1271 | * Called under connection lock. | 1288 | * Called under connection lock. |
1272 | **/ | 1289 | **/ |
1273 | static int | 1290 | static int |
1274 | iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 1291 | iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_task *task, |
1275 | struct iscsi_r2t_info *r2t) | 1292 | struct iscsi_r2t_info *r2t) |
1276 | { | 1293 | { |
1277 | struct iscsi_data *hdr; | 1294 | struct iscsi_data *hdr; |
@@ -1288,8 +1305,8 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1288 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); | 1305 | hdr->datasn = cpu_to_be32(r2t->solicit_datasn); |
1289 | r2t->solicit_datasn++; | 1306 | r2t->solicit_datasn++; |
1290 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 1307 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
1291 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 1308 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
1292 | hdr->itt = ctask->hdr->itt; | 1309 | hdr->itt = task->hdr->itt; |
1293 | hdr->exp_statsn = r2t->exp_statsn; | 1310 | hdr->exp_statsn = r2t->exp_statsn; |
1294 | new_offset = r2t->data_offset + r2t->sent; | 1311 | new_offset = r2t->data_offset + r2t->sent; |
1295 | hdr->offset = cpu_to_be32(new_offset); | 1312 | hdr->offset = cpu_to_be32(new_offset); |
@@ -1307,89 +1324,76 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
1307 | } | 1324 | } |
1308 | 1325 | ||
1309 | /** | 1326 | /** |
1310 | * iscsi_tcp_ctask - Initialize iSCSI SCSI_READ or SCSI_WRITE commands | 1327 | * iscsi_tcp_task - Initialize iSCSI SCSI_READ or SCSI_WRITE commands |
1311 | * @conn: iscsi connection | 1328 | * @conn: iscsi connection |
1312 | * @ctask: scsi command task | 1329 | * @task: scsi command task |
1313 | * @sc: scsi command | 1330 | * @sc: scsi command |
1314 | **/ | 1331 | **/ |
1315 | static int | 1332 | static int |
1316 | iscsi_tcp_ctask_init(struct iscsi_cmd_task *ctask) | 1333 | iscsi_tcp_task_init(struct iscsi_task *task) |
1317 | { | 1334 | { |
1318 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1335 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1319 | struct iscsi_conn *conn = ctask->conn; | 1336 | struct iscsi_conn *conn = task->conn; |
1320 | struct scsi_cmnd *sc = ctask->sc; | 1337 | struct scsi_cmnd *sc = task->sc; |
1321 | int err; | 1338 | int err; |
1322 | 1339 | ||
1323 | BUG_ON(__kfifo_len(tcp_ctask->r2tqueue)); | 1340 | if (!sc) { |
1324 | tcp_ctask->sent = 0; | 1341 | /* |
1325 | tcp_ctask->exp_datasn = 0; | 1342 | * mgmt tasks do not have a scatterlist since they come |
1343 | * in from the iscsi interface. | ||
1344 | */ | ||
1345 | debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, | ||
1346 | task->itt); | ||
1347 | |||
1348 | /* Prepare PDU, optionally w/ immediate data */ | ||
1349 | iscsi_tcp_send_hdr_prep(conn, task->hdr, sizeof(*task->hdr)); | ||
1350 | |||
1351 | /* If we have immediate data, attach a payload */ | ||
1352 | if (task->data_count) | ||
1353 | iscsi_tcp_send_linear_data_prepare(conn, task->data, | ||
1354 | task->data_count); | ||
1355 | return 0; | ||
1356 | } | ||
1357 | |||
1358 | BUG_ON(__kfifo_len(tcp_task->r2tqueue)); | ||
1359 | tcp_task->sent = 0; | ||
1360 | tcp_task->exp_datasn = 0; | ||
1326 | 1361 | ||
1327 | /* Prepare PDU, optionally w/ immediate data */ | 1362 | /* Prepare PDU, optionally w/ immediate data */ |
1328 | debug_scsi("ctask deq [cid %d itt 0x%x imm %d unsol %d]\n", | 1363 | debug_scsi("task deq [cid %d itt 0x%x imm %d unsol %d]\n", |
1329 | conn->id, ctask->itt, ctask->imm_count, | 1364 | conn->id, task->itt, task->imm_count, |
1330 | ctask->unsol_count); | 1365 | task->unsol_count); |
1331 | iscsi_tcp_send_hdr_prep(conn, ctask->hdr, ctask->hdr_len); | 1366 | iscsi_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); |
1332 | 1367 | ||
1333 | if (!ctask->imm_count) | 1368 | if (!task->imm_count) |
1334 | return 0; | 1369 | return 0; |
1335 | 1370 | ||
1336 | /* If we have immediate data, attach a payload */ | 1371 | /* If we have immediate data, attach a payload */ |
1337 | err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, | 1372 | err = iscsi_tcp_send_data_prep(conn, scsi_out(sc)->table.sgl, |
1338 | scsi_out(sc)->table.nents, | 1373 | scsi_out(sc)->table.nents, |
1339 | 0, ctask->imm_count); | 1374 | 0, task->imm_count); |
1340 | if (err) | 1375 | if (err) |
1341 | return err; | 1376 | return err; |
1342 | tcp_ctask->sent += ctask->imm_count; | 1377 | tcp_task->sent += task->imm_count; |
1343 | ctask->imm_count = 0; | 1378 | task->imm_count = 0; |
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | /** | ||
1348 | * iscsi_tcp_mtask_xmit - xmit management(immediate) task | ||
1349 | * @conn: iscsi connection | ||
1350 | * @mtask: task management task | ||
1351 | * | ||
1352 | * Notes: | ||
1353 | * The function can return -EAGAIN in which case caller must | ||
1354 | * call it again later, or recover. '0' return code means successful | ||
1355 | * xmit. | ||
1356 | **/ | ||
1357 | static int | ||
1358 | iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | ||
1359 | { | ||
1360 | int rc; | ||
1361 | |||
1362 | /* Flush any pending data first. */ | ||
1363 | rc = iscsi_tcp_flush(conn); | ||
1364 | if (rc < 0) | ||
1365 | return rc; | ||
1366 | |||
1367 | if (mtask->hdr->itt == RESERVED_ITT) { | ||
1368 | struct iscsi_session *session = conn->session; | ||
1369 | |||
1370 | spin_lock_bh(&session->lock); | ||
1371 | iscsi_free_mgmt_task(conn, mtask); | ||
1372 | spin_unlock_bh(&session->lock); | ||
1373 | } | ||
1374 | |||
1375 | return 0; | 1379 | return 0; |
1376 | } | 1380 | } |
1377 | 1381 | ||
1378 | /* | 1382 | /* |
1379 | * iscsi_tcp_ctask_xmit - xmit normal PDU task | 1383 | * iscsi_tcp_task_xmit - xmit normal PDU task |
1380 | * @conn: iscsi connection | 1384 | * @task: iscsi command task |
1381 | * @ctask: iscsi command task | ||
1382 | * | 1385 | * |
1383 | * We're expected to return 0 when everything was transmitted succesfully, | 1386 | * We're expected to return 0 when everything was transmitted succesfully, |
1384 | * -EAGAIN if there's still data in the queue, or != 0 for any other kind | 1387 | * -EAGAIN if there's still data in the queue, or != 0 for any other kind |
1385 | * of error. | 1388 | * of error. |
1386 | */ | 1389 | */ |
1387 | static int | 1390 | static int |
1388 | iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask) | 1391 | iscsi_tcp_task_xmit(struct iscsi_task *task) |
1389 | { | 1392 | { |
1390 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1393 | struct iscsi_conn *conn = task->conn; |
1391 | struct scsi_cmnd *sc = ctask->sc; | 1394 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1392 | struct scsi_data_buffer *sdb = scsi_out(sc); | 1395 | struct scsi_cmnd *sc = task->sc; |
1396 | struct scsi_data_buffer *sdb; | ||
1393 | int rc = 0; | 1397 | int rc = 0; |
1394 | 1398 | ||
1395 | flush: | 1399 | flush: |
@@ -1398,31 +1402,39 @@ flush: | |||
1398 | if (rc < 0) | 1402 | if (rc < 0) |
1399 | return rc; | 1403 | return rc; |
1400 | 1404 | ||
1405 | /* mgmt command */ | ||
1406 | if (!sc) { | ||
1407 | if (task->hdr->itt == RESERVED_ITT) | ||
1408 | iscsi_put_task(task); | ||
1409 | return 0; | ||
1410 | } | ||
1411 | |||
1401 | /* Are we done already? */ | 1412 | /* Are we done already? */ |
1402 | if (sc->sc_data_direction != DMA_TO_DEVICE) | 1413 | if (sc->sc_data_direction != DMA_TO_DEVICE) |
1403 | return 0; | 1414 | return 0; |
1404 | 1415 | ||
1405 | if (ctask->unsol_count != 0) { | 1416 | sdb = scsi_out(sc); |
1406 | struct iscsi_data *hdr = &tcp_ctask->unsol_dtask.hdr; | 1417 | if (task->unsol_count != 0) { |
1418 | struct iscsi_data *hdr = &tcp_task->unsol_dtask.hdr; | ||
1407 | 1419 | ||
1408 | /* Prepare a header for the unsolicited PDU. | 1420 | /* Prepare a header for the unsolicited PDU. |
1409 | * The amount of data we want to send will be | 1421 | * The amount of data we want to send will be |
1410 | * in ctask->data_count. | 1422 | * in task->data_count. |
1411 | * FIXME: return the data count instead. | 1423 | * FIXME: return the data count instead. |
1412 | */ | 1424 | */ |
1413 | iscsi_prep_unsolicit_data_pdu(ctask, hdr); | 1425 | iscsi_prep_unsolicit_data_pdu(task, hdr); |
1414 | 1426 | ||
1415 | debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", | 1427 | debug_tcp("unsol dout [itt 0x%x doff %d dlen %d]\n", |
1416 | ctask->itt, tcp_ctask->sent, ctask->data_count); | 1428 | task->itt, tcp_task->sent, task->data_count); |
1417 | 1429 | ||
1418 | iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); | 1430 | iscsi_tcp_send_hdr_prep(conn, hdr, sizeof(*hdr)); |
1419 | rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, | 1431 | rc = iscsi_tcp_send_data_prep(conn, sdb->table.sgl, |
1420 | sdb->table.nents, tcp_ctask->sent, | 1432 | sdb->table.nents, tcp_task->sent, |
1421 | ctask->data_count); | 1433 | task->data_count); |
1422 | if (rc) | 1434 | if (rc) |
1423 | goto fail; | 1435 | goto fail; |
1424 | tcp_ctask->sent += ctask->data_count; | 1436 | tcp_task->sent += task->data_count; |
1425 | ctask->unsol_count -= ctask->data_count; | 1437 | task->unsol_count -= task->data_count; |
1426 | goto flush; | 1438 | goto flush; |
1427 | } else { | 1439 | } else { |
1428 | struct iscsi_session *session = conn->session; | 1440 | struct iscsi_session *session = conn->session; |
@@ -1431,22 +1443,22 @@ flush: | |||
1431 | /* All unsolicited PDUs sent. Check for solicited PDUs. | 1443 | /* All unsolicited PDUs sent. Check for solicited PDUs. |
1432 | */ | 1444 | */ |
1433 | spin_lock_bh(&session->lock); | 1445 | spin_lock_bh(&session->lock); |
1434 | r2t = tcp_ctask->r2t; | 1446 | r2t = tcp_task->r2t; |
1435 | if (r2t != NULL) { | 1447 | if (r2t != NULL) { |
1436 | /* Continue with this R2T? */ | 1448 | /* Continue with this R2T? */ |
1437 | if (!iscsi_solicit_data_cont(conn, ctask, r2t)) { | 1449 | if (!iscsi_solicit_data_cont(conn, task, r2t)) { |
1438 | debug_scsi(" done with r2t %p\n", r2t); | 1450 | debug_scsi(" done with r2t %p\n", r2t); |
1439 | 1451 | ||
1440 | __kfifo_put(tcp_ctask->r2tpool.queue, | 1452 | __kfifo_put(tcp_task->r2tpool.queue, |
1441 | (void*)&r2t, sizeof(void*)); | 1453 | (void*)&r2t, sizeof(void*)); |
1442 | tcp_ctask->r2t = r2t = NULL; | 1454 | tcp_task->r2t = r2t = NULL; |
1443 | } | 1455 | } |
1444 | } | 1456 | } |
1445 | 1457 | ||
1446 | if (r2t == NULL) { | 1458 | if (r2t == NULL) { |
1447 | __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t, | 1459 | __kfifo_get(tcp_task->r2tqueue, (void*)&tcp_task->r2t, |
1448 | sizeof(void*)); | 1460 | sizeof(void*)); |
1449 | r2t = tcp_ctask->r2t; | 1461 | r2t = tcp_task->r2t; |
1450 | } | 1462 | } |
1451 | spin_unlock_bh(&session->lock); | 1463 | spin_unlock_bh(&session->lock); |
1452 | 1464 | ||
@@ -1457,7 +1469,7 @@ flush: | |||
1457 | } | 1469 | } |
1458 | 1470 | ||
1459 | debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", | 1471 | debug_scsi("sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", |
1460 | r2t, r2t->solicit_datasn - 1, ctask->itt, | 1472 | r2t, r2t->solicit_datasn - 1, task->itt, |
1461 | r2t->data_offset + r2t->sent, r2t->data_count); | 1473 | r2t->data_offset + r2t->sent, r2t->data_count); |
1462 | 1474 | ||
1463 | iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, | 1475 | iscsi_tcp_send_hdr_prep(conn, &r2t->dtask.hdr, |
@@ -1469,7 +1481,7 @@ flush: | |||
1469 | r2t->data_count); | 1481 | r2t->data_count); |
1470 | if (rc) | 1482 | if (rc) |
1471 | goto fail; | 1483 | goto fail; |
1472 | tcp_ctask->sent += r2t->data_count; | 1484 | tcp_task->sent += r2t->data_count; |
1473 | r2t->sent += r2t->data_count; | 1485 | r2t->sent += r2t->data_count; |
1474 | goto flush; | 1486 | goto flush; |
1475 | } | 1487 | } |
@@ -1486,7 +1498,7 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1486 | struct iscsi_cls_conn *cls_conn; | 1498 | struct iscsi_cls_conn *cls_conn; |
1487 | struct iscsi_tcp_conn *tcp_conn; | 1499 | struct iscsi_tcp_conn *tcp_conn; |
1488 | 1500 | ||
1489 | cls_conn = iscsi_conn_setup(cls_session, conn_idx); | 1501 | cls_conn = iscsi_conn_setup(cls_session, sizeof(*tcp_conn), conn_idx); |
1490 | if (!cls_conn) | 1502 | if (!cls_conn) |
1491 | return NULL; | 1503 | return NULL; |
1492 | conn = cls_conn->dd_data; | 1504 | conn = cls_conn->dd_data; |
@@ -1496,18 +1508,14 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1496 | */ | 1508 | */ |
1497 | conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; | 1509 | conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; |
1498 | 1510 | ||
1499 | tcp_conn = kzalloc(sizeof(*tcp_conn), GFP_KERNEL); | 1511 | tcp_conn = conn->dd_data; |
1500 | if (!tcp_conn) | ||
1501 | goto tcp_conn_alloc_fail; | ||
1502 | |||
1503 | conn->dd_data = tcp_conn; | ||
1504 | tcp_conn->iscsi_conn = conn; | 1512 | tcp_conn->iscsi_conn = conn; |
1505 | 1513 | ||
1506 | tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, | 1514 | tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, |
1507 | CRYPTO_ALG_ASYNC); | 1515 | CRYPTO_ALG_ASYNC); |
1508 | tcp_conn->tx_hash.flags = 0; | 1516 | tcp_conn->tx_hash.flags = 0; |
1509 | if (IS_ERR(tcp_conn->tx_hash.tfm)) | 1517 | if (IS_ERR(tcp_conn->tx_hash.tfm)) |
1510 | goto free_tcp_conn; | 1518 | goto free_conn; |
1511 | 1519 | ||
1512 | tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, | 1520 | tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, |
1513 | CRYPTO_ALG_ASYNC); | 1521 | CRYPTO_ALG_ASYNC); |
@@ -1519,14 +1527,12 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1519 | 1527 | ||
1520 | free_tx_tfm: | 1528 | free_tx_tfm: |
1521 | crypto_free_hash(tcp_conn->tx_hash.tfm); | 1529 | crypto_free_hash(tcp_conn->tx_hash.tfm); |
1522 | free_tcp_conn: | 1530 | free_conn: |
1523 | iscsi_conn_printk(KERN_ERR, conn, | 1531 | iscsi_conn_printk(KERN_ERR, conn, |
1524 | "Could not create connection due to crc32c " | 1532 | "Could not create connection due to crc32c " |
1525 | "loading error. Make sure the crc32c " | 1533 | "loading error. Make sure the crc32c " |
1526 | "module is built as a module or into the " | 1534 | "module is built as a module or into the " |
1527 | "kernel\n"); | 1535 | "kernel\n"); |
1528 | kfree(tcp_conn); | ||
1529 | tcp_conn_alloc_fail: | ||
1530 | iscsi_conn_teardown(cls_conn); | 1536 | iscsi_conn_teardown(cls_conn); |
1531 | return NULL; | 1537 | return NULL; |
1532 | } | 1538 | } |
@@ -1547,7 +1553,6 @@ iscsi_tcp_release_conn(struct iscsi_conn *conn) | |||
1547 | 1553 | ||
1548 | spin_lock_bh(&session->lock); | 1554 | spin_lock_bh(&session->lock); |
1549 | tcp_conn->sock = NULL; | 1555 | tcp_conn->sock = NULL; |
1550 | conn->recv_lock = NULL; | ||
1551 | spin_unlock_bh(&session->lock); | 1556 | spin_unlock_bh(&session->lock); |
1552 | sockfd_put(sock); | 1557 | sockfd_put(sock); |
1553 | } | 1558 | } |
@@ -1559,20 +1564,32 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) | |||
1559 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1564 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1560 | 1565 | ||
1561 | iscsi_tcp_release_conn(conn); | 1566 | iscsi_tcp_release_conn(conn); |
1562 | iscsi_conn_teardown(cls_conn); | ||
1563 | 1567 | ||
1564 | if (tcp_conn->tx_hash.tfm) | 1568 | if (tcp_conn->tx_hash.tfm) |
1565 | crypto_free_hash(tcp_conn->tx_hash.tfm); | 1569 | crypto_free_hash(tcp_conn->tx_hash.tfm); |
1566 | if (tcp_conn->rx_hash.tfm) | 1570 | if (tcp_conn->rx_hash.tfm) |
1567 | crypto_free_hash(tcp_conn->rx_hash.tfm); | 1571 | crypto_free_hash(tcp_conn->rx_hash.tfm); |
1568 | 1572 | ||
1569 | kfree(tcp_conn); | 1573 | iscsi_conn_teardown(cls_conn); |
1570 | } | 1574 | } |
1571 | 1575 | ||
1572 | static void | 1576 | static void |
1573 | iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) | 1577 | iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) |
1574 | { | 1578 | { |
1575 | struct iscsi_conn *conn = cls_conn->dd_data; | 1579 | struct iscsi_conn *conn = cls_conn->dd_data; |
1580 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | ||
1581 | |||
1582 | /* userspace may have goofed up and not bound us */ | ||
1583 | if (!tcp_conn->sock) | ||
1584 | return; | ||
1585 | /* | ||
1586 | * Make sure our recv side is stopped. | ||
1587 | * Older tools called conn stop before ep_disconnect | ||
1588 | * so IO could still be coming in. | ||
1589 | */ | ||
1590 | write_lock_bh(&tcp_conn->sock->sk->sk_callback_lock); | ||
1591 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | ||
1592 | write_unlock_bh(&tcp_conn->sock->sk->sk_callback_lock); | ||
1576 | 1593 | ||
1577 | iscsi_conn_stop(cls_conn, flag); | 1594 | iscsi_conn_stop(cls_conn, flag); |
1578 | iscsi_tcp_release_conn(conn); | 1595 | iscsi_tcp_release_conn(conn); |
@@ -1623,6 +1640,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1623 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, | 1640 | struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, |
1624 | int is_leading) | 1641 | int is_leading) |
1625 | { | 1642 | { |
1643 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
1644 | struct iscsi_host *ihost = shost_priv(shost); | ||
1626 | struct iscsi_conn *conn = cls_conn->dd_data; | 1645 | struct iscsi_conn *conn = cls_conn->dd_data; |
1627 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 1646 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
1628 | struct sock *sk; | 1647 | struct sock *sk; |
@@ -1646,8 +1665,8 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1646 | if (err) | 1665 | if (err) |
1647 | goto free_socket; | 1666 | goto free_socket; |
1648 | 1667 | ||
1649 | err = iscsi_tcp_get_addr(conn, sock, conn->local_address, | 1668 | err = iscsi_tcp_get_addr(conn, sock, ihost->local_address, |
1650 | &conn->local_port, kernel_getsockname); | 1669 | &ihost->local_port, kernel_getsockname); |
1651 | if (err) | 1670 | if (err) |
1652 | goto free_socket; | 1671 | goto free_socket; |
1653 | 1672 | ||
@@ -1664,13 +1683,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session, | |||
1664 | sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ | 1683 | sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ |
1665 | sk->sk_allocation = GFP_ATOMIC; | 1684 | sk->sk_allocation = GFP_ATOMIC; |
1666 | 1685 | ||
1667 | /* FIXME: disable Nagle's algorithm */ | ||
1668 | |||
1669 | /* | ||
1670 | * Intercept TCP callbacks for sendfile like receive | ||
1671 | * processing. | ||
1672 | */ | ||
1673 | conn->recv_lock = &sk->sk_callback_lock; | ||
1674 | iscsi_conn_set_callbacks(conn); | 1686 | iscsi_conn_set_callbacks(conn); |
1675 | tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; | 1687 | tcp_conn->sendpage = tcp_conn->sock->ops->sendpage; |
1676 | /* | 1688 | /* |
@@ -1684,21 +1696,6 @@ free_socket: | |||
1684 | return err; | 1696 | return err; |
1685 | } | 1697 | } |
1686 | 1698 | ||
1687 | /* called with host lock */ | ||
1688 | static void | ||
1689 | iscsi_tcp_mtask_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask) | ||
1690 | { | ||
1691 | debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt); | ||
1692 | |||
1693 | /* Prepare PDU, optionally w/ immediate data */ | ||
1694 | iscsi_tcp_send_hdr_prep(conn, mtask->hdr, sizeof(*mtask->hdr)); | ||
1695 | |||
1696 | /* If we have immediate data, attach a payload */ | ||
1697 | if (mtask->data_count) | ||
1698 | iscsi_tcp_send_linear_data_prepare(conn, mtask->data, | ||
1699 | mtask->data_count); | ||
1700 | } | ||
1701 | |||
1702 | static int | 1699 | static int |
1703 | iscsi_r2tpool_alloc(struct iscsi_session *session) | 1700 | iscsi_r2tpool_alloc(struct iscsi_session *session) |
1704 | { | 1701 | { |
@@ -1709,8 +1706,8 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1709 | * initialize per-task: R2T pool and xmit queue | 1706 | * initialize per-task: R2T pool and xmit queue |
1710 | */ | 1707 | */ |
1711 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | 1708 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { |
1712 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | 1709 | struct iscsi_task *task = session->cmds[cmd_i]; |
1713 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1710 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1714 | 1711 | ||
1715 | /* | 1712 | /* |
1716 | * pre-allocated x4 as much r2ts to handle race when | 1713 | * pre-allocated x4 as much r2ts to handle race when |
@@ -1719,16 +1716,16 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1719 | */ | 1716 | */ |
1720 | 1717 | ||
1721 | /* R2T pool */ | 1718 | /* R2T pool */ |
1722 | if (iscsi_pool_init(&tcp_ctask->r2tpool, session->max_r2t * 4, NULL, | 1719 | if (iscsi_pool_init(&tcp_task->r2tpool, session->max_r2t * 4, NULL, |
1723 | sizeof(struct iscsi_r2t_info))) { | 1720 | sizeof(struct iscsi_r2t_info))) { |
1724 | goto r2t_alloc_fail; | 1721 | goto r2t_alloc_fail; |
1725 | } | 1722 | } |
1726 | 1723 | ||
1727 | /* R2T xmit queue */ | 1724 | /* R2T xmit queue */ |
1728 | tcp_ctask->r2tqueue = kfifo_alloc( | 1725 | tcp_task->r2tqueue = kfifo_alloc( |
1729 | session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); | 1726 | session->max_r2t * 4 * sizeof(void*), GFP_KERNEL, NULL); |
1730 | if (tcp_ctask->r2tqueue == ERR_PTR(-ENOMEM)) { | 1727 | if (tcp_task->r2tqueue == ERR_PTR(-ENOMEM)) { |
1731 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1728 | iscsi_pool_free(&tcp_task->r2tpool); |
1732 | goto r2t_alloc_fail; | 1729 | goto r2t_alloc_fail; |
1733 | } | 1730 | } |
1734 | } | 1731 | } |
@@ -1737,11 +1734,11 @@ iscsi_r2tpool_alloc(struct iscsi_session *session) | |||
1737 | 1734 | ||
1738 | r2t_alloc_fail: | 1735 | r2t_alloc_fail: |
1739 | for (i = 0; i < cmd_i; i++) { | 1736 | for (i = 0; i < cmd_i; i++) { |
1740 | struct iscsi_cmd_task *ctask = session->cmds[i]; | 1737 | struct iscsi_task *task = session->cmds[i]; |
1741 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1738 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1742 | 1739 | ||
1743 | kfifo_free(tcp_ctask->r2tqueue); | 1740 | kfifo_free(tcp_task->r2tqueue); |
1744 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1741 | iscsi_pool_free(&tcp_task->r2tpool); |
1745 | } | 1742 | } |
1746 | return -ENOMEM; | 1743 | return -ENOMEM; |
1747 | } | 1744 | } |
@@ -1752,11 +1749,11 @@ iscsi_r2tpool_free(struct iscsi_session *session) | |||
1752 | int i; | 1749 | int i; |
1753 | 1750 | ||
1754 | for (i = 0; i < session->cmds_max; i++) { | 1751 | for (i = 0; i < session->cmds_max; i++) { |
1755 | struct iscsi_cmd_task *ctask = session->cmds[i]; | 1752 | struct iscsi_task *task = session->cmds[i]; |
1756 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | 1753 | struct iscsi_tcp_task *tcp_task = task->dd_data; |
1757 | 1754 | ||
1758 | kfifo_free(tcp_ctask->r2tqueue); | 1755 | kfifo_free(tcp_task->r2tqueue); |
1759 | iscsi_pool_free(&tcp_ctask->r2tpool); | 1756 | iscsi_pool_free(&tcp_task->r2tpool); |
1760 | } | 1757 | } |
1761 | } | 1758 | } |
1762 | 1759 | ||
@@ -1821,29 +1818,6 @@ iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, | |||
1821 | return len; | 1818 | return len; |
1822 | } | 1819 | } |
1823 | 1820 | ||
1824 | static int | ||
1825 | iscsi_tcp_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | ||
1826 | char *buf) | ||
1827 | { | ||
1828 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
1829 | int len; | ||
1830 | |||
1831 | switch (param) { | ||
1832 | case ISCSI_HOST_PARAM_IPADDRESS: | ||
1833 | spin_lock_bh(&session->lock); | ||
1834 | if (!session->leadconn) | ||
1835 | len = -ENODEV; | ||
1836 | else | ||
1837 | len = sprintf(buf, "%s\n", | ||
1838 | session->leadconn->local_address); | ||
1839 | spin_unlock_bh(&session->lock); | ||
1840 | break; | ||
1841 | default: | ||
1842 | return iscsi_host_get_param(shost, param, buf); | ||
1843 | } | ||
1844 | return len; | ||
1845 | } | ||
1846 | |||
1847 | static void | 1821 | static void |
1848 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | 1822 | iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) |
1849 | { | 1823 | { |
@@ -1869,54 +1843,70 @@ iscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) | |||
1869 | } | 1843 | } |
1870 | 1844 | ||
1871 | static struct iscsi_cls_session * | 1845 | static struct iscsi_cls_session * |
1872 | iscsi_tcp_session_create(struct iscsi_transport *iscsit, | 1846 | iscsi_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, |
1873 | struct scsi_transport_template *scsit, | 1847 | uint16_t qdepth, uint32_t initial_cmdsn, |
1874 | uint16_t cmds_max, uint16_t qdepth, | 1848 | uint32_t *hostno) |
1875 | uint32_t initial_cmdsn, uint32_t *hostno) | ||
1876 | { | 1849 | { |
1877 | struct iscsi_cls_session *cls_session; | 1850 | struct iscsi_cls_session *cls_session; |
1878 | struct iscsi_session *session; | 1851 | struct iscsi_session *session; |
1879 | uint32_t hn; | 1852 | struct Scsi_Host *shost; |
1880 | int cmd_i; | 1853 | int cmd_i; |
1881 | 1854 | ||
1882 | cls_session = iscsi_session_setup(iscsit, scsit, cmds_max, qdepth, | 1855 | if (ep) { |
1883 | sizeof(struct iscsi_tcp_cmd_task), | 1856 | printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); |
1884 | sizeof(struct iscsi_tcp_mgmt_task), | ||
1885 | initial_cmdsn, &hn); | ||
1886 | if (!cls_session) | ||
1887 | return NULL; | 1857 | return NULL; |
1888 | *hostno = hn; | ||
1889 | |||
1890 | session = class_to_transport_session(cls_session); | ||
1891 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | ||
1892 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | ||
1893 | struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data; | ||
1894 | |||
1895 | ctask->hdr = &tcp_ctask->hdr.cmd_hdr; | ||
1896 | ctask->hdr_max = sizeof(tcp_ctask->hdr) - ISCSI_DIGEST_SIZE; | ||
1897 | } | 1858 | } |
1898 | 1859 | ||
1899 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { | 1860 | shost = iscsi_host_alloc(&iscsi_sht, 0, qdepth); |
1900 | struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; | 1861 | if (!shost) |
1901 | struct iscsi_tcp_mgmt_task *tcp_mtask = mtask->dd_data; | 1862 | return NULL; |
1863 | shost->transportt = iscsi_tcp_scsi_transport; | ||
1864 | shost->max_lun = iscsi_max_lun; | ||
1865 | shost->max_id = 0; | ||
1866 | shost->max_channel = 0; | ||
1867 | shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; | ||
1868 | |||
1869 | if (iscsi_host_add(shost, NULL)) | ||
1870 | goto free_host; | ||
1871 | *hostno = shost->host_no; | ||
1872 | |||
1873 | cls_session = iscsi_session_setup(&iscsi_tcp_transport, shost, cmds_max, | ||
1874 | sizeof(struct iscsi_tcp_task), | ||
1875 | initial_cmdsn, 0); | ||
1876 | if (!cls_session) | ||
1877 | goto remove_host; | ||
1878 | session = cls_session->dd_data; | ||
1879 | |||
1880 | shost->can_queue = session->scsi_cmds_max; | ||
1881 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | ||
1882 | struct iscsi_task *task = session->cmds[cmd_i]; | ||
1883 | struct iscsi_tcp_task *tcp_task = task->dd_data; | ||
1902 | 1884 | ||
1903 | mtask->hdr = (struct iscsi_hdr *) &tcp_mtask->hdr; | 1885 | task->hdr = &tcp_task->hdr.cmd_hdr; |
1886 | task->hdr_max = sizeof(tcp_task->hdr) - ISCSI_DIGEST_SIZE; | ||
1904 | } | 1887 | } |
1905 | 1888 | ||
1906 | if (iscsi_r2tpool_alloc(class_to_transport_session(cls_session))) | 1889 | if (iscsi_r2tpool_alloc(session)) |
1907 | goto r2tpool_alloc_fail; | 1890 | goto remove_session; |
1908 | |||
1909 | return cls_session; | 1891 | return cls_session; |
1910 | 1892 | ||
1911 | r2tpool_alloc_fail: | 1893 | remove_session: |
1912 | iscsi_session_teardown(cls_session); | 1894 | iscsi_session_teardown(cls_session); |
1895 | remove_host: | ||
1896 | iscsi_host_remove(shost); | ||
1897 | free_host: | ||
1898 | iscsi_host_free(shost); | ||
1913 | return NULL; | 1899 | return NULL; |
1914 | } | 1900 | } |
1915 | 1901 | ||
1916 | static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) | 1902 | static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session) |
1917 | { | 1903 | { |
1918 | iscsi_r2tpool_free(class_to_transport_session(cls_session)); | 1904 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); |
1919 | iscsi_session_teardown(cls_session); | 1905 | |
1906 | iscsi_r2tpool_free(cls_session->dd_data); | ||
1907 | |||
1908 | iscsi_host_remove(shost); | ||
1909 | iscsi_host_free(shost); | ||
1920 | } | 1910 | } |
1921 | 1911 | ||
1922 | static int iscsi_tcp_slave_configure(struct scsi_device *sdev) | 1912 | static int iscsi_tcp_slave_configure(struct scsi_device *sdev) |
@@ -1971,14 +1961,11 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
1971 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | | 1961 | ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN | |
1972 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | | 1962 | ISCSI_FAST_ABORT | ISCSI_ABORT_TMO | |
1973 | ISCSI_LU_RESET_TMO | | 1963 | ISCSI_LU_RESET_TMO | |
1974 | ISCSI_PING_TMO | ISCSI_RECV_TMO, | 1964 | ISCSI_PING_TMO | ISCSI_RECV_TMO | |
1965 | ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME, | ||
1975 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | | 1966 | .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | |
1976 | ISCSI_HOST_INITIATOR_NAME | | 1967 | ISCSI_HOST_INITIATOR_NAME | |
1977 | ISCSI_HOST_NETDEV_NAME, | 1968 | ISCSI_HOST_NETDEV_NAME, |
1978 | .host_template = &iscsi_sht, | ||
1979 | .conndata_size = sizeof(struct iscsi_conn), | ||
1980 | .max_conn = 1, | ||
1981 | .max_cmd_len = 16, | ||
1982 | /* session management */ | 1969 | /* session management */ |
1983 | .create_session = iscsi_tcp_session_create, | 1970 | .create_session = iscsi_tcp_session_create, |
1984 | .destroy_session = iscsi_tcp_session_destroy, | 1971 | .destroy_session = iscsi_tcp_session_destroy, |
@@ -1992,16 +1979,14 @@ static struct iscsi_transport iscsi_tcp_transport = { | |||
1992 | .start_conn = iscsi_conn_start, | 1979 | .start_conn = iscsi_conn_start, |
1993 | .stop_conn = iscsi_tcp_conn_stop, | 1980 | .stop_conn = iscsi_tcp_conn_stop, |
1994 | /* iscsi host params */ | 1981 | /* iscsi host params */ |
1995 | .get_host_param = iscsi_tcp_host_get_param, | 1982 | .get_host_param = iscsi_host_get_param, |
1996 | .set_host_param = iscsi_host_set_param, | 1983 | .set_host_param = iscsi_host_set_param, |
1997 | /* IO */ | 1984 | /* IO */ |
1998 | .send_pdu = iscsi_conn_send_pdu, | 1985 | .send_pdu = iscsi_conn_send_pdu, |
1999 | .get_stats = iscsi_conn_get_stats, | 1986 | .get_stats = iscsi_conn_get_stats, |
2000 | .init_cmd_task = iscsi_tcp_ctask_init, | 1987 | .init_task = iscsi_tcp_task_init, |
2001 | .init_mgmt_task = iscsi_tcp_mtask_init, | 1988 | .xmit_task = iscsi_tcp_task_xmit, |
2002 | .xmit_cmd_task = iscsi_tcp_ctask_xmit, | 1989 | .cleanup_task = iscsi_tcp_cleanup_task, |
2003 | .xmit_mgmt_task = iscsi_tcp_mtask_xmit, | ||
2004 | .cleanup_cmd_task = iscsi_tcp_cleanup_ctask, | ||
2005 | /* recovery */ | 1990 | /* recovery */ |
2006 | .session_recovery_timedout = iscsi_session_recovery_timedout, | 1991 | .session_recovery_timedout = iscsi_session_recovery_timedout, |
2007 | }; | 1992 | }; |
@@ -2014,9 +1999,10 @@ iscsi_tcp_init(void) | |||
2014 | iscsi_max_lun); | 1999 | iscsi_max_lun); |
2015 | return -EINVAL; | 2000 | return -EINVAL; |
2016 | } | 2001 | } |
2017 | iscsi_tcp_transport.max_lun = iscsi_max_lun; | ||
2018 | 2002 | ||
2019 | if (!iscsi_register_transport(&iscsi_tcp_transport)) | 2003 | iscsi_tcp_scsi_transport = iscsi_register_transport( |
2004 | &iscsi_tcp_transport); | ||
2005 | if (!iscsi_tcp_scsi_transport) | ||
2020 | return -ENODEV; | 2006 | return -ENODEV; |
2021 | 2007 | ||
2022 | return 0; | 2008 | return 0; |
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h index ed0b991d1e72..498d8ca39848 100644 --- a/drivers/scsi/iscsi_tcp.h +++ b/drivers/scsi/iscsi_tcp.h | |||
@@ -103,11 +103,6 @@ struct iscsi_data_task { | |||
103 | char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ | 103 | char hdrext[ISCSI_DIGEST_SIZE];/* Header-Digest */ |
104 | }; | 104 | }; |
105 | 105 | ||
106 | struct iscsi_tcp_mgmt_task { | ||
107 | struct iscsi_hdr hdr; | ||
108 | char hdrext[ISCSI_DIGEST_SIZE]; /* Header-Digest */ | ||
109 | }; | ||
110 | |||
111 | struct iscsi_r2t_info { | 106 | struct iscsi_r2t_info { |
112 | __be32 ttt; /* copied from R2T */ | 107 | __be32 ttt; /* copied from R2T */ |
113 | __be32 exp_statsn; /* copied from R2T */ | 108 | __be32 exp_statsn; /* copied from R2T */ |
@@ -119,7 +114,7 @@ struct iscsi_r2t_info { | |||
119 | struct iscsi_data_task dtask; /* Data-Out header buf */ | 114 | struct iscsi_data_task dtask; /* Data-Out header buf */ |
120 | }; | 115 | }; |
121 | 116 | ||
122 | struct iscsi_tcp_cmd_task { | 117 | struct iscsi_tcp_task { |
123 | struct iscsi_hdr_buff { | 118 | struct iscsi_hdr_buff { |
124 | struct iscsi_cmd cmd_hdr; | 119 | struct iscsi_cmd cmd_hdr; |
125 | char hdrextbuf[ISCSI_MAX_AHS_SIZE + | 120 | char hdrextbuf[ISCSI_MAX_AHS_SIZE + |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index b43bf1d60dac..299e075a7b34 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -38,14 +38,6 @@ | |||
38 | #include <scsi/scsi_transport_iscsi.h> | 38 | #include <scsi/scsi_transport_iscsi.h> |
39 | #include <scsi/libiscsi.h> | 39 | #include <scsi/libiscsi.h> |
40 | 40 | ||
41 | struct iscsi_session * | ||
42 | class_to_transport_session(struct iscsi_cls_session *cls_session) | ||
43 | { | ||
44 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | ||
45 | return iscsi_hostdata(shost->hostdata); | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(class_to_transport_session); | ||
48 | |||
49 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ | 41 | /* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ |
50 | #define SNA32_CHECK 2147483648UL | 42 | #define SNA32_CHECK 2147483648UL |
51 | 43 | ||
@@ -87,68 +79,70 @@ iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) | |||
87 | * xmit thread | 79 | * xmit thread |
88 | */ | 80 | */ |
89 | if (!list_empty(&session->leadconn->xmitqueue) || | 81 | if (!list_empty(&session->leadconn->xmitqueue) || |
90 | !list_empty(&session->leadconn->mgmtqueue)) | 82 | !list_empty(&session->leadconn->mgmtqueue)) { |
91 | scsi_queue_work(session->host, | 83 | if (!(session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
92 | &session->leadconn->xmitwork); | 84 | scsi_queue_work(session->host, |
85 | &session->leadconn->xmitwork); | ||
86 | } | ||
93 | } | 87 | } |
94 | } | 88 | } |
95 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); | 89 | EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); |
96 | 90 | ||
97 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask, | 91 | void iscsi_prep_unsolicit_data_pdu(struct iscsi_task *task, |
98 | struct iscsi_data *hdr) | 92 | struct iscsi_data *hdr) |
99 | { | 93 | { |
100 | struct iscsi_conn *conn = ctask->conn; | 94 | struct iscsi_conn *conn = task->conn; |
101 | 95 | ||
102 | memset(hdr, 0, sizeof(struct iscsi_data)); | 96 | memset(hdr, 0, sizeof(struct iscsi_data)); |
103 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); | 97 | hdr->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); |
104 | hdr->datasn = cpu_to_be32(ctask->unsol_datasn); | 98 | hdr->datasn = cpu_to_be32(task->unsol_datasn); |
105 | ctask->unsol_datasn++; | 99 | task->unsol_datasn++; |
106 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; | 100 | hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; |
107 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 101 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
108 | 102 | ||
109 | hdr->itt = ctask->hdr->itt; | 103 | hdr->itt = task->hdr->itt; |
110 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 104 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
111 | hdr->offset = cpu_to_be32(ctask->unsol_offset); | 105 | hdr->offset = cpu_to_be32(task->unsol_offset); |
112 | 106 | ||
113 | if (ctask->unsol_count > conn->max_xmit_dlength) { | 107 | if (task->unsol_count > conn->max_xmit_dlength) { |
114 | hton24(hdr->dlength, conn->max_xmit_dlength); | 108 | hton24(hdr->dlength, conn->max_xmit_dlength); |
115 | ctask->data_count = conn->max_xmit_dlength; | 109 | task->data_count = conn->max_xmit_dlength; |
116 | ctask->unsol_offset += ctask->data_count; | 110 | task->unsol_offset += task->data_count; |
117 | hdr->flags = 0; | 111 | hdr->flags = 0; |
118 | } else { | 112 | } else { |
119 | hton24(hdr->dlength, ctask->unsol_count); | 113 | hton24(hdr->dlength, task->unsol_count); |
120 | ctask->data_count = ctask->unsol_count; | 114 | task->data_count = task->unsol_count; |
121 | hdr->flags = ISCSI_FLAG_CMD_FINAL; | 115 | hdr->flags = ISCSI_FLAG_CMD_FINAL; |
122 | } | 116 | } |
123 | } | 117 | } |
124 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); | 118 | EXPORT_SYMBOL_GPL(iscsi_prep_unsolicit_data_pdu); |
125 | 119 | ||
126 | static int iscsi_add_hdr(struct iscsi_cmd_task *ctask, unsigned len) | 120 | static int iscsi_add_hdr(struct iscsi_task *task, unsigned len) |
127 | { | 121 | { |
128 | unsigned exp_len = ctask->hdr_len + len; | 122 | unsigned exp_len = task->hdr_len + len; |
129 | 123 | ||
130 | if (exp_len > ctask->hdr_max) { | 124 | if (exp_len > task->hdr_max) { |
131 | WARN_ON(1); | 125 | WARN_ON(1); |
132 | return -EINVAL; | 126 | return -EINVAL; |
133 | } | 127 | } |
134 | 128 | ||
135 | WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ | 129 | WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ |
136 | ctask->hdr_len = exp_len; | 130 | task->hdr_len = exp_len; |
137 | return 0; | 131 | return 0; |
138 | } | 132 | } |
139 | 133 | ||
140 | /* | 134 | /* |
141 | * make an extended cdb AHS | 135 | * make an extended cdb AHS |
142 | */ | 136 | */ |
143 | static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | 137 | static int iscsi_prep_ecdb_ahs(struct iscsi_task *task) |
144 | { | 138 | { |
145 | struct scsi_cmnd *cmd = ctask->sc; | 139 | struct scsi_cmnd *cmd = task->sc; |
146 | unsigned rlen, pad_len; | 140 | unsigned rlen, pad_len; |
147 | unsigned short ahslength; | 141 | unsigned short ahslength; |
148 | struct iscsi_ecdb_ahdr *ecdb_ahdr; | 142 | struct iscsi_ecdb_ahdr *ecdb_ahdr; |
149 | int rc; | 143 | int rc; |
150 | 144 | ||
151 | ecdb_ahdr = iscsi_next_hdr(ctask); | 145 | ecdb_ahdr = iscsi_next_hdr(task); |
152 | rlen = cmd->cmd_len - ISCSI_CDB_SIZE; | 146 | rlen = cmd->cmd_len - ISCSI_CDB_SIZE; |
153 | 147 | ||
154 | BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); | 148 | BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); |
@@ -156,7 +150,7 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | |||
156 | 150 | ||
157 | pad_len = iscsi_padding(rlen); | 151 | pad_len = iscsi_padding(rlen); |
158 | 152 | ||
159 | rc = iscsi_add_hdr(ctask, sizeof(ecdb_ahdr->ahslength) + | 153 | rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) + |
160 | sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); | 154 | sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); |
161 | if (rc) | 155 | if (rc) |
162 | return rc; | 156 | return rc; |
@@ -171,19 +165,19 @@ static int iscsi_prep_ecdb_ahs(struct iscsi_cmd_task *ctask) | |||
171 | 165 | ||
172 | debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " | 166 | debug_scsi("iscsi_prep_ecdb_ahs: varlen_cdb_len %d " |
173 | "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", | 167 | "rlen %d pad_len %d ahs_length %d iscsi_headers_size %u\n", |
174 | cmd->cmd_len, rlen, pad_len, ahslength, ctask->hdr_len); | 168 | cmd->cmd_len, rlen, pad_len, ahslength, task->hdr_len); |
175 | 169 | ||
176 | return 0; | 170 | return 0; |
177 | } | 171 | } |
178 | 172 | ||
179 | static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | 173 | static int iscsi_prep_bidi_ahs(struct iscsi_task *task) |
180 | { | 174 | { |
181 | struct scsi_cmnd *sc = ctask->sc; | 175 | struct scsi_cmnd *sc = task->sc; |
182 | struct iscsi_rlength_ahdr *rlen_ahdr; | 176 | struct iscsi_rlength_ahdr *rlen_ahdr; |
183 | int rc; | 177 | int rc; |
184 | 178 | ||
185 | rlen_ahdr = iscsi_next_hdr(ctask); | 179 | rlen_ahdr = iscsi_next_hdr(task); |
186 | rc = iscsi_add_hdr(ctask, sizeof(*rlen_ahdr)); | 180 | rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr)); |
187 | if (rc) | 181 | if (rc) |
188 | return rc; | 182 | return rc; |
189 | 183 | ||
@@ -203,28 +197,28 @@ static int iscsi_prep_bidi_ahs(struct iscsi_cmd_task *ctask) | |||
203 | 197 | ||
204 | /** | 198 | /** |
205 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu | 199 | * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu |
206 | * @ctask: iscsi cmd task | 200 | * @task: iscsi task |
207 | * | 201 | * |
208 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set | 202 | * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set |
209 | * fields like dlength or final based on how much data it sends | 203 | * fields like dlength or final based on how much data it sends |
210 | */ | 204 | */ |
211 | static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | 205 | static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) |
212 | { | 206 | { |
213 | struct iscsi_conn *conn = ctask->conn; | 207 | struct iscsi_conn *conn = task->conn; |
214 | struct iscsi_session *session = conn->session; | 208 | struct iscsi_session *session = conn->session; |
215 | struct iscsi_cmd *hdr = ctask->hdr; | 209 | struct iscsi_cmd *hdr = task->hdr; |
216 | struct scsi_cmnd *sc = ctask->sc; | 210 | struct scsi_cmnd *sc = task->sc; |
217 | unsigned hdrlength, cmd_len; | 211 | unsigned hdrlength, cmd_len; |
218 | int rc; | 212 | int rc; |
219 | 213 | ||
220 | ctask->hdr_len = 0; | 214 | task->hdr_len = 0; |
221 | rc = iscsi_add_hdr(ctask, sizeof(*hdr)); | 215 | rc = iscsi_add_hdr(task, sizeof(*hdr)); |
222 | if (rc) | 216 | if (rc) |
223 | return rc; | 217 | return rc; |
224 | hdr->opcode = ISCSI_OP_SCSI_CMD; | 218 | hdr->opcode = ISCSI_OP_SCSI_CMD; |
225 | hdr->flags = ISCSI_ATTR_SIMPLE; | 219 | hdr->flags = ISCSI_ATTR_SIMPLE; |
226 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); | 220 | int_to_scsilun(sc->device->lun, (struct scsi_lun *)hdr->lun); |
227 | hdr->itt = build_itt(ctask->itt, session->age); | 221 | hdr->itt = build_itt(task->itt, session->age); |
228 | hdr->cmdsn = cpu_to_be32(session->cmdsn); | 222 | hdr->cmdsn = cpu_to_be32(session->cmdsn); |
229 | session->cmdsn++; | 223 | session->cmdsn++; |
230 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); | 224 | hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); |
@@ -232,17 +226,17 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
232 | if (cmd_len < ISCSI_CDB_SIZE) | 226 | if (cmd_len < ISCSI_CDB_SIZE) |
233 | memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); | 227 | memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); |
234 | else if (cmd_len > ISCSI_CDB_SIZE) { | 228 | else if (cmd_len > ISCSI_CDB_SIZE) { |
235 | rc = iscsi_prep_ecdb_ahs(ctask); | 229 | rc = iscsi_prep_ecdb_ahs(task); |
236 | if (rc) | 230 | if (rc) |
237 | return rc; | 231 | return rc; |
238 | cmd_len = ISCSI_CDB_SIZE; | 232 | cmd_len = ISCSI_CDB_SIZE; |
239 | } | 233 | } |
240 | memcpy(hdr->cdb, sc->cmnd, cmd_len); | 234 | memcpy(hdr->cdb, sc->cmnd, cmd_len); |
241 | 235 | ||
242 | ctask->imm_count = 0; | 236 | task->imm_count = 0; |
243 | if (scsi_bidi_cmnd(sc)) { | 237 | if (scsi_bidi_cmnd(sc)) { |
244 | hdr->flags |= ISCSI_FLAG_CMD_READ; | 238 | hdr->flags |= ISCSI_FLAG_CMD_READ; |
245 | rc = iscsi_prep_bidi_ahs(ctask); | 239 | rc = iscsi_prep_bidi_ahs(task); |
246 | if (rc) | 240 | if (rc) |
247 | return rc; | 241 | return rc; |
248 | } | 242 | } |
@@ -264,28 +258,28 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
264 | * | 258 | * |
265 | * pad_count bytes to be sent as zero-padding | 259 | * pad_count bytes to be sent as zero-padding |
266 | */ | 260 | */ |
267 | ctask->unsol_count = 0; | 261 | task->unsol_count = 0; |
268 | ctask->unsol_offset = 0; | 262 | task->unsol_offset = 0; |
269 | ctask->unsol_datasn = 0; | 263 | task->unsol_datasn = 0; |
270 | 264 | ||
271 | if (session->imm_data_en) { | 265 | if (session->imm_data_en) { |
272 | if (out_len >= session->first_burst) | 266 | if (out_len >= session->first_burst) |
273 | ctask->imm_count = min(session->first_burst, | 267 | task->imm_count = min(session->first_burst, |
274 | conn->max_xmit_dlength); | 268 | conn->max_xmit_dlength); |
275 | else | 269 | else |
276 | ctask->imm_count = min(out_len, | 270 | task->imm_count = min(out_len, |
277 | conn->max_xmit_dlength); | 271 | conn->max_xmit_dlength); |
278 | hton24(hdr->dlength, ctask->imm_count); | 272 | hton24(hdr->dlength, task->imm_count); |
279 | } else | 273 | } else |
280 | zero_data(hdr->dlength); | 274 | zero_data(hdr->dlength); |
281 | 275 | ||
282 | if (!session->initial_r2t_en) { | 276 | if (!session->initial_r2t_en) { |
283 | ctask->unsol_count = min(session->first_burst, out_len) | 277 | task->unsol_count = min(session->first_burst, out_len) |
284 | - ctask->imm_count; | 278 | - task->imm_count; |
285 | ctask->unsol_offset = ctask->imm_count; | 279 | task->unsol_offset = task->imm_count; |
286 | } | 280 | } |
287 | 281 | ||
288 | if (!ctask->unsol_count) | 282 | if (!task->unsol_count) |
289 | /* No unsolicit Data-Out's */ | 283 | /* No unsolicit Data-Out's */ |
290 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 284 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
291 | } else { | 285 | } else { |
@@ -298,7 +292,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
298 | } | 292 | } |
299 | 293 | ||
300 | /* calculate size of additional header segments (AHSs) */ | 294 | /* calculate size of additional header segments (AHSs) */ |
301 | hdrlength = ctask->hdr_len - sizeof(*hdr); | 295 | hdrlength = task->hdr_len - sizeof(*hdr); |
302 | 296 | ||
303 | WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); | 297 | WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); |
304 | hdrlength /= ISCSI_PAD_LEN; | 298 | hdrlength /= ISCSI_PAD_LEN; |
@@ -306,76 +300,115 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask) | |||
306 | WARN_ON(hdrlength >= 256); | 300 | WARN_ON(hdrlength >= 256); |
307 | hdr->hlength = hdrlength & 0xFF; | 301 | hdr->hlength = hdrlength & 0xFF; |
308 | 302 | ||
309 | if (conn->session->tt->init_cmd_task(conn->ctask)) | 303 | if (conn->session->tt->init_task && |
310 | return EIO; | 304 | conn->session->tt->init_task(task)) |
305 | return -EIO; | ||
306 | |||
307 | task->state = ISCSI_TASK_RUNNING; | ||
308 | list_move_tail(&task->running, &conn->run_list); | ||
311 | 309 | ||
312 | conn->scsicmd_pdus_cnt++; | 310 | conn->scsicmd_pdus_cnt++; |
313 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x " | 311 | debug_scsi("iscsi prep [%s cid %d sc %p cdb 0x%x itt 0x%x len %d " |
314 | "len %d bidi_len %d cmdsn %d win %d]\n", | 312 | "bidi_len %d cmdsn %d win %d]\n", scsi_bidi_cmnd(sc) ? |
315 | scsi_bidi_cmnd(sc) ? "bidirectional" : | 313 | "bidirectional" : sc->sc_data_direction == DMA_TO_DEVICE ? |
316 | sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read", | 314 | "write" : "read", conn->id, sc, sc->cmnd[0], task->itt, |
317 | conn->id, sc, sc->cmnd[0], ctask->itt, | 315 | scsi_bufflen(sc), |
318 | scsi_bufflen(sc), scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, | 316 | scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, |
319 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); | 317 | session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1); |
320 | return 0; | 318 | return 0; |
321 | } | 319 | } |
322 | 320 | ||
323 | /** | 321 | /** |
324 | * iscsi_complete_command - return command back to scsi-ml | 322 | * iscsi_complete_command - finish a task |
325 | * @ctask: iscsi cmd task | 323 | * @task: iscsi cmd task |
326 | * | 324 | * |
327 | * Must be called with session lock. | 325 | * Must be called with session lock. |
328 | * This function returns the scsi command to scsi-ml and returns | 326 | * This function returns the scsi command to scsi-ml or cleans |
329 | * the cmd task to the pool of available cmd tasks. | 327 | * up mgmt tasks then returns the task to the pool. |
330 | */ | 328 | */ |
331 | static void iscsi_complete_command(struct iscsi_cmd_task *ctask) | 329 | static void iscsi_complete_command(struct iscsi_task *task) |
332 | { | 330 | { |
333 | struct iscsi_conn *conn = ctask->conn; | 331 | struct iscsi_conn *conn = task->conn; |
334 | struct iscsi_session *session = conn->session; | 332 | struct iscsi_session *session = conn->session; |
335 | struct scsi_cmnd *sc = ctask->sc; | 333 | struct scsi_cmnd *sc = task->sc; |
336 | 334 | ||
337 | ctask->state = ISCSI_TASK_COMPLETED; | 335 | list_del_init(&task->running); |
338 | ctask->sc = NULL; | 336 | task->state = ISCSI_TASK_COMPLETED; |
339 | /* SCSI eh reuses commands to verify us */ | 337 | task->sc = NULL; |
340 | sc->SCp.ptr = NULL; | 338 | |
341 | if (conn->ctask == ctask) | 339 | if (conn->task == task) |
342 | conn->ctask = NULL; | 340 | conn->task = NULL; |
343 | list_del_init(&ctask->running); | 341 | /* |
344 | __kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*)); | 342 | * login task is preallocated so do not free |
345 | sc->scsi_done(sc); | 343 | */ |
344 | if (conn->login_task == task) | ||
345 | return; | ||
346 | |||
347 | __kfifo_put(session->cmdpool.queue, (void*)&task, sizeof(void*)); | ||
348 | |||
349 | if (conn->ping_task == task) | ||
350 | conn->ping_task = NULL; | ||
351 | |||
352 | if (sc) { | ||
353 | task->sc = NULL; | ||
354 | /* SCSI eh reuses commands to verify us */ | ||
355 | sc->SCp.ptr = NULL; | ||
356 | /* | ||
357 | * queue command may call this to free the task, but | ||
358 | * not have setup the sc callback | ||
359 | */ | ||
360 | if (sc->scsi_done) | ||
361 | sc->scsi_done(sc); | ||
362 | } | ||
363 | } | ||
364 | |||
365 | void __iscsi_get_task(struct iscsi_task *task) | ||
366 | { | ||
367 | atomic_inc(&task->refcount); | ||
346 | } | 368 | } |
369 | EXPORT_SYMBOL_GPL(__iscsi_get_task); | ||
347 | 370 | ||
348 | static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask) | 371 | static void __iscsi_put_task(struct iscsi_task *task) |
349 | { | 372 | { |
350 | atomic_inc(&ctask->refcount); | 373 | if (atomic_dec_and_test(&task->refcount)) |
374 | iscsi_complete_command(task); | ||
351 | } | 375 | } |
352 | 376 | ||
353 | static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask) | 377 | void iscsi_put_task(struct iscsi_task *task) |
354 | { | 378 | { |
355 | if (atomic_dec_and_test(&ctask->refcount)) | 379 | struct iscsi_session *session = task->conn->session; |
356 | iscsi_complete_command(ctask); | 380 | |
381 | spin_lock_bh(&session->lock); | ||
382 | __iscsi_put_task(task); | ||
383 | spin_unlock_bh(&session->lock); | ||
357 | } | 384 | } |
385 | EXPORT_SYMBOL_GPL(iscsi_put_task); | ||
358 | 386 | ||
359 | /* | 387 | /* |
360 | * session lock must be held | 388 | * session lock must be held |
361 | */ | 389 | */ |
362 | static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | 390 | static void fail_command(struct iscsi_conn *conn, struct iscsi_task *task, |
363 | int err) | 391 | int err) |
364 | { | 392 | { |
365 | struct scsi_cmnd *sc; | 393 | struct scsi_cmnd *sc; |
366 | 394 | ||
367 | sc = ctask->sc; | 395 | sc = task->sc; |
368 | if (!sc) | 396 | if (!sc) |
369 | return; | 397 | return; |
370 | 398 | ||
371 | if (ctask->state == ISCSI_TASK_PENDING) | 399 | if (task->state == ISCSI_TASK_PENDING) |
372 | /* | 400 | /* |
373 | * cmd never made it to the xmit thread, so we should not count | 401 | * cmd never made it to the xmit thread, so we should not count |
374 | * the cmd in the sequencing | 402 | * the cmd in the sequencing |
375 | */ | 403 | */ |
376 | conn->session->queued_cmdsn--; | 404 | conn->session->queued_cmdsn--; |
377 | else | 405 | else |
378 | conn->session->tt->cleanup_cmd_task(conn, ctask); | 406 | conn->session->tt->cleanup_task(conn, task); |
407 | /* | ||
408 | * Check if cleanup_task dropped the lock and the command completed, | ||
409 | */ | ||
410 | if (!task->sc) | ||
411 | return; | ||
379 | 412 | ||
380 | sc->result = err; | 413 | sc->result = err; |
381 | if (!scsi_bidi_cmnd(sc)) | 414 | if (!scsi_bidi_cmnd(sc)) |
@@ -384,39 +417,63 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask, | |||
384 | scsi_out(sc)->resid = scsi_out(sc)->length; | 417 | scsi_out(sc)->resid = scsi_out(sc)->length; |
385 | scsi_in(sc)->resid = scsi_in(sc)->length; | 418 | scsi_in(sc)->resid = scsi_in(sc)->length; |
386 | } | 419 | } |
387 | if (conn->ctask == ctask) | 420 | |
388 | conn->ctask = NULL; | 421 | if (conn->task == task) |
422 | conn->task = NULL; | ||
389 | /* release ref from queuecommand */ | 423 | /* release ref from queuecommand */ |
390 | __iscsi_put_ctask(ctask); | 424 | __iscsi_put_task(task); |
391 | } | 425 | } |
392 | 426 | ||
393 | /** | 427 | static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, |
394 | * iscsi_free_mgmt_task - return mgmt task back to pool | 428 | struct iscsi_task *task) |
395 | * @conn: iscsi connection | ||
396 | * @mtask: mtask | ||
397 | * | ||
398 | * Must be called with session lock. | ||
399 | */ | ||
400 | void iscsi_free_mgmt_task(struct iscsi_conn *conn, | ||
401 | struct iscsi_mgmt_task *mtask) | ||
402 | { | 429 | { |
403 | list_del_init(&mtask->running); | 430 | struct iscsi_session *session = conn->session; |
404 | if (conn->login_mtask == mtask) | 431 | struct iscsi_hdr *hdr = (struct iscsi_hdr *)task->hdr; |
405 | return; | 432 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; |
433 | |||
434 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | ||
435 | return -ENOTCONN; | ||
436 | |||
437 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
438 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
439 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
440 | /* | ||
441 | * pre-format CmdSN for outgoing PDU. | ||
442 | */ | ||
443 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
444 | if (hdr->itt != RESERVED_ITT) { | ||
445 | hdr->itt = build_itt(task->itt, session->age); | ||
446 | /* | ||
447 | * TODO: We always use immediate, so we never hit this. | ||
448 | * If we start to send tmfs or nops as non-immediate then | ||
449 | * we should start checking the cmdsn numbers for mgmt tasks. | ||
450 | */ | ||
451 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
452 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | ||
453 | session->queued_cmdsn++; | ||
454 | session->cmdsn++; | ||
455 | } | ||
456 | } | ||
406 | 457 | ||
407 | if (conn->ping_mtask == mtask) | 458 | if (session->tt->init_task) |
408 | conn->ping_mtask = NULL; | 459 | session->tt->init_task(task); |
409 | __kfifo_put(conn->session->mgmtpool.queue, | 460 | |
410 | (void*)&mtask, sizeof(void*)); | 461 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) |
462 | session->state = ISCSI_STATE_LOGGING_OUT; | ||
463 | |||
464 | list_move_tail(&task->running, &conn->mgmt_run_list); | ||
465 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
466 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, | ||
467 | task->data_count); | ||
468 | return 0; | ||
411 | } | 469 | } |
412 | EXPORT_SYMBOL_GPL(iscsi_free_mgmt_task); | ||
413 | 470 | ||
414 | static struct iscsi_mgmt_task * | 471 | static struct iscsi_task * |
415 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 472 | __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
416 | char *data, uint32_t data_size) | 473 | char *data, uint32_t data_size) |
417 | { | 474 | { |
418 | struct iscsi_session *session = conn->session; | 475 | struct iscsi_session *session = conn->session; |
419 | struct iscsi_mgmt_task *mtask; | 476 | struct iscsi_task *task; |
420 | 477 | ||
421 | if (session->state == ISCSI_STATE_TERMINATE) | 478 | if (session->state == ISCSI_STATE_TERMINATE) |
422 | return NULL; | 479 | return NULL; |
@@ -426,29 +483,56 @@ __iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
426 | /* | 483 | /* |
427 | * Login and Text are sent serially, in | 484 | * Login and Text are sent serially, in |
428 | * request-followed-by-response sequence. | 485 | * request-followed-by-response sequence. |
429 | * Same mtask can be used. Same ITT must be used. | 486 | * Same task can be used. Same ITT must be used. |
430 | * Note that login_mtask is preallocated at conn_create(). | 487 | * Note that login_task is preallocated at conn_create(). |
431 | */ | 488 | */ |
432 | mtask = conn->login_mtask; | 489 | task = conn->login_task; |
433 | else { | 490 | else { |
434 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); | 491 | BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); |
435 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); | 492 | BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); |
436 | 493 | ||
437 | if (!__kfifo_get(session->mgmtpool.queue, | 494 | if (!__kfifo_get(session->cmdpool.queue, |
438 | (void*)&mtask, sizeof(void*))) | 495 | (void*)&task, sizeof(void*))) |
439 | return NULL; | 496 | return NULL; |
497 | |||
498 | if ((hdr->opcode == (ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE)) && | ||
499 | hdr->ttt == RESERVED_ITT) { | ||
500 | conn->ping_task = task; | ||
501 | conn->last_ping = jiffies; | ||
502 | } | ||
440 | } | 503 | } |
504 | /* | ||
505 | * released in complete pdu for task we expect a response for, and | ||
506 | * released by the lld when it has transmitted the task for | ||
507 | * pdus we do not expect a response for. | ||
508 | */ | ||
509 | atomic_set(&task->refcount, 1); | ||
510 | task->conn = conn; | ||
511 | task->sc = NULL; | ||
441 | 512 | ||
442 | if (data_size) { | 513 | if (data_size) { |
443 | memcpy(mtask->data, data, data_size); | 514 | memcpy(task->data, data, data_size); |
444 | mtask->data_count = data_size; | 515 | task->data_count = data_size; |
516 | } else | ||
517 | task->data_count = 0; | ||
518 | |||
519 | memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); | ||
520 | INIT_LIST_HEAD(&task->running); | ||
521 | list_add_tail(&task->running, &conn->mgmtqueue); | ||
522 | |||
523 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | ||
524 | if (iscsi_prep_mgmt_task(conn, task)) { | ||
525 | __iscsi_put_task(task); | ||
526 | return NULL; | ||
527 | } | ||
528 | |||
529 | if (session->tt->xmit_task(task)) | ||
530 | task = NULL; | ||
531 | |||
445 | } else | 532 | } else |
446 | mtask->data_count = 0; | 533 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
447 | 534 | ||
448 | memcpy(mtask->hdr, hdr, sizeof(struct iscsi_hdr)); | 535 | return task; |
449 | INIT_LIST_HEAD(&mtask->running); | ||
450 | list_add_tail(&mtask->running, &conn->mgmtqueue); | ||
451 | return mtask; | ||
452 | } | 536 | } |
453 | 537 | ||
454 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | 538 | int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, |
@@ -462,7 +546,6 @@ int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, | |||
462 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) | 546 | if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) |
463 | err = -EPERM; | 547 | err = -EPERM; |
464 | spin_unlock_bh(&session->lock); | 548 | spin_unlock_bh(&session->lock); |
465 | scsi_queue_work(session->host, &conn->xmitwork); | ||
466 | return err; | 549 | return err; |
467 | } | 550 | } |
468 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | 551 | EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); |
@@ -471,7 +554,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
471 | * iscsi_cmd_rsp - SCSI Command Response processing | 554 | * iscsi_cmd_rsp - SCSI Command Response processing |
472 | * @conn: iscsi connection | 555 | * @conn: iscsi connection |
473 | * @hdr: iscsi header | 556 | * @hdr: iscsi header |
474 | * @ctask: scsi command task | 557 | * @task: scsi command task |
475 | * @data: cmd data buffer | 558 | * @data: cmd data buffer |
476 | * @datalen: len of buffer | 559 | * @datalen: len of buffer |
477 | * | 560 | * |
@@ -479,12 +562,12 @@ EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); | |||
479 | * then completes the command and task. | 562 | * then completes the command and task. |
480 | **/ | 563 | **/ |
481 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 564 | static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
482 | struct iscsi_cmd_task *ctask, char *data, | 565 | struct iscsi_task *task, char *data, |
483 | int datalen) | 566 | int datalen) |
484 | { | 567 | { |
485 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; | 568 | struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; |
486 | struct iscsi_session *session = conn->session; | 569 | struct iscsi_session *session = conn->session; |
487 | struct scsi_cmnd *sc = ctask->sc; | 570 | struct scsi_cmnd *sc = task->sc; |
488 | 571 | ||
489 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); | 572 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); |
490 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; | 573 | conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; |
@@ -508,7 +591,7 @@ invalid_datalen: | |||
508 | goto out; | 591 | goto out; |
509 | } | 592 | } |
510 | 593 | ||
511 | senselen = be16_to_cpu(get_unaligned((__be16 *) data)); | 594 | senselen = get_unaligned_be16(data); |
512 | if (datalen < senselen) | 595 | if (datalen < senselen) |
513 | goto invalid_datalen; | 596 | goto invalid_datalen; |
514 | 597 | ||
@@ -544,10 +627,10 @@ invalid_datalen: | |||
544 | } | 627 | } |
545 | out: | 628 | out: |
546 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", | 629 | debug_scsi("done [sc %lx res %d itt 0x%x]\n", |
547 | (long)sc, sc->result, ctask->itt); | 630 | (long)sc, sc->result, task->itt); |
548 | conn->scsirsp_pdus_cnt++; | 631 | conn->scsirsp_pdus_cnt++; |
549 | 632 | ||
550 | __iscsi_put_ctask(ctask); | 633 | __iscsi_put_task(task); |
551 | } | 634 | } |
552 | 635 | ||
553 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | 636 | static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) |
@@ -572,9 +655,9 @@ static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) | |||
572 | static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) | 655 | static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) |
573 | { | 656 | { |
574 | struct iscsi_nopout hdr; | 657 | struct iscsi_nopout hdr; |
575 | struct iscsi_mgmt_task *mtask; | 658 | struct iscsi_task *task; |
576 | 659 | ||
577 | if (!rhdr && conn->ping_mtask) | 660 | if (!rhdr && conn->ping_task) |
578 | return; | 661 | return; |
579 | 662 | ||
580 | memset(&hdr, 0, sizeof(struct iscsi_nopout)); | 663 | memset(&hdr, 0, sizeof(struct iscsi_nopout)); |
@@ -588,18 +671,9 @@ static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) | |||
588 | } else | 671 | } else |
589 | hdr.ttt = RESERVED_ITT; | 672 | hdr.ttt = RESERVED_ITT; |
590 | 673 | ||
591 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); | 674 | task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); |
592 | if (!mtask) { | 675 | if (!task) |
593 | iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); | 676 | iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); |
594 | return; | ||
595 | } | ||
596 | |||
597 | /* only track our nops */ | ||
598 | if (!rhdr) { | ||
599 | conn->ping_mtask = mtask; | ||
600 | conn->last_ping = jiffies; | ||
601 | } | ||
602 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
603 | } | 677 | } |
604 | 678 | ||
605 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 679 | static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
@@ -628,6 +702,31 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
628 | } | 702 | } |
629 | 703 | ||
630 | /** | 704 | /** |
705 | * iscsi_itt_to_task - look up task by itt | ||
706 | * @conn: iscsi connection | ||
707 | * @itt: itt | ||
708 | * | ||
709 | * This should be used for mgmt tasks like login and nops, or if | ||
710 | * the LDD's itt space does not include the session age. | ||
711 | * | ||
712 | * The session lock must be held. | ||
713 | */ | ||
714 | static struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) | ||
715 | { | ||
716 | struct iscsi_session *session = conn->session; | ||
717 | uint32_t i; | ||
718 | |||
719 | if (itt == RESERVED_ITT) | ||
720 | return NULL; | ||
721 | |||
722 | i = get_itt(itt); | ||
723 | if (i >= session->cmds_max) | ||
724 | return NULL; | ||
725 | |||
726 | return session->cmds[i]; | ||
727 | } | ||
728 | |||
729 | /** | ||
631 | * __iscsi_complete_pdu - complete pdu | 730 | * __iscsi_complete_pdu - complete pdu |
632 | * @conn: iscsi conn | 731 | * @conn: iscsi conn |
633 | * @hdr: iscsi header | 732 | * @hdr: iscsi header |
@@ -638,108 +737,28 @@ static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
638 | * queuecommand or send generic. session lock must be held and verify | 737 | * queuecommand or send generic. session lock must be held and verify |
639 | * itt must have been called. | 738 | * itt must have been called. |
640 | */ | 739 | */ |
641 | static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 740 | int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
642 | char *data, int datalen) | 741 | char *data, int datalen) |
643 | { | 742 | { |
644 | struct iscsi_session *session = conn->session; | 743 | struct iscsi_session *session = conn->session; |
645 | int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; | 744 | int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; |
646 | struct iscsi_cmd_task *ctask; | 745 | struct iscsi_task *task; |
647 | struct iscsi_mgmt_task *mtask; | ||
648 | uint32_t itt; | 746 | uint32_t itt; |
649 | 747 | ||
650 | conn->last_recv = jiffies; | 748 | conn->last_recv = jiffies; |
749 | rc = iscsi_verify_itt(conn, hdr->itt); | ||
750 | if (rc) | ||
751 | return rc; | ||
752 | |||
651 | if (hdr->itt != RESERVED_ITT) | 753 | if (hdr->itt != RESERVED_ITT) |
652 | itt = get_itt(hdr->itt); | 754 | itt = get_itt(hdr->itt); |
653 | else | 755 | else |
654 | itt = ~0U; | 756 | itt = ~0U; |
655 | 757 | ||
656 | if (itt < session->cmds_max) { | 758 | debug_scsi("[op 0x%x cid %d itt 0x%x len %d]\n", |
657 | ctask = session->cmds[itt]; | 759 | opcode, conn->id, itt, datalen); |
658 | |||
659 | debug_scsi("cmdrsp [op 0x%x cid %d itt 0x%x len %d]\n", | ||
660 | opcode, conn->id, ctask->itt, datalen); | ||
661 | |||
662 | switch(opcode) { | ||
663 | case ISCSI_OP_SCSI_CMD_RSP: | ||
664 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | ||
665 | iscsi_scsi_cmd_rsp(conn, hdr, ctask, data, | ||
666 | datalen); | ||
667 | break; | ||
668 | case ISCSI_OP_SCSI_DATA_IN: | ||
669 | BUG_ON((void*)ctask != ctask->sc->SCp.ptr); | ||
670 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
671 | conn->scsirsp_pdus_cnt++; | ||
672 | __iscsi_put_ctask(ctask); | ||
673 | } | ||
674 | break; | ||
675 | case ISCSI_OP_R2T: | ||
676 | /* LLD handles this for now */ | ||
677 | break; | ||
678 | default: | ||
679 | rc = ISCSI_ERR_BAD_OPCODE; | ||
680 | break; | ||
681 | } | ||
682 | } else if (itt >= ISCSI_MGMT_ITT_OFFSET && | ||
683 | itt < ISCSI_MGMT_ITT_OFFSET + session->mgmtpool_max) { | ||
684 | mtask = session->mgmt_cmds[itt - ISCSI_MGMT_ITT_OFFSET]; | ||
685 | |||
686 | debug_scsi("immrsp [op 0x%x cid %d itt 0x%x len %d]\n", | ||
687 | opcode, conn->id, mtask->itt, datalen); | ||
688 | 760 | ||
689 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | 761 | if (itt == ~0U) { |
690 | switch(opcode) { | ||
691 | case ISCSI_OP_LOGOUT_RSP: | ||
692 | if (datalen) { | ||
693 | rc = ISCSI_ERR_PROTO; | ||
694 | break; | ||
695 | } | ||
696 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
697 | /* fall through */ | ||
698 | case ISCSI_OP_LOGIN_RSP: | ||
699 | case ISCSI_OP_TEXT_RSP: | ||
700 | /* | ||
701 | * login related PDU's exp_statsn is handled in | ||
702 | * userspace | ||
703 | */ | ||
704 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | ||
705 | rc = ISCSI_ERR_CONN_FAILED; | ||
706 | iscsi_free_mgmt_task(conn, mtask); | ||
707 | break; | ||
708 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
709 | if (datalen) { | ||
710 | rc = ISCSI_ERR_PROTO; | ||
711 | break; | ||
712 | } | ||
713 | |||
714 | iscsi_tmf_rsp(conn, hdr); | ||
715 | iscsi_free_mgmt_task(conn, mtask); | ||
716 | break; | ||
717 | case ISCSI_OP_NOOP_IN: | ||
718 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || | ||
719 | datalen) { | ||
720 | rc = ISCSI_ERR_PROTO; | ||
721 | break; | ||
722 | } | ||
723 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
724 | |||
725 | if (conn->ping_mtask != mtask) { | ||
726 | /* | ||
727 | * If this is not in response to one of our | ||
728 | * nops then it must be from userspace. | ||
729 | */ | ||
730 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, | ||
731 | datalen)) | ||
732 | rc = ISCSI_ERR_CONN_FAILED; | ||
733 | } else | ||
734 | mod_timer(&conn->transport_timer, | ||
735 | jiffies + conn->recv_timeout); | ||
736 | iscsi_free_mgmt_task(conn, mtask); | ||
737 | break; | ||
738 | default: | ||
739 | rc = ISCSI_ERR_BAD_OPCODE; | ||
740 | break; | ||
741 | } | ||
742 | } else if (itt == ~0U) { | ||
743 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | 762 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); |
744 | 763 | ||
745 | switch(opcode) { | 764 | switch(opcode) { |
@@ -766,11 +785,104 @@ static int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
766 | rc = ISCSI_ERR_BAD_OPCODE; | 785 | rc = ISCSI_ERR_BAD_OPCODE; |
767 | break; | 786 | break; |
768 | } | 787 | } |
769 | } else | 788 | goto out; |
770 | rc = ISCSI_ERR_BAD_ITT; | 789 | } |
771 | 790 | ||
791 | switch(opcode) { | ||
792 | case ISCSI_OP_SCSI_CMD_RSP: | ||
793 | case ISCSI_OP_SCSI_DATA_IN: | ||
794 | task = iscsi_itt_to_ctask(conn, hdr->itt); | ||
795 | if (!task) | ||
796 | return ISCSI_ERR_BAD_ITT; | ||
797 | break; | ||
798 | case ISCSI_OP_R2T: | ||
799 | /* | ||
800 | * LLD handles R2Ts if they need to. | ||
801 | */ | ||
802 | return 0; | ||
803 | case ISCSI_OP_LOGOUT_RSP: | ||
804 | case ISCSI_OP_LOGIN_RSP: | ||
805 | case ISCSI_OP_TEXT_RSP: | ||
806 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
807 | case ISCSI_OP_NOOP_IN: | ||
808 | task = iscsi_itt_to_task(conn, hdr->itt); | ||
809 | if (!task) | ||
810 | return ISCSI_ERR_BAD_ITT; | ||
811 | break; | ||
812 | default: | ||
813 | return ISCSI_ERR_BAD_OPCODE; | ||
814 | } | ||
815 | |||
816 | switch(opcode) { | ||
817 | case ISCSI_OP_SCSI_CMD_RSP: | ||
818 | iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); | ||
819 | break; | ||
820 | case ISCSI_OP_SCSI_DATA_IN: | ||
821 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
822 | conn->scsirsp_pdus_cnt++; | ||
823 | iscsi_update_cmdsn(session, | ||
824 | (struct iscsi_nopin*) hdr); | ||
825 | __iscsi_put_task(task); | ||
826 | } | ||
827 | break; | ||
828 | case ISCSI_OP_LOGOUT_RSP: | ||
829 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
830 | if (datalen) { | ||
831 | rc = ISCSI_ERR_PROTO; | ||
832 | break; | ||
833 | } | ||
834 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
835 | goto recv_pdu; | ||
836 | case ISCSI_OP_LOGIN_RSP: | ||
837 | case ISCSI_OP_TEXT_RSP: | ||
838 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
839 | /* | ||
840 | * login related PDU's exp_statsn is handled in | ||
841 | * userspace | ||
842 | */ | ||
843 | goto recv_pdu; | ||
844 | case ISCSI_OP_SCSI_TMFUNC_RSP: | ||
845 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
846 | if (datalen) { | ||
847 | rc = ISCSI_ERR_PROTO; | ||
848 | break; | ||
849 | } | ||
850 | |||
851 | iscsi_tmf_rsp(conn, hdr); | ||
852 | __iscsi_put_task(task); | ||
853 | break; | ||
854 | case ISCSI_OP_NOOP_IN: | ||
855 | iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); | ||
856 | if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { | ||
857 | rc = ISCSI_ERR_PROTO; | ||
858 | break; | ||
859 | } | ||
860 | conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; | ||
861 | |||
862 | if (conn->ping_task != task) | ||
863 | /* | ||
864 | * If this is not in response to one of our | ||
865 | * nops then it must be from userspace. | ||
866 | */ | ||
867 | goto recv_pdu; | ||
868 | |||
869 | mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); | ||
870 | __iscsi_put_task(task); | ||
871 | break; | ||
872 | default: | ||
873 | rc = ISCSI_ERR_BAD_OPCODE; | ||
874 | break; | ||
875 | } | ||
876 | |||
877 | out: | ||
878 | return rc; | ||
879 | recv_pdu: | ||
880 | if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) | ||
881 | rc = ISCSI_ERR_CONN_FAILED; | ||
882 | __iscsi_put_task(task); | ||
772 | return rc; | 883 | return rc; |
773 | } | 884 | } |
885 | EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); | ||
774 | 886 | ||
775 | int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | 887 | int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, |
776 | char *data, int datalen) | 888 | char *data, int datalen) |
@@ -784,51 +896,63 @@ int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | |||
784 | } | 896 | } |
785 | EXPORT_SYMBOL_GPL(iscsi_complete_pdu); | 897 | EXPORT_SYMBOL_GPL(iscsi_complete_pdu); |
786 | 898 | ||
787 | /* verify itt (itt encoding: age+cid+itt) */ | 899 | int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) |
788 | int iscsi_verify_itt(struct iscsi_conn *conn, struct iscsi_hdr *hdr, | ||
789 | uint32_t *ret_itt) | ||
790 | { | 900 | { |
791 | struct iscsi_session *session = conn->session; | 901 | struct iscsi_session *session = conn->session; |
792 | struct iscsi_cmd_task *ctask; | 902 | uint32_t i; |
793 | uint32_t itt; | ||
794 | 903 | ||
795 | if (hdr->itt != RESERVED_ITT) { | 904 | if (itt == RESERVED_ITT) |
796 | if (((__force u32)hdr->itt & ISCSI_AGE_MASK) != | 905 | return 0; |
797 | (session->age << ISCSI_AGE_SHIFT)) { | ||
798 | iscsi_conn_printk(KERN_ERR, conn, | ||
799 | "received itt %x expected session " | ||
800 | "age (%x)\n", (__force u32)hdr->itt, | ||
801 | session->age & ISCSI_AGE_MASK); | ||
802 | return ISCSI_ERR_BAD_ITT; | ||
803 | } | ||
804 | 906 | ||
805 | itt = get_itt(hdr->itt); | 907 | if (((__force u32)itt & ISCSI_AGE_MASK) != |
806 | } else | 908 | (session->age << ISCSI_AGE_SHIFT)) { |
807 | itt = ~0U; | 909 | iscsi_conn_printk(KERN_ERR, conn, |
910 | "received itt %x expected session age (%x)\n", | ||
911 | (__force u32)itt, session->age); | ||
912 | return ISCSI_ERR_BAD_ITT; | ||
913 | } | ||
808 | 914 | ||
809 | if (itt < session->cmds_max) { | 915 | i = get_itt(itt); |
810 | ctask = session->cmds[itt]; | 916 | if (i >= session->cmds_max) { |
917 | iscsi_conn_printk(KERN_ERR, conn, | ||
918 | "received invalid itt index %u (max cmds " | ||
919 | "%u.\n", i, session->cmds_max); | ||
920 | return ISCSI_ERR_BAD_ITT; | ||
921 | } | ||
922 | return 0; | ||
923 | } | ||
924 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); | ||
811 | 925 | ||
812 | if (!ctask->sc) { | 926 | /** |
813 | iscsi_conn_printk(KERN_INFO, conn, "dropping ctask " | 927 | * iscsi_itt_to_ctask - look up ctask by itt |
814 | "with itt 0x%x\n", ctask->itt); | 928 | * @conn: iscsi connection |
815 | /* force drop */ | 929 | * @itt: itt |
816 | return ISCSI_ERR_NO_SCSI_CMD; | 930 | * |
817 | } | 931 | * This should be used for cmd tasks. |
932 | * | ||
933 | * The session lock must be held. | ||
934 | */ | ||
935 | struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) | ||
936 | { | ||
937 | struct iscsi_task *task; | ||
818 | 938 | ||
819 | if (ctask->sc->SCp.phase != session->age) { | 939 | if (iscsi_verify_itt(conn, itt)) |
820 | iscsi_conn_printk(KERN_ERR, conn, | 940 | return NULL; |
821 | "iscsi: ctask's session age %d, " | 941 | |
822 | "expected %d\n", ctask->sc->SCp.phase, | 942 | task = iscsi_itt_to_task(conn, itt); |
823 | session->age); | 943 | if (!task || !task->sc) |
824 | return ISCSI_ERR_SESSION_FAILED; | 944 | return NULL; |
825 | } | 945 | |
946 | if (task->sc->SCp.phase != conn->session->age) { | ||
947 | iscsi_session_printk(KERN_ERR, conn->session, | ||
948 | "task's session age %d, expected %d\n", | ||
949 | task->sc->SCp.phase, conn->session->age); | ||
950 | return NULL; | ||
826 | } | 951 | } |
827 | 952 | ||
828 | *ret_itt = itt; | 953 | return task; |
829 | return 0; | ||
830 | } | 954 | } |
831 | EXPORT_SYMBOL_GPL(iscsi_verify_itt); | 955 | EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); |
832 | 956 | ||
833 | void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | 957 | void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) |
834 | { | 958 | { |
@@ -850,61 +974,6 @@ void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) | |||
850 | } | 974 | } |
851 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); | 975 | EXPORT_SYMBOL_GPL(iscsi_conn_failure); |
852 | 976 | ||
853 | static void iscsi_prep_mtask(struct iscsi_conn *conn, | ||
854 | struct iscsi_mgmt_task *mtask) | ||
855 | { | ||
856 | struct iscsi_session *session = conn->session; | ||
857 | struct iscsi_hdr *hdr = mtask->hdr; | ||
858 | struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; | ||
859 | |||
860 | if (hdr->opcode != (ISCSI_OP_LOGIN | ISCSI_OP_IMMEDIATE) && | ||
861 | hdr->opcode != (ISCSI_OP_TEXT | ISCSI_OP_IMMEDIATE)) | ||
862 | nop->exp_statsn = cpu_to_be32(conn->exp_statsn); | ||
863 | /* | ||
864 | * pre-format CmdSN for outgoing PDU. | ||
865 | */ | ||
866 | nop->cmdsn = cpu_to_be32(session->cmdsn); | ||
867 | if (hdr->itt != RESERVED_ITT) { | ||
868 | hdr->itt = build_itt(mtask->itt, session->age); | ||
869 | /* | ||
870 | * TODO: We always use immediate, so we never hit this. | ||
871 | * If we start to send tmfs or nops as non-immediate then | ||
872 | * we should start checking the cmdsn numbers for mgmt tasks. | ||
873 | */ | ||
874 | if (conn->c_stage == ISCSI_CONN_STARTED && | ||
875 | !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | ||
876 | session->queued_cmdsn++; | ||
877 | session->cmdsn++; | ||
878 | } | ||
879 | } | ||
880 | |||
881 | if (session->tt->init_mgmt_task) | ||
882 | session->tt->init_mgmt_task(conn, mtask); | ||
883 | |||
884 | debug_scsi("mgmtpdu [op 0x%x hdr->itt 0x%x datalen %d]\n", | ||
885 | hdr->opcode & ISCSI_OPCODE_MASK, hdr->itt, | ||
886 | mtask->data_count); | ||
887 | } | ||
888 | |||
889 | static int iscsi_xmit_mtask(struct iscsi_conn *conn) | ||
890 | { | ||
891 | struct iscsi_hdr *hdr = conn->mtask->hdr; | ||
892 | int rc; | ||
893 | |||
894 | if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) | ||
895 | conn->session->state = ISCSI_STATE_LOGGING_OUT; | ||
896 | spin_unlock_bh(&conn->session->lock); | ||
897 | |||
898 | rc = conn->session->tt->xmit_mgmt_task(conn, conn->mtask); | ||
899 | spin_lock_bh(&conn->session->lock); | ||
900 | if (rc) | ||
901 | return rc; | ||
902 | |||
903 | /* done with this in-progress mtask */ | ||
904 | conn->mtask = NULL; | ||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | 977 | static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) |
909 | { | 978 | { |
910 | struct iscsi_session *session = conn->session; | 979 | struct iscsi_session *session = conn->session; |
@@ -922,37 +991,38 @@ static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) | |||
922 | return 0; | 991 | return 0; |
923 | } | 992 | } |
924 | 993 | ||
925 | static int iscsi_xmit_ctask(struct iscsi_conn *conn) | 994 | static int iscsi_xmit_task(struct iscsi_conn *conn) |
926 | { | 995 | { |
927 | struct iscsi_cmd_task *ctask = conn->ctask; | 996 | struct iscsi_task *task = conn->task; |
928 | int rc; | 997 | int rc; |
929 | 998 | ||
930 | __iscsi_get_ctask(ctask); | 999 | __iscsi_get_task(task); |
931 | spin_unlock_bh(&conn->session->lock); | 1000 | spin_unlock_bh(&conn->session->lock); |
932 | rc = conn->session->tt->xmit_cmd_task(conn, ctask); | 1001 | rc = conn->session->tt->xmit_task(task); |
933 | spin_lock_bh(&conn->session->lock); | 1002 | spin_lock_bh(&conn->session->lock); |
934 | __iscsi_put_ctask(ctask); | 1003 | __iscsi_put_task(task); |
935 | if (!rc) | 1004 | if (!rc) |
936 | /* done with this ctask */ | 1005 | /* done with this task */ |
937 | conn->ctask = NULL; | 1006 | conn->task = NULL; |
938 | return rc; | 1007 | return rc; |
939 | } | 1008 | } |
940 | 1009 | ||
941 | /** | 1010 | /** |
942 | * iscsi_requeue_ctask - requeue ctask to run from session workqueue | 1011 | * iscsi_requeue_task - requeue task to run from session workqueue |
943 | * @ctask: ctask to requeue | 1012 | * @task: task to requeue |
944 | * | 1013 | * |
945 | * LLDs that need to run a ctask from the session workqueue should call | 1014 | * LLDs that need to run a task from the session workqueue should call |
946 | * this. The session lock must be held. | 1015 | * this. The session lock must be held. This should only be called |
1016 | * by software drivers. | ||
947 | */ | 1017 | */ |
948 | void iscsi_requeue_ctask(struct iscsi_cmd_task *ctask) | 1018 | void iscsi_requeue_task(struct iscsi_task *task) |
949 | { | 1019 | { |
950 | struct iscsi_conn *conn = ctask->conn; | 1020 | struct iscsi_conn *conn = task->conn; |
951 | 1021 | ||
952 | list_move_tail(&ctask->running, &conn->requeue); | 1022 | list_move_tail(&task->running, &conn->requeue); |
953 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1023 | scsi_queue_work(conn->session->host, &conn->xmitwork); |
954 | } | 1024 | } |
955 | EXPORT_SYMBOL_GPL(iscsi_requeue_ctask); | 1025 | EXPORT_SYMBOL_GPL(iscsi_requeue_task); |
956 | 1026 | ||
957 | /** | 1027 | /** |
958 | * iscsi_data_xmit - xmit any command into the scheduled connection | 1028 | * iscsi_data_xmit - xmit any command into the scheduled connection |
@@ -974,14 +1044,8 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
974 | return -ENODATA; | 1044 | return -ENODATA; |
975 | } | 1045 | } |
976 | 1046 | ||
977 | if (conn->ctask) { | 1047 | if (conn->task) { |
978 | rc = iscsi_xmit_ctask(conn); | 1048 | rc = iscsi_xmit_task(conn); |
979 | if (rc) | ||
980 | goto again; | ||
981 | } | ||
982 | |||
983 | if (conn->mtask) { | ||
984 | rc = iscsi_xmit_mtask(conn); | ||
985 | if (rc) | 1049 | if (rc) |
986 | goto again; | 1050 | goto again; |
987 | } | 1051 | } |
@@ -993,17 +1057,14 @@ static int iscsi_data_xmit(struct iscsi_conn *conn) | |||
993 | */ | 1057 | */ |
994 | check_mgmt: | 1058 | check_mgmt: |
995 | while (!list_empty(&conn->mgmtqueue)) { | 1059 | while (!list_empty(&conn->mgmtqueue)) { |
996 | conn->mtask = list_entry(conn->mgmtqueue.next, | 1060 | conn->task = list_entry(conn->mgmtqueue.next, |
997 | struct iscsi_mgmt_task, running); | 1061 | struct iscsi_task, running); |
998 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1062 | if (iscsi_prep_mgmt_task(conn, conn->task)) { |
999 | iscsi_free_mgmt_task(conn, conn->mtask); | 1063 | __iscsi_put_task(conn->task); |
1000 | conn->mtask = NULL; | 1064 | conn->task = NULL; |
1001 | continue; | 1065 | continue; |
1002 | } | 1066 | } |
1003 | 1067 | rc = iscsi_xmit_task(conn); | |
1004 | iscsi_prep_mtask(conn, conn->mtask); | ||
1005 | list_move_tail(conn->mgmtqueue.next, &conn->mgmt_run_list); | ||
1006 | rc = iscsi_xmit_mtask(conn); | ||
1007 | if (rc) | 1068 | if (rc) |
1008 | goto again; | 1069 | goto again; |
1009 | } | 1070 | } |
@@ -1013,24 +1074,21 @@ check_mgmt: | |||
1013 | if (conn->tmf_state == TMF_QUEUED) | 1074 | if (conn->tmf_state == TMF_QUEUED) |
1014 | break; | 1075 | break; |
1015 | 1076 | ||
1016 | conn->ctask = list_entry(conn->xmitqueue.next, | 1077 | conn->task = list_entry(conn->xmitqueue.next, |
1017 | struct iscsi_cmd_task, running); | 1078 | struct iscsi_task, running); |
1018 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { | 1079 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { |
1019 | fail_command(conn, conn->ctask, DID_IMM_RETRY << 16); | 1080 | fail_command(conn, conn->task, DID_IMM_RETRY << 16); |
1020 | continue; | 1081 | continue; |
1021 | } | 1082 | } |
1022 | if (iscsi_prep_scsi_cmd_pdu(conn->ctask)) { | 1083 | if (iscsi_prep_scsi_cmd_pdu(conn->task)) { |
1023 | fail_command(conn, conn->ctask, DID_ABORT << 16); | 1084 | fail_command(conn, conn->task, DID_ABORT << 16); |
1024 | continue; | 1085 | continue; |
1025 | } | 1086 | } |
1026 | 1087 | rc = iscsi_xmit_task(conn); | |
1027 | conn->ctask->state = ISCSI_TASK_RUNNING; | ||
1028 | list_move_tail(conn->xmitqueue.next, &conn->run_list); | ||
1029 | rc = iscsi_xmit_ctask(conn); | ||
1030 | if (rc) | 1088 | if (rc) |
1031 | goto again; | 1089 | goto again; |
1032 | /* | 1090 | /* |
1033 | * we could continuously get new ctask requests so | 1091 | * we could continuously get new task requests so |
1034 | * we need to check the mgmt queue for nops that need to | 1092 | * we need to check the mgmt queue for nops that need to |
1035 | * be sent to aviod starvation | 1093 | * be sent to aviod starvation |
1036 | */ | 1094 | */ |
@@ -1048,11 +1106,11 @@ check_mgmt: | |||
1048 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) | 1106 | if (conn->session->state == ISCSI_STATE_LOGGING_OUT) |
1049 | break; | 1107 | break; |
1050 | 1108 | ||
1051 | conn->ctask = list_entry(conn->requeue.next, | 1109 | conn->task = list_entry(conn->requeue.next, |
1052 | struct iscsi_cmd_task, running); | 1110 | struct iscsi_task, running); |
1053 | conn->ctask->state = ISCSI_TASK_RUNNING; | 1111 | conn->task->state = ISCSI_TASK_RUNNING; |
1054 | list_move_tail(conn->requeue.next, &conn->run_list); | 1112 | list_move_tail(conn->requeue.next, &conn->run_list); |
1055 | rc = iscsi_xmit_ctask(conn); | 1113 | rc = iscsi_xmit_task(conn); |
1056 | if (rc) | 1114 | if (rc) |
1057 | goto again; | 1115 | goto again; |
1058 | if (!list_empty(&conn->mgmtqueue)) | 1116 | if (!list_empty(&conn->mgmtqueue)) |
@@ -1096,11 +1154,12 @@ enum { | |||
1096 | 1154 | ||
1097 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | 1155 | int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) |
1098 | { | 1156 | { |
1157 | struct iscsi_cls_session *cls_session; | ||
1099 | struct Scsi_Host *host; | 1158 | struct Scsi_Host *host; |
1100 | int reason = 0; | 1159 | int reason = 0; |
1101 | struct iscsi_session *session; | 1160 | struct iscsi_session *session; |
1102 | struct iscsi_conn *conn; | 1161 | struct iscsi_conn *conn; |
1103 | struct iscsi_cmd_task *ctask = NULL; | 1162 | struct iscsi_task *task = NULL; |
1104 | 1163 | ||
1105 | sc->scsi_done = done; | 1164 | sc->scsi_done = done; |
1106 | sc->result = 0; | 1165 | sc->result = 0; |
@@ -1109,10 +1168,11 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1109 | host = sc->device->host; | 1168 | host = sc->device->host; |
1110 | spin_unlock(host->host_lock); | 1169 | spin_unlock(host->host_lock); |
1111 | 1170 | ||
1112 | session = iscsi_hostdata(host->hostdata); | 1171 | cls_session = starget_to_session(scsi_target(sc->device)); |
1172 | session = cls_session->dd_data; | ||
1113 | spin_lock(&session->lock); | 1173 | spin_lock(&session->lock); |
1114 | 1174 | ||
1115 | reason = iscsi_session_chkready(session_to_cls(session)); | 1175 | reason = iscsi_session_chkready(cls_session); |
1116 | if (reason) { | 1176 | if (reason) { |
1117 | sc->result = reason; | 1177 | sc->result = reason; |
1118 | goto fault; | 1178 | goto fault; |
@@ -1167,26 +1227,39 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | |||
1167 | goto reject; | 1227 | goto reject; |
1168 | } | 1228 | } |
1169 | 1229 | ||
1170 | if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask, | 1230 | if (!__kfifo_get(session->cmdpool.queue, (void*)&task, |
1171 | sizeof(void*))) { | 1231 | sizeof(void*))) { |
1172 | reason = FAILURE_OOM; | 1232 | reason = FAILURE_OOM; |
1173 | goto reject; | 1233 | goto reject; |
1174 | } | 1234 | } |
1175 | session->queued_cmdsn++; | ||
1176 | |||
1177 | sc->SCp.phase = session->age; | 1235 | sc->SCp.phase = session->age; |
1178 | sc->SCp.ptr = (char *)ctask; | 1236 | sc->SCp.ptr = (char *)task; |
1179 | 1237 | ||
1180 | atomic_set(&ctask->refcount, 1); | 1238 | atomic_set(&task->refcount, 1); |
1181 | ctask->state = ISCSI_TASK_PENDING; | 1239 | task->state = ISCSI_TASK_PENDING; |
1182 | ctask->conn = conn; | 1240 | task->conn = conn; |
1183 | ctask->sc = sc; | 1241 | task->sc = sc; |
1184 | INIT_LIST_HEAD(&ctask->running); | 1242 | INIT_LIST_HEAD(&task->running); |
1243 | list_add_tail(&task->running, &conn->xmitqueue); | ||
1244 | |||
1245 | if (session->tt->caps & CAP_DATA_PATH_OFFLOAD) { | ||
1246 | if (iscsi_prep_scsi_cmd_pdu(task)) { | ||
1247 | sc->result = DID_ABORT << 16; | ||
1248 | sc->scsi_done = NULL; | ||
1249 | iscsi_complete_command(task); | ||
1250 | goto fault; | ||
1251 | } | ||
1252 | if (session->tt->xmit_task(task)) { | ||
1253 | sc->scsi_done = NULL; | ||
1254 | iscsi_complete_command(task); | ||
1255 | reason = FAILURE_SESSION_NOT_READY; | ||
1256 | goto reject; | ||
1257 | } | ||
1258 | } else | ||
1259 | scsi_queue_work(session->host, &conn->xmitwork); | ||
1185 | 1260 | ||
1186 | list_add_tail(&ctask->running, &conn->xmitqueue); | 1261 | session->queued_cmdsn++; |
1187 | spin_unlock(&session->lock); | 1262 | spin_unlock(&session->lock); |
1188 | |||
1189 | scsi_queue_work(host, &conn->xmitwork); | ||
1190 | spin_lock(host->host_lock); | 1263 | spin_lock(host->host_lock); |
1191 | return 0; | 1264 | return 0; |
1192 | 1265 | ||
@@ -1205,7 +1278,7 @@ fault: | |||
1205 | scsi_out(sc)->resid = scsi_out(sc)->length; | 1278 | scsi_out(sc)->resid = scsi_out(sc)->length; |
1206 | scsi_in(sc)->resid = scsi_in(sc)->length; | 1279 | scsi_in(sc)->resid = scsi_in(sc)->length; |
1207 | } | 1280 | } |
1208 | sc->scsi_done(sc); | 1281 | done(sc); |
1209 | spin_lock(host->host_lock); | 1282 | spin_lock(host->host_lock); |
1210 | return 0; | 1283 | return 0; |
1211 | } | 1284 | } |
@@ -1222,7 +1295,7 @@ EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); | |||
1222 | 1295 | ||
1223 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) | 1296 | void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) |
1224 | { | 1297 | { |
1225 | struct iscsi_session *session = class_to_transport_session(cls_session); | 1298 | struct iscsi_session *session = cls_session->dd_data; |
1226 | 1299 | ||
1227 | spin_lock_bh(&session->lock); | 1300 | spin_lock_bh(&session->lock); |
1228 | if (session->state != ISCSI_STATE_LOGGED_IN) { | 1301 | if (session->state != ISCSI_STATE_LOGGED_IN) { |
@@ -1236,9 +1309,13 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); | |||
1236 | 1309 | ||
1237 | int iscsi_eh_host_reset(struct scsi_cmnd *sc) | 1310 | int iscsi_eh_host_reset(struct scsi_cmnd *sc) |
1238 | { | 1311 | { |
1239 | struct Scsi_Host *host = sc->device->host; | 1312 | struct iscsi_cls_session *cls_session; |
1240 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1313 | struct iscsi_session *session; |
1241 | struct iscsi_conn *conn = session->leadconn; | 1314 | struct iscsi_conn *conn; |
1315 | |||
1316 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1317 | session = cls_session->dd_data; | ||
1318 | conn = session->leadconn; | ||
1242 | 1319 | ||
1243 | mutex_lock(&session->eh_mutex); | 1320 | mutex_lock(&session->eh_mutex); |
1244 | spin_lock_bh(&session->lock); | 1321 | spin_lock_bh(&session->lock); |
@@ -1300,11 +1377,11 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1300 | int timeout) | 1377 | int timeout) |
1301 | { | 1378 | { |
1302 | struct iscsi_session *session = conn->session; | 1379 | struct iscsi_session *session = conn->session; |
1303 | struct iscsi_mgmt_task *mtask; | 1380 | struct iscsi_task *task; |
1304 | 1381 | ||
1305 | mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, | 1382 | task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, |
1306 | NULL, 0); | 1383 | NULL, 0); |
1307 | if (!mtask) { | 1384 | if (!task) { |
1308 | spin_unlock_bh(&session->lock); | 1385 | spin_unlock_bh(&session->lock); |
1309 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); | 1386 | iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); |
1310 | spin_lock_bh(&session->lock); | 1387 | spin_lock_bh(&session->lock); |
@@ -1320,7 +1397,6 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1320 | 1397 | ||
1321 | spin_unlock_bh(&session->lock); | 1398 | spin_unlock_bh(&session->lock); |
1322 | mutex_unlock(&session->eh_mutex); | 1399 | mutex_unlock(&session->eh_mutex); |
1323 | scsi_queue_work(session->host, &conn->xmitwork); | ||
1324 | 1400 | ||
1325 | /* | 1401 | /* |
1326 | * block eh thread until: | 1402 | * block eh thread until: |
@@ -1339,7 +1415,7 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1339 | 1415 | ||
1340 | mutex_lock(&session->eh_mutex); | 1416 | mutex_lock(&session->eh_mutex); |
1341 | spin_lock_bh(&session->lock); | 1417 | spin_lock_bh(&session->lock); |
1342 | /* if the session drops it will clean up the mtask */ | 1418 | /* if the session drops it will clean up the task */ |
1343 | if (age != session->age || | 1419 | if (age != session->age || |
1344 | session->state != ISCSI_STATE_LOGGED_IN) | 1420 | session->state != ISCSI_STATE_LOGGED_IN) |
1345 | return -ENOTCONN; | 1421 | return -ENOTCONN; |
@@ -1353,48 +1429,51 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, | |||
1353 | static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, | 1429 | static void fail_all_commands(struct iscsi_conn *conn, unsigned lun, |
1354 | int error) | 1430 | int error) |
1355 | { | 1431 | { |
1356 | struct iscsi_cmd_task *ctask, *tmp; | 1432 | struct iscsi_task *task, *tmp; |
1357 | 1433 | ||
1358 | if (conn->ctask && (conn->ctask->sc->device->lun == lun || lun == -1)) | 1434 | if (conn->task && (conn->task->sc->device->lun == lun || lun == -1)) |
1359 | conn->ctask = NULL; | 1435 | conn->task = NULL; |
1360 | 1436 | ||
1361 | /* flush pending */ | 1437 | /* flush pending */ |
1362 | list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) { | 1438 | list_for_each_entry_safe(task, tmp, &conn->xmitqueue, running) { |
1363 | if (lun == ctask->sc->device->lun || lun == -1) { | 1439 | if (lun == task->sc->device->lun || lun == -1) { |
1364 | debug_scsi("failing pending sc %p itt 0x%x\n", | 1440 | debug_scsi("failing pending sc %p itt 0x%x\n", |
1365 | ctask->sc, ctask->itt); | 1441 | task->sc, task->itt); |
1366 | fail_command(conn, ctask, error << 16); | 1442 | fail_command(conn, task, error << 16); |
1367 | } | 1443 | } |
1368 | } | 1444 | } |
1369 | 1445 | ||
1370 | list_for_each_entry_safe(ctask, tmp, &conn->requeue, running) { | 1446 | list_for_each_entry_safe(task, tmp, &conn->requeue, running) { |
1371 | if (lun == ctask->sc->device->lun || lun == -1) { | 1447 | if (lun == task->sc->device->lun || lun == -1) { |
1372 | debug_scsi("failing requeued sc %p itt 0x%x\n", | 1448 | debug_scsi("failing requeued sc %p itt 0x%x\n", |
1373 | ctask->sc, ctask->itt); | 1449 | task->sc, task->itt); |
1374 | fail_command(conn, ctask, error << 16); | 1450 | fail_command(conn, task, error << 16); |
1375 | } | 1451 | } |
1376 | } | 1452 | } |
1377 | 1453 | ||
1378 | /* fail all other running */ | 1454 | /* fail all other running */ |
1379 | list_for_each_entry_safe(ctask, tmp, &conn->run_list, running) { | 1455 | list_for_each_entry_safe(task, tmp, &conn->run_list, running) { |
1380 | if (lun == ctask->sc->device->lun || lun == -1) { | 1456 | if (lun == task->sc->device->lun || lun == -1) { |
1381 | debug_scsi("failing in progress sc %p itt 0x%x\n", | 1457 | debug_scsi("failing in progress sc %p itt 0x%x\n", |
1382 | ctask->sc, ctask->itt); | 1458 | task->sc, task->itt); |
1383 | fail_command(conn, ctask, DID_BUS_BUSY << 16); | 1459 | fail_command(conn, task, DID_BUS_BUSY << 16); |
1384 | } | 1460 | } |
1385 | } | 1461 | } |
1386 | } | 1462 | } |
1387 | 1463 | ||
1388 | static void iscsi_suspend_tx(struct iscsi_conn *conn) | 1464 | void iscsi_suspend_tx(struct iscsi_conn *conn) |
1389 | { | 1465 | { |
1390 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1466 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1391 | scsi_flush_work(conn->session->host); | 1467 | if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
1468 | scsi_flush_work(conn->session->host); | ||
1392 | } | 1469 | } |
1470 | EXPORT_SYMBOL_GPL(iscsi_suspend_tx); | ||
1393 | 1471 | ||
1394 | static void iscsi_start_tx(struct iscsi_conn *conn) | 1472 | static void iscsi_start_tx(struct iscsi_conn *conn) |
1395 | { | 1473 | { |
1396 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); | 1474 | clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); |
1397 | scsi_queue_work(conn->session->host, &conn->xmitwork); | 1475 | if (!(conn->session->tt->caps & CAP_DATA_PATH_OFFLOAD)) |
1476 | scsi_queue_work(conn->session->host, &conn->xmitwork); | ||
1398 | } | 1477 | } |
1399 | 1478 | ||
1400 | static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | 1479 | static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) |
@@ -1405,7 +1484,7 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1405 | enum scsi_eh_timer_return rc = EH_NOT_HANDLED; | 1484 | enum scsi_eh_timer_return rc = EH_NOT_HANDLED; |
1406 | 1485 | ||
1407 | cls_session = starget_to_session(scsi_target(scmd->device)); | 1486 | cls_session = starget_to_session(scsi_target(scmd->device)); |
1408 | session = class_to_transport_session(cls_session); | 1487 | session = cls_session->dd_data; |
1409 | 1488 | ||
1410 | debug_scsi("scsi cmd %p timedout\n", scmd); | 1489 | debug_scsi("scsi cmd %p timedout\n", scmd); |
1411 | 1490 | ||
@@ -1443,7 +1522,7 @@ static enum scsi_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *scmd) | |||
1443 | jiffies)) | 1522 | jiffies)) |
1444 | rc = EH_RESET_TIMER; | 1523 | rc = EH_RESET_TIMER; |
1445 | /* if in the middle of checking the transport then give us more time */ | 1524 | /* if in the middle of checking the transport then give us more time */ |
1446 | if (conn->ping_mtask) | 1525 | if (conn->ping_task) |
1447 | rc = EH_RESET_TIMER; | 1526 | rc = EH_RESET_TIMER; |
1448 | done: | 1527 | done: |
1449 | spin_unlock(&session->lock); | 1528 | spin_unlock(&session->lock); |
@@ -1467,7 +1546,7 @@ static void iscsi_check_transport_timeouts(unsigned long data) | |||
1467 | 1546 | ||
1468 | recv_timeout *= HZ; | 1547 | recv_timeout *= HZ; |
1469 | last_recv = conn->last_recv; | 1548 | last_recv = conn->last_recv; |
1470 | if (conn->ping_mtask && | 1549 | if (conn->ping_task && |
1471 | time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), | 1550 | time_before_eq(conn->last_ping + (conn->ping_timeout * HZ), |
1472 | jiffies)) { | 1551 | jiffies)) { |
1473 | iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " | 1552 | iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " |
@@ -1493,27 +1572,30 @@ done: | |||
1493 | spin_unlock(&session->lock); | 1572 | spin_unlock(&session->lock); |
1494 | } | 1573 | } |
1495 | 1574 | ||
1496 | static void iscsi_prep_abort_task_pdu(struct iscsi_cmd_task *ctask, | 1575 | static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, |
1497 | struct iscsi_tm *hdr) | 1576 | struct iscsi_tm *hdr) |
1498 | { | 1577 | { |
1499 | memset(hdr, 0, sizeof(*hdr)); | 1578 | memset(hdr, 0, sizeof(*hdr)); |
1500 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; | 1579 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; |
1501 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; | 1580 | hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; |
1502 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 1581 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
1503 | memcpy(hdr->lun, ctask->hdr->lun, sizeof(hdr->lun)); | 1582 | memcpy(hdr->lun, task->hdr->lun, sizeof(hdr->lun)); |
1504 | hdr->rtt = ctask->hdr->itt; | 1583 | hdr->rtt = task->hdr->itt; |
1505 | hdr->refcmdsn = ctask->hdr->cmdsn; | 1584 | hdr->refcmdsn = task->hdr->cmdsn; |
1506 | } | 1585 | } |
1507 | 1586 | ||
1508 | int iscsi_eh_abort(struct scsi_cmnd *sc) | 1587 | int iscsi_eh_abort(struct scsi_cmnd *sc) |
1509 | { | 1588 | { |
1510 | struct Scsi_Host *host = sc->device->host; | 1589 | struct iscsi_cls_session *cls_session; |
1511 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1590 | struct iscsi_session *session; |
1512 | struct iscsi_conn *conn; | 1591 | struct iscsi_conn *conn; |
1513 | struct iscsi_cmd_task *ctask; | 1592 | struct iscsi_task *task; |
1514 | struct iscsi_tm *hdr; | 1593 | struct iscsi_tm *hdr; |
1515 | int rc, age; | 1594 | int rc, age; |
1516 | 1595 | ||
1596 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1597 | session = cls_session->dd_data; | ||
1598 | |||
1517 | mutex_lock(&session->eh_mutex); | 1599 | mutex_lock(&session->eh_mutex); |
1518 | spin_lock_bh(&session->lock); | 1600 | spin_lock_bh(&session->lock); |
1519 | /* | 1601 | /* |
@@ -1542,17 +1624,17 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1542 | conn->eh_abort_cnt++; | 1624 | conn->eh_abort_cnt++; |
1543 | age = session->age; | 1625 | age = session->age; |
1544 | 1626 | ||
1545 | ctask = (struct iscsi_cmd_task *)sc->SCp.ptr; | 1627 | task = (struct iscsi_task *)sc->SCp.ptr; |
1546 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt); | 1628 | debug_scsi("aborting [sc %p itt 0x%x]\n", sc, task->itt); |
1547 | 1629 | ||
1548 | /* ctask completed before time out */ | 1630 | /* task completed before time out */ |
1549 | if (!ctask->sc) { | 1631 | if (!task->sc) { |
1550 | debug_scsi("sc completed while abort in progress\n"); | 1632 | debug_scsi("sc completed while abort in progress\n"); |
1551 | goto success; | 1633 | goto success; |
1552 | } | 1634 | } |
1553 | 1635 | ||
1554 | if (ctask->state == ISCSI_TASK_PENDING) { | 1636 | if (task->state == ISCSI_TASK_PENDING) { |
1555 | fail_command(conn, ctask, DID_ABORT << 16); | 1637 | fail_command(conn, task, DID_ABORT << 16); |
1556 | goto success; | 1638 | goto success; |
1557 | } | 1639 | } |
1558 | 1640 | ||
@@ -1562,7 +1644,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1562 | conn->tmf_state = TMF_QUEUED; | 1644 | conn->tmf_state = TMF_QUEUED; |
1563 | 1645 | ||
1564 | hdr = &conn->tmhdr; | 1646 | hdr = &conn->tmhdr; |
1565 | iscsi_prep_abort_task_pdu(ctask, hdr); | 1647 | iscsi_prep_abort_task_pdu(task, hdr); |
1566 | 1648 | ||
1567 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { | 1649 | if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { |
1568 | rc = FAILED; | 1650 | rc = FAILED; |
@@ -1572,16 +1654,20 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1572 | switch (conn->tmf_state) { | 1654 | switch (conn->tmf_state) { |
1573 | case TMF_SUCCESS: | 1655 | case TMF_SUCCESS: |
1574 | spin_unlock_bh(&session->lock); | 1656 | spin_unlock_bh(&session->lock); |
1657 | /* | ||
1658 | * stop tx side incase the target had sent a abort rsp but | ||
1659 | * the initiator was still writing out data. | ||
1660 | */ | ||
1575 | iscsi_suspend_tx(conn); | 1661 | iscsi_suspend_tx(conn); |
1576 | /* | 1662 | /* |
1577 | * clean up task if aborted. grab the recv lock as a writer | 1663 | * we do not stop the recv side because targets have been |
1664 | * good and have never sent us a successful tmf response | ||
1665 | * then sent more data for the cmd. | ||
1578 | */ | 1666 | */ |
1579 | write_lock_bh(conn->recv_lock); | ||
1580 | spin_lock(&session->lock); | 1667 | spin_lock(&session->lock); |
1581 | fail_command(conn, ctask, DID_ABORT << 16); | 1668 | fail_command(conn, task, DID_ABORT << 16); |
1582 | conn->tmf_state = TMF_INITIAL; | 1669 | conn->tmf_state = TMF_INITIAL; |
1583 | spin_unlock(&session->lock); | 1670 | spin_unlock(&session->lock); |
1584 | write_unlock_bh(conn->recv_lock); | ||
1585 | iscsi_start_tx(conn); | 1671 | iscsi_start_tx(conn); |
1586 | goto success_unlocked; | 1672 | goto success_unlocked; |
1587 | case TMF_TIMEDOUT: | 1673 | case TMF_TIMEDOUT: |
@@ -1591,7 +1677,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1591 | case TMF_NOT_FOUND: | 1677 | case TMF_NOT_FOUND: |
1592 | if (!sc->SCp.ptr) { | 1678 | if (!sc->SCp.ptr) { |
1593 | conn->tmf_state = TMF_INITIAL; | 1679 | conn->tmf_state = TMF_INITIAL; |
1594 | /* ctask completed before tmf abort response */ | 1680 | /* task completed before tmf abort response */ |
1595 | debug_scsi("sc completed while abort in progress\n"); | 1681 | debug_scsi("sc completed while abort in progress\n"); |
1596 | goto success; | 1682 | goto success; |
1597 | } | 1683 | } |
@@ -1604,7 +1690,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc) | |||
1604 | success: | 1690 | success: |
1605 | spin_unlock_bh(&session->lock); | 1691 | spin_unlock_bh(&session->lock); |
1606 | success_unlocked: | 1692 | success_unlocked: |
1607 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt); | 1693 | debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, task->itt); |
1608 | mutex_unlock(&session->eh_mutex); | 1694 | mutex_unlock(&session->eh_mutex); |
1609 | return SUCCESS; | 1695 | return SUCCESS; |
1610 | 1696 | ||
@@ -1612,7 +1698,7 @@ failed: | |||
1612 | spin_unlock_bh(&session->lock); | 1698 | spin_unlock_bh(&session->lock); |
1613 | failed_unlocked: | 1699 | failed_unlocked: |
1614 | debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, | 1700 | debug_scsi("abort failed [sc %p itt 0x%x]\n", sc, |
1615 | ctask ? ctask->itt : 0); | 1701 | task ? task->itt : 0); |
1616 | mutex_unlock(&session->eh_mutex); | 1702 | mutex_unlock(&session->eh_mutex); |
1617 | return FAILED; | 1703 | return FAILED; |
1618 | } | 1704 | } |
@@ -1630,12 +1716,15 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) | |||
1630 | 1716 | ||
1631 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) | 1717 | int iscsi_eh_device_reset(struct scsi_cmnd *sc) |
1632 | { | 1718 | { |
1633 | struct Scsi_Host *host = sc->device->host; | 1719 | struct iscsi_cls_session *cls_session; |
1634 | struct iscsi_session *session = iscsi_hostdata(host->hostdata); | 1720 | struct iscsi_session *session; |
1635 | struct iscsi_conn *conn; | 1721 | struct iscsi_conn *conn; |
1636 | struct iscsi_tm *hdr; | 1722 | struct iscsi_tm *hdr; |
1637 | int rc = FAILED; | 1723 | int rc = FAILED; |
1638 | 1724 | ||
1725 | cls_session = starget_to_session(scsi_target(sc->device)); | ||
1726 | session = cls_session->dd_data; | ||
1727 | |||
1639 | debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); | 1728 | debug_scsi("LU Reset [sc %p lun %u]\n", sc, sc->device->lun); |
1640 | 1729 | ||
1641 | mutex_lock(&session->eh_mutex); | 1730 | mutex_lock(&session->eh_mutex); |
@@ -1678,13 +1767,11 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc) | |||
1678 | spin_unlock_bh(&session->lock); | 1767 | spin_unlock_bh(&session->lock); |
1679 | 1768 | ||
1680 | iscsi_suspend_tx(conn); | 1769 | iscsi_suspend_tx(conn); |
1681 | /* need to grab the recv lock then session lock */ | 1770 | |
1682 | write_lock_bh(conn->recv_lock); | ||
1683 | spin_lock(&session->lock); | 1771 | spin_lock(&session->lock); |
1684 | fail_all_commands(conn, sc->device->lun, DID_ERROR); | 1772 | fail_all_commands(conn, sc->device->lun, DID_ERROR); |
1685 | conn->tmf_state = TMF_INITIAL; | 1773 | conn->tmf_state = TMF_INITIAL; |
1686 | spin_unlock(&session->lock); | 1774 | spin_unlock(&session->lock); |
1687 | write_unlock_bh(conn->recv_lock); | ||
1688 | 1775 | ||
1689 | iscsi_start_tx(conn); | 1776 | iscsi_start_tx(conn); |
1690 | goto done; | 1777 | goto done; |
@@ -1760,177 +1847,203 @@ void iscsi_pool_free(struct iscsi_pool *q) | |||
1760 | } | 1847 | } |
1761 | EXPORT_SYMBOL_GPL(iscsi_pool_free); | 1848 | EXPORT_SYMBOL_GPL(iscsi_pool_free); |
1762 | 1849 | ||
1763 | /* | 1850 | /** |
1764 | * iSCSI Session's hostdata organization: | 1851 | * iscsi_host_add - add host to system |
1852 | * @shost: scsi host | ||
1853 | * @pdev: parent device | ||
1854 | * | ||
1855 | * This should be called by partial offload and software iscsi drivers | ||
1856 | * to add a host to the system. | ||
1857 | */ | ||
1858 | int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev) | ||
1859 | { | ||
1860 | if (!shost->can_queue) | ||
1861 | shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX; | ||
1862 | |||
1863 | return scsi_add_host(shost, pdev); | ||
1864 | } | ||
1865 | EXPORT_SYMBOL_GPL(iscsi_host_add); | ||
1866 | |||
1867 | /** | ||
1868 | * iscsi_host_alloc - allocate a host and driver data | ||
1869 | * @sht: scsi host template | ||
1870 | * @dd_data_size: driver host data size | ||
1871 | * @qdepth: default device queue depth | ||
1872 | * | ||
1873 | * This should be called by partial offload and software iscsi drivers. | ||
1874 | * To access the driver specific memory use the iscsi_host_priv() macro. | ||
1875 | */ | ||
1876 | struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, | ||
1877 | int dd_data_size, uint16_t qdepth) | ||
1878 | { | ||
1879 | struct Scsi_Host *shost; | ||
1880 | |||
1881 | shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); | ||
1882 | if (!shost) | ||
1883 | return NULL; | ||
1884 | shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; | ||
1885 | |||
1886 | if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { | ||
1887 | if (qdepth != 0) | ||
1888 | printk(KERN_ERR "iscsi: invalid queue depth of %d. " | ||
1889 | "Queue depth must be between 1 and %d.\n", | ||
1890 | qdepth, ISCSI_MAX_CMD_PER_LUN); | ||
1891 | qdepth = ISCSI_DEF_CMD_PER_LUN; | ||
1892 | } | ||
1893 | shost->cmd_per_lun = qdepth; | ||
1894 | return shost; | ||
1895 | } | ||
1896 | EXPORT_SYMBOL_GPL(iscsi_host_alloc); | ||
1897 | |||
1898 | /** | ||
1899 | * iscsi_host_remove - remove host and sessions | ||
1900 | * @shost: scsi host | ||
1765 | * | 1901 | * |
1766 | * *------------------* <== hostdata_session(host->hostdata) | 1902 | * This will also remove any sessions attached to the host, but if userspace |
1767 | * | ptr to class sess| | 1903 | * is managing the session at the same time this will break. TODO: add |
1768 | * |------------------| <== iscsi_hostdata(host->hostdata) | 1904 | * refcounting to the netlink iscsi interface so a rmmod or host hot unplug |
1769 | * | iscsi_session | | 1905 | * does not remove the memory from under us. |
1770 | * *------------------* | ||
1771 | */ | 1906 | */ |
1907 | void iscsi_host_remove(struct Scsi_Host *shost) | ||
1908 | { | ||
1909 | iscsi_host_for_each_session(shost, iscsi_session_teardown); | ||
1910 | scsi_remove_host(shost); | ||
1911 | } | ||
1912 | EXPORT_SYMBOL_GPL(iscsi_host_remove); | ||
1772 | 1913 | ||
1773 | #define hostdata_privsize(_sz) (sizeof(unsigned long) + _sz + \ | 1914 | void iscsi_host_free(struct Scsi_Host *shost) |
1774 | _sz % sizeof(unsigned long)) | 1915 | { |
1916 | struct iscsi_host *ihost = shost_priv(shost); | ||
1775 | 1917 | ||
1776 | #define hostdata_session(_hostdata) (iscsi_ptr(*(unsigned long *)_hostdata)) | 1918 | kfree(ihost->netdev); |
1919 | kfree(ihost->hwaddress); | ||
1920 | kfree(ihost->initiatorname); | ||
1921 | scsi_host_put(shost); | ||
1922 | } | ||
1923 | EXPORT_SYMBOL_GPL(iscsi_host_free); | ||
1777 | 1924 | ||
1778 | /** | 1925 | /** |
1779 | * iscsi_session_setup - create iscsi cls session and host and session | 1926 | * iscsi_session_setup - create iscsi cls session and host and session |
1780 | * @scsit: scsi transport template | ||
1781 | * @iscsit: iscsi transport template | 1927 | * @iscsit: iscsi transport template |
1782 | * @cmds_max: scsi host can queue | 1928 | * @shost: scsi host |
1783 | * @qdepth: scsi host cmds per lun | 1929 | * @cmds_max: session can queue |
1784 | * @cmd_task_size: LLD ctask private data size | 1930 | * @cmd_task_size: LLD task private data size |
1785 | * @mgmt_task_size: LLD mtask private data size | ||
1786 | * @initial_cmdsn: initial CmdSN | 1931 | * @initial_cmdsn: initial CmdSN |
1787 | * @hostno: host no allocated | ||
1788 | * | 1932 | * |
1789 | * This can be used by software iscsi_transports that allocate | 1933 | * This can be used by software iscsi_transports that allocate |
1790 | * a session per scsi host. | 1934 | * a session per scsi host. |
1791 | **/ | 1935 | * |
1936 | * Callers should set cmds_max to the largest total numer (mgmt + scsi) of | ||
1937 | * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks | ||
1938 | * for nop handling and login/logout requests. | ||
1939 | */ | ||
1792 | struct iscsi_cls_session * | 1940 | struct iscsi_cls_session * |
1793 | iscsi_session_setup(struct iscsi_transport *iscsit, | 1941 | iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, |
1794 | struct scsi_transport_template *scsit, | 1942 | uint16_t cmds_max, int cmd_task_size, |
1795 | uint16_t cmds_max, uint16_t qdepth, | 1943 | uint32_t initial_cmdsn, unsigned int id) |
1796 | int cmd_task_size, int mgmt_task_size, | ||
1797 | uint32_t initial_cmdsn, uint32_t *hostno) | ||
1798 | { | 1944 | { |
1799 | struct Scsi_Host *shost; | ||
1800 | struct iscsi_session *session; | 1945 | struct iscsi_session *session; |
1801 | struct iscsi_cls_session *cls_session; | 1946 | struct iscsi_cls_session *cls_session; |
1802 | int cmd_i; | 1947 | int cmd_i, scsi_cmds, total_cmds = cmds_max; |
1803 | 1948 | ||
1804 | if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) { | 1949 | if (!total_cmds) |
1805 | if (qdepth != 0) | 1950 | total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; |
1806 | printk(KERN_ERR "iscsi: invalid queue depth of %d. " | 1951 | /* |
1807 | "Queue depth must be between 1 and %d.\n", | 1952 | * The iscsi layer needs some tasks for nop handling and tmfs, |
1808 | qdepth, ISCSI_MAX_CMD_PER_LUN); | 1953 | * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX |
1809 | qdepth = ISCSI_DEF_CMD_PER_LUN; | 1954 | * + 1 command for scsi IO. |
1955 | */ | ||
1956 | if (total_cmds < ISCSI_TOTAL_CMDS_MIN) { | ||
1957 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " | ||
1958 | "must be a power of two that is at least %d.\n", | ||
1959 | total_cmds, ISCSI_TOTAL_CMDS_MIN); | ||
1960 | return NULL; | ||
1810 | } | 1961 | } |
1811 | 1962 | ||
1812 | if (!is_power_of_2(cmds_max) || cmds_max >= ISCSI_MGMT_ITT_OFFSET || | 1963 | if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { |
1813 | cmds_max < 2) { | 1964 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " |
1814 | if (cmds_max != 0) | 1965 | "must be a power of 2 less than or equal to %d.\n", |
1815 | printk(KERN_ERR "iscsi: invalid can_queue of %d. " | 1966 | cmds_max, ISCSI_TOTAL_CMDS_MAX); |
1816 | "can_queue must be a power of 2 and between " | 1967 | total_cmds = ISCSI_TOTAL_CMDS_MAX; |
1817 | "2 and %d - setting to %d.\n", cmds_max, | ||
1818 | ISCSI_MGMT_ITT_OFFSET, ISCSI_DEF_XMIT_CMDS_MAX); | ||
1819 | cmds_max = ISCSI_DEF_XMIT_CMDS_MAX; | ||
1820 | } | 1968 | } |
1821 | 1969 | ||
1822 | shost = scsi_host_alloc(iscsit->host_template, | 1970 | if (!is_power_of_2(total_cmds)) { |
1823 | hostdata_privsize(sizeof(*session))); | 1971 | printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " |
1824 | if (!shost) | 1972 | "must be a power of 2.\n", total_cmds); |
1825 | return NULL; | 1973 | total_cmds = rounddown_pow_of_two(total_cmds); |
1826 | 1974 | if (total_cmds < ISCSI_TOTAL_CMDS_MIN) | |
1827 | /* the iscsi layer takes one task for reserve */ | 1975 | return NULL; |
1828 | shost->can_queue = cmds_max - 1; | 1976 | printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n", |
1829 | shost->cmd_per_lun = qdepth; | 1977 | total_cmds); |
1830 | shost->max_id = 1; | 1978 | } |
1831 | shost->max_channel = 0; | 1979 | scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX; |
1832 | shost->max_lun = iscsit->max_lun; | ||
1833 | shost->max_cmd_len = iscsit->max_cmd_len; | ||
1834 | shost->transportt = scsit; | ||
1835 | shost->transportt->create_work_queue = 1; | ||
1836 | shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; | ||
1837 | *hostno = shost->host_no; | ||
1838 | 1980 | ||
1839 | session = iscsi_hostdata(shost->hostdata); | 1981 | cls_session = iscsi_alloc_session(shost, iscsit, |
1840 | memset(session, 0, sizeof(struct iscsi_session)); | 1982 | sizeof(struct iscsi_session)); |
1983 | if (!cls_session) | ||
1984 | return NULL; | ||
1985 | session = cls_session->dd_data; | ||
1986 | session->cls_session = cls_session; | ||
1841 | session->host = shost; | 1987 | session->host = shost; |
1842 | session->state = ISCSI_STATE_FREE; | 1988 | session->state = ISCSI_STATE_FREE; |
1843 | session->fast_abort = 1; | 1989 | session->fast_abort = 1; |
1844 | session->lu_reset_timeout = 15; | 1990 | session->lu_reset_timeout = 15; |
1845 | session->abort_timeout = 10; | 1991 | session->abort_timeout = 10; |
1846 | session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX; | 1992 | session->scsi_cmds_max = scsi_cmds; |
1847 | session->cmds_max = cmds_max; | 1993 | session->cmds_max = total_cmds; |
1848 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; | 1994 | session->queued_cmdsn = session->cmdsn = initial_cmdsn; |
1849 | session->exp_cmdsn = initial_cmdsn + 1; | 1995 | session->exp_cmdsn = initial_cmdsn + 1; |
1850 | session->max_cmdsn = initial_cmdsn + 1; | 1996 | session->max_cmdsn = initial_cmdsn + 1; |
1851 | session->max_r2t = 1; | 1997 | session->max_r2t = 1; |
1852 | session->tt = iscsit; | 1998 | session->tt = iscsit; |
1853 | mutex_init(&session->eh_mutex); | 1999 | mutex_init(&session->eh_mutex); |
2000 | spin_lock_init(&session->lock); | ||
1854 | 2001 | ||
1855 | /* initialize SCSI PDU commands pool */ | 2002 | /* initialize SCSI PDU commands pool */ |
1856 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, | 2003 | if (iscsi_pool_init(&session->cmdpool, session->cmds_max, |
1857 | (void***)&session->cmds, | 2004 | (void***)&session->cmds, |
1858 | cmd_task_size + sizeof(struct iscsi_cmd_task))) | 2005 | cmd_task_size + sizeof(struct iscsi_task))) |
1859 | goto cmdpool_alloc_fail; | 2006 | goto cmdpool_alloc_fail; |
1860 | 2007 | ||
1861 | /* pre-format cmds pool with ITT */ | 2008 | /* pre-format cmds pool with ITT */ |
1862 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { | 2009 | for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { |
1863 | struct iscsi_cmd_task *ctask = session->cmds[cmd_i]; | 2010 | struct iscsi_task *task = session->cmds[cmd_i]; |
1864 | 2011 | ||
1865 | if (cmd_task_size) | 2012 | if (cmd_task_size) |
1866 | ctask->dd_data = &ctask[1]; | 2013 | task->dd_data = &task[1]; |
1867 | ctask->itt = cmd_i; | 2014 | task->itt = cmd_i; |
1868 | INIT_LIST_HEAD(&ctask->running); | 2015 | INIT_LIST_HEAD(&task->running); |
1869 | } | ||
1870 | |||
1871 | spin_lock_init(&session->lock); | ||
1872 | |||
1873 | /* initialize immediate command pool */ | ||
1874 | if (iscsi_pool_init(&session->mgmtpool, session->mgmtpool_max, | ||
1875 | (void***)&session->mgmt_cmds, | ||
1876 | mgmt_task_size + sizeof(struct iscsi_mgmt_task))) | ||
1877 | goto mgmtpool_alloc_fail; | ||
1878 | |||
1879 | |||
1880 | /* pre-format immediate cmds pool with ITT */ | ||
1881 | for (cmd_i = 0; cmd_i < session->mgmtpool_max; cmd_i++) { | ||
1882 | struct iscsi_mgmt_task *mtask = session->mgmt_cmds[cmd_i]; | ||
1883 | |||
1884 | if (mgmt_task_size) | ||
1885 | mtask->dd_data = &mtask[1]; | ||
1886 | mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i; | ||
1887 | INIT_LIST_HEAD(&mtask->running); | ||
1888 | } | 2016 | } |
1889 | 2017 | ||
1890 | if (scsi_add_host(shost, NULL)) | ||
1891 | goto add_host_fail; | ||
1892 | |||
1893 | if (!try_module_get(iscsit->owner)) | 2018 | if (!try_module_get(iscsit->owner)) |
1894 | goto cls_session_fail; | 2019 | goto module_get_fail; |
1895 | |||
1896 | cls_session = iscsi_create_session(shost, iscsit, 0); | ||
1897 | if (!cls_session) | ||
1898 | goto module_put; | ||
1899 | *(unsigned long*)shost->hostdata = (unsigned long)cls_session; | ||
1900 | 2020 | ||
2021 | if (iscsi_add_session(cls_session, id)) | ||
2022 | goto cls_session_fail; | ||
1901 | return cls_session; | 2023 | return cls_session; |
1902 | 2024 | ||
1903 | module_put: | ||
1904 | module_put(iscsit->owner); | ||
1905 | cls_session_fail: | 2025 | cls_session_fail: |
1906 | scsi_remove_host(shost); | 2026 | module_put(iscsit->owner); |
1907 | add_host_fail: | 2027 | module_get_fail: |
1908 | iscsi_pool_free(&session->mgmtpool); | ||
1909 | mgmtpool_alloc_fail: | ||
1910 | iscsi_pool_free(&session->cmdpool); | 2028 | iscsi_pool_free(&session->cmdpool); |
1911 | cmdpool_alloc_fail: | 2029 | cmdpool_alloc_fail: |
1912 | scsi_host_put(shost); | 2030 | iscsi_free_session(cls_session); |
1913 | return NULL; | 2031 | return NULL; |
1914 | } | 2032 | } |
1915 | EXPORT_SYMBOL_GPL(iscsi_session_setup); | 2033 | EXPORT_SYMBOL_GPL(iscsi_session_setup); |
1916 | 2034 | ||
1917 | /** | 2035 | /** |
1918 | * iscsi_session_teardown - destroy session, host, and cls_session | 2036 | * iscsi_session_teardown - destroy session, host, and cls_session |
1919 | * shost: scsi host | 2037 | * @cls_session: iscsi session |
1920 | * | 2038 | * |
1921 | * This can be used by software iscsi_transports that allocate | 2039 | * The driver must have called iscsi_remove_session before |
1922 | * a session per scsi host. | 2040 | * calling this. |
1923 | **/ | 2041 | */ |
1924 | void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | 2042 | void iscsi_session_teardown(struct iscsi_cls_session *cls_session) |
1925 | { | 2043 | { |
1926 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 2044 | struct iscsi_session *session = cls_session->dd_data; |
1927 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
1928 | struct module *owner = cls_session->transport->owner; | 2045 | struct module *owner = cls_session->transport->owner; |
1929 | 2046 | ||
1930 | iscsi_remove_session(cls_session); | ||
1931 | scsi_remove_host(shost); | ||
1932 | |||
1933 | iscsi_pool_free(&session->mgmtpool); | ||
1934 | iscsi_pool_free(&session->cmdpool); | 2047 | iscsi_pool_free(&session->cmdpool); |
1935 | 2048 | ||
1936 | kfree(session->password); | 2049 | kfree(session->password); |
@@ -1938,12 +2051,10 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) | |||
1938 | kfree(session->username); | 2051 | kfree(session->username); |
1939 | kfree(session->username_in); | 2052 | kfree(session->username_in); |
1940 | kfree(session->targetname); | 2053 | kfree(session->targetname); |
1941 | kfree(session->netdev); | ||
1942 | kfree(session->hwaddress); | ||
1943 | kfree(session->initiatorname); | 2054 | kfree(session->initiatorname); |
2055 | kfree(session->ifacename); | ||
1944 | 2056 | ||
1945 | iscsi_free_session(cls_session); | 2057 | iscsi_destroy_session(cls_session); |
1946 | scsi_host_put(shost); | ||
1947 | module_put(owner); | 2058 | module_put(owner); |
1948 | } | 2059 | } |
1949 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); | 2060 | EXPORT_SYMBOL_GPL(iscsi_session_teardown); |
@@ -1951,22 +2062,26 @@ EXPORT_SYMBOL_GPL(iscsi_session_teardown); | |||
1951 | /** | 2062 | /** |
1952 | * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn | 2063 | * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn |
1953 | * @cls_session: iscsi_cls_session | 2064 | * @cls_session: iscsi_cls_session |
2065 | * @dd_size: private driver data size | ||
1954 | * @conn_idx: cid | 2066 | * @conn_idx: cid |
1955 | **/ | 2067 | */ |
1956 | struct iscsi_cls_conn * | 2068 | struct iscsi_cls_conn * |
1957 | iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | 2069 | iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, |
2070 | uint32_t conn_idx) | ||
1958 | { | 2071 | { |
1959 | struct iscsi_session *session = class_to_transport_session(cls_session); | 2072 | struct iscsi_session *session = cls_session->dd_data; |
1960 | struct iscsi_conn *conn; | 2073 | struct iscsi_conn *conn; |
1961 | struct iscsi_cls_conn *cls_conn; | 2074 | struct iscsi_cls_conn *cls_conn; |
1962 | char *data; | 2075 | char *data; |
1963 | 2076 | ||
1964 | cls_conn = iscsi_create_conn(cls_session, conn_idx); | 2077 | cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size, |
2078 | conn_idx); | ||
1965 | if (!cls_conn) | 2079 | if (!cls_conn) |
1966 | return NULL; | 2080 | return NULL; |
1967 | conn = cls_conn->dd_data; | 2081 | conn = cls_conn->dd_data; |
1968 | memset(conn, 0, sizeof(*conn)); | 2082 | memset(conn, 0, sizeof(*conn) + dd_size); |
1969 | 2083 | ||
2084 | conn->dd_data = cls_conn->dd_data + sizeof(*conn); | ||
1970 | conn->session = session; | 2085 | conn->session = session; |
1971 | conn->cls_conn = cls_conn; | 2086 | conn->cls_conn = cls_conn; |
1972 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; | 2087 | conn->c_stage = ISCSI_CONN_INITIAL_STAGE; |
@@ -1985,30 +2100,30 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx) | |||
1985 | INIT_LIST_HEAD(&conn->requeue); | 2100 | INIT_LIST_HEAD(&conn->requeue); |
1986 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); | 2101 | INIT_WORK(&conn->xmitwork, iscsi_xmitworker); |
1987 | 2102 | ||
1988 | /* allocate login_mtask used for the login/text sequences */ | 2103 | /* allocate login_task used for the login/text sequences */ |
1989 | spin_lock_bh(&session->lock); | 2104 | spin_lock_bh(&session->lock); |
1990 | if (!__kfifo_get(session->mgmtpool.queue, | 2105 | if (!__kfifo_get(session->cmdpool.queue, |
1991 | (void*)&conn->login_mtask, | 2106 | (void*)&conn->login_task, |
1992 | sizeof(void*))) { | 2107 | sizeof(void*))) { |
1993 | spin_unlock_bh(&session->lock); | 2108 | spin_unlock_bh(&session->lock); |
1994 | goto login_mtask_alloc_fail; | 2109 | goto login_task_alloc_fail; |
1995 | } | 2110 | } |
1996 | spin_unlock_bh(&session->lock); | 2111 | spin_unlock_bh(&session->lock); |
1997 | 2112 | ||
1998 | data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); | 2113 | data = kmalloc(ISCSI_DEF_MAX_RECV_SEG_LEN, GFP_KERNEL); |
1999 | if (!data) | 2114 | if (!data) |
2000 | goto login_mtask_data_alloc_fail; | 2115 | goto login_task_data_alloc_fail; |
2001 | conn->login_mtask->data = conn->data = data; | 2116 | conn->login_task->data = conn->data = data; |
2002 | 2117 | ||
2003 | init_timer(&conn->tmf_timer); | 2118 | init_timer(&conn->tmf_timer); |
2004 | init_waitqueue_head(&conn->ehwait); | 2119 | init_waitqueue_head(&conn->ehwait); |
2005 | 2120 | ||
2006 | return cls_conn; | 2121 | return cls_conn; |
2007 | 2122 | ||
2008 | login_mtask_data_alloc_fail: | 2123 | login_task_data_alloc_fail: |
2009 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 2124 | __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task, |
2010 | sizeof(void*)); | 2125 | sizeof(void*)); |
2011 | login_mtask_alloc_fail: | 2126 | login_task_alloc_fail: |
2012 | iscsi_destroy_conn(cls_conn); | 2127 | iscsi_destroy_conn(cls_conn); |
2013 | return NULL; | 2128 | return NULL; |
2014 | } | 2129 | } |
@@ -2068,7 +2183,7 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) | |||
2068 | spin_lock_bh(&session->lock); | 2183 | spin_lock_bh(&session->lock); |
2069 | kfree(conn->data); | 2184 | kfree(conn->data); |
2070 | kfree(conn->persistent_address); | 2185 | kfree(conn->persistent_address); |
2071 | __kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask, | 2186 | __kfifo_put(session->cmdpool.queue, (void*)&conn->login_task, |
2072 | sizeof(void*)); | 2187 | sizeof(void*)); |
2073 | if (session->leadconn == conn) | 2188 | if (session->leadconn == conn) |
2074 | session->leadconn = NULL; | 2189 | session->leadconn = NULL; |
@@ -2140,7 +2255,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) | |||
2140 | } | 2255 | } |
2141 | spin_unlock_bh(&session->lock); | 2256 | spin_unlock_bh(&session->lock); |
2142 | 2257 | ||
2143 | iscsi_unblock_session(session_to_cls(session)); | 2258 | iscsi_unblock_session(session->cls_session); |
2144 | wake_up(&conn->ehwait); | 2259 | wake_up(&conn->ehwait); |
2145 | return 0; | 2260 | return 0; |
2146 | } | 2261 | } |
@@ -2149,21 +2264,23 @@ EXPORT_SYMBOL_GPL(iscsi_conn_start); | |||
2149 | static void | 2264 | static void |
2150 | flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) | 2265 | flush_control_queues(struct iscsi_session *session, struct iscsi_conn *conn) |
2151 | { | 2266 | { |
2152 | struct iscsi_mgmt_task *mtask, *tmp; | 2267 | struct iscsi_task *task, *tmp; |
2153 | 2268 | ||
2154 | /* handle pending */ | 2269 | /* handle pending */ |
2155 | list_for_each_entry_safe(mtask, tmp, &conn->mgmtqueue, running) { | 2270 | list_for_each_entry_safe(task, tmp, &conn->mgmtqueue, running) { |
2156 | debug_scsi("flushing pending mgmt task itt 0x%x\n", mtask->itt); | 2271 | debug_scsi("flushing pending mgmt task itt 0x%x\n", task->itt); |
2157 | iscsi_free_mgmt_task(conn, mtask); | 2272 | /* release ref from prep task */ |
2273 | __iscsi_put_task(task); | ||
2158 | } | 2274 | } |
2159 | 2275 | ||
2160 | /* handle running */ | 2276 | /* handle running */ |
2161 | list_for_each_entry_safe(mtask, tmp, &conn->mgmt_run_list, running) { | 2277 | list_for_each_entry_safe(task, tmp, &conn->mgmt_run_list, running) { |
2162 | debug_scsi("flushing running mgmt task itt 0x%x\n", mtask->itt); | 2278 | debug_scsi("flushing running mgmt task itt 0x%x\n", task->itt); |
2163 | iscsi_free_mgmt_task(conn, mtask); | 2279 | /* release ref from prep task */ |
2280 | __iscsi_put_task(task); | ||
2164 | } | 2281 | } |
2165 | 2282 | ||
2166 | conn->mtask = NULL; | 2283 | conn->task = NULL; |
2167 | } | 2284 | } |
2168 | 2285 | ||
2169 | static void iscsi_start_session_recovery(struct iscsi_session *session, | 2286 | static void iscsi_start_session_recovery(struct iscsi_session *session, |
@@ -2182,17 +2299,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2182 | } | 2299 | } |
2183 | 2300 | ||
2184 | /* | 2301 | /* |
2185 | * The LLD either freed/unset the lock on us, or userspace called | ||
2186 | * stop but did not create a proper connection (connection was never | ||
2187 | * bound or it was unbound then stop was called). | ||
2188 | */ | ||
2189 | if (!conn->recv_lock) { | ||
2190 | spin_unlock_bh(&session->lock); | ||
2191 | mutex_unlock(&session->eh_mutex); | ||
2192 | return; | ||
2193 | } | ||
2194 | |||
2195 | /* | ||
2196 | * When this is called for the in_login state, we only want to clean | 2302 | * When this is called for the in_login state, we only want to clean |
2197 | * up the login task and connection. We do not need to block and set | 2303 | * up the login task and connection. We do not need to block and set |
2198 | * the recovery state again | 2304 | * the recovery state again |
@@ -2208,11 +2314,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2208 | spin_unlock_bh(&session->lock); | 2314 | spin_unlock_bh(&session->lock); |
2209 | 2315 | ||
2210 | iscsi_suspend_tx(conn); | 2316 | iscsi_suspend_tx(conn); |
2211 | |||
2212 | write_lock_bh(conn->recv_lock); | ||
2213 | set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); | ||
2214 | write_unlock_bh(conn->recv_lock); | ||
2215 | |||
2216 | /* | 2317 | /* |
2217 | * for connection level recovery we should not calculate | 2318 | * for connection level recovery we should not calculate |
2218 | * header digest. conn->hdr_size used for optimization | 2319 | * header digest. conn->hdr_size used for optimization |
@@ -2225,7 +2326,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session, | |||
2225 | if (session->state == ISCSI_STATE_IN_RECOVERY && | 2326 | if (session->state == ISCSI_STATE_IN_RECOVERY && |
2226 | old_stop_stage != STOP_CONN_RECOVER) { | 2327 | old_stop_stage != STOP_CONN_RECOVER) { |
2227 | debug_scsi("blocking session\n"); | 2328 | debug_scsi("blocking session\n"); |
2228 | iscsi_block_session(session_to_cls(session)); | 2329 | iscsi_block_session(session->cls_session); |
2229 | } | 2330 | } |
2230 | } | 2331 | } |
2231 | 2332 | ||
@@ -2260,7 +2361,7 @@ EXPORT_SYMBOL_GPL(iscsi_conn_stop); | |||
2260 | int iscsi_conn_bind(struct iscsi_cls_session *cls_session, | 2361 | int iscsi_conn_bind(struct iscsi_cls_session *cls_session, |
2261 | struct iscsi_cls_conn *cls_conn, int is_leading) | 2362 | struct iscsi_cls_conn *cls_conn, int is_leading) |
2262 | { | 2363 | { |
2263 | struct iscsi_session *session = class_to_transport_session(cls_session); | 2364 | struct iscsi_session *session = cls_session->dd_data; |
2264 | struct iscsi_conn *conn = cls_conn->dd_data; | 2365 | struct iscsi_conn *conn = cls_conn->dd_data; |
2265 | 2366 | ||
2266 | spin_lock_bh(&session->lock); | 2367 | spin_lock_bh(&session->lock); |
@@ -2399,6 +2500,14 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
2399 | if (!conn->persistent_address) | 2500 | if (!conn->persistent_address) |
2400 | return -ENOMEM; | 2501 | return -ENOMEM; |
2401 | break; | 2502 | break; |
2503 | case ISCSI_PARAM_IFACE_NAME: | ||
2504 | if (!session->ifacename) | ||
2505 | session->ifacename = kstrdup(buf, GFP_KERNEL); | ||
2506 | break; | ||
2507 | case ISCSI_PARAM_INITIATOR_NAME: | ||
2508 | if (!session->initiatorname) | ||
2509 | session->initiatorname = kstrdup(buf, GFP_KERNEL); | ||
2510 | break; | ||
2402 | default: | 2511 | default: |
2403 | return -ENOSYS; | 2512 | return -ENOSYS; |
2404 | } | 2513 | } |
@@ -2410,8 +2519,7 @@ EXPORT_SYMBOL_GPL(iscsi_set_param); | |||
2410 | int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | 2519 | int iscsi_session_get_param(struct iscsi_cls_session *cls_session, |
2411 | enum iscsi_param param, char *buf) | 2520 | enum iscsi_param param, char *buf) |
2412 | { | 2521 | { |
2413 | struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); | 2522 | struct iscsi_session *session = cls_session->dd_data; |
2414 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | ||
2415 | int len; | 2523 | int len; |
2416 | 2524 | ||
2417 | switch(param) { | 2525 | switch(param) { |
@@ -2466,6 +2574,15 @@ int iscsi_session_get_param(struct iscsi_cls_session *cls_session, | |||
2466 | case ISCSI_PARAM_PASSWORD_IN: | 2574 | case ISCSI_PARAM_PASSWORD_IN: |
2467 | len = sprintf(buf, "%s\n", session->password_in); | 2575 | len = sprintf(buf, "%s\n", session->password_in); |
2468 | break; | 2576 | break; |
2577 | case ISCSI_PARAM_IFACE_NAME: | ||
2578 | len = sprintf(buf, "%s\n", session->ifacename); | ||
2579 | break; | ||
2580 | case ISCSI_PARAM_INITIATOR_NAME: | ||
2581 | if (!session->initiatorname) | ||
2582 | len = sprintf(buf, "%s\n", "unknown"); | ||
2583 | else | ||
2584 | len = sprintf(buf, "%s\n", session->initiatorname); | ||
2585 | break; | ||
2469 | default: | 2586 | default: |
2470 | return -ENOSYS; | 2587 | return -ENOSYS; |
2471 | } | 2588 | } |
@@ -2525,29 +2642,35 @@ EXPORT_SYMBOL_GPL(iscsi_conn_get_param); | |||
2525 | int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, | 2642 | int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, |
2526 | char *buf) | 2643 | char *buf) |
2527 | { | 2644 | { |
2528 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | 2645 | struct iscsi_host *ihost = shost_priv(shost); |
2529 | int len; | 2646 | int len; |
2530 | 2647 | ||
2531 | switch (param) { | 2648 | switch (param) { |
2532 | case ISCSI_HOST_PARAM_NETDEV_NAME: | 2649 | case ISCSI_HOST_PARAM_NETDEV_NAME: |
2533 | if (!session->netdev) | 2650 | if (!ihost->netdev) |
2534 | len = sprintf(buf, "%s\n", "default"); | 2651 | len = sprintf(buf, "%s\n", "default"); |
2535 | else | 2652 | else |
2536 | len = sprintf(buf, "%s\n", session->netdev); | 2653 | len = sprintf(buf, "%s\n", ihost->netdev); |
2537 | break; | 2654 | break; |
2538 | case ISCSI_HOST_PARAM_HWADDRESS: | 2655 | case ISCSI_HOST_PARAM_HWADDRESS: |
2539 | if (!session->hwaddress) | 2656 | if (!ihost->hwaddress) |
2540 | len = sprintf(buf, "%s\n", "default"); | 2657 | len = sprintf(buf, "%s\n", "default"); |
2541 | else | 2658 | else |
2542 | len = sprintf(buf, "%s\n", session->hwaddress); | 2659 | len = sprintf(buf, "%s\n", ihost->hwaddress); |
2543 | break; | 2660 | break; |
2544 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 2661 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
2545 | if (!session->initiatorname) | 2662 | if (!ihost->initiatorname) |
2546 | len = sprintf(buf, "%s\n", "unknown"); | 2663 | len = sprintf(buf, "%s\n", "unknown"); |
2547 | else | 2664 | else |
2548 | len = sprintf(buf, "%s\n", session->initiatorname); | 2665 | len = sprintf(buf, "%s\n", ihost->initiatorname); |
2666 | break; | ||
2667 | case ISCSI_HOST_PARAM_IPADDRESS: | ||
2668 | if (!strlen(ihost->local_address)) | ||
2669 | len = sprintf(buf, "%s\n", "unknown"); | ||
2670 | else | ||
2671 | len = sprintf(buf, "%s\n", | ||
2672 | ihost->local_address); | ||
2549 | break; | 2673 | break; |
2550 | |||
2551 | default: | 2674 | default: |
2552 | return -ENOSYS; | 2675 | return -ENOSYS; |
2553 | } | 2676 | } |
@@ -2559,20 +2682,20 @@ EXPORT_SYMBOL_GPL(iscsi_host_get_param); | |||
2559 | int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, | 2682 | int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, |
2560 | char *buf, int buflen) | 2683 | char *buf, int buflen) |
2561 | { | 2684 | { |
2562 | struct iscsi_session *session = iscsi_hostdata(shost->hostdata); | 2685 | struct iscsi_host *ihost = shost_priv(shost); |
2563 | 2686 | ||
2564 | switch (param) { | 2687 | switch (param) { |
2565 | case ISCSI_HOST_PARAM_NETDEV_NAME: | 2688 | case ISCSI_HOST_PARAM_NETDEV_NAME: |
2566 | if (!session->netdev) | 2689 | if (!ihost->netdev) |
2567 | session->netdev = kstrdup(buf, GFP_KERNEL); | 2690 | ihost->netdev = kstrdup(buf, GFP_KERNEL); |
2568 | break; | 2691 | break; |
2569 | case ISCSI_HOST_PARAM_HWADDRESS: | 2692 | case ISCSI_HOST_PARAM_HWADDRESS: |
2570 | if (!session->hwaddress) | 2693 | if (!ihost->hwaddress) |
2571 | session->hwaddress = kstrdup(buf, GFP_KERNEL); | 2694 | ihost->hwaddress = kstrdup(buf, GFP_KERNEL); |
2572 | break; | 2695 | break; |
2573 | case ISCSI_HOST_PARAM_INITIATOR_NAME: | 2696 | case ISCSI_HOST_PARAM_INITIATOR_NAME: |
2574 | if (!session->initiatorname) | 2697 | if (!ihost->initiatorname) |
2575 | session->initiatorname = kstrdup(buf, GFP_KERNEL); | 2698 | ihost->initiatorname = kstrdup(buf, GFP_KERNEL); |
2576 | break; | 2699 | break; |
2577 | default: | 2700 | default: |
2578 | return -ENOSYS; | 2701 | return -ENOSYS; |
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index ec0b0f6e5e1a..e0e018d12653 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
@@ -33,6 +33,7 @@ struct lpfc_sli2_slim; | |||
33 | #define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ | 33 | #define LPFC_MAX_SG_SEG_CNT 256 /* sg element count per scsi cmnd */ |
34 | #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ | 34 | #define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ |
35 | #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ | 35 | #define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ |
36 | #define LPFC_VNAME_LEN 100 /* vport symbolic name length */ | ||
36 | 37 | ||
37 | /* | 38 | /* |
38 | * Following time intervals are used of adjusting SCSI device | 39 | * Following time intervals are used of adjusting SCSI device |
@@ -59,6 +60,9 @@ struct lpfc_sli2_slim; | |||
59 | 60 | ||
60 | #define MAX_HBAEVT 32 | 61 | #define MAX_HBAEVT 32 |
61 | 62 | ||
63 | /* lpfc wait event data ready flag */ | ||
64 | #define LPFC_DATA_READY (1<<0) | ||
65 | |||
62 | enum lpfc_polling_flags { | 66 | enum lpfc_polling_flags { |
63 | ENABLE_FCP_RING_POLLING = 0x1, | 67 | ENABLE_FCP_RING_POLLING = 0x1, |
64 | DISABLE_FCP_RING_INT = 0x2 | 68 | DISABLE_FCP_RING_INT = 0x2 |
@@ -425,9 +429,6 @@ struct lpfc_hba { | |||
425 | 429 | ||
426 | uint16_t pci_cfg_value; | 430 | uint16_t pci_cfg_value; |
427 | 431 | ||
428 | uint8_t work_found; | ||
429 | #define LPFC_MAX_WORKER_ITERATION 4 | ||
430 | |||
431 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ | 432 | uint8_t fc_linkspeed; /* Link speed after last READ_LA */ |
432 | 433 | ||
433 | uint32_t fc_eventTag; /* event tag for link attention */ | 434 | uint32_t fc_eventTag; /* event tag for link attention */ |
@@ -489,8 +490,9 @@ struct lpfc_hba { | |||
489 | uint32_t work_hs; /* HS stored in case of ERRAT */ | 490 | uint32_t work_hs; /* HS stored in case of ERRAT */ |
490 | uint32_t work_status[2]; /* Extra status from SLIM */ | 491 | uint32_t work_status[2]; /* Extra status from SLIM */ |
491 | 492 | ||
492 | wait_queue_head_t *work_wait; | 493 | wait_queue_head_t work_waitq; |
493 | struct task_struct *worker_thread; | 494 | struct task_struct *worker_thread; |
495 | long data_flags; | ||
494 | 496 | ||
495 | uint32_t hbq_in_use; /* HBQs in use flag */ | 497 | uint32_t hbq_in_use; /* HBQs in use flag */ |
496 | struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ | 498 | struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ |
@@ -637,6 +639,17 @@ lpfc_is_link_up(struct lpfc_hba *phba) | |||
637 | phba->link_state == LPFC_HBA_READY; | 639 | phba->link_state == LPFC_HBA_READY; |
638 | } | 640 | } |
639 | 641 | ||
642 | static inline void | ||
643 | lpfc_worker_wake_up(struct lpfc_hba *phba) | ||
644 | { | ||
645 | /* Set the lpfc data pending flag */ | ||
646 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
647 | |||
648 | /* Wake up worker thread */ | ||
649 | wake_up(&phba->work_waitq); | ||
650 | return; | ||
651 | } | ||
652 | |||
640 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ | 653 | #define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */ |
641 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature | 654 | #define FC_REG_TEMPERATURE_EVENT 0x20 /* Register for temperature |
642 | event */ | 655 | event */ |
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 960baaf11fb1..37bfa0bd1dae 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c | |||
@@ -1995,8 +1995,7 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, | |||
1995 | /* Don't allow mailbox commands to be sent when blocked | 1995 | /* Don't allow mailbox commands to be sent when blocked |
1996 | * or when in the middle of discovery | 1996 | * or when in the middle of discovery |
1997 | */ | 1997 | */ |
1998 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO || | 1998 | if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { |
1999 | vport->fc_flag & FC_NDISC_ACTIVE) { | ||
2000 | sysfs_mbox_idle(phba); | 1999 | sysfs_mbox_idle(phba); |
2001 | spin_unlock_irq(&phba->hbalock); | 2000 | spin_unlock_irq(&phba->hbalock); |
2002 | return -EAGAIN; | 2001 | return -EAGAIN; |
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 7c9f8317d972..1b8245213b83 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h | |||
@@ -142,7 +142,7 @@ int lpfc_config_port_post(struct lpfc_hba *); | |||
142 | int lpfc_hba_down_prep(struct lpfc_hba *); | 142 | int lpfc_hba_down_prep(struct lpfc_hba *); |
143 | int lpfc_hba_down_post(struct lpfc_hba *); | 143 | int lpfc_hba_down_post(struct lpfc_hba *); |
144 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); | 144 | void lpfc_hba_init(struct lpfc_hba *, uint32_t *); |
145 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int); | 145 | int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int); |
146 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); | 146 | void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); |
147 | int lpfc_online(struct lpfc_hba *); | 147 | int lpfc_online(struct lpfc_hba *); |
148 | void lpfc_unblock_mgmt_io(struct lpfc_hba *); | 148 | void lpfc_unblock_mgmt_io(struct lpfc_hba *); |
@@ -263,6 +263,7 @@ extern int lpfc_sli_mode; | |||
263 | extern int lpfc_enable_npiv; | 263 | extern int lpfc_enable_npiv; |
264 | 264 | ||
265 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); | 265 | int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); |
266 | int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); | ||
266 | void lpfc_terminate_rport_io(struct fc_rport *); | 267 | void lpfc_terminate_rport_io(struct fc_rport *); |
267 | void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); | 268 | void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); |
268 | 269 | ||
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 153afae567b5..7fc74cf5823b 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c | |||
@@ -101,7 +101,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
101 | /* Not enough posted buffers; Try posting more buffers */ | 101 | /* Not enough posted buffers; Try posting more buffers */ |
102 | phba->fc_stat.NoRcvBuf++; | 102 | phba->fc_stat.NoRcvBuf++; |
103 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | 103 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) |
104 | lpfc_post_buffer(phba, pring, 2, 1); | 104 | lpfc_post_buffer(phba, pring, 2); |
105 | return; | 105 | return; |
106 | } | 106 | } |
107 | 107 | ||
@@ -151,7 +151,7 @@ lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
151 | } | 151 | } |
152 | list_del(&iocbq->list); | 152 | list_del(&iocbq->list); |
153 | lpfc_sli_release_iocbq(phba, iocbq); | 153 | lpfc_sli_release_iocbq(phba, iocbq); |
154 | lpfc_post_buffer(phba, pring, i, 1); | 154 | lpfc_post_buffer(phba, pring, i); |
155 | } | 155 | } |
156 | } | 156 | } |
157 | } | 157 | } |
@@ -990,7 +990,7 @@ lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
990 | return; | 990 | return; |
991 | } | 991 | } |
992 | 992 | ||
993 | static int | 993 | int |
994 | lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, | 994 | lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, |
995 | size_t size) | 995 | size_t size) |
996 | { | 996 | { |
@@ -1679,20 +1679,18 @@ lpfc_fdmi_tmo(unsigned long ptr) | |||
1679 | { | 1679 | { |
1680 | struct lpfc_vport *vport = (struct lpfc_vport *)ptr; | 1680 | struct lpfc_vport *vport = (struct lpfc_vport *)ptr; |
1681 | struct lpfc_hba *phba = vport->phba; | 1681 | struct lpfc_hba *phba = vport->phba; |
1682 | uint32_t tmo_posted; | ||
1682 | unsigned long iflag; | 1683 | unsigned long iflag; |
1683 | 1684 | ||
1684 | spin_lock_irqsave(&vport->work_port_lock, iflag); | 1685 | spin_lock_irqsave(&vport->work_port_lock, iflag); |
1685 | if (!(vport->work_port_events & WORKER_FDMI_TMO)) { | 1686 | tmo_posted = vport->work_port_events & WORKER_FDMI_TMO; |
1687 | if (!tmo_posted) | ||
1686 | vport->work_port_events |= WORKER_FDMI_TMO; | 1688 | vport->work_port_events |= WORKER_FDMI_TMO; |
1687 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | 1689 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); |
1688 | 1690 | ||
1689 | spin_lock_irqsave(&phba->hbalock, iflag); | 1691 | if (!tmo_posted) |
1690 | if (phba->work_wait) | 1692 | lpfc_worker_wake_up(phba); |
1691 | lpfc_worker_wake_up(phba); | 1693 | return; |
1692 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
1693 | } | ||
1694 | else | ||
1695 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||
1696 | } | 1694 | } |
1697 | 1695 | ||
1698 | void | 1696 | void |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 886c5f1b11d2..f54e0f7eaee3 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -1754,29 +1754,34 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) | |||
1754 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1754 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
1755 | struct lpfc_work_evt *evtp; | 1755 | struct lpfc_work_evt *evtp; |
1756 | 1756 | ||
1757 | if (!(nlp->nlp_flag & NLP_DELAY_TMO)) | ||
1758 | return; | ||
1757 | spin_lock_irq(shost->host_lock); | 1759 | spin_lock_irq(shost->host_lock); |
1758 | nlp->nlp_flag &= ~NLP_DELAY_TMO; | 1760 | nlp->nlp_flag &= ~NLP_DELAY_TMO; |
1759 | spin_unlock_irq(shost->host_lock); | 1761 | spin_unlock_irq(shost->host_lock); |
1760 | del_timer_sync(&nlp->nlp_delayfunc); | 1762 | del_timer_sync(&nlp->nlp_delayfunc); |
1761 | nlp->nlp_last_elscmd = 0; | 1763 | nlp->nlp_last_elscmd = 0; |
1762 | |||
1763 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) { | 1764 | if (!list_empty(&nlp->els_retry_evt.evt_listp)) { |
1764 | list_del_init(&nlp->els_retry_evt.evt_listp); | 1765 | list_del_init(&nlp->els_retry_evt.evt_listp); |
1765 | /* Decrement nlp reference count held for the delayed retry */ | 1766 | /* Decrement nlp reference count held for the delayed retry */ |
1766 | evtp = &nlp->els_retry_evt; | 1767 | evtp = &nlp->els_retry_evt; |
1767 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | 1768 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); |
1768 | } | 1769 | } |
1769 | |||
1770 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { | 1770 | if (nlp->nlp_flag & NLP_NPR_2B_DISC) { |
1771 | spin_lock_irq(shost->host_lock); | 1771 | spin_lock_irq(shost->host_lock); |
1772 | nlp->nlp_flag &= ~NLP_NPR_2B_DISC; | 1772 | nlp->nlp_flag &= ~NLP_NPR_2B_DISC; |
1773 | spin_unlock_irq(shost->host_lock); | 1773 | spin_unlock_irq(shost->host_lock); |
1774 | if (vport->num_disc_nodes) { | 1774 | if (vport->num_disc_nodes) { |
1775 | /* Check to see if there are more | 1775 | if (vport->port_state < LPFC_VPORT_READY) { |
1776 | * PLOGIs to be sent | 1776 | /* Check if there are more ADISCs to be sent */ |
1777 | */ | 1777 | lpfc_more_adisc(vport); |
1778 | lpfc_more_plogi(vport); | 1778 | if ((vport->num_disc_nodes == 0) && |
1779 | 1779 | (vport->fc_npr_cnt)) | |
1780 | lpfc_els_disc_plogi(vport); | ||
1781 | } else { | ||
1782 | /* Check if there are more PLOGIs to be sent */ | ||
1783 | lpfc_more_plogi(vport); | ||
1784 | } | ||
1780 | if (vport->num_disc_nodes == 0) { | 1785 | if (vport->num_disc_nodes == 0) { |
1781 | spin_lock_irq(shost->host_lock); | 1786 | spin_lock_irq(shost->host_lock); |
1782 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | 1787 | vport->fc_flag &= ~FC_NDISC_ACTIVE; |
@@ -1798,10 +1803,6 @@ lpfc_els_retry_delay(unsigned long ptr) | |||
1798 | unsigned long flags; | 1803 | unsigned long flags; |
1799 | struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; | 1804 | struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; |
1800 | 1805 | ||
1801 | ndlp = (struct lpfc_nodelist *) ptr; | ||
1802 | phba = ndlp->vport->phba; | ||
1803 | evtp = &ndlp->els_retry_evt; | ||
1804 | |||
1805 | spin_lock_irqsave(&phba->hbalock, flags); | 1806 | spin_lock_irqsave(&phba->hbalock, flags); |
1806 | if (!list_empty(&evtp->evt_listp)) { | 1807 | if (!list_empty(&evtp->evt_listp)) { |
1807 | spin_unlock_irqrestore(&phba->hbalock, flags); | 1808 | spin_unlock_irqrestore(&phba->hbalock, flags); |
@@ -1812,11 +1813,11 @@ lpfc_els_retry_delay(unsigned long ptr) | |||
1812 | * count until the queued work is done | 1813 | * count until the queued work is done |
1813 | */ | 1814 | */ |
1814 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); | 1815 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); |
1815 | evtp->evt = LPFC_EVT_ELS_RETRY; | 1816 | if (evtp->evt_arg1) { |
1816 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 1817 | evtp->evt = LPFC_EVT_ELS_RETRY; |
1817 | if (phba->work_wait) | 1818 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
1818 | lpfc_worker_wake_up(phba); | 1819 | lpfc_worker_wake_up(phba); |
1819 | 1820 | } | |
1820 | spin_unlock_irqrestore(&phba->hbalock, flags); | 1821 | spin_unlock_irqrestore(&phba->hbalock, flags); |
1821 | return; | 1822 | return; |
1822 | } | 1823 | } |
@@ -2761,10 +2762,11 @@ lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, | |||
2761 | npr = (PRLI *) pcmd; | 2762 | npr = (PRLI *) pcmd; |
2762 | vpd = &phba->vpd; | 2763 | vpd = &phba->vpd; |
2763 | /* | 2764 | /* |
2764 | * If our firmware version is 3.20 or later, | 2765 | * If the remote port is a target and our firmware version is 3.20 or |
2765 | * set the following bits for FC-TAPE support. | 2766 | * later, set the following bits for FC-TAPE support. |
2766 | */ | 2767 | */ |
2767 | if (vpd->rev.feaLevelHigh >= 0x02) { | 2768 | if ((ndlp->nlp_type & NLP_FCP_TARGET) && |
2769 | (vpd->rev.feaLevelHigh >= 0x02)) { | ||
2768 | npr->ConfmComplAllowed = 1; | 2770 | npr->ConfmComplAllowed = 1; |
2769 | npr->Retry = 1; | 2771 | npr->Retry = 1; |
2770 | npr->TaskRetryIdReq = 1; | 2772 | npr->TaskRetryIdReq = 1; |
@@ -3056,27 +3058,16 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) | |||
3056 | { | 3058 | { |
3057 | struct lpfc_nodelist *ndlp = NULL; | 3059 | struct lpfc_nodelist *ndlp = NULL; |
3058 | 3060 | ||
3059 | /* Look at all nodes effected by pending RSCNs and move | 3061 | /* Move all affected nodes by pending RSCNs to NPR state. */ |
3060 | * them to NPR state. | ||
3061 | */ | ||
3062 | |||
3063 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { | 3062 | list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { |
3064 | if (!NLP_CHK_NODE_ACT(ndlp) || | 3063 | if (!NLP_CHK_NODE_ACT(ndlp) || |
3065 | ndlp->nlp_state == NLP_STE_UNUSED_NODE || | 3064 | (ndlp->nlp_state == NLP_STE_UNUSED_NODE) || |
3066 | lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0) | 3065 | !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) |
3067 | continue; | 3066 | continue; |
3068 | |||
3069 | lpfc_disc_state_machine(vport, ndlp, NULL, | 3067 | lpfc_disc_state_machine(vport, ndlp, NULL, |
3070 | NLP_EVT_DEVICE_RECOVERY); | 3068 | NLP_EVT_DEVICE_RECOVERY); |
3071 | 3069 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | |
3072 | /* | ||
3073 | * Make sure NLP_DELAY_TMO is NOT running after a device | ||
3074 | * recovery event. | ||
3075 | */ | ||
3076 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | ||
3077 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
3078 | } | 3070 | } |
3079 | |||
3080 | return 0; | 3071 | return 0; |
3081 | } | 3072 | } |
3082 | 3073 | ||
@@ -3781,91 +3772,27 @@ static int | |||
3781 | lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | 3772 | lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, |
3782 | struct lpfc_nodelist *fan_ndlp) | 3773 | struct lpfc_nodelist *fan_ndlp) |
3783 | { | 3774 | { |
3784 | struct lpfc_dmabuf *pcmd; | 3775 | struct lpfc_hba *phba = vport->phba; |
3785 | uint32_t *lp; | 3776 | uint32_t *lp; |
3786 | IOCB_t *icmd; | ||
3787 | uint32_t cmd, did; | ||
3788 | FAN *fp; | 3777 | FAN *fp; |
3789 | struct lpfc_nodelist *ndlp, *next_ndlp; | ||
3790 | struct lpfc_hba *phba = vport->phba; | ||
3791 | |||
3792 | /* FAN received */ | ||
3793 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, | ||
3794 | "0265 FAN received\n"); | ||
3795 | icmd = &cmdiocb->iocb; | ||
3796 | did = icmd->un.elsreq64.remoteID; | ||
3797 | pcmd = (struct lpfc_dmabuf *)cmdiocb->context2; | ||
3798 | lp = (uint32_t *)pcmd->virt; | ||
3799 | |||
3800 | cmd = *lp++; | ||
3801 | fp = (FAN *) lp; | ||
3802 | 3778 | ||
3779 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n"); | ||
3780 | lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt; | ||
3781 | fp = (FAN *) ++lp; | ||
3803 | /* FAN received; Fan does not have a reply sequence */ | 3782 | /* FAN received; Fan does not have a reply sequence */ |
3804 | 3783 | if ((vport == phba->pport) && | |
3805 | if (phba->pport->port_state == LPFC_LOCAL_CFG_LINK) { | 3784 | (vport->port_state == LPFC_LOCAL_CFG_LINK)) { |
3806 | if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName, | 3785 | if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName, |
3807 | sizeof(struct lpfc_name)) != 0) || | 3786 | sizeof(struct lpfc_name))) || |
3808 | (memcmp(&phba->fc_fabparam.portName, &fp->FportName, | 3787 | (memcmp(&phba->fc_fabparam.portName, &fp->FportName, |
3809 | sizeof(struct lpfc_name)) != 0)) { | 3788 | sizeof(struct lpfc_name)))) { |
3810 | /* | 3789 | /* This port has switched fabrics. FLOGI is required */ |
3811 | * This node has switched fabrics. FLOGI is required | ||
3812 | * Clean up the old rpi's | ||
3813 | */ | ||
3814 | |||
3815 | list_for_each_entry_safe(ndlp, next_ndlp, | ||
3816 | &vport->fc_nodes, nlp_listp) { | ||
3817 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3818 | continue; | ||
3819 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | ||
3820 | continue; | ||
3821 | if (ndlp->nlp_type & NLP_FABRIC) { | ||
3822 | /* | ||
3823 | * Clean up old Fabric, Nameserver and | ||
3824 | * other NLP_FABRIC logins | ||
3825 | */ | ||
3826 | lpfc_drop_node(vport, ndlp); | ||
3827 | |||
3828 | } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { | ||
3829 | /* Fail outstanding I/O now since this | ||
3830 | * device is marked for PLOGI | ||
3831 | */ | ||
3832 | lpfc_unreg_rpi(vport, ndlp); | ||
3833 | } | ||
3834 | } | ||
3835 | |||
3836 | lpfc_initial_flogi(vport); | 3790 | lpfc_initial_flogi(vport); |
3837 | return 0; | 3791 | } else { |
3838 | } | 3792 | /* FAN verified - skip FLOGI */ |
3839 | /* Discovery not needed, | 3793 | vport->fc_myDID = vport->fc_prevDID; |
3840 | * move the nodes to their original state. | 3794 | lpfc_issue_fabric_reglogin(vport); |
3841 | */ | ||
3842 | list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, | ||
3843 | nlp_listp) { | ||
3844 | if (!NLP_CHK_NODE_ACT(ndlp)) | ||
3845 | continue; | ||
3846 | if (ndlp->nlp_state != NLP_STE_NPR_NODE) | ||
3847 | continue; | ||
3848 | |||
3849 | switch (ndlp->nlp_prev_state) { | ||
3850 | case NLP_STE_UNMAPPED_NODE: | ||
3851 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | ||
3852 | lpfc_nlp_set_state(vport, ndlp, | ||
3853 | NLP_STE_UNMAPPED_NODE); | ||
3854 | break; | ||
3855 | |||
3856 | case NLP_STE_MAPPED_NODE: | ||
3857 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | ||
3858 | lpfc_nlp_set_state(vport, ndlp, | ||
3859 | NLP_STE_MAPPED_NODE); | ||
3860 | break; | ||
3861 | |||
3862 | default: | ||
3863 | break; | ||
3864 | } | ||
3865 | } | 3795 | } |
3866 | |||
3867 | /* Start discovery - this should just do CLEAR_LA */ | ||
3868 | lpfc_disc_start(vport); | ||
3869 | } | 3796 | } |
3870 | return 0; | 3797 | return 0; |
3871 | } | 3798 | } |
@@ -3875,20 +3802,17 @@ lpfc_els_timeout(unsigned long ptr) | |||
3875 | { | 3802 | { |
3876 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; | 3803 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; |
3877 | struct lpfc_hba *phba = vport->phba; | 3804 | struct lpfc_hba *phba = vport->phba; |
3805 | uint32_t tmo_posted; | ||
3878 | unsigned long iflag; | 3806 | unsigned long iflag; |
3879 | 3807 | ||
3880 | spin_lock_irqsave(&vport->work_port_lock, iflag); | 3808 | spin_lock_irqsave(&vport->work_port_lock, iflag); |
3881 | if ((vport->work_port_events & WORKER_ELS_TMO) == 0) { | 3809 | tmo_posted = vport->work_port_events & WORKER_ELS_TMO; |
3810 | if (!tmo_posted) | ||
3882 | vport->work_port_events |= WORKER_ELS_TMO; | 3811 | vport->work_port_events |= WORKER_ELS_TMO; |
3883 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | 3812 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); |
3884 | 3813 | ||
3885 | spin_lock_irqsave(&phba->hbalock, iflag); | 3814 | if (!tmo_posted) |
3886 | if (phba->work_wait) | 3815 | lpfc_worker_wake_up(phba); |
3887 | lpfc_worker_wake_up(phba); | ||
3888 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
3889 | } | ||
3890 | else | ||
3891 | spin_unlock_irqrestore(&vport->work_port_lock, iflag); | ||
3892 | return; | 3816 | return; |
3893 | } | 3817 | } |
3894 | 3818 | ||
@@ -3933,9 +3857,6 @@ lpfc_els_timeout_handler(struct lpfc_vport *vport) | |||
3933 | els_command == ELS_CMD_FDISC) | 3857 | els_command == ELS_CMD_FDISC) |
3934 | continue; | 3858 | continue; |
3935 | 3859 | ||
3936 | if (vport != piocb->vport) | ||
3937 | continue; | ||
3938 | |||
3939 | if (piocb->drvrTimeout > 0) { | 3860 | if (piocb->drvrTimeout > 0) { |
3940 | if (piocb->drvrTimeout >= timeout) | 3861 | if (piocb->drvrTimeout >= timeout) |
3941 | piocb->drvrTimeout -= timeout; | 3862 | piocb->drvrTimeout -= timeout; |
@@ -4089,7 +4010,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
4089 | payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; | 4010 | payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; |
4090 | cmd = *payload; | 4011 | cmd = *payload; |
4091 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) | 4012 | if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) |
4092 | lpfc_post_buffer(phba, pring, 1, 1); | 4013 | lpfc_post_buffer(phba, pring, 1); |
4093 | 4014 | ||
4094 | did = icmd->un.rcvels.remoteID; | 4015 | did = icmd->un.rcvels.remoteID; |
4095 | if (icmd->ulpStatus) { | 4016 | if (icmd->ulpStatus) { |
@@ -4398,7 +4319,7 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
4398 | phba->fc_stat.NoRcvBuf++; | 4319 | phba->fc_stat.NoRcvBuf++; |
4399 | /* Not enough posted buffers; Try posting more buffers */ | 4320 | /* Not enough posted buffers; Try posting more buffers */ |
4400 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) | 4321 | if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) |
4401 | lpfc_post_buffer(phba, pring, 0, 1); | 4322 | lpfc_post_buffer(phba, pring, 0); |
4402 | return; | 4323 | return; |
4403 | } | 4324 | } |
4404 | 4325 | ||
@@ -4842,18 +4763,16 @@ lpfc_fabric_block_timeout(unsigned long ptr) | |||
4842 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; | 4763 | struct lpfc_hba *phba = (struct lpfc_hba *) ptr; |
4843 | unsigned long iflags; | 4764 | unsigned long iflags; |
4844 | uint32_t tmo_posted; | 4765 | uint32_t tmo_posted; |
4766 | |||
4845 | spin_lock_irqsave(&phba->pport->work_port_lock, iflags); | 4767 | spin_lock_irqsave(&phba->pport->work_port_lock, iflags); |
4846 | tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO; | 4768 | tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO; |
4847 | if (!tmo_posted) | 4769 | if (!tmo_posted) |
4848 | phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO; | 4770 | phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO; |
4849 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); | 4771 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); |
4850 | 4772 | ||
4851 | if (!tmo_posted) { | 4773 | if (!tmo_posted) |
4852 | spin_lock_irqsave(&phba->hbalock, iflags); | 4774 | lpfc_worker_wake_up(phba); |
4853 | if (phba->work_wait) | 4775 | return; |
4854 | lpfc_worker_wake_up(phba); | ||
4855 | spin_unlock_irqrestore(&phba->hbalock, iflags); | ||
4856 | } | ||
4857 | } | 4776 | } |
4858 | 4777 | ||
4859 | static void | 4778 | static void |
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7cb68feb04fd..a98d11bf3576 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
@@ -153,11 +153,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) | |||
153 | * count until this queued work is done | 153 | * count until this queued work is done |
154 | */ | 154 | */ |
155 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); | 155 | evtp->evt_arg1 = lpfc_nlp_get(ndlp); |
156 | evtp->evt = LPFC_EVT_DEV_LOSS; | 156 | if (evtp->evt_arg1) { |
157 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 157 | evtp->evt = LPFC_EVT_DEV_LOSS; |
158 | if (phba->work_wait) | 158 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
159 | wake_up(phba->work_wait); | 159 | lpfc_worker_wake_up(phba); |
160 | 160 | } | |
161 | spin_unlock_irq(&phba->hbalock); | 161 | spin_unlock_irq(&phba->hbalock); |
162 | 162 | ||
163 | return; | 163 | return; |
@@ -276,14 +276,6 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) | |||
276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); | 276 | lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); |
277 | } | 277 | } |
278 | 278 | ||
279 | |||
280 | void | ||
281 | lpfc_worker_wake_up(struct lpfc_hba *phba) | ||
282 | { | ||
283 | wake_up(phba->work_wait); | ||
284 | return; | ||
285 | } | ||
286 | |||
287 | static void | 279 | static void |
288 | lpfc_work_list_done(struct lpfc_hba *phba) | 280 | lpfc_work_list_done(struct lpfc_hba *phba) |
289 | { | 281 | { |
@@ -429,6 +421,8 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
429 | || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { | 421 | || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { |
430 | if (pring->flag & LPFC_STOP_IOCB_EVENT) { | 422 | if (pring->flag & LPFC_STOP_IOCB_EVENT) { |
431 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 423 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
424 | /* Set the lpfc data pending flag */ | ||
425 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
432 | } else { | 426 | } else { |
433 | pring->flag &= ~LPFC_DEFERRED_RING_EVENT; | 427 | pring->flag &= ~LPFC_DEFERRED_RING_EVENT; |
434 | lpfc_sli_handle_slow_ring_event(phba, pring, | 428 | lpfc_sli_handle_slow_ring_event(phba, pring, |
@@ -459,69 +453,29 @@ lpfc_work_done(struct lpfc_hba *phba) | |||
459 | lpfc_work_list_done(phba); | 453 | lpfc_work_list_done(phba); |
460 | } | 454 | } |
461 | 455 | ||
462 | static int | ||
463 | check_work_wait_done(struct lpfc_hba *phba) | ||
464 | { | ||
465 | struct lpfc_vport *vport; | ||
466 | struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; | ||
467 | int rc = 0; | ||
468 | |||
469 | spin_lock_irq(&phba->hbalock); | ||
470 | list_for_each_entry(vport, &phba->port_list, listentry) { | ||
471 | if (vport->work_port_events) { | ||
472 | rc = 1; | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | if (rc || phba->work_ha || (!list_empty(&phba->work_list)) || | ||
477 | kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) { | ||
478 | rc = 1; | ||
479 | phba->work_found++; | ||
480 | } else | ||
481 | phba->work_found = 0; | ||
482 | spin_unlock_irq(&phba->hbalock); | ||
483 | return rc; | ||
484 | } | ||
485 | |||
486 | |||
487 | int | 456 | int |
488 | lpfc_do_work(void *p) | 457 | lpfc_do_work(void *p) |
489 | { | 458 | { |
490 | struct lpfc_hba *phba = p; | 459 | struct lpfc_hba *phba = p; |
491 | int rc; | 460 | int rc; |
492 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); | ||
493 | 461 | ||
494 | set_user_nice(current, -20); | 462 | set_user_nice(current, -20); |
495 | phba->work_wait = &work_waitq; | 463 | phba->data_flags = 0; |
496 | phba->work_found = 0; | ||
497 | 464 | ||
498 | while (1) { | 465 | while (1) { |
499 | 466 | /* wait and check worker queue activities */ | |
500 | rc = wait_event_interruptible(work_waitq, | 467 | rc = wait_event_interruptible(phba->work_waitq, |
501 | check_work_wait_done(phba)); | 468 | (test_and_clear_bit(LPFC_DATA_READY, |
502 | 469 | &phba->data_flags) | |
470 | || kthread_should_stop())); | ||
503 | BUG_ON(rc); | 471 | BUG_ON(rc); |
504 | 472 | ||
505 | if (kthread_should_stop()) | 473 | if (kthread_should_stop()) |
506 | break; | 474 | break; |
507 | 475 | ||
476 | /* Attend pending lpfc data processing */ | ||
508 | lpfc_work_done(phba); | 477 | lpfc_work_done(phba); |
509 | |||
510 | /* If there is alot of slow ring work, like during link up | ||
511 | * check_work_wait_done() may cause this thread to not give | ||
512 | * up the CPU for very long periods of time. This may cause | ||
513 | * soft lockups or other problems. To avoid these situations | ||
514 | * give up the CPU here after LPFC_MAX_WORKER_ITERATION | ||
515 | * consecutive iterations. | ||
516 | */ | ||
517 | if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) { | ||
518 | phba->work_found = 0; | ||
519 | schedule(); | ||
520 | } | ||
521 | } | 478 | } |
522 | spin_lock_irq(&phba->hbalock); | ||
523 | phba->work_wait = NULL; | ||
524 | spin_unlock_irq(&phba->hbalock); | ||
525 | return 0; | 479 | return 0; |
526 | } | 480 | } |
527 | 481 | ||
@@ -551,10 +505,10 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, | |||
551 | 505 | ||
552 | spin_lock_irqsave(&phba->hbalock, flags); | 506 | spin_lock_irqsave(&phba->hbalock, flags); |
553 | list_add_tail(&evtp->evt_listp, &phba->work_list); | 507 | list_add_tail(&evtp->evt_listp, &phba->work_list); |
554 | if (phba->work_wait) | ||
555 | lpfc_worker_wake_up(phba); | ||
556 | spin_unlock_irqrestore(&phba->hbalock, flags); | 508 | spin_unlock_irqrestore(&phba->hbalock, flags); |
557 | 509 | ||
510 | lpfc_worker_wake_up(phba); | ||
511 | |||
558 | return 1; | 512 | return 1; |
559 | } | 513 | } |
560 | 514 | ||
@@ -963,6 +917,10 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) | |||
963 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 917 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
964 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; | 918 | phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; |
965 | 919 | ||
920 | if (phba->cfg_enable_npiv) | ||
921 | lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, | ||
922 | "1309 Link Up Event npiv not supported in loop " | ||
923 | "topology\n"); | ||
966 | /* Get Loop Map information */ | 924 | /* Get Loop Map information */ |
967 | if (la->il) | 925 | if (la->il) |
968 | vport->fc_flag |= FC_LBIT; | 926 | vport->fc_flag |= FC_LBIT; |
@@ -1087,6 +1045,8 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
1087 | MAILBOX_t *mb = &pmb->mb; | 1045 | MAILBOX_t *mb = &pmb->mb; |
1088 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); | 1046 | struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); |
1089 | 1047 | ||
1048 | /* Unblock ELS traffic */ | ||
1049 | phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; | ||
1090 | /* Check for error */ | 1050 | /* Check for error */ |
1091 | if (mb->mbxStatus) { | 1051 | if (mb->mbxStatus) { |
1092 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, | 1052 | lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, |
@@ -1650,7 +1610,6 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1650 | ndlp->nlp_DID, old_state, state); | 1610 | ndlp->nlp_DID, old_state, state); |
1651 | 1611 | ||
1652 | if (old_state == NLP_STE_NPR_NODE && | 1612 | if (old_state == NLP_STE_NPR_NODE && |
1653 | (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && | ||
1654 | state != NLP_STE_NPR_NODE) | 1613 | state != NLP_STE_NPR_NODE) |
1655 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | 1614 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1656 | if (old_state == NLP_STE_UNMAPPED_NODE) { | 1615 | if (old_state == NLP_STE_UNMAPPED_NODE) { |
@@ -1687,8 +1646,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1687 | { | 1646 | { |
1688 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 1647 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
1689 | 1648 | ||
1690 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | 1649 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1691 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1692 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | 1650 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) |
1693 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | 1651 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); |
1694 | spin_lock_irq(shost->host_lock); | 1652 | spin_lock_irq(shost->host_lock); |
@@ -1701,8 +1659,7 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
1701 | static void | 1659 | static void |
1702 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | 1660 | lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) |
1703 | { | 1661 | { |
1704 | if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) | 1662 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1705 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1706 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) | 1663 | if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) |
1707 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); | 1664 | lpfc_nlp_counters(vport, ndlp->nlp_state, -1); |
1708 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, | 1665 | lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, |
@@ -2121,10 +2078,8 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2121 | ndlp->nlp_last_elscmd = 0; | 2078 | ndlp->nlp_last_elscmd = 0; |
2122 | del_timer_sync(&ndlp->nlp_delayfunc); | 2079 | del_timer_sync(&ndlp->nlp_delayfunc); |
2123 | 2080 | ||
2124 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) | 2081 | list_del_init(&ndlp->els_retry_evt.evt_listp); |
2125 | list_del_init(&ndlp->els_retry_evt.evt_listp); | 2082 | list_del_init(&ndlp->dev_loss_evt.evt_listp); |
2126 | if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) | ||
2127 | list_del_init(&ndlp->dev_loss_evt.evt_listp); | ||
2128 | 2083 | ||
2129 | lpfc_unreg_rpi(vport, ndlp); | 2084 | lpfc_unreg_rpi(vport, ndlp); |
2130 | 2085 | ||
@@ -2144,10 +2099,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) | |||
2144 | LPFC_MBOXQ_t *mbox; | 2099 | LPFC_MBOXQ_t *mbox; |
2145 | int rc; | 2100 | int rc; |
2146 | 2101 | ||
2147 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | 2102 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
2148 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
2149 | } | ||
2150 | |||
2151 | if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { | 2103 | if (ndlp->nlp_flag & NLP_DEFER_RM && !ndlp->nlp_rpi) { |
2152 | /* For this case we need to cleanup the default rpi | 2104 | /* For this case we need to cleanup the default rpi |
2153 | * allocated by the firmware. | 2105 | * allocated by the firmware. |
@@ -2317,8 +2269,7 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) | |||
2317 | /* Since this node is marked for discovery, | 2269 | /* Since this node is marked for discovery, |
2318 | * delay timeout is not needed. | 2270 | * delay timeout is not needed. |
2319 | */ | 2271 | */ |
2320 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | 2272 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
2321 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
2322 | } else | 2273 | } else |
2323 | ndlp = NULL; | 2274 | ndlp = NULL; |
2324 | } else { | 2275 | } else { |
@@ -2643,21 +2594,20 @@ lpfc_disc_timeout(unsigned long ptr) | |||
2643 | { | 2594 | { |
2644 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; | 2595 | struct lpfc_vport *vport = (struct lpfc_vport *) ptr; |
2645 | struct lpfc_hba *phba = vport->phba; | 2596 | struct lpfc_hba *phba = vport->phba; |
2597 | uint32_t tmo_posted; | ||
2646 | unsigned long flags = 0; | 2598 | unsigned long flags = 0; |
2647 | 2599 | ||
2648 | if (unlikely(!phba)) | 2600 | if (unlikely(!phba)) |
2649 | return; | 2601 | return; |
2650 | 2602 | ||
2651 | if ((vport->work_port_events & WORKER_DISC_TMO) == 0) { | 2603 | spin_lock_irqsave(&vport->work_port_lock, flags); |
2652 | spin_lock_irqsave(&vport->work_port_lock, flags); | 2604 | tmo_posted = vport->work_port_events & WORKER_DISC_TMO; |
2605 | if (!tmo_posted) | ||
2653 | vport->work_port_events |= WORKER_DISC_TMO; | 2606 | vport->work_port_events |= WORKER_DISC_TMO; |
2654 | spin_unlock_irqrestore(&vport->work_port_lock, flags); | 2607 | spin_unlock_irqrestore(&vport->work_port_lock, flags); |
2655 | 2608 | ||
2656 | spin_lock_irqsave(&phba->hbalock, flags); | 2609 | if (!tmo_posted) |
2657 | if (phba->work_wait) | 2610 | lpfc_worker_wake_up(phba); |
2658 | lpfc_worker_wake_up(phba); | ||
2659 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
2660 | } | ||
2661 | return; | 2611 | return; |
2662 | } | 2612 | } |
2663 | 2613 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index fa757b251f82..5b6e5395c8eb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
@@ -145,8 +145,10 @@ lpfc_config_port_prep(struct lpfc_hba *phba) | |||
145 | return -ERESTART; | 145 | return -ERESTART; |
146 | } | 146 | } |
147 | 147 | ||
148 | if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) | 148 | if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) { |
149 | mempool_free(pmb, phba->mbox_mem_pool); | ||
149 | return -EINVAL; | 150 | return -EINVAL; |
151 | } | ||
150 | 152 | ||
151 | /* Save information as VPD data */ | 153 | /* Save information as VPD data */ |
152 | vp->rev.rBit = 1; | 154 | vp->rev.rBit = 1; |
@@ -551,18 +553,18 @@ static void | |||
551 | lpfc_hb_timeout(unsigned long ptr) | 553 | lpfc_hb_timeout(unsigned long ptr) |
552 | { | 554 | { |
553 | struct lpfc_hba *phba; | 555 | struct lpfc_hba *phba; |
556 | uint32_t tmo_posted; | ||
554 | unsigned long iflag; | 557 | unsigned long iflag; |
555 | 558 | ||
556 | phba = (struct lpfc_hba *)ptr; | 559 | phba = (struct lpfc_hba *)ptr; |
557 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); | 560 | spin_lock_irqsave(&phba->pport->work_port_lock, iflag); |
558 | if (!(phba->pport->work_port_events & WORKER_HB_TMO)) | 561 | tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; |
562 | if (!tmo_posted) | ||
559 | phba->pport->work_port_events |= WORKER_HB_TMO; | 563 | phba->pport->work_port_events |= WORKER_HB_TMO; |
560 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); | 564 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); |
561 | 565 | ||
562 | spin_lock_irqsave(&phba->hbalock, iflag); | 566 | if (!tmo_posted) |
563 | if (phba->work_wait) | 567 | lpfc_worker_wake_up(phba); |
564 | wake_up(phba->work_wait); | ||
565 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
566 | return; | 568 | return; |
567 | } | 569 | } |
568 | 570 | ||
@@ -851,6 +853,8 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
851 | lpfc_read_la(phba, pmb, mp); | 853 | lpfc_read_la(phba, pmb, mp); |
852 | pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; | 854 | pmb->mbox_cmpl = lpfc_mbx_cmpl_read_la; |
853 | pmb->vport = vport; | 855 | pmb->vport = vport; |
856 | /* Block ELS IOCBs until we have processed this mbox command */ | ||
857 | phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; | ||
854 | rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); | 858 | rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); |
855 | if (rc == MBX_NOT_FINISHED) { | 859 | if (rc == MBX_NOT_FINISHED) { |
856 | rc = 4; | 860 | rc = 4; |
@@ -866,6 +870,7 @@ lpfc_handle_latt(struct lpfc_hba *phba) | |||
866 | return; | 870 | return; |
867 | 871 | ||
868 | lpfc_handle_latt_free_mbuf: | 872 | lpfc_handle_latt_free_mbuf: |
873 | phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; | ||
869 | lpfc_mbuf_free(phba, mp->virt, mp->phys); | 874 | lpfc_mbuf_free(phba, mp->virt, mp->phys); |
870 | lpfc_handle_latt_free_mp: | 875 | lpfc_handle_latt_free_mp: |
871 | kfree(mp); | 876 | kfree(mp); |
@@ -1194,8 +1199,7 @@ lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) | |||
1194 | /* Returns the number of buffers NOT posted. */ | 1199 | /* Returns the number of buffers NOT posted. */ |
1195 | /**************************************************/ | 1200 | /**************************************************/ |
1196 | int | 1201 | int |
1197 | lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt, | 1202 | lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) |
1198 | int type) | ||
1199 | { | 1203 | { |
1200 | IOCB_t *icmd; | 1204 | IOCB_t *icmd; |
1201 | struct lpfc_iocbq *iocb; | 1205 | struct lpfc_iocbq *iocb; |
@@ -1295,7 +1299,7 @@ lpfc_post_rcv_buf(struct lpfc_hba *phba) | |||
1295 | struct lpfc_sli *psli = &phba->sli; | 1299 | struct lpfc_sli *psli = &phba->sli; |
1296 | 1300 | ||
1297 | /* Ring 0, ELS / CT buffers */ | 1301 | /* Ring 0, ELS / CT buffers */ |
1298 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0, 1); | 1302 | lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0); |
1299 | /* Ring 2 - FCP no buffers needed */ | 1303 | /* Ring 2 - FCP no buffers needed */ |
1300 | 1304 | ||
1301 | return 0; | 1305 | return 0; |
@@ -1454,6 +1458,15 @@ lpfc_cleanup(struct lpfc_vport *vport) | |||
1454 | 1458 | ||
1455 | lpfc_disc_state_machine(vport, ndlp, NULL, | 1459 | lpfc_disc_state_machine(vport, ndlp, NULL, |
1456 | NLP_EVT_DEVICE_RM); | 1460 | NLP_EVT_DEVICE_RM); |
1461 | |||
1462 | /* nlp_type zero is not defined, nlp_flag zero also not defined, | ||
1463 | * nlp_state is unused, this happens when | ||
1464 | * an initiator has logged | ||
1465 | * into us so cleanup this ndlp. | ||
1466 | */ | ||
1467 | if ((ndlp->nlp_type == 0) && (ndlp->nlp_flag == 0) && | ||
1468 | (ndlp->nlp_state == 0)) | ||
1469 | lpfc_nlp_put(ndlp); | ||
1457 | } | 1470 | } |
1458 | 1471 | ||
1459 | /* At this point, ALL ndlp's should be gone | 1472 | /* At this point, ALL ndlp's should be gone |
@@ -2101,6 +2114,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) | |||
2101 | phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); | 2114 | phba->work_ha_mask = (HA_ERATT|HA_MBATT|HA_LATT); |
2102 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); | 2115 | phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); |
2103 | 2116 | ||
2117 | /* Initialize the wait queue head for the kernel thread */ | ||
2118 | init_waitqueue_head(&phba->work_waitq); | ||
2119 | |||
2104 | /* Startup the kernel thread for this host adapter. */ | 2120 | /* Startup the kernel thread for this host adapter. */ |
2105 | phba->worker_thread = kthread_run(lpfc_do_work, phba, | 2121 | phba->worker_thread = kthread_run(lpfc_do_work, phba, |
2106 | "lpfc_worker_%d", phba->brd_no); | 2122 | "lpfc_worker_%d", phba->brd_no); |
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index d08c4c890744..6688a8689b56 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c | |||
@@ -235,10 +235,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) | |||
235 | (iocb->iocb_cmpl) (phba, iocb, iocb); | 235 | (iocb->iocb_cmpl) (phba, iocb, iocb); |
236 | } | 236 | } |
237 | } | 237 | } |
238 | 238 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); | |
239 | /* If we are delaying issuing an ELS command, cancel it */ | ||
240 | if (ndlp->nlp_flag & NLP_DELAY_TMO) | ||
241 | lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); | ||
242 | return 0; | 239 | return 0; |
243 | } | 240 | } |
244 | 241 | ||
@@ -249,7 +246,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
249 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | 246 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); |
250 | struct lpfc_hba *phba = vport->phba; | 247 | struct lpfc_hba *phba = vport->phba; |
251 | struct lpfc_dmabuf *pcmd; | 248 | struct lpfc_dmabuf *pcmd; |
252 | struct lpfc_work_evt *evtp; | ||
253 | uint32_t *lp; | 249 | uint32_t *lp; |
254 | IOCB_t *icmd; | 250 | IOCB_t *icmd; |
255 | struct serv_parm *sp; | 251 | struct serv_parm *sp; |
@@ -425,73 +421,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
425 | ndlp, mbox); | 421 | ndlp, mbox); |
426 | return 1; | 422 | return 1; |
427 | } | 423 | } |
428 | |||
429 | /* If the remote NPort logs into us, before we can initiate | ||
430 | * discovery to them, cleanup the NPort from discovery accordingly. | ||
431 | */ | ||
432 | if (ndlp->nlp_state == NLP_STE_NPR_NODE) { | ||
433 | spin_lock_irq(shost->host_lock); | ||
434 | ndlp->nlp_flag &= ~NLP_DELAY_TMO; | ||
435 | spin_unlock_irq(shost->host_lock); | ||
436 | del_timer_sync(&ndlp->nlp_delayfunc); | ||
437 | ndlp->nlp_last_elscmd = 0; | ||
438 | |||
439 | if (!list_empty(&ndlp->els_retry_evt.evt_listp)) { | ||
440 | list_del_init(&ndlp->els_retry_evt.evt_listp); | ||
441 | /* Decrement ndlp reference count held for the | ||
442 | * delayed retry | ||
443 | */ | ||
444 | evtp = &ndlp->els_retry_evt; | ||
445 | lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); | ||
446 | } | ||
447 | |||
448 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { | ||
449 | spin_lock_irq(shost->host_lock); | ||
450 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
451 | spin_unlock_irq(shost->host_lock); | ||
452 | |||
453 | if ((ndlp->nlp_flag & NLP_ADISC_SND) && | ||
454 | (vport->num_disc_nodes)) { | ||
455 | /* Check to see if there are more | ||
456 | * ADISCs to be sent | ||
457 | */ | ||
458 | lpfc_more_adisc(vport); | ||
459 | |||
460 | if ((vport->num_disc_nodes == 0) && | ||
461 | (vport->fc_npr_cnt)) | ||
462 | lpfc_els_disc_plogi(vport); | ||
463 | |||
464 | if (vport->num_disc_nodes == 0) { | ||
465 | spin_lock_irq(shost->host_lock); | ||
466 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
467 | spin_unlock_irq(shost->host_lock); | ||
468 | lpfc_can_disctmo(vport); | ||
469 | lpfc_end_rscn(vport); | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | } else if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) && | ||
474 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) && | ||
475 | (vport->num_disc_nodes)) { | ||
476 | spin_lock_irq(shost->host_lock); | ||
477 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
478 | spin_unlock_irq(shost->host_lock); | ||
479 | /* Check to see if there are more | ||
480 | * PLOGIs to be sent | ||
481 | */ | ||
482 | lpfc_more_plogi(vport); | ||
483 | if (vport->num_disc_nodes == 0) { | ||
484 | spin_lock_irq(shost->host_lock); | ||
485 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
486 | spin_unlock_irq(shost->host_lock); | ||
487 | lpfc_can_disctmo(vport); | ||
488 | lpfc_end_rscn(vport); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); | 424 | lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); |
493 | return 1; | 425 | return 1; |
494 | |||
495 | out: | 426 | out: |
496 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | 427 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; |
497 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; | 428 | stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; |
@@ -574,7 +505,9 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
574 | else | 505 | else |
575 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); | 506 | lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); |
576 | 507 | ||
577 | if (!(ndlp->nlp_type & NLP_FABRIC) || | 508 | if ((!(ndlp->nlp_type & NLP_FABRIC) && |
509 | ((ndlp->nlp_type & NLP_FCP_TARGET) || | ||
510 | !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || | ||
578 | (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { | 511 | (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { |
579 | /* Only try to re-login if this is NOT a Fabric Node */ | 512 | /* Only try to re-login if this is NOT a Fabric Node */ |
580 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); | 513 | mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); |
@@ -751,6 +684,7 @@ static uint32_t | |||
751 | lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 684 | lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
752 | void *arg, uint32_t evt) | 685 | void *arg, uint32_t evt) |
753 | { | 686 | { |
687 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
754 | struct lpfc_hba *phba = vport->phba; | 688 | struct lpfc_hba *phba = vport->phba; |
755 | struct lpfc_iocbq *cmdiocb = arg; | 689 | struct lpfc_iocbq *cmdiocb = arg; |
756 | struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 690 | struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
@@ -776,7 +710,22 @@ lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
776 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, | 710 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, |
777 | NULL); | 711 | NULL); |
778 | } else { | 712 | } else { |
779 | lpfc_rcv_plogi(vport, ndlp, cmdiocb); | 713 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && |
714 | (ndlp->nlp_flag & NLP_NPR_2B_DISC) && | ||
715 | (vport->num_disc_nodes)) { | ||
716 | spin_lock_irq(shost->host_lock); | ||
717 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
718 | spin_unlock_irq(shost->host_lock); | ||
719 | /* Check if there are more PLOGIs to be sent */ | ||
720 | lpfc_more_plogi(vport); | ||
721 | if (vport->num_disc_nodes == 0) { | ||
722 | spin_lock_irq(shost->host_lock); | ||
723 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
724 | spin_unlock_irq(shost->host_lock); | ||
725 | lpfc_can_disctmo(vport); | ||
726 | lpfc_end_rscn(vport); | ||
727 | } | ||
728 | } | ||
780 | } /* If our portname was less */ | 729 | } /* If our portname was less */ |
781 | 730 | ||
782 | return ndlp->nlp_state; | 731 | return ndlp->nlp_state; |
@@ -1040,6 +989,7 @@ static uint32_t | |||
1040 | lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | 989 | lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, |
1041 | void *arg, uint32_t evt) | 990 | void *arg, uint32_t evt) |
1042 | { | 991 | { |
992 | struct Scsi_Host *shost = lpfc_shost_from_vport(vport); | ||
1043 | struct lpfc_hba *phba = vport->phba; | 993 | struct lpfc_hba *phba = vport->phba; |
1044 | struct lpfc_iocbq *cmdiocb; | 994 | struct lpfc_iocbq *cmdiocb; |
1045 | 995 | ||
@@ -1048,9 +998,28 @@ lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1048 | 998 | ||
1049 | cmdiocb = (struct lpfc_iocbq *) arg; | 999 | cmdiocb = (struct lpfc_iocbq *) arg; |
1050 | 1000 | ||
1051 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) | 1001 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { |
1052 | return ndlp->nlp_state; | 1002 | if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { |
1003 | spin_lock_irq(shost->host_lock); | ||
1004 | ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; | ||
1005 | spin_unlock_irq(shost->host_lock); | ||
1053 | 1006 | ||
1007 | if (vport->num_disc_nodes) { | ||
1008 | lpfc_more_adisc(vport); | ||
1009 | if ((vport->num_disc_nodes == 0) && | ||
1010 | (vport->fc_npr_cnt)) | ||
1011 | lpfc_els_disc_plogi(vport); | ||
1012 | if (vport->num_disc_nodes == 0) { | ||
1013 | spin_lock_irq(shost->host_lock); | ||
1014 | vport->fc_flag &= ~FC_NDISC_ACTIVE; | ||
1015 | spin_unlock_irq(shost->host_lock); | ||
1016 | lpfc_can_disctmo(vport); | ||
1017 | lpfc_end_rscn(vport); | ||
1018 | } | ||
1019 | } | ||
1020 | } | ||
1021 | return ndlp->nlp_state; | ||
1022 | } | ||
1054 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; | 1023 | ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; |
1055 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); | 1024 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); |
1056 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 1025 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
@@ -1742,24 +1711,21 @@ lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1742 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | 1711 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; |
1743 | 1712 | ||
1744 | /* Ignore PLOGI if we have an outstanding LOGO */ | 1713 | /* Ignore PLOGI if we have an outstanding LOGO */ |
1745 | if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) { | 1714 | if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) |
1746 | return ndlp->nlp_state; | 1715 | return ndlp->nlp_state; |
1747 | } | ||
1748 | |||
1749 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { | 1716 | if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { |
1717 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1750 | spin_lock_irq(shost->host_lock); | 1718 | spin_lock_irq(shost->host_lock); |
1751 | ndlp->nlp_flag &= ~NLP_NPR_ADISC; | 1719 | ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); |
1752 | spin_unlock_irq(shost->host_lock); | 1720 | spin_unlock_irq(shost->host_lock); |
1753 | return ndlp->nlp_state; | 1721 | } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { |
1754 | } | 1722 | /* send PLOGI immediately, move to PLOGI issue state */ |
1755 | 1723 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | |
1756 | /* send PLOGI immediately, move to PLOGI issue state */ | 1724 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; |
1757 | if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { | 1725 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); |
1758 | ndlp->nlp_prev_state = NLP_STE_NPR_NODE; | 1726 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); |
1759 | lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); | 1727 | } |
1760 | lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); | ||
1761 | } | 1728 | } |
1762 | |||
1763 | return ndlp->nlp_state; | 1729 | return ndlp->nlp_state; |
1764 | } | 1730 | } |
1765 | 1731 | ||
@@ -1810,7 +1776,6 @@ lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1810 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; | 1776 | struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; |
1811 | 1777 | ||
1812 | lpfc_rcv_padisc(vport, ndlp, cmdiocb); | 1778 | lpfc_rcv_padisc(vport, ndlp, cmdiocb); |
1813 | |||
1814 | /* | 1779 | /* |
1815 | * Do not start discovery if discovery is about to start | 1780 | * Do not start discovery if discovery is about to start |
1816 | * or discovery in progress for this node. Starting discovery | 1781 | * or discovery in progress for this node. Starting discovery |
@@ -1973,9 +1938,7 @@ lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
1973 | spin_lock_irq(shost->host_lock); | 1938 | spin_lock_irq(shost->host_lock); |
1974 | ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); | 1939 | ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); |
1975 | spin_unlock_irq(shost->host_lock); | 1940 | spin_unlock_irq(shost->host_lock); |
1976 | if (ndlp->nlp_flag & NLP_DELAY_TMO) { | 1941 | lpfc_cancel_retry_delay_tmo(vport, ndlp); |
1977 | lpfc_cancel_retry_delay_tmo(vport, ndlp); | ||
1978 | } | ||
1979 | return ndlp->nlp_state; | 1942 | return ndlp->nlp_state; |
1980 | } | 1943 | } |
1981 | 1944 | ||
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 0910a9ab76a5..c94da4f2b8a6 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
@@ -50,6 +50,7 @@ void | |||
50 | lpfc_adjust_queue_depth(struct lpfc_hba *phba) | 50 | lpfc_adjust_queue_depth(struct lpfc_hba *phba) |
51 | { | 51 | { |
52 | unsigned long flags; | 52 | unsigned long flags; |
53 | uint32_t evt_posted; | ||
53 | 54 | ||
54 | spin_lock_irqsave(&phba->hbalock, flags); | 55 | spin_lock_irqsave(&phba->hbalock, flags); |
55 | atomic_inc(&phba->num_rsrc_err); | 56 | atomic_inc(&phba->num_rsrc_err); |
@@ -65,17 +66,13 @@ lpfc_adjust_queue_depth(struct lpfc_hba *phba) | |||
65 | spin_unlock_irqrestore(&phba->hbalock, flags); | 66 | spin_unlock_irqrestore(&phba->hbalock, flags); |
66 | 67 | ||
67 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); | 68 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); |
68 | if ((phba->pport->work_port_events & | 69 | evt_posted = phba->pport->work_port_events & WORKER_RAMP_DOWN_QUEUE; |
69 | WORKER_RAMP_DOWN_QUEUE) == 0) { | 70 | if (!evt_posted) |
70 | phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; | 71 | phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; |
71 | } | ||
72 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | 72 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); |
73 | 73 | ||
74 | spin_lock_irqsave(&phba->hbalock, flags); | 74 | if (!evt_posted) |
75 | if (phba->work_wait) | 75 | lpfc_worker_wake_up(phba); |
76 | wake_up(phba->work_wait); | ||
77 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
78 | |||
79 | return; | 76 | return; |
80 | } | 77 | } |
81 | 78 | ||
@@ -89,6 +86,7 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport, | |||
89 | { | 86 | { |
90 | unsigned long flags; | 87 | unsigned long flags; |
91 | struct lpfc_hba *phba = vport->phba; | 88 | struct lpfc_hba *phba = vport->phba; |
89 | uint32_t evt_posted; | ||
92 | atomic_inc(&phba->num_cmd_success); | 90 | atomic_inc(&phba->num_cmd_success); |
93 | 91 | ||
94 | if (vport->cfg_lun_queue_depth <= sdev->queue_depth) | 92 | if (vport->cfg_lun_queue_depth <= sdev->queue_depth) |
@@ -103,16 +101,14 @@ lpfc_rampup_queue_depth(struct lpfc_vport *vport, | |||
103 | spin_unlock_irqrestore(&phba->hbalock, flags); | 101 | spin_unlock_irqrestore(&phba->hbalock, flags); |
104 | 102 | ||
105 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); | 103 | spin_lock_irqsave(&phba->pport->work_port_lock, flags); |
106 | if ((phba->pport->work_port_events & | 104 | evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE; |
107 | WORKER_RAMP_UP_QUEUE) == 0) { | 105 | if (!evt_posted) |
108 | phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; | 106 | phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; |
109 | } | ||
110 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); | 107 | spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); |
111 | 108 | ||
112 | spin_lock_irqsave(&phba->hbalock, flags); | 109 | if (!evt_posted) |
113 | if (phba->work_wait) | 110 | lpfc_worker_wake_up(phba); |
114 | wake_up(phba->work_wait); | 111 | return; |
115 | spin_unlock_irqrestore(&phba->hbalock, flags); | ||
116 | } | 112 | } |
117 | 113 | ||
118 | void | 114 | void |
@@ -609,9 +605,6 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
609 | result = cmd->result; | 605 | result = cmd->result; |
610 | sdev = cmd->device; | 606 | sdev = cmd->device; |
611 | lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); | 607 | lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); |
612 | spin_lock_irqsave(sdev->host->host_lock, flags); | ||
613 | lpfc_cmd->pCmd = NULL; /* This must be done before scsi_done */ | ||
614 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | ||
615 | cmd->scsi_done(cmd); | 608 | cmd->scsi_done(cmd); |
616 | 609 | ||
617 | if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { | 610 | if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { |
@@ -620,6 +613,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
620 | * wake up the thread. | 613 | * wake up the thread. |
621 | */ | 614 | */ |
622 | spin_lock_irqsave(sdev->host->host_lock, flags); | 615 | spin_lock_irqsave(sdev->host->host_lock, flags); |
616 | lpfc_cmd->pCmd = NULL; | ||
623 | if (lpfc_cmd->waitq) | 617 | if (lpfc_cmd->waitq) |
624 | wake_up(lpfc_cmd->waitq); | 618 | wake_up(lpfc_cmd->waitq); |
625 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | 619 | spin_unlock_irqrestore(sdev->host->host_lock, flags); |
@@ -690,6 +684,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
690 | * wake up the thread. | 684 | * wake up the thread. |
691 | */ | 685 | */ |
692 | spin_lock_irqsave(sdev->host->host_lock, flags); | 686 | spin_lock_irqsave(sdev->host->host_lock, flags); |
687 | lpfc_cmd->pCmd = NULL; | ||
693 | if (lpfc_cmd->waitq) | 688 | if (lpfc_cmd->waitq) |
694 | wake_up(lpfc_cmd->waitq); | 689 | wake_up(lpfc_cmd->waitq); |
695 | spin_unlock_irqrestore(sdev->host->host_lock, flags); | 690 | spin_unlock_irqrestore(sdev->host->host_lock, flags); |
@@ -849,14 +844,15 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | |||
849 | struct lpfc_iocbq *iocbq; | 844 | struct lpfc_iocbq *iocbq; |
850 | struct lpfc_iocbq *iocbqrsp; | 845 | struct lpfc_iocbq *iocbqrsp; |
851 | int ret; | 846 | int ret; |
847 | int status; | ||
852 | 848 | ||
853 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) | 849 | if (!rdata->pnode || !NLP_CHK_NODE_ACT(rdata->pnode)) |
854 | return FAILED; | 850 | return FAILED; |
855 | 851 | ||
856 | lpfc_cmd->rdata = rdata; | 852 | lpfc_cmd->rdata = rdata; |
857 | ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, | 853 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun, |
858 | FCP_TARGET_RESET); | 854 | FCP_TARGET_RESET); |
859 | if (!ret) | 855 | if (!status) |
860 | return FAILED; | 856 | return FAILED; |
861 | 857 | ||
862 | iocbq = &lpfc_cmd->cur_iocbq; | 858 | iocbq = &lpfc_cmd->cur_iocbq; |
@@ -869,12 +865,15 @@ lpfc_scsi_tgt_reset(struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_vport *vport, | |||
869 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | 865 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
870 | "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", | 866 | "0702 Issue Target Reset to TGT %d Data: x%x x%x\n", |
871 | tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); | 867 | tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag); |
872 | ret = lpfc_sli_issue_iocb_wait(phba, | 868 | status = lpfc_sli_issue_iocb_wait(phba, |
873 | &phba->sli.ring[phba->sli.fcp_ring], | 869 | &phba->sli.ring[phba->sli.fcp_ring], |
874 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 870 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
875 | if (ret != IOCB_SUCCESS) { | 871 | if (status != IOCB_SUCCESS) { |
876 | if (ret == IOCB_TIMEDOUT) | 872 | if (status == IOCB_TIMEDOUT) { |
877 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | 873 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; |
874 | ret = TIMEOUT_ERROR; | ||
875 | } else | ||
876 | ret = FAILED; | ||
878 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; | 877 | lpfc_cmd->status = IOSTAT_DRIVER_REJECT; |
879 | } else { | 878 | } else { |
880 | ret = SUCCESS; | 879 | ret = SUCCESS; |
@@ -1142,121 +1141,96 @@ lpfc_device_reset_handler(struct scsi_cmnd *cmnd) | |||
1142 | struct lpfc_iocbq *iocbq, *iocbqrsp; | 1141 | struct lpfc_iocbq *iocbq, *iocbqrsp; |
1143 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 1142 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
1144 | struct lpfc_nodelist *pnode = rdata->pnode; | 1143 | struct lpfc_nodelist *pnode = rdata->pnode; |
1145 | uint32_t cmd_result = 0, cmd_status = 0; | 1144 | unsigned long later; |
1146 | int ret = FAILED; | 1145 | int ret = SUCCESS; |
1147 | int iocb_status = IOCB_SUCCESS; | 1146 | int status; |
1148 | int cnt, loopcnt; | 1147 | int cnt; |
1149 | 1148 | ||
1150 | lpfc_block_error_handler(cmnd); | 1149 | lpfc_block_error_handler(cmnd); |
1151 | loopcnt = 0; | ||
1152 | /* | 1150 | /* |
1153 | * If target is not in a MAPPED state, delay the reset until | 1151 | * If target is not in a MAPPED state, delay the reset until |
1154 | * target is rediscovered or devloss timeout expires. | 1152 | * target is rediscovered or devloss timeout expires. |
1155 | */ | 1153 | */ |
1156 | while (1) { | 1154 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1155 | while (time_after(later, jiffies)) { | ||
1157 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | 1156 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) |
1158 | goto out; | 1157 | return FAILED; |
1159 | |||
1160 | if (pnode->nlp_state != NLP_STE_MAPPED_NODE) { | ||
1161 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
1162 | loopcnt++; | ||
1163 | rdata = cmnd->device->hostdata; | ||
1164 | if (!rdata || | ||
1165 | (loopcnt > ((vport->cfg_devloss_tmo * 2) + 1))){ | ||
1166 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1167 | "0721 LUN Reset rport " | ||
1168 | "failure: cnt x%x rdata x%p\n", | ||
1169 | loopcnt, rdata); | ||
1170 | goto out; | ||
1171 | } | ||
1172 | pnode = rdata->pnode; | ||
1173 | if (!pnode || !NLP_CHK_NODE_ACT(pnode)) | ||
1174 | goto out; | ||
1175 | } | ||
1176 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) | 1158 | if (pnode->nlp_state == NLP_STE_MAPPED_NODE) |
1177 | break; | 1159 | break; |
1160 | schedule_timeout_uninterruptible(msecs_to_jiffies(500)); | ||
1161 | rdata = cmnd->device->hostdata; | ||
1162 | if (!rdata) | ||
1163 | break; | ||
1164 | pnode = rdata->pnode; | ||
1165 | } | ||
1166 | if (!rdata || pnode->nlp_state != NLP_STE_MAPPED_NODE) { | ||
1167 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1168 | "0721 LUN Reset rport " | ||
1169 | "failure: msec x%x rdata x%p\n", | ||
1170 | jiffies_to_msecs(jiffies - later), rdata); | ||
1171 | return FAILED; | ||
1178 | } | 1172 | } |
1179 | |||
1180 | lpfc_cmd = lpfc_get_scsi_buf(phba); | 1173 | lpfc_cmd = lpfc_get_scsi_buf(phba); |
1181 | if (lpfc_cmd == NULL) | 1174 | if (lpfc_cmd == NULL) |
1182 | goto out; | 1175 | return FAILED; |
1183 | |||
1184 | lpfc_cmd->timeout = 60; | 1176 | lpfc_cmd->timeout = 60; |
1185 | lpfc_cmd->rdata = rdata; | 1177 | lpfc_cmd->rdata = rdata; |
1186 | 1178 | ||
1187 | ret = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, cmnd->device->lun, | 1179 | status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, |
1188 | FCP_TARGET_RESET); | 1180 | cmnd->device->lun, |
1189 | if (!ret) | 1181 | FCP_TARGET_RESET); |
1190 | goto out_free_scsi_buf; | 1182 | if (!status) { |
1191 | 1183 | lpfc_release_scsi_buf(phba, lpfc_cmd); | |
1184 | return FAILED; | ||
1185 | } | ||
1192 | iocbq = &lpfc_cmd->cur_iocbq; | 1186 | iocbq = &lpfc_cmd->cur_iocbq; |
1193 | 1187 | ||
1194 | /* get a buffer for this IOCB command response */ | 1188 | /* get a buffer for this IOCB command response */ |
1195 | iocbqrsp = lpfc_sli_get_iocbq(phba); | 1189 | iocbqrsp = lpfc_sli_get_iocbq(phba); |
1196 | if (iocbqrsp == NULL) | 1190 | if (iocbqrsp == NULL) { |
1197 | goto out_free_scsi_buf; | 1191 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
1198 | 1192 | return FAILED; | |
1193 | } | ||
1199 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, | 1194 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, |
1200 | "0703 Issue target reset to TGT %d LUN %d " | 1195 | "0703 Issue target reset to TGT %d LUN %d " |
1201 | "rpi x%x nlp_flag x%x\n", cmnd->device->id, | 1196 | "rpi x%x nlp_flag x%x\n", cmnd->device->id, |
1202 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); | 1197 | cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag); |
1203 | iocb_status = lpfc_sli_issue_iocb_wait(phba, | 1198 | status = lpfc_sli_issue_iocb_wait(phba, |
1204 | &phba->sli.ring[phba->sli.fcp_ring], | 1199 | &phba->sli.ring[phba->sli.fcp_ring], |
1205 | iocbq, iocbqrsp, lpfc_cmd->timeout); | 1200 | iocbq, iocbqrsp, lpfc_cmd->timeout); |
1206 | 1201 | if (status == IOCB_TIMEDOUT) { | |
1207 | if (iocb_status == IOCB_TIMEDOUT) | ||
1208 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; | 1202 | iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; |
1209 | 1203 | ret = TIMEOUT_ERROR; | |
1210 | if (iocb_status == IOCB_SUCCESS) | 1204 | } else { |
1211 | ret = SUCCESS; | 1205 | if (status != IOCB_SUCCESS) |
1212 | else | 1206 | ret = FAILED; |
1213 | ret = iocb_status; | 1207 | lpfc_release_scsi_buf(phba, lpfc_cmd); |
1214 | 1208 | } | |
1215 | cmd_result = iocbqrsp->iocb.un.ulpWord[4]; | 1209 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1216 | cmd_status = iocbqrsp->iocb.ulpStatus; | 1210 | "0713 SCSI layer issued device reset (%d, %d) " |
1217 | 1211 | "return x%x status x%x result x%x\n", | |
1212 | cmnd->device->id, cmnd->device->lun, ret, | ||
1213 | iocbqrsp->iocb.ulpStatus, | ||
1214 | iocbqrsp->iocb.un.ulpWord[4]); | ||
1218 | lpfc_sli_release_iocbq(phba, iocbqrsp); | 1215 | lpfc_sli_release_iocbq(phba, iocbqrsp); |
1219 | |||
1220 | /* | ||
1221 | * All outstanding txcmplq I/Os should have been aborted by the device. | ||
1222 | * Unfortunately, some targets do not abide by this forcing the driver | ||
1223 | * to double check. | ||
1224 | */ | ||
1225 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, | 1216 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun, |
1226 | LPFC_CTX_LUN); | 1217 | LPFC_CTX_TGT); |
1227 | if (cnt) | 1218 | if (cnt) |
1228 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 1219 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
1229 | cmnd->device->id, cmnd->device->lun, | 1220 | cmnd->device->id, cmnd->device->lun, |
1230 | LPFC_CTX_LUN); | 1221 | LPFC_CTX_TGT); |
1231 | loopcnt = 0; | 1222 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1232 | while(cnt) { | 1223 | while (time_after(later, jiffies) && cnt) { |
1233 | schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | 1224 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
1234 | |||
1235 | if (++loopcnt | ||
1236 | > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT) | ||
1237 | break; | ||
1238 | |||
1239 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, | 1225 | cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, |
1240 | cmnd->device->lun, LPFC_CTX_LUN); | 1226 | cmnd->device->lun, LPFC_CTX_TGT); |
1241 | } | 1227 | } |
1242 | |||
1243 | if (cnt) { | 1228 | if (cnt) { |
1244 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1229 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1245 | "0719 device reset I/O flush failure: " | 1230 | "0719 device reset I/O flush failure: " |
1246 | "cnt x%x\n", cnt); | 1231 | "cnt x%x\n", cnt); |
1247 | ret = FAILED; | 1232 | ret = FAILED; |
1248 | } | 1233 | } |
1249 | |||
1250 | out_free_scsi_buf: | ||
1251 | if (iocb_status != IOCB_TIMEDOUT) { | ||
1252 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1253 | } | ||
1254 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | ||
1255 | "0713 SCSI layer issued device reset (%d, %d) " | ||
1256 | "return x%x status x%x result x%x\n", | ||
1257 | cmnd->device->id, cmnd->device->lun, ret, | ||
1258 | cmd_status, cmd_result); | ||
1259 | out: | ||
1260 | return ret; | 1234 | return ret; |
1261 | } | 1235 | } |
1262 | 1236 | ||
@@ -1268,19 +1242,12 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1268 | struct lpfc_hba *phba = vport->phba; | 1242 | struct lpfc_hba *phba = vport->phba; |
1269 | struct lpfc_nodelist *ndlp = NULL; | 1243 | struct lpfc_nodelist *ndlp = NULL; |
1270 | int match; | 1244 | int match; |
1271 | int ret = FAILED, i, err_count = 0; | 1245 | int ret = SUCCESS, status, i; |
1272 | int cnt, loopcnt; | 1246 | int cnt; |
1273 | struct lpfc_scsi_buf * lpfc_cmd; | 1247 | struct lpfc_scsi_buf * lpfc_cmd; |
1248 | unsigned long later; | ||
1274 | 1249 | ||
1275 | lpfc_block_error_handler(cmnd); | 1250 | lpfc_block_error_handler(cmnd); |
1276 | |||
1277 | lpfc_cmd = lpfc_get_scsi_buf(phba); | ||
1278 | if (lpfc_cmd == NULL) | ||
1279 | goto out; | ||
1280 | |||
1281 | /* The lpfc_cmd storage is reused. Set all loop invariants. */ | ||
1282 | lpfc_cmd->timeout = 60; | ||
1283 | |||
1284 | /* | 1251 | /* |
1285 | * Since the driver manages a single bus device, reset all | 1252 | * Since the driver manages a single bus device, reset all |
1286 | * targets known to the driver. Should any target reset | 1253 | * targets known to the driver. Should any target reset |
@@ -1294,7 +1261,7 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1294 | if (!NLP_CHK_NODE_ACT(ndlp)) | 1261 | if (!NLP_CHK_NODE_ACT(ndlp)) |
1295 | continue; | 1262 | continue; |
1296 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && | 1263 | if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && |
1297 | i == ndlp->nlp_sid && | 1264 | ndlp->nlp_sid == i && |
1298 | ndlp->rport) { | 1265 | ndlp->rport) { |
1299 | match = 1; | 1266 | match = 1; |
1300 | break; | 1267 | break; |
@@ -1303,27 +1270,22 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1303 | spin_unlock_irq(shost->host_lock); | 1270 | spin_unlock_irq(shost->host_lock); |
1304 | if (!match) | 1271 | if (!match) |
1305 | continue; | 1272 | continue; |
1306 | 1273 | lpfc_cmd = lpfc_get_scsi_buf(phba); | |
1307 | ret = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, | 1274 | if (lpfc_cmd) { |
1308 | cmnd->device->lun, | 1275 | lpfc_cmd->timeout = 60; |
1309 | ndlp->rport->dd_data); | 1276 | status = lpfc_scsi_tgt_reset(lpfc_cmd, vport, i, |
1310 | if (ret != SUCCESS) { | 1277 | cmnd->device->lun, |
1278 | ndlp->rport->dd_data); | ||
1279 | if (status != TIMEOUT_ERROR) | ||
1280 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1281 | } | ||
1282 | if (!lpfc_cmd || status != SUCCESS) { | ||
1311 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1283 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1312 | "0700 Bus Reset on target %d failed\n", | 1284 | "0700 Bus Reset on target %d failed\n", |
1313 | i); | 1285 | i); |
1314 | err_count++; | 1286 | ret = FAILED; |
1315 | break; | ||
1316 | } | 1287 | } |
1317 | } | 1288 | } |
1318 | |||
1319 | if (ret != IOCB_TIMEDOUT) | ||
1320 | lpfc_release_scsi_buf(phba, lpfc_cmd); | ||
1321 | |||
1322 | if (err_count == 0) | ||
1323 | ret = SUCCESS; | ||
1324 | else | ||
1325 | ret = FAILED; | ||
1326 | |||
1327 | /* | 1289 | /* |
1328 | * All outstanding txcmplq I/Os should have been aborted by | 1290 | * All outstanding txcmplq I/Os should have been aborted by |
1329 | * the targets. Unfortunately, some targets do not abide by | 1291 | * the targets. Unfortunately, some targets do not abide by |
@@ -1333,27 +1295,19 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) | |||
1333 | if (cnt) | 1295 | if (cnt) |
1334 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], | 1296 | lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], |
1335 | 0, 0, LPFC_CTX_HOST); | 1297 | 0, 0, LPFC_CTX_HOST); |
1336 | loopcnt = 0; | 1298 | later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; |
1337 | while(cnt) { | 1299 | while (time_after(later, jiffies) && cnt) { |
1338 | schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ); | 1300 | schedule_timeout_uninterruptible(msecs_to_jiffies(20)); |
1339 | |||
1340 | if (++loopcnt | ||
1341 | > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT) | ||
1342 | break; | ||
1343 | |||
1344 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); | 1301 | cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST); |
1345 | } | 1302 | } |
1346 | |||
1347 | if (cnt) { | 1303 | if (cnt) { |
1348 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1304 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1349 | "0715 Bus Reset I/O flush failure: " | 1305 | "0715 Bus Reset I/O flush failure: " |
1350 | "cnt x%x left x%x\n", cnt, i); | 1306 | "cnt x%x left x%x\n", cnt, i); |
1351 | ret = FAILED; | 1307 | ret = FAILED; |
1352 | } | 1308 | } |
1353 | |||
1354 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, | 1309 | lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, |
1355 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); | 1310 | "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); |
1356 | out: | ||
1357 | return ret; | 1311 | return ret; |
1358 | } | 1312 | } |
1359 | 1313 | ||
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 70a0a9eab211..f40aa7b905f7 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c | |||
@@ -324,9 +324,7 @@ lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
324 | phba->work_ha |= HA_ERATT; | 324 | phba->work_ha |= HA_ERATT; |
325 | phba->work_hs = HS_FFER3; | 325 | phba->work_hs = HS_FFER3; |
326 | 326 | ||
327 | /* hbalock should already be held */ | 327 | lpfc_worker_wake_up(phba); |
328 | if (phba->work_wait) | ||
329 | lpfc_worker_wake_up(phba); | ||
330 | 328 | ||
331 | return NULL; | 329 | return NULL; |
332 | } | 330 | } |
@@ -1309,9 +1307,7 @@ lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) | |||
1309 | phba->work_ha |= HA_ERATT; | 1307 | phba->work_ha |= HA_ERATT; |
1310 | phba->work_hs = HS_FFER3; | 1308 | phba->work_hs = HS_FFER3; |
1311 | 1309 | ||
1312 | /* hbalock should already be held */ | 1310 | lpfc_worker_wake_up(phba); |
1313 | if (phba->work_wait) | ||
1314 | lpfc_worker_wake_up(phba); | ||
1315 | 1311 | ||
1316 | return; | 1312 | return; |
1317 | } | 1313 | } |
@@ -2611,12 +2607,9 @@ lpfc_mbox_timeout(unsigned long ptr) | |||
2611 | phba->pport->work_port_events |= WORKER_MBOX_TMO; | 2607 | phba->pport->work_port_events |= WORKER_MBOX_TMO; |
2612 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); | 2608 | spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); |
2613 | 2609 | ||
2614 | if (!tmo_posted) { | 2610 | if (!tmo_posted) |
2615 | spin_lock_irqsave(&phba->hbalock, iflag); | 2611 | lpfc_worker_wake_up(phba); |
2616 | if (phba->work_wait) | 2612 | return; |
2617 | lpfc_worker_wake_up(phba); | ||
2618 | spin_unlock_irqrestore(&phba->hbalock, iflag); | ||
2619 | } | ||
2620 | } | 2613 | } |
2621 | 2614 | ||
2622 | void | 2615 | void |
@@ -3374,8 +3367,12 @@ lpfc_sli_host_down(struct lpfc_vport *vport) | |||
3374 | for (i = 0; i < psli->num_rings; i++) { | 3367 | for (i = 0; i < psli->num_rings; i++) { |
3375 | pring = &psli->ring[i]; | 3368 | pring = &psli->ring[i]; |
3376 | prev_pring_flag = pring->flag; | 3369 | prev_pring_flag = pring->flag; |
3377 | if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */ | 3370 | /* Only slow rings */ |
3371 | if (pring->ringno == LPFC_ELS_RING) { | ||
3378 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 3372 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
3373 | /* Set the lpfc data pending flag */ | ||
3374 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
3375 | } | ||
3379 | /* | 3376 | /* |
3380 | * Error everything on the txq since these iocbs have not been | 3377 | * Error everything on the txq since these iocbs have not been |
3381 | * given to the FW yet. | 3378 | * given to the FW yet. |
@@ -3434,8 +3431,12 @@ lpfc_sli_hba_down(struct lpfc_hba *phba) | |||
3434 | spin_lock_irqsave(&phba->hbalock, flags); | 3431 | spin_lock_irqsave(&phba->hbalock, flags); |
3435 | for (i = 0; i < psli->num_rings; i++) { | 3432 | for (i = 0; i < psli->num_rings; i++) { |
3436 | pring = &psli->ring[i]; | 3433 | pring = &psli->ring[i]; |
3437 | if (pring->ringno == LPFC_ELS_RING) /* Only slow rings */ | 3434 | /* Only slow rings */ |
3435 | if (pring->ringno == LPFC_ELS_RING) { | ||
3438 | pring->flag |= LPFC_DEFERRED_RING_EVENT; | 3436 | pring->flag |= LPFC_DEFERRED_RING_EVENT; |
3437 | /* Set the lpfc data pending flag */ | ||
3438 | set_bit(LPFC_DATA_READY, &phba->data_flags); | ||
3439 | } | ||
3439 | 3440 | ||
3440 | /* | 3441 | /* |
3441 | * Error everything on the txq since these iocbs have not been | 3442 | * Error everything on the txq since these iocbs have not been |
@@ -3762,7 +3763,6 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, | |||
3762 | lpfc_ctx_cmd ctx_cmd) | 3763 | lpfc_ctx_cmd ctx_cmd) |
3763 | { | 3764 | { |
3764 | struct lpfc_scsi_buf *lpfc_cmd; | 3765 | struct lpfc_scsi_buf *lpfc_cmd; |
3765 | struct scsi_cmnd *cmnd; | ||
3766 | int rc = 1; | 3766 | int rc = 1; |
3767 | 3767 | ||
3768 | if (!(iocbq->iocb_flag & LPFC_IO_FCP)) | 3768 | if (!(iocbq->iocb_flag & LPFC_IO_FCP)) |
@@ -3772,19 +3772,20 @@ lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, | |||
3772 | return rc; | 3772 | return rc; |
3773 | 3773 | ||
3774 | lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); | 3774 | lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); |
3775 | cmnd = lpfc_cmd->pCmd; | ||
3776 | 3775 | ||
3777 | if (cmnd == NULL) | 3776 | if (lpfc_cmd->pCmd == NULL) |
3778 | return rc; | 3777 | return rc; |
3779 | 3778 | ||
3780 | switch (ctx_cmd) { | 3779 | switch (ctx_cmd) { |
3781 | case LPFC_CTX_LUN: | 3780 | case LPFC_CTX_LUN: |
3782 | if ((cmnd->device->id == tgt_id) && | 3781 | if ((lpfc_cmd->rdata->pnode) && |
3783 | (cmnd->device->lun == lun_id)) | 3782 | (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id) && |
3783 | (scsilun_to_int(&lpfc_cmd->fcp_cmnd->fcp_lun) == lun_id)) | ||
3784 | rc = 0; | 3784 | rc = 0; |
3785 | break; | 3785 | break; |
3786 | case LPFC_CTX_TGT: | 3786 | case LPFC_CTX_TGT: |
3787 | if (cmnd->device->id == tgt_id) | 3787 | if ((lpfc_cmd->rdata->pnode) && |
3788 | (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id)) | ||
3788 | rc = 0; | 3789 | rc = 0; |
3789 | break; | 3790 | break; |
3790 | case LPFC_CTX_HOST: | 3791 | case LPFC_CTX_HOST: |
@@ -3994,6 +3995,7 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, | |||
3994 | if (pmboxq->context1) | 3995 | if (pmboxq->context1) |
3995 | return MBX_NOT_FINISHED; | 3996 | return MBX_NOT_FINISHED; |
3996 | 3997 | ||
3998 | pmboxq->mbox_flag &= ~LPFC_MBX_WAKE; | ||
3997 | /* setup wake call as IOCB callback */ | 3999 | /* setup wake call as IOCB callback */ |
3998 | pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; | 4000 | pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; |
3999 | /* setup context field to pass wait_queue pointer to wake function */ | 4001 | /* setup context field to pass wait_queue pointer to wake function */ |
@@ -4159,7 +4161,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
4159 | "pwork:x%x hawork:x%x wait:x%x", | 4161 | "pwork:x%x hawork:x%x wait:x%x", |
4160 | phba->work_ha, work_ha_copy, | 4162 | phba->work_ha, work_ha_copy, |
4161 | (uint32_t)((unsigned long) | 4163 | (uint32_t)((unsigned long) |
4162 | phba->work_wait)); | 4164 | &phba->work_waitq)); |
4163 | 4165 | ||
4164 | control &= | 4166 | control &= |
4165 | ~(HC_R0INT_ENA << LPFC_ELS_RING); | 4167 | ~(HC_R0INT_ENA << LPFC_ELS_RING); |
@@ -4172,7 +4174,7 @@ lpfc_intr_handler(int irq, void *dev_id) | |||
4172 | "x%x hawork:x%x wait:x%x", | 4174 | "x%x hawork:x%x wait:x%x", |
4173 | phba->work_ha, work_ha_copy, | 4175 | phba->work_ha, work_ha_copy, |
4174 | (uint32_t)((unsigned long) | 4176 | (uint32_t)((unsigned long) |
4175 | phba->work_wait)); | 4177 | &phba->work_waitq)); |
4176 | } | 4178 | } |
4177 | spin_unlock(&phba->hbalock); | 4179 | spin_unlock(&phba->hbalock); |
4178 | } | 4180 | } |
@@ -4297,9 +4299,8 @@ send_current_mbox: | |||
4297 | 4299 | ||
4298 | spin_lock(&phba->hbalock); | 4300 | spin_lock(&phba->hbalock); |
4299 | phba->work_ha |= work_ha_copy; | 4301 | phba->work_ha |= work_ha_copy; |
4300 | if (phba->work_wait) | ||
4301 | lpfc_worker_wake_up(phba); | ||
4302 | spin_unlock(&phba->hbalock); | 4302 | spin_unlock(&phba->hbalock); |
4303 | lpfc_worker_wake_up(phba); | ||
4303 | } | 4304 | } |
4304 | 4305 | ||
4305 | ha_copy &= ~(phba->work_ha_mask); | 4306 | ha_copy &= ~(phba->work_ha_mask); |
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index b22b893019f4..ad24cacfbe10 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h | |||
@@ -18,7 +18,7 @@ | |||
18 | * included with this package. * | 18 | * included with this package. * |
19 | *******************************************************************/ | 19 | *******************************************************************/ |
20 | 20 | ||
21 | #define LPFC_DRIVER_VERSION "8.2.6" | 21 | #define LPFC_DRIVER_VERSION "8.2.7" |
22 | 22 | ||
23 | #define LPFC_DRIVER_NAME "lpfc" | 23 | #define LPFC_DRIVER_NAME "lpfc" |
24 | 24 | ||
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 6feaf59b0b1b..109f89d98830 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c | |||
@@ -216,6 +216,7 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | |||
216 | int vpi; | 216 | int vpi; |
217 | int rc = VPORT_ERROR; | 217 | int rc = VPORT_ERROR; |
218 | int status; | 218 | int status; |
219 | int size; | ||
219 | 220 | ||
220 | if ((phba->sli_rev < 3) || | 221 | if ((phba->sli_rev < 3) || |
221 | !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { | 222 | !(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { |
@@ -278,7 +279,20 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) | |||
278 | 279 | ||
279 | memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); | 280 | memcpy(vport->fc_portname.u.wwn, vport->fc_sparam.portName.u.wwn, 8); |
280 | memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); | 281 | memcpy(vport->fc_nodename.u.wwn, vport->fc_sparam.nodeName.u.wwn, 8); |
281 | 282 | size = strnlen(fc_vport->symbolic_name, LPFC_VNAME_LEN); | |
283 | if (size) { | ||
284 | vport->vname = kzalloc(size+1, GFP_KERNEL); | ||
285 | if (!vport->vname) { | ||
286 | lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, | ||
287 | "1814 Create VPORT failed. " | ||
288 | "vname allocation failed.\n"); | ||
289 | rc = VPORT_ERROR; | ||
290 | lpfc_free_vpi(phba, vpi); | ||
291 | destroy_port(vport); | ||
292 | goto error_out; | ||
293 | } | ||
294 | memcpy(vport->vname, fc_vport->symbolic_name, size+1); | ||
295 | } | ||
282 | if (fc_vport->node_name != 0) | 296 | if (fc_vport->node_name != 0) |
283 | u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); | 297 | u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); |
284 | if (fc_vport->port_name != 0) | 298 | if (fc_vport->port_name != 0) |
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index fd63b06d9ef1..11aa917629ac 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c | |||
@@ -1765,7 +1765,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1765 | default: | 1765 | default: |
1766 | return 0; | 1766 | return 0; |
1767 | } | 1767 | } |
1768 | if (mesg.event == mdev->ofdev.dev.power.power_state.event) | 1768 | if (ms->phase == sleeping) |
1769 | return 0; | 1769 | return 0; |
1770 | 1770 | ||
1771 | scsi_block_requests(ms->host); | 1771 | scsi_block_requests(ms->host); |
@@ -1780,8 +1780,6 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) | |||
1780 | disable_irq(ms->meshintr); | 1780 | disable_irq(ms->meshintr); |
1781 | set_mesh_power(ms, 0); | 1781 | set_mesh_power(ms, 0); |
1782 | 1782 | ||
1783 | mdev->ofdev.dev.power.power_state = mesg; | ||
1784 | |||
1785 | return 0; | 1783 | return 0; |
1786 | } | 1784 | } |
1787 | 1785 | ||
@@ -1790,7 +1788,7 @@ static int mesh_resume(struct macio_dev *mdev) | |||
1790 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); | 1788 | struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); |
1791 | unsigned long flags; | 1789 | unsigned long flags; |
1792 | 1790 | ||
1793 | if (mdev->ofdev.dev.power.power_state.event == PM_EVENT_ON) | 1791 | if (ms->phase != sleeping) |
1794 | return 0; | 1792 | return 0; |
1795 | 1793 | ||
1796 | set_mesh_power(ms, 1); | 1794 | set_mesh_power(ms, 1); |
@@ -1801,8 +1799,6 @@ static int mesh_resume(struct macio_dev *mdev) | |||
1801 | enable_irq(ms->meshintr); | 1799 | enable_irq(ms->meshintr); |
1802 | scsi_unblock_requests(ms->host); | 1800 | scsi_unblock_requests(ms->host); |
1803 | 1801 | ||
1804 | mdev->ofdev.dev.power.power_state.event = PM_EVENT_ON; | ||
1805 | |||
1806 | return 0; | 1802 | return 0; |
1807 | } | 1803 | } |
1808 | 1804 | ||
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 0c786944d2c2..5822dd595826 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c | |||
@@ -113,9 +113,6 @@ static struct iscsi_transport qla4xxx_iscsi_transport = { | |||
113 | .host_param_mask = ISCSI_HOST_HWADDRESS | | 113 | .host_param_mask = ISCSI_HOST_HWADDRESS | |
114 | ISCSI_HOST_IPADDRESS | | 114 | ISCSI_HOST_IPADDRESS | |
115 | ISCSI_HOST_INITIATOR_NAME, | 115 | ISCSI_HOST_INITIATOR_NAME, |
116 | .sessiondata_size = sizeof(struct ddb_entry), | ||
117 | .host_template = &qla4xxx_driver_template, | ||
118 | |||
119 | .tgt_dscvr = qla4xxx_tgt_dscvr, | 116 | .tgt_dscvr = qla4xxx_tgt_dscvr, |
120 | .get_conn_param = qla4xxx_conn_get_param, | 117 | .get_conn_param = qla4xxx_conn_get_param, |
121 | .get_session_param = qla4xxx_sess_get_param, | 118 | .get_session_param = qla4xxx_sess_get_param, |
@@ -275,7 +272,7 @@ int qla4xxx_add_sess(struct ddb_entry *ddb_entry) | |||
275 | return err; | 272 | return err; |
276 | } | 273 | } |
277 | 274 | ||
278 | ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0); | 275 | ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0, 0); |
279 | if (!ddb_entry->conn) { | 276 | if (!ddb_entry->conn) { |
280 | iscsi_remove_session(ddb_entry->sess); | 277 | iscsi_remove_session(ddb_entry->sess); |
281 | DEBUG2(printk(KERN_ERR "Could not add connection.\n")); | 278 | DEBUG2(printk(KERN_ERR "Could not add connection.\n")); |
@@ -292,7 +289,8 @@ struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha) | |||
292 | struct ddb_entry *ddb_entry; | 289 | struct ddb_entry *ddb_entry; |
293 | struct iscsi_cls_session *sess; | 290 | struct iscsi_cls_session *sess; |
294 | 291 | ||
295 | sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport); | 292 | sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport, |
293 | sizeof(struct ddb_entry)); | ||
296 | if (!sess) | 294 | if (!sess) |
297 | return NULL; | 295 | return NULL; |
298 | 296 | ||
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 110e776d1a07..36c92f961e15 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c | |||
@@ -855,9 +855,18 @@ void scsi_finish_command(struct scsi_cmnd *cmd) | |||
855 | 855 | ||
856 | good_bytes = scsi_bufflen(cmd); | 856 | good_bytes = scsi_bufflen(cmd); |
857 | if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { | 857 | if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { |
858 | int old_good_bytes = good_bytes; | ||
858 | drv = scsi_cmd_to_driver(cmd); | 859 | drv = scsi_cmd_to_driver(cmd); |
859 | if (drv->done) | 860 | if (drv->done) |
860 | good_bytes = drv->done(cmd); | 861 | good_bytes = drv->done(cmd); |
862 | /* | ||
863 | * USB may not give sense identifying bad sector and | ||
864 | * simply return a residue instead, so subtract off the | ||
865 | * residue if drv->done() error processing indicates no | ||
866 | * change to the completion length. | ||
867 | */ | ||
868 | if (good_bytes == old_good_bytes) | ||
869 | good_bytes -= scsi_get_resid(cmd); | ||
861 | } | 870 | } |
862 | scsi_io_completion(cmd, good_bytes); | 871 | scsi_io_completion(cmd, good_bytes); |
863 | } | 872 | } |
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f6600bfb5bde..01d11a01ffbf 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -94,6 +94,7 @@ static const char * scsi_debug_version_date = "20070104"; | |||
94 | #define DEF_VIRTUAL_GB 0 | 94 | #define DEF_VIRTUAL_GB 0 |
95 | #define DEF_FAKE_RW 0 | 95 | #define DEF_FAKE_RW 0 |
96 | #define DEF_VPD_USE_HOSTNO 1 | 96 | #define DEF_VPD_USE_HOSTNO 1 |
97 | #define DEF_SECTOR_SIZE 512 | ||
97 | 98 | ||
98 | /* bit mask values for scsi_debug_opts */ | 99 | /* bit mask values for scsi_debug_opts */ |
99 | #define SCSI_DEBUG_OPT_NOISE 1 | 100 | #define SCSI_DEBUG_OPT_NOISE 1 |
@@ -142,6 +143,7 @@ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; | |||
142 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; | 143 | static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; |
143 | static int scsi_debug_fake_rw = DEF_FAKE_RW; | 144 | static int scsi_debug_fake_rw = DEF_FAKE_RW; |
144 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; | 145 | static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; |
146 | static int scsi_debug_sector_size = DEF_SECTOR_SIZE; | ||
145 | 147 | ||
146 | static int scsi_debug_cmnd_count = 0; | 148 | static int scsi_debug_cmnd_count = 0; |
147 | 149 | ||
@@ -157,11 +159,6 @@ static int sdebug_heads; /* heads per disk */ | |||
157 | static int sdebug_cylinders_per; /* cylinders per surface */ | 159 | static int sdebug_cylinders_per; /* cylinders per surface */ |
158 | static int sdebug_sectors_per; /* sectors per cylinder */ | 160 | static int sdebug_sectors_per; /* sectors per cylinder */ |
159 | 161 | ||
160 | /* default sector size is 512 bytes, 2**9 bytes */ | ||
161 | #define POW2_SECT_SIZE 9 | ||
162 | #define SECT_SIZE (1 << POW2_SECT_SIZE) | ||
163 | #define SECT_SIZE_PER(TGT) SECT_SIZE | ||
164 | |||
165 | #define SDEBUG_MAX_PARTS 4 | 162 | #define SDEBUG_MAX_PARTS 4 |
166 | 163 | ||
167 | #define SDEBUG_SENSE_LEN 32 | 164 | #define SDEBUG_SENSE_LEN 32 |
@@ -646,6 +643,14 @@ static int inquiry_evpd_b0(unsigned char * arr) | |||
646 | return sizeof(vpdb0_data); | 643 | return sizeof(vpdb0_data); |
647 | } | 644 | } |
648 | 645 | ||
646 | static int inquiry_evpd_b1(unsigned char *arr) | ||
647 | { | ||
648 | memset(arr, 0, 0x3c); | ||
649 | arr[0] = 0; | ||
650 | arr[1] = 1; | ||
651 | |||
652 | return 0x3c; | ||
653 | } | ||
649 | 654 | ||
650 | #define SDEBUG_LONG_INQ_SZ 96 | 655 | #define SDEBUG_LONG_INQ_SZ 96 |
651 | #define SDEBUG_MAX_INQ_ARR_SZ 584 | 656 | #define SDEBUG_MAX_INQ_ARR_SZ 584 |
@@ -701,6 +706,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
701 | arr[n++] = 0x88; /* SCSI ports */ | 706 | arr[n++] = 0x88; /* SCSI ports */ |
702 | arr[n++] = 0x89; /* ATA information */ | 707 | arr[n++] = 0x89; /* ATA information */ |
703 | arr[n++] = 0xb0; /* Block limits (SBC) */ | 708 | arr[n++] = 0xb0; /* Block limits (SBC) */ |
709 | arr[n++] = 0xb1; /* Block characteristics (SBC) */ | ||
704 | arr[3] = n - 4; /* number of supported VPD pages */ | 710 | arr[3] = n - 4; /* number of supported VPD pages */ |
705 | } else if (0x80 == cmd[2]) { /* unit serial number */ | 711 | } else if (0x80 == cmd[2]) { /* unit serial number */ |
706 | arr[1] = cmd[2]; /*sanity */ | 712 | arr[1] = cmd[2]; /*sanity */ |
@@ -740,6 +746,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, | |||
740 | } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ | 746 | } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ |
741 | arr[1] = cmd[2]; /*sanity */ | 747 | arr[1] = cmd[2]; /*sanity */ |
742 | arr[3] = inquiry_evpd_b0(&arr[4]); | 748 | arr[3] = inquiry_evpd_b0(&arr[4]); |
749 | } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ | ||
750 | arr[1] = cmd[2]; /*sanity */ | ||
751 | arr[3] = inquiry_evpd_b1(&arr[4]); | ||
743 | } else { | 752 | } else { |
744 | /* Illegal request, invalid field in cdb */ | 753 | /* Illegal request, invalid field in cdb */ |
745 | mk_sense_buffer(devip, ILLEGAL_REQUEST, | 754 | mk_sense_buffer(devip, ILLEGAL_REQUEST, |
@@ -878,8 +887,8 @@ static int resp_readcap(struct scsi_cmnd * scp, | |||
878 | arr[2] = 0xff; | 887 | arr[2] = 0xff; |
879 | arr[3] = 0xff; | 888 | arr[3] = 0xff; |
880 | } | 889 | } |
881 | arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 890 | arr[6] = (scsi_debug_sector_size >> 8) & 0xff; |
882 | arr[7] = SECT_SIZE_PER(target) & 0xff; | 891 | arr[7] = scsi_debug_sector_size & 0xff; |
883 | return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); | 892 | return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); |
884 | } | 893 | } |
885 | 894 | ||
@@ -902,10 +911,10 @@ static int resp_readcap16(struct scsi_cmnd * scp, | |||
902 | capac = sdebug_capacity - 1; | 911 | capac = sdebug_capacity - 1; |
903 | for (k = 0; k < 8; ++k, capac >>= 8) | 912 | for (k = 0; k < 8; ++k, capac >>= 8) |
904 | arr[7 - k] = capac & 0xff; | 913 | arr[7 - k] = capac & 0xff; |
905 | arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; | 914 | arr[8] = (scsi_debug_sector_size >> 24) & 0xff; |
906 | arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; | 915 | arr[9] = (scsi_debug_sector_size >> 16) & 0xff; |
907 | arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 916 | arr[10] = (scsi_debug_sector_size >> 8) & 0xff; |
908 | arr[11] = SECT_SIZE_PER(target) & 0xff; | 917 | arr[11] = scsi_debug_sector_size & 0xff; |
909 | return fill_from_dev_buffer(scp, arr, | 918 | return fill_from_dev_buffer(scp, arr, |
910 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); | 919 | min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); |
911 | } | 920 | } |
@@ -1019,20 +1028,20 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) | |||
1019 | 1028 | ||
1020 | static int resp_format_pg(unsigned char * p, int pcontrol, int target) | 1029 | static int resp_format_pg(unsigned char * p, int pcontrol, int target) |
1021 | { /* Format device page for mode_sense */ | 1030 | { /* Format device page for mode_sense */ |
1022 | unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, | 1031 | unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, |
1023 | 0, 0, 0, 0, 0, 0, 0, 0, | 1032 | 0, 0, 0, 0, 0, 0, 0, 0, |
1024 | 0, 0, 0, 0, 0x40, 0, 0, 0}; | 1033 | 0, 0, 0, 0, 0x40, 0, 0, 0}; |
1025 | 1034 | ||
1026 | memcpy(p, format_pg, sizeof(format_pg)); | 1035 | memcpy(p, format_pg, sizeof(format_pg)); |
1027 | p[10] = (sdebug_sectors_per >> 8) & 0xff; | 1036 | p[10] = (sdebug_sectors_per >> 8) & 0xff; |
1028 | p[11] = sdebug_sectors_per & 0xff; | 1037 | p[11] = sdebug_sectors_per & 0xff; |
1029 | p[12] = (SECT_SIZE >> 8) & 0xff; | 1038 | p[12] = (scsi_debug_sector_size >> 8) & 0xff; |
1030 | p[13] = SECT_SIZE & 0xff; | 1039 | p[13] = scsi_debug_sector_size & 0xff; |
1031 | if (DEV_REMOVEABLE(target)) | 1040 | if (DEV_REMOVEABLE(target)) |
1032 | p[20] |= 0x20; /* should agree with INQUIRY */ | 1041 | p[20] |= 0x20; /* should agree with INQUIRY */ |
1033 | if (1 == pcontrol) | 1042 | if (1 == pcontrol) |
1034 | memset(p + 2, 0, sizeof(format_pg) - 2); | 1043 | memset(p + 2, 0, sizeof(format_pg) - 2); |
1035 | return sizeof(format_pg); | 1044 | return sizeof(format_pg); |
1036 | } | 1045 | } |
1037 | 1046 | ||
1038 | static int resp_caching_pg(unsigned char * p, int pcontrol, int target) | 1047 | static int resp_caching_pg(unsigned char * p, int pcontrol, int target) |
@@ -1206,8 +1215,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, | |||
1206 | ap[2] = (sdebug_capacity >> 8) & 0xff; | 1215 | ap[2] = (sdebug_capacity >> 8) & 0xff; |
1207 | ap[3] = sdebug_capacity & 0xff; | 1216 | ap[3] = sdebug_capacity & 0xff; |
1208 | } | 1217 | } |
1209 | ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 1218 | ap[6] = (scsi_debug_sector_size >> 8) & 0xff; |
1210 | ap[7] = SECT_SIZE_PER(target) & 0xff; | 1219 | ap[7] = scsi_debug_sector_size & 0xff; |
1211 | offset += bd_len; | 1220 | offset += bd_len; |
1212 | ap = arr + offset; | 1221 | ap = arr + offset; |
1213 | } else if (16 == bd_len) { | 1222 | } else if (16 == bd_len) { |
@@ -1215,10 +1224,10 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, | |||
1215 | 1224 | ||
1216 | for (k = 0; k < 8; ++k, capac >>= 8) | 1225 | for (k = 0; k < 8; ++k, capac >>= 8) |
1217 | ap[7 - k] = capac & 0xff; | 1226 | ap[7 - k] = capac & 0xff; |
1218 | ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; | 1227 | ap[12] = (scsi_debug_sector_size >> 24) & 0xff; |
1219 | ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; | 1228 | ap[13] = (scsi_debug_sector_size >> 16) & 0xff; |
1220 | ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; | 1229 | ap[14] = (scsi_debug_sector_size >> 8) & 0xff; |
1221 | ap[15] = SECT_SIZE_PER(target) & 0xff; | 1230 | ap[15] = scsi_debug_sector_size & 0xff; |
1222 | offset += bd_len; | 1231 | offset += bd_len; |
1223 | ap = arr + offset; | 1232 | ap = arr + offset; |
1224 | } | 1233 | } |
@@ -1519,10 +1528,10 @@ static int do_device_access(struct scsi_cmnd *scmd, | |||
1519 | if (block + num > sdebug_store_sectors) | 1528 | if (block + num > sdebug_store_sectors) |
1520 | rest = block + num - sdebug_store_sectors; | 1529 | rest = block + num - sdebug_store_sectors; |
1521 | 1530 | ||
1522 | ret = func(scmd, fake_storep + (block * SECT_SIZE), | 1531 | ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), |
1523 | (num - rest) * SECT_SIZE); | 1532 | (num - rest) * scsi_debug_sector_size); |
1524 | if (!ret && rest) | 1533 | if (!ret && rest) |
1525 | ret = func(scmd, fake_storep, rest * SECT_SIZE); | 1534 | ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); |
1526 | 1535 | ||
1527 | return ret; | 1536 | return ret; |
1528 | } | 1537 | } |
@@ -1575,10 +1584,10 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, | |||
1575 | write_unlock_irqrestore(&atomic_rw, iflags); | 1584 | write_unlock_irqrestore(&atomic_rw, iflags); |
1576 | if (-1 == ret) | 1585 | if (-1 == ret) |
1577 | return (DID_ERROR << 16); | 1586 | return (DID_ERROR << 16); |
1578 | else if ((ret < (num * SECT_SIZE)) && | 1587 | else if ((ret < (num * scsi_debug_sector_size)) && |
1579 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) | 1588 | (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) |
1580 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " | 1589 | printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " |
1581 | " IO sent=%d bytes\n", num * SECT_SIZE, ret); | 1590 | " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); |
1582 | return 0; | 1591 | return 0; |
1583 | } | 1592 | } |
1584 | 1593 | ||
@@ -2085,6 +2094,7 @@ module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); | |||
2085 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); | 2094 | module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); |
2086 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, | 2095 | module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, |
2087 | S_IRUGO | S_IWUSR); | 2096 | S_IRUGO | S_IWUSR); |
2097 | module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); | ||
2088 | 2098 | ||
2089 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); | 2099 | MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); |
2090 | MODULE_DESCRIPTION("SCSI debug adapter driver"); | 2100 | MODULE_DESCRIPTION("SCSI debug adapter driver"); |
@@ -2106,6 +2116,7 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); | |||
2106 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); | 2116 | MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); |
2107 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); | 2117 | MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); |
2108 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); | 2118 | MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); |
2119 | MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); | ||
2109 | 2120 | ||
2110 | 2121 | ||
2111 | static char sdebug_info[256]; | 2122 | static char sdebug_info[256]; |
@@ -2158,8 +2169,9 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta | |||
2158 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, | 2169 | scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, |
2159 | scsi_debug_cmnd_count, scsi_debug_delay, | 2170 | scsi_debug_cmnd_count, scsi_debug_delay, |
2160 | scsi_debug_max_luns, scsi_debug_scsi_level, | 2171 | scsi_debug_max_luns, scsi_debug_scsi_level, |
2161 | SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, | 2172 | scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, |
2162 | num_aborts, num_dev_resets, num_bus_resets, num_host_resets); | 2173 | sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, |
2174 | num_host_resets); | ||
2163 | if (pos < offset) { | 2175 | if (pos < offset) { |
2164 | len = 0; | 2176 | len = 0; |
2165 | begin = pos; | 2177 | begin = pos; |
@@ -2434,6 +2446,12 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, | |||
2434 | DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, | 2446 | DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, |
2435 | sdebug_vpd_use_hostno_store); | 2447 | sdebug_vpd_use_hostno_store); |
2436 | 2448 | ||
2449 | static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) | ||
2450 | { | ||
2451 | return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); | ||
2452 | } | ||
2453 | DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); | ||
2454 | |||
2437 | /* Note: The following function creates attribute files in the | 2455 | /* Note: The following function creates attribute files in the |
2438 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these | 2456 | /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these |
2439 | files (over those found in the /sys/module/scsi_debug/parameters | 2457 | files (over those found in the /sys/module/scsi_debug/parameters |
@@ -2459,11 +2477,13 @@ static int do_create_driverfs_files(void) | |||
2459 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2477 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
2460 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2478 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
2461 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2479 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2480 | ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | ||
2462 | return ret; | 2481 | return ret; |
2463 | } | 2482 | } |
2464 | 2483 | ||
2465 | static void do_remove_driverfs_files(void) | 2484 | static void do_remove_driverfs_files(void) |
2466 | { | 2485 | { |
2486 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); | ||
2467 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); | 2487 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); |
2468 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); | 2488 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); |
2469 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); | 2489 | driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); |
@@ -2499,10 +2519,22 @@ static int __init scsi_debug_init(void) | |||
2499 | int k; | 2519 | int k; |
2500 | int ret; | 2520 | int ret; |
2501 | 2521 | ||
2522 | switch (scsi_debug_sector_size) { | ||
2523 | case 512: | ||
2524 | case 1024: | ||
2525 | case 2048: | ||
2526 | case 4096: | ||
2527 | break; | ||
2528 | default: | ||
2529 | printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", | ||
2530 | scsi_debug_sector_size); | ||
2531 | return -EINVAL; | ||
2532 | } | ||
2533 | |||
2502 | if (scsi_debug_dev_size_mb < 1) | 2534 | if (scsi_debug_dev_size_mb < 1) |
2503 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ | 2535 | scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ |
2504 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; | 2536 | sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; |
2505 | sdebug_store_sectors = sz / SECT_SIZE; | 2537 | sdebug_store_sectors = sz / scsi_debug_sector_size; |
2506 | sdebug_capacity = get_sdebug_capacity(); | 2538 | sdebug_capacity = get_sdebug_capacity(); |
2507 | 2539 | ||
2508 | /* play around with geometry, don't waste too much on track 0 */ | 2540 | /* play around with geometry, don't waste too much on track 0 */ |
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index eaf5a8add1ba..006a95916f72 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c | |||
@@ -298,6 +298,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, | |||
298 | */ | 298 | */ |
299 | static int scsi_check_sense(struct scsi_cmnd *scmd) | 299 | static int scsi_check_sense(struct scsi_cmnd *scmd) |
300 | { | 300 | { |
301 | struct scsi_device *sdev = scmd->device; | ||
301 | struct scsi_sense_hdr sshdr; | 302 | struct scsi_sense_hdr sshdr; |
302 | 303 | ||
303 | if (! scsi_command_normalize_sense(scmd, &sshdr)) | 304 | if (! scsi_command_normalize_sense(scmd, &sshdr)) |
@@ -306,6 +307,16 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) | |||
306 | if (scsi_sense_is_deferred(&sshdr)) | 307 | if (scsi_sense_is_deferred(&sshdr)) |
307 | return NEEDS_RETRY; | 308 | return NEEDS_RETRY; |
308 | 309 | ||
310 | if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && | ||
311 | sdev->scsi_dh_data->scsi_dh->check_sense) { | ||
312 | int rc; | ||
313 | |||
314 | rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); | ||
315 | if (rc != SCSI_RETURN_NOT_HANDLED) | ||
316 | return rc; | ||
317 | /* handler does not care. Drop down to default handling */ | ||
318 | } | ||
319 | |||
309 | /* | 320 | /* |
310 | * Previous logic looked for FILEMARK, EOM or ILI which are | 321 | * Previous logic looked for FILEMARK, EOM or ILI which are |
311 | * mainly associated with tapes and returned SUCCESS. | 322 | * mainly associated with tapes and returned SUCCESS. |
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index cbf55d59a54c..88d1b5f44e59 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -65,7 +65,7 @@ static struct scsi_host_sg_pool scsi_sg_pools[] = { | |||
65 | }; | 65 | }; |
66 | #undef SP | 66 | #undef SP |
67 | 67 | ||
68 | static struct kmem_cache *scsi_bidi_sdb_cache; | 68 | static struct kmem_cache *scsi_sdb_cache; |
69 | 69 | ||
70 | static void scsi_run_queue(struct request_queue *q); | 70 | static void scsi_run_queue(struct request_queue *q); |
71 | 71 | ||
@@ -784,7 +784,7 @@ void scsi_release_buffers(struct scsi_cmnd *cmd) | |||
784 | struct scsi_data_buffer *bidi_sdb = | 784 | struct scsi_data_buffer *bidi_sdb = |
785 | cmd->request->next_rq->special; | 785 | cmd->request->next_rq->special; |
786 | scsi_free_sgtable(bidi_sdb); | 786 | scsi_free_sgtable(bidi_sdb); |
787 | kmem_cache_free(scsi_bidi_sdb_cache, bidi_sdb); | 787 | kmem_cache_free(scsi_sdb_cache, bidi_sdb); |
788 | cmd->request->next_rq->special = NULL; | 788 | cmd->request->next_rq->special = NULL; |
789 | } | 789 | } |
790 | } | 790 | } |
@@ -1059,7 +1059,7 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) | |||
1059 | 1059 | ||
1060 | if (blk_bidi_rq(cmd->request)) { | 1060 | if (blk_bidi_rq(cmd->request)) { |
1061 | struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( | 1061 | struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( |
1062 | scsi_bidi_sdb_cache, GFP_ATOMIC); | 1062 | scsi_sdb_cache, GFP_ATOMIC); |
1063 | if (!bidi_sdb) { | 1063 | if (!bidi_sdb) { |
1064 | error = BLKPREP_DEFER; | 1064 | error = BLKPREP_DEFER; |
1065 | goto err_exit; | 1065 | goto err_exit; |
@@ -1169,6 +1169,14 @@ int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) | |||
1169 | 1169 | ||
1170 | if (ret != BLKPREP_OK) | 1170 | if (ret != BLKPREP_OK) |
1171 | return ret; | 1171 | return ret; |
1172 | |||
1173 | if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh | ||
1174 | && sdev->scsi_dh_data->scsi_dh->prep_fn)) { | ||
1175 | ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req); | ||
1176 | if (ret != BLKPREP_OK) | ||
1177 | return ret; | ||
1178 | } | ||
1179 | |||
1172 | /* | 1180 | /* |
1173 | * Filesystem requests must transfer data. | 1181 | * Filesystem requests must transfer data. |
1174 | */ | 1182 | */ |
@@ -1329,7 +1337,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q, | |||
1329 | printk("scsi%d unblocking host at zero depth\n", | 1337 | printk("scsi%d unblocking host at zero depth\n", |
1330 | shost->host_no)); | 1338 | shost->host_no)); |
1331 | } else { | 1339 | } else { |
1332 | blk_plug_device(q); | ||
1333 | return 0; | 1340 | return 0; |
1334 | } | 1341 | } |
1335 | } | 1342 | } |
@@ -1693,11 +1700,11 @@ int __init scsi_init_queue(void) | |||
1693 | return -ENOMEM; | 1700 | return -ENOMEM; |
1694 | } | 1701 | } |
1695 | 1702 | ||
1696 | scsi_bidi_sdb_cache = kmem_cache_create("scsi_bidi_sdb", | 1703 | scsi_sdb_cache = kmem_cache_create("scsi_data_buffer", |
1697 | sizeof(struct scsi_data_buffer), | 1704 | sizeof(struct scsi_data_buffer), |
1698 | 0, 0, NULL); | 1705 | 0, 0, NULL); |
1699 | if (!scsi_bidi_sdb_cache) { | 1706 | if (!scsi_sdb_cache) { |
1700 | printk(KERN_ERR "SCSI: can't init scsi bidi sdb cache\n"); | 1707 | printk(KERN_ERR "SCSI: can't init scsi sdb cache\n"); |
1701 | goto cleanup_io_context; | 1708 | goto cleanup_io_context; |
1702 | } | 1709 | } |
1703 | 1710 | ||
@@ -1710,7 +1717,7 @@ int __init scsi_init_queue(void) | |||
1710 | if (!sgp->slab) { | 1717 | if (!sgp->slab) { |
1711 | printk(KERN_ERR "SCSI: can't init sg slab %s\n", | 1718 | printk(KERN_ERR "SCSI: can't init sg slab %s\n", |
1712 | sgp->name); | 1719 | sgp->name); |
1713 | goto cleanup_bidi_sdb; | 1720 | goto cleanup_sdb; |
1714 | } | 1721 | } |
1715 | 1722 | ||
1716 | sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, | 1723 | sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, |
@@ -1718,13 +1725,13 @@ int __init scsi_init_queue(void) | |||
1718 | if (!sgp->pool) { | 1725 | if (!sgp->pool) { |
1719 | printk(KERN_ERR "SCSI: can't init sg mempool %s\n", | 1726 | printk(KERN_ERR "SCSI: can't init sg mempool %s\n", |
1720 | sgp->name); | 1727 | sgp->name); |
1721 | goto cleanup_bidi_sdb; | 1728 | goto cleanup_sdb; |
1722 | } | 1729 | } |
1723 | } | 1730 | } |
1724 | 1731 | ||
1725 | return 0; | 1732 | return 0; |
1726 | 1733 | ||
1727 | cleanup_bidi_sdb: | 1734 | cleanup_sdb: |
1728 | for (i = 0; i < SG_MEMPOOL_NR; i++) { | 1735 | for (i = 0; i < SG_MEMPOOL_NR; i++) { |
1729 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; | 1736 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; |
1730 | if (sgp->pool) | 1737 | if (sgp->pool) |
@@ -1732,7 +1739,7 @@ cleanup_bidi_sdb: | |||
1732 | if (sgp->slab) | 1739 | if (sgp->slab) |
1733 | kmem_cache_destroy(sgp->slab); | 1740 | kmem_cache_destroy(sgp->slab); |
1734 | } | 1741 | } |
1735 | kmem_cache_destroy(scsi_bidi_sdb_cache); | 1742 | kmem_cache_destroy(scsi_sdb_cache); |
1736 | cleanup_io_context: | 1743 | cleanup_io_context: |
1737 | kmem_cache_destroy(scsi_io_context_cache); | 1744 | kmem_cache_destroy(scsi_io_context_cache); |
1738 | 1745 | ||
@@ -1744,7 +1751,7 @@ void scsi_exit_queue(void) | |||
1744 | int i; | 1751 | int i; |
1745 | 1752 | ||
1746 | kmem_cache_destroy(scsi_io_context_cache); | 1753 | kmem_cache_destroy(scsi_io_context_cache); |
1747 | kmem_cache_destroy(scsi_bidi_sdb_cache); | 1754 | kmem_cache_destroy(scsi_sdb_cache); |
1748 | 1755 | ||
1749 | for (i = 0; i < SG_MEMPOOL_NR; i++) { | 1756 | for (i = 0; i < SG_MEMPOOL_NR; i++) { |
1750 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; | 1757 | struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index a00eee6f7be9..196fe3af0d5e 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -346,7 +346,7 @@ static void scsi_target_dev_release(struct device *dev) | |||
346 | put_device(parent); | 346 | put_device(parent); |
347 | } | 347 | } |
348 | 348 | ||
349 | struct device_type scsi_target_type = { | 349 | static struct device_type scsi_target_type = { |
350 | .name = "scsi_target", | 350 | .name = "scsi_target", |
351 | .release = scsi_target_dev_release, | 351 | .release = scsi_target_dev_release, |
352 | }; | 352 | }; |
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 93d2b6714453..b6e561059779 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c | |||
@@ -439,6 +439,7 @@ struct bus_type scsi_bus_type = { | |||
439 | .resume = scsi_bus_resume, | 439 | .resume = scsi_bus_resume, |
440 | .remove = scsi_bus_remove, | 440 | .remove = scsi_bus_remove, |
441 | }; | 441 | }; |
442 | EXPORT_SYMBOL_GPL(scsi_bus_type); | ||
442 | 443 | ||
443 | int scsi_sysfs_register(void) | 444 | int scsi_sysfs_register(void) |
444 | { | 445 | { |
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 65d1737eb664..3af7cbcc5c5d 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -30,10 +30,11 @@ | |||
30 | #include <scsi/scsi_transport_iscsi.h> | 30 | #include <scsi/scsi_transport_iscsi.h> |
31 | #include <scsi/iscsi_if.h> | 31 | #include <scsi/iscsi_if.h> |
32 | 32 | ||
33 | #define ISCSI_SESSION_ATTRS 19 | 33 | #define ISCSI_SESSION_ATTRS 21 |
34 | #define ISCSI_CONN_ATTRS 13 | 34 | #define ISCSI_CONN_ATTRS 13 |
35 | #define ISCSI_HOST_ATTRS 4 | 35 | #define ISCSI_HOST_ATTRS 4 |
36 | #define ISCSI_TRANSPORT_VERSION "2.0-869" | 36 | |
37 | #define ISCSI_TRANSPORT_VERSION "2.0-870" | ||
37 | 38 | ||
38 | struct iscsi_internal { | 39 | struct iscsi_internal { |
39 | int daemon_pid; | 40 | int daemon_pid; |
@@ -101,16 +102,10 @@ show_transport_##name(struct device *dev, \ | |||
101 | static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); | 102 | static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); |
102 | 103 | ||
103 | show_transport_attr(caps, "0x%x"); | 104 | show_transport_attr(caps, "0x%x"); |
104 | show_transport_attr(max_lun, "%d"); | ||
105 | show_transport_attr(max_conn, "%d"); | ||
106 | show_transport_attr(max_cmd_len, "%d"); | ||
107 | 105 | ||
108 | static struct attribute *iscsi_transport_attrs[] = { | 106 | static struct attribute *iscsi_transport_attrs[] = { |
109 | &dev_attr_handle.attr, | 107 | &dev_attr_handle.attr, |
110 | &dev_attr_caps.attr, | 108 | &dev_attr_caps.attr, |
111 | &dev_attr_max_lun.attr, | ||
112 | &dev_attr_max_conn.attr, | ||
113 | &dev_attr_max_cmd_len.attr, | ||
114 | NULL, | 109 | NULL, |
115 | }; | 110 | }; |
116 | 111 | ||
@@ -118,18 +113,139 @@ static struct attribute_group iscsi_transport_group = { | |||
118 | .attrs = iscsi_transport_attrs, | 113 | .attrs = iscsi_transport_attrs, |
119 | }; | 114 | }; |
120 | 115 | ||
116 | /* | ||
117 | * iSCSI endpoint attrs | ||
118 | */ | ||
119 | #define iscsi_dev_to_endpoint(_dev) \ | ||
120 | container_of(_dev, struct iscsi_endpoint, dev) | ||
121 | |||
122 | #define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \ | ||
123 | struct device_attribute dev_attr_##_prefix##_##_name = \ | ||
124 | __ATTR(_name,_mode,_show,_store) | ||
125 | |||
126 | static void iscsi_endpoint_release(struct device *dev) | ||
127 | { | ||
128 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
129 | kfree(ep); | ||
130 | } | ||
131 | |||
132 | static struct class iscsi_endpoint_class = { | ||
133 | .name = "iscsi_endpoint", | ||
134 | .dev_release = iscsi_endpoint_release, | ||
135 | }; | ||
136 | |||
137 | static ssize_t | ||
138 | show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) | ||
139 | { | ||
140 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
141 | return sprintf(buf, "%u\n", ep->id); | ||
142 | } | ||
143 | static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); | ||
144 | |||
145 | static struct attribute *iscsi_endpoint_attrs[] = { | ||
146 | &dev_attr_ep_handle.attr, | ||
147 | NULL, | ||
148 | }; | ||
149 | |||
150 | static struct attribute_group iscsi_endpoint_group = { | ||
151 | .attrs = iscsi_endpoint_attrs, | ||
152 | }; | ||
121 | 153 | ||
154 | #define ISCSI_MAX_EPID -1 | ||
155 | |||
156 | static int iscsi_match_epid(struct device *dev, void *data) | ||
157 | { | ||
158 | struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); | ||
159 | unsigned int *epid = (unsigned int *) data; | ||
160 | |||
161 | return *epid == ep->id; | ||
162 | } | ||
163 | |||
164 | struct iscsi_endpoint * | ||
165 | iscsi_create_endpoint(int dd_size) | ||
166 | { | ||
167 | struct device *dev; | ||
168 | struct iscsi_endpoint *ep; | ||
169 | unsigned int id; | ||
170 | int err; | ||
171 | |||
172 | for (id = 1; id < ISCSI_MAX_EPID; id++) { | ||
173 | dev = class_find_device(&iscsi_endpoint_class, &id, | ||
174 | iscsi_match_epid); | ||
175 | if (!dev) | ||
176 | break; | ||
177 | } | ||
178 | if (id == ISCSI_MAX_EPID) { | ||
179 | printk(KERN_ERR "Too many connections. Max supported %u\n", | ||
180 | ISCSI_MAX_EPID - 1); | ||
181 | return NULL; | ||
182 | } | ||
183 | |||
184 | ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL); | ||
185 | if (!ep) | ||
186 | return NULL; | ||
187 | |||
188 | ep->id = id; | ||
189 | ep->dev.class = &iscsi_endpoint_class; | ||
190 | snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%u", id); | ||
191 | err = device_register(&ep->dev); | ||
192 | if (err) | ||
193 | goto free_ep; | ||
194 | |||
195 | err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group); | ||
196 | if (err) | ||
197 | goto unregister_dev; | ||
198 | |||
199 | if (dd_size) | ||
200 | ep->dd_data = &ep[1]; | ||
201 | return ep; | ||
202 | |||
203 | unregister_dev: | ||
204 | device_unregister(&ep->dev); | ||
205 | return NULL; | ||
206 | |||
207 | free_ep: | ||
208 | kfree(ep); | ||
209 | return NULL; | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(iscsi_create_endpoint); | ||
212 | |||
213 | void iscsi_destroy_endpoint(struct iscsi_endpoint *ep) | ||
214 | { | ||
215 | sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group); | ||
216 | device_unregister(&ep->dev); | ||
217 | } | ||
218 | EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint); | ||
219 | |||
220 | struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) | ||
221 | { | ||
222 | struct iscsi_endpoint *ep; | ||
223 | struct device *dev; | ||
224 | |||
225 | dev = class_find_device(&iscsi_endpoint_class, &handle, | ||
226 | iscsi_match_epid); | ||
227 | if (!dev) | ||
228 | return NULL; | ||
229 | |||
230 | ep = iscsi_dev_to_endpoint(dev); | ||
231 | /* | ||
232 | * we can drop this now because the interface will prevent | ||
233 | * removals and lookups from racing. | ||
234 | */ | ||
235 | put_device(dev); | ||
236 | return ep; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); | ||
122 | 239 | ||
123 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, | 240 | static int iscsi_setup_host(struct transport_container *tc, struct device *dev, |
124 | struct device *cdev) | 241 | struct device *cdev) |
125 | { | 242 | { |
126 | struct Scsi_Host *shost = dev_to_shost(dev); | 243 | struct Scsi_Host *shost = dev_to_shost(dev); |
127 | struct iscsi_host *ihost = shost->shost_data; | 244 | struct iscsi_cls_host *ihost = shost->shost_data; |
128 | 245 | ||
129 | memset(ihost, 0, sizeof(*ihost)); | 246 | memset(ihost, 0, sizeof(*ihost)); |
130 | INIT_LIST_HEAD(&ihost->sessions); | ||
131 | mutex_init(&ihost->mutex); | ||
132 | atomic_set(&ihost->nr_scans, 0); | 247 | atomic_set(&ihost->nr_scans, 0); |
248 | mutex_init(&ihost->mutex); | ||
133 | 249 | ||
134 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", | 250 | snprintf(ihost->scan_workq_name, KOBJ_NAME_LEN, "iscsi_scan_%d", |
135 | shost->host_no); | 251 | shost->host_no); |
@@ -144,7 +260,7 @@ static int iscsi_remove_host(struct transport_container *tc, struct device *dev, | |||
144 | struct device *cdev) | 260 | struct device *cdev) |
145 | { | 261 | { |
146 | struct Scsi_Host *shost = dev_to_shost(dev); | 262 | struct Scsi_Host *shost = dev_to_shost(dev); |
147 | struct iscsi_host *ihost = shost->shost_data; | 263 | struct iscsi_cls_host *ihost = shost->shost_data; |
148 | 264 | ||
149 | destroy_workqueue(ihost->scan_workq); | 265 | destroy_workqueue(ihost->scan_workq); |
150 | return 0; | 266 | return 0; |
@@ -287,6 +403,24 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
287 | return dev->release == iscsi_session_release; | 403 | return dev->release == iscsi_session_release; |
288 | } | 404 | } |
289 | 405 | ||
406 | static int iscsi_iter_session_fn(struct device *dev, void *data) | ||
407 | { | ||
408 | void (* fn) (struct iscsi_cls_session *) = data; | ||
409 | |||
410 | if (!iscsi_is_session_dev(dev)) | ||
411 | return 0; | ||
412 | fn(iscsi_dev_to_session(dev)); | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | void iscsi_host_for_each_session(struct Scsi_Host *shost, | ||
417 | void (*fn)(struct iscsi_cls_session *)) | ||
418 | { | ||
419 | device_for_each_child(&shost->shost_gendev, fn, | ||
420 | iscsi_iter_session_fn); | ||
421 | } | ||
422 | EXPORT_SYMBOL_GPL(iscsi_host_for_each_session); | ||
423 | |||
290 | /** | 424 | /** |
291 | * iscsi_scan_finished - helper to report when running scans are done | 425 | * iscsi_scan_finished - helper to report when running scans are done |
292 | * @shost: scsi host | 426 | * @shost: scsi host |
@@ -297,7 +431,7 @@ static int iscsi_is_session_dev(const struct device *dev) | |||
297 | */ | 431 | */ |
298 | int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) | 432 | int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) |
299 | { | 433 | { |
300 | struct iscsi_host *ihost = shost->shost_data; | 434 | struct iscsi_cls_host *ihost = shost->shost_data; |
301 | /* | 435 | /* |
302 | * qla4xxx will have kicked off some session unblocks before calling | 436 | * qla4xxx will have kicked off some session unblocks before calling |
303 | * scsi_scan_host, so just wait for them to complete. | 437 | * scsi_scan_host, so just wait for them to complete. |
@@ -306,42 +440,76 @@ int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) | |||
306 | } | 440 | } |
307 | EXPORT_SYMBOL_GPL(iscsi_scan_finished); | 441 | EXPORT_SYMBOL_GPL(iscsi_scan_finished); |
308 | 442 | ||
309 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | 443 | struct iscsi_scan_data { |
310 | uint id, uint lun) | 444 | unsigned int channel; |
445 | unsigned int id; | ||
446 | unsigned int lun; | ||
447 | }; | ||
448 | |||
449 | static int iscsi_user_scan_session(struct device *dev, void *data) | ||
311 | { | 450 | { |
312 | struct iscsi_host *ihost = shost->shost_data; | 451 | struct iscsi_scan_data *scan_data = data; |
313 | struct iscsi_cls_session *session; | 452 | struct iscsi_cls_session *session; |
453 | struct Scsi_Host *shost; | ||
454 | struct iscsi_cls_host *ihost; | ||
455 | unsigned long flags; | ||
456 | unsigned int id; | ||
457 | |||
458 | if (!iscsi_is_session_dev(dev)) | ||
459 | return 0; | ||
460 | |||
461 | session = iscsi_dev_to_session(dev); | ||
462 | shost = iscsi_session_to_shost(session); | ||
463 | ihost = shost->shost_data; | ||
314 | 464 | ||
315 | mutex_lock(&ihost->mutex); | 465 | mutex_lock(&ihost->mutex); |
316 | list_for_each_entry(session, &ihost->sessions, host_list) { | 466 | spin_lock_irqsave(&session->lock, flags); |
317 | if ((channel == SCAN_WILD_CARD || channel == 0) && | 467 | if (session->state != ISCSI_SESSION_LOGGED_IN) { |
318 | (id == SCAN_WILD_CARD || id == session->target_id)) | 468 | spin_unlock_irqrestore(&session->lock, flags); |
319 | scsi_scan_target(&session->dev, 0, | 469 | mutex_unlock(&ihost->mutex); |
320 | session->target_id, lun, 1); | 470 | return 0; |
321 | } | 471 | } |
322 | mutex_unlock(&ihost->mutex); | 472 | id = session->target_id; |
473 | spin_unlock_irqrestore(&session->lock, flags); | ||
323 | 474 | ||
475 | if (id != ISCSI_MAX_TARGET) { | ||
476 | if ((scan_data->channel == SCAN_WILD_CARD || | ||
477 | scan_data->channel == 0) && | ||
478 | (scan_data->id == SCAN_WILD_CARD || | ||
479 | scan_data->id == id)) | ||
480 | scsi_scan_target(&session->dev, 0, id, | ||
481 | scan_data->lun, 1); | ||
482 | } | ||
483 | mutex_unlock(&ihost->mutex); | ||
324 | return 0; | 484 | return 0; |
325 | } | 485 | } |
326 | 486 | ||
487 | static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, | ||
488 | uint id, uint lun) | ||
489 | { | ||
490 | struct iscsi_scan_data scan_data; | ||
491 | |||
492 | scan_data.channel = channel; | ||
493 | scan_data.id = id; | ||
494 | scan_data.lun = lun; | ||
495 | |||
496 | return device_for_each_child(&shost->shost_gendev, &scan_data, | ||
497 | iscsi_user_scan_session); | ||
498 | } | ||
499 | |||
327 | static void iscsi_scan_session(struct work_struct *work) | 500 | static void iscsi_scan_session(struct work_struct *work) |
328 | { | 501 | { |
329 | struct iscsi_cls_session *session = | 502 | struct iscsi_cls_session *session = |
330 | container_of(work, struct iscsi_cls_session, scan_work); | 503 | container_of(work, struct iscsi_cls_session, scan_work); |
331 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 504 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
332 | struct iscsi_host *ihost = shost->shost_data; | 505 | struct iscsi_cls_host *ihost = shost->shost_data; |
333 | unsigned long flags; | 506 | struct iscsi_scan_data scan_data; |
334 | 507 | ||
335 | spin_lock_irqsave(&session->lock, flags); | 508 | scan_data.channel = 0; |
336 | if (session->state != ISCSI_SESSION_LOGGED_IN) { | 509 | scan_data.id = SCAN_WILD_CARD; |
337 | spin_unlock_irqrestore(&session->lock, flags); | 510 | scan_data.lun = SCAN_WILD_CARD; |
338 | goto done; | ||
339 | } | ||
340 | spin_unlock_irqrestore(&session->lock, flags); | ||
341 | 511 | ||
342 | scsi_scan_target(&session->dev, 0, session->target_id, | 512 | iscsi_user_scan_session(&session->dev, &scan_data); |
343 | SCAN_WILD_CARD, 1); | ||
344 | done: | ||
345 | atomic_dec(&ihost->nr_scans); | 513 | atomic_dec(&ihost->nr_scans); |
346 | } | 514 | } |
347 | 515 | ||
@@ -381,7 +549,7 @@ static void __iscsi_unblock_session(struct work_struct *work) | |||
381 | container_of(work, struct iscsi_cls_session, | 549 | container_of(work, struct iscsi_cls_session, |
382 | unblock_work); | 550 | unblock_work); |
383 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 551 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
384 | struct iscsi_host *ihost = shost->shost_data; | 552 | struct iscsi_cls_host *ihost = shost->shost_data; |
385 | unsigned long flags; | 553 | unsigned long flags; |
386 | 554 | ||
387 | /* | 555 | /* |
@@ -449,15 +617,19 @@ static void __iscsi_unbind_session(struct work_struct *work) | |||
449 | container_of(work, struct iscsi_cls_session, | 617 | container_of(work, struct iscsi_cls_session, |
450 | unbind_work); | 618 | unbind_work); |
451 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 619 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
452 | struct iscsi_host *ihost = shost->shost_data; | 620 | struct iscsi_cls_host *ihost = shost->shost_data; |
621 | unsigned long flags; | ||
453 | 622 | ||
454 | /* Prevent new scans and make sure scanning is not in progress */ | 623 | /* Prevent new scans and make sure scanning is not in progress */ |
455 | mutex_lock(&ihost->mutex); | 624 | mutex_lock(&ihost->mutex); |
456 | if (list_empty(&session->host_list)) { | 625 | spin_lock_irqsave(&session->lock, flags); |
626 | if (session->target_id == ISCSI_MAX_TARGET) { | ||
627 | spin_unlock_irqrestore(&session->lock, flags); | ||
457 | mutex_unlock(&ihost->mutex); | 628 | mutex_unlock(&ihost->mutex); |
458 | return; | 629 | return; |
459 | } | 630 | } |
460 | list_del_init(&session->host_list); | 631 | session->target_id = ISCSI_MAX_TARGET; |
632 | spin_unlock_irqrestore(&session->lock, flags); | ||
461 | mutex_unlock(&ihost->mutex); | 633 | mutex_unlock(&ihost->mutex); |
462 | 634 | ||
463 | scsi_remove_target(&session->dev); | 635 | scsi_remove_target(&session->dev); |
@@ -467,18 +639,18 @@ static void __iscsi_unbind_session(struct work_struct *work) | |||
467 | static int iscsi_unbind_session(struct iscsi_cls_session *session) | 639 | static int iscsi_unbind_session(struct iscsi_cls_session *session) |
468 | { | 640 | { |
469 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 641 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
470 | struct iscsi_host *ihost = shost->shost_data; | 642 | struct iscsi_cls_host *ihost = shost->shost_data; |
471 | 643 | ||
472 | return queue_work(ihost->scan_workq, &session->unbind_work); | 644 | return queue_work(ihost->scan_workq, &session->unbind_work); |
473 | } | 645 | } |
474 | 646 | ||
475 | struct iscsi_cls_session * | 647 | struct iscsi_cls_session * |
476 | iscsi_alloc_session(struct Scsi_Host *shost, | 648 | iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, |
477 | struct iscsi_transport *transport) | 649 | int dd_size) |
478 | { | 650 | { |
479 | struct iscsi_cls_session *session; | 651 | struct iscsi_cls_session *session; |
480 | 652 | ||
481 | session = kzalloc(sizeof(*session) + transport->sessiondata_size, | 653 | session = kzalloc(sizeof(*session) + dd_size, |
482 | GFP_KERNEL); | 654 | GFP_KERNEL); |
483 | if (!session) | 655 | if (!session) |
484 | return NULL; | 656 | return NULL; |
@@ -487,7 +659,6 @@ iscsi_alloc_session(struct Scsi_Host *shost, | |||
487 | session->recovery_tmo = 120; | 659 | session->recovery_tmo = 120; |
488 | session->state = ISCSI_SESSION_FREE; | 660 | session->state = ISCSI_SESSION_FREE; |
489 | INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); | 661 | INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); |
490 | INIT_LIST_HEAD(&session->host_list); | ||
491 | INIT_LIST_HEAD(&session->sess_list); | 662 | INIT_LIST_HEAD(&session->sess_list); |
492 | INIT_WORK(&session->unblock_work, __iscsi_unblock_session); | 663 | INIT_WORK(&session->unblock_work, __iscsi_unblock_session); |
493 | INIT_WORK(&session->block_work, __iscsi_block_session); | 664 | INIT_WORK(&session->block_work, __iscsi_block_session); |
@@ -500,22 +671,57 @@ iscsi_alloc_session(struct Scsi_Host *shost, | |||
500 | session->dev.parent = &shost->shost_gendev; | 671 | session->dev.parent = &shost->shost_gendev; |
501 | session->dev.release = iscsi_session_release; | 672 | session->dev.release = iscsi_session_release; |
502 | device_initialize(&session->dev); | 673 | device_initialize(&session->dev); |
503 | if (transport->sessiondata_size) | 674 | if (dd_size) |
504 | session->dd_data = &session[1]; | 675 | session->dd_data = &session[1]; |
505 | return session; | 676 | return session; |
506 | } | 677 | } |
507 | EXPORT_SYMBOL_GPL(iscsi_alloc_session); | 678 | EXPORT_SYMBOL_GPL(iscsi_alloc_session); |
508 | 679 | ||
680 | static int iscsi_get_next_target_id(struct device *dev, void *data) | ||
681 | { | ||
682 | struct iscsi_cls_session *session; | ||
683 | unsigned long flags; | ||
684 | int err = 0; | ||
685 | |||
686 | if (!iscsi_is_session_dev(dev)) | ||
687 | return 0; | ||
688 | |||
689 | session = iscsi_dev_to_session(dev); | ||
690 | spin_lock_irqsave(&session->lock, flags); | ||
691 | if (*((unsigned int *) data) == session->target_id) | ||
692 | err = -EEXIST; | ||
693 | spin_unlock_irqrestore(&session->lock, flags); | ||
694 | return err; | ||
695 | } | ||
696 | |||
509 | int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) | 697 | int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) |
510 | { | 698 | { |
511 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 699 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
512 | struct iscsi_host *ihost; | 700 | struct iscsi_cls_host *ihost; |
513 | unsigned long flags; | 701 | unsigned long flags; |
702 | unsigned int id = target_id; | ||
514 | int err; | 703 | int err; |
515 | 704 | ||
516 | ihost = shost->shost_data; | 705 | ihost = shost->shost_data; |
517 | session->sid = atomic_add_return(1, &iscsi_session_nr); | 706 | session->sid = atomic_add_return(1, &iscsi_session_nr); |
518 | session->target_id = target_id; | 707 | |
708 | if (id == ISCSI_MAX_TARGET) { | ||
709 | for (id = 0; id < ISCSI_MAX_TARGET; id++) { | ||
710 | err = device_for_each_child(&shost->shost_gendev, &id, | ||
711 | iscsi_get_next_target_id); | ||
712 | if (!err) | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | if (id == ISCSI_MAX_TARGET) { | ||
717 | iscsi_cls_session_printk(KERN_ERR, session, | ||
718 | "Too many iscsi targets. Max " | ||
719 | "number of targets is %d.\n", | ||
720 | ISCSI_MAX_TARGET - 1); | ||
721 | goto release_host; | ||
722 | } | ||
723 | } | ||
724 | session->target_id = id; | ||
519 | 725 | ||
520 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", | 726 | snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", |
521 | session->sid); | 727 | session->sid); |
@@ -531,10 +737,6 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) | |||
531 | list_add(&session->sess_list, &sesslist); | 737 | list_add(&session->sess_list, &sesslist); |
532 | spin_unlock_irqrestore(&sesslock, flags); | 738 | spin_unlock_irqrestore(&sesslock, flags); |
533 | 739 | ||
534 | mutex_lock(&ihost->mutex); | ||
535 | list_add(&session->host_list, &ihost->sessions); | ||
536 | mutex_unlock(&ihost->mutex); | ||
537 | |||
538 | iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); | 740 | iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); |
539 | return 0; | 741 | return 0; |
540 | 742 | ||
@@ -548,18 +750,18 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); | |||
548 | * iscsi_create_session - create iscsi class session | 750 | * iscsi_create_session - create iscsi class session |
549 | * @shost: scsi host | 751 | * @shost: scsi host |
550 | * @transport: iscsi transport | 752 | * @transport: iscsi transport |
753 | * @dd_size: private driver data size | ||
551 | * @target_id: which target | 754 | * @target_id: which target |
552 | * | 755 | * |
553 | * This can be called from a LLD or iscsi_transport. | 756 | * This can be called from a LLD or iscsi_transport. |
554 | */ | 757 | */ |
555 | struct iscsi_cls_session * | 758 | struct iscsi_cls_session * |
556 | iscsi_create_session(struct Scsi_Host *shost, | 759 | iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport, |
557 | struct iscsi_transport *transport, | 760 | int dd_size, unsigned int target_id) |
558 | unsigned int target_id) | ||
559 | { | 761 | { |
560 | struct iscsi_cls_session *session; | 762 | struct iscsi_cls_session *session; |
561 | 763 | ||
562 | session = iscsi_alloc_session(shost, transport); | 764 | session = iscsi_alloc_session(shost, transport, dd_size); |
563 | if (!session) | 765 | if (!session) |
564 | return NULL; | 766 | return NULL; |
565 | 767 | ||
@@ -595,7 +797,7 @@ static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) | |||
595 | void iscsi_remove_session(struct iscsi_cls_session *session) | 797 | void iscsi_remove_session(struct iscsi_cls_session *session) |
596 | { | 798 | { |
597 | struct Scsi_Host *shost = iscsi_session_to_shost(session); | 799 | struct Scsi_Host *shost = iscsi_session_to_shost(session); |
598 | struct iscsi_host *ihost = shost->shost_data; | 800 | struct iscsi_cls_host *ihost = shost->shost_data; |
599 | unsigned long flags; | 801 | unsigned long flags; |
600 | int err; | 802 | int err; |
601 | 803 | ||
@@ -661,6 +863,7 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session); | |||
661 | /** | 863 | /** |
662 | * iscsi_create_conn - create iscsi class connection | 864 | * iscsi_create_conn - create iscsi class connection |
663 | * @session: iscsi cls session | 865 | * @session: iscsi cls session |
866 | * @dd_size: private driver data size | ||
664 | * @cid: connection id | 867 | * @cid: connection id |
665 | * | 868 | * |
666 | * This can be called from a LLD or iscsi_transport. The connection | 869 | * This can be called from a LLD or iscsi_transport. The connection |
@@ -673,18 +876,17 @@ EXPORT_SYMBOL_GPL(iscsi_destroy_session); | |||
673 | * non-zero. | 876 | * non-zero. |
674 | */ | 877 | */ |
675 | struct iscsi_cls_conn * | 878 | struct iscsi_cls_conn * |
676 | iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) | 879 | iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) |
677 | { | 880 | { |
678 | struct iscsi_transport *transport = session->transport; | 881 | struct iscsi_transport *transport = session->transport; |
679 | struct iscsi_cls_conn *conn; | 882 | struct iscsi_cls_conn *conn; |
680 | unsigned long flags; | 883 | unsigned long flags; |
681 | int err; | 884 | int err; |
682 | 885 | ||
683 | conn = kzalloc(sizeof(*conn) + transport->conndata_size, GFP_KERNEL); | 886 | conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL); |
684 | if (!conn) | 887 | if (!conn) |
685 | return NULL; | 888 | return NULL; |
686 | 889 | if (dd_size) | |
687 | if (transport->conndata_size) | ||
688 | conn->dd_data = &conn[1]; | 890 | conn->dd_data = &conn[1]; |
689 | 891 | ||
690 | INIT_LIST_HEAD(&conn->conn_list); | 892 | INIT_LIST_HEAD(&conn->conn_list); |
@@ -1017,21 +1219,20 @@ int iscsi_session_event(struct iscsi_cls_session *session, | |||
1017 | EXPORT_SYMBOL_GPL(iscsi_session_event); | 1219 | EXPORT_SYMBOL_GPL(iscsi_session_event); |
1018 | 1220 | ||
1019 | static int | 1221 | static int |
1020 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) | 1222 | iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, |
1223 | struct iscsi_uevent *ev, uint32_t initial_cmdsn, | ||
1224 | uint16_t cmds_max, uint16_t queue_depth) | ||
1021 | { | 1225 | { |
1022 | struct iscsi_transport *transport = priv->iscsi_transport; | 1226 | struct iscsi_transport *transport = priv->iscsi_transport; |
1023 | struct iscsi_cls_session *session; | 1227 | struct iscsi_cls_session *session; |
1024 | uint32_t hostno; | 1228 | uint32_t host_no; |
1025 | 1229 | ||
1026 | session = transport->create_session(transport, &priv->t, | 1230 | session = transport->create_session(ep, cmds_max, queue_depth, |
1027 | ev->u.c_session.cmds_max, | 1231 | initial_cmdsn, &host_no); |
1028 | ev->u.c_session.queue_depth, | ||
1029 | ev->u.c_session.initial_cmdsn, | ||
1030 | &hostno); | ||
1031 | if (!session) | 1232 | if (!session) |
1032 | return -ENOMEM; | 1233 | return -ENOMEM; |
1033 | 1234 | ||
1034 | ev->r.c_session_ret.host_no = hostno; | 1235 | ev->r.c_session_ret.host_no = host_no; |
1035 | ev->r.c_session_ret.sid = session->sid; | 1236 | ev->r.c_session_ret.sid = session->sid; |
1036 | return 0; | 1237 | return 0; |
1037 | } | 1238 | } |
@@ -1106,6 +1307,7 @@ static int | |||
1106 | iscsi_if_transport_ep(struct iscsi_transport *transport, | 1307 | iscsi_if_transport_ep(struct iscsi_transport *transport, |
1107 | struct iscsi_uevent *ev, int msg_type) | 1308 | struct iscsi_uevent *ev, int msg_type) |
1108 | { | 1309 | { |
1310 | struct iscsi_endpoint *ep; | ||
1109 | struct sockaddr *dst_addr; | 1311 | struct sockaddr *dst_addr; |
1110 | int rc = 0; | 1312 | int rc = 0; |
1111 | 1313 | ||
@@ -1115,22 +1317,33 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, | |||
1115 | return -EINVAL; | 1317 | return -EINVAL; |
1116 | 1318 | ||
1117 | dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); | 1319 | dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); |
1118 | rc = transport->ep_connect(dst_addr, | 1320 | ep = transport->ep_connect(dst_addr, |
1119 | ev->u.ep_connect.non_blocking, | 1321 | ev->u.ep_connect.non_blocking); |
1120 | &ev->r.ep_connect_ret.handle); | 1322 | if (IS_ERR(ep)) |
1323 | return PTR_ERR(ep); | ||
1324 | |||
1325 | ev->r.ep_connect_ret.handle = ep->id; | ||
1121 | break; | 1326 | break; |
1122 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: | 1327 | case ISCSI_UEVENT_TRANSPORT_EP_POLL: |
1123 | if (!transport->ep_poll) | 1328 | if (!transport->ep_poll) |
1124 | return -EINVAL; | 1329 | return -EINVAL; |
1125 | 1330 | ||
1126 | ev->r.retcode = transport->ep_poll(ev->u.ep_poll.ep_handle, | 1331 | ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle); |
1332 | if (!ep) | ||
1333 | return -EINVAL; | ||
1334 | |||
1335 | ev->r.retcode = transport->ep_poll(ep, | ||
1127 | ev->u.ep_poll.timeout_ms); | 1336 | ev->u.ep_poll.timeout_ms); |
1128 | break; | 1337 | break; |
1129 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: | 1338 | case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: |
1130 | if (!transport->ep_disconnect) | 1339 | if (!transport->ep_disconnect) |
1131 | return -EINVAL; | 1340 | return -EINVAL; |
1132 | 1341 | ||
1133 | transport->ep_disconnect(ev->u.ep_disconnect.ep_handle); | 1342 | ep = iscsi_lookup_endpoint(ev->u.ep_disconnect.ep_handle); |
1343 | if (!ep) | ||
1344 | return -EINVAL; | ||
1345 | |||
1346 | transport->ep_disconnect(ep); | ||
1134 | break; | 1347 | break; |
1135 | } | 1348 | } |
1136 | return rc; | 1349 | return rc; |
@@ -1195,6 +1408,7 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1195 | struct iscsi_internal *priv; | 1408 | struct iscsi_internal *priv; |
1196 | struct iscsi_cls_session *session; | 1409 | struct iscsi_cls_session *session; |
1197 | struct iscsi_cls_conn *conn; | 1410 | struct iscsi_cls_conn *conn; |
1411 | struct iscsi_endpoint *ep = NULL; | ||
1198 | 1412 | ||
1199 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); | 1413 | priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); |
1200 | if (!priv) | 1414 | if (!priv) |
@@ -1208,7 +1422,22 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
1208 | 1422 | ||
1209 | switch (nlh->nlmsg_type) { | 1423 | switch (nlh->nlmsg_type) { |
1210 | case ISCSI_UEVENT_CREATE_SESSION: | 1424 | case ISCSI_UEVENT_CREATE_SESSION: |
1211 | err = iscsi_if_create_session(priv, ev); | 1425 | err = iscsi_if_create_session(priv, ep, ev, |
1426 | ev->u.c_session.initial_cmdsn, | ||
1427 | ev->u.c_session.cmds_max, | ||
1428 | ev->u.c_session.queue_depth); | ||
1429 | break; | ||
1430 | case ISCSI_UEVENT_CREATE_BOUND_SESSION: | ||
1431 | ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle); | ||
1432 | if (!ep) { | ||
1433 | err = -EINVAL; | ||
1434 | break; | ||
1435 | } | ||
1436 | |||
1437 | err = iscsi_if_create_session(priv, ep, ev, | ||
1438 | ev->u.c_bound_session.initial_cmdsn, | ||
1439 | ev->u.c_bound_session.cmds_max, | ||
1440 | ev->u.c_bound_session.queue_depth); | ||
1212 | break; | 1441 | break; |
1213 | case ISCSI_UEVENT_DESTROY_SESSION: | 1442 | case ISCSI_UEVENT_DESTROY_SESSION: |
1214 | session = iscsi_session_lookup(ev->u.d_session.sid); | 1443 | session = iscsi_session_lookup(ev->u.d_session.sid); |
@@ -1414,6 +1643,8 @@ iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); | |||
1414 | iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); | 1643 | iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); |
1415 | iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); | 1644 | iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); |
1416 | iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); | 1645 | iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); |
1646 | iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); | ||
1647 | iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0) | ||
1417 | 1648 | ||
1418 | static ssize_t | 1649 | static ssize_t |
1419 | show_priv_session_state(struct device *dev, struct device_attribute *attr, | 1650 | show_priv_session_state(struct device *dev, struct device_attribute *attr, |
@@ -1580,6 +1811,8 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1580 | priv->daemon_pid = -1; | 1811 | priv->daemon_pid = -1; |
1581 | priv->iscsi_transport = tt; | 1812 | priv->iscsi_transport = tt; |
1582 | priv->t.user_scan = iscsi_user_scan; | 1813 | priv->t.user_scan = iscsi_user_scan; |
1814 | if (!(tt->caps & CAP_DATA_PATH_OFFLOAD)) | ||
1815 | priv->t.create_work_queue = 1; | ||
1583 | 1816 | ||
1584 | priv->dev.class = &iscsi_transport_class; | 1817 | priv->dev.class = &iscsi_transport_class; |
1585 | snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); | 1818 | snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); |
@@ -1595,7 +1828,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1595 | priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; | 1828 | priv->t.host_attrs.ac.attrs = &priv->host_attrs[0]; |
1596 | priv->t.host_attrs.ac.class = &iscsi_host_class.class; | 1829 | priv->t.host_attrs.ac.class = &iscsi_host_class.class; |
1597 | priv->t.host_attrs.ac.match = iscsi_host_match; | 1830 | priv->t.host_attrs.ac.match = iscsi_host_match; |
1598 | priv->t.host_size = sizeof(struct iscsi_host); | 1831 | priv->t.host_size = sizeof(struct iscsi_cls_host); |
1599 | transport_container_register(&priv->t.host_attrs); | 1832 | transport_container_register(&priv->t.host_attrs); |
1600 | 1833 | ||
1601 | SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME); | 1834 | SETUP_HOST_RD_ATTR(netdev, ISCSI_HOST_NETDEV_NAME); |
@@ -1653,6 +1886,8 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1653 | SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); | 1886 | SETUP_SESSION_RD_ATTR(fast_abort, ISCSI_FAST_ABORT); |
1654 | SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); | 1887 | SETUP_SESSION_RD_ATTR(abort_tmo, ISCSI_ABORT_TMO); |
1655 | SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); | 1888 | SETUP_SESSION_RD_ATTR(lu_reset_tmo,ISCSI_LU_RESET_TMO); |
1889 | SETUP_SESSION_RD_ATTR(ifacename, ISCSI_IFACE_NAME); | ||
1890 | SETUP_SESSION_RD_ATTR(initiatorname, ISCSI_INITIATOR_NAME); | ||
1656 | SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); | 1891 | SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); |
1657 | SETUP_PRIV_SESSION_RD_ATTR(state); | 1892 | SETUP_PRIV_SESSION_RD_ATTR(state); |
1658 | 1893 | ||
@@ -1668,6 +1903,7 @@ iscsi_register_transport(struct iscsi_transport *tt) | |||
1668 | 1903 | ||
1669 | unregister_dev: | 1904 | unregister_dev: |
1670 | device_unregister(&priv->dev); | 1905 | device_unregister(&priv->dev); |
1906 | return NULL; | ||
1671 | free_priv: | 1907 | free_priv: |
1672 | kfree(priv); | 1908 | kfree(priv); |
1673 | return NULL; | 1909 | return NULL; |
@@ -1715,10 +1951,14 @@ static __init int iscsi_transport_init(void) | |||
1715 | if (err) | 1951 | if (err) |
1716 | return err; | 1952 | return err; |
1717 | 1953 | ||
1718 | err = transport_class_register(&iscsi_host_class); | 1954 | err = class_register(&iscsi_endpoint_class); |
1719 | if (err) | 1955 | if (err) |
1720 | goto unregister_transport_class; | 1956 | goto unregister_transport_class; |
1721 | 1957 | ||
1958 | err = transport_class_register(&iscsi_host_class); | ||
1959 | if (err) | ||
1960 | goto unregister_endpoint_class; | ||
1961 | |||
1722 | err = transport_class_register(&iscsi_connection_class); | 1962 | err = transport_class_register(&iscsi_connection_class); |
1723 | if (err) | 1963 | if (err) |
1724 | goto unregister_host_class; | 1964 | goto unregister_host_class; |
@@ -1727,8 +1967,8 @@ static __init int iscsi_transport_init(void) | |||
1727 | if (err) | 1967 | if (err) |
1728 | goto unregister_conn_class; | 1968 | goto unregister_conn_class; |
1729 | 1969 | ||
1730 | nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL, | 1970 | nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, |
1731 | THIS_MODULE); | 1971 | NULL, THIS_MODULE); |
1732 | if (!nls) { | 1972 | if (!nls) { |
1733 | err = -ENOBUFS; | 1973 | err = -ENOBUFS; |
1734 | goto unregister_session_class; | 1974 | goto unregister_session_class; |
@@ -1748,6 +1988,8 @@ unregister_conn_class: | |||
1748 | transport_class_unregister(&iscsi_connection_class); | 1988 | transport_class_unregister(&iscsi_connection_class); |
1749 | unregister_host_class: | 1989 | unregister_host_class: |
1750 | transport_class_unregister(&iscsi_host_class); | 1990 | transport_class_unregister(&iscsi_host_class); |
1991 | unregister_endpoint_class: | ||
1992 | class_unregister(&iscsi_endpoint_class); | ||
1751 | unregister_transport_class: | 1993 | unregister_transport_class: |
1752 | class_unregister(&iscsi_transport_class); | 1994 | class_unregister(&iscsi_transport_class); |
1753 | return err; | 1995 | return err; |
@@ -1760,6 +2002,7 @@ static void __exit iscsi_transport_exit(void) | |||
1760 | transport_class_unregister(&iscsi_connection_class); | 2002 | transport_class_unregister(&iscsi_connection_class); |
1761 | transport_class_unregister(&iscsi_session_class); | 2003 | transport_class_unregister(&iscsi_session_class); |
1762 | transport_class_unregister(&iscsi_host_class); | 2004 | transport_class_unregister(&iscsi_host_class); |
2005 | class_unregister(&iscsi_endpoint_class); | ||
1763 | class_unregister(&iscsi_transport_class); | 2006 | class_unregister(&iscsi_transport_class); |
1764 | } | 2007 | } |
1765 | 2008 | ||
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index d53312c42547..0c63947d8a9d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -58,8 +58,8 @@ | |||
58 | #include <scsi/scsi_host.h> | 58 | #include <scsi/scsi_host.h> |
59 | #include <scsi/scsi_ioctl.h> | 59 | #include <scsi/scsi_ioctl.h> |
60 | #include <scsi/scsicam.h> | 60 | #include <scsi/scsicam.h> |
61 | #include <scsi/sd.h> | ||
62 | 61 | ||
62 | #include "sd.h" | ||
63 | #include "scsi_logging.h" | 63 | #include "scsi_logging.h" |
64 | 64 | ||
65 | MODULE_AUTHOR("Eric Youngdale"); | 65 | MODULE_AUTHOR("Eric Youngdale"); |
@@ -295,11 +295,6 @@ static int sd_major(int major_idx) | |||
295 | } | 295 | } |
296 | } | 296 | } |
297 | 297 | ||
298 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | ||
299 | { | ||
300 | return container_of(disk->private_data, struct scsi_disk, driver); | ||
301 | } | ||
302 | |||
303 | static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) | 298 | static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) |
304 | { | 299 | { |
305 | struct scsi_disk *sdkp = NULL; | 300 | struct scsi_disk *sdkp = NULL; |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h new file mode 100644 index 000000000000..03a3d45cfa42 --- /dev/null +++ b/drivers/scsi/sd.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #ifndef _SCSI_DISK_H | ||
2 | #define _SCSI_DISK_H | ||
3 | |||
4 | /* | ||
5 | * More than enough for everybody ;) The huge number of majors | ||
6 | * is a leftover from 16bit dev_t days, we don't really need that | ||
7 | * much numberspace. | ||
8 | */ | ||
9 | #define SD_MAJORS 16 | ||
10 | |||
11 | /* | ||
12 | * This is limited by the naming scheme enforced in sd_probe, | ||
13 | * add another character to it if you really need more disks. | ||
14 | */ | ||
15 | #define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26) | ||
16 | |||
17 | /* | ||
18 | * Time out in seconds for disks and Magneto-opticals (which are slower). | ||
19 | */ | ||
20 | #define SD_TIMEOUT (30 * HZ) | ||
21 | #define SD_MOD_TIMEOUT (75 * HZ) | ||
22 | |||
23 | /* | ||
24 | * Number of allowed retries | ||
25 | */ | ||
26 | #define SD_MAX_RETRIES 5 | ||
27 | #define SD_PASSTHROUGH_RETRIES 1 | ||
28 | |||
29 | /* | ||
30 | * Size of the initial data buffer for mode and read capacity data | ||
31 | */ | ||
32 | #define SD_BUF_SIZE 512 | ||
33 | |||
34 | struct scsi_disk { | ||
35 | struct scsi_driver *driver; /* always &sd_template */ | ||
36 | struct scsi_device *device; | ||
37 | struct device dev; | ||
38 | struct gendisk *disk; | ||
39 | unsigned int openers; /* protected by BKL for now, yuck */ | ||
40 | sector_t capacity; /* size in 512-byte sectors */ | ||
41 | u32 index; | ||
42 | u8 media_present; | ||
43 | u8 write_prot; | ||
44 | unsigned previous_state : 1; | ||
45 | unsigned WCE : 1; /* state of disk WCE bit */ | ||
46 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | ||
47 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ | ||
48 | }; | ||
49 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) | ||
50 | |||
51 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | ||
52 | { | ||
53 | return container_of(disk->private_data, struct scsi_disk, driver); | ||
54 | } | ||
55 | |||
56 | #define sd_printk(prefix, sdsk, fmt, a...) \ | ||
57 | (sdsk)->disk ? \ | ||
58 | sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ | ||
59 | (sdsk)->disk->disk_name, ##a) : \ | ||
60 | sdev_printk(prefix, (sdsk)->device, fmt, ##a) | ||
61 | |||
62 | #endif /* _SCSI_DISK_H */ | ||
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index fccd2e88d600..d3b8ebb83776 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -1036,6 +1036,9 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
1036 | case SG_SCSI_RESET_DEVICE: | 1036 | case SG_SCSI_RESET_DEVICE: |
1037 | val = SCSI_TRY_RESET_DEVICE; | 1037 | val = SCSI_TRY_RESET_DEVICE; |
1038 | break; | 1038 | break; |
1039 | case SG_SCSI_RESET_TARGET: | ||
1040 | val = SCSI_TRY_RESET_TARGET; | ||
1041 | break; | ||
1039 | case SG_SCSI_RESET_BUS: | 1042 | case SG_SCSI_RESET_BUS: |
1040 | val = SCSI_TRY_RESET_BUS; | 1043 | val = SCSI_TRY_RESET_BUS; |
1041 | break; | 1044 | break; |
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h index 0433d5d0caf3..430537183c18 100644 --- a/drivers/scsi/sym53c8xx_2/sym_misc.h +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h | |||
@@ -121,9 +121,7 @@ static __inline void sym_que_move(struct sym_quehead *orig, | |||
121 | } | 121 | } |
122 | } | 122 | } |
123 | 123 | ||
124 | #define sym_que_entry(ptr, type, member) \ | 124 | #define sym_que_entry(ptr, type, member) container_of(ptr, type, member) |
125 | ((type *)((char *)(ptr)-(unsigned int)(&((type *)0)->member))) | ||
126 | |||
127 | 125 | ||
128 | #define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) | 126 | #define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) |
129 | 127 | ||