.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* ------------------------------------------------------------ |
---|
2 | 3 | * ibmvscsi.c |
---|
3 | 4 | * (C) Copyright IBM Corporation 1994, 2004 |
---|
4 | 5 | * Authors: Colin DeVilbiss (devilbis@us.ibm.com) |
---|
5 | 6 | * Santiago Leon (santil@us.ibm.com) |
---|
6 | 7 | * Dave Boutcher (sleddog@us.ibm.com) |
---|
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 |
---|
21 | | - * USA |
---|
22 | 8 | * |
---|
23 | 9 | * ------------------------------------------------------------ |
---|
24 | 10 | * Emulation of a SCSI host adapter for Virtual I/O devices |
---|
.. | .. |
---|
683 | 669 | } |
---|
684 | 670 | |
---|
685 | 671 | /** |
---|
686 | | - * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields |
---|
| 672 | + * map_sg_data: - Maps dma for a scatterlist and initializes descriptor fields |
---|
687 | 673 | * @cmd: struct scsi_cmnd with the scatterlist |
---|
688 | 674 | * @srp_cmd: srp_cmd that contains the memory descriptor |
---|
689 | 675 | * @dev: device for which to map dma memory |
---|
.. | .. |
---|
821 | 807 | } |
---|
822 | 808 | |
---|
823 | 809 | /** |
---|
| 810 | + * ibmvscsi_set_request_limit - Set the adapter request_limit in response to |
---|
| 811 | + * an adapter failure, reset, or SRP Login. Done under host lock to prevent |
---|
| 812 | + * race with SCSI command submission. |
---|
| 813 | + * @hostdata: adapter to adjust |
---|
| 814 | + * @limit: new request limit |
---|
| 815 | + */ |
---|
| 816 | +static void ibmvscsi_set_request_limit(struct ibmvscsi_host_data *hostdata, int limit) |
---|
| 817 | +{ |
---|
| 818 | + unsigned long flags; |
---|
| 819 | + |
---|
| 820 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
| 821 | + atomic_set(&hostdata->request_limit, limit); |
---|
| 822 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
| 823 | +} |
---|
| 824 | + |
---|
| 825 | +/** |
---|
824 | 826 | * ibmvscsi_reset_host - Reset the connection to the server |
---|
825 | 827 | * @hostdata: struct ibmvscsi_host_data to reset |
---|
826 | 828 | */ |
---|
827 | 829 | static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) |
---|
828 | 830 | { |
---|
829 | 831 | scsi_block_requests(hostdata->host); |
---|
830 | | - atomic_set(&hostdata->request_limit, 0); |
---|
| 832 | + ibmvscsi_set_request_limit(hostdata, 0); |
---|
831 | 833 | |
---|
832 | 834 | purge_requests(hostdata, DID_ERROR); |
---|
833 | | - hostdata->reset_crq = 1; |
---|
| 835 | + hostdata->action = IBMVSCSI_HOST_ACTION_RESET; |
---|
834 | 836 | wake_up(&hostdata->work_wait_q); |
---|
835 | 837 | } |
---|
836 | 838 | |
---|
.. | .. |
---|
1160 | 1162 | dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n", |
---|
1161 | 1163 | evt_struct->xfer_iu->srp.login_rej.reason); |
---|
1162 | 1164 | /* Login failed. */ |
---|
1163 | | - atomic_set(&hostdata->request_limit, -1); |
---|
| 1165 | + ibmvscsi_set_request_limit(hostdata, -1); |
---|
1164 | 1166 | return; |
---|
1165 | 1167 | default: |
---|
1166 | 1168 | dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n", |
---|
1167 | 1169 | evt_struct->xfer_iu->srp.login_rsp.opcode); |
---|
1168 | 1170 | /* Login failed. */ |
---|
1169 | | - atomic_set(&hostdata->request_limit, -1); |
---|
| 1171 | + ibmvscsi_set_request_limit(hostdata, -1); |
---|
1170 | 1172 | return; |
---|
1171 | 1173 | } |
---|
1172 | 1174 | |
---|
.. | .. |
---|
1177 | 1179 | * This value is set rather than added to request_limit because |
---|
1178 | 1180 | * request_limit could have been set to -1 by this client. |
---|
1179 | 1181 | */ |
---|
1180 | | - atomic_set(&hostdata->request_limit, |
---|
| 1182 | + ibmvscsi_set_request_limit(hostdata, |
---|
1181 | 1183 | be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta)); |
---|
1182 | 1184 | |
---|
1183 | 1185 | /* If we had any pending I/Os, kick them */ |
---|
1184 | | - scsi_unblock_requests(hostdata->host); |
---|
| 1186 | + hostdata->action = IBMVSCSI_HOST_ACTION_UNBLOCK; |
---|
| 1187 | + wake_up(&hostdata->work_wait_q); |
---|
1185 | 1188 | } |
---|
1186 | 1189 | |
---|
1187 | 1190 | /** |
---|
.. | .. |
---|
1208 | 1211 | login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT | |
---|
1209 | 1212 | SRP_BUF_FORMAT_INDIRECT); |
---|
1210 | 1213 | |
---|
1211 | | - spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
1212 | 1214 | /* Start out with a request limit of 0, since this is negotiated in |
---|
1213 | 1215 | * the login request we are just sending and login requests always |
---|
1214 | 1216 | * get sent by the driver regardless of request_limit. |
---|
1215 | 1217 | */ |
---|
1216 | | - atomic_set(&hostdata->request_limit, 0); |
---|
| 1218 | + ibmvscsi_set_request_limit(hostdata, 0); |
---|
1217 | 1219 | |
---|
| 1220 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
1218 | 1221 | rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2); |
---|
1219 | 1222 | spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
1220 | 1223 | dev_info(hostdata->dev, "sent SRP login\n"); |
---|
.. | .. |
---|
1794 | 1797 | return; |
---|
1795 | 1798 | case VIOSRP_CRQ_XPORT_EVENT: /* Hypervisor telling us the connection is closed */ |
---|
1796 | 1799 | scsi_block_requests(hostdata->host); |
---|
1797 | | - atomic_set(&hostdata->request_limit, 0); |
---|
| 1800 | + ibmvscsi_set_request_limit(hostdata, 0); |
---|
1798 | 1801 | if (crq->format == 0x06) { |
---|
1799 | 1802 | /* We need to re-setup the interpartition connection */ |
---|
1800 | 1803 | dev_info(hostdata->dev, "Re-enabling adapter!\n"); |
---|
1801 | 1804 | hostdata->client_migrated = 1; |
---|
1802 | | - hostdata->reenable_crq = 1; |
---|
| 1805 | + hostdata->action = IBMVSCSI_HOST_ACTION_REENABLE; |
---|
1803 | 1806 | purge_requests(hostdata, DID_REQUEUE); |
---|
1804 | 1807 | wake_up(&hostdata->work_wait_q); |
---|
1805 | 1808 | } else { |
---|
.. | .. |
---|
2052 | 2055 | .show = show_host_config, |
---|
2053 | 2056 | }; |
---|
2054 | 2057 | |
---|
| 2058 | +static int ibmvscsi_host_reset(struct Scsi_Host *shost, int reset_type) |
---|
| 2059 | +{ |
---|
| 2060 | + struct ibmvscsi_host_data *hostdata = shost_priv(shost); |
---|
| 2061 | + |
---|
| 2062 | + dev_info(hostdata->dev, "Initiating adapter reset!\n"); |
---|
| 2063 | + ibmvscsi_reset_host(hostdata); |
---|
| 2064 | + |
---|
| 2065 | + return 0; |
---|
| 2066 | +} |
---|
| 2067 | + |
---|
2055 | 2068 | static struct device_attribute *ibmvscsi_attrs[] = { |
---|
2056 | 2069 | &ibmvscsi_host_vhost_loc, |
---|
2057 | 2070 | &ibmvscsi_host_vhost_name, |
---|
.. | .. |
---|
2078 | 2091 | .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler, |
---|
2079 | 2092 | .slave_configure = ibmvscsi_slave_configure, |
---|
2080 | 2093 | .change_queue_depth = ibmvscsi_change_queue_depth, |
---|
| 2094 | + .host_reset = ibmvscsi_host_reset, |
---|
2081 | 2095 | .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT, |
---|
2082 | 2096 | .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, |
---|
2083 | 2097 | .this_id = -1, |
---|
2084 | 2098 | .sg_tablesize = SG_ALL, |
---|
2085 | | - .use_clustering = ENABLE_CLUSTERING, |
---|
2086 | 2099 | .shost_attrs = ibmvscsi_attrs, |
---|
2087 | 2100 | }; |
---|
2088 | 2101 | |
---|
.. | .. |
---|
2108 | 2121 | |
---|
2109 | 2122 | static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) |
---|
2110 | 2123 | { |
---|
| 2124 | + unsigned long flags; |
---|
2111 | 2125 | int rc; |
---|
2112 | 2126 | char *action = "reset"; |
---|
2113 | 2127 | |
---|
2114 | | - if (hostdata->reset_crq) { |
---|
2115 | | - smp_rmb(); |
---|
2116 | | - hostdata->reset_crq = 0; |
---|
2117 | | - |
---|
| 2128 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
| 2129 | + switch (hostdata->action) { |
---|
| 2130 | + case IBMVSCSI_HOST_ACTION_UNBLOCK: |
---|
| 2131 | + rc = 0; |
---|
| 2132 | + break; |
---|
| 2133 | + case IBMVSCSI_HOST_ACTION_RESET: |
---|
| 2134 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
2118 | 2135 | rc = ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); |
---|
| 2136 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
2119 | 2137 | if (!rc) |
---|
2120 | 2138 | rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); |
---|
2121 | 2139 | vio_enable_interrupts(to_vio_dev(hostdata->dev)); |
---|
2122 | | - } else if (hostdata->reenable_crq) { |
---|
2123 | | - smp_rmb(); |
---|
| 2140 | + break; |
---|
| 2141 | + case IBMVSCSI_HOST_ACTION_REENABLE: |
---|
2124 | 2142 | action = "enable"; |
---|
| 2143 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
2125 | 2144 | rc = ibmvscsi_reenable_crq_queue(&hostdata->queue, hostdata); |
---|
2126 | | - hostdata->reenable_crq = 0; |
---|
| 2145 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
2127 | 2146 | if (!rc) |
---|
2128 | 2147 | rc = ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0); |
---|
2129 | | - } else |
---|
| 2148 | + break; |
---|
| 2149 | + case IBMVSCSI_HOST_ACTION_NONE: |
---|
| 2150 | + default: |
---|
| 2151 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
2130 | 2152 | return; |
---|
| 2153 | + } |
---|
| 2154 | + |
---|
| 2155 | + hostdata->action = IBMVSCSI_HOST_ACTION_NONE; |
---|
| 2156 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
2131 | 2157 | |
---|
2132 | 2158 | if (rc) { |
---|
2133 | | - atomic_set(&hostdata->request_limit, -1); |
---|
| 2159 | + ibmvscsi_set_request_limit(hostdata, -1); |
---|
2134 | 2160 | dev_err(hostdata->dev, "error after %s\n", action); |
---|
2135 | 2161 | } |
---|
2136 | 2162 | |
---|
2137 | 2163 | scsi_unblock_requests(hostdata->host); |
---|
2138 | 2164 | } |
---|
2139 | 2165 | |
---|
2140 | | -static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) |
---|
| 2166 | +static int __ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) |
---|
2141 | 2167 | { |
---|
2142 | 2168 | if (kthread_should_stop()) |
---|
2143 | 2169 | return 1; |
---|
2144 | | - else if (hostdata->reset_crq) { |
---|
2145 | | - smp_rmb(); |
---|
2146 | | - return 1; |
---|
2147 | | - } else if (hostdata->reenable_crq) { |
---|
2148 | | - smp_rmb(); |
---|
2149 | | - return 1; |
---|
| 2170 | + switch (hostdata->action) { |
---|
| 2171 | + case IBMVSCSI_HOST_ACTION_NONE: |
---|
| 2172 | + return 0; |
---|
| 2173 | + case IBMVSCSI_HOST_ACTION_RESET: |
---|
| 2174 | + case IBMVSCSI_HOST_ACTION_REENABLE: |
---|
| 2175 | + case IBMVSCSI_HOST_ACTION_UNBLOCK: |
---|
| 2176 | + default: |
---|
| 2177 | + break; |
---|
2150 | 2178 | } |
---|
2151 | 2179 | |
---|
2152 | | - return 0; |
---|
| 2180 | + return 1; |
---|
| 2181 | +} |
---|
| 2182 | + |
---|
| 2183 | +static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) |
---|
| 2184 | +{ |
---|
| 2185 | + unsigned long flags; |
---|
| 2186 | + int rc; |
---|
| 2187 | + |
---|
| 2188 | + spin_lock_irqsave(hostdata->host->host_lock, flags); |
---|
| 2189 | + rc = __ibmvscsi_work_to_do(hostdata); |
---|
| 2190 | + spin_unlock_irqrestore(hostdata->host->host_lock, flags); |
---|
| 2191 | + |
---|
| 2192 | + return rc; |
---|
2153 | 2193 | } |
---|
2154 | 2194 | |
---|
2155 | 2195 | static int ibmvscsi_work(void *data) |
---|
.. | .. |
---|
2202 | 2242 | init_waitqueue_head(&hostdata->work_wait_q); |
---|
2203 | 2243 | hostdata->host = host; |
---|
2204 | 2244 | hostdata->dev = dev; |
---|
2205 | | - atomic_set(&hostdata->request_limit, -1); |
---|
| 2245 | + ibmvscsi_set_request_limit(hostdata, -1); |
---|
2206 | 2246 | hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT; |
---|
2207 | 2247 | |
---|
2208 | 2248 | if (map_persist_bufs(hostdata)) { |
---|
.. | .. |
---|
2362 | 2402 | static struct srp_function_template ibmvscsi_transport_functions = { |
---|
2363 | 2403 | }; |
---|
2364 | 2404 | |
---|
2365 | | -int __init ibmvscsi_module_init(void) |
---|
| 2405 | +static int __init ibmvscsi_module_init(void) |
---|
2366 | 2406 | { |
---|
2367 | 2407 | int ret; |
---|
2368 | 2408 | |
---|
.. | .. |
---|
2384 | 2424 | return ret; |
---|
2385 | 2425 | } |
---|
2386 | 2426 | |
---|
2387 | | -void __exit ibmvscsi_module_exit(void) |
---|
| 2427 | +static void __exit ibmvscsi_module_exit(void) |
---|
2388 | 2428 | { |
---|
2389 | 2429 | vio_unregister_driver(&ibmvscsi_driver); |
---|
2390 | 2430 | srp_release_transport(ibmvscsi_transport_template); |
---|