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