1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* |
3 | * zfcp device driver |
4 | * |
5 | * Fibre Channel related definitions and inline functions for the zfcp |
6 | * device driver |
7 | * |
8 | * Copyright IBM Corp. 2009, 2017 |
9 | */ |
10 | |
11 | #ifndef ZFCP_FC_H |
12 | #define ZFCP_FC_H |
13 | |
14 | #include <scsi/fc/fc_els.h> |
15 | #include <scsi/fc/fc_fcp.h> |
16 | #include <scsi/fc/fc_ns.h> |
17 | #include <scsi/scsi_cmnd.h> |
18 | #include <scsi/scsi_tcq.h> |
19 | #include "zfcp_fsf.h" |
20 | |
21 | #define ZFCP_FC_CT_SIZE_PAGE (PAGE_SIZE - sizeof(struct fc_ct_hdr)) |
22 | #define ZFCP_FC_GPN_FT_ENT_PAGE (ZFCP_FC_CT_SIZE_PAGE \ |
23 | / sizeof(struct fc_gpn_ft_resp)) |
24 | #define ZFCP_FC_GPN_FT_NUM_BUFS 4 /* memory pages */ |
25 | |
26 | #define ZFCP_FC_GPN_FT_MAX_SIZE (ZFCP_FC_GPN_FT_NUM_BUFS * PAGE_SIZE \ |
27 | - sizeof(struct fc_ct_hdr)) |
28 | #define ZFCP_FC_GPN_FT_MAX_ENT (ZFCP_FC_GPN_FT_NUM_BUFS * \ |
29 | (ZFCP_FC_GPN_FT_ENT_PAGE + 1)) |
30 | |
31 | #define ZFCP_FC_CTELS_TMO (2 * FC_DEF_R_A_TOV / 1000) |
32 | |
33 | /** |
34 | * struct zfcp_fc_event - FC HBAAPI event for internal queueing from irq context |
35 | * @code: Event code |
36 | * @data: Event data |
37 | * @list: list_head for zfcp_fc_events list |
38 | */ |
39 | struct zfcp_fc_event { |
40 | enum fc_host_event_code code; |
41 | u32 data; |
42 | struct list_head list; |
43 | }; |
44 | |
45 | /** |
46 | * struct zfcp_fc_events - Infrastructure for posting FC events from irq context |
47 | * @list: List for queueing of events from irq context to workqueue |
48 | * @list_lock: Lock for event list |
49 | * @work: work_struct for forwarding events in workqueue |
50 | */ |
51 | struct zfcp_fc_events { |
52 | struct list_head list; |
53 | spinlock_t list_lock; |
54 | struct work_struct work; |
55 | }; |
56 | |
57 | /** |
58 | * struct zfcp_fc_gid_pn_req - container for ct header plus gid_pn request |
59 | * @ct_hdr: FC GS common transport header |
60 | * @gid_pn: GID_PN request |
61 | */ |
62 | struct zfcp_fc_gid_pn_req { |
63 | struct fc_ct_hdr ct_hdr; |
64 | struct fc_ns_gid_pn gid_pn; |
65 | } __packed; |
66 | |
67 | /** |
68 | * struct zfcp_fc_gid_pn_rsp - container for ct header plus gid_pn response |
69 | * @ct_hdr: FC GS common transport header |
70 | * @gid_pn: GID_PN response |
71 | */ |
72 | struct zfcp_fc_gid_pn_rsp { |
73 | struct fc_ct_hdr ct_hdr; |
74 | struct fc_gid_pn_resp gid_pn; |
75 | } __packed; |
76 | |
77 | /** |
78 | * struct zfcp_fc_gpn_ft - container for ct header plus gpn_ft request |
79 | * @ct_hdr: FC GS common transport header |
80 | * @gpn_ft: GPN_FT request |
81 | */ |
82 | struct zfcp_fc_gpn_ft_req { |
83 | struct fc_ct_hdr ct_hdr; |
84 | struct fc_ns_gid_ft gpn_ft; |
85 | } __packed; |
86 | |
87 | /** |
88 | * struct zfcp_fc_gspn_req - container for ct header plus GSPN_ID request |
89 | * @ct_hdr: FC GS common transport header |
90 | * @gspn: GSPN_ID request |
91 | */ |
92 | struct zfcp_fc_gspn_req { |
93 | struct fc_ct_hdr ct_hdr; |
94 | struct fc_gid_pn_resp gspn; |
95 | } __packed; |
96 | |
97 | /** |
98 | * struct zfcp_fc_gspn_rsp - container for ct header plus GSPN_ID response |
99 | * @ct_hdr: FC GS common transport header |
100 | * @gspn: GSPN_ID response |
101 | * @name: The name string of the GSPN_ID response |
102 | */ |
103 | struct zfcp_fc_gspn_rsp { |
104 | struct fc_ct_hdr ct_hdr; |
105 | struct fc_gspn_resp gspn; |
106 | char name[FC_SYMBOLIC_NAME_SIZE]; |
107 | } __packed; |
108 | |
109 | /** |
110 | * struct zfcp_fc_rspn_req - container for ct header plus RSPN_ID request |
111 | * @ct_hdr: FC GS common transport header |
112 | * @rspn: RSPN_ID request |
113 | * @name: The name string of the RSPN_ID request |
114 | */ |
115 | struct zfcp_fc_rspn_req { |
116 | struct fc_ct_hdr ct_hdr; |
117 | struct fc_ns_rspn rspn; |
118 | char name[FC_SYMBOLIC_NAME_SIZE]; |
119 | } __packed; |
120 | |
121 | /** |
122 | * struct zfcp_fc_req - Container for FC ELS and CT requests sent from zfcp |
123 | * @ct_els: data required for issuing fsf command |
124 | * @sg_req: scatterlist entry for request data, refers to embedded @u submember |
125 | * @sg_rsp: scatterlist entry for response data, refers to embedded @u submember |
126 | * @u: request and response specific data |
127 | * @u.adisc: ADISC specific data |
128 | * @u.adisc.req: ADISC request |
129 | * @u.adisc.rsp: ADISC response |
130 | * @u.gid_pn: GID_PN specific data |
131 | * @u.gid_pn.req: GID_PN request |
132 | * @u.gid_pn.rsp: GID_PN response |
133 | * @u.gpn_ft: GPN_FT specific data |
134 | * @u.gpn_ft.sg_rsp2: GPN_FT response, not embedded here, allocated elsewhere |
135 | * @u.gpn_ft.req: GPN_FT request |
136 | * @u.gspn: GSPN specific data |
137 | * @u.gspn.req: GSPN request |
138 | * @u.gspn.rsp: GSPN response |
139 | * @u.rspn: RSPN specific data |
140 | * @u.rspn.req: RSPN request |
141 | * @u.rspn.rsp: RSPN response |
142 | */ |
143 | struct zfcp_fc_req { |
144 | struct zfcp_fsf_ct_els ct_els; |
145 | struct scatterlist sg_req; |
146 | struct scatterlist sg_rsp; |
147 | union { |
148 | struct { |
149 | struct fc_els_adisc req; |
150 | struct fc_els_adisc rsp; |
151 | } adisc; |
152 | struct { |
153 | struct zfcp_fc_gid_pn_req req; |
154 | struct zfcp_fc_gid_pn_rsp rsp; |
155 | } gid_pn; |
156 | struct { |
157 | struct scatterlist sg_rsp2[ZFCP_FC_GPN_FT_NUM_BUFS - 1]; |
158 | struct zfcp_fc_gpn_ft_req req; |
159 | } gpn_ft; |
160 | struct { |
161 | struct zfcp_fc_gspn_req req; |
162 | struct zfcp_fc_gspn_rsp rsp; |
163 | } gspn; |
164 | struct { |
165 | struct zfcp_fc_rspn_req req; |
166 | struct fc_ct_hdr rsp; |
167 | } rspn; |
168 | } u; |
169 | }; |
170 | |
171 | /** |
172 | * enum zfcp_fc_wka_status - FC WKA port status in zfcp |
173 | * @ZFCP_FC_WKA_PORT_OFFLINE: Port is closed and not in use |
174 | * @ZFCP_FC_WKA_PORT_CLOSING: The FSF "close port" request is pending |
175 | * @ZFCP_FC_WKA_PORT_OPENING: The FSF "open port" request is pending |
176 | * @ZFCP_FC_WKA_PORT_ONLINE: The port is open and the port handle is valid |
177 | */ |
178 | enum zfcp_fc_wka_status { |
179 | ZFCP_FC_WKA_PORT_OFFLINE, |
180 | ZFCP_FC_WKA_PORT_CLOSING, |
181 | ZFCP_FC_WKA_PORT_OPENING, |
182 | ZFCP_FC_WKA_PORT_ONLINE, |
183 | }; |
184 | |
185 | /** |
186 | * struct zfcp_fc_wka_port - representation of well-known-address (WKA) FC port |
187 | * @adapter: Pointer to adapter structure this WKA port belongs to |
188 | * @opened: Wait for completion of open command |
189 | * @closed: Wait for completion of close command |
190 | * @status: Current status of WKA port |
191 | * @refcount: Reference count to keep port open as long as it is in use |
192 | * @d_id: FC destination id or well-known-address |
193 | * @handle: FSF handle for the open WKA port |
194 | * @mutex: Mutex used during opening/closing state changes |
195 | * @work: For delaying the closing of the WKA port |
196 | */ |
197 | struct zfcp_fc_wka_port { |
198 | struct zfcp_adapter *adapter; |
199 | wait_queue_head_t opened; |
200 | wait_queue_head_t closed; |
201 | enum zfcp_fc_wka_status status; |
202 | atomic_t refcount; |
203 | u32 d_id; |
204 | u32 handle; |
205 | struct mutex mutex; |
206 | struct delayed_work work; |
207 | }; |
208 | |
209 | /** |
210 | * struct zfcp_fc_wka_ports - Data structures for FC generic services |
211 | * @ms: FC Management service |
212 | * @ts: FC time service |
213 | * @ds: FC directory service |
214 | * @as: FC alias service |
215 | */ |
216 | struct zfcp_fc_wka_ports { |
217 | struct zfcp_fc_wka_port ms; |
218 | struct zfcp_fc_wka_port ts; |
219 | struct zfcp_fc_wka_port ds; |
220 | struct zfcp_fc_wka_port as; |
221 | }; |
222 | |
223 | /** |
224 | * zfcp_fc_scsi_to_fcp - setup FCP command with data from scsi_cmnd |
225 | * @fcp: fcp_cmnd to setup |
226 | * @scsi: scsi_cmnd where to get LUN, task attributes/flags and CDB |
227 | */ |
228 | static inline |
229 | void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi) |
230 | { |
231 | u32 datalen; |
232 | |
233 | int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun); |
234 | |
235 | fcp->fc_pri_ta = FCP_PTA_SIMPLE; |
236 | |
237 | if (scsi->sc_data_direction == DMA_FROM_DEVICE) |
238 | fcp->fc_flags |= FCP_CFL_RDDATA; |
239 | if (scsi->sc_data_direction == DMA_TO_DEVICE) |
240 | fcp->fc_flags |= FCP_CFL_WRDATA; |
241 | |
242 | memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len); |
243 | |
244 | datalen = scsi_bufflen(cmd: scsi); |
245 | fcp->fc_dl = cpu_to_be32(datalen); |
246 | |
247 | if (scsi_get_prot_type(scmd: scsi) == SCSI_PROT_DIF_TYPE1) { |
248 | datalen += datalen / scsi->device->sector_size * 8; |
249 | fcp->fc_dl = cpu_to_be32(datalen); |
250 | } |
251 | } |
252 | |
253 | /** |
254 | * zfcp_fc_fcp_tm() - Setup FCP command as task management command. |
255 | * @fcp: Pointer to FCP_CMND IU to set up. |
256 | * @dev: Pointer to SCSI_device where to send the task management command. |
257 | * @tm_flags: Task management flags to setup tm command. |
258 | */ |
259 | static inline |
260 | void zfcp_fc_fcp_tm(struct fcp_cmnd *fcp, struct scsi_device *dev, u8 tm_flags) |
261 | { |
262 | int_to_scsilun(dev->lun, (struct scsi_lun *) &fcp->fc_lun); |
263 | fcp->fc_tm_flags = tm_flags; |
264 | } |
265 | |
266 | /** |
267 | * zfcp_fc_evap_fcp_rsp - evaluate FCP RSP IU and update scsi_cmnd accordingly |
268 | * @fcp_rsp: FCP RSP IU to evaluate |
269 | * @scsi: SCSI command where to update status and sense buffer |
270 | */ |
271 | static inline |
272 | void zfcp_fc_eval_fcp_rsp(struct fcp_resp_with_ext *fcp_rsp, |
273 | struct scsi_cmnd *scsi) |
274 | { |
275 | struct fcp_resp_rsp_info *rsp_info; |
276 | char *sense; |
277 | u32 sense_len, resid; |
278 | u8 rsp_flags; |
279 | |
280 | scsi->result |= fcp_rsp->resp.fr_status; |
281 | |
282 | rsp_flags = fcp_rsp->resp.fr_flags; |
283 | |
284 | if (unlikely(rsp_flags & FCP_RSP_LEN_VAL)) { |
285 | rsp_info = (struct fcp_resp_rsp_info *) &fcp_rsp[1]; |
286 | if (rsp_info->rsp_code == FCP_TMF_CMPL) |
287 | set_host_byte(cmd: scsi, status: DID_OK); |
288 | else { |
289 | set_host_byte(cmd: scsi, status: DID_ERROR); |
290 | return; |
291 | } |
292 | } |
293 | |
294 | if (unlikely(rsp_flags & FCP_SNS_LEN_VAL)) { |
295 | sense = (char *) &fcp_rsp[1]; |
296 | if (rsp_flags & FCP_RSP_LEN_VAL) |
297 | sense += be32_to_cpu(fcp_rsp->ext.fr_rsp_len); |
298 | sense_len = min_t(u32, be32_to_cpu(fcp_rsp->ext.fr_sns_len), |
299 | SCSI_SENSE_BUFFERSIZE); |
300 | memcpy(scsi->sense_buffer, sense, sense_len); |
301 | } |
302 | |
303 | if (unlikely(rsp_flags & FCP_RESID_UNDER)) { |
304 | resid = be32_to_cpu(fcp_rsp->ext.fr_resid); |
305 | scsi_set_resid(cmd: scsi, resid); |
306 | if (scsi_bufflen(cmd: scsi) - resid < scsi->underflow && |
307 | !(rsp_flags & FCP_SNS_LEN_VAL) && |
308 | fcp_rsp->resp.fr_status == SAM_STAT_GOOD) |
309 | set_host_byte(cmd: scsi, status: DID_ERROR); |
310 | } else if (unlikely(rsp_flags & FCP_RESID_OVER)) { |
311 | /* FCP_DL was not sufficient for SCSI data length */ |
312 | if (fcp_rsp->resp.fr_status == SAM_STAT_GOOD) |
313 | set_host_byte(cmd: scsi, status: DID_ERROR); |
314 | } |
315 | } |
316 | |
317 | #endif |
318 | |