]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiExtScsiPassThru.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiExtScsiPassThru.c
1 /** @file
2 The implementation of EFI_EXT_SCSI_PASS_THRU_PROTOCOL.
3
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "IScsiImpl.h"
10
11 EFI_EXT_SCSI_PASS_THRU_PROTOCOL gIScsiExtScsiPassThruProtocolTemplate = {
12 NULL,
13 IScsiExtScsiPassThruFunction,
14 IScsiExtScsiPassThruGetNextTargetLun,
15 IScsiExtScsiPassThruBuildDevicePath,
16 IScsiExtScsiPassThruGetTargetLun,
17 IScsiExtScsiPassThruResetChannel,
18 IScsiExtScsiPassThruResetTargetLun,
19 IScsiExtScsiPassThruGetNextTarget
20 };
21
22 /**
23 Sends a SCSI Request Packet to a SCSI device that is attached to the SCSI channel.
24 This function supports both blocking I/O and nonblocking I/O. The blocking I/O
25 functionality is required, and the nonblocking I/O functionality is optional.
26
27 @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
28 @param[in] Target The Target is an array of size TARGET_MAX_BYTES and it
29 represents the id of the SCSI device to send the SCSI
30 Request Packet. Each transport driver may choose to
31 utilize a subset of this size to suit the needs
32 of transport target representation. For example, a
33 Fibre Channel driver may use only 8 bytes (WWN)
34 to represent an FC target.
35 @param[in] Lun The LUN of the SCSI device to send the SCSI Request Packet.
36 @param[in, out] Packet A pointer to the SCSI Request Packet to send to the
37 SCSI device specified by Target and Lun.
38 @param[in] Event If nonblocking I/O is not supported then Event is ignored,
39 and blocking I/O is performed. If Event is NULL, then
40 blocking I/O is performed. If Event is not NULL and non
41 blocking I/O is supported, then nonblocking I/O is performed,
42 and Event will be signaled when the SCSI Request Packet
43 completes.
44
45 @retval EFI_SUCCESS The SCSI Request Packet was sent by the host. For
46 bi-directional commands, InTransferLength bytes
47 were transferred from InDataBuffer.
48 For write and bi-directional commands, OutTransferLength
49 bytes were transferred by OutDataBuffer.
50 @retval EFI_BAD_BUFFER_SIZE The SCSI Request Packet was not executed.
51 The number of bytes that could be transferred is
52 returned in InTransferLength. For write and
53 bi-directional commands, OutTransferLength bytes
54 were transferred by OutDataBuffer.
55 @retval EFI_NOT_READY The SCSI Request Packet could not be sent because
56 there are too many SCSI Request Packets already
57 queued. The caller may retry later.
58 @retval EFI_DEVICE_ERROR A device error occurred while attempting to send
59 the SCSI Request Packet.
60 @retval EFI_INVALID_PARAMETER Target, Lun, or the contents of ScsiRequestPacket,
61 are invalid.
62 @retval EFI_UNSUPPORTED The command described by the SCSI Request Packet
63 is not supported by the host adapter.
64 This includes the case of Bi-directional SCSI
65 commands not supported by the implementation.
66 The SCSI Request Packet was not sent,
67 so no additional status information is available.
68 @retval EFI_TIMEOUT A timeout occurred while waiting for the SCSI
69 Request Packet to execute.
70
71 **/
72 EFI_STATUS
73 EFIAPI
74 IScsiExtScsiPassThruFunction (
75 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
76 IN UINT8 *Target,
77 IN UINT64 Lun,
78 IN OUT EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET *Packet,
79 IN EFI_EVENT Event OPTIONAL
80 )
81 {
82 EFI_STATUS Status;
83 ISCSI_DRIVER_DATA *Private;
84
85 if (Target[0] != 0) {
86 return EFI_INVALID_PARAMETER;
87 }
88
89 if ((Packet == NULL) || (Packet->Cdb == NULL)) {
90 return EFI_INVALID_PARAMETER;
91 }
92
93 Status = IScsiExecuteScsiCommand (This, Target, Lun, Packet);
94 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {
95 //
96 // Try to reinstate the session and re-execute the Scsi command.
97 //
98 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);
99 if (EFI_ERROR (IScsiSessionReinstatement (Private->Session))) {
100 return EFI_DEVICE_ERROR;
101 }
102
103 Status = IScsiExecuteScsiCommand (This, Target, Lun, Packet);
104 }
105
106 return Status;
107 }
108
109 /**
110 Used to retrieve the list of legal Target IDs and LUNs for SCSI devices on
111 a SCSI channel. These can either be the list SCSI devices that are actually
112 present on the SCSI channel, or the list of legal Target Ids and LUNs for the
113 SCSI channel. Regardless, the caller of this function must probe the Target ID
114 and LUN returned to see if a SCSI device is actually present at that location
115 on the SCSI channel.
116
117 @param[in] This The EFI_EXT_SCSI_PASS_THRU_PROTOCOL instance.
118 @param[in, out] Target On input, a pointer to the Target ID of a SCSI
119 device present on the SCSI channel. On output, a
120 pointer to the Target ID of the next SCSI device
121 present on a SCSI channel. An input value of
122 0xFFFFFFFF retrieves the Target ID of the first
123 SCSI device present on a SCSI channel.
124 @param[in, out] Lun On input, a pointer to the LUN of a SCSI device
125 present on the SCSI channel. On output, a pointer
126 to the LUN of the next SCSI device present on a
127 SCSI channel.
128
129 @retval EFI_SUCCESS The Target ID and Lun of the next SCSI device on
130 the SCSI channel was returned in Target and Lun.
131 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI
132 channel.
133 @retval EFI_INVALID_PARAMETER Target is not 0xFFFFFFFF,and Target and Lun were
134 not returned on a previous call to
135 GetNextDevice().
136
137 **/
138 EFI_STATUS
139 EFIAPI
140 IScsiExtScsiPassThruGetNextTargetLun (
141 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
142 IN OUT UINT8 **Target,
143 IN OUT UINT64 *Lun
144 )
145 {
146 ISCSI_DRIVER_DATA *Private;
147 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
148 UINT8 TargetId[TARGET_MAX_BYTES];
149
150 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);
151 ConfigNvData = &Private->Session->ConfigData->SessionConfigData;
152
153 if (((*Target)[0] == 0) && (CompareMem (Lun, ConfigNvData->BootLun, sizeof (UINT64)) == 0)) {
154 //
155 // Only one <Target, Lun> pair per iSCSI Driver instance.
156 //
157 return EFI_NOT_FOUND;
158 }
159
160 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
161 if (CompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {
162 (*Target)[0] = 0;
163 CopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));
164
165 return EFI_SUCCESS;
166 }
167
168 return EFI_INVALID_PARAMETER;
169 }
170
171 /**
172 Allocate and build a device path node for a SCSI device on a SCSI channel.
173
174 @param[in] This Protocol instance pointer.
175 @param[in] Target The Target ID of the SCSI device for which a
176 device path node is to be allocated and built.
177 @param[in] Lun The LUN of the SCSI device for which a device
178 path node is to be allocated and built.
179 @param[in, out] DevicePath A pointer to a single device path node that
180 describes the SCSI device specified by Target and
181 Lun. This function is responsible for allocating
182 the buffer DevicePath with the boot service
183 AllocatePool(). It is the caller's
184 responsibility to free DevicePath when the caller
185 is finished with DevicePath.
186
187 @retval EFI_SUCCESS The device path node that describes the SCSI
188 device specified by Target and Lun was allocated
189 and returned in DevicePath.
190 @retval EFI_NOT_FOUND The SCSI devices specified by Target and Lun does
191 not exist on the SCSI channel.
192 @retval EFI_INVALID_PARAMETER DevicePath is NULL.
193 @retval EFI_OUT_OF_RESOURCES There are not enough resources to allocate
194 DevicePath.
195
196 **/
197 EFI_STATUS
198 EFIAPI
199 IScsiExtScsiPassThruBuildDevicePath (
200 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
201 IN UINT8 *Target,
202 IN UINT64 Lun,
203 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
204 )
205 {
206 ISCSI_DRIVER_DATA *Private;
207 ISCSI_SESSION *Session;
208 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
209 ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfig;
210 EFI_DEV_PATH *Node;
211 UINTN DevPathNodeLen;
212
213 if (DevicePath == NULL) {
214 return EFI_INVALID_PARAMETER;
215 }
216
217 if (Target[0] != 0) {
218 return EFI_NOT_FOUND;
219 }
220
221 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);
222 Session = Private->Session;
223 ConfigNvData = &Session->ConfigData->SessionConfigData;
224 AuthConfig = Session->AuthData.CHAP.AuthConfig;
225
226 if (CompareMem (&Lun, ConfigNvData->BootLun, sizeof (UINT64)) != 0) {
227 return EFI_NOT_FOUND;
228 }
229
230 DevPathNodeLen = sizeof (ISCSI_DEVICE_PATH) + AsciiStrLen (ConfigNvData->TargetName) + 1;
231 Node = AllocateZeroPool (DevPathNodeLen);
232 if (Node == NULL) {
233 return EFI_OUT_OF_RESOURCES;
234 }
235
236 Node->DevPath.Type = MESSAGING_DEVICE_PATH;
237 Node->DevPath.SubType = MSG_ISCSI_DP;
238 SetDevicePathNodeLength (&Node->DevPath, DevPathNodeLen);
239
240 //
241 // 0 for TCP, others are reserved.
242 //
243 Node->Iscsi.NetworkProtocol = 0;
244
245 Node->Iscsi.LoginOption = 0;
246
247 switch (Session->AuthType) {
248 case ISCSI_AUTH_TYPE_NONE:
249 Node->Iscsi.LoginOption |= 0x0800;
250 break;
251
252 case ISCSI_AUTH_TYPE_CHAP:
253 //
254 // Bit12: 0=CHAP_BI, 1=CHAP_UNI
255 //
256 if (AuthConfig->CHAPType == ISCSI_CHAP_UNI) {
257 Node->Iscsi.LoginOption |= 0x1000;
258 }
259
260 break;
261
262 default:
263 break;
264 }
265
266 CopyMem (&Node->Iscsi.Lun, ConfigNvData->BootLun, sizeof (UINT64));
267 Node->Iscsi.TargetPortalGroupTag = Session->TargetPortalGroupTag;
268 AsciiStrCpyS ((CHAR8 *)Node + sizeof (ISCSI_DEVICE_PATH), AsciiStrLen (ConfigNvData->TargetName) + 1, ConfigNvData->TargetName);
269
270 *DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Node;
271
272 return EFI_SUCCESS;
273 }
274
275 /**
276 Translate a device path node to a Target ID and LUN.
277
278 @param[in] This Protocol instance pointer.
279 @param[in] DevicePath A pointer to the device path node that describes
280 a SCSI device on the SCSI channel.
281 @param[out] Target A pointer to the Target ID of a SCSI device on
282 the SCSI channel.
283 @param[out] Lun A pointer to the LUN of a SCSI device on the SCSI
284 channel.
285
286 @retval EFI_SUCCESS DevicePath was successfully translated to a
287 Target ID and LUN, and they were returned in
288 Target and Lun.
289 @retval EFI_INVALID_PARAMETER DevicePath/Target/Lun is NULL.
290 @retval EFI_UNSUPPORTED This driver does not support the device path node
291 type in DevicePath.
292 @retval EFI_NOT_FOUND A valid translation does not exist from DevicePath
293 to a TargetID and LUN.
294
295 **/
296 EFI_STATUS
297 EFIAPI
298 IScsiExtScsiPassThruGetTargetLun (
299 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
300 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
301 OUT UINT8 **Target,
302 OUT UINT64 *Lun
303 )
304 {
305 ISCSI_DRIVER_DATA *Private;
306 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
307
308 if ((DevicePath == NULL) || (Target == NULL) || (Lun == NULL)) {
309 return EFI_INVALID_PARAMETER;
310 }
311
312 if ((DevicePath->Type != MESSAGING_DEVICE_PATH) ||
313 (DevicePath->SubType != MSG_ISCSI_DP) ||
314 (DevicePathNodeLength (DevicePath) <= sizeof (ISCSI_DEVICE_PATH))
315 )
316 {
317 return EFI_UNSUPPORTED;
318 }
319
320 Private = ISCSI_DRIVER_DATA_FROM_EXT_SCSI_PASS_THRU (This);
321 ConfigNvData = &Private->Session->ConfigData->SessionConfigData;
322
323 SetMem (*Target, TARGET_MAX_BYTES, 0xFF);
324 (*Target)[0] = 0;
325
326 if (AsciiStrCmp (ConfigNvData->TargetName, (CHAR8 *)DevicePath + sizeof (ISCSI_DEVICE_PATH)) != 0) {
327 return EFI_UNSUPPORTED;
328 }
329
330 CopyMem (Lun, ConfigNvData->BootLun, sizeof (UINT64));
331
332 return EFI_SUCCESS;
333 }
334
335 /**
336 Resets a SCSI channel. This operation resets all the SCSI devices connected to
337 the SCSI channel.
338
339 @param[in] This Protocol instance pointer.
340
341 @retval EFI_UNSUPPORTED It is not supported.
342
343 **/
344 EFI_STATUS
345 EFIAPI
346 IScsiExtScsiPassThruResetChannel (
347 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This
348 )
349 {
350 return EFI_UNSUPPORTED;
351 }
352
353 /**
354 Resets a SCSI device that is connected to a SCSI channel.
355
356 @param[in] This Protocol instance pointer.
357 @param[in] Target The Target ID of the SCSI device to reset.
358 @param[in] Lun The LUN of the SCSI device to reset.
359
360 @retval EFI_UNSUPPORTED It is not supported.
361
362 **/
363 EFI_STATUS
364 EFIAPI
365 IScsiExtScsiPassThruResetTargetLun (
366 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
367 IN UINT8 *Target,
368 IN UINT64 Lun
369 )
370 {
371 return EFI_UNSUPPORTED;
372 }
373
374 /**
375 Retrieve the list of legal Target IDs for SCSI devices on a SCSI channel.
376
377 @param[in] This A pointer to the EFI_EXT_SCSI_PASS_THRU_PROTOCOL
378 instance.
379 @param[in, out] Target (TARGET_MAX_BYTES) of a SCSI device present on
380 the SCSI channel. On output, a pointer to the
381 Target ID (an array of TARGET_MAX_BYTES) of the
382 next SCSI device present on a SCSI channel.
383 An input value of 0xF(all bytes in the array are 0xF)
384 in the Target array retrieves the Target ID of the
385 first SCSI device present on a SCSI channel.
386
387 @retval EFI_SUCCESS The Target ID of the next SCSI device on the SCSI
388 channel was returned in Target.
389 @retval EFI_INVALID_PARAMETER Target or Lun is NULL.
390 @retval EFI_TIMEOUT Target array is not all 0xF, and Target was not
391 returned on a previous call to GetNextTarget().
392 @retval EFI_NOT_FOUND There are no more SCSI devices on this SCSI channel.
393
394 **/
395 EFI_STATUS
396 EFIAPI
397 IScsiExtScsiPassThruGetNextTarget (
398 IN EFI_EXT_SCSI_PASS_THRU_PROTOCOL *This,
399 IN OUT UINT8 **Target
400 )
401 {
402 UINT8 TargetId[TARGET_MAX_BYTES];
403
404 SetMem (TargetId, TARGET_MAX_BYTES, 0xFF);
405
406 if (CompareMem (*Target, TargetId, TARGET_MAX_BYTES) == 0) {
407 (*Target)[0] = 0;
408 return EFI_SUCCESS;
409 } else if ((*Target)[0] == 0) {
410 return EFI_NOT_FOUND;
411 } else {
412 return EFI_INVALID_PARAMETER;
413 }
414 }