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